Merge remote-tracking branch 'aosp/master' into HEAD

Due to an issue with Ranchu HWC, update to master ToT to support
composer@2.4, which is needed to support QEMU after backporting and
switching to Ranchu HWC for crosvm.

Bug: 216827224
Change-Id: I67e6f20833f0cf43bb1b7d909d5117992846d0e8
diff --git a/.ci/.common.sh b/.ci/.common.sh
deleted file mode 100644
index 0183aba..0000000
--- a/.ci/.common.sh
+++ /dev/null
@@ -1,42 +0,0 @@
-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"
-
-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 "
-CXXARGS+=" -fvisibility-inlines-hidden -std=gnu++17 -DHWC2_USE_CPP11 -DHWC2_INCLUDE_STRINGIFICATION -fno-rtti"
-
-BUILD_FILES=(
-backend/BackendClient.cpp
-backend/Backend.cpp
-backend/BackendManager.cpp
-backend/BackendRCarDu.cpp
-bufferinfo/BufferInfoGetter.cpp
-#bufferinfo/BufferInfoMapperMetadata.cpp
-bufferinfo/legacy/BufferInfoImagination.cpp
-bufferinfo/legacy/BufferInfoLibdrm.cpp
-bufferinfo/legacy/BufferInfoMaliHisi.cpp
-bufferinfo/legacy/BufferInfoMaliMediatek.cpp
-bufferinfo/legacy/BufferInfoMaliMeson.cpp
-bufferinfo/legacy/BufferInfoMinigbm.cpp
-compositor/DrmDisplayComposition.cpp
-compositor/DrmDisplayCompositor.cpp
-compositor/Planner.cpp
-drm/DrmConnector.cpp
-drm/DrmCrtc.cpp
-drm/DrmDevice.cpp
-drm/DrmEncoder.cpp
-drm/DrmEventListener.cpp
-drm/DrmFbImporter.cpp
-drm/DrmMode.cpp
-drm/DrmPlane.cpp
-drm/DrmProperty.cpp
-DrmHwcTwo.cpp
-drm/ResourceManager.cpp
-drm/VSyncWorker.cpp
-tests/worker_test.cpp
-utils/autolock.cpp
-#utils/hwcutils.cpp
-utils/Worker.cpp
-)
diff --git a/.ci/.gitlab-ci-checkcommit.sh b/.ci/.gitlab-ci-checkcommit.sh
index 817afa7..c6f7c4e 100755
--- a/.ci/.gitlab-ci-checkcommit.sh
+++ b/.ci/.gitlab-ci-checkcommit.sh
@@ -50,7 +50,7 @@
 		exit 1
 	fi
 
-	git show "$h" -- | clang-format-diff-11 -p 1 -style=file > /tmp/format-fixup.patch
+	git show "$h" -- | clang-format-diff-14 -p 1 -style=file > /tmp/format-fixup.patch
 	if [ -s  /tmp/format-fixup.patch ]; then
 		cat /tmp/format-fixup.patch >&2
 		exit 1
diff --git a/.ci/.gitlab-ci-clang-build.sh b/.ci/.gitlab-ci-clang-build.sh
deleted file mode 100755
index 1070365..0000000
--- a/.ci/.gitlab-ci-clang-build.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-
-. ./.ci/.common.sh
-
-set -xe
-
-for source in "${BUILD_FILES[@]}"
-do
-    filename=$(basename -- "$source")
-    $CLANG $source $INCLUDE_DIRS $CXXARGS -c -o /tmp/"${filename%.*}.o"
-done
diff --git a/.ci/.gitlab-ci-clang-tidy-coarse.sh b/.ci/.gitlab-ci-clang-tidy-coarse.sh
deleted file mode 100755
index de0c024..0000000
--- a/.ci/.gitlab-ci-clang-tidy-coarse.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/bash
-
-. ./.ci/.common.sh
-
-TIDY_COARSE_CHECKS="-*,android-*,bugprone-*,cert-*,clang-analyzer-*,"
-TIDY_COARSE_CHECKS+="cppcoreguidelines-*,"
-TIDY_COARSE_CHECKS+="-cppcoreguidelines-pro-bounds-array-to-pointer-decay,"
-TIDY_COARSE_CHECKS+="-cppcoreguidelines-pro-bounds-constant-array-index,"
-TIDY_COARSE_CHECKS+="-cppcoreguidelines-pro-bounds-pointer-arithmetic,"
-TIDY_COARSE_CHECKS+="-cppcoreguidelines-pro-type-cstyle-cast,"
-TIDY_COARSE_CHECKS+="-cppcoreguidelines-pro-type-union-access,"
-TIDY_COARSE_CHECKS+="-cppcoreguidelines-pro-type-vararg,"
-TIDY_COARSE_CHECKS+="-cppcoreguidelines-avoid-magic-numbers,"
-TIDY_COARSE_CHECKS+="-cppcoreguidelines-macro-usage,"
-TIDY_COARSE_CHECKS+="-cppcoreguidelines-avoid-c-arrays,"
-TIDY_COARSE_CHECKS+="google-*,"
-TIDY_COARSE_CHECKS+="-google-readability-braces-around-statements,"
-TIDY_COARSE_CHECKS+="-google-readability-casting,"
-TIDY_COARSE_CHECKS+="misc-*,"
-TIDY_COARSE_CHECKS+="modernize-*,"
-TIDY_COARSE_CHECKS+="-modernize-avoid-c-arrays,"
-TIDY_COARSE_CHECKS+="-modernize-use-trailing-return-type,"
-TIDY_COARSE_CHECKS+="performance-*,"
-TIDY_COARSE_CHECKS+="portability-*,"
-TIDY_COARSE_CHECKS+="readability-*,"
-TIDY_COARSE_CHECKS+="-readability-braces-around-statements,"
-TIDY_COARSE_CHECKS+="-readability-convert-member-functions-to-static,"
-TIDY_COARSE_CHECKS+="-readability-implicit-bool-conversion,"
-TIDY_COARSE_CHECKS+="-readability-magic-numbers,"
-TIDY_COARSE_CHECKS+="-readability-use-anyofallof"
-
-TIDY_FILES=( "${BUILD_FILES[@]}" )
-
-set -xe
-
-for source in "${TIDY_FILES[@]}"
-do
-    $CLANG_TIDY $source --checks=$TIDY_COARSE_CHECKS -- -x c++ $INCLUDE_DIRS $CXXARGS
-done
diff --git a/.ci/.gitlab-ci-clang-tidy-fine.sh b/.ci/.gitlab-ci-clang-tidy-fine.sh
deleted file mode 100755
index c1805e8..0000000
--- a/.ci/.gitlab-ci-clang-tidy-fine.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-
-. ./.ci/.common.sh
-
-TIDY_FILES=(
-drm/DrmFbImporter.h
-utils/UniqueFd.h
-utils/log.h
-utils/properties.h
-)
-
-set -xe
-
-for source in "${TIDY_FILES[@]}"
-do
-    $CLANG_TIDY $source -- -x c++ $INCLUDE_DIRS $CXXARGS
-done
diff --git a/.ci/Makefile b/.ci/Makefile
new file mode 100644
index 0000000..581c6d9
--- /dev/null
+++ b/.ci/Makefile
@@ -0,0 +1,159 @@
+
+INCLUDE_DIRS := . ../libdrm/include/drm include ./.ci/android_headers ./tests/test_include
+SYSTEM_INCLUDE_DIRS := /usr/include/libdrm
+
+CLANG := clang++-14
+CLANG_TIDY := clang-tidy-14
+OUT_DIR := /tmp/drm_hwcomposer/build
+SRC_DIR := .
+
+CXXFLAGS := -fPIC -Wall -Wextra -Werror -DPLATFORM_SDK_VERSION=31 -D__ANDROID_API__=31
+CXXFLAGS += -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS
+CXXFLAGS += -fvisibility-inlines-hidden -std=gnu++17 -DHWC2_USE_CPP11 -DHWC2_INCLUDE_STRINGIFICATION -fno-rtti
+
+SKIP_FILES := \
+    bufferinfo/BufferInfoMapperMetadata.cpp
+
+TIDY_FILES_OVERRIDE := \
+    bufferinfo/legacy/BufferInfoImagination.cpp:COARSE  \
+    bufferinfo/legacy/BufferInfoLibdrm.cpp:COARSE       \
+    bufferinfo/legacy/BufferInfoMaliHisi.cpp:COARSE     \
+    bufferinfo/legacy/BufferInfoMaliMediatek.cpp:COARSE \
+    bufferinfo/legacy/BufferInfoMaliMeson.cpp:COARSE    \
+    bufferinfo/legacy/BufferInfoMinigbm.cpp:COARSE      \
+    drm/DrmFbImporter.h:FINE                            \
+    drm/DrmMode.h:COARSE                                \
+    drm/DrmProperty.h:COARSE                            \
+    drm/DrmUnique.h:FINE                                \
+    drm/DrmProperty.cpp:COARSE                          \
+    drm/VSyncWorker.cpp:COARSE                          \
+    hwc2_device/DrmHwcTwo.cpp:COARSE                    \
+    hwc2_device/DrmHwcTwo.h:COARSE                      \
+    hwc2_device/HwcDisplay.cpp:COARSE                   \
+    hwc2_device/HwcDisplay.h:COARSE                     \
+    tests/worker_test.cpp:COARSE                        \
+    utils/Worker.h:COARSE                               \
+    utils/UniqueFd.h:FINE                               \
+    utils/log.h:FINE                                    \
+    utils/properties.h:FINE                             \
+
+TIDY_CHECKS_FINE := *                                   \
+    -llvmlibc* -fuchsia-* -altera-*                     \
+    -llvm-header-guard                                  \
+    -cppcoreguidelines-pro-type-vararg                  \
+    -hicpp-vararg                                       \
+    -hicpp-signed-bitwise                               \
+    -readability-identifier-length                      \
+
+TIDY_CHECKS_NORMAL :=                                   \
+    $(TIDY_CHECKS_FINE)                                 \
+    -hicpp*                                             \
+    -bugprone-easily-swappable-parameters               \
+    -cppcoreguidelines-special-member-functions \
+    -cppcoreguidelines-avoid-c-arrays \
+    -cppcoreguidelines-pro-bounds-array-to-pointer-decay \
+    -cppcoreguidelines-pro-bounds-constant-array-index \
+    -cppcoreguidelines-avoid-magic-numbers \
+    -google-readability-braces-around-statements \
+    -google-readability-casting \
+    -misc-non-private-member-variables-in-classes \
+    -modernize-avoid-c-arrays \
+    -modernize-use-nodiscard \
+    -modernize-use-trailing-return-type \
+    -readability-braces-around-statements \
+
+TIDY_CHECKS_COARSE := \
+    $(TIDY_CHECKS_NORMAL) \
+    -cppcoreguidelines-non-private-member-variables-in-classes \
+    -cppcoreguidelines-pro-bounds-pointer-arithmetic \
+    -cppcoreguidelines-pro-type-cstyle-cast \
+    -cppcoreguidelines-pro-type-reinterpret-cast \
+    -cppcoreguidelines-pro-type-static-cast-downcast \
+    -cppcoreguidelines-pro-type-union-access \
+    -cppcoreguidelines-macro-usage \
+    -readability-convert-member-functions-to-static \
+    -readability-implicit-bool-conversion \
+    -readability-identifier-naming \
+    -readability-magic-numbers \
+
+.PHONY: all build tidy clean
+
+all: build tidy
+
+clean:
+	rm -rf $(OUT_DIR)/
+
+# Build
+
+BUILD_FILES_AUTO := $(shell find -L $(SRC_DIR) -not -path '*/\.*' -not -path '*/tests/test_include/*' -path '*.cpp')
+SKIP_FILES_path := $(foreach file,$(SKIP_FILES),$(SRC_DIR)/$(file))
+
+BUILD_FILES := $(subst ./,,$(filter-out $(SKIP_FILES_path),$(BUILD_FILES_AUTO)))
+
+_OBJ := $(BUILD_FILES:.cpp=.o)
+OBJ  := $(patsubst %,$(OUT_DIR)/%,$(_OBJ))
+
+DEPS := $(patsubst %.cpp,$(OUT_DIR)/%.d,$(BUILD_FILES))
+
+build: $(OBJ)
+
+CXXARGS := $(foreach dir,$(INCLUDE_DIRS),-I$(SRC_DIR)/$(dir)) $(foreach dir,$(SYSTEM_INCLUDE_DIRS),-I$(dir)) $(CXXFLAGS)
+
+$(OUT_DIR)/%.o: $(SRC_DIR)/%.cpp
+	mkdir -p $(dir $@)
+	$(CLANG) $< $(CXXARGS) -c -o $@
+
+$(OUT_DIR)/%.d: $(SRC_DIR)/%.cpp
+	mkdir -p $(dir $@)
+	$(CLANG) $(CXXARGS) $< -MM -MT $(OUT_DIR)/$(patsubst %.cpp,%.o,$<) -o $@
+
+# TIDY
+TIDY_FILES_AUTO := $(shell find -L $(SRC_DIR) -not -path '*/\.*' -not -path '*/tests/test_include/*' \( -path '*.cpp' -o -path '*.h' \))
+
+TIDY_FILES_AUTO_filtered := $(filter-out $(SKIP_FILES_path),$(TIDY_FILES_AUTO))
+
+TIDY_FILES_OVERRIDE_path := $(foreach pair,$(TIDY_FILES_OVERRIDE),$(SRC_DIR)/$(pair))
+
+TIDY_FILES_OVERRIDE_name_only := $(foreach pair,$(TIDY_FILES_OVERRIDE_path),$(word 1, $(subst :, ,$(pair))))
+
+TIDY_FILES := $(sort $(TIDY_FILES_AUTO_filtered) $(TIDY_FILES_OVERRIDE_name_only))
+
+space := $(subst ,, )
+comma := ,
+
+TIDY_ARGS_NONE := --checks="-*,llvm-include-order"
+TIDY_ARGS_     := --checks="-*,llvm-include-order"
+TIDY_ARGS_FINE := --checks="$(subst $(space),$(comma),$(strip $(TIDY_CHECKS_FINE)))"
+TIDY_ARGS_NORMAL := --checks="$(subst $(space),$(comma),$(strip $(TIDY_CHECKS_NORMAL)))"
+TIDY_ARGS_COARSE := --checks="$(subst $(space),$(comma),$(strip $(TIDY_CHECKS_COARSE)))"
+
+define process-tidy
+
+_TARG := $(OUT_DIR)/$1.tidy.ts
+_DEP := $(SRC_DIR)/$1
+
+TIDY_DEPS += $(_TARG)
+
+TIDY_LEVEL_1 := $$(strip $$(foreach pair,$$(TIDY_FILES_OVERRIDE_path),$$(if $$(filter $$(word 1, $$(subst :, ,$$(pair))),$1),$$(word 2, $$(subst :, ,$$(pair))),)))
+
+TIDY_LEVEL_2 := $$(if $$(TIDY_LEVEL_1),$$(TIDY_LEVEL_1),NORMAL)
+
+TIDY_ARGS := $$(TIDY_ARGS_$$(TIDY_LEVEL_2))
+
+$$(_TARG): _DEP := $$(_DEP)
+$$(_TARG): _TARG := $$(_TARG)
+$$(_TARG): TIDY_ARGS := $$(TIDY_ARGS)
+$$(_TARG): $$(_DEP)
+	mkdir -p $$(dir $$(_TARG))
+	$$(CLANG_TIDY) $$(_DEP) $$(TIDY_ARGS) -- -x c++ $$(CXXARGS) -Wno-pragma-once-outside-header
+	touch $$(_TARG)
+
+endef
+
+$(foreach file,$(TIDY_FILES),$(eval $(call process-tidy,$(file))))
+
+tidy: $(TIDY_DEPS)
+
+ifneq ($(MAKECMDGOALS), clean)
+-include $(DEPS)
+endif
diff --git a/.clang-tidy b/.clang-tidy
index 0bb7bf0..3731a29 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -1,14 +1,3 @@
-# fuchsia: Conflicts with other checks
-# llvm-header-guard: Does not match drm_hwc header gusrd style 
-# Allow using ALOGE 
-
-Checks: >
-    *,
-    -fuchsia*,
-    -llvm*,
-    -cppcoreguidelines-pro-type-vararg, -hicpp-vararg,
-    -hicpp-signed-bitwise,
-
 # Turn all the warnings from the checks above into errors.
 WarningsAsErrors: "*"
 
@@ -17,26 +6,55 @@
 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.PrivateMemberSuffix
+    value:           _
+  - key:             readability-identifier-naming.PublicMemberSuffix
+    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
+  - key:             cppcoreguidelines-macro-usage.AllowedRegexp
+    value:           "LOG_TAG|ATRACE_TAG"
+  - key:             readability-magic-numbers.IgnoredFloatingPointValues
+    value:           '1000.0'
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 04eb6c5..eb0c265 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,8 +1,11 @@
-image: ubuntu:20.10
+image: ubuntu:22.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-14 clang-tidy-14 clang-format-14 git libdrm-dev blueprint-tools libgtest-dev make >/dev/null
 
 stages:
   - build
@@ -10,7 +13,8 @@
 
 build:
   stage: build
-  script: "./.ci/.gitlab-ci-clang-build.sh"
+  script:
+    - make -f .ci/Makefile
   artifacts:
     when: on_failure
     untracked: true
@@ -21,17 +25,3 @@
   artifacts:
     when: on_failure
     untracked: true
-
-tidy-coarse:
-  stage: style
-  script: "./.ci/.gitlab-ci-clang-tidy-coarse.sh"
-  artifacts:
-    when: on_failure
-    untracked: true
-
-tidy-fine:
-  stage: style
-  script: "./.ci/.gitlab-ci-clang-tidy-fine.sh"
-  artifacts:
-    when: on_failure
-    untracked: true
diff --git a/Android.bp b/Android.bp
index a4d8e18..a7a2e94 100644
--- a/Android.bp
+++ b/Android.bp
@@ -37,10 +37,7 @@
 
     srcs: ["utils/Worker.cpp"],
 
-    include_dirs: [
-        "external/drm_hwcomposer",
-        "external/drm_hwcomposer/include",
-    ],
+    include_dirs: ["external/drm_hwcomposer"],
 
     cflags: [
         "-Wall",
@@ -68,10 +65,7 @@
         "libutils",
     ],
 
-    include_dirs: [
-        "external/drm_hwcomposer",
-        "external/drm_hwcomposer/include",
-    ],
+    include_dirs: ["external/drm_hwcomposer"],
 
     static_libs: ["libdrmhwc_utils"],
 
@@ -83,6 +77,7 @@
     cppflags: [
         "-DHWC2_INCLUDE_STRINGIFICATION",
         "-DHWC2_USE_CPP11",
+        "-std=c++17",
     ],
 
     product_variables: {
@@ -95,54 +90,64 @@
     vendor: true,
 }
 
-cc_library_static {
-    name: "drm_hwcomposer",
-    defaults: ["hwcomposer.drm_defaults"],
+filegroup {
+    name: "drm_hwcomposer_common",
     srcs: [
-        "DrmHwcTwo.cpp",
-
         "bufferinfo/BufferInfoGetter.cpp",
         "bufferinfo/BufferInfoMapperMetadata.cpp",
 
-        "compositor/DrmDisplayComposition.cpp",
-        "compositor/DrmDisplayCompositor.cpp",
-        "compositor/Planner.cpp",
+        "compositor/DrmKmsPlan.cpp",
 
+        "drm/DrmAtomicStateManager.cpp",
         "drm/DrmConnector.cpp",
         "drm/DrmCrtc.cpp",
         "drm/DrmDevice.cpp",
+        "drm/DrmDisplayPipeline.cpp",
         "drm/DrmEncoder.cpp",
-        "drm/DrmEventListener.cpp",
         "drm/DrmFbImporter.cpp",
         "drm/DrmMode.cpp",
         "drm/DrmPlane.cpp",
         "drm/DrmProperty.cpp",
         "drm/ResourceManager.cpp",
+        "drm/UEventListener.cpp",
         "drm/VSyncWorker.cpp",
 
-        "utils/autolock.cpp",
-        "utils/hwcutils.cpp",
-
         "backend/Backend.cpp",
         "backend/BackendClient.cpp",
         "backend/BackendManager.cpp",
-        "backend/BackendRCarDu.cpp",
+
+        "hwc2_device/DrmHwcTwo.cpp",
+        "hwc2_device/HwcDisplay.cpp",
+        "hwc2_device/HwcDisplayConfigs.cpp",
+        "hwc2_device/HwcLayer.cpp",
+        "hwc2_device/hwc2_device.cpp",
     ],
 }
 
+// Kept only for compatibility with older Android version. Please do not use!
+cc_library_static {
+    name: "drm_hwcomposer",
+    defaults: ["hwcomposer.drm_defaults"],
+    srcs: [":drm_hwcomposer_common"],
+}
+
 cc_library_shared {
     name: "hwcomposer.drm",
     defaults: ["hwcomposer.drm_defaults"],
-    whole_static_libs: ["drm_hwcomposer"],
-    srcs: ["bufferinfo/legacy/BufferInfoLibdrm.cpp"],
+    srcs: [
+        ":drm_hwcomposer_common",
+        "bufferinfo/legacy/BufferInfoLibdrm.cpp",
+    ],
+    cflags: ["-DUSE_IMAPPER4_METADATA_API"],
 }
 
 cc_library_shared {
     name: "hwcomposer.drm_minigbm",
     defaults: ["hwcomposer.drm_defaults"],
-    whole_static_libs: ["drm_hwcomposer"],
-    srcs: ["bufferinfo/legacy/BufferInfoMinigbm.cpp"],
-    include_dirs: ["external/minigbm/cros_gralloc"],
+    srcs: [
+        ":drm_hwcomposer_common",
+        "bufferinfo/legacy/BufferInfoMinigbm.cpp",
+    ],
 }
 
 // Used by hwcomposer.drm_imagination
diff --git a/DrmHwcTwo.cpp b/DrmHwcTwo.cpp
deleted file mode 100644
index 02667cf..0000000
--- a/DrmHwcTwo.cpp
+++ /dev/null
@@ -1,1528 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#define LOG_TAG "hwc-drm-two"
-
-#include "DrmHwcTwo.h"
-
-#include <fcntl.h>
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer2.h>
-#include <sync/sync.h>
-#include <unistd.h>
-
-#include <cinttypes>
-#include <iostream>
-#include <sstream>
-#include <string>
-
-#include "backend/BackendManager.h"
-#include "bufferinfo/BufferInfoGetter.h"
-#include "compositor/DrmDisplayComposition.h"
-#include "utils/log.h"
-#include "utils/properties.h"
-
-namespace android {
-
-DrmHwcTwo::DrmHwcTwo() : hwc2_device() {
-  common.tag = HARDWARE_DEVICE_TAG;
-  common.version = HWC_DEVICE_API_VERSION_2_0;
-  common.close = HookDevClose;
-  getCapabilities = HookDevGetCapabilities;
-  getFunction = HookDevGetFunction;
-}
-
-HWC2::Error DrmHwcTwo::CreateDisplay(hwc2_display_t displ,
-                                     HWC2::DisplayType type) {
-  DrmDevice *drm = resource_manager_.GetDrmDevice(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));
-
-  DrmCrtc *crtc = drm->GetCrtcForDisplay(static_cast<int>(displ));
-  if (!crtc) {
-    ALOGE("Failed to get crtc for display %d", static_cast<int>(displ));
-    return HWC2::Error::BadDisplay;
-  }
-  auto display_planes = std::vector<DrmPlane *>();
-  for (const auto &plane : drm->planes()) {
-    if (plane->GetCrtcSupported(*crtc))
-      display_planes.push_back(plane.get());
-  }
-  displays_.at(displ).Init(&display_planes);
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::Init() {
-  int rv = resource_manager_.Init();
-  if (rv) {
-    ALOGE("Can't initialize the resource manager %d", rv);
-    return HWC2::Error::NoResources;
-  }
-
-  HWC2::Error ret = HWC2::Error::None;
-  for (int i = 0; i < resource_manager_.getDisplayCount(); i++) {
-    ret = CreateDisplay(i, HWC2::DisplayType::Physical);
-    if (ret != HWC2::Error::None) {
-      ALOGE("Failed to create display %d with error %d", i, ret);
-      return ret;
-    }
-  }
-
-  const auto &drm_devices = resource_manager_.getDrmDevices();
-  for (const auto &device : drm_devices) {
-    // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
-    device->RegisterHotplugHandler(new DrmHotplugHandler(this, device.get()));
-  }
-  return ret;
-}
-
-template <typename... Args>
-static inline HWC2::Error unsupported(char const *func, Args... /*args*/) {
-  ALOGV("Unsupported function: %s", func);
-  return HWC2::Error::Unsupported;
-}
-
-static inline void supported(char const *func) {
-  ALOGV("Supported function: %s", func);
-}
-
-HWC2::Error DrmHwcTwo::CreateVirtualDisplay(uint32_t width, uint32_t height,
-                                            int32_t *format,
-                                            hwc2_display_t *display) {
-  // TODO(nobody): Implement virtual display
-  return unsupported(__func__, width, height, format, display);
-}
-
-HWC2::Error DrmHwcTwo::DestroyVirtualDisplay(hwc2_display_t display) {
-  // TODO(nobody): Implement virtual display
-  return unsupported(__func__, display);
-}
-
-std::string DrmHwcTwo::HwcDisplay::DumpDelta(
-    DrmHwcTwo::HwcDisplay::Stats delta) {
-  if (delta.total_pixops_ == 0)
-    return "No stats yet";
-  double ratio = 1.0 - double(delta.gpu_pixops_) / double(delta.total_pixops_);
-
-  std::stringstream ss;
-  ss << " Total frames count: " << delta.total_frames_ << "\n"
-     << " Failed to test commit frames: " << delta.failed_kms_validate_ << "\n"
-     << " Failed to commit frames: " << delta.failed_kms_present_ << "\n"
-     << ((delta.failed_kms_present_ > 0)
-             ? " !!! Internal failure, FIX it please\n"
-             : "")
-     << " Flattened frames: " << delta.frames_flattened_ << "\n"
-     << " Pixel operations (free units)"
-     << " : [TOTAL: " << delta.total_pixops_ << " / GPU: " << delta.gpu_pixops_
-     << "]\n"
-     << " Composition efficiency: " << ratio;
-
-  return ss.str();
-}
-
-std::string DrmHwcTwo::HwcDisplay::Dump() {
-  std::stringstream ss;
-  ss << "- Display on: " << connector_->name() << "\n"
-     << "  Flattening state: " << compositor_.GetFlatteningState() << "\n"
-     << "Statistics since system boot:\n"
-     << DumpDelta(total_stats_) << "\n\n"
-     << "Statistics since last dumpsys request:\n"
-     << DumpDelta(total_stats_.minus(prev_stats_)) << "\n\n";
-
-  memcpy(&prev_stats_, &total_stats_, sizeof(Stats));
-  return ss.str();
-}
-
-void DrmHwcTwo::Dump(uint32_t *outSize, char *outBuffer) {
-  supported(__func__);
-
-  if (outBuffer != nullptr) {
-    auto copied_bytes = mDumpString.copy(outBuffer, *outSize);
-    *outSize = static_cast<uint32_t>(copied_bytes);
-    return;
-  }
-
-  std::stringstream output;
-
-  output << "-- drm_hwcomposer --\n\n";
-
-  for (std::pair<const hwc2_display_t, DrmHwcTwo::HwcDisplay> &dp : displays_)
-    output << dp.second.Dump();
-
-  mDumpString = output.str();
-  *outSize = static_cast<uint32_t>(mDumpString.size());
-}
-
-uint32_t DrmHwcTwo::GetMaxVirtualDisplayCount() {
-  // TODO(nobody): Implement virtual display
-  unsupported(__func__);
-  return 0;
-}
-
-HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
-                                        hwc2_callback_data_t data,
-                                        hwc2_function_pointer_t function) {
-  supported(__func__);
-
-  switch (static_cast<HWC2::Callback>(descriptor)) {
-    case HWC2::Callback::Hotplug: {
-      SetHotplugCallback(data, function);
-      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);
-      break;
-    }
-    case HWC2::Callback::Vsync: {
-      for (std::pair<const hwc2_display_t, DrmHwcTwo::HwcDisplay> &d :
-           displays_)
-        d.second.RegisterVsyncCallback(data, function);
-      break;
-    }
-    default:
-      break;
-  }
-  return HWC2::Error::None;
-}
-
-DrmHwcTwo::HwcDisplay::HwcDisplay(ResourceManager *resource_manager,
-                                  DrmDevice *drm, hwc2_display_t handle,
-                                  HWC2::DisplayType type)
-    : resource_manager_(resource_manager),
-      drm_(drm),
-      handle_(handle),
-      type_(type),
-      color_transform_hint_(HAL_COLOR_TRANSFORM_IDENTITY) {
-  supported(__func__);
-
-  // clang-format off
-  color_transform_matrix_ = {1.0, 0.0, 0.0, 0.0,
-                             0.0, 1.0, 0.0, 0.0,
-                             0.0, 0.0, 1.0, 0.0,
-                             0.0, 0.0, 0.0, 1.0};
-  // clang-format on
-}
-
-void DrmHwcTwo::HwcDisplay::ClearDisplay() {
-  compositor_.ClearDisplay();
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::Init(std::vector<DrmPlane *> *planes) {
-  supported(__func__);
-  planner_ = Planner::CreateInstance(drm_);
-  if (!planner_) {
-    ALOGE("Failed to create planner instance for composition");
-    return HWC2::Error::NoResources;
-  }
-
-  int display = static_cast<int>(handle_);
-  int ret = compositor_.Init(resource_manager_, display);
-  if (ret) {
-    ALOGE("Failed display compositor init for display %d (%d)", display, ret);
-    return HWC2::Error::NoResources;
-  }
-
-  // Split up the given display planes into primary and overlay to properly
-  // interface with the composition
-  char use_overlay_planes_prop[PROPERTY_VALUE_MAX];
-  property_get("vendor.hwc.drm.use_overlay_planes", use_overlay_planes_prop,
-               "1");
-  bool use_overlay_planes = strtol(use_overlay_planes_prop, nullptr, 10);
-  for (auto &plane : *planes) {
-    if (plane->type() == DRM_PLANE_TYPE_PRIMARY)
-      primary_planes_.push_back(plane);
-    else if (use_overlay_planes && (plane)->type() == DRM_PLANE_TYPE_OVERLAY)
-      overlay_planes_.push_back(plane);
-  }
-
-  crtc_ = drm_->GetCrtcForDisplay(display);
-  if (!crtc_) {
-    ALOGE("Failed to get crtc for display %d", display);
-    return HWC2::Error::BadDisplay;
-  }
-
-  connector_ = drm_->GetConnectorForDisplay(display);
-  if (!connector_) {
-    ALOGE("Failed to get connector for display %d", display);
-    return HWC2::Error::BadDisplay;
-  }
-
-  ret = vsync_worker_.Init(drm_, display);
-  if (ret) {
-    ALOGE("Failed to create event worker for d=%d %d\n", display, ret);
-    return HWC2::Error::BadDisplay;
-  }
-
-  ret = BackendManager::GetInstance().SetBackendForDisplay(this);
-  if (ret) {
-    ALOGE("Failed to set backend for d=%d %d\n", display, ret);
-    return HWC2::Error::BadDisplay;
-  }
-
-  return ChosePreferredConfig();
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::ChosePreferredConfig() {
-  // Fetch the number of modes from the display
-  uint32_t num_configs = 0;
-  HWC2::Error err = GetDisplayConfigs(&num_configs, nullptr);
-  if (err != HWC2::Error::None || !num_configs)
-    return err;
-
-  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_)
-    l.second.accept_type_change();
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::CreateLayer(hwc2_layer_t *layer) {
-  supported(__func__);
-  layers_.emplace(static_cast<hwc2_layer_t>(layer_idx_), HwcLayer());
-  *layer = static_cast<hwc2_layer_t>(layer_idx_);
-  ++layer_idx_;
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::DestroyLayer(hwc2_layer_t layer) {
-  supported(__func__);
-  if (!get_layer(layer))
-    return HWC2::Error::BadLayer;
-
-  layers_.erase(layer);
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::GetActiveConfig(hwc2_config_t *config) {
-  supported(__func__);
-  DrmMode const &mode = connector_->active_mode();
-  if (mode.id() == 0)
-    return HWC2::Error::BadConfig;
-
-  *config = mode.id();
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::GetChangedCompositionTypes(
-    uint32_t *num_elements, hwc2_layer_t *layers, int32_t *types) {
-  supported(__func__);
-  uint32_t num_changes = 0;
-  for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) {
-    if (l.second.type_changed()) {
-      if (layers && num_changes < *num_elements)
-        layers[num_changes] = l.first;
-      if (types && num_changes < *num_elements)
-        types[num_changes] = static_cast<int32_t>(l.second.validated_type());
-      ++num_changes;
-    }
-  }
-  if (!layers && !types)
-    *num_elements = num_changes;
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::GetClientTargetSupport(uint32_t width,
-                                                          uint32_t height,
-                                                          int32_t /*format*/,
-                                                          int32_t dataspace) {
-  supported(__func__);
-  std::pair<uint32_t, uint32_t> min = drm_->min_resolution();
-  std::pair<uint32_t, uint32_t> max = drm_->max_resolution();
-
-  if (width < min.first || height < min.second)
-    return HWC2::Error::Unsupported;
-
-  if (width > max.first || height > max.second)
-    return HWC2::Error::Unsupported;
-
-  if (dataspace != HAL_DATASPACE_UNKNOWN)
-    return HWC2::Error::Unsupported;
-
-  // TODO(nobody): Validate format can be handled by either GL or planes
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::GetColorModes(uint32_t *num_modes,
-                                                 int32_t *modes) {
-  supported(__func__);
-  if (!modes)
-    *num_modes = 1;
-
-  if (modes)
-    *modes = HAL_COLOR_MODE_NATIVE;
-
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayAttribute(hwc2_config_t config,
-                                                       int32_t attribute_in,
-                                                       int32_t *value) {
-  supported(__func__);
-  auto mode = std::find_if(connector_->modes().begin(),
-                           connector_->modes().end(),
-                           [config](DrmMode const &m) {
-                             return m.id() == config;
-                           });
-  if (mode == connector_->modes().end()) {
-    ALOGE("Could not find active mode for %d", config);
-    return HWC2::Error::BadConfig;
-  }
-
-  static const int32_t kUmPerInch = 25400;
-  uint32_t mm_width = connector_->mm_width();
-  uint32_t mm_height = connector_->mm_height();
-  auto attribute = static_cast<HWC2::Attribute>(attribute_in);
-  switch (attribute) {
-    case HWC2::Attribute::Width:
-      *value = mode->h_display();
-      break;
-    case HWC2::Attribute::Height:
-      *value = mode->v_display();
-      break;
-    case HWC2::Attribute::VsyncPeriod:
-      // in nanoseconds
-      *value = 1000.0 * 1000.0 * 1000.0 / mode->v_refresh();
-      break;
-    case HWC2::Attribute::DpiX:
-      // Dots per 1000 inches
-      *value = mm_width ? (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;
-      break;
-#if PLATFORM_SDK_VERSION > 29
-    case HWC2::Attribute::ConfigGroup:
-      *value = 0; /* TODO: Add support for config groups */
-      break;
-#endif
-    default:
-      *value = -1;
-      return HWC2::Error::BadConfig;
-  }
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayConfigs(uint32_t *num_configs,
-                                                     hwc2_config_t *configs) {
-  supported(__func__);
-  // Since this callback is normally invoked twice (once to get the count, and
-  // once to populate configs), we don't really want to read the edid
-  // redundantly. Instead, only update the modes on the first invocation. While
-  // it's possible this will result in stale modes, it'll all come out in the
-  // wash when we try to set the active config later.
-  if (!configs) {
-    int ret = connector_->UpdateModes();
-    if (ret) {
-      ALOGE("Failed to update display modes %d", ret);
-      return HWC2::Error::BadDisplay;
-    }
-  }
-
-  // Since the upper layers only look at vactive/hactive/refresh, height and
-  // width, it doesn't differentiate interlaced from progressive and other
-  // similar modes. Depending on the order of modes we return to SF, it could
-  // end up choosing a suboptimal configuration and dropping the preferred
-  // mode. To workaround this, don't offer interlaced modes to SF if there is
-  // at least one non-interlaced alternative and only offer a single WxH@R
-  // mode with at least the prefered mode from in DrmConnector::UpdateModes()
-
-  // TODO(nobody): Remove the following block of code until AOSP handles all
-  // modes
-  std::vector<DrmMode> sel_modes;
-
-  // Add the preferred mode first to be sure it's not dropped
-  auto mode = std::find_if(connector_->modes().begin(),
-                           connector_->modes().end(), [&](DrmMode const &m) {
-                             return m.id() ==
-                                    connector_->get_preferred_mode_id();
-                           });
-  if (mode != connector_->modes().end())
-    sel_modes.push_back(*mode);
-
-  // Add the active mode if different from preferred mode
-  if (connector_->active_mode().id() != connector_->get_preferred_mode_id())
-    sel_modes.push_back(connector_->active_mode());
-
-  // Cycle over the modes and filter out "similar" modes, keeping only the
-  // first ones in the order given by DRM (from CEA ids and timings order)
-  for (const DrmMode &mode : connector_->modes()) {
-    // TODO(nobody): Remove this when 3D Attributes are in AOSP
-    if (mode.flags() & DRM_MODE_FLAG_3D_MASK)
-      continue;
-
-    // TODO(nobody): Remove this when the Interlaced attribute is in AOSP
-    if (mode.flags() & DRM_MODE_FLAG_INTERLACE) {
-      auto m = std::find_if(connector_->modes().begin(),
-                            connector_->modes().end(),
-                            [&mode](DrmMode const &m) {
-                              return !(m.flags() & DRM_MODE_FLAG_INTERLACE) &&
-                                     m.h_display() == mode.h_display() &&
-                                     m.v_display() == mode.v_display();
-                            });
-      if (m == connector_->modes().end())
-        sel_modes.push_back(mode);
-
-      continue;
-    }
-
-    // Search for a similar WxH@R mode in the filtered list and drop it if
-    // another mode with the same WxH@R has already been selected
-    // TODO(nobody): Remove this when AOSP handles duplicates modes
-    auto m = std::find_if(sel_modes.begin(), sel_modes.end(),
-                          [&mode](DrmMode const &m) {
-                            return m.h_display() == mode.h_display() &&
-                                   m.v_display() == mode.v_display() &&
-                                   m.v_refresh() == mode.v_refresh();
-                          });
-    if (m == sel_modes.end())
-      sel_modes.push_back(mode);
-  }
-
-  auto num_modes = static_cast<uint32_t>(sel_modes.size());
-  if (!configs) {
-    *num_configs = num_modes;
-    return HWC2::Error::None;
-  }
-
-  uint32_t idx = 0;
-  for (const DrmMode &mode : sel_modes) {
-    if (idx >= *num_configs)
-      break;
-    configs[idx++] = mode.id();
-  }
-  *num_configs = idx;
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayName(uint32_t *size, char *name) {
-  supported(__func__);
-  std::ostringstream stream;
-  stream << "display-" << connector_->id();
-  std::string string = stream.str();
-  size_t length = string.length();
-  if (!name) {
-    *size = length;
-    return HWC2::Error::None;
-  }
-
-  *size = std::min<uint32_t>(static_cast<uint32_t>(length - 1), *size);
-  strncpy(name, string.c_str(), *size);
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayRequests(int32_t *display_requests,
-                                                      uint32_t *num_elements,
-                                                      hwc2_layer_t *layers,
-                                                      int32_t *layer_requests) {
-  supported(__func__);
-  // TODO(nobody): I think virtual display should request
-  //      HWC2_DISPLAY_REQUEST_WRITE_CLIENT_TARGET_TO_OUTPUT here
-  unsupported(__func__, display_requests, num_elements, layers, layer_requests);
-  *num_elements = 0;
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayType(int32_t *type) {
-  supported(__func__);
-  *type = static_cast<int32_t>(type_);
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::GetDozeSupport(int32_t *support) {
-  supported(__func__);
-  *support = 0;
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::GetHdrCapabilities(
-    uint32_t *num_types, int32_t * /*types*/, float * /*max_luminance*/,
-    float * /*max_average_luminance*/, float * /*min_luminance*/) {
-  supported(__func__);
-  *num_types = 0;
-  return HWC2::Error::None;
-}
-
-/* Find API details at:
- * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1767
- */
-HWC2::Error DrmHwcTwo::HwcDisplay::GetReleaseFences(uint32_t *num_elements,
-                                                    hwc2_layer_t *layers,
-                                                    int32_t *fences) {
-  supported(__func__);
-  uint32_t num_layers = 0;
-
-  for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) {
-    ++num_layers;
-    if (layers == nullptr || fences == nullptr)
-      continue;
-
-    if (num_layers > *num_elements) {
-      ALOGW("Overflow num_elements %d/%d", num_layers, *num_elements);
-      return HWC2::Error::None;
-    }
-
-    layers[num_layers - 1] = l.first;
-    fences[num_layers - 1] = l.second.release_fence_.Release();
-  }
-  *num_elements = num_layers;
-  return HWC2::Error::None;
-}
-
-void DrmHwcTwo::HwcDisplay::AddFenceToPresentFence(UniqueFd fd) {
-  if (!fd) {
-    return;
-  }
-
-  if (present_fence_) {
-    present_fence_ = UniqueFd(
-        sync_merge("dc_present", present_fence_.Get(), fd.Get()));
-  } else {
-    present_fence_ = std::move(fd);
-  }
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::CreateComposition(bool test) {
-  // order the layers by z-order
-  bool use_client_layer = false;
-  uint32_t client_z_order = UINT32_MAX;
-  std::map<uint32_t, DrmHwcTwo::HwcLayer *> z_map;
-  for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) {
-    switch (l.second.validated_type()) {
-      case HWC2::Composition::Device:
-        z_map.emplace(std::make_pair(l.second.z_order(), &l.second));
-        break;
-      case HWC2::Composition::Client:
-        // Place it at the z_order of the lowest client layer
-        use_client_layer = true;
-        client_z_order = std::min(client_z_order, l.second.z_order());
-        break;
-      default:
-        continue;
-    }
-  }
-  if (use_client_layer)
-    z_map.emplace(std::make_pair(client_z_order, &client_layer_));
-
-  if (z_map.empty())
-    return HWC2::Error::BadLayer;
-
-  std::vector<DrmHwcLayer> composition_layers;
-
-  // now that they're ordered by z, add them to the composition
-  for (std::pair<const uint32_t, DrmHwcTwo::HwcLayer *> &l : z_map) {
-    DrmHwcLayer layer;
-    l.second->PopulateDrmLayer(&layer);
-    int ret = layer.ImportBuffer(drm_);
-    if (ret) {
-      ALOGE("Failed to import layer, ret=%d", ret);
-      return HWC2::Error::NoResources;
-    }
-    composition_layers.emplace_back(std::move(layer));
-  }
-
-  auto composition = std::make_unique<DrmDisplayComposition>(crtc_,
-                                                             planner_.get());
-
-  // TODO(nobody): Don't always assume geometry changed
-  int ret = composition->SetLayers(composition_layers.data(),
-                                   composition_layers.size(), true);
-  if (ret) {
-    ALOGE("Failed to set layers in the composition ret=%d", ret);
-    return HWC2::Error::BadLayer;
-  }
-
-  std::vector<DrmPlane *> primary_planes(primary_planes_);
-  std::vector<DrmPlane *> overlay_planes(overlay_planes_);
-  ret = composition->Plan(&primary_planes, &overlay_planes);
-  if (ret) {
-    ALOGV("Failed to plan the composition ret=%d", ret);
-    return HWC2::Error::BadConfig;
-  }
-
-  // Disable the planes we're not using
-  for (auto i = primary_planes.begin(); i != primary_planes.end();) {
-    composition->AddPlaneDisable(*i);
-    i = primary_planes.erase(i);
-  }
-  for (auto i = overlay_planes.begin(); i != overlay_planes.end();) {
-    composition->AddPlaneDisable(*i);
-    i = overlay_planes.erase(i);
-  }
-
-  if (test) {
-    ret = compositor_.TestComposition(composition.get());
-  } else {
-    ret = compositor_.ApplyComposition(std::move(composition));
-    AddFenceToPresentFence(compositor_.TakeOutFence());
-  }
-  if (ret) {
-    if (!test)
-      ALOGE("Failed to apply the frame composition ret=%d", ret);
-    return HWC2::Error::BadParameter;
-  }
-  return HWC2::Error::None;
-}
-
-/* Find API details at:
- * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1805
- */
-HWC2::Error DrmHwcTwo::HwcDisplay::PresentDisplay(int32_t *present_fence) {
-  supported(__func__);
-  HWC2::Error ret;
-
-  ++total_stats_.total_frames_;
-
-  ret = CreateComposition(false);
-  if (ret != HWC2::Error::None)
-    ++total_stats_.failed_kms_present_;
-
-  if (ret == HWC2::Error::BadLayer) {
-    // Can we really have no client or device layers?
-    *present_fence = -1;
-    return HWC2::Error::None;
-  }
-  if (ret != HWC2::Error::None)
-    return ret;
-
-  *present_fence = present_fence_.Release();
-
-  ++frame_no_;
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::SetActiveConfig(hwc2_config_t config) {
-  supported(__func__);
-  auto mode = std::find_if(connector_->modes().begin(),
-                           connector_->modes().end(),
-                           [config](DrmMode const &m) {
-                             return m.id() == config;
-                           });
-  if (mode == connector_->modes().end()) {
-    ALOGE("Could not find active mode for %d", config);
-    return HWC2::Error::BadConfig;
-  }
-
-  auto composition = std::make_unique<DrmDisplayComposition>(crtc_,
-                                                             planner_.get());
-  int ret = composition->SetDisplayMode(*mode);
-  if (ret) {
-    return HWC2::Error::BadConfig;
-  }
-  ret = compositor_.ApplyComposition(std::move(composition));
-  if (ret) {
-    ALOGE("Failed to queue dpms composition on %d", ret);
-    return HWC2::Error::BadConfig;
-  }
-
-  connector_->set_active_mode(*mode);
-
-  // Setup the client layer's dimensions
-  hwc_rect_t display_frame = {.left = 0,
-                              .top = 0,
-                              .right = static_cast<int>(mode->h_display()),
-                              .bottom = static_cast<int>(mode->v_display())};
-  client_layer_.SetLayerDisplayFrame(display_frame);
-
-  return HWC2::Error::None;
-}
-
-/* Find API details at:
- * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1861
- */
-HWC2::Error DrmHwcTwo::HwcDisplay::SetClientTarget(buffer_handle_t target,
-                                                   int32_t acquire_fence,
-                                                   int32_t dataspace,
-                                                   hwc_region_t /*damage*/) {
-  supported(__func__);
-
-  client_layer_.set_buffer(target);
-  client_layer_.acquire_fence_ = UniqueFd(acquire_fence);
-  client_layer_.SetLayerDataspace(dataspace);
-
-  /* TODO: Do not update source_crop every call.
-   * It makes sense to do it once after every hotplug event. */
-  hwc_drm_bo bo{};
-  BufferInfoGetter::GetInstance()->ConvertBoInfo(target, &bo);
-
-  hwc_frect_t source_crop = {.left = 0.0F,
-                             .top = 0.0F,
-                             .right = bo.width + 0.0F,
-                             .bottom = bo.height + 0.0F};
-  client_layer_.SetLayerSourceCrop(source_crop);
-
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::SetColorMode(int32_t mode) {
-  supported(__func__);
-
-  if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_BT2100_HLG)
-    return HWC2::Error::BadParameter;
-
-  if (mode != HAL_COLOR_MODE_NATIVE)
-    return HWC2::Error::Unsupported;
-
-  color_mode_ = mode;
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::SetColorTransform(const float *matrix,
-                                                     int32_t hint) {
-  supported(__func__);
-  if (hint < HAL_COLOR_TRANSFORM_IDENTITY ||
-      hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA)
-    return HWC2::Error::BadParameter;
-
-  if (!matrix && hint == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX)
-    return HWC2::Error::BadParameter;
-
-  color_transform_hint_ = static_cast<android_color_transform_t>(hint);
-  if (color_transform_hint_ == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX)
-    std::copy(matrix, matrix + MATRIX_SIZE, color_transform_matrix_.begin());
-
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::SetOutputBuffer(buffer_handle_t buffer,
-                                                   int32_t release_fence) {
-  supported(__func__);
-  // TODO(nobody): Need virtual display support
-  return unsupported(__func__, buffer, release_fence);
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::SetPowerMode(int32_t mode_in) {
-  supported(__func__);
-  uint64_t dpms_value = 0;
-  auto mode = static_cast<HWC2::PowerMode>(mode_in);
-  switch (mode) {
-    case HWC2::PowerMode::Off:
-      dpms_value = DRM_MODE_DPMS_OFF;
-      break;
-    case HWC2::PowerMode::On:
-      dpms_value = DRM_MODE_DPMS_ON;
-      break;
-    case HWC2::PowerMode::Doze:
-    case HWC2::PowerMode::DozeSuspend:
-      return HWC2::Error::Unsupported;
-    default:
-      ALOGI("Power mode %d is unsupported\n", mode);
-      return HWC2::Error::BadParameter;
-  };
-
-  auto composition = std::make_unique<DrmDisplayComposition>(crtc_,
-                                                             planner_.get());
-  composition->SetDpmsMode(dpms_value);
-  int ret = compositor_.ApplyComposition(std::move(composition));
-  if (ret) {
-    ALOGE("Failed to apply the dpms composition ret=%d", ret);
-    return HWC2::Error::BadParameter;
-  }
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::SetVsyncEnabled(int32_t enabled) {
-  supported(__func__);
-  vsync_worker_.VSyncControl(HWC2_VSYNC_ENABLE == enabled);
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::ValidateDisplay(uint32_t *num_types,
-                                                   uint32_t *num_requests) {
-  supported(__func__);
-
-  return backend_->ValidateDisplay(this, num_types, num_requests);
-}
-
-std::vector<DrmHwcTwo::HwcLayer *>
-DrmHwcTwo::HwcDisplay::GetOrderLayersByZPos() {
-  std::vector<DrmHwcTwo::HwcLayer *> ordered_layers;
-  ordered_layers.reserve(layers_.size());
-
-  for (auto &[handle, layer] : layers_) {
-    ordered_layers.emplace_back(&layer);
-  }
-
-  std::sort(std::begin(ordered_layers), std::end(ordered_layers),
-            [](const DrmHwcTwo::HwcLayer *lhs, const DrmHwcTwo::HwcLayer *rhs) {
-              return lhs->z_order() < rhs->z_order();
-            });
-
-  return ordered_layers;
-}
-
-#if PLATFORM_SDK_VERSION > 29
-HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayConnectionType(uint32_t *outType) {
-  if (connector_->internal())
-    *outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::Internal);
-  else if (connector_->external())
-    *outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::External);
-  else
-    return HWC2::Error::BadConfig;
-
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayVsyncPeriod(
-    hwc2_vsync_period_t *outVsyncPeriod /* ns */) {
-  supported(__func__);
-  DrmMode const &mode = connector_->active_mode();
-  if (mode.id() == 0)
-    return HWC2::Error::BadConfig;
-
-  *outVsyncPeriod = 1E9 / mode.v_refresh();
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::SetActiveConfigWithConstraints(
-    hwc2_config_t /*config*/,
-    hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints,
-    hwc_vsync_period_change_timeline_t *outTimeline) {
-  supported(__func__);
-
-  if (vsyncPeriodChangeConstraints == nullptr || outTimeline == nullptr) {
-    return HWC2::Error::BadParameter;
-  }
-
-  return HWC2::Error::BadConfig;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::SetAutoLowLatencyMode(bool /*on*/) {
-  return HWC2::Error::Unsupported;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::GetSupportedContentTypes(
-    uint32_t *outNumSupportedContentTypes,
-    const uint32_t *outSupportedContentTypes) {
-  if (outSupportedContentTypes == nullptr)
-    *outNumSupportedContentTypes = 0;
-
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::SetContentType(int32_t contentType) {
-  supported(__func__);
-
-  if (contentType != HWC2_CONTENT_TYPE_NONE)
-    return HWC2::Error::Unsupported;
-
-  /* TODO: Map to the DRM Connector property:
-   * https://elixir.bootlin.com/linux/v5.4-rc5/source/drivers/gpu/drm/drm_connector.c#L809
-   */
-
-  return HWC2::Error::None;
-}
-#endif
-
-#if PLATFORM_SDK_VERSION > 28
-HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayIdentificationData(
-    uint8_t *outPort, uint32_t *outDataSize, uint8_t *outData) {
-  supported(__func__);
-
-  drmModePropertyBlobPtr blob = nullptr;
-
-  if (connector_->GetEdidBlob(blob)) {
-    ALOGE("Failed to get edid property value.");
-    return HWC2::Error::Unsupported;
-  }
-
-  if (outData) {
-    *outDataSize = std::min(*outDataSize, blob->length);
-    memcpy(outData, blob->data, *outDataSize);
-  } else {
-    *outDataSize = blob->length;
-  }
-  *outPort = connector_->id();
-
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayCapabilities(
-    uint32_t *outNumCapabilities, uint32_t *outCapabilities) {
-  unsupported(__func__, outCapabilities);
-
-  if (outNumCapabilities == nullptr) {
-    return HWC2::Error::BadParameter;
-  }
-
-  *outNumCapabilities = 0;
-
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayBrightnessSupport(
-    bool *supported) {
-  *supported = false;
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::SetDisplayBrightness(
-    float /* brightness */) {
-  return HWC2::Error::Unsupported;
-}
-
-#endif /* PLATFORM_SDK_VERSION > 28 */
-
-#if PLATFORM_SDK_VERSION > 27
-
-HWC2::Error DrmHwcTwo::HwcDisplay::GetRenderIntents(
-    int32_t mode, uint32_t *outNumIntents,
-    int32_t * /*android_render_intent_v1_1_t*/ outIntents) {
-  if (mode != HAL_COLOR_MODE_NATIVE) {
-    return HWC2::Error::BadParameter;
-  }
-
-  if (outIntents == nullptr) {
-    *outNumIntents = 1;
-    return HWC2::Error::None;
-  }
-  *outNumIntents = 1;
-  outIntents[0] = HAL_RENDER_INTENT_COLORIMETRIC;
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcDisplay::SetColorModeWithIntent(int32_t mode,
-                                                          int32_t intent) {
-  if (intent < HAL_RENDER_INTENT_COLORIMETRIC ||
-      intent > HAL_RENDER_INTENT_TONE_MAP_ENHANCE)
-    return HWC2::Error::BadParameter;
-
-  if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_BT2100_HLG)
-    return HWC2::Error::BadParameter;
-
-  if (mode != HAL_COLOR_MODE_NATIVE)
-    return HWC2::Error::Unsupported;
-
-  if (intent != HAL_RENDER_INTENT_COLORIMETRIC)
-    return HWC2::Error::Unsupported;
-
-  color_mode_ = mode;
-  return HWC2::Error::None;
-}
-
-#endif /* PLATFORM_SDK_VERSION > 27 */
-
-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);
-  return HWC2::Error::None;
-}
-
-/* Find API details at:
- * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=2314
- */
-HWC2::Error DrmHwcTwo::HwcLayer::SetLayerBuffer(buffer_handle_t buffer,
-                                                int32_t acquire_fence) {
-  supported(__func__);
-
-  set_buffer(buffer);
-  acquire_fence_ = UniqueFd(acquire_fence);
-  return HWC2::Error::None;
-}
-
-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;
-}
-
-HWC2::Error DrmHwcTwo::HwcLayer::SetLayerCompositionType(int32_t type) {
-  sf_type_ = static_cast<HWC2::Composition>(type);
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcLayer::SetLayerDataspace(int32_t dataspace) {
-  supported(__func__);
-  dataspace_ = static_cast<android_dataspace_t>(dataspace);
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcLayer::SetLayerDisplayFrame(hwc_rect_t frame) {
-  supported(__func__);
-  display_frame_ = frame;
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcLayer::SetLayerPlaneAlpha(float alpha) {
-  supported(__func__);
-  alpha_ = alpha;
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSidebandStream(
-    const native_handle_t *stream) {
-  supported(__func__);
-  // TODO(nobody): We don't support sideband
-  return unsupported(__func__, stream);
-}
-
-HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSourceCrop(hwc_frect_t crop) {
-  supported(__func__);
-  source_crop_ = crop;
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSurfaceDamage(hwc_region_t damage) {
-  supported(__func__);
-  // TODO(nobody): We don't use surface damage, marking as unsupported
-  unsupported(__func__, damage);
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcLayer::SetLayerTransform(int32_t transform) {
-  supported(__func__);
-  transform_ = static_cast<HWC2::Transform>(transform);
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcLayer::SetLayerVisibleRegion(hwc_region_t visible) {
-  supported(__func__);
-  // TODO(nobody): We don't use this information, marking as unsupported
-  unsupported(__func__, visible);
-  return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::HwcLayer::SetLayerZOrder(uint32_t order) {
-  supported(__func__);
-  z_order_ = order;
-  return HWC2::Error::None;
-}
-
-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->source_crop = source_crop_;
-  layer->SetTransform(static_cast<int32_t>(transform_));
-  layer->dataspace = dataspace_;
-}
-
-void DrmHwcTwo::HandleDisplayHotplug(hwc2_display_t displayid, int state) {
-  const std::lock_guard<std::mutex> lock(hotplug_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);
-}
-
-void DrmHwcTwo::HandleInitialHotplugState(DrmDevice *drmDevice) {
-  for (const auto &conn : drmDevice->connectors()) {
-    if (conn->state() != DRM_MODE_CONNECTED)
-      continue;
-    HandleDisplayHotplug(conn->display(), conn->state());
-  }
-}
-
-void DrmHwcTwo::DrmHotplugHandler::HandleEvent(uint64_t timestamp_us) {
-  for (const auto &conn : drm_->connectors()) {
-    drmModeConnection old_state = conn->state();
-    drmModeConnection cur_state = conn->UpdateModes()
-                                      ? DRM_MODE_UNKNOWNCONNECTION
-                                      : conn->state();
-
-    if (cur_state == old_state)
-      continue;
-
-    ALOGI("%s event @%" PRIu64 " for connector %u on display %d",
-          cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", timestamp_us,
-          conn->id(), conn->display());
-
-    int display_id = conn->display();
-    if (cur_state == DRM_MODE_CONNECTED) {
-      auto &display = hwc2_->displays_.at(display_id);
-      display.ChosePreferredConfig();
-    } else {
-      auto &display = hwc2_->displays_.at(display_id);
-      display.ClearDisplay();
-    }
-
-    hwc2_->HandleDisplayHotplug(display_id, cur_state);
-  }
-}
-
-// static
-int DrmHwcTwo::HookDevClose(hw_device_t * /*dev*/) {
-  unsupported(__func__);
-  return 0;
-}
-
-// static
-void DrmHwcTwo::HookDevGetCapabilities(hwc2_device_t * /*dev*/,
-                                       uint32_t *out_count,
-                                       int32_t * /*out_capabilities*/) {
-  supported(__func__);
-  *out_count = 0;
-}
-
-// static
-hwc2_function_pointer_t DrmHwcTwo::HookDevGetFunction(
-    struct hwc2_device * /*dev*/, int32_t descriptor) {
-  supported(__func__);
-  auto func = static_cast<HWC2::FunctionDescriptor>(descriptor);
-  switch (func) {
-    // Device functions
-    case HWC2::FunctionDescriptor::CreateVirtualDisplay:
-      return ToHook<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>(
-          DeviceHook<int32_t, decltype(&DrmHwcTwo::CreateVirtualDisplay),
-                     &DrmHwcTwo::CreateVirtualDisplay, uint32_t, uint32_t,
-                     int32_t *, hwc2_display_t *>);
-    case HWC2::FunctionDescriptor::DestroyVirtualDisplay:
-      return ToHook<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>(
-          DeviceHook<int32_t, decltype(&DrmHwcTwo::DestroyVirtualDisplay),
-                     &DrmHwcTwo::DestroyVirtualDisplay, hwc2_display_t>);
-    case HWC2::FunctionDescriptor::Dump:
-      return ToHook<HWC2_PFN_DUMP>(
-          DeviceHook<void, decltype(&DrmHwcTwo::Dump), &DrmHwcTwo::Dump,
-                     uint32_t *, char *>);
-    case HWC2::FunctionDescriptor::GetMaxVirtualDisplayCount:
-      return ToHook<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>(
-          DeviceHook<uint32_t, decltype(&DrmHwcTwo::GetMaxVirtualDisplayCount),
-                     &DrmHwcTwo::GetMaxVirtualDisplayCount>);
-    case HWC2::FunctionDescriptor::RegisterCallback:
-      return ToHook<HWC2_PFN_REGISTER_CALLBACK>(
-          DeviceHook<int32_t, decltype(&DrmHwcTwo::RegisterCallback),
-                     &DrmHwcTwo::RegisterCallback, int32_t,
-                     hwc2_callback_data_t, hwc2_function_pointer_t>);
-
-    // Display functions
-    case HWC2::FunctionDescriptor::AcceptDisplayChanges:
-      return ToHook<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>(
-          DisplayHook<decltype(&HwcDisplay::AcceptDisplayChanges),
-                      &HwcDisplay::AcceptDisplayChanges>);
-    case HWC2::FunctionDescriptor::CreateLayer:
-      return ToHook<HWC2_PFN_CREATE_LAYER>(
-          DisplayHook<decltype(&HwcDisplay::CreateLayer),
-                      &HwcDisplay::CreateLayer, hwc2_layer_t *>);
-    case HWC2::FunctionDescriptor::DestroyLayer:
-      return ToHook<HWC2_PFN_DESTROY_LAYER>(
-          DisplayHook<decltype(&HwcDisplay::DestroyLayer),
-                      &HwcDisplay::DestroyLayer, hwc2_layer_t>);
-    case HWC2::FunctionDescriptor::GetActiveConfig:
-      return ToHook<HWC2_PFN_GET_ACTIVE_CONFIG>(
-          DisplayHook<decltype(&HwcDisplay::GetActiveConfig),
-                      &HwcDisplay::GetActiveConfig, hwc2_config_t *>);
-    case HWC2::FunctionDescriptor::GetChangedCompositionTypes:
-      return ToHook<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>(
-          DisplayHook<decltype(&HwcDisplay::GetChangedCompositionTypes),
-                      &HwcDisplay::GetChangedCompositionTypes, uint32_t *,
-                      hwc2_layer_t *, int32_t *>);
-    case HWC2::FunctionDescriptor::GetClientTargetSupport:
-      return ToHook<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(
-          DisplayHook<decltype(&HwcDisplay::GetClientTargetSupport),
-                      &HwcDisplay::GetClientTargetSupport, uint32_t, uint32_t,
-                      int32_t, int32_t>);
-    case HWC2::FunctionDescriptor::GetColorModes:
-      return ToHook<HWC2_PFN_GET_COLOR_MODES>(
-          DisplayHook<decltype(&HwcDisplay::GetColorModes),
-                      &HwcDisplay::GetColorModes, uint32_t *, int32_t *>);
-    case HWC2::FunctionDescriptor::GetDisplayAttribute:
-      return ToHook<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(
-          DisplayHook<decltype(&HwcDisplay::GetDisplayAttribute),
-                      &HwcDisplay::GetDisplayAttribute, hwc2_config_t, int32_t,
-                      int32_t *>);
-    case HWC2::FunctionDescriptor::GetDisplayConfigs:
-      return ToHook<HWC2_PFN_GET_DISPLAY_CONFIGS>(
-          DisplayHook<decltype(&HwcDisplay::GetDisplayConfigs),
-                      &HwcDisplay::GetDisplayConfigs, uint32_t *,
-                      hwc2_config_t *>);
-    case HWC2::FunctionDescriptor::GetDisplayName:
-      return ToHook<HWC2_PFN_GET_DISPLAY_NAME>(
-          DisplayHook<decltype(&HwcDisplay::GetDisplayName),
-                      &HwcDisplay::GetDisplayName, uint32_t *, char *>);
-    case HWC2::FunctionDescriptor::GetDisplayRequests:
-      return ToHook<HWC2_PFN_GET_DISPLAY_REQUESTS>(
-          DisplayHook<decltype(&HwcDisplay::GetDisplayRequests),
-                      &HwcDisplay::GetDisplayRequests, int32_t *, uint32_t *,
-                      hwc2_layer_t *, int32_t *>);
-    case HWC2::FunctionDescriptor::GetDisplayType:
-      return ToHook<HWC2_PFN_GET_DISPLAY_TYPE>(
-          DisplayHook<decltype(&HwcDisplay::GetDisplayType),
-                      &HwcDisplay::GetDisplayType, int32_t *>);
-    case HWC2::FunctionDescriptor::GetDozeSupport:
-      return ToHook<HWC2_PFN_GET_DOZE_SUPPORT>(
-          DisplayHook<decltype(&HwcDisplay::GetDozeSupport),
-                      &HwcDisplay::GetDozeSupport, int32_t *>);
-    case HWC2::FunctionDescriptor::GetHdrCapabilities:
-      return ToHook<HWC2_PFN_GET_HDR_CAPABILITIES>(
-          DisplayHook<decltype(&HwcDisplay::GetHdrCapabilities),
-                      &HwcDisplay::GetHdrCapabilities, uint32_t *, int32_t *,
-                      float *, float *, float *>);
-    case HWC2::FunctionDescriptor::GetReleaseFences:
-      return ToHook<HWC2_PFN_GET_RELEASE_FENCES>(
-          DisplayHook<decltype(&HwcDisplay::GetReleaseFences),
-                      &HwcDisplay::GetReleaseFences, uint32_t *, hwc2_layer_t *,
-                      int32_t *>);
-    case HWC2::FunctionDescriptor::PresentDisplay:
-      return ToHook<HWC2_PFN_PRESENT_DISPLAY>(
-          DisplayHook<decltype(&HwcDisplay::PresentDisplay),
-                      &HwcDisplay::PresentDisplay, int32_t *>);
-    case HWC2::FunctionDescriptor::SetActiveConfig:
-      return ToHook<HWC2_PFN_SET_ACTIVE_CONFIG>(
-          DisplayHook<decltype(&HwcDisplay::SetActiveConfig),
-                      &HwcDisplay::SetActiveConfig, hwc2_config_t>);
-    case HWC2::FunctionDescriptor::SetClientTarget:
-      return ToHook<HWC2_PFN_SET_CLIENT_TARGET>(
-          DisplayHook<decltype(&HwcDisplay::SetClientTarget),
-                      &HwcDisplay::SetClientTarget, buffer_handle_t, int32_t,
-                      int32_t, hwc_region_t>);
-    case HWC2::FunctionDescriptor::SetColorMode:
-      return ToHook<HWC2_PFN_SET_COLOR_MODE>(
-          DisplayHook<decltype(&HwcDisplay::SetColorMode),
-                      &HwcDisplay::SetColorMode, int32_t>);
-    case HWC2::FunctionDescriptor::SetColorTransform:
-      return ToHook<HWC2_PFN_SET_COLOR_TRANSFORM>(
-          DisplayHook<decltype(&HwcDisplay::SetColorTransform),
-                      &HwcDisplay::SetColorTransform, const float *, int32_t>);
-    case HWC2::FunctionDescriptor::SetOutputBuffer:
-      return ToHook<HWC2_PFN_SET_OUTPUT_BUFFER>(
-          DisplayHook<decltype(&HwcDisplay::SetOutputBuffer),
-                      &HwcDisplay::SetOutputBuffer, buffer_handle_t, int32_t>);
-    case HWC2::FunctionDescriptor::SetPowerMode:
-      return ToHook<HWC2_PFN_SET_POWER_MODE>(
-          DisplayHook<decltype(&HwcDisplay::SetPowerMode),
-                      &HwcDisplay::SetPowerMode, int32_t>);
-    case HWC2::FunctionDescriptor::SetVsyncEnabled:
-      return ToHook<HWC2_PFN_SET_VSYNC_ENABLED>(
-          DisplayHook<decltype(&HwcDisplay::SetVsyncEnabled),
-                      &HwcDisplay::SetVsyncEnabled, int32_t>);
-    case HWC2::FunctionDescriptor::ValidateDisplay:
-      return ToHook<HWC2_PFN_VALIDATE_DISPLAY>(
-          DisplayHook<decltype(&HwcDisplay::ValidateDisplay),
-                      &HwcDisplay::ValidateDisplay, uint32_t *, uint32_t *>);
-#if PLATFORM_SDK_VERSION > 27
-    case HWC2::FunctionDescriptor::GetRenderIntents:
-      return ToHook<HWC2_PFN_GET_RENDER_INTENTS>(
-          DisplayHook<decltype(&HwcDisplay::GetRenderIntents),
-                      &HwcDisplay::GetRenderIntents, int32_t, uint32_t *,
-                      int32_t *>);
-    case HWC2::FunctionDescriptor::SetColorModeWithRenderIntent:
-      return ToHook<HWC2_PFN_SET_COLOR_MODE_WITH_RENDER_INTENT>(
-          DisplayHook<decltype(&HwcDisplay::SetColorModeWithIntent),
-                      &HwcDisplay::SetColorModeWithIntent, int32_t, int32_t>);
-#endif
-#if PLATFORM_SDK_VERSION > 28
-    case HWC2::FunctionDescriptor::GetDisplayIdentificationData:
-      return ToHook<HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA>(
-          DisplayHook<decltype(&HwcDisplay::GetDisplayIdentificationData),
-                      &HwcDisplay::GetDisplayIdentificationData, uint8_t *,
-                      uint32_t *, uint8_t *>);
-    case HWC2::FunctionDescriptor::GetDisplayCapabilities:
-      return ToHook<HWC2_PFN_GET_DISPLAY_CAPABILITIES>(
-          DisplayHook<decltype(&HwcDisplay::GetDisplayCapabilities),
-                      &HwcDisplay::GetDisplayCapabilities, uint32_t *,
-                      uint32_t *>);
-    case HWC2::FunctionDescriptor::GetDisplayBrightnessSupport:
-      return ToHook<HWC2_PFN_GET_DISPLAY_BRIGHTNESS_SUPPORT>(
-          DisplayHook<decltype(&HwcDisplay::GetDisplayBrightnessSupport),
-                      &HwcDisplay::GetDisplayBrightnessSupport, bool *>);
-    case HWC2::FunctionDescriptor::SetDisplayBrightness:
-      return ToHook<HWC2_PFN_SET_DISPLAY_BRIGHTNESS>(
-          DisplayHook<decltype(&HwcDisplay::SetDisplayBrightness),
-                      &HwcDisplay::SetDisplayBrightness, float>);
-#endif /* PLATFORM_SDK_VERSION > 28 */
-#if PLATFORM_SDK_VERSION > 29
-    case HWC2::FunctionDescriptor::GetDisplayConnectionType:
-      return ToHook<HWC2_PFN_GET_DISPLAY_CONNECTION_TYPE>(
-          DisplayHook<decltype(&HwcDisplay::GetDisplayConnectionType),
-                      &HwcDisplay::GetDisplayConnectionType, uint32_t *>);
-    case HWC2::FunctionDescriptor::GetDisplayVsyncPeriod:
-      return ToHook<HWC2_PFN_GET_DISPLAY_VSYNC_PERIOD>(
-          DisplayHook<decltype(&HwcDisplay::GetDisplayVsyncPeriod),
-                      &HwcDisplay::GetDisplayVsyncPeriod,
-                      hwc2_vsync_period_t *>);
-    case HWC2::FunctionDescriptor::SetActiveConfigWithConstraints:
-      return ToHook<HWC2_PFN_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS>(
-          DisplayHook<decltype(&HwcDisplay::SetActiveConfigWithConstraints),
-                      &HwcDisplay::SetActiveConfigWithConstraints,
-                      hwc2_config_t, hwc_vsync_period_change_constraints_t *,
-                      hwc_vsync_period_change_timeline_t *>);
-    case HWC2::FunctionDescriptor::SetAutoLowLatencyMode:
-      return ToHook<HWC2_PFN_SET_AUTO_LOW_LATENCY_MODE>(
-          DisplayHook<decltype(&HwcDisplay::SetAutoLowLatencyMode),
-                      &HwcDisplay::SetAutoLowLatencyMode, bool>);
-    case HWC2::FunctionDescriptor::GetSupportedContentTypes:
-      return ToHook<HWC2_PFN_GET_SUPPORTED_CONTENT_TYPES>(
-          DisplayHook<decltype(&HwcDisplay::GetSupportedContentTypes),
-                      &HwcDisplay::GetSupportedContentTypes, uint32_t *,
-                      uint32_t *>);
-    case HWC2::FunctionDescriptor::SetContentType:
-      return ToHook<HWC2_PFN_SET_CONTENT_TYPE>(
-          DisplayHook<decltype(&HwcDisplay::SetContentType),
-                      &HwcDisplay::SetContentType, int32_t>);
-#endif
-    // Layer functions
-    case HWC2::FunctionDescriptor::SetCursorPosition:
-      return ToHook<HWC2_PFN_SET_CURSOR_POSITION>(
-          LayerHook<decltype(&HwcLayer::SetCursorPosition),
-                    &HwcLayer::SetCursorPosition, int32_t, int32_t>);
-    case HWC2::FunctionDescriptor::SetLayerBlendMode:
-      return ToHook<HWC2_PFN_SET_LAYER_BLEND_MODE>(
-          LayerHook<decltype(&HwcLayer::SetLayerBlendMode),
-                    &HwcLayer::SetLayerBlendMode, int32_t>);
-    case HWC2::FunctionDescriptor::SetLayerBuffer:
-      return ToHook<HWC2_PFN_SET_LAYER_BUFFER>(
-          LayerHook<decltype(&HwcLayer::SetLayerBuffer),
-                    &HwcLayer::SetLayerBuffer, buffer_handle_t, int32_t>);
-    case HWC2::FunctionDescriptor::SetLayerColor:
-      return ToHook<HWC2_PFN_SET_LAYER_COLOR>(
-          LayerHook<decltype(&HwcLayer::SetLayerColor),
-                    &HwcLayer::SetLayerColor, hwc_color_t>);
-    case HWC2::FunctionDescriptor::SetLayerCompositionType:
-      return ToHook<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>(
-          LayerHook<decltype(&HwcLayer::SetLayerCompositionType),
-                    &HwcLayer::SetLayerCompositionType, int32_t>);
-    case HWC2::FunctionDescriptor::SetLayerDataspace:
-      return ToHook<HWC2_PFN_SET_LAYER_DATASPACE>(
-          LayerHook<decltype(&HwcLayer::SetLayerDataspace),
-                    &HwcLayer::SetLayerDataspace, int32_t>);
-    case HWC2::FunctionDescriptor::SetLayerDisplayFrame:
-      return ToHook<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>(
-          LayerHook<decltype(&HwcLayer::SetLayerDisplayFrame),
-                    &HwcLayer::SetLayerDisplayFrame, hwc_rect_t>);
-    case HWC2::FunctionDescriptor::SetLayerPlaneAlpha:
-      return ToHook<HWC2_PFN_SET_LAYER_PLANE_ALPHA>(
-          LayerHook<decltype(&HwcLayer::SetLayerPlaneAlpha),
-                    &HwcLayer::SetLayerPlaneAlpha, float>);
-    case HWC2::FunctionDescriptor::SetLayerSidebandStream:
-      return ToHook<HWC2_PFN_SET_LAYER_SIDEBAND_STREAM>(
-          LayerHook<decltype(&HwcLayer::SetLayerSidebandStream),
-                    &HwcLayer::SetLayerSidebandStream,
-                    const native_handle_t *>);
-    case HWC2::FunctionDescriptor::SetLayerSourceCrop:
-      return ToHook<HWC2_PFN_SET_LAYER_SOURCE_CROP>(
-          LayerHook<decltype(&HwcLayer::SetLayerSourceCrop),
-                    &HwcLayer::SetLayerSourceCrop, hwc_frect_t>);
-    case HWC2::FunctionDescriptor::SetLayerSurfaceDamage:
-      return ToHook<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>(
-          LayerHook<decltype(&HwcLayer::SetLayerSurfaceDamage),
-                    &HwcLayer::SetLayerSurfaceDamage, hwc_region_t>);
-    case HWC2::FunctionDescriptor::SetLayerTransform:
-      return ToHook<HWC2_PFN_SET_LAYER_TRANSFORM>(
-          LayerHook<decltype(&HwcLayer::SetLayerTransform),
-                    &HwcLayer::SetLayerTransform, int32_t>);
-    case HWC2::FunctionDescriptor::SetLayerVisibleRegion:
-      return ToHook<HWC2_PFN_SET_LAYER_VISIBLE_REGION>(
-          LayerHook<decltype(&HwcLayer::SetLayerVisibleRegion),
-                    &HwcLayer::SetLayerVisibleRegion, hwc_region_t>);
-    case HWC2::FunctionDescriptor::SetLayerZOrder:
-      return ToHook<HWC2_PFN_SET_LAYER_Z_ORDER>(
-          LayerHook<decltype(&HwcLayer::SetLayerZOrder),
-                    &HwcLayer::SetLayerZOrder, uint32_t>);
-    case HWC2::FunctionDescriptor::Invalid:
-    default:
-      return nullptr;
-  }
-}
-
-// static
-int DrmHwcTwo::HookDevOpen(const struct hw_module_t *module, const char *name,
-                           struct hw_device_t **dev) {
-  supported(__func__);
-  if (strcmp(name, HWC_HARDWARE_COMPOSER) != 0) {
-    ALOGE("Invalid module name- %s", name);
-    return -EINVAL;
-  }
-
-  std::unique_ptr<DrmHwcTwo> ctx(new DrmHwcTwo());
-  if (!ctx) {
-    ALOGE("Failed to allocate DrmHwcTwo");
-    return -ENOMEM;
-  }
-
-  HWC2::Error err = ctx->Init();
-  if (err != HWC2::Error::None) {
-    ALOGE("Failed to initialize DrmHwcTwo err=%d\n", err);
-    return -EINVAL;
-  }
-
-  ctx->common.module = (hw_module_t *)module;
-  *dev = &ctx->common;
-  ctx.release();  // NOLINT(bugprone-unused-return-value)
-  return 0;
-}
-}  // namespace android
-
-// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
-static struct hw_module_methods_t hwc2_module_methods = {
-    .open = android::DrmHwcTwo::HookDevOpen,
-};
-
-// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
-hw_module_t HAL_MODULE_INFO_SYM = {
-    .tag = HARDWARE_MODULE_TAG,
-    .module_api_version = HARDWARE_MODULE_API_VERSION(2, 0),
-    .id = HWC_HARDWARE_MODULE_ID,
-    .name = "DrmHwcTwo module",
-    .author = "The Android Open Source Project",
-    .methods = &hwc2_module_methods,
-    .dso = nullptr,
-    .reserved = {0},
-};
diff --git a/DrmHwcTwo.h b/DrmHwcTwo.h
deleted file mode 100644
index 111c664..0000000
--- a/DrmHwcTwo.h
+++ /dev/null
@@ -1,425 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_DRM_HWC_TWO_H_
-#define ANDROID_DRM_HWC_TWO_H_
-
-#include <hardware/hwcomposer2.h>
-#include <math.h>
-
-#include <array>
-#include <map>
-
-#include "compositor/DrmDisplayCompositor.h"
-#include "compositor/Planner.h"
-#include "drm/ResourceManager.h"
-#include "drm/VSyncWorker.h"
-#include "drmhwcomposer.h"
-
-namespace android {
-
-class Backend;
-
-class DrmHwcTwo : public hwc2_device_t {
- public:
-  static int HookDevOpen(const struct hw_module_t *module, const char *name,
-                         struct hw_device_t **dev);
-
-  DrmHwcTwo();
-
-  HWC2::Error Init();
-
-  hwc2_callback_data_t hotplug_callback_data_ = NULL;
-  HWC2_PFN_HOTPLUG hotplug_callback_hook_ = NULL;
-  std::mutex hotplug_callback_lock;
-
-  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);
-  }
-
-  class HwcLayer {
-   public:
-    HWC2::Composition sf_type() const {
-      return sf_type_;
-    }
-    HWC2::Composition validated_type() const {
-      return validated_type_;
-    }
-    void accept_type_change() {
-      sf_type_ = validated_type_;
-    }
-    void set_validated_type(HWC2::Composition type) {
-      validated_type_ = type;
-    }
-    bool type_changed() const {
-      return sf_type_ != validated_type_;
-    }
-
-    uint32_t z_order() const {
-      return z_order_;
-    }
-
-    buffer_handle_t buffer() {
-      return buffer_;
-    }
-    void set_buffer(buffer_handle_t buffer) {
-      buffer_ = buffer;
-    }
-
-    hwc_rect_t display_frame() {
-      return display_frame_;
-    }
-
-    void PopulateDrmLayer(DrmHwcLayer *layer);
-
-    bool RequireScalingOrPhasing() {
-      float src_width = source_crop_.right - source_crop_.left;
-      float src_height = source_crop_.bottom - source_crop_.top;
-
-      float dest_width = display_frame_.right - display_frame_.left;
-      float dest_height = display_frame_.bottom - display_frame_.top;
-
-      bool scaling = src_width != dest_width || src_height != dest_height;
-      bool phasing = (source_crop_.left - floor(source_crop_.left) != 0) ||
-                     (source_crop_.top - floor(source_crop_.top) != 0);
-      return scaling || phasing;
-    }
-
-    // Layer hooks
-    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 SetLayerCompositionType(int32_t type);
-    HWC2::Error SetLayerDataspace(int32_t dataspace);
-    HWC2::Error SetLayerDisplayFrame(hwc_rect_t frame);
-    HWC2::Error SetLayerPlaneAlpha(float alpha);
-    HWC2::Error SetLayerSidebandStream(const native_handle_t *stream);
-    HWC2::Error SetLayerSourceCrop(hwc_frect_t crop);
-    HWC2::Error SetLayerSurfaceDamage(hwc_region_t damage);
-    HWC2::Error SetLayerTransform(int32_t transform);
-    HWC2::Error SetLayerVisibleRegion(hwc_region_t visible);
-    HWC2::Error SetLayerZOrder(uint32_t order);
-
-    UniqueFd acquire_fence_;
-
-    /*
-     * Release fence is not used.
-     * There is no release fence support available in the DRM/KMS. In case no
-     * release fence provided application will use this buffer for writing when
-     * the next frame present fence is signaled.
-     */
-    UniqueFd release_fence_;
-
-   private:
-    // sf_type_ stores the initial type given to us by surfaceflinger,
-    // validated_type_ stores the type after running ValidateDisplay
-    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;
-    uint32_t z_order_ = 0;
-    android_dataspace_t dataspace_ = HAL_DATASPACE_UNKNOWN;
-  };
-
-  class HwcDisplay {
-   public:
-    HwcDisplay(ResourceManager *resource_manager, DrmDevice *drm,
-               hwc2_display_t handle, HWC2::DisplayType type);
-    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();
-
-    void ClearDisplay();
-
-    std::string Dump();
-
-    // HWC Hooks
-    HWC2::Error AcceptDisplayChanges();
-    HWC2::Error CreateLayer(hwc2_layer_t *layer);
-    HWC2::Error DestroyLayer(hwc2_layer_t layer);
-    HWC2::Error GetActiveConfig(hwc2_config_t *config);
-    HWC2::Error GetChangedCompositionTypes(uint32_t *num_elements,
-                                           hwc2_layer_t *layers,
-                                           int32_t *types);
-    HWC2::Error GetClientTargetSupport(uint32_t width, uint32_t height,
-                                       int32_t format, int32_t dataspace);
-    HWC2::Error GetColorModes(uint32_t *num_modes, int32_t *modes);
-    HWC2::Error GetDisplayAttribute(hwc2_config_t config, int32_t attribute,
-                                    int32_t *value);
-    HWC2::Error GetDisplayConfigs(uint32_t *num_configs,
-                                  hwc2_config_t *configs);
-    HWC2::Error GetDisplayName(uint32_t *size, char *name);
-    HWC2::Error GetDisplayRequests(int32_t *display_requests,
-                                   uint32_t *num_elements, hwc2_layer_t *layers,
-                                   int32_t *layer_requests);
-    HWC2::Error GetDisplayType(int32_t *type);
-#if PLATFORM_SDK_VERSION > 27
-    HWC2::Error GetRenderIntents(int32_t mode, uint32_t *outNumIntents,
-                                 int32_t *outIntents);
-    HWC2::Error SetColorModeWithIntent(int32_t mode, int32_t intent);
-#endif
-#if PLATFORM_SDK_VERSION > 28
-    HWC2::Error GetDisplayIdentificationData(uint8_t *outPort,
-                                             uint32_t *outDataSize,
-                                             uint8_t *outData);
-    HWC2::Error GetDisplayCapabilities(uint32_t *outNumCapabilities,
-                                       uint32_t *outCapabilities);
-    HWC2::Error GetDisplayBrightnessSupport(bool *supported);
-    HWC2::Error SetDisplayBrightness(float);
-#endif
-#if PLATFORM_SDK_VERSION > 29
-    HWC2::Error GetDisplayConnectionType(uint32_t *outType);
-    HWC2::Error GetDisplayVsyncPeriod(hwc2_vsync_period_t *outVsyncPeriod);
-
-    HWC2::Error SetActiveConfigWithConstraints(
-        hwc2_config_t config,
-        hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints,
-        hwc_vsync_period_change_timeline_t *outTimeline);
-    HWC2::Error SetAutoLowLatencyMode(bool on);
-    HWC2::Error GetSupportedContentTypes(
-        uint32_t *outNumSupportedContentTypes,
-        const uint32_t *outSupportedContentTypes);
-
-    HWC2::Error SetContentType(int32_t contentType);
-#endif
-
-    HWC2::Error GetDozeSupport(int32_t *support);
-    HWC2::Error GetHdrCapabilities(uint32_t *num_types, int32_t *types,
-                                   float *max_luminance,
-                                   float *max_average_luminance,
-                                   float *min_luminance);
-    HWC2::Error GetReleaseFences(uint32_t *num_elements, hwc2_layer_t *layers,
-                                 int32_t *fences);
-    HWC2::Error PresentDisplay(int32_t *present_fence);
-    HWC2::Error SetActiveConfig(hwc2_config_t config);
-    HWC2::Error ChosePreferredConfig();
-    HWC2::Error SetClientTarget(buffer_handle_t target, int32_t acquire_fence,
-                                int32_t dataspace, hwc_region_t damage);
-    HWC2::Error SetColorMode(int32_t mode);
-    HWC2::Error SetColorTransform(const float *matrix, int32_t hint);
-    HWC2::Error SetOutputBuffer(buffer_handle_t buffer, int32_t release_fence);
-    HWC2::Error SetPowerMode(int32_t mode);
-    HWC2::Error SetVsyncEnabled(int32_t enabled);
-    HWC2::Error ValidateDisplay(uint32_t *num_types, uint32_t *num_requests);
-    HwcLayer *get_layer(hwc2_layer_t layer) {
-      auto it = layers_.find(layer);
-      if (it == layers_.end())
-        return nullptr;
-      return &it->second;
-    }
-
-    /* Statistics */
-    struct Stats {
-      Stats minus(Stats b) {
-        return {total_frames_ - b.total_frames_,
-                total_pixops_ - b.total_pixops_,
-                gpu_pixops_ - b.gpu_pixops_,
-                failed_kms_validate_ - b.failed_kms_validate_,
-                failed_kms_present_ - b.failed_kms_present_,
-                frames_flattened_ - b.frames_flattened_};
-      }
-
-      uint32_t total_frames_ = 0;
-      uint64_t total_pixops_ = 0;
-      uint64_t gpu_pixops_ = 0;
-      uint32_t failed_kms_validate_ = 0;
-      uint32_t failed_kms_present_ = 0;
-      uint32_t frames_flattened_ = 0;
-    };
-
-    const Backend *backend() const {
-      return backend_.get();
-    }
-    void set_backend(std::unique_ptr<Backend> backend) {
-      backend_ = std::move(backend);
-    }
-
-    const std::vector<DrmPlane *> &primary_planes() const {
-      return primary_planes_;
-    }
-
-    const std::vector<DrmPlane *> &overlay_planes() const {
-      return overlay_planes_;
-    }
-
-    std::map<hwc2_layer_t, HwcLayer> &layers() {
-      return layers_;
-    }
-
-    const DrmDisplayCompositor &compositor() const {
-      return compositor_;
-    }
-
-    const DrmDevice *drm() const {
-      return drm_;
-    }
-
-    const DrmConnector *connector() const {
-      return connector_;
-    }
-
-    ResourceManager *resource_manager() const {
-      return resource_manager_;
-    }
-
-    android_color_transform_t &color_transform_hint() {
-      return color_transform_hint_;
-    }
-
-    Stats &total_stats() {
-      return total_stats_;
-    }
-
-   private:
-    void AddFenceToPresentFence(UniqueFd fd);
-
-    constexpr static size_t MATRIX_SIZE = 16;
-
-    ResourceManager *resource_manager_;
-    DrmDevice *drm_;
-    DrmDisplayCompositor compositor_;
-    std::unique_ptr<Planner> planner_;
-
-    std::vector<DrmPlane *> primary_planes_;
-    std::vector<DrmPlane *> overlay_planes_;
-
-    std::unique_ptr<Backend> backend_;
-
-    VSyncWorker vsync_worker_;
-    DrmConnector *connector_ = NULL;
-    DrmCrtc *crtc_ = NULL;
-    hwc2_display_t handle_;
-    HWC2::DisplayType type_;
-    uint32_t layer_idx_ = 0;
-    std::map<hwc2_layer_t, HwcLayer> layers_;
-    HwcLayer client_layer_;
-    UniqueFd present_fence_;
-    int32_t color_mode_{};
-    std::array<float, MATRIX_SIZE> color_transform_matrix_{};
-    android_color_transform_t color_transform_hint_;
-
-    uint32_t frame_no_ = 0;
-    Stats total_stats_;
-    Stats prev_stats_;
-    std::string DumpDelta(DrmHwcTwo::HwcDisplay::Stats delta);
-  };
-
-  class DrmHotplugHandler : public DrmEventHandler {
-   public:
-    DrmHotplugHandler(DrmHwcTwo *hwc2, DrmDevice *drm)
-        : hwc2_(hwc2), drm_(drm) {
-    }
-    void HandleEvent(uint64_t timestamp_us);
-
-   private:
-    DrmHwcTwo *hwc2_;
-    DrmDevice *drm_;
-  };
-
- private:
-  static DrmHwcTwo *toDrmHwcTwo(hwc2_device_t *dev) {
-    return static_cast<DrmHwcTwo *>(dev);
-  }
-
-  template <typename PFN, typename T>
-  static hwc2_function_pointer_t ToHook(T function) {
-    static_assert(std::is_same<PFN, T>::value, "Incompatible fn pointer");
-    return reinterpret_cast<hwc2_function_pointer_t>(function);
-  }
-
-  template <typename T, typename HookType, HookType func, typename... Args>
-  static T DeviceHook(hwc2_device_t *dev, Args... args) {
-    DrmHwcTwo *hwc = toDrmHwcTwo(dev);
-    return static_cast<T>(((*hwc).*func)(std::forward<Args>(args)...));
-  }
-
-  static HwcDisplay *GetDisplay(DrmHwcTwo *hwc, hwc2_display_t display_handle) {
-    auto it = hwc->displays_.find(display_handle);
-    if (it == hwc->displays_.end())
-      return nullptr;
-
-    return &it->second;
-  }
-
-  template <typename HookType, HookType func, typename... Args>
-  static int32_t DisplayHook(hwc2_device_t *dev, hwc2_display_t display_handle,
-                             Args... args) {
-    HwcDisplay *display = GetDisplay(toDrmHwcTwo(dev), display_handle);
-    if (!display)
-      return static_cast<int32_t>(HWC2::Error::BadDisplay);
-
-    return static_cast<int32_t>((display->*func)(std::forward<Args>(args)...));
-  }
-
-  template <typename HookType, HookType func, typename... Args>
-  static int32_t LayerHook(hwc2_device_t *dev, hwc2_display_t display_handle,
-                           hwc2_layer_t layer_handle, Args... args) {
-    HwcDisplay *display = GetDisplay(toDrmHwcTwo(dev), display_handle);
-    if (!display)
-      return static_cast<int32_t>(HWC2::Error::BadDisplay);
-
-    HwcLayer *layer = display->get_layer(layer_handle);
-    if (!layer)
-      return static_cast<int32_t>(HWC2::Error::BadLayer);
-
-    return static_cast<int32_t>((layer->*func)(std::forward<Args>(args)...));
-  }
-
-  // hwc2_device_t hooks
-  static int HookDevClose(hw_device_t *dev);
-  static void HookDevGetCapabilities(hwc2_device_t *dev, uint32_t *out_count,
-                                     int32_t *out_capabilities);
-  static hwc2_function_pointer_t HookDevGetFunction(struct hwc2_device *device,
-                                                    int32_t descriptor);
-
-  // Device functions
-  HWC2::Error CreateVirtualDisplay(uint32_t width, uint32_t height,
-                                   int32_t *format, hwc2_display_t *display);
-  HWC2::Error DestroyVirtualDisplay(hwc2_display_t display);
-  void Dump(uint32_t *outSize, char *outBuffer);
-  uint32_t GetMaxVirtualDisplayCount();
-  HWC2::Error RegisterCallback(int32_t descriptor, hwc2_callback_data_t data,
-                               hwc2_function_pointer_t function);
-  HWC2::Error CreateDisplay(hwc2_display_t displ, HWC2::DisplayType type);
-  void HandleDisplayHotplug(hwc2_display_t displayid, int state);
-  void HandleInitialHotplugState(DrmDevice *drmDevice);
-
-  ResourceManager resource_manager_;
-  std::map<hwc2_display_t, HwcDisplay> displays_;
-
-  std::string mDumpString;
-};
-}  // namespace android
-
-#endif
diff --git a/OWNERS b/OWNERS
index 75e29ae..cead4fc 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,5 +1,5 @@
 adelva@google.com
-john.stultz@linaro.org
+dimitrysh@google.com
+jstultz@google.com
 marcheu@google.com
 seanpaul@google.com
-zachr@google.com
diff --git a/README.md b/README.md
index 728bc76..e98b5ae 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-14 -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..ba0518a 100644
--- a/backend/Backend.cpp
+++ b/backend/Backend.cpp
@@ -23,8 +23,7 @@
 
 namespace android {
 
-HWC2::Error Backend::ValidateDisplay(DrmHwcTwo::HwcDisplay *display,
-                                     uint32_t *num_types,
+HWC2::Error Backend::ValidateDisplay(HwcDisplay *display, uint32_t *num_types,
                                      uint32_t *num_requests) {
   *num_types = 0;
   *num_requests = 0;
@@ -34,7 +33,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);
@@ -45,8 +45,10 @@
 
     bool testing_needed = !(client_start == 0 && client_size == layers.size());
 
+    AtomicCommitArgs a_args = {.test_only = true};
+
     if (testing_needed &&
-        display->CreateComposition(true) != HWC2::Error::None) {
+        display->CreateComposition(a_args) != HWC2::Error::None) {
       ++display->total_stats().failed_kms_validate_;
       client_start = 0;
       client_size = layers.size();
@@ -56,22 +58,19 @@
 
   *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());
 
-  return *num_types ? HWC2::Error::HasChanges : HWC2::Error::None;
+  return *num_types != 0 ? HWC2::Error::HasChanges : HWC2::Error::None;
 }
 
 std::tuple<int, size_t> Backend::GetClientLayers(
-    DrmHwcTwo::HwcDisplay *display,
-    const std::vector<DrmHwcTwo::HwcLayer *> &layers) {
+    HwcDisplay *display, const std::vector<HwcLayer *> &layers) {
   int client_start = -1;
   size_t client_size = 0;
 
-  for (int z_order = 0; z_order < layers.size(); ++z_order) {
+  for (size_t z_order = 0; z_order < layers.size(); ++z_order) {
     if (IsClientLayer(display, layers[z_order])) {
       if (client_start < 0)
         client_start = (int)z_order;
@@ -82,13 +81,12 @@
   return GetExtraClientRange(display, layers, client_start, client_size);
 }
 
-bool Backend::IsClientLayer(DrmHwcTwo::HwcDisplay *display,
-                            DrmHwcTwo::HwcLayer *layer) {
-  return !HardwareSupportsLayerType(layer->sf_type()) ||
-         !BufferInfoGetter::GetInstance()->IsHandleUsable(layer->buffer()) ||
+bool Backend::IsClientLayer(HwcDisplay *display, HwcLayer *layer) {
+  return !HardwareSupportsLayerType(layer->GetSfType()) ||
+         !layer->IsLayerUsableAsDevice() ||
          display->color_transform_hint() != HAL_COLOR_TRANSFORM_IDENTITY ||
-         (layer->RequireScalingOrPhasing() &&
-          display->resource_manager()->ForcedScalingWithGpu());
+         (layer->GetLayerData().pi.RequireScalingOrPhasing() &&
+          display->GetHwc2()->GetResMan().ForcedScalingWithGpu());
 }
 
 bool Backend::HardwareSupportsLayerType(HWC2::Composition comp_type) {
@@ -96,34 +94,33 @@
          comp_type == HWC2::Composition::Cursor;
 }
 
-uint32_t Backend::CalcPixOps(const std::vector<DrmHwcTwo::HwcLayer *> &layers,
+uint32_t Backend::CalcPixOps(const std::vector<HwcLayer *> &layers,
                              size_t first_z, size_t size) {
   uint32_t pixops = 0;
-  for (int z_order = 0; z_order < layers.size(); ++z_order) {
+  for (size_t z_order = 0; z_order < layers.size(); ++z_order) {
     if (z_order >= first_z && z_order < first_z + size) {
-      hwc_rect_t df = layers[z_order]->display_frame();
+      hwc_rect_t &df = layers[z_order]->GetLayerData().pi.display_frame;
       pixops += (df.right - df.left) * (df.bottom - df.top);
     }
   }
   return pixops;
 }
 
-void Backend::MarkValidated(std::vector<DrmHwcTwo::HwcLayer *> &layers,
+void Backend::MarkValidated(std::vector<HwcLayer *> &layers,
                             size_t client_first_z, size_t client_size) {
-  for (int z_order = 0; z_order < layers.size(); ++z_order) {
+  for (size_t z_order = 0; z_order < layers.size(); ++z_order) {
     if (z_order >= client_first_z && z_order < client_first_z + client_size)
-      layers[z_order]->set_validated_type(HWC2::Composition::Client);
+      layers[z_order]->SetValidatedType(HWC2::Composition::Client);
     else
-      layers[z_order]->set_validated_type(HWC2::Composition::Device);
+      layers[z_order]->SetValidatedType(HWC2::Composition::Device);
   }
 }
 
 std::tuple<int, int> Backend::GetExtraClientRange(
-    DrmHwcTwo::HwcDisplay *display,
-    const std::vector<DrmHwcTwo::HwcLayer *> &layers, int client_start,
-    size_t client_size) {
-  size_t avail_planes = display->primary_planes().size() +
-                        display->overlay_planes().size();
+    HwcDisplay *display, const std::vector<HwcLayer *> &layers,
+    int client_start, size_t client_size) {
+  auto planes = display->GetPipe().GetUsablePlanes();
+  size_t avail_planes = planes.size();
 
   /*
    * If more layers then planes, save one plane
@@ -151,12 +148,12 @@
       steps = 1 + layers.size() - extra_client;
     }
 
-    uint32_t gpu_pixops = INT_MAX;
-    for (int i = 0; i < steps; i++) {
+    uint32_t gpu_pixops = UINT32_MAX;
+    for (size_t i = 0; i < steps; i++) {
       uint32_t po = CalcPixOps(layers, start + i, client_size);
       if (po < gpu_pixops) {
         gpu_pixops = po;
-        client_start = start + i;
+        client_start = start + int(i);
       }
     }
   }
diff --git a/backend/Backend.h b/backend/Backend.h
index fc9a733..82b8fca 100644
--- a/backend/Backend.h
+++ b/backend/Backend.h
@@ -17,32 +17,28 @@
 #ifndef ANDROID_BACKEND_H
 #define ANDROID_BACKEND_H
 
-#include "DrmHwcTwo.h"
+#include "hwc2_device/DrmHwcTwo.h"
 
 namespace android {
 
 class Backend {
  public:
   virtual ~Backend() = default;
-  virtual HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display,
-                                      uint32_t *num_types,
+  virtual HWC2::Error ValidateDisplay(HwcDisplay *display, uint32_t *num_types,
                                       uint32_t *num_requests);
   virtual std::tuple<int, size_t> GetClientLayers(
-      DrmHwcTwo::HwcDisplay *display,
-      const std::vector<DrmHwcTwo::HwcLayer *> &layers);
-  virtual bool IsClientLayer(DrmHwcTwo::HwcDisplay *display,
-                             DrmHwcTwo::HwcLayer *layer);
+      HwcDisplay *display, const std::vector<HwcLayer *> &layers);
+  virtual bool IsClientLayer(HwcDisplay *display, HwcLayer *layer);
 
  protected:
-  bool HardwareSupportsLayerType(HWC2::Composition comp_type);
-  uint32_t CalcPixOps(const std::vector<DrmHwcTwo::HwcLayer *> &layers,
-                      size_t first_z, size_t size);
-  void MarkValidated(std::vector<DrmHwcTwo::HwcLayer *> &layers,
-                     size_t client_first_z, size_t client_size);
-  std::tuple<int, int> GetExtraClientRange(
-      DrmHwcTwo::HwcDisplay *display,
-      const std::vector<DrmHwcTwo::HwcLayer *> &layers, int client_start,
-      size_t client_size);
+  static bool HardwareSupportsLayerType(HWC2::Composition comp_type);
+  static uint32_t CalcPixOps(const std::vector<HwcLayer *> &layers,
+                             size_t first_z, size_t size);
+  static void MarkValidated(std::vector<HwcLayer *> &layers,
+                            size_t client_first_z, size_t client_size);
+  static std::tuple<int, int> GetExtraClientRange(
+      HwcDisplay *display, const std::vector<HwcLayer *> &layers,
+      int client_start, size_t client_size);
 };
 }  // namespace android
 
diff --git a/backend/BackendClient.cpp b/backend/BackendClient.cpp
index 49963b8..606dca2 100644
--- a/backend/BackendClient.cpp
+++ b/backend/BackendClient.cpp
@@ -20,11 +20,11 @@
 
 namespace android {
 
-HWC2::Error BackendClient::ValidateDisplay(DrmHwcTwo::HwcDisplay *display,
+HWC2::Error BackendClient::ValidateDisplay(HwcDisplay *display,
                                            uint32_t *num_types,
                                            uint32_t * /*num_requests*/) {
-  for (auto & [ layer_handle, layer ] : display->layers()) {
-    layer.set_validated_type(HWC2::Composition::Client);
+  for (auto &[layer_handle, layer] : display->layers()) {
+    layer.SetValidatedType(HWC2::Composition::Client);
     ++*num_types;
   }
   return HWC2::Error::HasChanges;
diff --git a/backend/BackendClient.h b/backend/BackendClient.h
index 13543f1..95abb0f 100644
--- a/backend/BackendClient.h
+++ b/backend/BackendClient.h
@@ -23,8 +23,7 @@
 
 class BackendClient : public Backend {
  public:
-  HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display,
-                              uint32_t *num_types,
+  HWC2::Error ValidateDisplay(HwcDisplay *display, uint32_t *num_types,
                               uint32_t *num_requests) override;
 };
 }  // namespace android
diff --git a/backend/BackendManager.cpp b/backend/BackendManager.cpp
index 7b89761..9bf6324 100644
--- a/backend/BackendManager.cpp
+++ b/backend/BackendManager.cpp
@@ -36,28 +36,30 @@
 }
 
 int BackendManager::RegisterBackend(const std::string &name,
-                                    backend_constructor_t backend_constructor) {
+                                    BackendConstructorT backend_constructor) {
   available_backends_[name] = std::move(backend_constructor);
   return 0;
 }
 
-int BackendManager::SetBackendForDisplay(DrmHwcTwo::HwcDisplay *display) {
-  std::string driver_name(display->drm()->GetName());
+int BackendManager::SetBackendForDisplay(HwcDisplay *display) {
+  std::string driver_name(display->GetPipe().device->GetName());
   char backend_override[PROPERTY_VALUE_MAX];
   property_get("vendor.hwc.backend_override", backend_override,
                driver_name.c_str());
   std::string backend_name(backend_override);
 
   display->set_backend(GetBackendByName(backend_name));
-  if (!display->backend()) {
+  if (display->backend() == nullptr) {
     ALOGE("Failed to set backend '%s' for '%s' and driver '%s'",
-          backend_name.c_str(), display->connector()->name().c_str(),
+          backend_name.c_str(),
+          display->GetPipe().connector->Get()->GetName().c_str(),
           driver_name.c_str());
     return -EINVAL;
   }
 
   ALOGI("Backend '%s' for '%s' and driver '%s' was successfully set",
-        backend_name.c_str(), display->connector()->name().c_str(),
+        backend_name.c_str(),
+        display->GetPipe().connector->Get()->GetName().c_str(),
         driver_name.c_str());
 
   return 0;
diff --git a/backend/BackendManager.h b/backend/BackendManager.h
index 9b314db..751cb78 100644
--- a/backend/BackendManager.h
+++ b/backend/BackendManager.h
@@ -24,6 +24,7 @@
 
 #include "Backend.h"
 
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
 #define REGISTER_BACKEND(name_str_, backend_)                               \
   static int                                                                \
       backend = BackendManager::GetInstance()                               \
@@ -36,21 +37,21 @@
 
 class BackendManager {
  public:
-  using backend_constructor_t = std::function<std::unique_ptr<Backend>()>;
+  using BackendConstructorT = std::function<std::unique_ptr<Backend>()>;
   static BackendManager &GetInstance();
   int RegisterBackend(const std::string &name,
-                      backend_constructor_t backend_constructor);
-  int SetBackendForDisplay(DrmHwcTwo::HwcDisplay *display);
+                      BackendConstructorT backend_constructor);
+  int SetBackendForDisplay(HwcDisplay *display);
   std::unique_ptr<Backend> GetBackendByName(std::string &name);
-  HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display,
-                              uint32_t *num_types, uint32_t *num_requests);
+  HWC2::Error ValidateDisplay(HwcDisplay *display, uint32_t *num_types,
+                              uint32_t *num_requests);
 
  private:
   BackendManager() = default;
 
   static const std::vector<std::string> kClientDevices;
 
-  std::map<std::string, backend_constructor_t> available_backends_;
+  std::map<std::string, BackendConstructorT> available_backends_;
 };
 }  // namespace android
 
diff --git a/backend/BackendRCarDu.cpp b/backend/BackendRCarDu.cpp
deleted file mode 100644
index b012797..0000000
--- a/backend/BackendRCarDu.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BackendRCarDu.h"
-
-#include "BackendManager.h"
-#include "bufferinfo/BufferInfoGetter.h"
-#include "drm_fourcc.h"
-
-namespace android {
-
-bool BackendRCarDu::IsClientLayer(DrmHwcTwo::HwcDisplay *display,
-                                  DrmHwcTwo::HwcLayer *layer) {
-  hwc_drm_bo_t bo;
-
-  int ret = BufferInfoGetter::GetInstance()->ConvertBoInfo(layer->buffer(),
-                                                           &bo);
-  if (ret)
-    return true;
-
-  if (bo.format == DRM_FORMAT_ABGR8888)
-    return true;
-
-  if (layer->RequireScalingOrPhasing())
-    return true;
-
-  return Backend::IsClientLayer(display, layer);
-}
-
-// clang-format off
-// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables, cert-err58-cpp)
-REGISTER_BACKEND("rcar-du", BackendRCarDu);
-// clang-format on
-
-}  // namespace android
\ No newline at end of file
diff --git a/backend/BackendRCarDu.h b/backend/BackendRCarDu.h
deleted file mode 100644
index 8a1011a..0000000
--- a/backend/BackendRCarDu.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef HWC_DISPLAY_BACKEND_RCAR_DU_H
-#define HWC_DISPLAY_BACKEND_RCAR_DU_H
-
-#include "Backend.h"
-
-namespace android {
-
-class BackendRCarDu : public Backend {
- public:
-  bool IsClientLayer(DrmHwcTwo::HwcDisplay *display,
-                     DrmHwcTwo::HwcLayer *layer) override;
-};
-}  // namespace android
-
-#endif
diff --git a/bufferinfo/BufferInfo.h b/bufferinfo/BufferInfo.h
new file mode 100644
index 0000000..b2297f9
--- /dev/null
+++ b/bufferinfo/BufferInfo.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+constexpr int kBufferMaxPlanes = 4;
+
+enum class BufferColorSpace : int32_t {
+  kUndefined,
+  kItuRec601,
+  kItuRec709,
+  kItuRec2020,
+};
+
+enum class BufferSampleRange : int32_t {
+  kUndefined,
+  kFullRange,
+  kLimitedRange,
+};
+
+enum class BufferBlendMode : int32_t {
+  kUndefined,
+  kNone,
+  kPreMult,
+  kCoverage,
+};
+
+struct BufferInfo {
+  uint32_t width;
+  uint32_t height;
+  uint32_t format; /* DRM_FORMAT_* from drm_fourcc.h */
+  uint32_t pitches[kBufferMaxPlanes];
+  uint32_t offsets[kBufferMaxPlanes];
+  /* sizes[] is used only by mapper@4 metadata getter for internal purposes */
+  uint32_t sizes[kBufferMaxPlanes];
+  int prime_fds[kBufferMaxPlanes];
+  uint64_t modifiers[kBufferMaxPlanes];
+
+  BufferColorSpace color_space;
+  BufferSampleRange sample_range;
+  BufferBlendMode blend_mode;
+};
diff --git a/bufferinfo/BufferInfoGetter.cpp b/bufferinfo/BufferInfoGetter.cpp
index 7f7f8ae..95c1a23 100644
--- a/bufferinfo/BufferInfoGetter.cpp
+++ b/bufferinfo/BufferInfoGetter.cpp
@@ -22,9 +22,14 @@
 #include "BufferInfoMapperMetadata.h"
 #endif
 
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 
+#include <mutex>
+
 #include "utils/log.h"
 #include "utils/properties.h"
 
@@ -32,39 +37,42 @@
 
 BufferInfoGetter *BufferInfoGetter::GetInstance() {
   static std::unique_ptr<BufferInfoGetter> inst;
-  if (inst == nullptr) {
-#if PLATFORM_SDK_VERSION >= 30
+  if (!inst) {
+#if PLATFORM_SDK_VERSION >= 30 && defined(USE_IMAPPER4_METADATA_API)
     inst.reset(BufferInfoMapperMetadata::CreateInstance());
-    if (inst == nullptr) {
+    if (!inst) {
       ALOGW(
           "Generic buffer getter is not available. Falling back to legacy...");
-#endif
-      inst = LegacyBufferInfoGetter::CreateInstance();
-#if PLATFORM_SDK_VERSION >= 30
     }
 #endif
+    if (!inst) {
+      inst = LegacyBufferInfoGetter::CreateInstance();
+    }
   }
 
   return inst.get();
 }
 
-bool BufferInfoGetter::IsHandleUsable(buffer_handle_t handle) {
-  hwc_drm_bo_t bo;
-  memset(&bo, 0, sizeof(hwc_drm_bo_t));
+std::optional<BufferUniqueId> BufferInfoGetter::GetUniqueId(
+    buffer_handle_t handle) {
+  struct stat sb {};
+  if (fstat(handle->data[0], &sb) != 0) {
+    return {};
+  }
 
-  if (ConvertBoInfo(handle, &bo) != 0) {
-    return false;
+  if (sb.st_size == 0) {
+    return {};
   }
-  if (bo.prime_fds[0] == 0) {
-    return false;
-  }
-  return true;
+
+  return static_cast<BufferUniqueId>(sb.st_ino);
 }
 
 int LegacyBufferInfoGetter::Init() {
-  int ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
-                          (const hw_module_t **)&gralloc_);
-  if (ret) {
+  int ret = hw_get_module(
+      GRALLOC_HARDWARE_MODULE_ID,
+      // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+      reinterpret_cast<const hw_module_t **>(&gralloc_));
+  if (ret != 0) {
     ALOGE("Failed to open gralloc module");
     return ret;
   }
diff --git a/bufferinfo/BufferInfoGetter.h b/bufferinfo/BufferInfoGetter.h
index 60ca985..5591296 100644
--- a/bufferinfo/BufferInfoGetter.h
+++ b/bufferinfo/BufferInfoGetter.h
@@ -20,8 +20,10 @@
 #include <drm/drm_fourcc.h>
 #include <hardware/gralloc.h>
 
+#include <optional>
+
+#include "BufferInfo.h"
 #include "drm/DrmDevice.h"
-#include "drmhwcgralloc.h"
 
 #ifndef DRM_FORMAT_INVALID
 #define DRM_FORMAT_INVALID 0
@@ -29,14 +31,16 @@
 
 namespace android {
 
+using BufferUniqueId = uint64_t;
+
 class BufferInfoGetter {
  public:
-  virtual ~BufferInfoGetter() {
-  }
+  virtual ~BufferInfoGetter() = default;
 
-  virtual int ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) = 0;
+  virtual auto GetBoInfo(buffer_handle_t handle)
+      -> std::optional<BufferInfo> = 0;
 
-  bool IsHandleUsable(buffer_handle_t handle);
+  virtual std::optional<BufferUniqueId> GetUniqueId(buffer_handle_t handle);
 
   static BufferInfoGetter *GetInstance();
 
@@ -49,25 +53,34 @@
 
   int Init();
 
-  int ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) override = 0;
+  virtual int ValidateGralloc() {
+    return 0;
+  }
 
   static std::unique_ptr<LegacyBufferInfoGetter> CreateInstance();
 
   static uint32_t ConvertHalFormatToDrm(uint32_t hal_format);
+
+  // NOLINTNEXTLINE:(readability-identifier-naming)
   const gralloc_module_t *gralloc_;
 };
 
 #ifdef DISABLE_LEGACY_GETTERS
 #define LEGACY_BUFFER_INFO_GETTER(getter_)
 #else
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
 #define LEGACY_BUFFER_INFO_GETTER(getter_)                             \
   std::unique_ptr<LegacyBufferInfoGetter>                              \
   LegacyBufferInfoGetter::CreateInstance() {                           \
     auto instance = std::make_unique<getter_>();                       \
     if (instance) {                                                    \
-      int ret = instance->Init();                                      \
-      if (ret) {                                                       \
-        ALOGE("Failed to initialize the " #getter_ " getter %d", ret); \
+      int err = instance->Init();                                      \
+      if (err) {                                                       \
+        ALOGE("Failed to initialize the " #getter_ " getter %d", err); \
+        instance.reset();                                              \
+      }                                                                \
+      err = instance->ValidateGralloc();                               \
+      if (err) {                                                       \
         instance.reset();                                              \
       }                                                                \
     }                                                                  \
diff --git a/bufferinfo/BufferInfoMapperMetadata.cpp b/bufferinfo/BufferInfoMapperMetadata.cpp
index 23a9072..bdacb74 100644
--- a/bufferinfo/BufferInfoMapperMetadata.cpp
+++ b/bufferinfo/BufferInfoMapperMetadata.cpp
@@ -46,98 +46,103 @@
  * so that it can be overridden.
  */
 int __attribute__((weak))
-BufferInfoMapperMetadata::GetFds(buffer_handle_t handle, hwc_drm_bo_t *bo) {
-  int num_fds = handle->numFds;
+BufferInfoMapperMetadata::GetFds(buffer_handle_t handle, BufferInfo *bo) {
+  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 < kBufferMaxPlanes; 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;
 }
 
-int BufferInfoMapperMetadata::ConvertBoInfo(buffer_handle_t handle,
-                                            hwc_drm_bo_t *bo) {
+auto BufferInfoMapperMetadata::GetBoInfo(buffer_handle_t handle)
+    -> std::optional<BufferInfo> {
   GraphicBufferMapper &mapper = GraphicBufferMapper::getInstance();
-  if (!handle)
-    return -EINVAL;
+  if (handle == nullptr)
+    return {};
 
-  uint64_t usage = 0;
-  int err = mapper.getUsage(handle, &usage);
-  if (err) {
-    ALOGE("Failed to get usage err=%d", err);
-    return err;
-  }
-  bo->usage = static_cast<uint32_t>(usage);
+  BufferInfo bi{};
 
-  ui::PixelFormat hal_format;
-  err = mapper.getPixelFormatRequested(handle, &hal_format);
-  if (err) {
-    ALOGE("Failed to get HAL Pixel Format err=%d", err);
-    return err;
-  }
-  bo->hal_format = static_cast<uint32_t>(hal_format);
-
-  err = mapper.getPixelFormatFourCC(handle, &bo->format);
-  if (err) {
+  int err = mapper.getPixelFormatFourCC(handle, &bi.format);
+  if (err != 0) {
     ALOGE("Failed to get FourCC format err=%d", err);
-    return err;
+    return {};
   }
 
-  err = mapper.getPixelFormatModifier(handle, &bo->modifiers[0]);
-  if (err) {
+  err = mapper.getPixelFormatModifier(handle, &bi.modifiers[0]);
+  if (err != 0) {
     ALOGE("Failed to get DRM Modifier err=%d", err);
-    return err;
+    return {};
   }
 
   uint64_t width = 0;
   err = mapper.getWidth(handle, &width);
-  if (err) {
+  if (err != 0) {
     ALOGE("Failed to get Width err=%d", err);
-    return err;
+    return {};
   }
-  bo->width = static_cast<uint32_t>(width);
+  bi.width = static_cast<uint32_t>(width);
 
   uint64_t height = 0;
   err = mapper.getHeight(handle, &height);
-  if (err) {
+  if (err != 0) {
     ALOGE("Failed to get Height err=%d", err);
-    return err;
+    return {};
   }
-  bo->height = static_cast<uint32_t>(height);
+  bi.height = static_cast<uint32_t>(height);
 
   std::vector<ui::PlaneLayout> layouts;
   err = mapper.getPlaneLayouts(handle, &layouts);
-  if (err) {
+  if (err != 0) {
     ALOGE("Failed to get Plane Layouts err=%d", err);
-    return err;
+    return {};
   }
 
   for (uint32_t i = 0; i < layouts.size(); i++) {
-    bo->modifiers[i] = bo->modifiers[0];
-    bo->pitches[i] = layouts[i].strideInBytes;
-    bo->offsets[i] = layouts[i].offsetInBytes;
+    bi.modifiers[i] = bi.modifiers[0];
+    bi.pitches[i] = layouts[i].strideInBytes;
+    bi.offsets[i] = layouts[i].offsetInBytes;
+    bi.sizes[i] = layouts[i].totalSizeInBytes;
   }
 
-  return GetFds(handle, bo);
+  err = GetFds(handle, &bi);
+  if (err != 0) {
+    ALOGE("Failed to get fds (err=%d)", err);
+    return {};
+  }
+
+  return bi;
 }
 
 }  // namespace android
diff --git a/bufferinfo/BufferInfoMapperMetadata.h b/bufferinfo/BufferInfoMapperMetadata.h
index d335705..ab269dc 100644
--- a/bufferinfo/BufferInfoMapperMetadata.h
+++ b/bufferinfo/BufferInfoMapperMetadata.h
@@ -25,9 +25,9 @@
  public:
   using BufferInfoGetter::BufferInfoGetter;
 
-  int ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
+  auto GetBoInfo(buffer_handle_t handle) -> std::optional<BufferInfo> override;
 
-  int GetFds(buffer_handle_t handle, hwc_drm_bo_t *bo);
+  int GetFds(buffer_handle_t handle, BufferInfo *bo);
 
   static BufferInfoGetter *CreateInstance();
 };
diff --git a/bufferinfo/legacy/BufferInfoImagination.cpp b/bufferinfo/legacy/BufferInfoImagination.cpp
index d646072..1858ddb 100644
--- a/bufferinfo/legacy/BufferInfoImagination.cpp
+++ b/bufferinfo/legacy/BufferInfoImagination.cpp
@@ -20,6 +20,8 @@
 
 #include <xf86drm.h>
 
+#include <cerrno>
+
 #include "img_gralloc1_public.h"
 #include "utils/log.h"
 
@@ -27,24 +29,24 @@
 
 LEGACY_BUFFER_INFO_GETTER(BufferInfoImagination);
 
-int BufferInfoImagination::ConvertBoInfo(buffer_handle_t handle,
-                                         hwc_drm_bo_t *bo) {
+auto BufferInfoImagination::GetBoInfo(buffer_handle_t handle)
+    -> std::optional<BufferInfo> {
   auto *hnd = (IMG_native_handle_t *)handle;
   if (!hnd)
-    return -EINVAL;
+    return {};
 
   /* Extra bits are responsible for buffer compression and memory layout */
   if (hnd->iFormat & ~0x10f) {
     ALOGV("Special buffer formats are not supported");
-    return -EINVAL;
+    return {};
   }
 
-  bo->width = hnd->iWidth;
-  bo->height = hnd->iHeight;
-  bo->usage = hnd->usage;
-  bo->prime_fds[0] = hnd->fd[0];
-  bo->pitches[0] = ALIGN(hnd->iWidth, HW_ALIGN) * hnd->uiBpp >> 3;
-  bo->hal_format = hnd->iFormat;
+  BufferInfo bi{};
+
+  bi.width = hnd->iWidth;
+  bi.height = hnd->iHeight;
+  bi.prime_fds[0] = hnd->fd[0];
+  bi.pitches[0] = ALIGN(hnd->iWidth, HW_ALIGN) * hnd->uiBpp >> 3;
 
   switch (hnd->iFormat) {
 #ifdef HAL_PIXEL_FORMAT_BGRX_8888
@@ -53,14 +55,14 @@
       break;
 #endif
     default:
-      bo->format = ConvertHalFormatToDrm(hnd->iFormat & 0xf);
-      if (bo->format == DRM_FORMAT_INVALID) {
+      bi.format = ConvertHalFormatToDrm(hnd->iFormat & 0xf);
+      if (bi.format == DRM_FORMAT_INVALID) {
         ALOGV("Cannot convert hal format to drm format %u", hnd->iFormat);
-        return -EINVAL;
+        return {};
       }
   }
 
-  return 0;
+  return bi;
 }
 
 }  // namespace android
diff --git a/bufferinfo/legacy/BufferInfoImagination.h b/bufferinfo/legacy/BufferInfoImagination.h
index 765b279..635e3b5 100644
--- a/bufferinfo/legacy/BufferInfoImagination.h
+++ b/bufferinfo/legacy/BufferInfoImagination.h
@@ -27,7 +27,7 @@
  public:
   using LegacyBufferInfoGetter::LegacyBufferInfoGetter;
 
-  int ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
+  auto GetBoInfo(buffer_handle_t handle) -> std::optional<BufferInfo> override;
 };
 }  // namespace android
 
diff --git a/bufferinfo/legacy/BufferInfoLibdrm.cpp b/bufferinfo/legacy/BufferInfoLibdrm.cpp
index 52f792f..ac71ec0 100644
--- a/bufferinfo/legacy/BufferInfoLibdrm.cpp
+++ b/bufferinfo/legacy/BufferInfoLibdrm.cpp
@@ -23,6 +23,8 @@
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 
+#include <mutex>
+
 #include "utils/log.h"
 #include "utils/properties.h"
 
@@ -37,14 +39,19 @@
 
 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_ */
 };
 
+#ifndef DRM_FORMAT_XYUV8888
+#define DRM_FORMAT_XYUV8888 \
+  fourcc_code('X', 'Y', 'U', 'V') /* [31:0] X:Y:Cb:Cr 8:8:8:8 little endian */
+#endif
+
 /* The following table is used to look up a DRI image FourCC based
  * on native format and information contained in android_ycbcr struct. */
 static const struct DroidYuvFormat kDroidYuvFormats[] = {
@@ -64,18 +71,19 @@
 
 #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 uint32_t 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 &&
         droid_yuv_format.chroma_step == chroma_step)
       return droid_yuv_format.fourcc;
 
-  return -1;
+  return UINT32_MAX;
 }
 
-static bool is_yuv(int native) {
+static bool is_yuv(uint32_t native) {
+  // NOLINTNEXTLINE(readability-use-anyofallof)
   for (auto droid_yuv_format : kDroidYuvFormats)
     if (droid_yuv_format.native == native)
       return true;
@@ -83,8 +91,8 @@
   return false;
 }
 
-bool BufferInfoLibdrm::GetYuvPlaneInfo(int num_fds, buffer_handle_t handle,
-                                       hwc_drm_bo_t *bo) {
+bool BufferInfoLibdrm::GetYuvPlaneInfo(uint32_t hal_format, int num_fds,
+                                       buffer_handle_t handle, BufferInfo *bo) {
   struct android_ycbcr ycbcr {};
   enum chroma_order chroma_order {};
   int ret = 0;
@@ -128,12 +136,12 @@
 
   /* .chroma_step is the byte distance between the same chroma channel
    * values of subsequent pixels, assumed to be the same for Cb and Cr. */
-  bo->format = get_fourcc_yuv(bo->hal_format, chroma_order, ycbcr.chroma_step);
-  if (bo->format == -1) {
+  bo->format = get_fourcc_yuv(hal_format, chroma_order, ycbcr.chroma_step);
+  if (bo->format == UINT32_MAX) {
     ALOGW(
         "unsupported YUV format, native = %x, chroma_order = %s, chroma_step = "
         "%d",
-        bo->hal_format, chroma_order == kYCbCr ? "YCbCr" : "YCrCb",
+        hal_format, chroma_order == kYCbCr ? "YCbCr" : "YCrCb",
         (int)ycbcr.chroma_step);
     return false;
   }
@@ -154,14 +162,16 @@
   return true;
 }
 
-int BufferInfoLibdrm::ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) {
+auto BufferInfoLibdrm::GetBoInfo(buffer_handle_t handle)
+    -> std::optional<BufferInfo> {
   gralloc_handle_t *gr_handle = gralloc_handle(handle);
   if (!gr_handle)
-    return -EINVAL;
+    return {};
 
-  bo->width = gr_handle->width;
-  bo->height = gr_handle->height;
-  bo->hal_format = gr_handle->format;
+  BufferInfo bi{};
+
+  bi.width = gr_handle->width;
+  bi.height = gr_handle->height;
 
 #if GRALLOC_HANDLE_VERSION < 4
   static std::once_flag once;
@@ -171,32 +181,47 @@
   });
 #endif
 #if GRALLOC_HANDLE_VERSION == 4
-  bo->modifiers[0] = gr_handle->modifier;
+  bi.modifiers[0] = gr_handle->modifier;
 #endif
 
-  bo->usage = gr_handle->usage;
-  bo->prime_fds[0] = gr_handle->prime_fd;
+  bi.prime_fds[0] = gr_handle->prime_fd;
 
   if (is_yuv(gr_handle->format)) {
-    if (!GetYuvPlaneInfo(handle->numFds, handle, bo))
-      return -EINVAL;
+    if (!GetYuvPlaneInfo(gr_handle->format, handle->numFds, handle, &bi))
+      return {};
   } else {
-    bo->pitches[0] = gr_handle->stride;
-    bo->offsets[0] = 0;
+    bi.pitches[0] = gr_handle->stride;
+    bi.offsets[0] = 0;
 
     /* FOSS graphic components (gbm_gralloc, mesa3d) are translating
      * HAL_PIXEL_FORMAT_RGB_565 to DRM_FORMAT_RGB565 without swapping
      * the R and B components. Same must be done here. */
-    switch (bo->hal_format) {
+    switch (gr_handle->format) {
       case HAL_PIXEL_FORMAT_RGB_565:
-        bo->format = DRM_FORMAT_RGB565;
+        bi.format = DRM_FORMAT_RGB565;
         break;
       default:
-        bo->format = ConvertHalFormatToDrm(gr_handle->format);
+        bi.format = ConvertHalFormatToDrm(gr_handle->format);
     }
 
-    if (bo->format == DRM_FORMAT_INVALID)
-      return -EINVAL;
+    if (bi.format == DRM_FORMAT_INVALID)
+      return {};
+  }
+
+  return bi;
+}
+
+constexpr char gbm_gralloc_module_name[] = "GBM Memory Allocator";
+constexpr char drm_gralloc_module_name[] = "DRM Memory Allocator";
+
+int BufferInfoLibdrm::ValidateGralloc() {
+  if (strcmp(gralloc_->common.name, drm_gralloc_module_name) != 0 &&
+      strcmp(gralloc_->common.name, gbm_gralloc_module_name) != 0) {
+    ALOGE(
+        "Gralloc name isn't valid: Expected: \"%s\" or \"%s\", Actual: \"%s\"",
+        gbm_gralloc_module_name, drm_gralloc_module_name,
+        gralloc_->common.name);
+    return -EINVAL;
   }
 
   return 0;
diff --git a/bufferinfo/legacy/BufferInfoLibdrm.h b/bufferinfo/legacy/BufferInfoLibdrm.h
index 4d37d00..7f5b08c 100644
--- a/bufferinfo/legacy/BufferInfoLibdrm.h
+++ b/bufferinfo/legacy/BufferInfoLibdrm.h
@@ -26,10 +26,12 @@
 class BufferInfoLibdrm : public LegacyBufferInfoGetter {
  public:
   using LegacyBufferInfoGetter::LegacyBufferInfoGetter;
-  int ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
+  auto GetBoInfo(buffer_handle_t handle) -> std::optional<BufferInfo> override;
+  int ValidateGralloc() override;
 
  private:
-  bool GetYuvPlaneInfo(int num_fds, buffer_handle_t handle, hwc_drm_bo_t *bo);
+  bool GetYuvPlaneInfo(uint32_t hal_format, int num_fds, buffer_handle_t handle,
+                       BufferInfo *bo);
 };
 
 }  // namespace android
diff --git a/bufferinfo/legacy/BufferInfoMaliHisi.cpp b/bufferinfo/legacy/BufferInfoMaliHisi.cpp
index 5fc413a..1c7f4d0 100644
--- a/bufferinfo/legacy/BufferInfoMaliHisi.cpp
+++ b/bufferinfo/legacy/BufferInfoMaliHisi.cpp
@@ -66,33 +66,33 @@
 }
 #endif
 
-int BufferInfoMaliHisi::ConvertBoInfo(buffer_handle_t handle,
-                                      hwc_drm_bo_t *bo) {
+auto BufferInfoMaliHisi::GetBoInfo(buffer_handle_t handle)
+    -> std::optional<BufferInfo> {
   bool is_rgb = false;
 
   const auto *hnd = (private_handle_t const *)handle;
   if (!hnd)
-    return -EINVAL;
+    return {};
 
   if (!(hnd->usage & GRALLOC_USAGE_HW_FB))
-    return -EINVAL;
+    return {};
 
   uint32_t fmt = ConvertHalFormatToDrm(hnd->req_format);
   if (fmt == DRM_FORMAT_INVALID)
-    return -EINVAL;
+    return {};
+
+  BufferInfo bi{};
 
   is_rgb = IsDrmFormatRgb(fmt);
-  bo->modifiers[0] = ConvertGrallocFormatToDrmModifiers(hnd->internal_format,
-                                                        is_rgb);
+  bi.modifiers[0] = ConvertGrallocFormatToDrmModifiers(hnd->internal_format,
+                                                       is_rgb);
 
-  bo->width = hnd->width;
-  bo->height = hnd->height;
-  bo->hal_format = hnd->req_format;
-  bo->format = fmt;
-  bo->usage = hnd->usage;
-  bo->pitches[0] = hnd->byte_stride;
-  bo->prime_fds[0] = hnd->share_fd;
-  bo->offsets[0] = 0;
+  bi.width = hnd->width;
+  bi.height = hnd->height;
+  bi.format = fmt;
+  bi.pitches[0] = hnd->byte_stride;
+  bi.prime_fds[0] = hnd->share_fd;
+  bi.offsets[0] = 0;
 
   switch (fmt) {
     case DRM_FORMAT_YVU420: {
@@ -106,20 +106,20 @@
       int v_size = vu_stride * (adjusted_height / 2);
 
       /* V plane*/
-      bo->prime_fds[1] = hnd->share_fd;
-      bo->pitches[1] = vu_stride;
-      bo->offsets[1] = y_size;
+      bi.prime_fds[1] = hnd->share_fd;
+      bi.pitches[1] = vu_stride;
+      bi.offsets[1] = y_size;
       /* U plane */
-      bo->prime_fds[2] = hnd->share_fd;
-      bo->pitches[2] = vu_stride;
-      bo->offsets[2] = y_size + v_size;
+      bi.prime_fds[2] = hnd->share_fd;
+      bi.pitches[2] = vu_stride;
+      bi.offsets[2] = y_size + v_size;
       break;
     }
     default:
       break;
   }
 
-  return 0;
+  return bi;
 }
 
 }  // namespace android
diff --git a/bufferinfo/legacy/BufferInfoMaliHisi.h b/bufferinfo/legacy/BufferInfoMaliHisi.h
index 698a0d3..cc37491 100644
--- a/bufferinfo/legacy/BufferInfoMaliHisi.h
+++ b/bufferinfo/legacy/BufferInfoMaliHisi.h
@@ -27,7 +27,7 @@
  public:
   using LegacyBufferInfoGetter::LegacyBufferInfoGetter;
 
-  int ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
+  auto GetBoInfo(buffer_handle_t handle) -> std::optional<BufferInfo> override;
 
  private:
   uint64_t ConvertGrallocFormatToDrmModifiers(uint64_t flags, bool is_rgb);
diff --git a/bufferinfo/legacy/BufferInfoMaliMediatek.cpp b/bufferinfo/legacy/BufferInfoMaliMediatek.cpp
index 7e6f3a8..2e10460 100644
--- a/bufferinfo/legacy/BufferInfoMaliMediatek.cpp
+++ b/bufferinfo/legacy/BufferInfoMaliMediatek.cpp
@@ -32,26 +32,26 @@
 
 LEGACY_BUFFER_INFO_GETTER(BufferInfoMaliMediatek);
 
-int BufferInfoMaliMediatek::ConvertBoInfo(buffer_handle_t handle,
-                                          hwc_drm_bo_t *bo) {
+auto BufferInfoMaliMediatek::GetBoInfo(buffer_handle_t handle)
+    -> std::optional<BufferInfo> {
   const auto *hnd = (private_handle_t const *)handle;
   if (!hnd)
-    return -EINVAL;
+    return {};
 
   uint32_t fmt = ConvertHalFormatToDrm(hnd->req_format);
   if (fmt == DRM_FORMAT_INVALID)
-    return -EINVAL;
+    return {};
 
-  bo->width = hnd->width;
-  bo->height = hnd->height;
-  bo->hal_format = hnd->req_format;
-  bo->format = fmt;
-  bo->usage = hnd->consumer_usage | hnd->producer_usage;
-  bo->prime_fds[0] = hnd->share_fd;
-  bo->pitches[0] = hnd->byte_stride;
-  bo->offsets[0] = 0;
+  BufferInfo bi{};
 
-  return 0;
+  bi.width = hnd->width;
+  bi.height = hnd->height;
+  bi.format = fmt;
+  bi.prime_fds[0] = hnd->share_fd;
+  bi.pitches[0] = hnd->byte_stride;
+  bi.offsets[0] = 0;
+
+  return bi;
 }
 
 }  // namespace android
diff --git a/bufferinfo/legacy/BufferInfoMaliMediatek.h b/bufferinfo/legacy/BufferInfoMaliMediatek.h
index 1204818..43d987a 100644
--- a/bufferinfo/legacy/BufferInfoMaliMediatek.h
+++ b/bufferinfo/legacy/BufferInfoMaliMediatek.h
@@ -27,7 +27,7 @@
  public:
   using LegacyBufferInfoGetter::LegacyBufferInfoGetter;
 
-  int ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
+  auto GetBoInfo(buffer_handle_t handle) -> std::optional<BufferInfo> override;
 };
 }  // namespace android
 
diff --git a/bufferinfo/legacy/BufferInfoMaliMeson.cpp b/bufferinfo/legacy/BufferInfoMaliMeson.cpp
index 9daf542..8160296 100644
--- a/bufferinfo/legacy/BufferInfoMaliMeson.cpp
+++ b/bufferinfo/legacy/BufferInfoMaliMeson.cpp
@@ -61,32 +61,32 @@
 }
 #endif
 
-int BufferInfoMaliMeson::ConvertBoInfo(buffer_handle_t handle,
-                                       hwc_drm_bo_t *bo) {
+auto BufferInfoMaliMeson::GetBoInfo(buffer_handle_t handle)
+    -> std::optional<BufferInfo> {
   const auto *hnd = (private_handle_t const *)handle;
   if (!hnd)
-    return -EINVAL;
+    return {};
 
   if (!(hnd->usage & GRALLOC_USAGE_HW_FB))
-    return -EINVAL;
+    return {};
 
   uint32_t fmt = ConvertHalFormatToDrm(hnd->req_format);
   if (fmt == DRM_FORMAT_INVALID)
-    return -EINVAL;
+    return {};
 
-  bo->modifiers[0] = BufferInfoMaliMeson::ConvertGrallocFormatToDrmModifiers(
+  BufferInfo bi{};
+
+  bi.modifiers[0] = BufferInfoMaliMeson::ConvertGrallocFormatToDrmModifiers(
       hnd->internal_format);
 
-  bo->width = hnd->width;
-  bo->height = hnd->height;
-  bo->hal_format = hnd->req_format;
-  bo->format = fmt;
-  bo->usage = hnd->usage;
-  bo->prime_fds[0] = hnd->share_fd;
-  bo->pitches[0] = hnd->byte_stride;
-  bo->offsets[0] = 0;
+  bi.width = hnd->width;
+  bi.height = hnd->height;
+  bi.format = fmt;
+  bi.prime_fds[0] = hnd->share_fd;
+  bi.pitches[0] = hnd->byte_stride;
+  bi.offsets[0] = 0;
 
-  return 0;
+  return bi;
 }
 
 }  // namespace android
diff --git a/bufferinfo/legacy/BufferInfoMaliMeson.h b/bufferinfo/legacy/BufferInfoMaliMeson.h
index ce5d3f9..3b6fab0 100644
--- a/bufferinfo/legacy/BufferInfoMaliMeson.h
+++ b/bufferinfo/legacy/BufferInfoMaliMeson.h
@@ -26,7 +26,7 @@
 class BufferInfoMaliMeson : public LegacyBufferInfoGetter {
  public:
   using LegacyBufferInfoGetter::LegacyBufferInfoGetter;
-  int ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
+  auto GetBoInfo(buffer_handle_t handle) -> std::optional<BufferInfo> override;
 
  private:
   uint64_t ConvertGrallocFormatToDrmModifiers(uint64_t flags);
diff --git a/bufferinfo/legacy/BufferInfoMinigbm.cpp b/bufferinfo/legacy/BufferInfoMinigbm.cpp
index d030dff..c5a9e98 100644
--- a/bufferinfo/legacy/BufferInfoMinigbm.cpp
+++ b/bufferinfo/legacy/BufferInfoMinigbm.cpp
@@ -21,35 +21,102 @@
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 
-#include "cros_gralloc_handle.h"
+#include <cerrno>
+#include <cstring>
+
 #include "utils/log.h"
-
-#define DRM_FORMAT_YVU420_ANDROID fourcc_code('9', '9', '9', '7')
-
 namespace android {
 
 LEGACY_BUFFER_INFO_GETTER(BufferInfoMinigbm);
 
-int BufferInfoMinigbm::ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) {
-  auto *gr_handle = (cros_gralloc_handle *)handle;
-  if (!gr_handle)
+constexpr int CROS_GRALLOC_DRM_GET_FORMAT = 1;
+constexpr int CROS_GRALLOC_DRM_GET_DIMENSIONS = 2;
+constexpr int CROS_GRALLOC_DRM_GET_BUFFER_INFO = 4;
+constexpr int CROS_GRALLOC_DRM_GET_USAGE = 5;
+
+struct cros_gralloc0_buffer_info {
+  uint32_t drm_fourcc;
+  int num_fds;
+  int fds[4];
+  uint64_t modifier;
+  int offset[4];
+  int stride[4];
+};
+
+auto BufferInfoMinigbm::GetBoInfo(buffer_handle_t handle)
+    -> std::optional<BufferInfo> {
+  if (handle == nullptr) {
+    return {};
+  }
+
+  BufferInfo bi{};
+
+  uint32_t width{};
+  uint32_t height{};
+  if (gralloc_->perform(gralloc_, CROS_GRALLOC_DRM_GET_DIMENSIONS, handle,
+                        &width, &height) != 0) {
+    ALOGE(
+        "CROS_GRALLOC_DRM_GET_DIMENSIONS operation has failed. "
+        "Please ensure you are using the latest minigbm.");
+    return {};
+  }
+
+  int32_t droid_format{};
+  if (gralloc_->perform(gralloc_, CROS_GRALLOC_DRM_GET_FORMAT, handle,
+                        &droid_format) != 0) {
+    ALOGE(
+        "CROS_GRALLOC_DRM_GET_FORMAT operation has failed. "
+        "Please ensure you are using the latest minigbm.");
+    return {};
+  }
+
+  uint32_t usage{};
+  if (gralloc_->perform(gralloc_, CROS_GRALLOC_DRM_GET_USAGE, handle, &usage) !=
+      0) {
+    ALOGE(
+        "CROS_GRALLOC_DRM_GET_USAGE operation has failed. "
+        "Please ensure you are using the latest minigbm.");
+    return {};
+  }
+
+  struct cros_gralloc0_buffer_info info {};
+  if (gralloc_->perform(gralloc_, CROS_GRALLOC_DRM_GET_BUFFER_INFO, handle,
+                        &info) != 0) {
+    ALOGE(
+        "CROS_GRALLOC_DRM_GET_BUFFER_INFO operation has failed. "
+        "Please ensure you are using the latest minigbm.");
+    return {};
+  }
+
+  bi.width = width;
+  bi.height = height;
+
+  bi.format = info.drm_fourcc;
+
+  for (int i = 0; i < info.num_fds; i++) {
+    bi.modifiers[i] = info.modifier;
+    bi.prime_fds[i] = info.fds[i];
+    bi.pitches[i] = info.stride[i];
+    bi.offsets[i] = info.offset[i];
+  }
+
+  return bi;
+}
+
+constexpr char cros_gralloc_module_name[] = "CrOS Gralloc";
+
+int BufferInfoMinigbm::ValidateGralloc() {
+  if (strcmp(gralloc_->common.name, cros_gralloc_module_name) != 0) {
+    ALOGE("Gralloc name isn't valid: Expected: \"%s\", Actual: \"%s\"",
+          cros_gralloc_module_name, gralloc_->common.name);
     return -EINVAL;
+  }
 
-  bo->width = gr_handle->width;
-  bo->height = gr_handle->height;
-  bo->hal_format = gr_handle->droid_format;
-
-  bo->format = gr_handle->format;
-  if (bo->format == DRM_FORMAT_YVU420_ANDROID)
-    bo->format = DRM_FORMAT_YVU420;
-
-  bo->usage = gr_handle->usage;
-
-  for (int i = 0; i < gr_handle->num_planes; i++) {
-    bo->modifiers[i] = gr_handle->format_modifier;
-    bo->prime_fds[i] = gr_handle->fds[i];
-    bo->pitches[i] = gr_handle->strides[i];
-    bo->offsets[i] = gr_handle->offsets[i];
+  if (gralloc_->perform == nullptr) {
+    ALOGE(
+        "CrOS gralloc has no perform call implemented. Please upgrade your "
+        "minigbm.");
+    return -EINVAL;
   }
 
   return 0;
diff --git a/bufferinfo/legacy/BufferInfoMinigbm.h b/bufferinfo/legacy/BufferInfoMinigbm.h
index bff9d74..40d9926 100644
--- a/bufferinfo/legacy/BufferInfoMinigbm.h
+++ b/bufferinfo/legacy/BufferInfoMinigbm.h
@@ -26,7 +26,8 @@
 class BufferInfoMinigbm : public LegacyBufferInfoGetter {
  public:
   using LegacyBufferInfoGetter::LegacyBufferInfoGetter;
-  int ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
+  auto GetBoInfo(buffer_handle_t handle) -> std::optional<BufferInfo> override;
+  int ValidateGralloc() override;
 };
 
 }  // namespace android
diff --git a/build_deploy.sh b/build_deploy.sh
new file mode 100755
index 0000000..ef25e5c
--- /dev/null
+++ b/build_deploy.sh
@@ -0,0 +1,26 @@
+#!/bin/bash -e
+
+# To see logs after deploy run: $ HWCLOG=1 TESTDEV=<DEV> ./build_deploy.sh
+
+[ -z "$TESTDEV" ] && echo "Run $ TESTDEV=<Your lunch target> ./build_deploy.sh" && false
+
+cd ../..
+. build/envsetup.sh
+lunch $TESTDEV
+cd -
+
+mm
+
+adb root && adb remount && adb sync vendor
+
+adb shell stop
+adb shell stop vendor.hwcomposer-2-1 && adb shell start vendor.hwcomposer-2-1 || true
+adb shell stop vendor.hwcomposer-2-2 && adb shell start vendor.hwcomposer-2-2 || true
+adb shell stop vendor.hwcomposer-2-3 && adb shell start vendor.hwcomposer-2-3 || true
+adb shell stop vendor.hwcomposer-2-4 && adb shell start vendor.hwcomposer-2-4 || true
+
+[ $HWCLOG -eq "1" ] && adb logcat -c
+
+adb shell start
+
+[ $HWCLOG -eq "1" ] && adb logcat | grep -i hwc
diff --git a/compositor/DrmDisplayComposition.cpp b/compositor/DrmDisplayComposition.cpp
deleted file mode 100644
index 49dff0e..0000000
--- a/compositor/DrmDisplayComposition.cpp
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "hwc-drm-display-composition"
-
-#include "DrmDisplayComposition.h"
-
-#include <sync/sync.h>
-#include <xf86drmMode.h>
-
-#include <algorithm>
-#include <cstdlib>
-#include <unordered_set>
-
-#include "DrmDisplayCompositor.h"
-#include "Planner.h"
-#include "drm/DrmDevice.h"
-#include "utils/log.h"
-
-namespace android {
-
-DrmDisplayComposition::DrmDisplayComposition(DrmCrtc *crtc, Planner *planner)
-    : crtc_(crtc),  // Can be NULL if we haven't modeset yet
-      planner_(planner) {
-}
-
-bool DrmDisplayComposition::validate_composition_type(DrmCompositionType des) {
-  return type_ == DRM_COMPOSITION_TYPE_EMPTY || type_ == des;
-}
-
-int DrmDisplayComposition::SetLayers(DrmHwcLayer *layers, size_t num_layers,
-                                     bool geometry_changed) {
-  if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME))
-    return -EINVAL;
-
-  geometry_changed_ = geometry_changed;
-
-  for (size_t layer_index = 0; layer_index < num_layers; layer_index++) {
-    layers_.emplace_back(std::move(layers[layer_index]));
-  }
-
-  type_ = DRM_COMPOSITION_TYPE_FRAME;
-  return 0;
-}
-
-int DrmDisplayComposition::SetDpmsMode(uint32_t dpms_mode) {
-  if (!validate_composition_type(DRM_COMPOSITION_TYPE_DPMS))
-    return -EINVAL;
-  dpms_mode_ = dpms_mode;
-  type_ = DRM_COMPOSITION_TYPE_DPMS;
-  return 0;
-}
-
-int DrmDisplayComposition::SetDisplayMode(const DrmMode &display_mode) {
-  if (!validate_composition_type(DRM_COMPOSITION_TYPE_MODESET)) {
-    ALOGE("SetDisplayMode() Failed to validate composition type");
-    return -EINVAL;
-  }
-  display_mode_ = display_mode;
-  dpms_mode_ = DRM_MODE_DPMS_ON;
-  type_ = DRM_COMPOSITION_TYPE_MODESET;
-  return 0;
-}
-
-int DrmDisplayComposition::AddPlaneDisable(DrmPlane *plane) {
-  composition_planes_.emplace_back(DrmCompositionPlane::Type::kDisable, plane);
-  return 0;
-}
-
-int DrmDisplayComposition::AddPlaneComposition(DrmCompositionPlane plane) {
-  composition_planes_.emplace_back(std::move(plane));
-  return 0;
-}
-
-int DrmDisplayComposition::Plan(std::vector<DrmPlane *> *primary_planes,
-                                std::vector<DrmPlane *> *overlay_planes) {
-  if (type_ != DRM_COMPOSITION_TYPE_FRAME)
-    return 0;
-
-  std::map<size_t, DrmHwcLayer *> to_composite;
-
-  for (size_t i = 0; i < layers_.size(); ++i)
-    to_composite.emplace(std::make_pair(i, &layers_[i]));
-
-  int ret = 0;
-  std::tie(ret,
-           composition_planes_) = planner_->ProvisionPlanes(to_composite, crtc_,
-                                                            primary_planes,
-                                                            overlay_planes);
-  if (ret) {
-    ALOGV("Planner failed provisioning planes ret=%d", ret);
-    return ret;
-  }
-
-  // Remove the planes we used from the pool before returning. This ensures they
-  // won't be reused by another display in the composition.
-  for (auto &i : composition_planes_) {
-    if (!i.plane())
-      continue;
-
-    // make sure that source layers are ordered based on zorder
-    std::sort(i.source_layers().begin(), i.source_layers().end());
-
-    std::vector<DrmPlane *> *container = nullptr;
-    if (i.plane()->type() == DRM_PLANE_TYPE_PRIMARY)
-      container = primary_planes;
-    else
-      container = overlay_planes;
-    for (auto j = container->begin(); j != container->end(); ++j) {
-      if (*j == i.plane()) {
-        container->erase(j);
-        break;
-      }
-    }
-  }
-
-  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
deleted file mode 100644
index 1738630..0000000
--- a/compositor/DrmDisplayComposition.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_DRM_DISPLAY_COMPOSITION_H_
-#define ANDROID_DRM_DISPLAY_COMPOSITION_H_
-
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
-
-#include <sstream>
-#include <vector>
-
-#include "drm/DrmCrtc.h"
-#include "drm/DrmPlane.h"
-#include "drmhwcomposer.h"
-
-namespace android {
-
-class Importer;
-class Planner;
-
-enum DrmCompositionType {
-  DRM_COMPOSITION_TYPE_EMPTY,
-  DRM_COMPOSITION_TYPE_FRAME,
-  DRM_COMPOSITION_TYPE_DPMS,
-  DRM_COMPOSITION_TYPE_MODESET,
-};
-
-class DrmCompositionPlane {
- public:
-  enum class Type : int32_t {
-    kDisable,
-    kLayer,
-  };
-
-  DrmCompositionPlane() = default;
-  DrmCompositionPlane(DrmCompositionPlane &&rhs) = default;
-  DrmCompositionPlane &operator=(DrmCompositionPlane &&other) = default;
-  DrmCompositionPlane(Type type, DrmPlane *plane) : type_(type), plane_(plane) {
-  }
-  DrmCompositionPlane(Type type, DrmPlane *plane, size_t source_layer)
-      : type_(type), plane_(plane), source_layers_(1, source_layer) {
-  }
-
-  Type type() const {
-    return type_;
-  }
-
-  DrmPlane *plane() const {
-    return plane_;
-  }
-  void set_plane(DrmPlane *plane) {
-    plane_ = plane;
-  }
-
-  std::vector<size_t> &source_layers() {
-    return source_layers_;
-  }
-
-  const std::vector<size_t> &source_layers() const {
-    return source_layers_;
-  }
-
- private:
-  Type type_ = Type::kDisable;
-  DrmPlane *plane_ = NULL;
-  std::vector<size_t> source_layers_;
-};
-
-class DrmDisplayComposition {
- public:
-  DrmDisplayComposition(const DrmDisplayComposition &) = delete;
-  DrmDisplayComposition(DrmCrtc *crtc, Planner *planner);
-  ~DrmDisplayComposition() = default;
-
-  int SetLayers(DrmHwcLayer *layers, size_t num_layers, bool geometry_changed);
-  int AddPlaneComposition(DrmCompositionPlane plane);
-  int AddPlaneDisable(DrmPlane *plane);
-  int SetDpmsMode(uint32_t dpms_mode);
-  int SetDisplayMode(const DrmMode &display_mode);
-
-  int Plan(std::vector<DrmPlane *> *primary_planes,
-           std::vector<DrmPlane *> *overlay_planes);
-
-  std::vector<DrmHwcLayer> &layers() {
-    return layers_;
-  }
-
-  std::vector<DrmCompositionPlane> &composition_planes() {
-    return composition_planes_;
-  }
-
-  bool geometry_changed() const {
-    return geometry_changed_;
-  }
-
-  DrmCompositionType type() const {
-    return type_;
-  }
-
-  uint32_t dpms_mode() const {
-    return dpms_mode_;
-  }
-
-  const DrmMode &display_mode() const {
-    return display_mode_;
-  }
-
-  DrmCrtc *crtc() const {
-    return crtc_;
-  }
-
-  Planner *planner() const {
-    return planner_;
-  }
-
-  void Dump(std::ostringstream *out) const;
-
-  UniqueFd out_fence_;
-
- private:
-  bool validate_composition_type(DrmCompositionType desired);
-
-  DrmCrtc *crtc_ = NULL;
-  Planner *planner_ = NULL;
-
-  DrmCompositionType type_ = DRM_COMPOSITION_TYPE_EMPTY;
-  uint32_t dpms_mode_ = DRM_MODE_DPMS_ON;
-  DrmMode display_mode_;
-
-  bool geometry_changed_ = true;
-  std::vector<DrmHwcLayer> layers_;
-  std::vector<DrmCompositionPlane> composition_planes_;
-};
-}  // namespace android
-
-#endif  // ANDROID_DRM_DISPLAY_COMPOSITION_H_
diff --git a/compositor/DrmDisplayCompositor.cpp b/compositor/DrmDisplayCompositor.cpp
deleted file mode 100644
index a1fe50f..0000000
--- a/compositor/DrmDisplayCompositor.cpp
+++ /dev/null
@@ -1,767 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#define LOG_TAG "hwc-drm-display-compositor"
-
-#include "DrmDisplayCompositor.h"
-
-#include <drm/drm_mode.h>
-#include <pthread.h>
-#include <sched.h>
-#include <sync/sync.h>
-#include <utils/Trace.h>
-
-#include <array>
-#include <cstdlib>
-#include <ctime>
-#include <sstream>
-#include <vector>
-
-#include "drm/DrmCrtc.h"
-#include "drm/DrmDevice.h"
-#include "drm/DrmPlane.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;
-}
-
-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) {
-  resource_manager_ = resource_manager;
-  display_ = display;
-  DrmDevice *drm = resource_manager_->GetDrmDevice(display);
-  if (!drm) {
-    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;
-}
-
-std::unique_ptr<DrmDisplayComposition>
-DrmDisplayCompositor::CreateInitializedComposition() const {
-  DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
-  DrmCrtc *crtc = drm->GetCrtcForDisplay(display_);
-  if (!crtc) {
-    ALOGE("Failed to find crtc for display = %d", display_);
-    return std::unique_ptr<DrmDisplayComposition>();
-  }
-
-  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_);
-  DrmConnector *connector = drm->GetConnectorForDisplay(display_);
-  if (connector == nullptr) {
-    ALOGE("Failed to determine display mode: no connector for display %d",
-          display_);
-    return std::make_tuple(0, 0, -ENODEV);
-  }
-
-  const DrmMode &mode = connector->active_mode();
-  return std::make_tuple(mode.h_display(), mode.v_display(), 0);
-}
-
-int DrmDisplayCompositor::DisablePlanes(DrmDisplayComposition *display_comp) {
-  drmModeAtomicReqPtr pset = drmModeAtomicAlloc();
-  if (!pset) {
-    ALOGE("Failed to allocate property set");
-    return -ENOMEM;
-  }
-
-  int ret = 0;
-  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;
-    }
-  }
-  DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
-  ret = drmModeAtomicCommit(drm->fd(), pset, 0, drm);
-  if (ret) {
-    ALOGE("Failed to commit pset ret=%d\n", ret);
-    drmModeAtomicFree(pset);
-    return ret;
-  }
-
-  drmModeAtomicFree(pset);
-  return 0;
-}
-
-int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp,
-                                      bool test_only) {
-  ATRACE_CALL();
-
-  int ret = 0;
-
-  std::vector<DrmHwcLayer> &layers = display_comp->layers();
-  std::vector<DrmCompositionPlane> &comp_planes = display_comp
-                                                      ->composition_planes();
-  DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
-  uint64_t out_fences[drm->crtcs().size()];
-
-  DrmConnector *connector = drm->GetConnectorForDisplay(display_);
-  if (!connector) {
-    ALOGE("Could not locate connector for display %d", display_);
-    return -ENODEV;
-  }
-  DrmCrtc *crtc = drm->GetCrtcForDisplay(display_);
-  if (!crtc) {
-    ALOGE("Could not locate crtc for display %d", display_);
-    return -ENODEV;
-  }
-
-  drmModeAtomicReqPtr pset = drmModeAtomicAlloc();
-  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 (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;
-    }
-  }
-
-  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",
-              source_layers.size(), comp_plane.type());
-        continue;
-      }
-
-      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;
-      }
-      DrmHwcLayer &layer = layers[source_layers.front()];
-      if (!layer.FbIdHandle) {
-        ALOGE("Expected a valid framebuffer for pset");
-        break;
-      }
-      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;
-      }
-    }
-  }
-
-  if (!ret) {
-    uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
-    if (test_only)
-      flags |= DRM_MODE_ATOMIC_TEST_ONLY;
-
-    ret = drmModeAtomicCommit(drm->fd(), pset, 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;
-    }
-
-    /* TODO: Add dpms to the pset when the kernel supports it */
-    ret = ApplyDpms(display_comp);
-    if (ret) {
-      ALOGE("Failed to apply DPMS after modeset %d\n", ret);
-      return ret;
-    }
-
-    connector->set_active_mode(mode_.mode);
-    mode_.old_blob_id = mode_.blob_id;
-    mode_.blob_id = 0;
-    mode_.needs_modeset = false;
-  }
-
-  if (crtc->out_fence_ptr_property().id()) {
-    display_comp->out_fence_ = UniqueFd((int)out_fences[crtc->pipe()]);
-  }
-
-  return ret;
-}
-
-int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
-  DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
-  DrmConnector *conn = drm->GetConnectorForDisplay(display_);
-  if (!conn) {
-    ALOGE("Failed to get DrmConnector for display %d", display_);
-    return -ENODEV;
-  }
-
-  const DrmProperty &prop = conn->dpms_property();
-  int ret = drmModeConnectorSetProperty(drm->fd(), conn->id(), prop.id(),
-                                        display_comp->dpms_mode());
-  if (ret) {
-    ALOGE("Failed to set DPMS property for connector %d", conn->id());
-    return ret;
-  }
-  return 0;
-}
-
-std::tuple<int, uint32_t> DrmDisplayCompositor::CreateModeBlob(
-    const DrmMode &mode) {
-  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);
-}
-
-void DrmDisplayCompositor::ClearDisplay() {
-  if (!active_composition_)
-    return;
-
-  if (DisablePlanes(active_composition_.get()))
-    return;
-
-  active_composition_.reset(nullptr);
-}
-
-void DrmDisplayCompositor::ApplyFrame(
-    std::unique_ptr<DrmDisplayComposition> composition, int status) {
-  AutoLock lock(&lock_, __func__);
-  if (lock.Lock())
-    return;
-  int ret = status;
-
-  if (!ret) {
-    ret = CommitFrame(composition.get(), false);
-  }
-
-  if (ret) {
-    ALOGE("Composite failed for display %d", display_);
-    // Disable the hw used by the last active composition. This allows us to
-    // signal the release fences from that composition to avoid hanging.
-    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(
-    std::unique_ptr<DrmDisplayComposition> composition) {
-  int ret = 0;
-  switch (composition->type()) {
-    case DRM_COMPOSITION_TYPE_FRAME:
-      if (composition->geometry_changed()) {
-        // Send the composition to the kernel to ensure we can commit it. This
-        // is just a test, it won't actually commit the frame.
-        ret = CommitFrame(composition.get(), true);
-        if (ret) {
-          ALOGE("Commit test failed for display %d, FIXME", display_);
-          return ret;
-        }
-      }
-
-      ApplyFrame(std::move(composition), ret);
-      break;
-    case DRM_COMPOSITION_TYPE_DPMS:
-      active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON);
-      ret = ApplyDpms(composition.get());
-      if (ret)
-        ALOGE("Failed to apply dpms for display %d", display_);
-      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) {
-        ALOGE("Failed to create mode blob for display %d", display_);
-        return ret;
-      }
-      mode_.needs_modeset = true;
-      return 0;
-    default:
-      ALOGE("Unknown composition type %d", composition->type());
-      return -EINVAL;
-  }
-
-  return ret;
-}
-
-int DrmDisplayCompositor::TestComposition(DrmDisplayComposition *composition) {
-  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
deleted file mode 100644
index c0eed0c..0000000
--- a/compositor/DrmDisplayCompositor.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_DRM_DISPLAY_COMPOSITOR_H_
-#define ANDROID_DRM_DISPLAY_COMPOSITOR_H_
-
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
-#include <pthread.h>
-
-#include <functional>
-#include <memory>
-#include <sstream>
-#include <tuple>
-
-#include "DrmDisplayComposition.h"
-#include "Planner.h"
-#include "drm/ResourceManager.h"
-#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);
-  }
-
-  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_) {
-      return UniqueFd();
-    }
-    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;
-  };
-
-  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);
-
-  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);
-
-  ResourceManager *resource_manager_;
-  int display_;
-
-  std::unique_ptr<DrmDisplayComposition> active_composition_;
-
-  bool initialized_;
-  bool active_;
-  bool use_hw_overlays_;
-
-  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
-
-#endif  // ANDROID_DRM_DISPLAY_COMPOSITOR_H_
diff --git a/compositor/DrmKmsPlan.cpp b/compositor/DrmKmsPlan.cpp
new file mode 100644
index 0000000..6289b84
--- /dev/null
+++ b/compositor/DrmKmsPlan.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "hwc-composition-drm-kms-plan"
+
+#include "DrmKmsPlan.h"
+
+#include "drm/DrmDevice.h"
+#include "drm/DrmPlane.h"
+#include "utils/log.h"
+
+namespace android {
+auto DrmKmsPlan::CreateDrmKmsPlan(DrmDisplayPipeline &pipe,
+                                  std::vector<LayerData> composition)
+    -> std::unique_ptr<DrmKmsPlan> {
+  auto plan = std::make_unique<DrmKmsPlan>();
+
+  auto avail_planes = pipe.GetUsablePlanes();
+
+  int z_pos = 0;
+  for (auto &dhl : composition) {
+    std::shared_ptr<BindingOwner<DrmPlane>> plane;
+
+    /* Skip unsupported planes */
+    do {
+      if (avail_planes.empty()) {
+        return {};
+      }
+
+      plane = *avail_planes.begin();
+      avail_planes.erase(avail_planes.begin());
+    } while (!plane->Get()->IsValidForLayer(&dhl));
+
+    LayerToPlaneJoining joining = {
+        .layer = std::move(dhl),
+        .plane = plane,
+        .z_pos = z_pos++,
+    };
+
+    plan->plan.emplace_back(std::move(joining));
+  }
+
+  return plan;
+}
+
+}  // namespace android
diff --git a/compositor/DrmKmsPlan.h b/compositor/DrmKmsPlan.h
new file mode 100644
index 0000000..91f636e
--- /dev/null
+++ b/compositor/DrmKmsPlan.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_DRM_KMS_PLAN_H_
+#define ANDROID_DRM_KMS_PLAN_H_
+
+#include <memory>
+#include <vector>
+
+#include "LayerData.h"
+
+namespace android {
+
+class DrmDevice;
+
+struct DrmKmsPlan {
+  struct LayerToPlaneJoining {
+    LayerData layer;
+    std::shared_ptr<BindingOwner<DrmPlane>> plane;
+    int z_pos;
+  };
+
+  std::vector<LayerToPlaneJoining> plan;
+
+  static auto CreateDrmKmsPlan(DrmDisplayPipeline &pipe,
+                               std::vector<LayerData> composition)
+      -> std::unique_ptr<DrmKmsPlan>;
+};
+
+}  // namespace android
+#endif
diff --git a/compositor/LayerData.h b/compositor/LayerData.h
new file mode 100644
index 0000000..d04514d
--- /dev/null
+++ b/compositor/LayerData.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#pragma once
+
+#include <hardware/hardware.h>
+#include <hardware/hwcomposer.h>
+
+#include <cmath>
+#include <cstdbool>
+#include <cstdint>
+#include <optional>
+#include <vector>
+
+#include "bufferinfo/BufferInfo.h"
+#include "drm/DrmFbImporter.h"
+#include "utils/UniqueFd.h"
+
+namespace android {
+
+class DrmFbIdHandle;
+
+enum LayerTransform : uint32_t {
+  kIdentity = 0,
+  kFlipH = 1 << 0,
+  kFlipV = 1 << 1,
+  kRotate90 = 1 << 2,
+  kRotate180 = 1 << 3,
+  kRotate270 = 1 << 4,
+};
+
+struct PresentInfo {
+  LayerTransform transform{};
+  uint16_t alpha = UINT16_MAX;
+  hwc_frect_t source_crop{};
+  hwc_rect_t display_frame{};
+
+  bool RequireScalingOrPhasing() const {
+    float src_width = source_crop.right - source_crop.left;
+    float src_height = source_crop.bottom - source_crop.top;
+
+    auto dest_width = float(display_frame.right - display_frame.left);
+    auto dest_height = float(display_frame.bottom - display_frame.top);
+
+    bool scaling = src_width != dest_width || src_height != dest_height;
+    bool phasing = (source_crop.left - std::floor(source_crop.left) != 0) ||
+                   (source_crop.top - std::floor(source_crop.top) != 0);
+    return scaling || phasing;
+  }
+};
+
+struct LayerData {
+  auto Clone() {
+    LayerData clonned;
+    clonned.bi = bi;
+    clonned.fb = fb;
+    clonned.pi = pi;
+    clonned.acquire_fence = std::move(acquire_fence);
+    return clonned;
+  }
+
+  std::optional<BufferInfo> bi;
+  std::shared_ptr<DrmFbIdHandle> fb;
+  PresentInfo pi;
+  UniqueFd acquire_fence;
+};
+
+}  // namespace android
diff --git a/compositor/Planner.cpp b/compositor/Planner.cpp
deleted file mode 100644
index 9db03c3..0000000
--- a/compositor/Planner.cpp
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "hwc-platform"
-
-#include "Planner.h"
-
-#include <algorithm>
-
-#include "drm/DrmDevice.h"
-#include "utils/log.h"
-
-namespace android {
-
-std::unique_ptr<Planner> Planner::CreateInstance(DrmDevice * /*device*/) {
-  std::unique_ptr<Planner> planner(new Planner);
-  planner->AddStage<PlanStageGreedy>();
-  return planner;
-}
-
-std::vector<DrmPlane *> Planner::GetUsablePlanes(
-    DrmCrtc *crtc, std::vector<DrmPlane *> *primary_planes,
-    std::vector<DrmPlane *> *overlay_planes) {
-  std::vector<DrmPlane *> usable_planes;
-  std::copy_if(primary_planes->begin(), primary_planes->end(),
-               std::back_inserter(usable_planes),
-               [=](DrmPlane *plane) { return plane->GetCrtcSupported(*crtc); });
-  std::copy_if(overlay_planes->begin(), overlay_planes->end(),
-               std::back_inserter(usable_planes),
-               [=](DrmPlane *plane) { return plane->GetCrtcSupported(*crtc); });
-  return usable_planes;
-}
-
-std::tuple<int, std::vector<DrmCompositionPlane>> Planner::ProvisionPlanes(
-    std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc,
-    std::vector<DrmPlane *> *primary_planes,
-    std::vector<DrmPlane *> *overlay_planes) {
-  std::vector<DrmCompositionPlane> composition;
-  std::vector<DrmPlane *> planes = GetUsablePlanes(crtc, primary_planes,
-                                                   overlay_planes);
-  if (planes.empty()) {
-    ALOGE("Display %d has no usable planes", crtc->display());
-    return std::make_tuple(-ENODEV, std::vector<DrmCompositionPlane>());
-  }
-
-  // Go through the provisioning stages and provision planes
-  for (auto &i : stages_) {
-    int ret = i->ProvisionPlanes(&composition, layers, &planes);
-    if (ret) {
-      ALOGV("Failed provision stage with ret %d", ret);
-      return std::make_tuple(ret, std::vector<DrmCompositionPlane>());
-    }
-  }
-
-  return std::make_tuple(0, std::move(composition));
-}
-
-int PlanStageProtected::ProvisionPlanes(
-    std::vector<DrmCompositionPlane> *composition,
-    std::map<size_t, DrmHwcLayer *> &layers,
-    std::vector<DrmPlane *> *planes) {
-  int ret = 0;
-  for (auto i = layers.begin(); i != layers.end();) {
-    if (!i->second->protected_usage()) {
-      ++i;
-      continue;
-    }
-
-    ret = Emplace(composition, planes, DrmCompositionPlane::Type::kLayer,
-                  std::make_pair(i->first, i->second));
-    if (ret) {
-      ALOGE("Failed to dedicate protected layer! Dropping it.");
-      return ret;
-    }
-
-    i = layers.erase(i);
-  }
-
-  return 0;
-}
-
-int PlanStageGreedy::ProvisionPlanes(
-    std::vector<DrmCompositionPlane> *composition,
-    std::map<size_t, DrmHwcLayer *> &layers,
-    std::vector<DrmPlane *> *planes) {
-  // Fill up the remaining planes
-  for (auto i = layers.begin(); i != layers.end(); i = layers.erase(i)) {
-    int ret = Emplace(composition, planes, DrmCompositionPlane::Type::kLayer,
-                      std::make_pair(i->first, i->second));
-    // We don't have any planes left
-    if (ret == -ENOENT)
-      break;
-
-    if (ret) {
-      ALOGV("Failed to emplace layer %zu, dropping it", i->first);
-      return ret;
-    }
-  }
-
-  return 0;
-}
-}  // namespace android
diff --git a/compositor/Planner.h b/compositor/Planner.h
deleted file mode 100644
index 3390acb..0000000
--- a/compositor/Planner.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_DRM_PLATFORM_H_
-#define ANDROID_DRM_PLATFORM_H_
-
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
-
-#include <map>
-#include <memory>
-#include <vector>
-
-#include "compositor/DrmDisplayComposition.h"
-#include "drmhwcomposer.h"
-
-namespace android {
-
-class DrmDevice;
-
-class Planner {
- public:
-  class PlanStage {
-   public:
-    virtual ~PlanStage() {
-    }
-
-    virtual int ProvisionPlanes(std::vector<DrmCompositionPlane> *composition,
-                                std::map<size_t, DrmHwcLayer *> &layers,
-                                std::vector<DrmPlane *> *planes) = 0;
-
-   protected:
-    // Removes and returns the next available plane from planes
-    static DrmPlane *PopPlane(std::vector<DrmPlane *> *planes) {
-      if (planes->empty())
-        return NULL;
-      DrmPlane *plane = planes->front();
-      planes->erase(planes->begin());
-      return plane;
-    }
-
-    // Inserts the given layer:plane in the composition at the back
-    static int Emplace(std::vector<DrmCompositionPlane> *composition,
-                       std::vector<DrmPlane *> *planes,
-                       DrmCompositionPlane::Type type,
-                       std::pair<size_t, DrmHwcLayer *> layer) {
-      DrmPlane *plane = PopPlane(planes);
-      std::vector<DrmPlane *> unused_planes;
-      int ret = -ENOENT;
-      while (plane) {
-        ret = plane->IsValidForLayer(layer.second) ? 0 : -EINVAL;
-        if (!ret)
-          break;
-        if (!plane->zpos_property().is_immutable())
-          unused_planes.push_back(plane);
-        plane = PopPlane(planes);
-      }
-
-      if (!ret) {
-        composition->emplace_back(type, plane, layer.first);
-        planes->insert(planes->begin(), unused_planes.begin(),
-                       unused_planes.end());
-      }
-
-      return ret;
-    }
-  };
-
-  // Creates a planner instance with platform-specific planning stages
-  static std::unique_ptr<Planner> CreateInstance(DrmDevice *drm);
-
-  // Takes a stack of layers and provisions hardware planes for them. If the
-  // entire stack can't fit in hardware, FIXME
-  //
-  // @layers: a map of index:layer of layers to composite
-  // @primary_planes: a vector of primary planes available for this frame
-  // @overlay_planes: a vector of overlay planes available for this frame
-  //
-  // Returns: A tuple with the status of the operation (0 for success) and
-  //          a vector of the resulting plan (ie: layer->plane mapping).
-  std::tuple<int, std::vector<DrmCompositionPlane>> ProvisionPlanes(
-      std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc,
-      std::vector<DrmPlane *> *primary_planes,
-      std::vector<DrmPlane *> *overlay_planes);
-
-  template <typename T, typename... A>
-  void AddStage(A &&...args) {
-    stages_.emplace_back(
-        std::unique_ptr<PlanStage>(new T(std::forward(args)...)));
-  }
-
- private:
-  std::vector<DrmPlane *> GetUsablePlanes(
-      DrmCrtc *crtc, std::vector<DrmPlane *> *primary_planes,
-      std::vector<DrmPlane *> *overlay_planes);
-
-  std::vector<std::unique_ptr<PlanStage>> stages_;
-};
-
-// This plan stage extracts all protected layers and places them on dedicated
-// planes.
-class PlanStageProtected : public Planner::PlanStage {
- public:
-  int ProvisionPlanes(std::vector<DrmCompositionPlane> *composition,
-                      std::map<size_t, DrmHwcLayer *> &layers,
-                      std::vector<DrmPlane *> *planes);
-};
-
-// This plan stage places as many layers on dedicated planes as possible (first
-// come first serve), and then sticks the rest in a precomposition plane (if
-// needed).
-class PlanStageGreedy : public Planner::PlanStage {
- public:
-  int ProvisionPlanes(std::vector<DrmCompositionPlane> *composition,
-                      std::map<size_t, DrmHwcLayer *> &layers,
-                      std::vector<DrmPlane *> *planes);
-};
-}  // namespace android
-#endif
diff --git a/drm/DrmAtomicStateManager.cpp b/drm/DrmAtomicStateManager.cpp
new file mode 100644
index 0000000..5d2eebd
--- /dev/null
+++ b/drm/DrmAtomicStateManager.cpp
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#undef NDEBUG /* Required for assert to work */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#define LOG_TAG "hwc-drm-atomic-state-manager"
+
+#include "DrmAtomicStateManager.h"
+
+#include <drm/drm_mode.h>
+#include <pthread.h>
+#include <sched.h>
+#include <sync/sync.h>
+#include <utils/Trace.h>
+
+#include <array>
+#include <cassert>
+#include <cstdlib>
+#include <ctime>
+#include <sstream>
+#include <vector>
+
+#include "drm/DrmCrtc.h"
+#include "drm/DrmDevice.h"
+#include "drm/DrmPlane.h"
+#include "drm/DrmUnique.h"
+#include "utils/log.h"
+
+namespace android {
+
+// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
+auto DrmAtomicStateManager::CommitFrame(AtomicCommitArgs &args) -> int {
+  ATRACE_CALL();
+
+  if (args.active && *args.active == active_frame_state_.crtc_active_state) {
+    /* Don't set the same state twice */
+    args.active.reset();
+  }
+
+  if (!args.HasInputs()) {
+    /* nothing to do */
+    return 0;
+  }
+
+  if (!active_frame_state_.crtc_active_state) {
+    /* Force activate display */
+    args.active = true;
+  }
+
+  auto new_frame_state = NewFrameState();
+
+  auto *drm = pipe_->device;
+  auto *connector = pipe_->connector->Get();
+  auto *crtc = pipe_->crtc->Get();
+
+  auto pset = MakeDrmModeAtomicReqUnique();
+  if (!pset) {
+    ALOGE("Failed to allocate property set");
+    return -ENOMEM;
+  }
+
+  int out_fence = -1;
+  if (!crtc->GetOutFencePtrProperty().AtomicSet(*pset, uint64_t(&out_fence))) {
+    return -EINVAL;
+  }
+
+  bool nonblock = true;
+
+  if (args.active) {
+    nonblock = false;
+    new_frame_state.crtc_active_state = *args.active;
+    if (!crtc->GetActiveProperty().AtomicSet(*pset, *args.active ? 1 : 0) ||
+        !connector->GetCrtcIdProperty().AtomicSet(*pset, crtc->GetId())) {
+      return -EINVAL;
+    }
+  }
+
+  if (args.display_mode) {
+    new_frame_state.mode_blob = args.display_mode.value().CreateModeBlob(*drm);
+
+    if (!new_frame_state.mode_blob) {
+      ALOGE("Failed to create mode_blob");
+      return -EINVAL;
+    }
+
+    if (!crtc->GetModeProperty().AtomicSet(*pset, *new_frame_state.mode_blob)) {
+      return -EINVAL;
+    }
+  }
+
+  auto unused_planes = new_frame_state.used_planes;
+
+  if (args.composition) {
+    new_frame_state.used_planes.clear();
+
+    for (auto &joining : args.composition->plan) {
+      DrmPlane *plane = joining.plane->Get();
+      LayerData &layer = joining.layer;
+
+      new_frame_state.used_framebuffers.emplace_back(layer.fb);
+      new_frame_state.used_planes.emplace_back(joining.plane);
+
+      /* Remove from 'unused' list, since plane is re-used */
+      auto &v = unused_planes;
+      v.erase(std::remove(v.begin(), v.end(), joining.plane), v.end());
+
+      if (plane->AtomicSetState(*pset, layer, joining.z_pos, crtc->GetId()) !=
+          0) {
+        return -EINVAL;
+      }
+    }
+  }
+
+  if (args.composition) {
+    for (auto &plane : unused_planes) {
+      if (plane->Get()->AtomicDisablePlane(*pset) != 0) {
+        return -EINVAL;
+      }
+    }
+  }
+
+  uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
+
+  if (args.test_only) {
+    return drmModeAtomicCommit(drm->GetFd(), pset.get(),
+                               flags | DRM_MODE_ATOMIC_TEST_ONLY, drm);
+  }
+
+  if (last_present_fence_) {
+    ATRACE_NAME("WaitPriorFramePresented");
+
+    constexpr int kTimeoutMs = 500;
+    int err = sync_wait(last_present_fence_.Get(), kTimeoutMs);
+    if (err != 0) {
+      ALOGE("sync_wait(fd=%i) returned: %i (errno: %i)",
+            last_present_fence_.Get(), err, errno);
+    }
+
+    CleanupPriorFrameResources();
+  }
+
+  if (nonblock) {
+    flags |= DRM_MODE_ATOMIC_NONBLOCK;
+  }
+
+  int err = drmModeAtomicCommit(drm->GetFd(), pset.get(), flags, drm);
+
+  if (err != 0) {
+    ALOGE("Failed to commit pset ret=%d\n", err);
+    return err;
+  }
+
+  if (nonblock) {
+    last_present_fence_ = UniqueFd::Dup(out_fence);
+    staged_frame_state_ = std::move(new_frame_state);
+    frames_staged_++;
+    ptt_->Notify();
+  } else {
+    active_frame_state_ = std::move(new_frame_state);
+  }
+
+  if (args.display_mode) {
+    /* TODO(nobody): we still need this for synthetic vsync, remove after
+     * vsync reworked */
+    connector->SetActiveMode(*args.display_mode);
+  }
+
+  args.out_fence = UniqueFd(out_fence);
+
+  return 0;
+}
+
+PresentTrackerThread::PresentTrackerThread(DrmAtomicStateManager *st_man)
+    : st_man_(st_man),
+      mutex_(&st_man_->pipe_->device->GetResMan().GetMainLock()) {
+  pt_ = std::thread(&PresentTrackerThread::PresentTrackerThreadFn, this);
+}
+
+PresentTrackerThread::~PresentTrackerThread() {
+  ALOGI("PresentTrackerThread successfully destroyed");
+}
+
+void PresentTrackerThread::PresentTrackerThreadFn() {
+  /* object should be destroyed on thread exit */
+  auto self = std::unique_ptr<PresentTrackerThread>(this);
+
+  int tracking_at_the_moment = -1;
+
+  for (;;) {
+    UniqueFd present_fence;
+
+    {
+      std::unique_lock lk(*mutex_);
+      cv_.wait(lk, [&] {
+        return st_man_ == nullptr ||
+               st_man_->frames_staged_ > tracking_at_the_moment;
+      });
+
+      if (st_man_ == nullptr) {
+        break;
+      }
+
+      tracking_at_the_moment = st_man_->frames_staged_;
+
+      present_fence = UniqueFd::Dup(st_man_->last_present_fence_.Get());
+      if (!present_fence) {
+        continue;
+      }
+    }
+
+    {
+      ATRACE_NAME("AsyncWaitForBuffersSwap");
+      constexpr int kTimeoutMs = 500;
+      int err = sync_wait(present_fence.Get(), kTimeoutMs);
+      if (err != 0) {
+        ALOGE("sync_wait(fd=%i) returned: %i (errno: %i)", present_fence.Get(),
+              err, errno);
+      }
+    }
+
+    {
+      std::unique_lock lk(*mutex_);
+      if (st_man_ == nullptr) {
+        break;
+      }
+
+      /* If resources is already cleaned-up by main thread, skip */
+      if (tracking_at_the_moment > st_man_->frames_tracked_) {
+        st_man_->CleanupPriorFrameResources();
+      }
+    }
+  }
+}
+
+void DrmAtomicStateManager::CleanupPriorFrameResources() {
+  assert(frames_staged_ - frames_tracked_ == 1);
+  assert(last_present_fence_);
+
+  ATRACE_NAME("CleanupPriorFrameResources");
+  frames_tracked_++;
+  active_frame_state_ = std::move(staged_frame_state_);
+  last_present_fence_ = {};
+}
+
+auto DrmAtomicStateManager::ExecuteAtomicCommit(AtomicCommitArgs &args) -> int {
+  int err = CommitFrame(args);
+
+  if (!args.test_only) {
+    if (err != 0) {
+      ALOGE("Composite failed for pipeline %s",
+            pipe_->connector->Get()->GetName().c_str());
+      // Disable the hw used by the last active composition. This allows us to
+      // signal the release fences from that composition to avoid hanging.
+      AtomicCommitArgs cl_args{};
+      cl_args.composition = std::make_shared<DrmKmsPlan>();
+      if (CommitFrame(cl_args) != 0) {
+        ALOGE("Failed to clean-up active composition for pipeline %s",
+              pipe_->connector->Get()->GetName().c_str());
+      }
+      return err;
+    }
+  }
+
+  return err;
+}  // namespace android
+
+auto DrmAtomicStateManager::ActivateDisplayUsingDPMS() -> int {
+  return drmModeConnectorSetProperty(pipe_->device->GetFd(),
+                                     pipe_->connector->Get()->GetId(),
+                                     pipe_->connector->Get()
+                                         ->GetDpmsProperty()
+                                         .id(),
+                                     DRM_MODE_DPMS_ON);
+}
+
+}  // namespace android
diff --git a/drm/DrmAtomicStateManager.h b/drm/DrmAtomicStateManager.h
new file mode 100644
index 0000000..b0b85ac
--- /dev/null
+++ b/drm/DrmAtomicStateManager.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_DRM_ATOMIC_STATE_MANAGER_H_
+#define ANDROID_DRM_ATOMIC_STATE_MANAGER_H_
+
+#include <pthread.h>
+
+#include <functional>
+#include <memory>
+#include <optional>
+#include <sstream>
+#include <tuple>
+
+#include "compositor/DrmKmsPlan.h"
+#include "compositor/LayerData.h"
+#include "drm/DrmPlane.h"
+#include "drm/ResourceManager.h"
+#include "drm/VSyncWorker.h"
+
+namespace android {
+
+struct AtomicCommitArgs {
+  /* inputs. All fields are optional, but at least one has to be specified */
+  bool test_only = false;
+  std::optional<DrmMode> display_mode;
+  std::optional<bool> active;
+  std::shared_ptr<DrmKmsPlan> composition;
+
+  /* out */
+  UniqueFd out_fence;
+
+  /* helpers */
+  auto HasInputs() -> bool {
+    return display_mode || active || composition;
+  }
+};
+
+class PresentTrackerThread {
+ public:
+  explicit PresentTrackerThread(DrmAtomicStateManager *st_man);
+
+  ~PresentTrackerThread();
+
+  void Stop() {
+    /* Exit thread by signalling that object is no longer valid */
+    st_man_ = nullptr;
+    Notify();
+    pt_.detach();
+  }
+
+  void Notify() {
+    cv_.notify_all();
+  }
+
+ private:
+  DrmAtomicStateManager *st_man_{};
+
+  void PresentTrackerThreadFn();
+
+  std::condition_variable cv_;
+  std::thread pt_;
+  std::mutex *mutex_;
+};
+
+class DrmAtomicStateManager {
+  friend class PresentTrackerThread;
+
+ public:
+  explicit DrmAtomicStateManager(DrmDisplayPipeline *pipe)
+      : pipe_(pipe),
+        ptt_(std::make_unique<PresentTrackerThread>(this).release()){};
+
+  DrmAtomicStateManager(const DrmAtomicStateManager &) = delete;
+  ~DrmAtomicStateManager() {
+    ptt_->Stop();
+  }
+
+  auto ExecuteAtomicCommit(AtomicCommitArgs &args) -> int;
+  auto ActivateDisplayUsingDPMS() -> int;
+
+ private:
+  auto CommitFrame(AtomicCommitArgs &args) -> int;
+
+  struct KmsState {
+    /* Required to cleanup unused planes */
+    std::vector<std::shared_ptr<BindingOwner<DrmPlane>>> used_planes;
+    /* We have to hold a reference to framebuffer while displaying it ,
+     * otherwise picture will blink */
+    std::vector<std::shared_ptr<DrmFbIdHandle>> used_framebuffers;
+
+    DrmModeUserPropertyBlobUnique mode_blob;
+
+    int release_fence_pt_index{};
+
+    /* To avoid setting the inactive state twice, which will fail the commit */
+    bool crtc_active_state{};
+  } active_frame_state_;
+
+  auto NewFrameState() -> KmsState {
+    auto *prev_frame_state = &active_frame_state_;
+    return (KmsState){
+        .used_planes = prev_frame_state->used_planes,
+        .crtc_active_state = prev_frame_state->crtc_active_state,
+    };
+  }
+
+  DrmDisplayPipeline *const pipe_;
+
+  void CleanupPriorFrameResources();
+
+  /* Present (swap) tracking */
+  PresentTrackerThread *ptt_;
+  KmsState staged_frame_state_;
+  UniqueFd last_present_fence_;
+  int frames_staged_{};
+  int frames_tracked_{};
+};
+
+}  // namespace android
+
+#endif  // ANDROID_DRM_DISPLAY_COMPOSITOR_H_
diff --git a/drm/DrmConnector.cpp b/drm/DrmConnector.cpp
index 0468527..4737316 100644
--- a/drm/DrmConnector.cpp
+++ b/drm/DrmConnector.cpp
@@ -28,227 +28,164 @@
 #include "DrmDevice.h"
 #include "utils/log.h"
 
+#ifndef DRM_MODE_CONNECTOR_SPI
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
+#define DRM_MODE_CONNECTOR_SPI 19
+#endif
+
+#ifndef DRM_MODE_CONNECTOR_USB
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
+#define DRM_MODE_CONNECTOR_USB 20
+#endif
+
 namespace android {
 
-constexpr size_t kTypesCount = 17;
+constexpr size_t kTypesCount = 21;
 
-DrmConnector::DrmConnector(DrmDevice *drm, drmModeConnectorPtr c,
-                           DrmEncoder *current_encoder,
-                           std::vector<DrmEncoder *> &possible_encoders)
-    : drm_(drm),
-      id_(c->connector_id),
-      encoder_(current_encoder),
-      display_(-1),
-      type_(c->connector_type),
-      type_id_(c->connector_type_id),
-      state_(c->connection),
-      mm_width_(c->mmWidth),
-      mm_height_(c->mmHeight),
-      possible_encoders_(possible_encoders) {
+static bool GetOptionalConnectorProperty(const DrmDevice &dev,
+                                         const DrmConnector &connector,
+                                         const char *prop_name,
+                                         DrmProperty *property) {
+  return dev.GetProperty(connector.GetId(), DRM_MODE_OBJECT_CONNECTOR,
+                         prop_name, property) == 0;
 }
 
-int DrmConnector::Init() {
-  int ret = drm_->GetConnectorProperty(*this, "DPMS", &dpms_property_);
-  if (ret) {
-    ALOGE("Could not get DPMS property\n");
-    return ret;
+static bool GetConnectorProperty(const DrmDevice &dev,
+                                 const DrmConnector &connector,
+                                 const char *prop_name, DrmProperty *property) {
+  if (!GetOptionalConnectorProperty(dev, connector, prop_name, property)) {
+    ALOGE("Could not get %s property\n", prop_name);
+    return false;
   }
-  ret = drm_->GetConnectorProperty(*this, "CRTC_ID", &crtc_id_property_);
-  if (ret) {
-    ALOGE("Could not get CRTC_ID property\n");
-    return ret;
+  return true;
+}
+
+auto DrmConnector::CreateInstance(DrmDevice &dev, uint32_t connector_id,
+                                  uint32_t index)
+    -> std::unique_ptr<DrmConnector> {
+  auto conn = MakeDrmModeConnectorUnique(dev.GetFd(), connector_id);
+  if (!conn) {
+    ALOGE("Failed to get connector %d", connector_id);
+    return {};
   }
-  UpdateEdidProperty();
-  if (writeback()) {
-    ret = drm_->GetConnectorProperty(*this, "WRITEBACK_PIXEL_FORMATS",
-                                     &writeback_pixel_formats_);
-    if (ret) {
-      ALOGE("Could not get WRITEBACK_PIXEL_FORMATS connector_id = %d\n", id_);
-      return ret;
-    }
-    ret = drm_->GetConnectorProperty(*this, "WRITEBACK_FB_ID",
-                                     &writeback_fb_id_);
-    if (ret) {
-      ALOGE("Could not get WRITEBACK_FB_ID connector_id = %d\n", id_);
-      return ret;
-    }
-    ret = drm_->GetConnectorProperty(*this, "WRITEBACK_OUT_FENCE_PTR",
-                                     &writeback_out_fence_);
-    if (ret) {
-      ALOGE("Could not get WRITEBACK_OUT_FENCE_PTR connector_id = %d\n", id_);
-      return ret;
-    }
+
+  auto c = std::unique_ptr<DrmConnector>(
+      new DrmConnector(std::move(conn), &dev, index));
+
+  if (!GetConnectorProperty(dev, *c, "DPMS", &c->dpms_property_) ||
+      !GetConnectorProperty(dev, *c, "CRTC_ID", &c->crtc_id_property_)) {
+    return {};
   }
-  return 0;
+
+  c->UpdateEdidProperty();
+
+  if (c->IsWriteback() &&
+      (!GetConnectorProperty(dev, *c, "WRITEBACK_PIXEL_FORMATS",
+                             &c->writeback_pixel_formats_) ||
+       !GetConnectorProperty(dev, *c, "WRITEBACK_FB_ID",
+                             &c->writeback_fb_id_) ||
+       !GetConnectorProperty(dev, *c, "WRITEBACK_OUT_FENCE_PTR",
+                             &c->writeback_out_fence_))) {
+    return {};
+  }
+
+  return c;
 }
 
 int DrmConnector::UpdateEdidProperty() {
-  int ret = drm_->GetConnectorProperty(*this, "EDID", &edid_property_);
-  if (ret) {
-    ALOGW("Could not get EDID property\n");
-  }
-  return ret;
+  return GetOptionalConnectorProperty(*drm_, *this, "EDID", &edid_property_)
+             ? 0
+             : -EINVAL;
 }
 
-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 {};
   }
 
-  std::tie(ret, blob_id) = edid_property().value();
-  if (ret) {
-    return ret;
+  std::tie(ret, blob_id) = GetEdidProperty().value();
+  if (ret != 0) {
+    return {};
   }
 
-  blob = drmModeGetPropertyBlob(drm_->fd(), blob_id);
-  return !blob;
+  return MakeDrmModePropertyBlobUnique(drm_->GetFd(), blob_id);
 }
 
-uint32_t DrmConnector::id() const {
-  return id_;
+bool DrmConnector::IsInternal() const {
+  auto type = connector_->connector_type;
+  return type == DRM_MODE_CONNECTOR_LVDS || type == DRM_MODE_CONNECTOR_eDP ||
+         type == DRM_MODE_CONNECTOR_DSI || type == DRM_MODE_CONNECTOR_VIRTUAL ||
+         type == DRM_MODE_CONNECTOR_DPI || type == DRM_MODE_CONNECTOR_SPI;
 }
 
-int DrmConnector::display() const {
-  return display_;
+bool DrmConnector::IsExternal() const {
+  auto type = connector_->connector_type;
+  return type == DRM_MODE_CONNECTOR_HDMIA ||
+         type == DRM_MODE_CONNECTOR_DisplayPort ||
+         type == DRM_MODE_CONNECTOR_DVID || type == DRM_MODE_CONNECTOR_DVII ||
+         type == DRM_MODE_CONNECTOR_VGA || type == DRM_MODE_CONNECTOR_USB;
 }
 
-void DrmConnector::set_display(int display) {
-  display_ = display;
-}
-
-bool DrmConnector::internal() const {
-  return type_ == DRM_MODE_CONNECTOR_LVDS || type_ == DRM_MODE_CONNECTOR_eDP ||
-         type_ == DRM_MODE_CONNECTOR_DSI ||
-         type_ == DRM_MODE_CONNECTOR_VIRTUAL || type_ == DRM_MODE_CONNECTOR_DPI;
-}
-
-bool DrmConnector::external() const {
-  return type_ == DRM_MODE_CONNECTOR_HDMIA ||
-         type_ == DRM_MODE_CONNECTOR_DisplayPort ||
-         type_ == DRM_MODE_CONNECTOR_DVID || type_ == DRM_MODE_CONNECTOR_DVII ||
-         type_ == DRM_MODE_CONNECTOR_VGA;
-}
-
-bool DrmConnector::writeback() const {
+bool DrmConnector::IsWriteback() const {
 #ifdef DRM_MODE_CONNECTOR_WRITEBACK
-  return type_ == DRM_MODE_CONNECTOR_WRITEBACK;
+  return connector_->connector_type == DRM_MODE_CONNECTOR_WRITEBACK;
 #else
   return false;
 #endif
 }
 
-bool DrmConnector::valid_type() const {
-  return internal() || external() || writeback();
+bool DrmConnector::IsValid() const {
+  return IsInternal() || IsExternal() || IsWriteback();
 }
 
-std::string DrmConnector::name() const {
+std::string DrmConnector::GetName() const {
   constexpr std::array<const char *, kTypesCount> kNames =
-      {"None",   "VGA",  "DVI-I",     "DVI-D",   "DVI-A", "Composite",
-       "SVIDEO", "LVDS", "Component", "DIN",     "DP",    "HDMI-A",
-       "HDMI-B", "TV",   "eDP",       "Virtual", "DSI"};
+      {"None",      "VGA",  "DVI-I",     "DVI-D",   "DVI-A", "Composite",
+       "SVIDEO",    "LVDS", "Component", "DIN",     "DP",    "HDMI-A",
+       "HDMI-B",    "TV",   "eDP",       "Virtual", "DSI",   "DPI",
+       "Writeback", "SPI",  "USB"};
 
-  if (type_ < kTypesCount) {
+  if (connector_->connector_type < kTypesCount) {
     std::ostringstream name_buf;
-    name_buf << kNames[type_] << "-" << type_id_;
+    name_buf << kNames[connector_->connector_type] << "-"
+             << connector_->connector_type_id;
     return name_buf.str();
   }
 
-  ALOGE("Unknown type in connector %d, could not make his name", id_);
+  ALOGE("Unknown type in connector %d, could not make his name", GetId());
   return "None";
 }
 
 int DrmConnector::UpdateModes() {
-  int fd = drm_->fd();
-
-  drmModeConnectorPtr c = drmModeGetConnector(fd, id_);
-  if (!c) {
-    ALOGE("Failed to get connector %d", id_);
+  auto conn = MakeDrmModeConnectorUnique(drm_->GetFd(), GetId());
+  if (!conn) {
+    ALOGE("Failed to get connector %d", GetId());
     return -ENODEV;
   }
+  connector_ = std::move(conn);
 
-  state_ = c->connection;
-
-  bool preferred_mode_found = false;
-  std::vector<DrmMode> new_modes;
-  for (int i = 0; i < c->count_modes; ++i) {
+  modes_.clear();
+  for (int i = 0; i < connector_->count_modes; ++i) {
     bool exists = false;
     for (const DrmMode &mode : modes_) {
-      if (mode == c->modes[i]) {
-        new_modes.push_back(mode);
+      if (mode == connector_->modes[i]) {
         exists = true;
         break;
       }
     }
+
     if (!exists) {
-      DrmMode m(&c->modes[i]);
-      m.set_id(drm_->next_mode_id());
-      new_modes.push_back(m);
-    }
-    // Use only the first DRM_MODE_TYPE_PREFERRED mode found
-    if (!preferred_mode_found &&
-        (new_modes.back().type() & DRM_MODE_TYPE_PREFERRED)) {
-      preferred_mode_id_ = new_modes.back().id();
-      preferred_mode_found = true;
+      modes_.emplace_back(DrmMode(&connector_->modes[i]));
     }
   }
-  modes_.swap(new_modes);
-  if (!preferred_mode_found && !modes_.empty()) {
-    preferred_mode_id_ = modes_[0].id();
-  }
+
   return 0;
 }
 
-const DrmMode &DrmConnector::active_mode() const {
-  return active_mode_;
-}
-
-void DrmConnector::set_active_mode(const DrmMode &mode) {
+void DrmConnector::SetActiveMode(DrmMode &mode) {
   active_mode_ = mode;
 }
 
-const DrmProperty &DrmConnector::dpms_property() const {
-  return dpms_property_;
-}
-
-const DrmProperty &DrmConnector::crtc_id_property() const {
-  return crtc_id_property_;
-}
-
-const DrmProperty &DrmConnector::edid_property() const {
-  return edid_property_;
-}
-
-const DrmProperty &DrmConnector::writeback_pixel_formats() const {
-  return writeback_pixel_formats_;
-}
-
-const DrmProperty &DrmConnector::writeback_fb_id() const {
-  return writeback_fb_id_;
-}
-
-const DrmProperty &DrmConnector::writeback_out_fence() const {
-  return writeback_out_fence_;
-}
-
-DrmEncoder *DrmConnector::encoder() const {
-  return encoder_;
-}
-
-void DrmConnector::set_encoder(DrmEncoder *encoder) {
-  encoder_ = encoder;
-}
-
-drmModeConnection DrmConnector::state() const {
-  return state_;
-}
-
-uint32_t DrmConnector::mm_width() const {
-  return mm_width_;
-}
-
-uint32_t DrmConnector::mm_height() const {
-  return mm_height_;
-}
 }  // namespace android
diff --git a/drm/DrmConnector.h b/drm/DrmConnector.h
index 3bc18c8..629b3cc 100644
--- a/drm/DrmConnector.h
+++ b/drm/DrmConnector.h
@@ -17,87 +17,112 @@
 #ifndef ANDROID_DRM_CONNECTOR_H_
 #define ANDROID_DRM_CONNECTOR_H_
 
-#include <stdint.h>
 #include <xf86drmMode.h>
 
+#include <cstdint>
 #include <string>
 #include <vector>
 
 #include "DrmEncoder.h"
 #include "DrmMode.h"
 #include "DrmProperty.h"
+#include "DrmUnique.h"
 
 namespace android {
 
 class DrmDevice;
 
-class DrmConnector {
+class DrmConnector : public PipelineBindable<DrmConnector> {
  public:
-  DrmConnector(DrmDevice *drm, drmModeConnectorPtr c,
-               DrmEncoder *current_encoder,
-               std::vector<DrmEncoder *> &possible_encoders);
+  static auto CreateInstance(DrmDevice &dev, uint32_t connector_id,
+                             uint32_t index) -> std::unique_ptr<DrmConnector>;
+
   DrmConnector(const DrmProperty &) = delete;
   DrmConnector &operator=(const DrmProperty &) = delete;
 
-  int Init();
   int UpdateEdidProperty();
-  int GetEdidBlob(drmModePropertyBlobPtr &blob);
+  auto GetEdidBlob() -> DrmModePropertyBlobUnique;
 
-  uint32_t id() const;
+  auto GetDev() const -> DrmDevice & {
+    return *drm_;
+  }
 
-  int display() const;
-  void set_display(int display);
+  auto GetId() const {
+    return connector_->connector_id;
+  }
 
-  bool internal() const;
-  bool external() const;
-  bool writeback() const;
-  bool valid_type() const;
+  auto GetIndexInResArray() const {
+    return index_in_res_array_;
+  }
 
-  std::string name() const;
+  auto GetCurrentEncoderId() const {
+    return connector_->encoder_id;
+  }
+
+  auto SupportsEncoder(DrmEncoder &enc) const {
+    for (int i = 0; i < connector_->count_encoders; i++) {
+      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+      if (connector_->encoders[i] == enc.GetId()) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  bool IsInternal() const;
+  bool IsExternal() const;
+  bool IsWriteback() const;
+  bool IsValid() const;
+
+  std::string GetName() const;
 
   int UpdateModes();
 
-  const std::vector<DrmMode> &modes() const {
+  auto &GetModes() const {
     return modes_;
   }
-  const DrmMode &active_mode() const;
-  void set_active_mode(const DrmMode &mode);
 
-  const DrmProperty &dpms_property() const;
-  const DrmProperty &crtc_id_property() const;
-  const DrmProperty &edid_property() const;
-  const DrmProperty &writeback_pixel_formats() const;
-  const DrmProperty &writeback_fb_id() const;
-  const DrmProperty &writeback_out_fence() const;
-
-  const std::vector<DrmEncoder *> &possible_encoders() const {
-    return possible_encoders_;
+  auto &GetActiveMode() const {
+    return active_mode_;
   }
-  DrmEncoder *encoder() const;
-  void set_encoder(DrmEncoder *encoder);
 
-  drmModeConnection state() const;
+  void SetActiveMode(DrmMode &mode);
 
-  uint32_t mm_width() const;
-  uint32_t mm_height() const;
-
-  uint32_t get_preferred_mode_id() const {
-    return preferred_mode_id_;
+  auto &GetDpmsProperty() const {
+    return dpms_property_;
   }
 
+  auto &GetCrtcIdProperty() const {
+    return crtc_id_property_;
+  }
+
+  auto &GetEdidProperty() const {
+    return edid_property_;
+  }
+
+  auto IsConnected() const {
+    return connector_->connection == DRM_MODE_CONNECTED;
+  }
+
+  auto GetMmWidth() const {
+    return connector_->mmWidth;
+  }
+
+  auto GetMmHeight() const {
+    return connector_->mmHeight;
+  };
+
  private:
-  DrmDevice *drm_;
+  DrmConnector(DrmModeConnectorUnique connector, DrmDevice *drm, uint32_t index)
+      : connector_(std::move(connector)),
+        drm_(drm),
+        index_in_res_array_(index){};
 
-  uint32_t id_;
-  DrmEncoder *encoder_;
-  int display_;
+  DrmModeConnectorUnique connector_;
+  DrmDevice *const drm_;
 
-  uint32_t type_;
-  uint32_t type_id_;
-  drmModeConnection state_;
-
-  uint32_t mm_width_;
-  uint32_t mm_height_;
+  const uint32_t index_in_res_array_;
 
   DrmMode active_mode_;
   std::vector<DrmMode> modes_;
@@ -108,10 +133,6 @@
   DrmProperty writeback_pixel_formats_;
   DrmProperty writeback_fb_id_;
   DrmProperty writeback_out_fence_;
-
-  std::vector<DrmEncoder *> possible_encoders_;
-
-  uint32_t preferred_mode_id_{};
 };
 }  // namespace android
 
diff --git a/drm/DrmCrtc.cpp b/drm/DrmCrtc.cpp
index 4da08fe..b54f14b 100644
--- a/drm/DrmCrtc.cpp
+++ b/drm/DrmCrtc.cpp
@@ -27,60 +27,41 @@
 
 namespace android {
 
-DrmCrtc::DrmCrtc(DrmDevice *drm, drmModeCrtcPtr c, unsigned pipe)
-    : drm_(drm), id_(c->crtc_id), pipe_(pipe), display_(-1), mode_(&c->mode) {
+static int GetCrtcProperty(const DrmDevice &dev, const DrmCrtc &crtc,
+                           const char *prop_name, DrmProperty *property) {
+  return dev.GetProperty(crtc.GetId(), DRM_MODE_OBJECT_CRTC, prop_name,
+                         property);
 }
 
-int DrmCrtc::Init() {
-  int ret = drm_->GetCrtcProperty(*this, "ACTIVE", &active_property_);
-  if (ret) {
+auto DrmCrtc::CreateInstance(DrmDevice &dev, uint32_t crtc_id, uint32_t index)
+    -> std::unique_ptr<DrmCrtc> {
+  auto crtc = MakeDrmModeCrtcUnique(dev.GetFd(), crtc_id);
+  if (!crtc) {
+    ALOGE("Failed to get CRTC %d", crtc_id);
+    return {};
+  }
+
+  auto c = std::unique_ptr<DrmCrtc>(new DrmCrtc(std::move(crtc), index));
+
+  int ret = GetCrtcProperty(dev, *c, "ACTIVE", &c->active_property_);
+  if (ret != 0) {
     ALOGE("Failed to get ACTIVE property");
-    return ret;
+    return {};
   }
 
-  ret = drm_->GetCrtcProperty(*this, "MODE_ID", &mode_property_);
-  if (ret) {
+  ret = GetCrtcProperty(dev, *c, "MODE_ID", &c->mode_property_);
+  if (ret != 0) {
     ALOGE("Failed to get MODE_ID property");
-    return ret;
+    return {};
   }
 
-  ret = drm_->GetCrtcProperty(*this, "OUT_FENCE_PTR", &out_fence_ptr_property_);
-  if (ret) {
+  ret = GetCrtcProperty(dev, *c, "OUT_FENCE_PTR", &c->out_fence_ptr_property_);
+  if (ret != 0) {
     ALOGE("Failed to get OUT_FENCE_PTR property");
-    return ret;
+    return {};
   }
-  return 0;
+
+  return c;
 }
 
-uint32_t DrmCrtc::id() const {
-  return id_;
-}
-
-unsigned DrmCrtc::pipe() const {
-  return pipe_;
-}
-
-int DrmCrtc::display() const {
-  return display_;
-}
-
-void DrmCrtc::set_display(int display) {
-  display_ = display;
-}
-
-bool DrmCrtc::can_bind(int display) const {
-  return display_ == -1 || display_ == display;
-}
-
-const DrmProperty &DrmCrtc::active_property() const {
-  return active_property_;
-}
-
-const DrmProperty &DrmCrtc::mode_property() const {
-  return mode_property_;
-}
-
-const DrmProperty &DrmCrtc::out_fence_ptr_property() const {
-  return out_fence_ptr_property_;
-}
 }  // namespace android
diff --git a/drm/DrmCrtc.h b/drm/DrmCrtc.h
index 7972bef..ebf0a97 100644
--- a/drm/DrmCrtc.h
+++ b/drm/DrmCrtc.h
@@ -17,44 +17,55 @@
 #ifndef ANDROID_DRM_CRTC_H_
 #define ANDROID_DRM_CRTC_H_
 
-#include <stdint.h>
 #include <xf86drmMode.h>
 
+#include <cstdint>
+
+#include "DrmDisplayPipeline.h"
 #include "DrmMode.h"
 #include "DrmProperty.h"
+#include "DrmUnique.h"
 
 namespace android {
 
 class DrmDevice;
 
-class DrmCrtc {
+class DrmCrtc : public PipelineBindable<DrmCrtc> {
  public:
-  DrmCrtc(DrmDevice *drm, drmModeCrtcPtr c, unsigned pipe);
+  static auto CreateInstance(DrmDevice &dev, uint32_t crtc_id, uint32_t index)
+      -> std::unique_ptr<DrmCrtc>;
+
+  DrmCrtc() = delete;
   DrmCrtc(const DrmCrtc &) = delete;
   DrmCrtc &operator=(const DrmCrtc &) = delete;
 
-  int Init();
+  auto GetId() const {
+    return crtc_->crtc_id;
+  }
 
-  uint32_t id() const;
-  unsigned pipe() const;
+  auto GetIndexInResArray() const {
+    return index_in_res_array_;
+  }
 
-  int display() const;
-  void set_display(int display);
+  auto &GetActiveProperty() const {
+    return active_property_;
+  }
 
-  bool can_bind(int display) const;
+  auto &GetModeProperty() const {
+    return mode_property_;
+  }
 
-  const DrmProperty &active_property() const;
-  const DrmProperty &mode_property() const;
-  const DrmProperty &out_fence_ptr_property() const;
+  auto &GetOutFencePtrProperty() const {
+    return out_fence_ptr_property_;
+  }
 
  private:
-  DrmDevice *drm_;
+  DrmCrtc(DrmModeCrtcUnique crtc, uint32_t index)
+      : crtc_(std::move(crtc)), index_in_res_array_(index){};
 
-  uint32_t id_;
-  unsigned pipe_;
-  int display_;
+  DrmModeCrtcUnique crtc_;
 
-  DrmMode mode_;
+  const uint32_t index_in_res_array_;
 
   DrmProperty active_property_;
   DrmProperty mode_property_;
diff --git a/drm/DrmDevice.cpp b/drm/DrmDevice.cpp
index abc8edc..0f73f1f 100644
--- a/drm/DrmDevice.cpp
+++ b/drm/DrmDevice.cpp
@@ -18,153 +18,86 @@
 
 #include "DrmDevice.h"
 
-#include <fcntl.h>
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 
-#include <algorithm>
-#include <array>
-#include <cerrno>
 #include <cinttypes>
 #include <cstdint>
-#include <sstream>
 #include <string>
 
+#include "drm/DrmAtomicStateManager.h"
+#include "drm/DrmPlane.h"
+#include "drm/ResourceManager.h"
 #include "utils/log.h"
 #include "utils/properties.h"
 
-static void trim_left(std::string *str) {
-  str->erase(std::begin(*str),
-             std::find_if(std::begin(*str), std::end(*str),
-                          [](int ch) { return std::isspace(ch) == 0; }));
-}
-
-static void trim_right(std::string *str) {
-  str->erase(std::find_if(std::rbegin(*str), std::rend(*str),
-                          [](int ch) { return std::isspace(ch) == 0; })
-                 .base(),
-             std::end(*str));
-}
-
-static void trim(std::string *str) {
-  trim_left(str);
-  trim_right(str);
-}
-
 namespace android {
 
-static std::vector<std::string> read_primary_display_order_prop() {
-  std::array<char, PROPERTY_VALUE_MAX> display_order_buf{};
-  property_get("vendor.hwc.drm.primary_display_order", display_order_buf.data(),
-               "...");
-
-  std::vector<std::string> display_order;
-  std::istringstream str(display_order_buf.data());
-  for (std::string conn_name; std::getline(str, conn_name, ',');) {
-    trim(&conn_name);
-    display_order.push_back(std::move(conn_name));
-  }
-  return display_order;
-}
-
-static std::vector<DrmConnector *> make_primary_display_candidates(
-    const std::vector<std::unique_ptr<DrmConnector>> &connectors) {
-  std::vector<DrmConnector *> primary_candidates;
-  std::transform(std::begin(connectors), std::end(connectors),
-                 std::back_inserter(primary_candidates),
-                 [](const std::unique_ptr<DrmConnector> &conn) {
-                   return conn.get();
-                 });
-  primary_candidates.erase(std::remove_if(std::begin(primary_candidates),
-                                          std::end(primary_candidates),
-                                          [](const DrmConnector *conn) {
-                                            return conn->state() !=
-                                                   DRM_MODE_CONNECTED;
-                                          }),
-                           std::end(primary_candidates));
-
-  std::vector<std::string> display_order = read_primary_display_order_prop();
-  bool use_other = display_order.back() == "...";
-
-  // putting connectors from primary_display_order first
-  auto curr_connector = std::begin(primary_candidates);
-  for (const std::string &display_name : display_order) {
-    auto it = std::find_if(std::begin(primary_candidates),
-                           std::end(primary_candidates),
-                           [&display_name](const DrmConnector *conn) {
-                             return conn->name() == display_name;
-                           });
-    if (it != std::end(primary_candidates)) {
-      std::iter_swap(it, curr_connector);
-      ++curr_connector;
-    }
+auto DrmDevice::CreateInstance(std::string const &path,
+                               ResourceManager *res_man)
+    -> std::unique_ptr<DrmDevice> {
+  if (!IsKMSDev(path.c_str())) {
+    return {};
   }
 
-  if (use_other) {
-    // then putting internal connectors second, everything else afterwards
-    std::partition(curr_connector, std::end(primary_candidates),
-                   [](const DrmConnector *conn) { return conn->internal(); });
-  } else {
-    primary_candidates.erase(curr_connector, std::end(primary_candidates));
+  auto device = std::unique_ptr<DrmDevice>(new DrmDevice(res_man));
+
+  if (device->Init(path.c_str()) != 0) {
+    return {};
   }
 
-  return primary_candidates;
+  return device;
 }
 
-DrmDevice::DrmDevice() : event_listener_(this) {
-  self.reset(this);
-  mDrmFbImporter = std::make_unique<DrmFbImporter>(self);
+DrmDevice::DrmDevice(ResourceManager *res_man) : res_man_(res_man) {
+  drm_fb_importer_ = std::make_unique<DrmFbImporter>(*this);
 }
 
-DrmDevice::~DrmDevice() {
-  event_listener_.Exit();
-}
-
-std::tuple<int, int> DrmDevice::Init(const char *path, int num_displays) {
+auto DrmDevice::Init(const char *path) -> int {
   /* TODO: Use drmOpenControl here instead */
   fd_ = UniqueFd(open(path, O_RDWR | O_CLOEXEC));
-  if (fd() < 0) {
+  if (!fd_) {
+    // NOLINTNEXTLINE(concurrency-mt-unsafe): Fixme
     ALOGE("Failed to open dri %s: %s", path, strerror(errno));
-    return std::make_tuple(-ENODEV, 0);
+    return -ENODEV;
   }
 
-  int ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
-  if (ret) {
+  int ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+  if (ret != 0) {
     ALOGE("Failed to set universal plane cap %d", ret);
-    return std::make_tuple(ret, 0);
+    return ret;
   }
 
-  ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_ATOMIC, 1);
-  if (ret) {
+  ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_ATOMIC, 1);
+  if (ret != 0) {
     ALOGE("Failed to set atomic cap %d", ret);
-    return std::make_tuple(ret, 0);
+    return ret;
   }
 
 #ifdef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS
-  ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
-  if (ret) {
+  ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
+  if (ret != 0) {
     ALOGI("Failed to set writeback cap %d", ret);
-    ret = 0;
   }
 #endif
 
   uint64_t cap_value = 0;
-  if (drmGetCap(fd(), DRM_CAP_ADDFB2_MODIFIERS, &cap_value)) {
+  if (drmGetCap(GetFd(), DRM_CAP_ADDFB2_MODIFIERS, &cap_value) != 0) {
     ALOGW("drmGetCap failed. Fallback to no modifier support.");
     cap_value = 0;
   }
   HasAddFb2ModifiersSupport_ = cap_value != 0;
 
-  drmSetMaster(fd());
-  if (!drmIsMaster(fd())) {
+  drmSetMaster(GetFd());
+  if (drmIsMaster(GetFd()) == 0) {
     ALOGE("DRM/KMS master access required");
-    return std::make_tuple(-EACCES, 0);
+    return -EACCES;
   }
 
-  drmModeResPtr res = drmModeGetResources(fd());
+  auto res = MakeDrmModeResUnique(GetFd());
   if (!res) {
     ALOGE("Failed to get DrmDevice resources");
-    return std::make_tuple(-ENODEV, 0);
+    return -ENODEV;
   }
 
   min_resolution_ = std::pair<uint32_t, uint32_t>(res->min_width,
@@ -172,392 +105,100 @@
   max_resolution_ = std::pair<uint32_t, uint32_t>(res->max_width,
                                                   res->max_height);
 
-  // Assumes that the primary display will always be in the first
-  // drm_device opened.
-  bool found_primary = num_displays != 0;
-
-  for (int i = 0; !ret && i < res->count_crtcs; ++i) {
-    drmModeCrtcPtr c = drmModeGetCrtc(fd(), res->crtcs[i]);
-    if (!c) {
-      ALOGE("Failed to get crtc %d", res->crtcs[i]);
-      ret = -ENODEV;
-      break;
+  for (int i = 0; i < res->count_crtcs; ++i) {
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+    auto crtc = DrmCrtc::CreateInstance(*this, res->crtcs[i], i);
+    if (crtc) {
+      crtcs_.emplace_back(std::move(crtc));
     }
-
-    std::unique_ptr<DrmCrtc> crtc(new DrmCrtc(this, c, i));
-    drmModeFreeCrtc(c);
-
-    ret = crtc->Init();
-    if (ret) {
-      ALOGE("Failed to initialize crtc %d", res->crtcs[i]);
-      break;
-    }
-    crtcs_.emplace_back(std::move(crtc));
   }
 
-  std::vector<int> possible_clones;
-  for (int i = 0; !ret && i < res->count_encoders; ++i) {
-    drmModeEncoderPtr e = drmModeGetEncoder(fd(), res->encoders[i]);
-    if (!e) {
-      ALOGE("Failed to get encoder %d", res->encoders[i]);
-      ret = -ENODEV;
-      break;
+  for (int i = 0; i < res->count_encoders; ++i) {
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+    auto enc = DrmEncoder::CreateInstance(*this, res->encoders[i], i);
+    if (enc) {
+      encoders_.emplace_back(std::move(enc));
     }
-
-    std::vector<DrmCrtc *> possible_crtcs;
-    DrmCrtc *current_crtc = nullptr;
-    for (auto &crtc : crtcs_) {
-      if ((1 << crtc->pipe()) & e->possible_crtcs)
-        possible_crtcs.push_back(crtc.get());
-
-      if (crtc->id() == e->crtc_id)
-        current_crtc = crtc.get();
-    }
-
-    std::unique_ptr<DrmEncoder> enc(
-        new DrmEncoder(e, current_crtc, possible_crtcs));
-    possible_clones.push_back(e->possible_clones);
-    drmModeFreeEncoder(e);
-
-    encoders_.emplace_back(std::move(enc));
   }
 
-  for (unsigned int i = 0; i < encoders_.size(); i++) {
-    for (unsigned int j = 0; j < encoders_.size(); j++)
-      if (possible_clones[i] & (1 << j))
-        encoders_[i]->AddPossibleClone(encoders_[j].get());
-  }
+  for (int i = 0; i < res->count_connectors; ++i) {
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+    auto conn = DrmConnector::CreateInstance(*this, res->connectors[i], i);
 
-  for (int i = 0; !ret && i < res->count_connectors; ++i) {
-    drmModeConnectorPtr c = drmModeGetConnector(fd(), res->connectors[i]);
-    if (!c) {
-      ALOGE("Failed to get connector %d", res->connectors[i]);
-      ret = -ENODEV;
-      break;
+    if (!conn) {
+      continue;
     }
 
-    std::vector<DrmEncoder *> possible_encoders;
-    DrmEncoder *current_encoder = nullptr;
-    for (int j = 0; j < c->count_encoders; ++j) {
-      for (auto &encoder : encoders_) {
-        if (encoder->id() == c->encoders[j])
-          possible_encoders.push_back(encoder.get());
-        if (encoder->id() == c->encoder_id)
-          current_encoder = encoder.get();
-      }
-    }
-
-    std::unique_ptr<DrmConnector> conn(
-        new DrmConnector(this, c, current_encoder, possible_encoders));
-
-    drmModeFreeConnector(c);
-
-    ret = conn->Init();
-    if (ret) {
-      ALOGE("Init connector %d failed", res->connectors[i]);
-      break;
-    }
-
-    if (conn->writeback())
+    if (conn->IsWriteback()) {
       writeback_connectors_.emplace_back(std::move(conn));
-    else
+    } else {
       connectors_.emplace_back(std::move(conn));
-  }
-
-  // Primary display priority:
-  // 1) vendor.hwc.drm.primary_display_order property
-  // 2) internal connectors
-  // 3) anything else
-  std::vector<DrmConnector *>
-      primary_candidates = make_primary_display_candidates(connectors_);
-  if (!primary_candidates.empty() && !found_primary) {
-    DrmConnector &conn = **std::begin(primary_candidates);
-    conn.set_display(num_displays);
-    displays_[num_displays] = num_displays;
-    ++num_displays;
-    found_primary = true;
-  } else {
-    ALOGE(
-        "Failed to find primary display from "
-        "\"vendor.hwc.drm.primary_display_order\" property");
-  }
-
-  // If no priority display were found then pick first available as primary and
-  // for the others assign consecutive display_numbers.
-  for (auto &conn : connectors_) {
-    if (conn->external() || conn->internal()) {
-      if (!found_primary) {
-        conn->set_display(num_displays);
-        displays_[num_displays] = num_displays;
-        found_primary = true;
-        ++num_displays;
-      } else if (conn->display() < 0) {
-        conn->set_display(num_displays);
-        displays_[num_displays] = num_displays;
-        ++num_displays;
-      }
     }
   }
 
-  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(GetFd());
   if (!plane_res) {
     ALOGE("Failed to get plane resources");
-    return std::make_tuple(-ENOENT, 0);
+    return -ENOENT;
   }
 
   for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
-    drmModePlanePtr p = drmModeGetPlane(fd(), plane_res->planes[i]);
-    if (!p) {
-      ALOGE("Failed to get plane %d", plane_res->planes[i]);
-      ret = -ENODEV;
-      break;
-    }
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+    auto plane = DrmPlane::CreateInstance(*this, plane_res->planes[i]);
 
-    std::unique_ptr<DrmPlane> plane(new DrmPlane(this, p));
-
-    drmModeFreePlane(p);
-
-    ret = plane->Init();
-    if (ret) {
-      ALOGE("Init plane %d failed", plane_res->planes[i]);
-      break;
-    }
-
-    planes_.emplace_back(std::move(plane));
-  }
-  drmModeFreePlaneResources(plane_res);
-  if (ret)
-    return std::make_tuple(ret, 0);
-
-  ret = event_listener_.Init();
-  if (ret) {
-    ALOGE("Can't initialize event listener %d", ret);
-    return std::make_tuple(ret, 0);
-  }
-
-  for (auto &conn : connectors_) {
-    ret = CreateDisplayPipe(conn.get());
-    if (ret) {
-      ALOGE("Failed CreateDisplayPipe %d with %d", conn->id(), ret);
-      return std::make_tuple(ret, 0);
-    }
-    if (!AttachWriteback(conn.get())) {
-      ALOGI("Display %d has writeback attach to it", conn->display());
-    }
-  }
-  return std::make_tuple(ret, displays_.size());
-}
-
-bool DrmDevice::HandlesDisplay(int display) const {
-  return displays_.find(display) != displays_.end();
-}
-
-DrmConnector *DrmDevice::GetConnectorForDisplay(int display) const {
-  for (const auto &conn : connectors_) {
-    if (conn->display() == display)
-      return conn.get();
-  }
-  return nullptr;
-}
-
-DrmConnector *DrmDevice::GetWritebackConnectorForDisplay(int display) const {
-  for (const auto &conn : writeback_connectors_) {
-    if (conn->display() == display)
-      return conn.get();
-  }
-  return nullptr;
-}
-
-// TODO(nobody): what happens when hotplugging
-DrmConnector *DrmDevice::AvailableWritebackConnector(int display) const {
-  DrmConnector *writeback_conn = GetWritebackConnectorForDisplay(display);
-  DrmConnector *display_conn = GetConnectorForDisplay(display);
-  // If we have a writeback already attached to the same CRTC just use that,
-  // if possible.
-  if (display_conn && writeback_conn &&
-      writeback_conn->encoder()->CanClone(display_conn->encoder()))
-    return writeback_conn;
-
-  // Use another CRTC if available and doesn't have any connector
-  for (const auto &crtc : crtcs_) {
-    if (crtc->display() == display)
-      continue;
-    display_conn = GetConnectorForDisplay(crtc->display());
-    // If we have a display connected don't use it for writeback
-    if (display_conn && display_conn->state() == DRM_MODE_CONNECTED)
-      continue;
-    writeback_conn = GetWritebackConnectorForDisplay(crtc->display());
-    if (writeback_conn)
-      return writeback_conn;
-  }
-  return nullptr;
-}
-
-DrmCrtc *DrmDevice::GetCrtcForDisplay(int display) const {
-  for (const auto &crtc : crtcs_) {
-    if (crtc->display() == display)
-      return crtc.get();
-  }
-  return nullptr;
-}
-
-DrmPlane *DrmDevice::GetPlane(uint32_t id) const {
-  for (const auto &plane : planes_) {
-    if (plane->id() == id)
-      return plane.get();
-  }
-  return nullptr;
-}
-
-const std::vector<std::unique_ptr<DrmCrtc>> &DrmDevice::crtcs() const {
-  return crtcs_;
-}
-
-uint32_t DrmDevice::next_mode_id() {
-  return ++mode_id_;
-}
-
-int DrmDevice::TryEncoderForDisplay(int display, DrmEncoder *enc) {
-  /* First try to use the currently-bound crtc */
-  DrmCrtc *crtc = enc->crtc();
-  if (crtc && crtc->can_bind(display)) {
-    crtc->set_display(display);
-    enc->set_crtc(crtc);
-    return 0;
-  }
-
-  /* Try to find a possible crtc which will work */
-  for (DrmCrtc *crtc : enc->possible_crtcs()) {
-    /* We've already tried this earlier */
-    if (crtc == enc->crtc())
-      continue;
-
-    if (crtc->can_bind(display)) {
-      crtc->set_display(display);
-      enc->set_crtc(crtc);
-      return 0;
+    if (plane) {
+      planes_.emplace_back(std::move(plane));
     }
   }
 
-  /* We can't use the encoder, but nothing went wrong, try another one */
-  return -EAGAIN;
+  return 0;
 }
 
-int DrmDevice::CreateDisplayPipe(DrmConnector *connector) {
-  int display = connector->display();
-  /* Try to use current setup first */
-  if (connector->encoder()) {
-    int ret = TryEncoderForDisplay(display, connector->encoder());
-    if (!ret) {
-      return 0;
-    }
-
-    if (ret != -EAGAIN) {
-      ALOGE("Could not set mode %d/%d", display, ret);
-      return ret;
-    }
-  }
-
-  for (DrmEncoder *enc : connector->possible_encoders()) {
-    int ret = TryEncoderForDisplay(display, enc);
-    if (!ret) {
-      connector->set_encoder(enc);
-      return 0;
-    }
-
-    if (ret != -EAGAIN) {
-      ALOGE("Could not set mode %d/%d", display, ret);
-      return ret;
-    }
-  }
-  ALOGE("Could not find a suitable encoder/crtc for display %d",
-        connector->display());
-  return -ENODEV;
-}
-
-// Attach writeback connector to the CRTC linked to the display_conn
-int DrmDevice::AttachWriteback(DrmConnector *display_conn) {
-  DrmCrtc *display_crtc = display_conn->encoder()->crtc();
-  if (GetWritebackConnectorForDisplay(display_crtc->display()) != nullptr) {
-    ALOGE("Display already has writeback attach to it");
-    return -EINVAL;
-  }
-  for (auto &writeback_conn : writeback_connectors_) {
-    if (writeback_conn->display() >= 0)
-      continue;
-    for (DrmEncoder *writeback_enc : writeback_conn->possible_encoders()) {
-      for (DrmCrtc *possible_crtc : writeback_enc->possible_crtcs()) {
-        if (possible_crtc != display_crtc)
-          continue;
-        // Use just encoders which had not been bound already
-        if (writeback_enc->can_bind(display_crtc->display())) {
-          writeback_enc->set_crtc(display_crtc);
-          writeback_conn->set_encoder(writeback_enc);
-          writeback_conn->set_display(display_crtc->display());
-          writeback_conn->UpdateModes();
-          return 0;
-        }
-      }
-    }
-  }
-  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;
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
   create_blob.data = (__u64)data;
 
-  int ret = drmIoctl(fd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
-  if (ret) {
+  int ret = drmIoctl(GetFd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
+  if (ret != 0) {
     ALOGE("Failed to create mode property blob %d", ret);
-    return ret;
+    return {};
   }
-  *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;
-}
-
-DrmEventListener *DrmDevice::event_listener() {
-  return &event_listener_;
+  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(GetFd(), 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;
+      });
 }
 
 int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type,
                            const char *prop_name, DrmProperty *property) const {
   drmModeObjectPropertiesPtr props = nullptr;
 
-  props = drmModeObjectGetProperties(fd(), obj_id, obj_type);
-  if (!props) {
+  props = drmModeObjectGetProperties(GetFd(), obj_id, obj_type);
+  if (props == nullptr) {
     ALOGE("Failed to get properties for %d/%x", obj_id, obj_type);
     return -ENODEV;
   }
 
   bool found = false;
   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]);
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+    drmModePropertyPtr p = drmModeGetProperty(GetFd(), props->props[i]);
+    if (strcmp(p->name, prop_name) == 0) {
+      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+      property->Init(obj_id, p, props->prop_values[i]);
       found = true;
     }
     drmModeFreeProperty(p);
@@ -567,27 +208,10 @@
   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) {
-  return GetProperty(crtc.id(), DRM_MODE_OBJECT_CRTC, prop_name, property);
-}
-
-int DrmDevice::GetConnectorProperty(const DrmConnector &connector,
-                                    const char *prop_name,
-                                    DrmProperty *property) {
-  return GetProperty(connector.id(), DRM_MODE_OBJECT_CONNECTOR, prop_name,
-                     property);
-}
-
 std::string DrmDevice::GetName() const {
-  auto *ver = drmGetVersion(fd());
-  if (!ver) {
-    ALOGW("Failed to get drm version for fd=%d", fd());
+  auto *ver = drmGetVersion(GetFd());
+  if (ver == nullptr) {
+    ALOGW("Failed to get drm version for fd=%d", GetFd());
     return "generic";
   }
 
@@ -595,4 +219,40 @@
   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;
+}
+
+auto DrmDevice::GetConnectors()
+    -> const std::vector<std::unique_ptr<DrmConnector>> & {
+  return connectors_;
+}
+
+auto DrmDevice::GetPlanes() -> const std::vector<std::unique_ptr<DrmPlane>> & {
+  return planes_;
+}
+
+auto DrmDevice::GetCrtcs() -> const std::vector<std::unique_ptr<DrmCrtc>> & {
+  return crtcs_;
+}
+
+auto DrmDevice::GetEncoders()
+    -> const std::vector<std::unique_ptr<DrmEncoder>> & {
+  return encoders_;
+}
+
 }  // namespace android
diff --git a/drm/DrmDevice.h b/drm/DrmDevice.h
index dfca263..4cf0132 100644
--- a/drm/DrmDevice.h
+++ b/drm/DrmDevice.h
@@ -17,112 +17,108 @@
 #ifndef ANDROID_DRM_H_
 #define ANDROID_DRM_H_
 
-#include <stdint.h>
-
+#include <cstdint>
 #include <map>
 #include <tuple>
 
 #include "DrmConnector.h"
 #include "DrmCrtc.h"
 #include "DrmEncoder.h"
-#include "DrmEventListener.h"
 #include "DrmFbImporter.h"
-#include "DrmPlane.h"
 #include "utils/UniqueFd.h"
 
 namespace android {
 
 class DrmFbImporter;
 class DrmPlane;
+class ResourceManager;
 
 class DrmDevice {
  public:
-  DrmDevice();
-  ~DrmDevice();
+  ~DrmDevice() = default;
 
-  std::tuple<int, int> Init(const char *path, int num_displays);
+  static auto CreateInstance(std::string const &path, ResourceManager *res_man)
+      -> std::unique_ptr<DrmDevice>;
 
-  int fd() const {
+  auto GetFd() const {
     return fd_.Get();
   }
 
-  const std::vector<std::unique_ptr<DrmConnector>> &connectors() const {
-    return connectors_;
+  auto &GetResMan() {
+    return *res_man_;
   }
 
-  const std::vector<std::unique_ptr<DrmPlane>> &planes() const {
-    return planes_;
-  }
+  auto GetConnectors() -> const std::vector<std::unique_ptr<DrmConnector>> &;
+  auto GetPlanes() -> const std::vector<std::unique_ptr<DrmPlane>> &;
+  auto GetCrtcs() -> const std::vector<std::unique_ptr<DrmCrtc>> &;
+  auto GetEncoders() -> const std::vector<std::unique_ptr<DrmEncoder>> &;
 
-  std::pair<uint32_t, uint32_t> min_resolution() const {
+  auto GetMinResolution() const {
     return min_resolution_;
   }
 
-  std::pair<uint32_t, uint32_t> max_resolution() const {
+  auto GetMaxResolution() const {
     return max_resolution_;
   }
 
-  DrmConnector *GetConnectorForDisplay(int display) const;
-  DrmConnector *GetWritebackConnectorForDisplay(int display) const;
-  DrmConnector *AvailableWritebackConnector(int display) const;
-  DrmCrtc *GetCrtcForDisplay(int display) const;
-  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);
-  int GetConnectorProperty(const DrmConnector &connector, const char *prop_name,
-                           DrmProperty *property);
-
   std::string GetName() const;
 
-  const std::vector<std::unique_ptr<DrmCrtc>> &crtcs() const;
-  uint32_t next_mode_id();
+  auto RegisterUserPropertyBlob(void *data, size_t length) const
+      -> DrmModeUserPropertyBlobUnique;
 
-  int CreatePropertyBlob(void *data, size_t length, uint32_t *blob_id) const;
-  int DestroyPropertyBlob(uint32_t blob_id) const;
-  bool HandlesDisplay(int display) const;
-  void RegisterHotplugHandler(DrmEventHandler *handler) {
-    event_listener_.RegisterHotplugHandler(handler);
-  }
-
-  bool HasAddFb2ModifiersSupport() const {
+  auto HasAddFb2ModifiersSupport() const {
     return HasAddFb2ModifiersSupport_;
   }
 
-  DrmFbImporter &GetDrmFbImporter() {
-    return *mDrmFbImporter.get();
+  auto &GetDrmFbImporter() {
+    return *drm_fb_importer_;
   }
 
- private:
-  int TryEncoderForDisplay(int display, DrmEncoder *enc);
+  auto FindCrtcById(uint32_t id) const -> DrmCrtc * {
+    for (const auto &crtc : crtcs_) {
+      if (crtc->GetId() == id) {
+        return crtc.get();
+      }
+    };
+
+    return nullptr;
+  }
+
+  auto FindEncoderById(uint32_t id) const -> DrmEncoder * {
+    for (const auto &enc : encoders_) {
+      if (enc->GetId() == id) {
+        return enc.get();
+      }
+    };
+
+    return nullptr;
+  }
+
   int GetProperty(uint32_t obj_id, uint32_t obj_type, const char *prop_name,
                   DrmProperty *property) const;
 
-  int CreateDisplayPipe(DrmConnector *connector);
-  int AttachWriteback(DrmConnector *display_conn);
+ private:
+  explicit DrmDevice(ResourceManager *res_man);
+  auto Init(const char *path) -> int;
+
+  static auto IsKMSDev(const char *path) -> bool;
 
   UniqueFd fd_;
-  uint32_t mode_id_ = 0;
 
   std::vector<std::unique_ptr<DrmConnector>> connectors_;
   std::vector<std::unique_ptr<DrmConnector>> writeback_connectors_;
   std::vector<std::unique_ptr<DrmEncoder>> encoders_;
   std::vector<std::unique_ptr<DrmCrtc>> crtcs_;
   std::vector<std::unique_ptr<DrmPlane>> planes_;
-  DrmEventListener event_listener_;
 
   std::pair<uint32_t, uint32_t> min_resolution_;
   std::pair<uint32_t, uint32_t> max_resolution_;
-  std::map<int, int> displays_;
 
   bool HasAddFb2ModifiersSupport_{};
 
-  std::shared_ptr<DrmDevice> self;
+  std::unique_ptr<DrmFbImporter> drm_fb_importer_;
 
-  std::unique_ptr<DrmFbImporter> mDrmFbImporter;
+  ResourceManager *const res_man_;
 };
 }  // namespace android
 
diff --git a/drm/DrmDisplayPipeline.cpp b/drm/DrmDisplayPipeline.cpp
new file mode 100644
index 0000000..f993d28
--- /dev/null
+++ b/drm/DrmDisplayPipeline.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "hwc-drm-display-pipeline"
+
+#include "DrmDisplayPipeline.h"
+
+#include "DrmAtomicStateManager.h"
+#include "DrmConnector.h"
+#include "DrmCrtc.h"
+#include "DrmDevice.h"
+#include "DrmEncoder.h"
+#include "DrmPlane.h"
+#include "utils/log.h"
+#include "utils/properties.h"
+
+namespace android {
+
+template <class O>
+auto PipelineBindable<O>::BindPipeline(DrmDisplayPipeline *pipeline,
+                                       bool return_object_if_bound)
+    -> std::shared_ptr<BindingOwner<O>> {
+  auto owner_object = owner_object_.lock();
+  if (owner_object) {
+    if (bound_pipeline_ == pipeline && return_object_if_bound) {
+      return owner_object;
+    }
+
+    return {};
+  }
+  owner_object = std::make_shared<BindingOwner<O>>(static_cast<O *>(this));
+
+  owner_object_ = owner_object;
+  bound_pipeline_ = pipeline;
+  return owner_object;
+}
+
+static auto TryCreatePipeline(DrmDevice &dev, DrmConnector &connector,
+                              DrmEncoder &enc, DrmCrtc &crtc)
+    -> std::unique_ptr<DrmDisplayPipeline> {
+  /* Check if resources are available */
+
+  auto pipe = std::make_unique<DrmDisplayPipeline>();
+  pipe->device = &dev;
+
+  pipe->connector = connector.BindPipeline(pipe.get());
+  pipe->encoder = enc.BindPipeline(pipe.get());
+  pipe->crtc = crtc.BindPipeline(pipe.get());
+
+  if (!pipe->connector || !pipe->encoder || !pipe->crtc) {
+    return {};
+  }
+
+  std::vector<DrmPlane *> primary_planes;
+  std::vector<DrmPlane *> overlay_planes;
+
+  /* Attach necessary resources */
+  auto display_planes = std::vector<DrmPlane *>();
+  for (const auto &plane : dev.GetPlanes()) {
+    if (plane->IsCrtcSupported(crtc)) {
+      if (plane->GetType() == DRM_PLANE_TYPE_PRIMARY) {
+        primary_planes.emplace_back(plane.get());
+      } else if (plane->GetType() == DRM_PLANE_TYPE_OVERLAY) {
+        overlay_planes.emplace_back(plane.get());
+      } else {
+        ALOGI("Ignoring cursor plane %d", plane->GetId());
+      }
+    }
+  }
+
+  if (primary_planes.empty()) {
+    ALOGE("Primary plane for CRTC %d not found", crtc.GetId());
+    return {};
+  }
+
+  if (primary_planes.size() > 1) {
+    ALOGE("Found more than 1 primary plane for CRTC %d", crtc.GetId());
+    return {};
+  }
+
+  pipe->primary_plane = primary_planes[0]->BindPipeline(pipe.get());
+  if (!pipe->primary_plane) {
+    ALOGE("Primary plane %d is already owned. Internal error.",
+          primary_planes[0]->GetId());
+    return {};
+  }
+
+  pipe->atomic_state_manager = std::make_unique<DrmAtomicStateManager>(
+      pipe.get());
+
+  return pipe;
+}
+
+static auto TryCreatePipelineUsingEncoder(DrmDevice &dev, DrmConnector &conn,
+                                          DrmEncoder &enc)
+    -> std::unique_ptr<DrmDisplayPipeline> {
+  /* First try to use the currently-bound crtc */
+  auto *crtc = dev.FindCrtcById(enc.GetCurrentCrtcId());
+  if (crtc != nullptr) {
+    auto pipeline = TryCreatePipeline(dev, conn, enc, *crtc);
+    if (pipeline) {
+      return pipeline;
+    }
+  }
+
+  /* Try to find a possible crtc which will work */
+  for (const auto &crtc : dev.GetCrtcs()) {
+    if (enc.SupportsCrtc(*crtc)) {
+      auto pipeline = TryCreatePipeline(dev, conn, enc, *crtc);
+      if (pipeline) {
+        return pipeline;
+      }
+    }
+  }
+
+  /* We can't use this encoder, but nothing went wrong, try another one */
+  return {};
+}
+
+auto DrmDisplayPipeline::CreatePipeline(DrmConnector &connector)
+    -> std::unique_ptr<DrmDisplayPipeline> {
+  auto &dev = connector.GetDev();
+  /* Try to use current setup first */
+  auto *encoder = dev.FindEncoderById(connector.GetCurrentEncoderId());
+
+  if (encoder != nullptr) {
+    auto pipeline = TryCreatePipelineUsingEncoder(dev, connector, *encoder);
+    if (pipeline) {
+      return pipeline;
+    }
+  }
+
+  for (const auto &enc : dev.GetEncoders()) {
+    if (connector.SupportsEncoder(*enc)) {
+      auto pipeline = TryCreatePipelineUsingEncoder(dev, connector, *enc);
+      if (pipeline) {
+        return pipeline;
+      }
+    }
+  }
+
+  ALOGE("Could not find a suitable encoder/crtc for connector %s",
+        connector.GetName().c_str());
+
+  return {};
+}
+
+static bool ReadUseOverlayProperty() {
+  char use_overlay_planes_prop[PROPERTY_VALUE_MAX];
+  property_get("vendor.hwc.drm.use_overlay_planes", use_overlay_planes_prop,
+               "1");
+  constexpr int kStrtolBase = 10;
+  return strtol(use_overlay_planes_prop, nullptr, kStrtolBase) != 0;
+}
+
+auto DrmDisplayPipeline::GetUsablePlanes()
+    -> std::vector<std::shared_ptr<BindingOwner<DrmPlane>>> {
+  std::vector<std::shared_ptr<BindingOwner<DrmPlane>>> planes;
+  planes.emplace_back(primary_plane);
+
+  static bool use_overlay_planes = ReadUseOverlayProperty();
+
+  if (use_overlay_planes) {
+    for (const auto &plane : device->GetPlanes()) {
+      if (plane->IsCrtcSupported(*crtc->Get())) {
+        if (plane->GetType() == DRM_PLANE_TYPE_OVERLAY) {
+          auto op = plane->BindPipeline(this, true);
+          if (op) {
+            planes.emplace_back(op);
+          }
+        }
+      }
+    }
+  }
+
+  return planes;
+}
+
+}  // namespace android
diff --git a/drm/DrmDisplayPipeline.h b/drm/DrmDisplayPipeline.h
new file mode 100644
index 0000000..7ec619e
--- /dev/null
+++ b/drm/DrmDisplayPipeline.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_DRMDISPLAYPIPELINE_H_
+#define ANDROID_DRMDISPLAYPIPELINE_H_
+
+#include <memory>
+#include <vector>
+
+namespace android {
+
+class DrmConnector;
+class DrmDevice;
+class DrmPlane;
+class DrmCrtc;
+class DrmEncoder;
+class DrmAtomicStateManager;
+
+struct DrmDisplayPipeline;
+
+template <class O>
+class BindingOwner;
+
+template <class O>
+class PipelineBindable {
+  friend class BindingOwner<O>;
+
+ public:
+  auto *GetPipeline() {
+    return bound_pipeline_;
+  }
+
+  auto BindPipeline(DrmDisplayPipeline *pipeline,
+                    bool return_object_if_bound = false)
+      -> std::shared_ptr<BindingOwner<O>>;
+
+ private:
+  DrmDisplayPipeline *bound_pipeline_;
+  std::weak_ptr<BindingOwner<O>> owner_object_;
+};
+
+template <class B>
+class BindingOwner {
+ public:
+  explicit BindingOwner(B *pb) : bindable_(pb){};
+  ~BindingOwner() {
+    bindable_->bound_pipeline_ = nullptr;
+  }
+
+  B *Get() {
+    return bindable_;
+  }
+
+ private:
+  B *const bindable_;
+};
+
+struct DrmDisplayPipeline {
+  static auto CreatePipeline(DrmConnector &connector)
+      -> std::unique_ptr<DrmDisplayPipeline>;
+
+  auto GetUsablePlanes()
+      -> std::vector<std::shared_ptr<BindingOwner<DrmPlane>>>;
+
+  DrmDevice *device;
+
+  std::shared_ptr<BindingOwner<DrmConnector>> connector;
+  std::shared_ptr<BindingOwner<DrmEncoder>> encoder;
+  std::shared_ptr<BindingOwner<DrmCrtc>> crtc;
+  std::shared_ptr<BindingOwner<DrmPlane>> primary_plane;
+
+  std::unique_ptr<DrmAtomicStateManager> atomic_state_manager;
+};
+
+}  // namespace android
+
+#endif
diff --git a/drm/DrmEncoder.cpp b/drm/DrmEncoder.cpp
index ad05f88..eed5b5f 100644
--- a/drm/DrmEncoder.cpp
+++ b/drm/DrmEncoder.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "hwc-drm-encoder"
+
 #include "DrmEncoder.h"
 
 #include <xf86drmMode.h>
@@ -21,43 +23,19 @@
 #include <cstdint>
 
 #include "DrmDevice.h"
+#include "utils/log.h"
 
 namespace android {
 
-DrmEncoder::DrmEncoder(drmModeEncoderPtr e, DrmCrtc *current_crtc,
-                       std::vector<DrmCrtc *> possible_crtcs)
-    : id_(e->encoder_id),
-      crtc_(current_crtc),
-      display_(-1),
-      possible_crtcs_(std::move(possible_crtcs)) {
+auto DrmEncoder::CreateInstance(DrmDevice &dev, uint32_t encoder_id,
+                                uint32_t index) -> std::unique_ptr<DrmEncoder> {
+  auto e = MakeDrmModeEncoderUnique(dev.GetFd(), encoder_id);
+  if (!e) {
+    ALOGE("Failed to get encoder %d", encoder_id);
+    return {};
+  }
+
+  return std::unique_ptr<DrmEncoder>(new DrmEncoder(std::move(e), index));
 }
 
-uint32_t DrmEncoder::id() const {
-  return id_;
-}
-
-DrmCrtc *DrmEncoder::crtc() const {
-  return crtc_;
-}
-
-bool DrmEncoder::CanClone(DrmEncoder *encoder) {
-  return possible_clones_.find(encoder) != possible_clones_.end();
-}
-
-void DrmEncoder::AddPossibleClone(DrmEncoder *possible_clone) {
-  possible_clones_.insert(possible_clone);
-}
-
-void DrmEncoder::set_crtc(DrmCrtc *crtc) {
-  crtc_ = crtc;
-  display_ = crtc->display();
-}
-
-int DrmEncoder::display() const {
-  return display_;
-}
-
-bool DrmEncoder::can_bind(int display) const {
-  return display_ == -1 || display_ == display;
-}
 }  // namespace android
diff --git a/drm/DrmEncoder.h b/drm/DrmEncoder.h
index 4c01bc1..39a695c 100644
--- a/drm/DrmEncoder.h
+++ b/drm/DrmEncoder.h
@@ -17,43 +17,52 @@
 #ifndef ANDROID_DRM_ENCODER_H_
 #define ANDROID_DRM_ENCODER_H_
 
-#include <stdint.h>
 #include <xf86drmMode.h>
 
+#include <cstdint>
 #include <set>
 #include <vector>
 
 #include "DrmCrtc.h"
+#include "DrmDisplayPipeline.h"
 
 namespace android {
 
-class DrmEncoder {
+class DrmEncoder : public PipelineBindable<DrmEncoder> {
  public:
-  DrmEncoder(drmModeEncoderPtr e, DrmCrtc *current_crtc,
-             std::vector<DrmCrtc *> possible_crtcs);
+  static auto CreateInstance(DrmDevice &dev, uint32_t encoder_id,
+                             uint32_t index) -> std::unique_ptr<DrmEncoder>;
+
   DrmEncoder(const DrmEncoder &) = delete;
   DrmEncoder &operator=(const DrmEncoder &) = delete;
 
-  uint32_t id() const;
+  auto GetId() const {
+    return enc_->encoder_id;
+  };
 
-  DrmCrtc *crtc() const;
-  void set_crtc(DrmCrtc *crtc);
-  bool can_bind(int display) const;
-  int display() const;
-
-  const std::vector<DrmCrtc *> &possible_crtcs() const {
-    return possible_crtcs_;
+  auto GetIndexInResArray() const {
+    return index_in_res_array_;
   }
-  bool CanClone(DrmEncoder *encoder);
-  void AddPossibleClone(DrmEncoder *possible_clone);
+
+  auto CanClone(DrmEncoder &encoder) {
+    return (enc_->possible_clones & (1 << encoder.GetIndexInResArray())) != 0;
+  }
+
+  auto SupportsCrtc(DrmCrtc &crtc) {
+    return (enc_->possible_crtcs & (1 << crtc.GetIndexInResArray())) != 0;
+  }
+
+  auto GetCurrentCrtcId() {
+    return enc_->crtc_id;
+  }
 
  private:
-  uint32_t id_;
-  DrmCrtc *crtc_;
-  int display_;
+  DrmEncoder(DrmModeEncoderUnique enc, uint32_t index)
+      : enc_(std::move(enc)), index_in_res_array_(index){};
 
-  std::vector<DrmCrtc *> possible_crtcs_;
-  std::set<DrmEncoder *> possible_clones_;
+  DrmModeEncoderUnique enc_;
+
+  const uint32_t index_in_res_array_;
 };
 }  // namespace android
 
diff --git a/drm/DrmEventListener.cpp b/drm/DrmEventListener.cpp
deleted file mode 100644
index b303653..0000000
--- a/drm/DrmEventListener.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "hwc-drm-event-listener"
-
-#include "DrmEventListener.h"
-
-#include <linux/netlink.h>
-#include <sys/socket.h>
-#include <xf86drm.h>
-
-#include <cassert>
-#include <cerrno>
-#include <cstring>
-
-#include "DrmDevice.h"
-#include "utils/log.h"
-
-/* Originally defined in system/core/libsystem/include/system/graphics.h */
-#define HAL_PRIORITY_URGENT_DISPLAY (-8)
-
-namespace android {
-
-DrmEventListener::DrmEventListener(DrmDevice *drm)
-    : Worker("drm-event-listener", HAL_PRIORITY_URGENT_DISPLAY), drm_(drm) {
-}
-
-int DrmEventListener::Init() {
-  uevent_fd_ = UniqueFd(
-      socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT));
-  if (!uevent_fd_) {
-    ALOGE("Failed to open uevent socket: %s", strerror(errno));
-    return -errno;
-  }
-
-  struct sockaddr_nl addr {};
-  addr.nl_family = AF_NETLINK;
-  addr.nl_pid = 0;
-  addr.nl_groups = 0xFFFFFFFF;
-
-  int ret = bind(uevent_fd_.Get(), (struct sockaddr *)&addr, sizeof(addr));
-  if (ret) {
-    ALOGE("Failed to bind uevent socket: %s", strerror(errno));
-    return -errno;
-  }
-
-  // NOLINTNEXTLINE(readability-isolate-declaration)
-  FD_ZERO(&fds_);
-  FD_SET(drm_->fd(), &fds_);
-  FD_SET(uevent_fd_.Get(), &fds_);
-  max_fd_ = std::max(drm_->fd(), uevent_fd_.Get());
-
-  return InitWorker();
-}
-
-void DrmEventListener::RegisterHotplugHandler(DrmEventHandler *handler) {
-  assert(!hotplug_handler_);
-  hotplug_handler_.reset(handler);
-}
-
-void DrmEventListener::FlipHandler(int /* fd */, unsigned int /* sequence */,
-                                   unsigned int tv_sec, unsigned int tv_usec,
-                                   void *user_data) {
-  auto *handler = (DrmEventHandler *)user_data;
-  if (!handler)
-    return;
-
-  handler->HandleEvent((uint64_t)tv_sec * 1000 * 1000 + tv_usec);
-  delete handler;  // NOLINT(cppcoreguidelines-owning-memory)
-}
-
-void DrmEventListener::UEventHandler() {
-  char buffer[1024];
-  int ret = 0;
-
-  struct timespec ts {};
-
-  uint64_t timestamp = 0;
-  ret = clock_gettime(CLOCK_MONOTONIC, &ts);
-  if (!ret)
-    timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
-  else
-    ALOGE("Failed to get monotonic clock on hotplug %d", ret);
-
-  while (true) {
-    ret = read(uevent_fd_.Get(), &buffer, sizeof(buffer));
-    if (ret == 0)
-      return;
-
-    if (ret < 0) {
-      ALOGE("Got error reading uevent %d", ret);
-      return;
-    }
-
-    if (!hotplug_handler_)
-      continue;
-
-    bool drm_event = false;
-    bool hotplug_event = false;
-    for (uint32_t i = 0; i < ret;) {
-      char *event = buffer + i;
-      if (strcmp(event, "DEVTYPE=drm_minor") != 0)
-        drm_event = true;
-      else if (strcmp(event, "HOTPLUG=1") != 0)
-        hotplug_event = true;
-
-      i += strlen(event) + 1;
-    }
-
-    if (drm_event && hotplug_event)
-      hotplug_handler_->HandleEvent(timestamp);
-  }
-}
-
-void DrmEventListener::Routine() {
-  int ret = 0;
-  do {
-    ret = select(max_fd_ + 1, &fds_, nullptr, nullptr, nullptr);
-  } while (ret == -1 && errno == EINTR);
-
-  if (FD_ISSET(drm_->fd(), &fds_)) {
-    drmEventContext event_context =
-        {.version = 2,
-         .vblank_handler = nullptr,
-         .page_flip_handler = DrmEventListener::FlipHandler};
-    drmHandleEvent(drm_->fd(), &event_context);
-  }
-
-  if (FD_ISSET(uevent_fd_.Get(), &fds_))
-    UEventHandler();
-}
-}  // namespace android
diff --git a/drm/DrmEventListener.h b/drm/DrmEventListener.h
deleted file mode 100644
index f1f7310..0000000
--- a/drm/DrmEventListener.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_DRM_EVENT_LISTENER_H_
-#define ANDROID_DRM_EVENT_LISTENER_H_
-
-#include "utils/UniqueFd.h"
-#include "utils/Worker.h"
-
-namespace android {
-
-class DrmDevice;
-
-class DrmEventHandler {
- public:
-  DrmEventHandler() {
-  }
-  virtual ~DrmEventHandler() {
-  }
-
-  virtual void HandleEvent(uint64_t timestamp_us) = 0;
-};
-
-class DrmEventListener : public Worker {
- public:
-  DrmEventListener(DrmDevice *drm);
-  virtual ~DrmEventListener() {
-  }
-
-  int Init();
-
-  void RegisterHotplugHandler(DrmEventHandler *handler);
-
-  static void FlipHandler(int fd, unsigned int sequence, unsigned int tv_sec,
-                          unsigned int tv_usec, void *user_data);
-
- protected:
-  virtual void Routine();
-
- private:
-  void UEventHandler();
-
-  fd_set fds_{};
-  UniqueFd uevent_fd_;
-  int max_fd_ = -1;
-
-  DrmDevice *drm_;
-  std::unique_ptr<DrmEventHandler> hotplug_handler_;
-};
-}  // namespace android
-
-#endif
diff --git a/drm/DrmFbImporter.cpp b/drm/DrmFbImporter.cpp
index 8440093..585b789 100644
--- a/drm/DrmFbImporter.cpp
+++ b/drm/DrmFbImporter.cpp
@@ -15,11 +15,14 @@
  */
 
 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
 #define LOG_TAG "hwc-platform-drm-generic"
 
 #include "DrmFbImporter.h"
 
 #include <hardware/gralloc.h>
+#include <utils/Trace.h>
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 
@@ -31,9 +34,11 @@
 
 namespace android {
 
-auto DrmFbIdHandle::CreateInstance(hwc_drm_bo_t *bo, GemHandle first_gem_handle,
-                                   const std::shared_ptr<DrmDevice> &drm)
+auto DrmFbIdHandle::CreateInstance(BufferInfo *bo, GemHandle first_gem_handle,
+                                   DrmDevice &drm)
     -> std::shared_ptr<DrmFbIdHandle> {
+  ATRACE_NAME("Import dmabufs and register FB");
+
   // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): priv. constructor usage
   std::shared_ptr<DrmFbIdHandle> local(new DrmFbIdHandle(drm));
 
@@ -41,10 +46,10 @@
   int32_t err = 0;
 
   /* Framebuffer object creation require gem handle for every used plane */
-  for (int i = 1; i < local->gem_handles_.size(); i++) {
+  for (size_t i = 1; i < local->gem_handles_.size(); i++) {
     if (bo->prime_fds[i] > 0) {
       if (bo->prime_fds[i] != bo->prime_fds[0]) {
-        err = drmPrimeFDToHandle(drm->fd(), bo->prime_fds[i],
+        err = drmPrimeFDToHandle(drm.GetFd(), bo->prime_fds[i],
                                  &local->gem_handles_.at(i));
         if (err != 0) {
           ALOGE("failed to import prime fd %d errno=%d", bo->prime_fds[i],
@@ -59,7 +64,7 @@
   bool has_modifiers = bo->modifiers[0] != DRM_FORMAT_MOD_NONE &&
                        bo->modifiers[0] != DRM_FORMAT_MOD_INVALID;
 
-  if (!drm->HasAddFb2ModifiersSupport() && has_modifiers) {
+  if (!drm.HasAddFb2ModifiersSupport() && has_modifiers) {
     ALOGE("No ADDFB2 with modifier support. Can't import modifier %" PRIu64,
           bo->modifiers[0]);
     local.reset();
@@ -68,12 +73,12 @@
 
   /* Create framebuffer object */
   if (!has_modifiers) {
-    err = drmModeAddFB2(drm->fd(), bo->width, bo->height, bo->format,
-                        &local->gem_handles_[0], &bo->pitches[0],
+    err = drmModeAddFB2(drm.GetFd(), bo->width, bo->height, bo->format,
+                        local->gem_handles_.data(), &bo->pitches[0],
                         &bo->offsets[0], &local->fb_id_, 0);
   } else {
-    err = drmModeAddFB2WithModifiers(drm->fd(), bo->width, bo->height,
-                                     bo->format, &local->gem_handles_[0],
+    err = drmModeAddFB2WithModifiers(drm.GetFd(), bo->width, bo->height,
+                                     bo->format, local->gem_handles_.data(),
                                      &bo->pitches[0], &bo->offsets[0],
                                      &bo->modifiers[0], &local->fb_id_,
                                      DRM_MODE_FB_MODIFIERS);
@@ -87,8 +92,10 @@
 }
 
 DrmFbIdHandle::~DrmFbIdHandle() {
+  ATRACE_NAME("Close FB and dmabufs");
+
   /* Destroy framebuffer object */
-  if (drmModeRmFB(drm_->fd(), fb_id_) != 0) {
+  if (drmModeRmFB(drm_->GetFd(), fb_id_) != 0) {
     ALOGE("Failed to rm fb");
   }
 
@@ -101,7 +108,7 @@
    * request via system properties)
    */
   struct drm_gem_close gem_close {};
-  for (int i = 0; i < gem_handles_.size(); i++) {
+  for (size_t i = 0; i < gem_handles_.size(); i++) {
     /* Don't close invalid handle. Close handle only once in cases
      * where several YUV planes located in the single buffer. */
     if (gem_handles_[i] == 0 ||
@@ -109,22 +116,23 @@
       continue;
     }
     gem_close.handle = gem_handles_[i];
-    int32_t err = drmIoctl(drm_->fd(), DRM_IOCTL_GEM_CLOSE, &gem_close);
+    int32_t err = drmIoctl(drm_->GetFd(), DRM_IOCTL_GEM_CLOSE, &gem_close);
     if (err != 0) {
       ALOGE("Failed to close gem handle %d, errno: %d", gem_handles_[i], errno);
     }
   }
 }
 
-auto DrmFbImporter::GetOrCreateFbId(hwc_drm_bo_t *bo)
+auto DrmFbImporter::GetOrCreateFbId(BufferInfo *bo)
     -> std::shared_ptr<DrmFbIdHandle> {
   /* Lookup DrmFbIdHandle in cache first. First handle serves as a cache key. */
   GemHandle first_handle = 0;
-  int32_t err = drmPrimeFDToHandle(drm_->fd(), bo->prime_fds[0], &first_handle);
+  int32_t err = drmPrimeFDToHandle(drm_->GetFd(), bo->prime_fds[0],
+                                   &first_handle);
 
   if (err != 0) {
     ALOGE("Failed to import prime fd %d ret=%d", bo->prime_fds[0], err);
-    return std::shared_ptr<DrmFbIdHandle>();
+    return {};
   }
 
   auto drm_fb_id_cached = drm_fb_id_handle_cache_.find(first_handle);
@@ -143,7 +151,7 @@
   }
 
   /* No DrmFbIdHandle found in cache, create framebuffer object */
-  auto fb_id_handle = DrmFbIdHandle::CreateInstance(bo, first_handle, drm_);
+  auto fb_id_handle = DrmFbIdHandle::CreateInstance(bo, first_handle, *drm_);
   if (fb_id_handle) {
     drm_fb_id_handle_cache_[first_handle] = fb_id_handle;
   }
diff --git a/drm/DrmFbImporter.h b/drm/DrmFbImporter.h
index 167aa60..9e94238 100644
--- a/drm/DrmFbImporter.h
+++ b/drm/DrmFbImporter.h
@@ -23,8 +23,8 @@
 #include <array>
 #include <map>
 
+#include "bufferinfo/BufferInfo.h"
 #include "drm/DrmDevice.h"
-#include "drmhwcgralloc.h"
 
 #ifndef DRM_FORMAT_INVALID
 #define DRM_FORMAT_INVALID 0
@@ -36,9 +36,8 @@
 
 class DrmFbIdHandle {
  public:
-  static auto CreateInstance(hwc_drm_bo_t *bo, GemHandle first_gem_handle,
-                             const std::shared_ptr<DrmDevice> &drm)
-      -> std::shared_ptr<DrmFbIdHandle>;
+  static auto CreateInstance(BufferInfo *bo, GemHandle first_gem_handle,
+                             DrmDevice &drm) -> std::shared_ptr<DrmFbIdHandle>;
 
   ~DrmFbIdHandle();
   DrmFbIdHandle(DrmFbIdHandle &&) = delete;
@@ -51,26 +50,24 @@
   }
 
  private:
-  explicit DrmFbIdHandle(std::shared_ptr<DrmDevice> drm)
-      : drm_(std::move(drm)){};
+  explicit DrmFbIdHandle(DrmDevice &drm) : drm_(&drm){};
 
-  const std::shared_ptr<DrmDevice> drm_;
+  DrmDevice *const drm_;
 
   uint32_t fb_id_{};
-  std::array<GemHandle, HWC_DRM_BO_MAX_PLANES> gem_handles_{};
+  std::array<GemHandle, kBufferMaxPlanes> gem_handles_{};
 };
 
 class DrmFbImporter {
  public:
-  explicit DrmFbImporter(std::shared_ptr<DrmDevice> drm)
-      : drm_(std::move(drm)){};
+  explicit DrmFbImporter(DrmDevice &drm) : drm_(&drm){};
   ~DrmFbImporter() = default;
   DrmFbImporter(const DrmFbImporter &) = delete;
   DrmFbImporter(DrmFbImporter &&) = delete;
   auto operator=(const DrmFbImporter &) = delete;
   auto operator=(DrmFbImporter &&) = delete;
 
-  auto GetOrCreateFbId(hwc_drm_bo_t *bo) -> std::shared_ptr<DrmFbIdHandle>;
+  auto GetOrCreateFbId(BufferInfo *bo) -> std::shared_ptr<DrmFbIdHandle>;
 
  private:
   void CleanupEmptyCacheElements() {
@@ -84,7 +81,7 @@
     }
   }
 
-  const std::shared_ptr<DrmDevice> drm_;
+  DrmDevice *const drm_;
 
   std::map<GemHandle, std::weak_ptr<DrmFbIdHandle>> drm_fb_id_handle_cache_;
 };
diff --git a/drm/DrmMode.cpp b/drm/DrmMode.cpp
index dd25758..010ea1b 100644
--- a/drm/DrmMode.cpp
+++ b/drm/DrmMode.cpp
@@ -49,79 +49,56 @@
          v_scan_ == m.vscan && flags_ == m.flags && type_ == m.type;
 }
 
-void DrmMode::ToDrmModeModeInfo(drm_mode_modeinfo *m) const {
-  m->clock = clock_;
-  m->hdisplay = h_display_;
-  m->hsync_start = h_sync_start_;
-  m->hsync_end = h_sync_end_;
-  m->htotal = h_total_;
-  m->hskew = h_skew_;
-  m->vdisplay = v_display_;
-  m->vsync_start = v_sync_start_;
-  m->vsync_end = v_sync_end_;
-  m->vtotal = v_total_;
-  m->vscan = v_scan_;
-  m->vrefresh = v_refresh_;
-  m->flags = flags_;
-  m->type = type_;
-  strncpy(m->name, name_.c_str(), DRM_DISPLAY_MODE_LEN);
-}
-
-uint32_t DrmMode::id() const {
-  return id_;
-}
-
-void DrmMode::set_id(uint32_t id) {
-  id_ = id;
-}
-
 uint32_t DrmMode::clock() const {
   return clock_;
 }
 
-uint32_t DrmMode::h_display() const {
+uint16_t DrmMode::h_display() const {
   return h_display_;
 }
 
-uint32_t DrmMode::h_sync_start() const {
+uint16_t DrmMode::h_sync_start() const {
   return h_sync_start_;
 }
 
-uint32_t DrmMode::h_sync_end() const {
+uint16_t DrmMode::h_sync_end() const {
   return h_sync_end_;
 }
 
-uint32_t DrmMode::h_total() const {
+uint16_t DrmMode::h_total() const {
   return h_total_;
 }
 
-uint32_t DrmMode::h_skew() const {
+uint16_t DrmMode::h_skew() const {
   return h_skew_;
 }
 
-uint32_t DrmMode::v_display() const {
+uint16_t DrmMode::v_display() const {
   return v_display_;
 }
 
-uint32_t DrmMode::v_sync_start() const {
+uint16_t DrmMode::v_sync_start() const {
   return v_sync_start_;
 }
 
-uint32_t DrmMode::v_sync_end() const {
+uint16_t DrmMode::v_sync_end() const {
   return v_sync_end_;
 }
 
-uint32_t DrmMode::v_total() const {
+uint16_t DrmMode::v_total() const {
   return v_total_;
 }
 
-uint32_t DrmMode::v_scan() const {
+uint16_t DrmMode::v_scan() const {
   return v_scan_;
 }
 
 float DrmMode::v_refresh() const {
+  if (clock_ == 0) {
+    return v_refresh_;
+  }
   // 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 {
@@ -133,6 +110,31 @@
 }
 
 std::string DrmMode::name() const {
-  return name_;
+  return name_ + "@" + std::to_string(v_refresh());
 }
+
+auto DrmMode::CreateModeBlob(const DrmDevice &drm)
+    -> DrmModeUserPropertyBlobUnique {
+  struct drm_mode_modeinfo drm_mode = {
+      .clock = clock_,
+      .hdisplay = h_display_,
+      .hsync_start = h_sync_start_,
+      .hsync_end = h_sync_end_,
+      .htotal = h_total_,
+      .hskew = h_skew_,
+      .vdisplay = v_display_,
+      .vsync_start = v_sync_start_,
+      .vsync_end = v_sync_end_,
+      .vtotal = v_total_,
+      .vscan = v_scan_,
+      .vrefresh = v_refresh_,
+      .flags = flags_,
+      .type = type_,
+  };
+  strncpy(drm_mode.name, name_.c_str(), DRM_DISPLAY_MODE_LEN);
+
+  return drm.RegisterUserPropertyBlob(&drm_mode,
+                                       sizeof(struct drm_mode_modeinfo));
+}
+
 }  // namespace android
diff --git a/drm/DrmMode.h b/drm/DrmMode.h
index 313a8ea..20515f9 100644
--- a/drm/DrmMode.h
+++ b/drm/DrmMode.h
@@ -17,37 +17,38 @@
 #ifndef ANDROID_DRM_MODE_H_
 #define ANDROID_DRM_MODE_H_
 
-#include <stdint.h>
 #include <xf86drmMode.h>
 
+#include <cstdint>
+#include <cstdio>
 #include <string>
 
+#include "DrmUnique.h"
+
 namespace android {
 
+class DrmDevice;
+
 class DrmMode {
  public:
   DrmMode() = default;
-  DrmMode(drmModeModeInfoPtr m);
+  explicit DrmMode(drmModeModeInfoPtr m);
 
   bool operator==(const drmModeModeInfo &m) const;
-  void ToDrmModeModeInfo(drm_mode_modeinfo *m) const;
-
-  uint32_t id() const;
-  void set_id(uint32_t id);
 
   uint32_t clock() const;
 
-  uint32_t h_display() const;
-  uint32_t h_sync_start() const;
-  uint32_t h_sync_end() const;
-  uint32_t h_total() const;
-  uint32_t h_skew() const;
+  uint16_t h_display() const;
+  uint16_t h_sync_start() const;
+  uint16_t h_sync_end() const;
+  uint16_t h_total() const;
+  uint16_t h_skew() const;
 
-  uint32_t v_display() const;
-  uint32_t v_sync_start() const;
-  uint32_t v_sync_end() const;
-  uint32_t v_total() const;
-  uint32_t v_scan() const;
+  uint16_t v_display() const;
+  uint16_t v_sync_start() const;
+  uint16_t v_sync_end() const;
+  uint16_t v_total() const;
+  uint16_t v_scan() const;
   float v_refresh() const;
 
   uint32_t flags() const;
@@ -55,23 +56,23 @@
 
   std::string name() const;
 
- private:
-  uint32_t id_ = 0;
+  auto CreateModeBlob(const DrmDevice &drm) -> DrmModeUserPropertyBlobUnique;
 
+ private:
   uint32_t clock_ = 0;
 
-  uint32_t h_display_ = 0;
-  uint32_t h_sync_start_ = 0;
-  uint32_t h_sync_end_ = 0;
-  uint32_t h_total_ = 0;
-  uint32_t h_skew_ = 0;
+  uint16_t h_display_ = 0;
+  uint16_t h_sync_start_ = 0;
+  uint16_t h_sync_end_ = 0;
+  uint16_t h_total_ = 0;
+  uint16_t h_skew_ = 0;
 
-  uint32_t v_display_ = 0;
-  uint32_t v_sync_start_ = 0;
-  uint32_t v_sync_end_ = 0;
-  uint32_t v_total_ = 0;
-  uint32_t v_scan_ = 0;
-  uint32_t v_refresh_ = 0;
+  uint16_t v_display_ = 0;
+  uint16_t v_sync_start_ = 0;
+  uint16_t v_sync_end_ = 0;
+  uint16_t v_total_ = 0;
+  uint16_t v_scan_ = 0;
+  uint16_t v_refresh_ = 0;
 
   uint32_t flags_ = 0;
   uint32_t type_ = 0;
diff --git a/drm/DrmPlane.cpp b/drm/DrmPlane.cpp
index 6433fb6..329ef1c 100644
--- a/drm/DrmPlane.cpp
+++ b/drm/DrmPlane.cpp
@@ -29,25 +29,38 @@
 
 namespace android {
 
-DrmPlane::DrmPlane(DrmDevice *drm, drmModePlanePtr p)
-    : drm_(drm),
-      id_(p->plane_id),
-      possible_crtc_mask_(p->possible_crtcs),
-      formats_(p->formats, p->formats + p->count_formats) {
+auto DrmPlane::CreateInstance(DrmDevice &dev, uint32_t plane_id)
+    -> std::unique_ptr<DrmPlane> {
+  auto p = MakeDrmModePlaneUnique(dev.GetFd(), plane_id);
+  if (!p) {
+    ALOGE("Failed to get plane %d", plane_id);
+    return {};
+  }
+
+  auto plane = std::unique_ptr<DrmPlane>(new DrmPlane(dev, std::move(p)));
+
+  if (plane->Init() != 0) {
+    ALOGE("Failed to init plane %d", plane_id);
+    return {};
+  }
+
+  return plane;
 }
 
 int DrmPlane::Init() {
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+  formats_ = {plane_->formats, plane_->formats + plane_->count_formats};
+
   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) {
+  if (ret != 0) {
     ALOGE("Failed to get plane type property value");
     return ret;
   }
@@ -62,178 +75,110 @@
       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", LayerTransform::kIdentity,
+                                    transform_enum_map_);
+    rotation_property_.AddEnumToMap("rotate-90", LayerTransform::kRotate90,
+                                    transform_enum_map_);
+    rotation_property_.AddEnumToMap("rotate-180", LayerTransform::kRotate180,
+                                    transform_enum_map_);
+    rotation_property_.AddEnumToMap("rotate-270", LayerTransform::kRotate270,
+                                    transform_enum_map_);
+    rotation_property_.AddEnumToMap("reflect-x", LayerTransform::kFlipH,
+                                    transform_enum_map_);
+    rotation_property_.AddEnumToMap("reflect-y", LayerTransform::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", BufferBlendMode::kPreMult,
+                                 blending_enum_map_);
+    blend_property_.AddEnumToMap("Coverage", BufferBlendMode::kCoverage,
+                                 blending_enum_map_);
+    blend_property_.AddEnumToMap("None", BufferBlendMode::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",
+                                           BufferColorSpace::kItuRec709,
+                                           color_encoding_enum_map_);
+      color_encoding_propery_.AddEnumToMap("ITU-R BT.601 YCbCr",
+                                           BufferColorSpace::kItuRec601,
+                                           color_encoding_enum_map_);
+      color_encoding_propery_.AddEnumToMap("ITU-R BT.2020 YCbCr",
+                                           BufferColorSpace::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",
+                                         BufferSampleRange::kFullRange,
+                                         color_range_enum_map_);
+      color_range_property_.AddEnumToMap("YCbCr limited range",
+                                         BufferSampleRange::kLimitedRange,
+                                         color_range_enum_map_);
+    }
   }
 
   return 0;
 }
 
-uint32_t DrmPlane::id() const {
-  return id_;
+bool DrmPlane::IsCrtcSupported(const DrmCrtc &crtc) const {
+  return ((1 << crtc.GetIndexInResArray()) & plane_->possible_crtcs) != 0;
 }
 
-bool DrmPlane::GetCrtcSupported(const DrmCrtc &crtc) const {
-  return ((1 << crtc.pipe()) & possible_crtc_mask_) != 0;
-}
-
-bool DrmPlane::IsValidForLayer(DrmHwcLayer *layer) {
-  if (rotation_property_.id() == 0) {
-    if (layer->transform != DrmHwcTransform::kIdentity) {
-      ALOGV("Rotation is not supported on plane %d", id_);
+bool DrmPlane::IsValidForLayer(LayerData *layer) {
+  if (!rotation_property_) {
+    if (layer->pi.transform != LayerTransform::kIdentity) {
+      ALOGV("No rotation property on plane %d", GetId());
       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->pi.transform) == 0) {
+      ALOGV("Transform is not supported on plane %d", GetId());
+      return false;
     }
   }
 
-  if (alpha_property_.id() == 0 && layer->alpha != 0xffff) {
-    ALOGV("Alpha is not supported on plane %d", id_);
+  if (alpha_property_.id() == 0 && layer->pi.alpha != UINT16_MAX) {
+    ALOGV("Alpha is not supported on plane %d", GetId());
     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->bi->blend_mode) == 0 &&
+      layer->bi->blend_mode != BufferBlendMode::kNone &&
+      layer->bi->blend_mode != BufferBlendMode::kPreMult) {
+    ALOGV("Blending is not supported on plane %d", GetId());
+    return false;
   }
 
-  uint32_t format = layer->buffer_info.format;
+  uint32_t format = layer->bi->format;
   if (!IsFormatSupported(format)) {
-    ALOGV("Plane %d does not supports %c%c%c%c format", id_, format,
+    ALOGV("Plane %d does not supports %c%c%c%c format", GetId(), format,
           format >> 8, format >> 16, format >> 24);
     return false;
   }
@@ -241,10 +186,6 @@
   return true;
 }
 
-uint32_t DrmPlane::type() const {
-  return type_;
-}
-
 bool DrmPlane::IsFormatSupported(uint32_t format) const {
   return std::find(std::begin(formats_), std::end(formats_), format) !=
          std::end(formats_);
@@ -257,71 +198,122 @@
                           }) != std::end(formats_);
 }
 
-const DrmProperty &DrmPlane::crtc_property() const {
-  return crtc_property_;
+static uint64_t ToDrmRotation(LayerTransform transform) {
+  uint64_t rotation = 0;
+  if ((transform & LayerTransform::kFlipH) != 0)
+    rotation |= DRM_MODE_REFLECT_X;
+  if ((transform & LayerTransform::kFlipV) != 0)
+    rotation |= DRM_MODE_REFLECT_Y;
+  if ((transform & LayerTransform::kRotate90) != 0)
+    rotation |= DRM_MODE_ROTATE_90;
+  else if ((transform & LayerTransform::kRotate180) != 0)
+    rotation |= DRM_MODE_ROTATE_180;
+  else if ((transform & LayerTransform::kRotate270) != 0)
+    rotation |= DRM_MODE_ROTATE_270;
+  else
+    rotation |= DRM_MODE_ROTATE_0;
+
+  return rotation;
 }
 
-const DrmProperty &DrmPlane::fb_property() const {
-  return fb_property_;
+/* Convert float to 16.16 fixed point */
+static int To1616FixPt(float in) {
+  constexpr int kBitShift = 16;
+  return int(in * (1 << kBitShift));
 }
 
-const DrmProperty &DrmPlane::crtc_x_property() const {
-  return crtc_x_property_;
+auto DrmPlane::AtomicSetState(drmModeAtomicReq &pset, LayerData &layer,
+                              uint32_t zpos, uint32_t crtc_id) -> int {
+  if (!layer.fb) {
+    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;
+  }
+
+  auto &disp = layer.pi.display_frame;
+  auto &src = layer.pi.source_crop;
+  if (!crtc_property_.AtomicSet(pset, crtc_id) ||
+      !fb_property_.AtomicSet(pset, layer.fb->GetFbId()) ||
+      !crtc_x_property_.AtomicSet(pset, disp.left) ||
+      !crtc_y_property_.AtomicSet(pset, disp.top) ||
+      !crtc_w_property_.AtomicSet(pset, disp.right - disp.left) ||
+      !crtc_h_property_.AtomicSet(pset, disp.bottom - disp.top) ||
+      !src_x_property_.AtomicSet(pset, To1616FixPt(src.left)) ||
+      !src_y_property_.AtomicSet(pset, To1616FixPt(src.top)) ||
+      !src_w_property_.AtomicSet(pset, To1616FixPt(src.right - src.left)) ||
+      !src_h_property_.AtomicSet(pset, To1616FixPt(src.bottom - src.top))) {
+    return -EINVAL;
+  }
+
+  if (rotation_property_ &&
+      !rotation_property_.AtomicSet(pset, ToDrmRotation(layer.pi.transform))) {
+    return -EINVAL;
+  }
+
+  if (alpha_property_ && !alpha_property_.AtomicSet(pset, layer.pi.alpha)) {
+    return -EINVAL;
+  }
+
+  if (blending_enum_map_.count(layer.bi->blend_mode) != 0 &&
+      !blend_property_.AtomicSet(pset,
+                                 blending_enum_map_[layer.bi->blend_mode])) {
+    return -EINVAL;
+  }
+
+  if (color_encoding_enum_map_.count(layer.bi->color_space) != 0 &&
+      !color_encoding_propery_
+           .AtomicSet(pset, color_encoding_enum_map_[layer.bi->color_space])) {
+    return -EINVAL;
+  }
+
+  if (color_range_enum_map_.count(layer.bi->sample_range) != 0 &&
+      !color_range_property_
+           .AtomicSet(pset, color_range_enum_map_[layer.bi->sample_range])) {
+    return -EINVAL;
+  }
+
+  return 0;
 }
 
-const DrmProperty &DrmPlane::crtc_y_property() const {
-  return crtc_y_property_;
+auto DrmPlane::AtomicDisablePlane(drmModeAtomicReq &pset) -> int {
+  if (!crtc_property_.AtomicSet(pset, 0) || !fb_property_.AtomicSet(pset, 0)) {
+    return -EINVAL;
+  }
+
+  return 0;
 }
 
-const DrmProperty &DrmPlane::crtc_w_property() const {
-  return crtc_w_property_;
+auto DrmPlane::GetPlaneProperty(const char *prop_name, DrmProperty &property,
+                                Presence presence) -> bool {
+  int err = drm_->GetProperty(GetId(), 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,
+            GetId());
+    } else {
+      ALOGV("Could not get optional property \"%s\" from plane %d", prop_name,
+            GetId());
+    }
+    return false;
+  }
+
+  return true;
 }
 
-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_;
-}
-
-const DrmProperty &DrmPlane::zpos_property() const {
-  return zpos_property_;
-}
-
-const DrmProperty &DrmPlane::rotation_property() const {
-  return rotation_property_;
-}
-
-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..31f0a33 100644
--- a/drm/DrmPlane.h
+++ b/drm/DrmPlane.h
@@ -17,60 +17,60 @@
 #ifndef ANDROID_DRM_PLANE_H_
 #define ANDROID_DRM_PLANE_H_
 
-#include <stdint.h>
 #include <xf86drmMode.h>
 
+#include <cstdint>
 #include <vector>
 
 #include "DrmCrtc.h"
 #include "DrmProperty.h"
-#include "drmhwcomposer.h"
+#include "compositor/LayerData.h"
 
 namespace android {
 
 class DrmDevice;
+struct LayerData;
 
-class DrmPlane {
+class DrmPlane : public PipelineBindable<DrmPlane> {
  public:
-  DrmPlane(DrmDevice *drm, drmModePlanePtr p);
   DrmPlane(const DrmPlane &) = delete;
   DrmPlane &operator=(const DrmPlane &) = delete;
 
-  int Init();
+  static auto CreateInstance(DrmDevice &dev, uint32_t plane_id)
+      -> std::unique_ptr<DrmPlane>;
 
-  uint32_t id() const;
+  bool IsCrtcSupported(const DrmCrtc &crtc) const;
+  bool IsValidForLayer(LayerData *layer);
 
-  bool GetCrtcSupported(const DrmCrtc &crtc) const;
-  bool IsValidForLayer(DrmHwcLayer *layer);
-
-  uint32_t type() const;
+  auto GetType() const {
+    return type_;
+  }
 
   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;
-  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;
+  auto AtomicSetState(drmModeAtomicReq &pset, LayerData &layer, uint32_t zpos,
+                      uint32_t crtc_id) -> int;
+  auto AtomicDisablePlane(drmModeAtomicReq &pset) -> int;
+  auto &GetZPosProperty() const {
+    return zpos_property_;
+  }
+
+  auto GetId() const {
+    return plane_->plane_id;
+  }
 
  private:
-  DrmDevice *drm_;
-  uint32_t id_;
+  DrmPlane(DrmDevice &dev, DrmModePlaneUnique plane)
+      : drm_(&dev), plane_(std::move(plane)){};
+  DrmDevice *const drm_;
+  DrmModePlaneUnique plane_;
 
-  uint32_t possible_crtc_mask_;
+  enum class Presence { kOptional, kMandatory };
+
+  auto Init() -> int;
+  auto GetPlaneProperty(const char *prop_name, DrmProperty &property,
+                        Presence presence = Presence::kMandatory) -> bool;
 
   uint32_t type_{};
 
@@ -93,6 +93,11 @@
   DrmProperty in_fence_fd_property_;
   DrmProperty color_encoding_propery_;
   DrmProperty color_range_property_;
+
+  std::map<BufferBlendMode, uint64_t> blending_enum_map_;
+  std::map<BufferColorSpace, uint64_t> color_encoding_enum_map_;
+  std::map<BufferSampleRange, uint64_t> color_range_enum_map_;
+  std::map<LayerTransform, 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..26a7c38 100644
--- a/drm/DrmProperty.h
+++ b/drm/DrmProperty.h
@@ -17,9 +17,10 @@
 #ifndef ANDROID_DRM_PROPERTY_H_
 #define ANDROID_DRM_PROPERTY_H_
 
-#include <stdint.h>
 #include <xf86drmMode.h>
 
+#include <cstdint>
+#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,16 +55,28 @@
   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;
+
+  explicit operator bool() const {
+    return id_ != 0;
+  }
+
  private:
   class DrmPropertyEnum {
    public:
-    DrmPropertyEnum(drm_mode_property_enum *e);
+    explicit DrmPropertyEnum(drm_mode_property_enum *e);
     ~DrmPropertyEnum() = default;
 
     uint64_t value_;
     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..dbf0993 100644
--- a/drm/ResourceManager.cpp
+++ b/drm/ResourceManager.cpp
@@ -18,119 +18,165 @@
 
 #include "ResourceManager.h"
 
-#include <fcntl.h>
 #include <sys/stat.h>
 
+#include <ctime>
 #include <sstream>
 
 #include "bufferinfo/BufferInfoGetter.h"
+#include "drm/DrmAtomicStateManager.h"
+#include "drm/DrmDevice.h"
+#include "drm/DrmDisplayPipeline.h"
+#include "drm/DrmPlane.h"
 #include "utils/log.h"
 #include "utils/properties.h"
 
 namespace android {
 
-ResourceManager::ResourceManager() : num_displays_(0), gralloc_(nullptr) {
+ResourceManager::ResourceManager(
+    PipelineToFrontendBindingInterface *p2f_bind_interface)
+    : frontend_interface_(p2f_bind_interface) {
+  if (uevent_listener_.Init() != 0) {
+    ALOGE("Can't initialize event listener");
+  }
 }
 
-int ResourceManager::Init() {
+ResourceManager::~ResourceManager() {
+  uevent_listener_.Exit();
+}
+
+void ResourceManager::Init() {
+  if (initialized_) {
+    ALOGE("Already initialized");
+    return;
+  }
+
   char path_pattern[PROPERTY_VALUE_MAX];
   // Could be a valid path or it can have at the end of it the wildcard %
   // which means that it will try open all devices until an error is met.
   int path_len = property_get("vendor.hwc.drm.device", path_pattern,
                               "/dev/dri/card%");
-  int ret = 0;
   if (path_pattern[path_len - 1] != '%') {
-    ret = AddDrmDevice(std::string(path_pattern));
+    auto dev = DrmDevice::CreateInstance(path_pattern, this);
+    if (dev) {
+      drms_.emplace_back(std::move(dev));
+    }
   } else {
     path_pattern[path_len - 1] = '\0';
-    for (int idx = 0; !ret; ++idx) {
+    for (int idx = 0;; ++idx) {
       std::ostringstream path;
       path << path_pattern << idx;
 
       struct stat buf {};
-      if (stat(path.str().c_str(), &buf))
+      if (stat(path.str().c_str(), &buf) != 0)
         break;
 
-      if (IsKMSDev(path.str().c_str()))
-        ret = AddDrmDevice(path.str());
+      auto dev = DrmDevice::CreateInstance(path.str(), this);
+      if (dev) {
+        drms_.emplace_back(std::move(dev));
+      }
     }
   }
 
-  if (!num_displays_) {
-    ALOGE("Failed to initialize any displays");
-    return ret ? -EINVAL : ret;
-  }
-
   char scale_with_gpu[PROPERTY_VALUE_MAX];
   property_get("vendor.hwc.drm.scale_with_gpu", scale_with_gpu, "0");
   scale_with_gpu_ = bool(strncmp(scale_with_gpu, "0", 1));
 
-  if (!BufferInfoGetter::GetInstance()) {
+  if (BufferInfoGetter::GetInstance() == nullptr) {
     ALOGE("Failed to initialize BufferInfoGetter");
-    return -EINVAL;
+    return;
   }
 
-  return hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
-                       (const hw_module_t **)&gralloc_);
+  uevent_listener_.RegisterHotplugHandler([this] {
+    const std::lock_guard<std::mutex> lock(GetMainLock());
+    UpdateFrontendDisplays();
+  });
+
+  UpdateFrontendDisplays();
+
+  initialized_ = true;
 }
 
-int ResourceManager::AddDrmDevice(const std::string &path) {
-  auto drm = std::make_unique<DrmDevice>();
-  int displays_added = 0;
-  int ret = 0;
-  std::tie(ret, displays_added) = drm->Init(path.c_str(), num_displays_);
-  drms_.push_back(std::move(drm));
-  num_displays_ += displays_added;
-  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;
+void ResourceManager::DeInit() {
+  if (!initialized_) {
+    ALOGE("Not initialized");
+    return;
   }
+
+  uevent_listener_.RegisterHotplugHandler([] {});
+
+  DetachAllFrontendDisplays();
+  drms_.clear();
+
+  initialized_ = false;
+}
+
+auto ResourceManager::GetTimeMonotonicNs() -> int64_t {
+  struct timespec ts {};
+  clock_gettime(CLOCK_MONOTONIC, &ts);
+  constexpr int64_t kNsInSec = 1000000000LL;
+  return int64_t(ts.tv_sec) * kNsInSec + int64_t(ts.tv_nsec);
+}
+
+void ResourceManager::UpdateFrontendDisplays() {
+  auto ordered_connectors = GetOrderedConnectors();
+
+  for (auto *conn : ordered_connectors) {
+    conn->UpdateModes();
+    bool connected = conn->IsConnected();
+    bool attached = attached_pipelines_.count(conn) != 0;
+
+    if (connected != attached) {
+      ALOGI("%s connector %s", connected ? "Attaching" : "Detaching",
+            conn->GetName().c_str());
+
+      if (connected) {
+        auto pipeline = DrmDisplayPipeline::CreatePipeline(*conn);
+        if (pipeline) {
+          frontend_interface_->BindDisplay(pipeline.get());
+          attached_pipelines_[conn] = std::move(pipeline);
+        }
+      } else {
+        auto &pipeline = attached_pipelines_[conn];
+        frontend_interface_->UnbindDisplay(pipeline.get());
+        attached_pipelines_.erase(conn);
+      }
+    }
+  }
+  frontend_interface_->FinalizeDisplayBinding();
+}
+
+void ResourceManager::DetachAllFrontendDisplays() {
+  for (auto &p : attached_pipelines_) {
+    frontend_interface_->UnbindDisplay(p.second.get());
+  }
+  attached_pipelines_.clear();
+  frontend_interface_->FinalizeDisplayBinding();
+}
+
+auto ResourceManager::GetOrderedConnectors() -> std::vector<DrmConnector *> {
+  /* Put internal displays first then external to
+   * ensure Internal will take Primary slot
+   */
+
+  std::vector<DrmConnector *> ordered_connectors;
+
   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;
+    for (const auto &conn : drm->GetConnectors()) {
+      if (conn->IsInternal()) {
+        ordered_connectors.emplace_back(conn.get());
+      }
+    }
   }
 
-  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))
-      return drm.get();
+    for (const auto &conn : drm->GetConnectors()) {
+      if (conn->IsExternal()) {
+        ordered_connectors.emplace_back(conn.get());
+      }
+    }
   }
-  return nullptr;
-}
 
-const gralloc_module_t *ResourceManager::gralloc() {
-  return gralloc_;
+  return ordered_connectors;
 }
 }  // namespace android
diff --git a/drm/ResourceManager.h b/drm/ResourceManager.h
index 9b4155b..144d00e 100644
--- a/drm/ResourceManager.h
+++ b/drm/ResourceManager.h
@@ -17,41 +17,66 @@
 #ifndef RESOURCEMANAGER_H
 #define RESOURCEMANAGER_H
 
-#include <string.h>
+#include <cstring>
 
 #include "DrmDevice.h"
+#include "DrmDisplayPipeline.h"
 #include "DrmFbImporter.h"
+#include "UEventListener.h"
 
 namespace android {
 
+class PipelineToFrontendBindingInterface {
+ public:
+  virtual ~PipelineToFrontendBindingInterface() = default;
+  virtual bool BindDisplay(DrmDisplayPipeline *);
+  virtual bool UnbindDisplay(DrmDisplayPipeline *);
+  virtual void FinalizeDisplayBinding();
+};
+
 class ResourceManager {
  public:
-  ResourceManager();
+  explicit ResourceManager(
+      PipelineToFrontendBindingInterface *p2f_bind_interface);
   ResourceManager(const ResourceManager &) = delete;
   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_;
-  }
-  int getDisplayCount() const {
-    return num_displays_;
-  }
-  bool ForcedScalingWithGpu() {
+  ResourceManager(const ResourceManager &&) = delete;
+  ResourceManager &&operator=(const ResourceManager &&) = delete;
+  ~ResourceManager();
+
+  void Init();
+
+  void DeInit();
+
+  bool ForcedScalingWithGpu() const {
     return scale_with_gpu_;
   }
 
- private:
-  int AddDrmDevice(std::string const &path);
-  static bool IsKMSDev(const char *path);
+  auto &GetMainLock() {
+    return main_lock_;
+  }
 
-  int num_displays_;
+  static auto GetTimeMonotonicNs() -> int64_t;
+
+ private:
+  auto GetOrderedConnectors() -> std::vector<DrmConnector *>;
+  void UpdateFrontendDisplays();
+  void DetachAllFrontendDisplays();
+
   std::vector<std::unique_ptr<DrmDevice>> drms_;
-  const gralloc_module_t *gralloc_;
 
   bool scale_with_gpu_{};
+
+  UEventListener uevent_listener_;
+
+  std::mutex main_lock_;
+
+  std::map<DrmConnector *, std::unique_ptr<DrmDisplayPipeline>>
+      attached_pipelines_;
+
+  PipelineToFrontendBindingInterface *const frontend_interface_;
+
+  bool initialized_{};
 };
 }  // namespace android
 
diff --git a/drm/UEventListener.cpp b/drm/UEventListener.cpp
new file mode 100644
index 0000000..b56b8e1
--- /dev/null
+++ b/drm/UEventListener.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "hwc-uevent-listener"
+
+#include "UEventListener.h"
+
+#include <cerrno>
+
+#include "utils/log.h"
+
+/* Originally defined in system/core/libsystem/include/system/graphics.h as
+ * #define HAL_PRIORITY_URGENT_DISPLAY (-8)*/
+constexpr int kHalPriorityUrgentDisplay = -8;
+
+namespace android {
+
+UEventListener::UEventListener()
+    : Worker("uevent-listener", kHalPriorityUrgentDisplay){};
+
+int UEventListener::Init() {
+  uevent_ = UEvent::CreateInstance();
+  if (!uevent_) {
+    return -ENODEV;
+  }
+
+  return InitWorker();
+}
+
+void UEventListener::Routine() {
+  while (true) {
+    auto uevent_str = uevent_->ReadNext();
+
+    if (!hotplug_handler_ || !uevent_str)
+      continue;
+
+    bool drm_event = uevent_str->find("DEVTYPE=drm_minor") != std::string::npos;
+    bool hotplug_event = uevent_str->find("HOTPLUG=1") != std::string::npos;
+
+    if (drm_event && hotplug_event) {
+      constexpr useconds_t kDelayAfterUeventUs = 200000;
+      /* We need some delay to ensure DrmConnector::UpdateModes() will query
+       * correct modes list, otherwise at least RPI4 board may report 0 modes */
+      usleep(kDelayAfterUeventUs);
+      hotplug_handler_();
+    }
+  }
+}
+}  // namespace android
diff --git a/drm/UEventListener.h b/drm/UEventListener.h
new file mode 100644
index 0000000..c8b8582
--- /dev/null
+++ b/drm/UEventListener.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UEVENT_LISTENER_H_
+#define ANDROID_UEVENT_LISTENER_H_
+
+#include <functional>
+
+#include "utils/UEvent.h"
+#include "utils/Worker.h"
+
+namespace android {
+
+class UEventListener : public Worker {
+ public:
+  UEventListener();
+  ~UEventListener() override = default;
+
+  int Init();
+
+  void RegisterHotplugHandler(std::function<void()> hotplug_handler) {
+    hotplug_handler_ = std::move(hotplug_handler);
+  }
+
+ protected:
+  void Routine() override;
+
+ private:
+  std::unique_ptr<UEvent> uevent_;
+
+  std::function<void()> hotplug_handler_;
+};
+}  // namespace android
+
+#endif
diff --git a/drm/VSyncWorker.cpp b/drm/VSyncWorker.cpp
index 25eeeab..ed41189 100644
--- a/drm/VSyncWorker.cpp
+++ b/drm/VSyncWorker.cpp
@@ -29,35 +29,17 @@
 
 namespace android {
 
-VSyncWorker::VSyncWorker()
-    : Worker("vsync", HAL_PRIORITY_URGENT_DISPLAY),
-      drm_(nullptr),
-      display_(-1),
-      enabled_(false),
-      last_timestamp_(-1) {
-}
+VSyncWorker::VSyncWorker() : Worker("vsync", HAL_PRIORITY_URGENT_DISPLAY){};
 
-int VSyncWorker::Init(DrmDevice *drm, int display) {
-  drm_ = drm;
-  display_ = display;
+auto VSyncWorker::Init(DrmDisplayPipeline *pipe,
+                       std::function<void(uint64_t /*timestamp*/)> callback)
+    -> int {
+  pipe_ = pipe;
+  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;
@@ -88,7 +70,7 @@
          last_timestamp_;
 }
 
-static const int64_t kOneSecondNs = 1 * 1000 * 1000 * 1000;
+static const int64_t kOneSecondNs = 1LL * 1000 * 1000 * 1000;
 
 int VSyncWorker::SyntheticWaitVBlank(int64_t *timestamp) {
   struct timespec vsync {};
@@ -97,21 +79,20 @@
     return ret;
 
   float refresh = 60.0F;  // Default to 60Hz refresh rate
-  DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
-  if (conn && conn->active_mode().v_refresh() != 0.0F)
-    refresh = conn->active_mode().v_refresh();
-  else
-    ALOGW("Vsync worker active with conn=%p refresh=%f\n", conn,
-          conn ? conn->active_mode().v_refresh() : 0.0F);
+  if (pipe_ != nullptr &&
+      pipe_->connector->Get()->GetActiveMode().v_refresh() != 0.0F) {
+    refresh = pipe_->connector->Get()->GetActiveMode().v_refresh();
+  }
 
-  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;
   vsync.tv_nsec = int(phased_timestamp - (vsync.tv_sec * kOneSecondNs));
   do {
     ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &vsync, nullptr);
-  } while (ret == -1 && errno == EINTR);
+  } while (ret == EINTR);
   if (ret)
     return ret;
 
@@ -131,27 +112,26 @@
     }
   }
 
-  int display = display_;
-  std::shared_ptr<VsyncCallback> callback(callback_);
+  auto *pipe = pipe_;
   Unlock();
 
-  DrmCrtc *crtc = drm_->GetCrtcForDisplay(display);
-  if (!crtc) {
-    ALOGE("Failed to get crtc for display");
-    return;
-  }
-  uint32_t high_crtc = (crtc->pipe() << DRM_VBLANK_HIGH_CRTC_SHIFT);
-
-  drmVBlank vblank;
-  memset(&vblank, 0, sizeof(vblank));
-  vblank.request.type = (drmVBlankSeqType)(
-      DRM_VBLANK_RELATIVE | (high_crtc & DRM_VBLANK_HIGH_CRTC_MASK));
-  vblank.request.sequence = 1;
-
+  ret = -EAGAIN;
   int64_t timestamp = 0;
-  ret = drmWaitVBlank(drm_->fd(), &vblank);
-  if (ret == -EINTR)
-    return;
+  drmVBlank vblank{};
+
+  if (pipe != nullptr) {
+    uint32_t high_crtc = (pipe->crtc->Get()->GetIndexInResArray()
+                          << DRM_VBLANK_HIGH_CRTC_SHIFT);
+
+    vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE |
+                                             (high_crtc &
+                                              DRM_VBLANK_HIGH_CRTC_MASK));
+    vblank.request.sequence = 1;
+
+    ret = drmWaitVBlank(pipe->device->GetFd(), &vblank);
+    if (ret == -EINTR)
+      return;
+  }
 
   if (ret) {
     ret = SyntheticWaitVBlank(&timestamp);
@@ -165,13 +145,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..1e6d39f 100644
--- a/drm/VSyncWorker.h
+++ b/drm/VSyncWorker.h
@@ -20,9 +20,10 @@
 #include <hardware/hardware.h>
 #include <hardware/hwcomposer.h>
 #include <hardware/hwcomposer2.h>
-#include <stdint.h>
 
 #include <atomic>
+#include <cstdint>
+#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(DrmDisplayPipeline *pipe,
+            std::function<void(uint64_t /*timestamp*/)> callback) -> int;
 
   void VSyncControl(bool enabled);
 
@@ -55,19 +48,11 @@
   int64_t GetPhasedVSync(int64_t frame_ns, int64_t current) const;
   int SyntheticWaitVBlank(int64_t *timestamp);
 
-  DrmDevice *drm_;
+  std::function<void(uint64_t /*timestamp*/)> callback_;
 
-  // 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;
-
-  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;
+  DrmDisplayPipeline *pipe_ = nullptr;
+  std::atomic_bool enabled_ = false;
+  int64_t last_timestamp_ = -1;
 };
 }  // namespace android
 
diff --git a/hwc2_device/DrmHwcTwo.cpp b/hwc2_device/DrmHwcTwo.cpp
new file mode 100644
index 0000000..4accb07
--- /dev/null
+++ b/hwc2_device/DrmHwcTwo.cpp
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "hwc-drm-two"
+
+#include "DrmHwcTwo.h"
+
+#include <cinttypes>
+
+#include "backend/Backend.h"
+#include "utils/log.h"
+
+namespace android {
+
+DrmHwcTwo::DrmHwcTwo() : resource_manager_(this){};
+
+/* Must be called after every display attach/detach cycle */
+void DrmHwcTwo::FinalizeDisplayBinding() {
+  if (displays_.count(kPrimaryDisplay) == 0) {
+    /* Primary display MUST always exist */
+    ALOGI("No pipelines available. Creating null-display for headless mode");
+    displays_[kPrimaryDisplay] = std::make_unique<
+        HwcDisplay>(kPrimaryDisplay, HWC2::DisplayType::Physical, this);
+    /* Initializes null-display */
+    displays_[kPrimaryDisplay]->SetPipeline(nullptr);
+  }
+
+  if (displays_[kPrimaryDisplay]->IsInHeadlessMode() &&
+      !display_handles_.empty()) {
+    /* Reattach first secondary display to take place of the primary */
+    auto *pipe = display_handles_.begin()->first;
+    ALOGI("Primary display was disconnected, reattaching '%s' as new primary",
+          pipe->connector->Get()->GetName().c_str());
+    UnbindDisplay(pipe);
+    BindDisplay(pipe);
+  }
+
+  // Finally, send hotplug events to the client
+  for (auto &dhe : deferred_hotplug_events_) {
+    SendHotplugEventToClient(dhe.first, dhe.second);
+  }
+  deferred_hotplug_events_.clear();
+
+  /* Wait 0.2s before removing the displays to flush pending HWC2 transactions
+   */
+  auto &mutex = GetResMan().GetMainLock();
+  mutex.unlock();
+  const int kTimeForSFToDisposeDisplayUs = 200000;
+  usleep(kTimeForSFToDisposeDisplayUs);
+  mutex.lock();
+  std::vector<std::unique_ptr<HwcDisplay>> for_disposal;
+  for (auto handle : displays_for_removal_list_) {
+    for_disposal.emplace_back(
+        std::unique_ptr<HwcDisplay>(displays_[handle].release()));
+    displays_.erase(handle);
+  }
+  /* Destroy HwcDisplays while unlocked to avoid vsyncworker deadlocks */
+  mutex.unlock();
+  for_disposal.clear();
+  mutex.lock();
+}
+
+bool DrmHwcTwo::BindDisplay(DrmDisplayPipeline *pipeline) {
+  if (display_handles_.count(pipeline) != 0) {
+    ALOGE("%s, pipeline is already used by another display, FIXME!!!: %p",
+          __func__, pipeline);
+    return false;
+  }
+
+  uint32_t disp_handle = kPrimaryDisplay;
+
+  if (displays_.count(kPrimaryDisplay) != 0 &&
+      !displays_[kPrimaryDisplay]->IsInHeadlessMode()) {
+    disp_handle = ++last_display_handle_;
+  }
+
+  if (displays_.count(disp_handle) == 0) {
+    auto disp = std::make_unique<HwcDisplay>(disp_handle,
+                                             HWC2::DisplayType::Physical, this);
+    displays_[disp_handle] = std::move(disp);
+  }
+
+  ALOGI("Attaching pipeline '%s' to the display #%d%s",
+        pipeline->connector->Get()->GetName().c_str(), (int)disp_handle,
+        disp_handle == kPrimaryDisplay ? " (Primary)" : "");
+
+  displays_[disp_handle]->SetPipeline(pipeline);
+  display_handles_[pipeline] = disp_handle;
+
+  return true;
+}
+
+bool DrmHwcTwo::UnbindDisplay(DrmDisplayPipeline *pipeline) {
+  if (display_handles_.count(pipeline) == 0) {
+    ALOGE("%s, can't find the display, pipeline: %p", __func__, pipeline);
+    return false;
+  }
+  auto handle = display_handles_[pipeline];
+  display_handles_.erase(pipeline);
+
+  ALOGI("Detaching the pipeline '%s' from the display #%i%s",
+        pipeline->connector->Get()->GetName().c_str(), (int)handle,
+        handle == kPrimaryDisplay ? " (Primary)" : "");
+
+  if (displays_.count(handle) == 0) {
+    ALOGE("%s, can't find the display, handle: %" PRIu64, __func__, handle);
+    return false;
+  }
+  displays_[handle]->SetPipeline(nullptr);
+
+  /* We must defer display disposal and removal, since it may still have pending
+   * HWC_API calls scheduled and waiting until ueventlistener thread releases
+   * main lock, otherwise transaction may fail and SF may crash
+   */
+  if (handle != kPrimaryDisplay) {
+    displays_for_removal_list_.emplace_back(handle);
+  }
+  return true;
+}
+
+HWC2::Error DrmHwcTwo::CreateVirtualDisplay(uint32_t /*width*/,
+                                            uint32_t /*height*/,
+                                            int32_t * /*format*/,
+                                            hwc2_display_t * /*display*/) {
+  // TODO(nobody): Implement virtual display
+  return HWC2::Error::Unsupported;
+}
+
+HWC2::Error DrmHwcTwo::DestroyVirtualDisplay(hwc2_display_t /*display*/) {
+  // TODO(nobody): Implement virtual display
+  return HWC2::Error::Unsupported;
+}
+
+void DrmHwcTwo::Dump(uint32_t *outSize, char *outBuffer) {
+  if (outBuffer != nullptr) {
+    auto copied_bytes = mDumpString.copy(outBuffer, *outSize);
+    *outSize = static_cast<uint32_t>(copied_bytes);
+    return;
+  }
+
+  std::stringstream output;
+
+  output << "-- drm_hwcomposer --\n\n";
+
+  for (auto &disp : displays_)
+    output << disp.second->Dump();
+
+  mDumpString = output.str();
+  *outSize = static_cast<uint32_t>(mDumpString.size());
+}
+
+uint32_t DrmHwcTwo::GetMaxVirtualDisplayCount() {
+  // TODO(nobody): Implement virtual display
+  return 0;
+}
+
+HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
+                                        hwc2_callback_data_t data,
+                                        hwc2_function_pointer_t function) {
+  switch (static_cast<HWC2::Callback>(descriptor)) {
+    case HWC2::Callback::Hotplug: {
+      hotplug_callback_ = std::make_pair(HWC2_PFN_HOTPLUG(function), data);
+      if (function != nullptr) {
+        resource_manager_.Init();
+      } else {
+        resource_manager_.DeInit();
+        /* Headless display may still be here. Remove it! */
+        if (displays_.count(kPrimaryDisplay) != 0) {
+          displays_[kPrimaryDisplay]->Deinit();
+          auto &mutex = GetResMan().GetMainLock();
+          mutex.unlock();
+          displays_.erase(kPrimaryDisplay);
+          mutex.lock();
+        }
+      }
+      break;
+    }
+    case HWC2::Callback::Refresh: {
+      refresh_callback_ = std::make_pair(HWC2_PFN_REFRESH(function), data);
+      break;
+    }
+    case HWC2::Callback::Vsync: {
+      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;
+    }
+    case HWC2::Callback::VsyncPeriodTimingChanged: {
+      period_timing_changed_callback_ = std::
+          make_pair(HWC2_PFN_VSYNC_PERIOD_TIMING_CHANGED(function), data);
+      break;
+    }
+#endif
+    default:
+      break;
+  }
+  return HWC2::Error::None;
+}
+
+void DrmHwcTwo::SendHotplugEventToClient(hwc2_display_t displayid,
+                                         bool connected) {
+  auto &mutex = GetResMan().GetMainLock();
+  if (mutex.try_lock()) {
+    ALOGE("FIXME!!!: Main mutex must be locked in %s", __func__);
+    mutex.unlock();
+    return;
+  }
+
+  auto hc = hotplug_callback_;
+  if (hc.first != nullptr && hc.second != nullptr) {
+    /* For some reason CLIENT will call HWC2 API in hotplug callback handler,
+     * which will cause deadlock . Unlock main mutex to prevent this.
+     */
+    mutex.unlock();
+    hc.first(hc.second, displayid,
+             connected == DRM_MODE_CONNECTED ? HWC2_CONNECTION_CONNECTED
+                                             : HWC2_CONNECTION_DISCONNECTED);
+    mutex.lock();
+  }
+}
+
+void DrmHwcTwo::SendVsyncEventToClient(
+    hwc2_display_t displayid, int64_t timestamp,
+    [[maybe_unused]] uint32_t vsync_period) const {
+  /* vsync callback */
+#if PLATFORM_SDK_VERSION > 29
+  if (vsync_2_4_callback_.first != nullptr &&
+      vsync_2_4_callback_.second != nullptr) {
+    vsync_2_4_callback_.first(vsync_2_4_callback_.second, displayid, timestamp,
+                              vsync_period);
+  } else
+#endif
+      if (vsync_callback_.first != nullptr &&
+          vsync_callback_.second != nullptr) {
+    vsync_callback_.first(vsync_callback_.second, displayid, timestamp);
+  }
+}
+
+void DrmHwcTwo::SendVsyncPeriodTimingChangedEventToClient(
+    [[maybe_unused]] hwc2_display_t displayid,
+    [[maybe_unused]] int64_t timestamp) const {
+#if PLATFORM_SDK_VERSION > 29
+  hwc_vsync_period_change_timeline_t timeline = {
+      .newVsyncAppliedTimeNanos = timestamp,
+      .refreshRequired = false,
+      .refreshTimeNanos = 0,
+  };
+  if (period_timing_changed_callback_.first != nullptr &&
+      period_timing_changed_callback_.second != nullptr) {
+    period_timing_changed_callback_
+        .first(period_timing_changed_callback_.second, displayid, &timeline);
+  }
+#endif
+}
+
+}  // namespace android
diff --git a/hwc2_device/DrmHwcTwo.h b/hwc2_device/DrmHwcTwo.h
new file mode 100644
index 0000000..2b8a74f
--- /dev/null
+++ b/hwc2_device/DrmHwcTwo.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_DRM_HWC_TWO_H_
+#define ANDROID_DRM_HWC_TWO_H_
+
+#include <hardware/hwcomposer2.h>
+
+#include "drm/ResourceManager.h"
+#include "hwc2_device/HwcDisplay.h"
+
+namespace android {
+
+class DrmHwcTwo : public PipelineToFrontendBindingInterface {
+ public:
+  DrmHwcTwo();
+  ~DrmHwcTwo() override = default;
+
+  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_{};
+  std::pair<HWC2_PFN_VSYNC_PERIOD_TIMING_CHANGED, hwc2_callback_data_t>
+      period_timing_changed_callback_{};
+#endif
+  std::pair<HWC2_PFN_REFRESH, hwc2_callback_data_t> refresh_callback_{};
+
+  // Device functions
+  HWC2::Error CreateVirtualDisplay(uint32_t width, uint32_t height,
+                                   int32_t *format, hwc2_display_t *display);
+  HWC2::Error DestroyVirtualDisplay(hwc2_display_t display);
+  void Dump(uint32_t *outSize, char *outBuffer);
+  uint32_t GetMaxVirtualDisplayCount();
+  HWC2::Error RegisterCallback(int32_t descriptor, hwc2_callback_data_t data,
+                               hwc2_function_pointer_t function);
+
+  auto GetDisplay(hwc2_display_t display_handle) {
+    return displays_.count(display_handle) != 0
+               ? displays_[display_handle].get()
+               : nullptr;
+  }
+
+  auto &GetResMan() {
+    return resource_manager_;
+  }
+
+  void ScheduleHotplugEvent(hwc2_display_t displayid, bool connected) {
+    deferred_hotplug_events_[displayid] = connected;
+  }
+
+  // PipelineToFrontendBindingInterface
+  bool BindDisplay(DrmDisplayPipeline *pipeline) override;
+  bool UnbindDisplay(DrmDisplayPipeline *pipeline) override;
+  void FinalizeDisplayBinding() override;
+
+  void SendVsyncEventToClient(hwc2_display_t displayid, int64_t timestamp,
+                              uint32_t vsync_period) const;
+  void SendVsyncPeriodTimingChangedEventToClient(hwc2_display_t displayid,
+                                                 int64_t timestamp) const;
+
+ private:
+  void SendHotplugEventToClient(hwc2_display_t displayid, bool connected);
+
+  ResourceManager resource_manager_;
+  std::map<hwc2_display_t, std::unique_ptr<HwcDisplay>> displays_;
+  std::map<DrmDisplayPipeline *, hwc2_display_t> display_handles_;
+
+  std::string mDumpString;
+
+  std::map<hwc2_display_t, bool> deferred_hotplug_events_;
+  std::vector<hwc2_display_t> displays_for_removal_list_;
+
+  uint32_t last_display_handle_ = kPrimaryDisplay;
+};
+}  // namespace android
+
+#endif
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
new file mode 100644
index 0000000..d968ab3
--- /dev/null
+++ b/hwc2_device/HwcDisplay.cpp
@@ -0,0 +1,974 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "hwc-display"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "HwcDisplay.h"
+
+#include "DrmHwcTwo.h"
+#include "backend/Backend.h"
+#include "backend/BackendManager.h"
+#include "bufferinfo/BufferInfoGetter.h"
+#include "utils/log.h"
+#include "utils/properties.h"
+
+namespace android {
+
+std::string HwcDisplay::DumpDelta(HwcDisplay::Stats delta) {
+  if (delta.total_pixops_ == 0)
+    return "No stats yet";
+  double ratio = 1.0 - double(delta.gpu_pixops_) / double(delta.total_pixops_);
+
+  std::stringstream ss;
+  ss << " Total frames count: " << delta.total_frames_ << "\n"
+     << " Failed to test commit frames: " << delta.failed_kms_validate_ << "\n"
+     << " Failed to commit frames: " << delta.failed_kms_present_ << "\n"
+     << ((delta.failed_kms_present_ > 0)
+             ? " !!! Internal failure, FIX it please\n"
+             : "")
+     << " Flattened frames: " << delta.frames_flattened_ << "\n"
+     << " Pixel operations (free units)"
+     << " : [TOTAL: " << delta.total_pixops_ << " / GPU: " << delta.gpu_pixops_
+     << "]\n"
+     << " Composition efficiency: " << ratio;
+
+  return ss.str();
+}
+
+std::string 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::string connector_name = IsInHeadlessMode()
+                                   ? "NULL-DISPLAY"
+                                   : GetPipe().connector->Get()->GetName();
+
+  std::stringstream ss;
+  ss << "- Display on: " << connector_name << "\n"
+     << "  Flattening state: " << flattening_state_str << "\n"
+     << "Statistics since system boot:\n"
+     << DumpDelta(total_stats_) << "\n\n"
+     << "Statistics since last dumpsys request:\n"
+     << DumpDelta(total_stats_.minus(prev_stats_)) << "\n\n";
+
+  memcpy(&prev_stats_, &total_stats_, sizeof(Stats));
+  return ss.str();
+}
+
+HwcDisplay::HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type,
+                       DrmHwcTwo *hwc2)
+    : hwc2_(hwc2),
+      handle_(handle),
+      type_(type),
+      client_layer_(this),
+      color_transform_hint_(HAL_COLOR_TRANSFORM_IDENTITY) {
+  // clang-format off
+  color_transform_matrix_ = {1.0, 0.0, 0.0, 0.0,
+                             0.0, 1.0, 0.0, 0.0,
+                             0.0, 0.0, 1.0, 0.0,
+                             0.0, 0.0, 0.0, 1.0};
+  // clang-format on
+}
+
+HwcDisplay::~HwcDisplay() = default;
+
+void HwcDisplay::SetPipeline(DrmDisplayPipeline *pipeline) {
+  Deinit();
+
+  pipeline_ = pipeline;
+
+  if (pipeline != nullptr || handle_ == kPrimaryDisplay) {
+    Init();
+    hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ true);
+  } else {
+    hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ false);
+  }
+}
+
+void HwcDisplay::Deinit() {
+  if (pipeline_ != nullptr) {
+    AtomicCommitArgs a_args{};
+    a_args.composition = std::make_shared<DrmKmsPlan>();
+    GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
+/*
+ *  TODO:
+ *  Unfortunately the following causes regressions on db845c
+ *  with VtsHalGraphicsComposerV2_3TargetTest due to the display
+ *  never coming back. Patches to avoiding that issue on the
+ *  the kernel side unfortunately causes further crashes in
+ *  drm_hwcomposer, because the client detach takes longer then the
+ *  1 second max VTS expects. So for now as a workaround, lets skip
+ *  deactivating the display on deinit, which matches previous
+ *  behavior prior to commit d0494d9b8097
+ */
+#if 0
+    a_args.composition = {};
+    a_args.active = false;
+    GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
+#endif
+
+    vsync_worker_.Init(nullptr, [](int64_t) {});
+    current_plan_.reset();
+    backend_.reset();
+  }
+
+  SetClientTarget(nullptr, -1, 0, {});
+}
+
+HWC2::Error HwcDisplay::Init() {
+  ChosePreferredConfig();
+
+  int ret = vsync_worker_.Init(pipeline_, [this](int64_t timestamp) {
+    const std::lock_guard<std::mutex> lock(hwc2_->GetResMan().GetMainLock());
+    if (vsync_event_en_) {
+      uint32_t period_ns{};
+      GetDisplayVsyncPeriod(&period_ns);
+      hwc2_->SendVsyncEventToClient(handle_, timestamp, period_ns);
+    }
+    if (vsync_flattening_en_) {
+      ProcessFlatenningVsyncInternal();
+    }
+    if (vsync_tracking_en_) {
+      last_vsync_ts_ = timestamp;
+    }
+    if (!vsync_event_en_ && !vsync_flattening_en_ && !vsync_tracking_en_) {
+      vsync_worker_.VSyncControl(false);
+    }
+  });
+  if (ret && ret != -EALREADY) {
+    ALOGE("Failed to create event worker for d=%d %d\n", int(handle_), ret);
+    return HWC2::Error::BadDisplay;
+  }
+
+  if (!IsInHeadlessMode()) {
+    ret = BackendManager::GetInstance().SetBackendForDisplay(this);
+    if (ret) {
+      ALOGE("Failed to set backend for d=%d %d\n", int(handle_), ret);
+      return HWC2::Error::BadDisplay;
+    }
+  }
+
+  client_layer_.SetLayerBlendMode(HWC2_BLEND_MODE_PREMULTIPLIED);
+
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::ChosePreferredConfig() {
+  HWC2::Error err{};
+  if (!IsInHeadlessMode()) {
+    err = configs_.Update(*pipeline_->connector->Get());
+  } else {
+    configs_.FillHeadless();
+  }
+  if (!IsInHeadlessMode() && err != HWC2::Error::None) {
+    return HWC2::Error::BadDisplay;
+  }
+
+  return SetActiveConfig(configs_.preferred_config_id);
+}
+
+HWC2::Error HwcDisplay::AcceptDisplayChanges() {
+  for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_)
+    l.second.AcceptTypeChange();
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::CreateLayer(hwc2_layer_t *layer) {
+  layers_.emplace(static_cast<hwc2_layer_t>(layer_idx_), HwcLayer(this));
+  *layer = static_cast<hwc2_layer_t>(layer_idx_);
+  ++layer_idx_;
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::DestroyLayer(hwc2_layer_t layer) {
+  if (!get_layer(layer)) {
+    return HWC2::Error::BadLayer;
+  }
+
+  layers_.erase(layer);
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::GetActiveConfig(hwc2_config_t *config) const {
+  if (configs_.hwc_configs.count(staged_mode_config_id_) == 0)
+    return HWC2::Error::BadConfig;
+
+  *config = staged_mode_config_id_;
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::GetChangedCompositionTypes(uint32_t *num_elements,
+                                                   hwc2_layer_t *layers,
+                                                   int32_t *types) {
+  if (IsInHeadlessMode()) {
+    *num_elements = 0;
+    return HWC2::Error::None;
+  }
+
+  uint32_t num_changes = 0;
+  for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) {
+    if (l.second.IsTypeChanged()) {
+      if (layers && num_changes < *num_elements)
+        layers[num_changes] = l.first;
+      if (types && num_changes < *num_elements)
+        types[num_changes] = static_cast<int32_t>(l.second.GetValidatedType());
+      ++num_changes;
+    }
+  }
+  if (!layers && !types)
+    *num_elements = num_changes;
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::GetClientTargetSupport(uint32_t width, uint32_t height,
+                                               int32_t /*format*/,
+                                               int32_t dataspace) {
+  if (IsInHeadlessMode()) {
+    return HWC2::Error::None;
+  }
+
+  std::pair<uint32_t, uint32_t> min = pipeline_->device->GetMinResolution();
+  std::pair<uint32_t, uint32_t> max = pipeline_->device->GetMaxResolution();
+
+  if (width < min.first || height < min.second)
+    return HWC2::Error::Unsupported;
+
+  if (width > max.first || height > max.second)
+    return HWC2::Error::Unsupported;
+
+  if (dataspace != HAL_DATASPACE_UNKNOWN)
+    return HWC2::Error::Unsupported;
+
+  // TODO(nobody): Validate format can be handled by either GL or planes
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::GetColorModes(uint32_t *num_modes, int32_t *modes) {
+  if (!modes)
+    *num_modes = 1;
+
+  if (modes)
+    *modes = HAL_COLOR_MODE_NATIVE;
+
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::GetDisplayAttribute(hwc2_config_t config,
+                                            int32_t attribute_in,
+                                            int32_t *value) {
+  int conf = static_cast<int>(config);
+
+  if (configs_.hwc_configs.count(conf) == 0) {
+    ALOGE("Could not find mode #%d", conf);
+    return HWC2::Error::BadConfig;
+  }
+
+  auto &hwc_config = configs_.hwc_configs[conf];
+
+  static const int32_t kUmPerInch = 25400;
+  uint32_t mm_width = configs_.mm_width;
+  uint32_t mm_height = configs_.mm_height;
+  auto attribute = static_cast<HWC2::Attribute>(attribute_in);
+  switch (attribute) {
+    case HWC2::Attribute::Width:
+      *value = static_cast<int>(hwc_config.mode.h_display());
+      break;
+    case HWC2::Attribute::Height:
+      *value = static_cast<int>(hwc_config.mode.v_display());
+      break;
+    case HWC2::Attribute::VsyncPeriod:
+      // in nanoseconds
+      *value = static_cast<int>(1E9 / hwc_config.mode.v_refresh());
+      break;
+    case HWC2::Attribute::DpiX:
+      // Dots per 1000 inches
+      *value = mm_width ? static_cast<int>(hwc_config.mode.h_display() *
+                                           kUmPerInch / mm_width)
+                        : -1;
+      break;
+    case HWC2::Attribute::DpiY:
+      // Dots per 1000 inches
+      *value = mm_height ? static_cast<int>(hwc_config.mode.v_display() *
+                                            kUmPerInch / mm_height)
+                         : -1;
+      break;
+#if PLATFORM_SDK_VERSION > 29
+    case HWC2::Attribute::ConfigGroup:
+      /* Dispite ConfigGroup is a part of HWC2.4 API, framework
+       * able to request it even if service @2.1 is used */
+      *value = int(hwc_config.group_id);
+      break;
+#endif
+    default:
+      *value = -1;
+      return HWC2::Error::BadConfig;
+  }
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::GetDisplayConfigs(uint32_t *num_configs,
+                                          hwc2_config_t *configs) {
+  uint32_t idx = 0;
+  for (auto &hwc_config : configs_.hwc_configs) {
+    if (hwc_config.second.disabled) {
+      continue;
+    }
+
+    if (configs != nullptr) {
+      if (idx >= *num_configs) {
+        break;
+      }
+      configs[idx] = hwc_config.second.id;
+    }
+
+    idx++;
+  }
+  *num_configs = idx;
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::GetDisplayName(uint32_t *size, char *name) {
+  std::ostringstream stream;
+  if (IsInHeadlessMode()) {
+    stream << "null-display";
+  } else {
+    stream << "display-" << GetPipe().connector->Get()->GetId();
+  }
+  std::string string = stream.str();
+  size_t length = string.length();
+  if (!name) {
+    *size = length;
+    return HWC2::Error::None;
+  }
+
+  *size = std::min<uint32_t>(static_cast<uint32_t>(length - 1), *size);
+  strncpy(name, string.c_str(), *size);
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::GetDisplayRequests(int32_t * /*display_requests*/,
+                                           uint32_t *num_elements,
+                                           hwc2_layer_t * /*layers*/,
+                                           int32_t * /*layer_requests*/) {
+  // TODO(nobody): I think virtual display should request
+  //      HWC2_DISPLAY_REQUEST_WRITE_CLIENT_TARGET_TO_OUTPUT here
+  *num_elements = 0;
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::GetDisplayType(int32_t *type) {
+  *type = static_cast<int32_t>(type_);
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::GetDozeSupport(int32_t *support) {
+  *support = 0;
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::GetHdrCapabilities(uint32_t *num_types,
+                                           int32_t * /*types*/,
+                                           float * /*max_luminance*/,
+                                           float * /*max_average_luminance*/,
+                                           float * /*min_luminance*/) {
+  *num_types = 0;
+  return HWC2::Error::None;
+}
+
+/* Find API details at:
+ * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1767
+ *
+ * Called after PresentDisplay(), CLIENT is expecting release fence for the
+ * prior buffer (not the one assigned to the layer at the moment).
+ */
+HWC2::Error HwcDisplay::GetReleaseFences(uint32_t *num_elements,
+                                         hwc2_layer_t *layers,
+                                         int32_t *fences) {
+  if (IsInHeadlessMode()) {
+    *num_elements = 0;
+    return HWC2::Error::None;
+  }
+
+  uint32_t num_layers = 0;
+
+  for (auto &l : layers_) {
+    if (!l.second.GetPriorBufferScanOutFlag() || !present_fence_) {
+      continue;
+    }
+
+    ++num_layers;
+
+    if (layers == nullptr || fences == nullptr)
+      continue;
+
+    if (num_layers > *num_elements) {
+      ALOGW("Overflow num_elements %d/%d", num_layers, *num_elements);
+      return HWC2::Error::None;
+    }
+
+    layers[num_layers - 1] = l.first;
+    fences[num_layers - 1] = UniqueFd::Dup(present_fence_.Get()).Release();
+  }
+  *num_elements = num_layers;
+
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
+  if (IsInHeadlessMode()) {
+    ALOGE("%s: Display is in headless mode, should never reach here", __func__);
+    return HWC2::Error::None;
+  }
+
+  int PrevModeVsyncPeriodNs = static_cast<int>(
+      1E9 / GetPipe().connector->Get()->GetActiveMode().v_refresh());
+
+  auto mode_update_commited_ = false;
+  if (staged_mode_ &&
+      staged_mode_change_time_ <= ResourceManager::GetTimeMonotonicNs()) {
+    client_layer_.SetLayerDisplayFrame(
+        (hwc_rect_t){.left = 0,
+                     .top = 0,
+                     .right = static_cast<int>(staged_mode_->h_display()),
+                     .bottom = static_cast<int>(staged_mode_->v_display())});
+
+    configs_.active_config_id = staged_mode_config_id_;
+
+    a_args.display_mode = *staged_mode_;
+    if (!a_args.test_only) {
+      mode_update_commited_ = true;
+    }
+  }
+
+  // order the layers by z-order
+  bool use_client_layer = false;
+  uint32_t client_z_order = UINT32_MAX;
+  std::map<uint32_t, HwcLayer *> z_map;
+  for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) {
+    switch (l.second.GetValidatedType()) {
+      case HWC2::Composition::Device:
+        z_map.emplace(std::make_pair(l.second.GetZOrder(), &l.second));
+        break;
+      case HWC2::Composition::Client:
+        // Place it at the z_order of the lowest client layer
+        use_client_layer = true;
+        client_z_order = std::min(client_z_order, l.second.GetZOrder());
+        break;
+      default:
+        continue;
+    }
+  }
+  if (use_client_layer)
+    z_map.emplace(std::make_pair(client_z_order, &client_layer_));
+
+  if (z_map.empty())
+    return HWC2::Error::BadLayer;
+
+  std::vector<LayerData> composition_layers;
+
+  /* Import & populate */
+  for (std::pair<const uint32_t, HwcLayer *> &l : z_map) {
+    l.second->PopulateLayerData(a_args.test_only);
+  }
+
+  // now that they're ordered by z, add them to the composition
+  for (std::pair<const uint32_t, HwcLayer *> &l : z_map) {
+    if (!l.second->IsLayerUsableAsDevice()) {
+      /* This will be normally triggered on validation of the first frame
+       * containing CLIENT layer. At this moment client buffer is not yet
+       * provided by the CLIENT.
+       * This may be triggered once in HwcLayer lifecycle in case FB can't be
+       * imported. For example when non-contiguous buffer is imported into
+       * contiguous-only DRM/KMS driver.
+       */
+      return HWC2::Error::BadLayer;
+    }
+    composition_layers.emplace_back(l.second->GetLayerData().Clone());
+  }
+
+  /* Store plan to ensure shared planes won't be stolen by other display
+   * in between of ValidateDisplay() and PresentDisplay() calls
+   */
+  current_plan_ = DrmKmsPlan::CreateDrmKmsPlan(GetPipe(),
+                                               std::move(composition_layers));
+  if (!current_plan_) {
+    if (!a_args.test_only) {
+      ALOGE("Failed to create DrmKmsPlan");
+    }
+    return HWC2::Error::BadConfig;
+  }
+
+  a_args.composition = current_plan_;
+
+  int ret = GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
+
+  if (ret) {
+    if (!a_args.test_only)
+      ALOGE("Failed to apply the frame composition ret=%d", ret);
+    return HWC2::Error::BadParameter;
+  }
+
+  if (mode_update_commited_) {
+    staged_mode_.reset();
+    vsync_tracking_en_ = false;
+    if (last_vsync_ts_ != 0) {
+      hwc2_->SendVsyncPeriodTimingChangedEventToClient(
+          handle_, last_vsync_ts_ + PrevModeVsyncPeriodNs);
+    }
+  }
+
+  return HWC2::Error::None;
+}
+
+/* Find API details at:
+ * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1805
+ */
+HWC2::Error HwcDisplay::PresentDisplay(int32_t *out_present_fence) {
+  if (IsInHeadlessMode()) {
+    *out_present_fence = -1;
+    return HWC2::Error::None;
+  }
+  HWC2::Error ret{};
+
+  ++total_stats_.total_frames_;
+
+  AtomicCommitArgs a_args{};
+  ret = CreateComposition(a_args);
+
+  if (ret != HWC2::Error::None)
+    ++total_stats_.failed_kms_present_;
+
+  if (ret == HWC2::Error::BadLayer) {
+    // Can we really have no client or device layers?
+    *out_present_fence = -1;
+    return HWC2::Error::None;
+  }
+  if (ret != HWC2::Error::None)
+    return ret;
+
+  this->present_fence_ = UniqueFd::Dup(a_args.out_fence.Get());
+  *out_present_fence = a_args.out_fence.Release();
+
+  ++frame_no_;
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::SetActiveConfigInternal(uint32_t config,
+                                                int64_t change_time) {
+  if (configs_.hwc_configs.count(config) == 0) {
+    ALOGE("Could not find active mode for %u", config);
+    return HWC2::Error::BadConfig;
+  }
+
+  staged_mode_ = configs_.hwc_configs[config].mode;
+  staged_mode_change_time_ = change_time;
+  staged_mode_config_id_ = config;
+
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::SetActiveConfig(hwc2_config_t config) {
+  return SetActiveConfigInternal(config, ResourceManager::GetTimeMonotonicNs());
+}
+
+/* Find API details at:
+ * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1861
+ */
+HWC2::Error HwcDisplay::SetClientTarget(buffer_handle_t target,
+                                        int32_t acquire_fence,
+                                        int32_t dataspace,
+                                        hwc_region_t /*damage*/) {
+  client_layer_.SetLayerBuffer(target, acquire_fence);
+  client_layer_.SetLayerDataspace(dataspace);
+
+  /*
+   * target can be nullptr, this does mean the Composer Service is calling
+   * cleanDisplayResources() on after receiving HOTPLUG event. See more at:
+   * https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h;l=350;drc=944b68180b008456ed2eb4d4d329e33b19bd5166
+   */
+  if (target == nullptr) {
+    client_layer_.SwChainClearCache();
+    return HWC2::Error::None;
+  }
+
+  if (IsInHeadlessMode()) {
+    return HWC2::Error::None;
+  }
+
+  client_layer_.PopulateLayerData(/*test = */ true);
+  if (!client_layer_.IsLayerUsableAsDevice()) {
+    ALOGE("Client layer must be always usable by DRM/KMS");
+    return HWC2::Error::BadLayer;
+  }
+
+  auto &bi = client_layer_.GetLayerData().bi;
+  hwc_frect_t source_crop = {.left = 0.0F,
+                             .top = 0.0F,
+                             .right = static_cast<float>(bi->width),
+                             .bottom = static_cast<float>(bi->height)};
+  client_layer_.SetLayerSourceCrop(source_crop);
+
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::SetColorMode(int32_t mode) {
+  if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_BT2100_HLG)
+    return HWC2::Error::BadParameter;
+
+  if (mode != HAL_COLOR_MODE_NATIVE)
+    return HWC2::Error::Unsupported;
+
+  color_mode_ = mode;
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::SetColorTransform(const float *matrix, int32_t hint) {
+  if (hint < HAL_COLOR_TRANSFORM_IDENTITY ||
+      hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA)
+    return HWC2::Error::BadParameter;
+
+  if (!matrix && hint == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX)
+    return HWC2::Error::BadParameter;
+
+  color_transform_hint_ = static_cast<android_color_transform_t>(hint);
+  if (color_transform_hint_ == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX)
+    std::copy(matrix, matrix + MATRIX_SIZE, color_transform_matrix_.begin());
+
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::SetOutputBuffer(buffer_handle_t /*buffer*/,
+                                        int32_t /*release_fence*/) {
+  // TODO(nobody): Need virtual display support
+  return HWC2::Error::Unsupported;
+}
+
+HWC2::Error HwcDisplay::SetPowerMode(int32_t mode_in) {
+  auto mode = static_cast<HWC2::PowerMode>(mode_in);
+
+  AtomicCommitArgs a_args{};
+
+  switch (mode) {
+    case HWC2::PowerMode::Off:
+      a_args.active = false;
+      break;
+    case HWC2::PowerMode::On:
+      a_args.active = true;
+      break;
+    case HWC2::PowerMode::Doze:
+    case HWC2::PowerMode::DozeSuspend:
+      return HWC2::Error::Unsupported;
+    default:
+      ALOGE("Incorrect power mode value (%d)\n", mode);
+      return HWC2::Error::BadParameter;
+  }
+
+  if (IsInHeadlessMode()) {
+    return HWC2::Error::None;
+  }
+
+  if (a_args.active) {
+    /*
+     * Setting the display to active before we have a composition
+     * can break some drivers, so skip setting a_args.active to
+     * true, as the next composition frame will implicitly activate
+     * the display
+     */
+    return GetPipe().atomic_state_manager->ActivateDisplayUsingDPMS() == 0
+               ? HWC2::Error::None
+               : HWC2::Error::BadParameter;
+  };
+
+  int err = GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
+  if (err) {
+    ALOGE("Failed to apply the dpms composition err=%d", err);
+    return HWC2::Error::BadParameter;
+  }
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::SetVsyncEnabled(int32_t enabled) {
+  vsync_event_en_ = HWC2_VSYNC_ENABLE == enabled;
+  if (vsync_event_en_) {
+    vsync_worker_.VSyncControl(true);
+  }
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::ValidateDisplay(uint32_t *num_types,
+                                        uint32_t *num_requests) {
+  if (IsInHeadlessMode()) {
+    *num_types = *num_requests = 0;
+    return HWC2::Error::None;
+  }
+
+  /* In current drm_hwc design in case previous frame layer was not validated as
+   * a CLIENT, it is used by display controller (Front buffer). We have to store
+   * this state to provide the CLIENT with the release fences for such buffers.
+   */
+  for (auto &l : layers_) {
+    l.second.SetPriorBufferScanOutFlag(l.second.GetValidatedType() !=
+                                       HWC2::Composition::Client);
+  }
+
+  return backend_->ValidateDisplay(this, num_types, num_requests);
+}
+
+std::vector<HwcLayer *> HwcDisplay::GetOrderLayersByZPos() {
+  std::vector<HwcLayer *> ordered_layers;
+  ordered_layers.reserve(layers_.size());
+
+  for (auto &[handle, layer] : layers_) {
+    ordered_layers.emplace_back(&layer);
+  }
+
+  std::sort(std::begin(ordered_layers), std::end(ordered_layers),
+            [](const HwcLayer *lhs, const HwcLayer *rhs) {
+              return lhs->GetZOrder() < rhs->GetZOrder();
+            });
+
+  return ordered_layers;
+}
+
+HWC2::Error HwcDisplay::GetDisplayVsyncPeriod(
+    uint32_t *outVsyncPeriod /* ns */) {
+  return GetDisplayAttribute(configs_.active_config_id,
+                             HWC2_ATTRIBUTE_VSYNC_PERIOD,
+                             (int32_t *)(outVsyncPeriod));
+}
+
+#if PLATFORM_SDK_VERSION > 29
+HWC2::Error HwcDisplay::GetDisplayConnectionType(uint32_t *outType) {
+  if (IsInHeadlessMode()) {
+    *outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::Internal);
+    return HWC2::Error::None;
+  }
+  /* Primary display should be always internal,
+   * otherwise SF will be unhappy and will crash
+   */
+  if (GetPipe().connector->Get()->IsInternal() || handle_ == kPrimaryDisplay)
+    *outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::Internal);
+  else if (GetPipe().connector->Get()->IsExternal())
+    *outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::External);
+  else
+    return HWC2::Error::BadConfig;
+
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::SetActiveConfigWithConstraints(
+    hwc2_config_t config,
+    hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints,
+    hwc_vsync_period_change_timeline_t *outTimeline) {
+  if (vsyncPeriodChangeConstraints == nullptr || outTimeline == nullptr) {
+    return HWC2::Error::BadParameter;
+  }
+
+  uint32_t current_vsync_period{};
+  GetDisplayVsyncPeriod(&current_vsync_period);
+
+  if (vsyncPeriodChangeConstraints->seamlessRequired) {
+    return HWC2::Error::SeamlessNotAllowed;
+  }
+
+  outTimeline->refreshTimeNanos = vsyncPeriodChangeConstraints
+                                      ->desiredTimeNanos -
+                                  current_vsync_period;
+  auto ret = SetActiveConfigInternal(config, outTimeline->refreshTimeNanos);
+  if (ret != HWC2::Error::None) {
+    return ret;
+  }
+
+  outTimeline->refreshRequired = true;
+  outTimeline->newVsyncAppliedTimeNanos = vsyncPeriodChangeConstraints
+                                              ->desiredTimeNanos;
+
+  last_vsync_ts_ = 0;
+  vsync_tracking_en_ = true;
+  vsync_worker_.VSyncControl(true);
+
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::SetAutoLowLatencyMode(bool /*on*/) {
+  return HWC2::Error::Unsupported;
+}
+
+HWC2::Error HwcDisplay::GetSupportedContentTypes(
+    uint32_t *outNumSupportedContentTypes,
+    const uint32_t *outSupportedContentTypes) {
+  if (outSupportedContentTypes == nullptr)
+    *outNumSupportedContentTypes = 0;
+
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::SetContentType(int32_t contentType) {
+  if (contentType != HWC2_CONTENT_TYPE_NONE)
+    return HWC2::Error::Unsupported;
+
+  /* TODO: Map to the DRM Connector property:
+   * https://elixir.bootlin.com/linux/v5.4-rc5/source/drivers/gpu/drm/drm_connector.c#L809
+   */
+
+  return HWC2::Error::None;
+}
+#endif
+
+#if PLATFORM_SDK_VERSION > 28
+HWC2::Error HwcDisplay::GetDisplayIdentificationData(uint8_t *outPort,
+                                                     uint32_t *outDataSize,
+                                                     uint8_t *outData) {
+  if (IsInHeadlessMode()) {
+    return HWC2::Error::Unsupported;
+  }
+
+  auto blob = GetPipe().connector->Get()->GetEdidBlob();
+  if (!blob) {
+    return HWC2::Error::Unsupported;
+  }
+
+  *outPort = handle_; /* TDOD(nobody): What should be here? */
+
+  if (outData) {
+    *outDataSize = std::min(*outDataSize, blob->length);
+    memcpy(outData, blob->data, *outDataSize);
+  } else {
+    *outDataSize = blob->length;
+  }
+
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::GetDisplayCapabilities(uint32_t *outNumCapabilities,
+                                               uint32_t * /*outCapabilities*/) {
+  if (outNumCapabilities == nullptr) {
+    return HWC2::Error::BadParameter;
+  }
+
+  *outNumCapabilities = 0;
+
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::GetDisplayBrightnessSupport(bool *supported) {
+  *supported = false;
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::SetDisplayBrightness(float /* brightness */) {
+  return HWC2::Error::Unsupported;
+}
+
+#endif /* PLATFORM_SDK_VERSION > 28 */
+
+#if PLATFORM_SDK_VERSION > 27
+
+HWC2::Error HwcDisplay::GetRenderIntents(
+    int32_t mode, uint32_t *outNumIntents,
+    int32_t * /*android_render_intent_v1_1_t*/ outIntents) {
+  if (mode != HAL_COLOR_MODE_NATIVE) {
+    return HWC2::Error::BadParameter;
+  }
+
+  if (outIntents == nullptr) {
+    *outNumIntents = 1;
+    return HWC2::Error::None;
+  }
+  *outNumIntents = 1;
+  outIntents[0] = HAL_RENDER_INTENT_COLORIMETRIC;
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcDisplay::SetColorModeWithIntent(int32_t mode, int32_t intent) {
+  if (intent < HAL_RENDER_INTENT_COLORIMETRIC ||
+      intent > HAL_RENDER_INTENT_TONE_MAP_ENHANCE)
+    return HWC2::Error::BadParameter;
+
+  if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_BT2100_HLG)
+    return HWC2::Error::BadParameter;
+
+  if (mode != HAL_COLOR_MODE_NATIVE)
+    return HWC2::Error::Unsupported;
+
+  if (intent != HAL_RENDER_INTENT_COLORIMETRIC)
+    return HWC2::Error::Unsupported;
+
+  color_mode_ = mode;
+  return HWC2::Error::None;
+}
+
+#endif /* PLATFORM_SDK_VERSION > 27 */
+
+const Backend *HwcDisplay::backend() const {
+  return backend_.get();
+}
+
+void HwcDisplay::set_backend(std::unique_ptr<Backend> backend) {
+  backend_ = std::move(backend);
+}
+
+/* returns true if composition should be sent to client */
+bool HwcDisplay::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;
+  }
+
+  vsync_flattening_en_ = true;
+  vsync_worker_.VSyncControl(true);
+  flattenning_state_ = ClientFlattenningState::VsyncCountdownMax;
+  return false;
+}
+
+void HwcDisplay::ProcessFlatenningVsyncInternal() {
+  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_);
+    vsync_flattening_en_ = false;
+  }
+}
+
+}  // namespace android
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
new file mode 100644
index 0000000..d79efb0
--- /dev/null
+++ b/hwc2_device/HwcDisplay.h
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWC2_DEVICE_HWC_DISPLAY_H
+#define ANDROID_HWC2_DEVICE_HWC_DISPLAY_H
+
+#include <hardware/hwcomposer2.h>
+
+#include <optional>
+
+#include "HwcDisplayConfigs.h"
+#include "compositor/LayerData.h"
+#include "drm/DrmAtomicStateManager.h"
+#include "drm/ResourceManager.h"
+#include "drm/VSyncWorker.h"
+#include "hwc2_device/HwcLayer.h"
+
+namespace android {
+
+class Backend;
+class DrmHwcTwo;
+
+inline constexpr uint32_t kPrimaryDisplay = 0;
+
+class HwcDisplay {
+ public:
+  HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type, DrmHwcTwo *hwc2);
+  HwcDisplay(const HwcDisplay &) = delete;
+  ~HwcDisplay();
+
+  /* SetPipeline should be carefully used only by DrmHwcTwo hotplug handlers */
+  void SetPipeline(DrmDisplayPipeline *pipeline);
+
+  HWC2::Error CreateComposition(AtomicCommitArgs &a_args);
+  std::vector<HwcLayer *> GetOrderLayersByZPos();
+
+  void ClearDisplay();
+
+  std::string Dump();
+
+  // HWC Hooks
+  HWC2::Error AcceptDisplayChanges();
+  HWC2::Error CreateLayer(hwc2_layer_t *layer);
+  HWC2::Error DestroyLayer(hwc2_layer_t layer);
+  HWC2::Error GetActiveConfig(hwc2_config_t *config) const;
+  HWC2::Error GetChangedCompositionTypes(uint32_t *num_elements,
+                                         hwc2_layer_t *layers, int32_t *types);
+  HWC2::Error GetClientTargetSupport(uint32_t width, uint32_t height,
+                                     int32_t format, int32_t dataspace);
+  HWC2::Error GetColorModes(uint32_t *num_modes, int32_t *modes);
+  HWC2::Error GetDisplayAttribute(hwc2_config_t config, int32_t attribute,
+                                  int32_t *value);
+  HWC2::Error GetDisplayConfigs(uint32_t *num_configs, hwc2_config_t *configs);
+  HWC2::Error GetDisplayName(uint32_t *size, char *name);
+  HWC2::Error GetDisplayRequests(int32_t *display_requests,
+                                 uint32_t *num_elements, hwc2_layer_t *layers,
+                                 int32_t *layer_requests);
+  HWC2::Error GetDisplayType(int32_t *type);
+#if PLATFORM_SDK_VERSION > 27
+  HWC2::Error GetRenderIntents(int32_t mode, uint32_t *outNumIntents,
+                               int32_t *outIntents);
+  HWC2::Error SetColorModeWithIntent(int32_t mode, int32_t intent);
+#endif
+#if PLATFORM_SDK_VERSION > 28
+  HWC2::Error GetDisplayIdentificationData(uint8_t *outPort,
+                                           uint32_t *outDataSize,
+                                           uint8_t *outData);
+  HWC2::Error GetDisplayCapabilities(uint32_t *outNumCapabilities,
+                                     uint32_t *outCapabilities);
+  HWC2::Error GetDisplayBrightnessSupport(bool *supported);
+  HWC2::Error SetDisplayBrightness(float);
+#endif
+#if PLATFORM_SDK_VERSION > 29
+  HWC2::Error GetDisplayConnectionType(uint32_t *outType);
+
+  HWC2::Error SetActiveConfigWithConstraints(
+      hwc2_config_t config,
+      hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints,
+      hwc_vsync_period_change_timeline_t *outTimeline);
+  HWC2::Error SetAutoLowLatencyMode(bool on);
+  HWC2::Error GetSupportedContentTypes(
+      uint32_t *outNumSupportedContentTypes,
+      const uint32_t *outSupportedContentTypes);
+
+  HWC2::Error SetContentType(int32_t contentType);
+#endif
+  HWC2::Error GetDisplayVsyncPeriod(uint32_t *outVsyncPeriod);
+
+  HWC2::Error GetDozeSupport(int32_t *support);
+  HWC2::Error GetHdrCapabilities(uint32_t *num_types, int32_t *types,
+                                 float *max_luminance,
+                                 float *max_average_luminance,
+                                 float *min_luminance);
+  HWC2::Error GetReleaseFences(uint32_t *num_elements, hwc2_layer_t *layers,
+                               int32_t *fences);
+  HWC2::Error PresentDisplay(int32_t *out_present_fence);
+  HWC2::Error SetActiveConfig(hwc2_config_t config);
+  HWC2::Error ChosePreferredConfig();
+  HWC2::Error SetClientTarget(buffer_handle_t target, int32_t acquire_fence,
+                              int32_t dataspace, hwc_region_t damage);
+  HWC2::Error SetColorMode(int32_t mode);
+  HWC2::Error SetColorTransform(const float *matrix, int32_t hint);
+  HWC2::Error SetOutputBuffer(buffer_handle_t buffer, int32_t release_fence);
+  HWC2::Error SetPowerMode(int32_t mode);
+  HWC2::Error SetVsyncEnabled(int32_t enabled);
+  HWC2::Error ValidateDisplay(uint32_t *num_types, uint32_t *num_requests);
+  HwcLayer *get_layer(hwc2_layer_t layer) {
+    auto it = layers_.find(layer);
+    if (it == layers_.end())
+      return nullptr;
+    return &it->second;
+  }
+
+  /* Statistics */
+  struct Stats {
+    Stats minus(Stats b) const {
+      return {total_frames_ - b.total_frames_,
+              total_pixops_ - b.total_pixops_,
+              gpu_pixops_ - b.gpu_pixops_,
+              failed_kms_validate_ - b.failed_kms_validate_,
+              failed_kms_present_ - b.failed_kms_present_,
+              frames_flattened_ - b.frames_flattened_};
+    }
+
+    uint32_t total_frames_ = 0;
+    uint64_t total_pixops_ = 0;
+    uint64_t gpu_pixops_ = 0;
+    uint32_t failed_kms_validate_ = 0;
+    uint32_t failed_kms_present_ = 0;
+    uint32_t frames_flattened_ = 0;
+  };
+
+  const Backend *backend() const;
+  void set_backend(std::unique_ptr<Backend> backend);
+
+  auto GetHwc2() {
+    return hwc2_;
+  }
+
+  std::map<hwc2_layer_t, HwcLayer> &layers() {
+    return layers_;
+  }
+
+  auto &GetPipe() {
+    return *pipeline_;
+  }
+
+  android_color_transform_t &color_transform_hint() {
+    return color_transform_hint_;
+  }
+
+  Stats &total_stats() {
+    return total_stats_;
+  }
+
+  /* returns true if composition should be sent to client */
+  bool ProcessClientFlatteningState(bool skip);
+  void ProcessFlatenningVsyncInternal();
+
+  /* Headless mode required to keep SurfaceFlinger alive when all display are
+   * disconnected, Without headless mode Android will continuously crash.
+   * Only single internal (primary) display is required to be in HEADLESS mode
+   * to prevent the crash. See:
+   * https://source.android.com/devices/graphics/hotplug#handling-common-scenarios
+   */
+  bool IsInHeadlessMode() {
+    return !pipeline_;
+  }
+
+  void Deinit();
+
+ 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};
+
+  constexpr static size_t MATRIX_SIZE = 16;
+
+  HwcDisplayConfigs configs_;
+
+  DrmHwcTwo *const hwc2_;
+
+  UniqueFd present_fence_;
+
+  std::optional<DrmMode> staged_mode_;
+  int64_t staged_mode_change_time_{};
+  uint32_t staged_mode_config_id_{};
+
+  DrmDisplayPipeline *pipeline_{};
+
+  std::unique_ptr<Backend> backend_;
+
+  VSyncWorker vsync_worker_;
+  bool vsync_event_en_{};
+  bool vsync_flattening_en_{};
+  bool vsync_tracking_en_{};
+  int64_t last_vsync_ts_{};
+
+  const hwc2_display_t handle_;
+  HWC2::DisplayType type_;
+
+  uint32_t layer_idx_{};
+
+  std::map<hwc2_layer_t, HwcLayer> layers_;
+  HwcLayer client_layer_;
+  int32_t color_mode_{};
+  std::array<float, MATRIX_SIZE> color_transform_matrix_{};
+  android_color_transform_t color_transform_hint_;
+
+  std::shared_ptr<DrmKmsPlan> current_plan_;
+
+  uint32_t frame_no_ = 0;
+  Stats total_stats_;
+  Stats prev_stats_;
+  std::string DumpDelta(HwcDisplay::Stats delta);
+
+  HWC2::Error Init();
+
+  HWC2::Error SetActiveConfigInternal(uint32_t config, int64_t change_time);
+};
+
+}  // namespace android
+
+#endif
diff --git a/hwc2_device/HwcDisplayConfigs.cpp b/hwc2_device/HwcDisplayConfigs.cpp
new file mode 100644
index 0000000..6a3ed5a
--- /dev/null
+++ b/hwc2_device/HwcDisplayConfigs.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "hwc-display-configs"
+
+#include "HwcDisplayConfigs.h"
+
+#include <cmath>
+
+#include "drm/DrmConnector.h"
+#include "utils/log.h"
+
+constexpr uint32_t kHeadlessModeDisplayWidthMm = 163;
+constexpr uint32_t kHeadlessModeDisplayHeightMm = 122;
+constexpr uint32_t kHeadlessModeDisplayWidthPx = 1024;
+constexpr uint32_t kHeadlessModeDisplayHeightPx = 768;
+constexpr uint32_t kHeadlessModeDisplayVRefresh = 60;
+
+namespace android {
+
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+uint32_t HwcDisplayConfigs::last_config_id = 1;
+
+void HwcDisplayConfigs::FillHeadless() {
+  hwc_configs.clear();
+
+  last_config_id++;
+  preferred_config_id = active_config_id = last_config_id;
+  auto headless_drm_mode_info = (drmModeModeInfo){
+      .hdisplay = kHeadlessModeDisplayWidthPx,
+      .vdisplay = kHeadlessModeDisplayHeightPx,
+      .vrefresh = kHeadlessModeDisplayVRefresh,
+      .name = "HEADLESS-MODE",
+  };
+  hwc_configs[active_config_id] = (HwcDisplayConfig){
+      .id = active_config_id,
+      .group_id = 1,
+      .mode = DrmMode(&headless_drm_mode_info),
+  };
+
+  mm_width = kHeadlessModeDisplayWidthMm;
+  mm_height = kHeadlessModeDisplayHeightMm;
+}
+
+// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
+HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
+  /* In case UpdateModes will fail we will still have one mode for headless
+   * mode*/
+  FillHeadless();
+  /* Read real configs */
+  int ret = connector.UpdateModes();
+  if (ret != 0) {
+    ALOGE("Failed to update display modes %d", ret);
+    return HWC2::Error::BadDisplay;
+  }
+
+  if (connector.GetModes().empty()) {
+    ALOGE("No modes reported by KMS");
+    return HWC2::Error::BadDisplay;
+  }
+
+  hwc_configs.clear();
+  mm_width = connector.GetMmWidth();
+  mm_height = connector.GetMmHeight();
+
+  preferred_config_id = 0;
+  uint32_t preferred_config_group_id = 0;
+
+  uint32_t first_config_id = last_config_id;
+  uint32_t last_group_id = 1;
+
+  /* Group modes */
+  for (const auto &mode : connector.GetModes()) {
+    /* Find group for the new mode or create new group */
+    uint32_t group_found = 0;
+    for (auto &hwc_config : hwc_configs) {
+      if (mode.h_display() == hwc_config.second.mode.h_display() &&
+          mode.v_display() == hwc_config.second.mode.v_display()) {
+        group_found = hwc_config.second.group_id;
+      }
+    }
+    if (group_found == 0) {
+      group_found = last_group_id++;
+    }
+
+    bool disabled = false;
+    if ((mode.flags() & DRM_MODE_FLAG_3D_MASK) != 0) {
+      ALOGI("Disabling display mode %s (Modes with 3D flag aren't supported)",
+            mode.name().c_str());
+      disabled = true;
+    }
+
+    /* Add config */
+    hwc_configs[last_config_id] = {
+        .id = last_config_id,
+        .group_id = group_found,
+        .mode = mode,
+        .disabled = disabled,
+    };
+
+    /* Chwck if the mode is preferred */
+    if ((mode.type() & DRM_MODE_TYPE_PREFERRED) != 0 &&
+        preferred_config_id == 0) {
+      preferred_config_id = last_config_id;
+      preferred_config_group_id = group_found;
+    }
+
+    last_config_id++;
+  }
+
+  /* We must have preferred mode. Set first mode as preferred
+   * in case KMS haven't reported anything. */
+  if (preferred_config_id == 0) {
+    preferred_config_id = first_config_id;
+    preferred_config_group_id = 1;
+  }
+
+  for (uint32_t group = 1; group < last_group_id; group++) {
+    bool has_interlaced = false;
+    bool has_progressive = false;
+    for (auto &hwc_config : hwc_configs) {
+      if (hwc_config.second.group_id != group || hwc_config.second.disabled) {
+        continue;
+      }
+
+      if (hwc_config.second.IsInterlaced()) {
+        has_interlaced = true;
+      } else {
+        has_progressive = true;
+      }
+    }
+
+    bool has_both = has_interlaced && has_progressive;
+    if (!has_both) {
+      continue;
+    }
+
+    bool group_contains_preferred_interlaced = false;
+    if (group == preferred_config_group_id &&
+        hwc_configs[preferred_config_id].IsInterlaced()) {
+      group_contains_preferred_interlaced = true;
+    }
+
+    for (auto &hwc_config : hwc_configs) {
+      if (hwc_config.second.group_id != group || hwc_config.second.disabled) {
+        continue;
+      }
+
+      bool disable = group_contains_preferred_interlaced
+                         ? !hwc_config.second.IsInterlaced()
+                         : hwc_config.second.IsInterlaced();
+
+      if (disable) {
+        ALOGI(
+            "Group %i: Disabling display mode %s (This group should consist "
+            "of %s modes)",
+            group, hwc_config.second.mode.name().c_str(),
+            group_contains_preferred_interlaced ? "interlaced" : "progressive");
+
+        hwc_config.second.disabled = true;
+      }
+    }
+  }
+
+  /* Group should not contain 2 modes with FPS delta less than ~1HZ
+   * otherwise android.graphics.cts.SetFrameRateTest CTS will fail
+   */
+  constexpr float kMinFpsDelta = 1.0;  // FPS
+  for (uint32_t m1 = first_config_id; m1 < last_config_id; m1++) {
+    for (uint32_t m2 = first_config_id; m2 < last_config_id; m2++) {
+      if (m1 != m2 && hwc_configs[m1].group_id == hwc_configs[m2].group_id &&
+          !hwc_configs[m1].disabled && !hwc_configs[m2].disabled &&
+          fabsf(hwc_configs[m1].mode.v_refresh() -
+                hwc_configs[m2].mode.v_refresh()) < kMinFpsDelta) {
+        ALOGI(
+            "Group %i: Disabling display mode %s (Refresh rate value is "
+            "too close to existing mode %s)",
+            hwc_configs[m2].group_id, hwc_configs[m2].mode.name().c_str(),
+            hwc_configs[m1].mode.name().c_str());
+
+        hwc_configs[m2].disabled = true;
+      }
+    }
+  }
+
+  return HWC2::Error::None;
+}
+
+}  // namespace android
diff --git a/hwc2_device/HwcDisplayConfigs.h b/hwc2_device/HwcDisplayConfigs.h
new file mode 100644
index 0000000..7c173d6
--- /dev/null
+++ b/hwc2_device/HwcDisplayConfigs.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWC2_DEVICE_HWC_DISPLAY_CONFIGS_H
+#define ANDROID_HWC2_DEVICE_HWC_DISPLAY_CONFIGS_H
+
+#include <hardware/hwcomposer2.h>
+
+#include <map>
+
+#include "drm/DrmMode.h"
+
+namespace android {
+
+class DrmConnector;
+
+struct HwcDisplayConfig {
+  uint32_t id{};
+  uint32_t group_id{};
+  DrmMode mode;
+  bool disabled{};
+
+  bool IsInterlaced() const {
+    return (mode.flags() & DRM_MODE_FLAG_INTERLACE) != 0;
+  }
+};
+
+struct HwcDisplayConfigs {
+  HWC2::Error Update(DrmConnector &conn);
+  void FillHeadless();
+
+  std::map<uint32_t /*config_id*/, struct HwcDisplayConfig> hwc_configs;
+
+  uint32_t active_config_id = 0;
+  uint32_t preferred_config_id = 0;
+
+  // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+  static uint32_t last_config_id;
+
+  uint32_t mm_width = 0;
+  uint32_t mm_height = 0;
+};
+
+}  // namespace android
+
+#endif
diff --git a/hwc2_device/HwcLayer.cpp b/hwc2_device/HwcLayer.cpp
new file mode 100644
index 0000000..c278732
--- /dev/null
+++ b/hwc2_device/HwcLayer.cpp
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "hwc-layer"
+
+#include "HwcLayer.h"
+
+#include "HwcDisplay.h"
+#include "bufferinfo/BufferInfoGetter.h"
+#include "utils/log.h"
+
+namespace android {
+
+// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
+HWC2::Error HwcLayer::SetCursorPosition(int32_t /*x*/, int32_t /*y*/) {
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcLayer::SetLayerBlendMode(int32_t mode) {
+  switch (static_cast<HWC2::BlendMode>(mode)) {
+    case HWC2::BlendMode::None:
+      blend_mode_ = BufferBlendMode::kNone;
+      break;
+    case HWC2::BlendMode::Premultiplied:
+      blend_mode_ = BufferBlendMode::kPreMult;
+      break;
+    case HWC2::BlendMode::Coverage:
+      blend_mode_ = BufferBlendMode::kCoverage;
+      break;
+    default:
+      ALOGE("Unknown blending mode b=%d", blend_mode_);
+      blend_mode_ = BufferBlendMode::kUndefined;
+      break;
+  }
+  return HWC2::Error::None;
+}
+
+/* Find API details at:
+ * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=2314
+ */
+HWC2::Error HwcLayer::SetLayerBuffer(buffer_handle_t buffer,
+                                     int32_t acquire_fence) {
+  acquire_fence_ = UniqueFd(acquire_fence);
+  buffer_handle_ = buffer;
+  buffer_handle_updated_ = true;
+
+  return HWC2::Error::None;
+}
+
+// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
+HWC2::Error HwcLayer::SetLayerColor(hwc_color_t /*color*/) {
+  // TODO(nobody): Put to client composition here?
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcLayer::SetLayerCompositionType(int32_t type) {
+  sf_type_ = static_cast<HWC2::Composition>(type);
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcLayer::SetLayerDataspace(int32_t dataspace) {
+  switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
+    case HAL_DATASPACE_STANDARD_BT709:
+      color_space_ = BufferColorSpace::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_ = BufferColorSpace::kItuRec601;
+      break;
+    case HAL_DATASPACE_STANDARD_BT2020:
+    case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
+      color_space_ = BufferColorSpace::kItuRec2020;
+      break;
+    default:
+      color_space_ = BufferColorSpace::kUndefined;
+  }
+
+  switch (dataspace & HAL_DATASPACE_RANGE_MASK) {
+    case HAL_DATASPACE_RANGE_FULL:
+      sample_range_ = BufferSampleRange::kFullRange;
+      break;
+    case HAL_DATASPACE_RANGE_LIMITED:
+      sample_range_ = BufferSampleRange::kLimitedRange;
+      break;
+    default:
+      sample_range_ = BufferSampleRange::kUndefined;
+  }
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcLayer::SetLayerDisplayFrame(hwc_rect_t frame) {
+  layer_data_.pi.display_frame = frame;
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcLayer::SetLayerPlaneAlpha(float alpha) {
+  layer_data_.pi.alpha = std::lround(alpha * UINT16_MAX);
+  return HWC2::Error::None;
+}
+
+// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
+HWC2::Error HwcLayer::SetLayerSidebandStream(
+    const native_handle_t* /*stream*/) {
+  // TODO(nobody): We don't support sideband
+  return HWC2::Error::Unsupported;
+}
+
+HWC2::Error HwcLayer::SetLayerSourceCrop(hwc_frect_t crop) {
+  layer_data_.pi.source_crop = crop;
+  return HWC2::Error::None;
+}
+
+// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
+HWC2::Error HwcLayer::SetLayerSurfaceDamage(hwc_region_t /*damage*/) {
+  // TODO(nobody): We don't use surface damage, marking as unsupported
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcLayer::SetLayerTransform(int32_t 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 = LayerTransform::kRotate270;
+  } else if (transform == HWC_TRANSFORM_ROT_180) {
+    l_transform = LayerTransform::kRotate180;
+  } else {
+    if ((transform & HWC_TRANSFORM_FLIP_H) != 0)
+      l_transform |= LayerTransform::kFlipH;
+    if ((transform & HWC_TRANSFORM_FLIP_V) != 0)
+      l_transform |= LayerTransform::kFlipV;
+    if ((transform & HWC_TRANSFORM_ROT_90) != 0)
+      l_transform |= LayerTransform::kRotate90;
+  }
+
+  layer_data_.pi.transform = static_cast<LayerTransform>(l_transform);
+  return HWC2::Error::None;
+}
+
+// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
+HWC2::Error HwcLayer::SetLayerVisibleRegion(hwc_region_t /*visible*/) {
+  // TODO(nobody): We don't use this information, marking as unsupported
+  return HWC2::Error::None;
+}
+
+HWC2::Error HwcLayer::SetLayerZOrder(uint32_t order) {
+  z_order_ = order;
+  return HWC2::Error::None;
+}
+
+void HwcLayer::ImportFb() {
+  if (!IsLayerUsableAsDevice() || !buffer_handle_updated_) {
+    return;
+  }
+  buffer_handle_updated_ = false;
+
+  layer_data_.fb = {};
+
+  auto unique_id = BufferInfoGetter::GetInstance()->GetUniqueId(buffer_handle_);
+  if (unique_id && SwChainGetBufferFromCache(*unique_id)) {
+    return;
+  }
+
+  layer_data_.bi = BufferInfoGetter::GetInstance()->GetBoInfo(buffer_handle_);
+  if (!layer_data_.bi) {
+    ALOGW("Unable to get buffer information (0x%p)", buffer_handle_);
+    bi_get_failed_ = true;
+    return;
+  }
+
+  layer_data_
+      .fb = parent_->GetPipe().device->GetDrmFbImporter().GetOrCreateFbId(
+      &layer_data_.bi.value());
+
+  if (!layer_data_.fb) {
+    ALOGV("Unable to create framebuffer object for buffer 0x%p",
+          buffer_handle_);
+    fb_import_failed_ = true;
+    return;
+  }
+
+  if (unique_id) {
+    SwChainAddCurrentBuffer(*unique_id);
+  }
+}
+
+void HwcLayer::PopulateLayerData(bool test) {
+  ImportFb();
+
+  if (blend_mode_ != BufferBlendMode::kUndefined) {
+    layer_data_.bi->blend_mode = blend_mode_;
+  }
+  if (color_space_ != BufferColorSpace::kUndefined) {
+    layer_data_.bi->color_space = color_space_;
+  }
+  if (sample_range_ != BufferSampleRange::kUndefined) {
+    layer_data_.bi->sample_range = sample_range_;
+  }
+
+  if (!test) {
+    layer_data_.acquire_fence = std::move(acquire_fence_);
+  }
+}
+
+/* SwapChain Cache */
+
+bool HwcLayer::SwChainGetBufferFromCache(BufferUniqueId unique_id) {
+  if (swchain_lookup_table_.count(unique_id) == 0) {
+    return false;
+  }
+
+  int seq = swchain_lookup_table_[unique_id];
+
+  if (swchain_cache_.count(seq) == 0) {
+    return false;
+  }
+
+  auto& el = swchain_cache_[seq];
+  if (!el.bi) {
+    return false;
+  }
+
+  layer_data_.bi = el.bi;
+  layer_data_.fb = el.fb;
+
+  return true;
+}
+
+void HwcLayer::SwChainReassemble(BufferUniqueId unique_id) {
+  if (swchain_lookup_table_.count(unique_id) != 0) {
+    if (swchain_lookup_table_[unique_id] ==
+        int(swchain_lookup_table_.size()) - 1) {
+      /* Skip same buffer */
+      return;
+    }
+    if (swchain_lookup_table_[unique_id] == 0) {
+      swchain_reassembled_ = true;
+      return;
+    }
+    /* Tracking error */
+    SwChainClearCache();
+    return;
+  }
+
+  swchain_lookup_table_[unique_id] = int(swchain_lookup_table_.size());
+}
+
+void HwcLayer::SwChainAddCurrentBuffer(BufferUniqueId unique_id) {
+  if (!swchain_reassembled_) {
+    SwChainReassemble(unique_id);
+  }
+
+  if (swchain_reassembled_) {
+    if (swchain_lookup_table_.count(unique_id) == 0) {
+      SwChainClearCache();
+      return;
+    }
+
+    int seq = swchain_lookup_table_[unique_id];
+
+    if (swchain_cache_.count(seq) == 0) {
+      swchain_cache_[seq] = {};
+    }
+
+    swchain_cache_[seq].bi = layer_data_.bi;
+    swchain_cache_[seq].fb = layer_data_.fb;
+  }
+}
+
+void HwcLayer::SwChainClearCache() {
+  swchain_cache_.clear();
+  swchain_lookup_table_.clear();
+  swchain_reassembled_ = false;
+}
+
+}  // namespace android
\ No newline at end of file
diff --git a/hwc2_device/HwcLayer.h b/hwc2_device/HwcLayer.h
new file mode 100644
index 0000000..41b3dbb
--- /dev/null
+++ b/hwc2_device/HwcLayer.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWC2_DEVICE_HWC_LAYER_H
+#define ANDROID_HWC2_DEVICE_HWC_LAYER_H
+
+#include <hardware/hwcomposer2.h>
+
+#include "bufferinfo/BufferInfoGetter.h"
+#include "compositor/LayerData.h"
+
+namespace android {
+
+class HwcDisplay;
+
+class HwcLayer {
+ public:
+  explicit HwcLayer(HwcDisplay *parent_display) : parent_(parent_display){};
+
+  HWC2::Composition GetSfType() const {
+    return sf_type_;
+  }
+  HWC2::Composition GetValidatedType() const {
+    return validated_type_;
+  }
+  void AcceptTypeChange() {
+    sf_type_ = validated_type_;
+  }
+  void SetValidatedType(HWC2::Composition type) {
+    validated_type_ = type;
+  }
+  bool IsTypeChanged() const {
+    return sf_type_ != validated_type_;
+  }
+
+  bool GetPriorBufferScanOutFlag() const {
+    return prior_buffer_scanout_flag_;
+  }
+
+  void SetPriorBufferScanOutFlag(bool state) {
+    prior_buffer_scanout_flag_ = state;
+  }
+
+  uint32_t GetZOrder() const {
+    return z_order_;
+  }
+
+  auto &GetLayerData() {
+    return layer_data_;
+  }
+
+  // Layer hooks
+  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 SetLayerCompositionType(int32_t type);
+  HWC2::Error SetLayerDataspace(int32_t dataspace);
+  HWC2::Error SetLayerDisplayFrame(hwc_rect_t frame);
+  HWC2::Error SetLayerPlaneAlpha(float alpha);
+  HWC2::Error SetLayerSidebandStream(const native_handle_t *stream);
+  HWC2::Error SetLayerSourceCrop(hwc_frect_t crop);
+  HWC2::Error SetLayerSurfaceDamage(hwc_region_t damage);
+  HWC2::Error SetLayerTransform(int32_t transform);
+  HWC2::Error SetLayerVisibleRegion(hwc_region_t visible);
+  HWC2::Error SetLayerZOrder(uint32_t order);
+
+ private:
+  // sf_type_ stores the initial type given to us by surfaceflinger,
+  // validated_type_ stores the type after running ValidateDisplay
+  HWC2::Composition sf_type_ = HWC2::Composition::Invalid;
+  HWC2::Composition validated_type_ = HWC2::Composition::Invalid;
+
+  uint32_t z_order_ = 0;
+  LayerData layer_data_;
+
+  /* Should be populated to layer_data_.acquire_fence only before presenting */
+  UniqueFd acquire_fence_;
+
+  /* The following buffer data can have 2 sources:
+   * 1 - Mapper@4 metadata API
+   * 2 - HWC@2 API
+   * We keep ability to have 2 sources in drm_hwc. It may be useful for CLIENT
+   * layer, at this moment HWC@2 API can't specify blending mode for this layer,
+   * but Mapper@4 can do that
+   */
+  BufferColorSpace color_space_{};
+  BufferSampleRange sample_range_{};
+  BufferBlendMode blend_mode_{};
+  buffer_handle_t buffer_handle_{};
+  bool buffer_handle_updated_{};
+
+  bool prior_buffer_scanout_flag_{};
+
+  HwcDisplay *const parent_;
+
+  /* Layer state */
+ public:
+  void PopulateLayerData(bool test);
+
+  bool IsLayerUsableAsDevice() const {
+    return !bi_get_failed_ && !fb_import_failed_ && buffer_handle_ != nullptr;
+  }
+
+ private:
+  void ImportFb();
+  bool bi_get_failed_{};
+  bool fb_import_failed_{};
+
+  /* SwapChain Cache */
+ public:
+  void SwChainClearCache();
+
+ private:
+  struct SwapChainElement {
+    std::optional<BufferInfo> bi;
+    std::shared_ptr<DrmFbIdHandle> fb;
+  };
+
+  bool SwChainGetBufferFromCache(BufferUniqueId unique_id);
+  void SwChainReassemble(BufferUniqueId unique_id);
+  void SwChainAddCurrentBuffer(BufferUniqueId unique_id);
+
+  std::map<int /*seq_no*/, SwapChainElement> swchain_cache_;
+  std::map<BufferUniqueId, int /*seq_no*/> swchain_lookup_table_;
+  bool swchain_reassembled_{};
+};
+
+}  // namespace android
+
+#endif
diff --git a/hwc2_device/hwc2_device.cpp b/hwc2_device/hwc2_device.cpp
new file mode 100644
index 0000000..a6dedb4
--- /dev/null
+++ b/hwc2_device/hwc2_device.cpp
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
+// #define LOG_NDEBUG 0 // Uncomment to see HWC2 API calls in logcat
+
+#define LOG_TAG "hwc2-device"
+
+#include <cinttypes>
+
+#include "DrmHwcTwo.h"
+#include "backend/Backend.h"
+#include "utils/log.h"
+
+namespace android {
+
+/* Converts long __PRETTY_FUNCTION__ result, e.g.:
+ * "int32_t android::LayerHook(hwc2_device_t *, hwc2_display_t, hwc2_layer_t,"
+ * "Args...) [HookType = HWC2::Error (android::HwcLayer::*)(const native_handle"
+ * "*,int), func = &android::HwcLayer::SetLayerBuffer, Args = <const
+ * "native_handle, int>"
+ * to the short "android::HwcLayer::SetLayerBuffer" for better logs readability
+ */
+static std::string GetFuncName(const char *pretty_function) {
+  std::string str(pretty_function);
+  const char *start = "func = &";
+  size_t p1 = str.find(start);
+  p1 += strlen(start);
+  size_t p2 = str.find(',', p1);
+  return str.substr(p1, p2 - p1);
+}
+
+struct Drmhwc2Device : hwc2_device {
+  DrmHwcTwo drmhwctwo;
+};
+
+static DrmHwcTwo *ToDrmHwcTwo(hwc2_device_t *dev) {
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast):
+  return &static_cast<Drmhwc2Device *>(dev)->drmhwctwo;
+}
+
+template <typename PFN, typename T>
+static hwc2_function_pointer_t ToHook(T function) {
+  static_assert(std::is_same<PFN, T>::value, "Incompatible fn pointer");
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast):
+  return reinterpret_cast<hwc2_function_pointer_t>(function);
+}
+
+template <typename T, typename HookType, HookType func, typename... Args>
+static T DeviceHook(hwc2_device_t *dev, Args... args) {
+  ALOGV("Device hook: %s", GetFuncName(__PRETTY_FUNCTION__).c_str());
+  DrmHwcTwo *hwc = ToDrmHwcTwo(dev);
+  const std::lock_guard<std::mutex> lock(hwc->GetResMan().GetMainLock());
+  return static_cast<T>(((*hwc).*func)(std::forward<Args>(args)...));
+}
+
+template <typename HookType, HookType func, typename... Args>
+static int32_t DisplayHook(hwc2_device_t *dev, hwc2_display_t display_handle,
+                           Args... args) {
+  ALOGV("Display #%" PRIu64 " hook: %s", display_handle,
+        GetFuncName(__PRETTY_FUNCTION__).c_str());
+  DrmHwcTwo *hwc = ToDrmHwcTwo(dev);
+  const std::lock_guard<std::mutex> lock(hwc->GetResMan().GetMainLock());
+  auto *display = hwc->GetDisplay(display_handle);
+  if (display == nullptr)
+    return static_cast<int32_t>(HWC2::Error::BadDisplay);
+
+  return static_cast<int32_t>((display->*func)(std::forward<Args>(args)...));
+}
+
+template <typename HookType, HookType func, typename... Args>
+static int32_t LayerHook(hwc2_device_t *dev, hwc2_display_t display_handle,
+                         hwc2_layer_t layer_handle, Args... args) {
+  ALOGV("Display #%" PRIu64 " Layer: #%" PRIu64 " hook: %s", display_handle,
+        layer_handle, GetFuncName(__PRETTY_FUNCTION__).c_str());
+  DrmHwcTwo *hwc = ToDrmHwcTwo(dev);
+  const std::lock_guard<std::mutex> lock(hwc->GetResMan().GetMainLock());
+  auto *display = hwc->GetDisplay(display_handle);
+  if (display == nullptr)
+    return static_cast<int32_t>(HWC2::Error::BadDisplay);
+
+  HwcLayer *layer = display->get_layer(layer_handle);
+  if (!layer)
+    return static_cast<int32_t>(HWC2::Error::BadLayer);
+
+  return static_cast<int32_t>((layer->*func)(std::forward<Args>(args)...));
+}
+
+static int HookDevClose(hw_device_t *dev) {
+  // NOLINTNEXTLINE (cppcoreguidelines-pro-type-reinterpret-cast): Safe
+  auto *hwc2_dev = reinterpret_cast<hwc2_device_t *>(dev);
+  std::unique_ptr<DrmHwcTwo> ctx(ToDrmHwcTwo(hwc2_dev));
+  return 0;
+}
+
+static void HookDevGetCapabilities(hwc2_device_t * /*dev*/, uint32_t *out_count,
+                                   int32_t * /*out_capabilities*/) {
+  *out_count = 0;
+}
+
+static hwc2_function_pointer_t HookDevGetFunction(struct hwc2_device * /*dev*/,
+                                                  int32_t descriptor) {
+  auto func = static_cast<HWC2::FunctionDescriptor>(descriptor);
+  switch (func) {
+    // Device functions
+    case HWC2::FunctionDescriptor::CreateVirtualDisplay:
+      return ToHook<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>(
+          DeviceHook<int32_t, decltype(&DrmHwcTwo::CreateVirtualDisplay),
+                     &DrmHwcTwo::CreateVirtualDisplay, uint32_t, uint32_t,
+                     int32_t *, hwc2_display_t *>);
+    case HWC2::FunctionDescriptor::DestroyVirtualDisplay:
+      return ToHook<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>(
+          DeviceHook<int32_t, decltype(&DrmHwcTwo::DestroyVirtualDisplay),
+                     &DrmHwcTwo::DestroyVirtualDisplay, hwc2_display_t>);
+    case HWC2::FunctionDescriptor::Dump:
+      return ToHook<HWC2_PFN_DUMP>(
+          DeviceHook<void, decltype(&DrmHwcTwo::Dump), &DrmHwcTwo::Dump,
+                     uint32_t *, char *>);
+    case HWC2::FunctionDescriptor::GetMaxVirtualDisplayCount:
+      return ToHook<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>(
+          DeviceHook<uint32_t, decltype(&DrmHwcTwo::GetMaxVirtualDisplayCount),
+                     &DrmHwcTwo::GetMaxVirtualDisplayCount>);
+    case HWC2::FunctionDescriptor::RegisterCallback:
+      return ToHook<HWC2_PFN_REGISTER_CALLBACK>(
+          DeviceHook<int32_t, decltype(&DrmHwcTwo::RegisterCallback),
+                     &DrmHwcTwo::RegisterCallback, int32_t,
+                     hwc2_callback_data_t, hwc2_function_pointer_t>);
+
+    // Display functions
+    case HWC2::FunctionDescriptor::AcceptDisplayChanges:
+      return ToHook<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>(
+          DisplayHook<decltype(&HwcDisplay::AcceptDisplayChanges),
+                      &HwcDisplay::AcceptDisplayChanges>);
+    case HWC2::FunctionDescriptor::CreateLayer:
+      return ToHook<HWC2_PFN_CREATE_LAYER>(
+          DisplayHook<decltype(&HwcDisplay::CreateLayer),
+                      &HwcDisplay::CreateLayer, hwc2_layer_t *>);
+    case HWC2::FunctionDescriptor::DestroyLayer:
+      return ToHook<HWC2_PFN_DESTROY_LAYER>(
+          DisplayHook<decltype(&HwcDisplay::DestroyLayer),
+                      &HwcDisplay::DestroyLayer, hwc2_layer_t>);
+    case HWC2::FunctionDescriptor::GetActiveConfig:
+      return ToHook<HWC2_PFN_GET_ACTIVE_CONFIG>(
+          DisplayHook<decltype(&HwcDisplay::GetActiveConfig),
+                      &HwcDisplay::GetActiveConfig, hwc2_config_t *>);
+    case HWC2::FunctionDescriptor::GetChangedCompositionTypes:
+      return ToHook<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>(
+          DisplayHook<decltype(&HwcDisplay::GetChangedCompositionTypes),
+                      &HwcDisplay::GetChangedCompositionTypes, uint32_t *,
+                      hwc2_layer_t *, int32_t *>);
+    case HWC2::FunctionDescriptor::GetClientTargetSupport:
+      return ToHook<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(
+          DisplayHook<decltype(&HwcDisplay::GetClientTargetSupport),
+                      &HwcDisplay::GetClientTargetSupport, uint32_t, uint32_t,
+                      int32_t, int32_t>);
+    case HWC2::FunctionDescriptor::GetColorModes:
+      return ToHook<HWC2_PFN_GET_COLOR_MODES>(
+          DisplayHook<decltype(&HwcDisplay::GetColorModes),
+                      &HwcDisplay::GetColorModes, uint32_t *, int32_t *>);
+    case HWC2::FunctionDescriptor::GetDisplayAttribute:
+      return ToHook<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(
+          DisplayHook<decltype(&HwcDisplay::GetDisplayAttribute),
+                      &HwcDisplay::GetDisplayAttribute, hwc2_config_t, int32_t,
+                      int32_t *>);
+    case HWC2::FunctionDescriptor::GetDisplayConfigs:
+      return ToHook<HWC2_PFN_GET_DISPLAY_CONFIGS>(
+          DisplayHook<decltype(&HwcDisplay::GetDisplayConfigs),
+                      &HwcDisplay::GetDisplayConfigs, uint32_t *,
+                      hwc2_config_t *>);
+    case HWC2::FunctionDescriptor::GetDisplayName:
+      return ToHook<HWC2_PFN_GET_DISPLAY_NAME>(
+          DisplayHook<decltype(&HwcDisplay::GetDisplayName),
+                      &HwcDisplay::GetDisplayName, uint32_t *, char *>);
+    case HWC2::FunctionDescriptor::GetDisplayRequests:
+      return ToHook<HWC2_PFN_GET_DISPLAY_REQUESTS>(
+          DisplayHook<decltype(&HwcDisplay::GetDisplayRequests),
+                      &HwcDisplay::GetDisplayRequests, int32_t *, uint32_t *,
+                      hwc2_layer_t *, int32_t *>);
+    case HWC2::FunctionDescriptor::GetDisplayType:
+      return ToHook<HWC2_PFN_GET_DISPLAY_TYPE>(
+          DisplayHook<decltype(&HwcDisplay::GetDisplayType),
+                      &HwcDisplay::GetDisplayType, int32_t *>);
+    case HWC2::FunctionDescriptor::GetDozeSupport:
+      return ToHook<HWC2_PFN_GET_DOZE_SUPPORT>(
+          DisplayHook<decltype(&HwcDisplay::GetDozeSupport),
+                      &HwcDisplay::GetDozeSupport, int32_t *>);
+    case HWC2::FunctionDescriptor::GetHdrCapabilities:
+      return ToHook<HWC2_PFN_GET_HDR_CAPABILITIES>(
+          DisplayHook<decltype(&HwcDisplay::GetHdrCapabilities),
+                      &HwcDisplay::GetHdrCapabilities, uint32_t *, int32_t *,
+                      float *, float *, float *>);
+    case HWC2::FunctionDescriptor::GetReleaseFences:
+      return ToHook<HWC2_PFN_GET_RELEASE_FENCES>(
+          DisplayHook<decltype(&HwcDisplay::GetReleaseFences),
+                      &HwcDisplay::GetReleaseFences, uint32_t *, hwc2_layer_t *,
+                      int32_t *>);
+    case HWC2::FunctionDescriptor::PresentDisplay:
+      return ToHook<HWC2_PFN_PRESENT_DISPLAY>(
+          DisplayHook<decltype(&HwcDisplay::PresentDisplay),
+                      &HwcDisplay::PresentDisplay, int32_t *>);
+    case HWC2::FunctionDescriptor::SetActiveConfig:
+      return ToHook<HWC2_PFN_SET_ACTIVE_CONFIG>(
+          DisplayHook<decltype(&HwcDisplay::SetActiveConfig),
+                      &HwcDisplay::SetActiveConfig, hwc2_config_t>);
+    case HWC2::FunctionDescriptor::SetClientTarget:
+      return ToHook<HWC2_PFN_SET_CLIENT_TARGET>(
+          DisplayHook<decltype(&HwcDisplay::SetClientTarget),
+                      &HwcDisplay::SetClientTarget, buffer_handle_t, int32_t,
+                      int32_t, hwc_region_t>);
+    case HWC2::FunctionDescriptor::SetColorMode:
+      return ToHook<HWC2_PFN_SET_COLOR_MODE>(
+          DisplayHook<decltype(&HwcDisplay::SetColorMode),
+                      &HwcDisplay::SetColorMode, int32_t>);
+    case HWC2::FunctionDescriptor::SetColorTransform:
+      return ToHook<HWC2_PFN_SET_COLOR_TRANSFORM>(
+          DisplayHook<decltype(&HwcDisplay::SetColorTransform),
+                      &HwcDisplay::SetColorTransform, const float *, int32_t>);
+    case HWC2::FunctionDescriptor::SetOutputBuffer:
+      return ToHook<HWC2_PFN_SET_OUTPUT_BUFFER>(
+          DisplayHook<decltype(&HwcDisplay::SetOutputBuffer),
+                      &HwcDisplay::SetOutputBuffer, buffer_handle_t, int32_t>);
+    case HWC2::FunctionDescriptor::SetPowerMode:
+      return ToHook<HWC2_PFN_SET_POWER_MODE>(
+          DisplayHook<decltype(&HwcDisplay::SetPowerMode),
+                      &HwcDisplay::SetPowerMode, int32_t>);
+    case HWC2::FunctionDescriptor::SetVsyncEnabled:
+      return ToHook<HWC2_PFN_SET_VSYNC_ENABLED>(
+          DisplayHook<decltype(&HwcDisplay::SetVsyncEnabled),
+                      &HwcDisplay::SetVsyncEnabled, int32_t>);
+    case HWC2::FunctionDescriptor::ValidateDisplay:
+      return ToHook<HWC2_PFN_VALIDATE_DISPLAY>(
+          DisplayHook<decltype(&HwcDisplay::ValidateDisplay),
+                      &HwcDisplay::ValidateDisplay, uint32_t *, uint32_t *>);
+#if PLATFORM_SDK_VERSION > 27
+    case HWC2::FunctionDescriptor::GetRenderIntents:
+      return ToHook<HWC2_PFN_GET_RENDER_INTENTS>(
+          DisplayHook<decltype(&HwcDisplay::GetRenderIntents),
+                      &HwcDisplay::GetRenderIntents, int32_t, uint32_t *,
+                      int32_t *>);
+    case HWC2::FunctionDescriptor::SetColorModeWithRenderIntent:
+      return ToHook<HWC2_PFN_SET_COLOR_MODE_WITH_RENDER_INTENT>(
+          DisplayHook<decltype(&HwcDisplay::SetColorModeWithIntent),
+                      &HwcDisplay::SetColorModeWithIntent, int32_t, int32_t>);
+#endif
+#if PLATFORM_SDK_VERSION > 28
+    case HWC2::FunctionDescriptor::GetDisplayIdentificationData:
+      return ToHook<HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA>(
+          DisplayHook<decltype(&HwcDisplay::GetDisplayIdentificationData),
+                      &HwcDisplay::GetDisplayIdentificationData, uint8_t *,
+                      uint32_t *, uint8_t *>);
+    case HWC2::FunctionDescriptor::GetDisplayCapabilities:
+      return ToHook<HWC2_PFN_GET_DISPLAY_CAPABILITIES>(
+          DisplayHook<decltype(&HwcDisplay::GetDisplayCapabilities),
+                      &HwcDisplay::GetDisplayCapabilities, uint32_t *,
+                      uint32_t *>);
+    case HWC2::FunctionDescriptor::GetDisplayBrightnessSupport:
+      return ToHook<HWC2_PFN_GET_DISPLAY_BRIGHTNESS_SUPPORT>(
+          DisplayHook<decltype(&HwcDisplay::GetDisplayBrightnessSupport),
+                      &HwcDisplay::GetDisplayBrightnessSupport, bool *>);
+    case HWC2::FunctionDescriptor::SetDisplayBrightness:
+      return ToHook<HWC2_PFN_SET_DISPLAY_BRIGHTNESS>(
+          DisplayHook<decltype(&HwcDisplay::SetDisplayBrightness),
+                      &HwcDisplay::SetDisplayBrightness, float>);
+#endif /* PLATFORM_SDK_VERSION > 28 */
+#if PLATFORM_SDK_VERSION > 29
+    case HWC2::FunctionDescriptor::GetDisplayConnectionType:
+      return ToHook<HWC2_PFN_GET_DISPLAY_CONNECTION_TYPE>(
+          DisplayHook<decltype(&HwcDisplay::GetDisplayConnectionType),
+                      &HwcDisplay::GetDisplayConnectionType, uint32_t *>);
+    case HWC2::FunctionDescriptor::GetDisplayVsyncPeriod:
+      return ToHook<HWC2_PFN_GET_DISPLAY_VSYNC_PERIOD>(
+          DisplayHook<decltype(&HwcDisplay::GetDisplayVsyncPeriod),
+                      &HwcDisplay::GetDisplayVsyncPeriod,
+                      hwc2_vsync_period_t *>);
+    case HWC2::FunctionDescriptor::SetActiveConfigWithConstraints:
+      return ToHook<HWC2_PFN_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS>(
+          DisplayHook<decltype(&HwcDisplay::SetActiveConfigWithConstraints),
+                      &HwcDisplay::SetActiveConfigWithConstraints,
+                      hwc2_config_t, hwc_vsync_period_change_constraints_t *,
+                      hwc_vsync_period_change_timeline_t *>);
+    case HWC2::FunctionDescriptor::SetAutoLowLatencyMode:
+      return ToHook<HWC2_PFN_SET_AUTO_LOW_LATENCY_MODE>(
+          DisplayHook<decltype(&HwcDisplay::SetAutoLowLatencyMode),
+                      &HwcDisplay::SetAutoLowLatencyMode, bool>);
+    case HWC2::FunctionDescriptor::GetSupportedContentTypes:
+      return ToHook<HWC2_PFN_GET_SUPPORTED_CONTENT_TYPES>(
+          DisplayHook<decltype(&HwcDisplay::GetSupportedContentTypes),
+                      &HwcDisplay::GetSupportedContentTypes, uint32_t *,
+                      uint32_t *>);
+    case HWC2::FunctionDescriptor::SetContentType:
+      return ToHook<HWC2_PFN_SET_CONTENT_TYPE>(
+          DisplayHook<decltype(&HwcDisplay::SetContentType),
+                      &HwcDisplay::SetContentType, int32_t>);
+#endif
+    // Layer functions
+    case HWC2::FunctionDescriptor::SetCursorPosition:
+      return ToHook<HWC2_PFN_SET_CURSOR_POSITION>(
+          LayerHook<decltype(&HwcLayer::SetCursorPosition),
+                    &HwcLayer::SetCursorPosition, int32_t, int32_t>);
+    case HWC2::FunctionDescriptor::SetLayerBlendMode:
+      return ToHook<HWC2_PFN_SET_LAYER_BLEND_MODE>(
+          LayerHook<decltype(&HwcLayer::SetLayerBlendMode),
+                    &HwcLayer::SetLayerBlendMode, int32_t>);
+    case HWC2::FunctionDescriptor::SetLayerBuffer:
+      return ToHook<HWC2_PFN_SET_LAYER_BUFFER>(
+          LayerHook<decltype(&HwcLayer::SetLayerBuffer),
+                    &HwcLayer::SetLayerBuffer, buffer_handle_t, int32_t>);
+    case HWC2::FunctionDescriptor::SetLayerColor:
+      return ToHook<HWC2_PFN_SET_LAYER_COLOR>(
+          LayerHook<decltype(&HwcLayer::SetLayerColor),
+                    &HwcLayer::SetLayerColor, hwc_color_t>);
+    case HWC2::FunctionDescriptor::SetLayerCompositionType:
+      return ToHook<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>(
+          LayerHook<decltype(&HwcLayer::SetLayerCompositionType),
+                    &HwcLayer::SetLayerCompositionType, int32_t>);
+    case HWC2::FunctionDescriptor::SetLayerDataspace:
+      return ToHook<HWC2_PFN_SET_LAYER_DATASPACE>(
+          LayerHook<decltype(&HwcLayer::SetLayerDataspace),
+                    &HwcLayer::SetLayerDataspace, int32_t>);
+    case HWC2::FunctionDescriptor::SetLayerDisplayFrame:
+      return ToHook<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>(
+          LayerHook<decltype(&HwcLayer::SetLayerDisplayFrame),
+                    &HwcLayer::SetLayerDisplayFrame, hwc_rect_t>);
+    case HWC2::FunctionDescriptor::SetLayerPlaneAlpha:
+      return ToHook<HWC2_PFN_SET_LAYER_PLANE_ALPHA>(
+          LayerHook<decltype(&HwcLayer::SetLayerPlaneAlpha),
+                    &HwcLayer::SetLayerPlaneAlpha, float>);
+    case HWC2::FunctionDescriptor::SetLayerSidebandStream:
+      return ToHook<HWC2_PFN_SET_LAYER_SIDEBAND_STREAM>(
+          LayerHook<decltype(&HwcLayer::SetLayerSidebandStream),
+                    &HwcLayer::SetLayerSidebandStream,
+                    const native_handle_t *>);
+    case HWC2::FunctionDescriptor::SetLayerSourceCrop:
+      return ToHook<HWC2_PFN_SET_LAYER_SOURCE_CROP>(
+          LayerHook<decltype(&HwcLayer::SetLayerSourceCrop),
+                    &HwcLayer::SetLayerSourceCrop, hwc_frect_t>);
+    case HWC2::FunctionDescriptor::SetLayerSurfaceDamage:
+      return ToHook<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>(
+          LayerHook<decltype(&HwcLayer::SetLayerSurfaceDamage),
+                    &HwcLayer::SetLayerSurfaceDamage, hwc_region_t>);
+    case HWC2::FunctionDescriptor::SetLayerTransform:
+      return ToHook<HWC2_PFN_SET_LAYER_TRANSFORM>(
+          LayerHook<decltype(&HwcLayer::SetLayerTransform),
+                    &HwcLayer::SetLayerTransform, int32_t>);
+    case HWC2::FunctionDescriptor::SetLayerVisibleRegion:
+      return ToHook<HWC2_PFN_SET_LAYER_VISIBLE_REGION>(
+          LayerHook<decltype(&HwcLayer::SetLayerVisibleRegion),
+                    &HwcLayer::SetLayerVisibleRegion, hwc_region_t>);
+    case HWC2::FunctionDescriptor::SetLayerZOrder:
+      return ToHook<HWC2_PFN_SET_LAYER_Z_ORDER>(
+          LayerHook<decltype(&HwcLayer::SetLayerZOrder),
+                    &HwcLayer::SetLayerZOrder, uint32_t>);
+    case HWC2::FunctionDescriptor::Invalid:
+    default:
+      return nullptr;
+  }
+}
+
+static int HookDevOpen(const struct hw_module_t *module, const char *name,
+                       struct hw_device_t **dev) {
+  if (strcmp(name, HWC_HARDWARE_COMPOSER) != 0) {
+    ALOGE("Invalid module name- %s", name);
+    return -EINVAL;
+  }
+
+  auto ctx = std::make_unique<Drmhwc2Device>();
+  if (!ctx) {
+    ALOGE("Failed to allocate DrmHwcTwo");
+    return -ENOMEM;
+  }
+
+  ctx->common.tag = HARDWARE_DEVICE_TAG;
+  ctx->common.version = HWC_DEVICE_API_VERSION_2_0;
+  ctx->common.close = HookDevClose;
+  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
+  ctx->common.module = (hw_module_t *)module;
+  ctx->getCapabilities = HookDevGetCapabilities;
+  ctx->getFunction = HookDevGetFunction;
+
+  *dev = &ctx.release()->common;
+
+  return 0;
+}
+
+}  // namespace android
+
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+static struct hw_module_methods_t hwc2_module_methods = {
+    .open = android::HookDevOpen,
+};
+
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+hw_module_t HAL_MODULE_INFO_SYM = {
+    .tag = HARDWARE_MODULE_TAG,
+    .module_api_version = HARDWARE_MODULE_API_VERSION(2, 0),
+    .id = HWC_HARDWARE_MODULE_ID,
+    .name = "DrmHwcTwo module",
+    .author = "The Android Open Source Project",
+    .methods = &hwc2_module_methods,
+    .dso = nullptr,
+    .reserved = {0},
+};
diff --git a/include/drmhwcgralloc.h b/include/drmhwcgralloc.h
deleted file mode 100644
index db54802..0000000
--- a/include/drmhwcgralloc.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_DRMHWCGRALLOC_H_
-#define ANDROID_DRMHWCGRALLOC_H_
-
-#include <stdint.h>
-
-#define HWC_DRM_BO_MAX_PLANES 4
-typedef struct hwc_drm_bo {
-  uint32_t width;
-  uint32_t height;
-  uint32_t format;     /* DRM_FORMAT_* from drm_fourcc.h */
-  uint32_t hal_format; /* HAL_PIXEL_FORMAT_* */
-  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];
-  uint64_t modifiers[HWC_DRM_BO_MAX_PLANES];
-  int acquire_fence_fd;
-} hwc_drm_bo_t;
-
-#endif  // ANDROID_DRMHWCGRALLOC_H_
diff --git a/include/drmhwcomposer.h b/include/drmhwcomposer.h
deleted file mode 100644
index 22af12b..0000000
--- a/include/drmhwcomposer.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_DRM_HWCOMPOSER_H_
-#define ANDROID_DRM_HWCOMPOSER_H_
-
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-#include <vector>
-
-#include "drm/DrmFbImporter.h"
-#include "drmhwcgralloc.h"
-#include "utils/UniqueFd.h"
-
-namespace android {
-
-class DrmFbIdHandle;
-
-enum DrmHwcTransform {
-  kIdentity = 0,
-  kFlipH = 1 << 0,
-  kFlipV = 1 << 1,
-  kRotate90 = 1 << 2,
-  kRotate180 = 1 << 3,
-  kRotate270 = 1 << 4,
-};
-
-enum class DrmHwcBlending : int32_t {
-  kNone = HWC_BLENDING_NONE,
-  kPreMult = HWC_BLENDING_PREMULT,
-  kCoverage = HWC_BLENDING_COVERAGE,
-};
-
-struct DrmHwcLayer {
-  buffer_handle_t sf_handle = NULL;
-  hwc_drm_bo_t buffer_info{};
-  std::shared_ptr<DrmFbIdHandle> FbIdHandle;
-
-  int gralloc_buffer_usage = 0;
-  uint32_t transform;
-  DrmHwcBlending blending = DrmHwcBlending::kNone;
-  uint16_t alpha = 0xffff;
-  hwc_frect_t source_crop;
-  hwc_rect_t display_frame;
-  android_dataspace_t dataspace;
-
-  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;
-  }
-};
-
-}  // namespace android
-
-#endif
diff --git a/presubmit.sh b/presubmit.sh
index 249aaf5..a551398 100755
--- a/presubmit.sh
+++ b/presubmit.sh
@@ -4,18 +4,10 @@
 
 echo "Run native build:"
 
-./.ci/.gitlab-ci-clang-build.sh
+make -f .ci/Makefile -j12
 
 echo "Run style check:"
 
 ./.ci/.gitlab-ci-checkcommit.sh
 
-echo "Run coarse clang-tidy check:"
-
-./.ci/.gitlab-ci-clang-tidy-coarse.sh
-
-echo "Run fine clang-tidy check:"
-
-./.ci/.gitlab-ci-clang-tidy-fine.sh
-
 echo -e "\n\e[32m --- SUCCESS ---"
diff --git a/tests/Android.bp b/tests/Android.bp
index 473c944..f3ebb71 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -1,9 +1,9 @@
 cc_library_shared {
     name: "hwcomposer.filegroups_build_test",
     defaults: ["hwcomposer.drm_defaults"],
-    whole_static_libs: ["drm_hwcomposer"],
 
     srcs: [
+        ":drm_hwcomposer_common",
         ":drm_hwcomposer_platformhisi",
         ":drm_hwcomposer_platformimagination",
         ":drm_hwcomposer_platformmediatek",
@@ -37,8 +37,19 @@
     header_libs: ["libhardware_headers"],
     static_libs: ["libdrmhwc_utils"],
     shared_libs: ["hwcomposer.drm"],
+    include_dirs: ["external/drm_hwcomposer"],
+}
+
+// Tool for listening and dumping uevents
+cc_test {
+    name: "hwc-drm-uevent-print",
+
+    srcs: ["uevent_print.cpp"],
+
+    vendor: true,
+    header_libs: ["libhardware_headers"],
+    shared_libs: ["liblog"],
     include_dirs: [
         "external/drm_hwcomposer",
-        "external/drm_hwcomposer/include",
     ],
 }
diff --git a/tests/test_include/cros_gralloc_handle.h b/tests/test_include/cros_gralloc_handle.h
deleted file mode 100644
index d77d777..0000000
--- a/tests/test_include/cros_gralloc_handle.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// clang-format off
-/*
- * Copyright 2016 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef CROS_GRALLOC_HANDLE_H
-#define CROS_GRALLOC_HANDLE_H
-
-#include <cstdint>
-#include <cutils/native_handle.h>
-
-#define DRV_MAX_PLANES 4
-#define DRV_MAX_FDS (DRV_MAX_PLANES + 1)
-
-struct cros_gralloc_handle : public native_handle_t {
-	/*
-	 * File descriptors must immediately follow the native_handle_t base and used file
-	 * descriptors must be packed at the beginning of this array to work with
-	 * native_handle_clone().
-	 *
-	 * This field contains 'num_planes' plane file descriptors followed by an optional metadata
-	 * reserved region file descriptor if 'reserved_region_size' is greater than zero.
-	 */
-	int32_t fds[DRV_MAX_FDS];
-	uint32_t strides[DRV_MAX_PLANES];
-	uint32_t offsets[DRV_MAX_PLANES];
-	uint32_t sizes[DRV_MAX_PLANES];
-	uint32_t id;
-	uint32_t width;
-	uint32_t height;
-	uint32_t format; /* DRM format */
-	uint32_t tiling;
-	uint64_t format_modifier;
-	uint64_t use_flags; /* Buffer creation flags */
-	uint32_t magic;
-	uint32_t pixel_stride;
-	int32_t droid_format;
-	int32_t usage; /* Android usage. */
-	uint32_t num_planes;
-	uint64_t reserved_region_size;
-	uint64_t total_size; /* Total allocation size */
-	/*
-	 * Name is a null terminated char array located at handle->base.data[handle->name_offset].
-	 */
-	uint32_t name_offset;
-} __attribute__((packed));
-
-typedef const struct cros_gralloc_handle *cros_gralloc_handle_t;
-
-#endif
-// clang-format on
diff --git a/tests/uevent_print.cpp b/tests/uevent_print.cpp
new file mode 100644
index 0000000..6ffbbfb
--- /dev/null
+++ b/tests/uevent_print.cpp
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#include <iostream>
+
+#include "utils/UEvent.h"
+
+int main() {
+  auto uevent = android::UEvent::CreateInstance();
+  if (!uevent) {
+    std::cout << "Can't initialize UEvent class" << std::endl;
+    return -ENODEV;
+  }
+
+  int number = 0;
+  for (;;) {
+    auto msg = uevent->ReadNext();
+    if (!msg) {
+      continue;
+    }
+
+    std::cout << "New event #" << number++ << std::endl
+              << *msg << std::endl
+              << std::endl;
+  }
+}
diff --git a/utils/UEvent.h b/utils/UEvent.h
new file mode 100644
index 0000000..17b3cab
--- /dev/null
+++ b/utils/UEvent.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#pragma once
+
+#include <linux/netlink.h>
+#include <sys/socket.h>
+
+#include <cerrno>
+#include <memory>
+#include <optional>
+#include <string>
+
+#include "UniqueFd.h"
+#include "log.h"
+
+namespace android {
+
+class UEvent {
+ public:
+  static auto CreateInstance() -> std::unique_ptr<UEvent> {
+    auto fd = UniqueFd(
+        socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT));
+
+    if (!fd) {
+      ALOGE("Failed to open uevent socket: errno=%i", errno);
+      return {};
+    }
+
+    struct sockaddr_nl addr {};
+    addr.nl_family = AF_NETLINK;
+    addr.nl_pid = 0;
+    addr.nl_groups = UINT32_MAX;
+
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
+    int ret = bind(fd.Get(), (struct sockaddr *)&addr, sizeof(addr));
+    if (ret != 0) {
+      ALOGE("Failed to bind uevent socket: errno=%i", errno);
+      return {};
+    }
+
+    return std::unique_ptr<UEvent>(new UEvent(fd));
+  }
+
+  auto ReadNext() -> std::optional<std::string> {
+    constexpr int kUEventBufferSize = 1024;
+    char buffer[kUEventBufferSize];
+    ssize_t ret = 0;
+    ret = read(fd_.Get(), &buffer, sizeof(buffer));
+    if (ret == 0)
+      return {};
+
+    if (ret < 0) {
+      ALOGE("Got error reading uevent %zd", ret);
+      return {};
+    }
+
+    for (int i = 0; i < ret - 1; i++) {
+      if (buffer[i] == '\0') {
+        buffer[i] = '\n';
+      }
+    }
+
+    return std::string(buffer);
+  }
+
+ private:
+  explicit UEvent(UniqueFd &fd) : fd_(std::move(fd)){};
+  UniqueFd fd_;
+};
+
+}  // namespace android
diff --git a/utils/UniqueFd.h b/utils/UniqueFd.h
index 1a390ba..d747a7f 100644
--- a/utils/UniqueFd.h
+++ b/utils/UniqueFd.h
@@ -17,6 +17,7 @@
 #ifndef UNIQUEFD_H_
 #define UNIQUEFD_H_
 
+#include <fcntl.h>
 #include <unistd.h>
 
 #include <memory>
@@ -73,6 +74,11 @@
     return fd_;
   }
 
+  static auto Dup(int fd) {
+    // NOLINTNEXTLINE(android-cloexec-dup): fcntl has issue (see issue #63)
+    return UniqueFd(dup(fd));
+  }
+
   explicit operator bool() const {
     return fd_ != kEmptyFd;
   }
diff --git a/utils/Worker.h b/utils/Worker.h
index 73a80da..74cfdc4 100644
--- a/utils/Worker.h
+++ b/utils/Worker.h
@@ -17,10 +17,9 @@
 #ifndef ANDROID_WORKER_H_
 #define ANDROID_WORKER_H_
 
-#include <stdint.h>
-#include <stdlib.h>
-
 #include <condition_variable>
+#include <cstdint>
+#include <cstdlib>
 #include <mutex>
 #include <string>
 #include <thread>
@@ -45,9 +44,10 @@
     return initialized_;
   }
 
+  virtual ~Worker();
+
  protected:
   Worker(const char *name, int priority);
-  virtual ~Worker();
 
   int InitWorker();
   virtual void Routine() = 0;
diff --git a/utils/autolock.cpp b/utils/autolock.cpp
deleted file mode 100644
index 3342e46..0000000
--- a/utils/autolock.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#define LOG_TAG "hwc-drm-auto-lock"
-
-#include "autolock.h"
-
-#include <pthread.h>
-
-#include <cerrno>
-
-#include "utils/log.h"
-
-namespace android {
-
-int AutoLock::Lock() {
-  if (locked_) {
-    ALOGE("Invalid attempt to double lock AutoLock %s", name_);
-    return -EINVAL;
-  }
-  int ret = pthread_mutex_lock(mutex_);
-  if (ret) {
-    ALOGE("Failed to acquire %s lock %d", name_, ret);
-    return ret;
-  }
-  locked_ = true;
-  return 0;
-}
-
-int AutoLock::Unlock() {
-  if (!locked_) {
-    ALOGE("Invalid attempt to unlock unlocked AutoLock %s", name_);
-    return -EINVAL;
-  }
-  int ret = pthread_mutex_unlock(mutex_);
-  if (ret) {
-    ALOGE("Failed to release %s lock %d", name_, ret);
-    return ret;
-  }
-  locked_ = false;
-  return 0;
-}
-}  // namespace android
diff --git a/utils/autolock.h b/utils/autolock.h
deleted file mode 100644
index 006406a..0000000
--- a/utils/autolock.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <pthread.h>
-
-namespace android {
-
-class AutoLock {
- public:
-  AutoLock(pthread_mutex_t *mutex, const char *const name)
-      : mutex_(mutex), name_(name) {
-  }
-  ~AutoLock() {
-    if (locked_)
-      Unlock();
-  }
-
-  AutoLock(const AutoLock &rhs) = delete;
-  AutoLock &operator=(const AutoLock &rhs) = delete;
-
-  int Lock();
-  int Unlock();
-
- private:
-  pthread_mutex_t *const mutex_;
-  bool locked_ = false;
-  const char *const name_;
-};
-}  // namespace android
diff --git a/utils/hwcutils.cpp b/utils/hwcutils.cpp
deleted file mode 100644
index 6de6500..0000000
--- a/utils/hwcutils.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#define LOG_TAG "hwc-drm-utils"
-
-#include <log/log.h>
-#include <ui/Gralloc.h>
-#include <ui/GraphicBufferMapper.h>
-
-#include "bufferinfo/BufferInfoGetter.h"
-#include "drm/DrmFbImporter.h"
-#include "drmhwcomposer.h"
-
-#define UNUSED(x) (void)(x)
-
-namespace android {
-
-int DrmHwcLayer::ImportBuffer(DrmDevice *drmDevice) {
-  buffer_info = hwc_drm_bo_t{};
-
-  int ret = BufferInfoGetter::GetInstance()->ConvertBoInfo(sf_handle,
-                                                           &buffer_info);
-  if (ret) {
-    ALOGE("Failed to convert buffer info %d", ret);
-    return ret;
-  }
-
-  FbIdHandle = drmDevice->GetDrmFbImporter().GetOrCreateFbId(&buffer_info);
-  if (!FbIdHandle) {
-    ALOGE("Failed to import buffer");
-    return -EINVAL;
-  }
-
-  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..0b49c61 100644
--- a/utils/properties.h
+++ b/utils/properties.h
@@ -14,13 +14,14 @@
 // 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 {
+  // NOLINTNEXTLINE (concurrency-mt-unsafe)
   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