Przeglądaj źródła

drm_hwcomposer: Merge 'aosp/upstream-main' into HEAD

Sync with upstream

* aosp/upstream-main:
  drm_hwcomposer: Fix BufferInfoMaliMeson
  drm_hwcomposer: Workaround for screen de-activating causing db845c regression
  drm_hwcomposer: Split the composition cleanup and display's deactivation
  drm_hwcomposer: Fix EINTR handling in clock_nanosleep
  drm_hwcomposer: Don't try to import client layer in headless mode
  drm_hwcomposer: Implement BI and FB caching
  drm_hwcomposer: Add unique handle ID getter into buffergetter class
  drm_hwcomposer: Reorganize struct DrmHwcLayer
  drm_hwcomposer: Set return type to std::optional for BufferInfoGetters
  drm_hwcomposer: Move include/drmhwcgralloc.h to bufferinfo/BufferInfo.h
  drm_hwcomposer: Use atrace for framebuffer's import/remove events
  drm_hwcomposer: Add non-blocking commit support
  drm_hwcomposer: Fix HwcLayer::GetReleaseFences()
  drm_hwcomposer: Allow accessing ResourceManager from DrmDevce
  drm_hwcomposer: CI: Bump clang toolchain version to v14
  drm_hwcomposer: Fix HwcDisplay::GetDisplayIdentificationData()
  drm_hwcomposer: Fix SetPowerMode() VTS tests for headless mode
  drm_hwcomposer: Fixes for display hotplug / headless mode

Signed-off-by: John Stultz <jstultz@google.com>
Change-Id: I629e0274bb5ce7371d0437aff985fa76e69510ba
John Stultz 1 rok temu
rodzic
commit
cd31422280
48 zmienionych plików z 958 dodań i 614 usunięć
  1. 1 1
      .ci/.gitlab-ci-checkcommit.sh
  2. 3 2
      .ci/Makefile
  3. 2 2
      .gitlab-ci.yml
  4. 2 10
      Android.bp
  5. 1 1
      README.md
  6. 3 3
      backend/Backend.cpp
  7. 57 0
      bufferinfo/BufferInfo.h
  8. 15 9
      bufferinfo/BufferInfoGetter.cpp
  9. 8 3
      bufferinfo/BufferInfoGetter.h
  10. 26 34
      bufferinfo/BufferInfoMapperMetadata.cpp
  11. 2 2
      bufferinfo/BufferInfoMapperMetadata.h
  12. 14 14
      bufferinfo/legacy/BufferInfoImagination.cpp
  13. 1 1
      bufferinfo/legacy/BufferInfoImagination.h
  14. 23 22
      bufferinfo/legacy/BufferInfoLibdrm.cpp
  15. 3 2
      bufferinfo/legacy/BufferInfoLibdrm.h
  16. 23 23
      bufferinfo/legacy/BufferInfoMaliHisi.cpp
  17. 1 1
      bufferinfo/legacy/BufferInfoMaliHisi.h
  18. 15 15
      bufferinfo/legacy/BufferInfoMaliMediatek.cpp
  19. 1 1
      bufferinfo/legacy/BufferInfoMaliMediatek.h
  20. 15 15
      bufferinfo/legacy/BufferInfoMaliMeson.cpp
  21. 1 1
      bufferinfo/legacy/BufferInfoMaliMeson.h
  22. 17 17
      bufferinfo/legacy/BufferInfoMinigbm.cpp
  23. 1 1
      bufferinfo/legacy/BufferInfoMinigbm.h
  24. 1 1
      compositor/DrmKmsPlan.cpp
  25. 3 3
      compositor/DrmKmsPlan.h
  26. 81 0
      compositor/LayerData.h
  27. 118 19
      drm/DrmAtomicStateManager.cpp
  28. 52 6
      drm/DrmAtomicStateManager.h
  29. 18 2
      drm/DrmDevice.cpp
  30. 14 4
      drm/DrmDevice.h
  31. 11 4
      drm/DrmFbImporter.cpp
  32. 4 4
      drm/DrmFbImporter.h
  33. 50 51
      drm/DrmPlane.cpp
  34. 8 8
      drm/DrmPlane.h
  35. 11 13
      drm/ResourceManager.cpp
  36. 0 1
      drm/ResourceManager.h
  37. 1 1
      drm/VSyncWorker.cpp
  38. 8 2
      hwc2_device/DrmHwcTwo.cpp
  39. 116 51
      hwc2_device/HwcDisplay.cpp
  40. 6 2
      hwc2_device/HwcDisplay.h
  41. 150 36
      hwc2_device/HwcLayer.cpp
  42. 62 41
      hwc2_device/HwcLayer.h
  43. 0 42
      include/drmhwcgralloc.h
  44. 0 89
      include/drmhwcomposer.h
  45. 1 4
      tests/Android.bp
  46. 6 0
      utils/UniqueFd.h
  47. 2 1
      utils/Worker.h
  48. 0 49
      utils/hwcutils.cpp

+ 1 - 1
.ci/.gitlab-ci-checkcommit.sh

@@ -50,7 +50,7 @@ git log --pretty='%h' FETCH_HEAD..HEAD | while read h; do
 		exit 1
 	fi
 
-	git show "$h" -- | clang-format-diff-13 -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

+ 3 - 2
.ci/Makefile

@@ -2,8 +2,8 @@
 INCLUDE_DIRS := . ../libdrm/include/drm include ./.ci/android_headers ./tests/test_include
 SYSTEM_INCLUDE_DIRS := /usr/include/libdrm
 
-CLANG := clang++-13
-CLANG_TIDY := clang-tidy-13
+CLANG := clang++-14
+CLANG_TIDY := clang-tidy-14
 OUT_DIR := /tmp/drm_hwcomposer/build
 SRC_DIR := .
 
@@ -43,6 +43,7 @@ TIDY_CHECKS_FINE := *                                   \
     -cppcoreguidelines-pro-type-vararg                  \
     -hicpp-vararg                                       \
     -hicpp-signed-bitwise                               \
+    -readability-identifier-length                      \
 
 TIDY_CHECKS_NORMAL :=                                   \
     $(TIDY_CHECKS_FINE)                                 \

+ 2 - 2
.gitlab-ci.yml

@@ -1,11 +1,11 @@
-image: ubuntu:21.10
+image: ubuntu:22.04
 
 variables:
   DEBIAN_FRONTEND: noninteractive
 
 before_script:
   - apt-get --quiet update --yes >/dev/null
-  - apt-get --quiet install --yes clang-13 clang-tidy-13 clang-format-13 git libdrm-dev blueprint-tools libgtest-dev make >/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

+ 2 - 10
Android.bp

@@ -37,10 +37,7 @@ cc_library_static {
 
     srcs: ["utils/Worker.cpp"],
 
-    include_dirs: [
-        "external/drm_hwcomposer",
-        "external/drm_hwcomposer/include",
-    ],
+    include_dirs: ["external/drm_hwcomposer"],
 
     cflags: [
         "-Wall",
@@ -68,10 +65,7 @@ cc_defaults {
         "libutils",
     ],
 
-    include_dirs: [
-        "external/drm_hwcomposer",
-        "external/drm_hwcomposer/include",
-    ],
+    include_dirs: ["external/drm_hwcomposer"],
 
     static_libs: ["libdrmhwc_utils"],
 
@@ -118,8 +112,6 @@ filegroup {
         "drm/UEventListener.cpp",
         "drm/VSyncWorker.cpp",
 
-        "utils/hwcutils.cpp",
-
         "backend/Backend.cpp",
         "backend/BackendClient.cpp",
         "backend/BackendManager.cpp",

+ 1 - 1
README.md

@@ -16,7 +16,7 @@ A short list of contribution guidelines:
   you with formatting of your patches:
 
     ```
-    git diff | clang-format-diff-13 -p 1 -style=file
+    git diff | clang-format-diff-14 -p 1 -style=file
     ```
 
 * Hardware specific changes should be tested on relevant platforms before

+ 3 - 3
backend/Backend.cpp

@@ -83,9 +83,9 @@ std::tuple<int, size_t> Backend::GetClientLayers(
 
 bool Backend::IsClientLayer(HwcDisplay *display, HwcLayer *layer) {
   return !HardwareSupportsLayerType(layer->GetSfType()) ||
-         !BufferInfoGetter::GetInstance()->IsHandleUsable(layer->GetBuffer()) ||
+         !layer->IsLayerUsableAsDevice() ||
          display->color_transform_hint() != HAL_COLOR_TRANSFORM_IDENTITY ||
-         (layer->RequireScalingOrPhasing() &&
+         (layer->GetLayerData().pi.RequireScalingOrPhasing() &&
           display->GetHwc2()->GetResMan().ForcedScalingWithGpu());
 }
 
@@ -99,7 +99,7 @@ uint32_t Backend::CalcPixOps(const std::vector<HwcLayer *> &layers,
   uint32_t pixops = 0;
   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]->GetDisplayFrame();
+      hwc_rect_t &df = layers[z_order]->GetLayerData().pi.display_frame;
       pixops += (df.right - df.left) * (df.bottom - df.top);
     }
   }

+ 57 - 0
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;
+};

+ 15 - 9
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"
 
@@ -48,17 +53,18 @@ BufferInfoGetter *BufferInfoGetter::GetInstance() {
   return inst.get();
 }
 
-bool BufferInfoGetter::IsHandleUsable(buffer_handle_t handle) {
-  hwc_drm_bo_t bo;
-  memset(&bo, 0, sizeof(hwc_drm_bo_t));
-
-  if (ConvertBoInfo(handle, &bo) != 0) {
-    return false;
+std::optional<BufferUniqueId> BufferInfoGetter::GetUniqueId(
+    buffer_handle_t handle) {
+  struct stat sb {};
+  if (fstat(handle->data[0], &sb) != 0) {
+    return {};
   }
-  if (bo.prime_fds[0] == 0) {
-    return false;
+
+  if (sb.st_size == 0) {
+    return {};
   }
-  return true;
+
+  return static_cast<BufferUniqueId>(sb.st_ino);
 }
 
 int LegacyBufferInfoGetter::Init() {

+ 8 - 3
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,13 +31,16 @@
 
 namespace android {
 
+using BufferUniqueId = uint64_t;
+
 class BufferInfoGetter {
  public:
   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();
 

+ 26 - 34
bufferinfo/BufferInfoMapperMetadata.cpp

@@ -46,7 +46,7 @@ BufferInfoGetter *BufferInfoMapperMetadata::CreateInstance() {
  * so that it can be overridden.
  */
 int __attribute__((weak))
-BufferInfoMapperMetadata::GetFds(buffer_handle_t handle, hwc_drm_bo_t *bo) {
+BufferInfoMapperMetadata::GetFds(buffer_handle_t handle, BufferInfo *bo) {
   int fd_index = 0;
 
   if (handle->numFds <= 0) {
@@ -54,7 +54,7 @@ BufferInfoMapperMetadata::GetFds(buffer_handle_t handle, hwc_drm_bo_t *bo) {
     return android::BAD_VALUE;
   }
 
-  for (int i = 0; i < kHwcDrmBoMaxPlanes; i++) {
+  for (int i = 0; i < kBufferMaxPlanes; i++) {
     /* If no size, we're out of usable planes */
     if (bo->sizes[i] <= 0) {
       if (i == 0) {
@@ -86,71 +86,63 @@ BufferInfoMapperMetadata::GetFds(buffer_handle_t handle, hwc_drm_bo_t *bo) {
   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 == nullptr)
-    return -EINVAL;
+    return {};
 
-  uint64_t usage = 0;
-  int err = mapper.getUsage(handle, &usage);
-  if (err != 0) {
-    ALOGE("Failed to get usage err=%d", err);
-    return err;
-  }
-  bo->usage = static_cast<uint32_t>(usage);
-
-  ui::PixelFormat hal_format;
-  err = mapper.getPixelFormatRequested(handle, &hal_format);
-  if (err != 0) {
-    ALOGE("Failed to get HAL Pixel Format err=%d", err);
-    return err;
-  }
-  bo->hal_format = static_cast<uint32_t>(hal_format);
+  BufferInfo bi{};
 
-  err = mapper.getPixelFormatFourCC(handle, &bo->format);
+  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]);
+  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 != 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 != 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 != 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;
-    bo->sizes[i] = layouts[i].totalSizeInBytes;
+    bi.modifiers[i] = bi.modifiers[0];
+    bi.pitches[i] = layouts[i].strideInBytes;
+    bi.offsets[i] = layouts[i].offsetInBytes;
+    bi.sizes[i] = layouts[i].totalSizeInBytes;
+  }
+
+  err = GetFds(handle, &bi);
+  if (err != 0) {
+    ALOGE("Failed to get fds (err=%d)", err);
+    return {};
   }
 
-  return GetFds(handle, bo);
+  return bi;
 }
 
 }  // namespace android

+ 2 - 2
bufferinfo/BufferInfoMapperMetadata.h

@@ -25,9 +25,9 @@ class BufferInfoMapperMetadata : public BufferInfoGetter {
  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();
 };

+ 14 - 14
bufferinfo/legacy/BufferInfoImagination.cpp

@@ -29,24 +29,24 @@ namespace android {
 
 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
@@ -55,14 +55,14 @@ int BufferInfoImagination::ConvertBoInfo(buffer_handle_t handle,
       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

+ 1 - 1
bufferinfo/legacy/BufferInfoImagination.h

@@ -27,7 +27,7 @@ class BufferInfoImagination : 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;
 };
 }  // namespace android
 

+ 23 - 22
bufferinfo/legacy/BufferInfoLibdrm.cpp

@@ -91,8 +91,8 @@ static bool is_yuv(uint32_t native) {
   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;
@@ -136,12 +136,12 @@ bool BufferInfoLibdrm::GetYuvPlaneInfo(int num_fds, buffer_handle_t handle,
 
   /* .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);
+  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;
   }
@@ -162,14 +162,16 @@ bool BufferInfoLibdrm::GetYuvPlaneInfo(int num_fds, buffer_handle_t handle,
   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 {};
+
+  BufferInfo bi{};
 
-  bo->width = gr_handle->width;
-  bo->height = gr_handle->height;
-  bo->hal_format = gr_handle->format;
+  bi.width = gr_handle->width;
+  bi.height = gr_handle->height;
 
 #if GRALLOC_HANDLE_VERSION < 4
   static std::once_flag once;
@@ -179,35 +181,34 @@ int BufferInfoLibdrm::ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) {
   });
 #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 0;
+  return bi;
 }
 
 constexpr char gbm_gralloc_module_name[] = "GBM Memory Allocator";

+ 3 - 2
bufferinfo/legacy/BufferInfoLibdrm.h

@@ -26,11 +26,12 @@ namespace android {
 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

+ 23 - 23
bufferinfo/legacy/BufferInfoMaliHisi.cpp

@@ -66,33 +66,33 @@ uint64_t BufferInfoMaliHisi::ConvertGrallocFormatToDrmModifiers(
 }
 #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);
-
-  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.modifiers[0] = ConvertGrallocFormatToDrmModifiers(hnd->internal_format,
+                                                       is_rgb);
+
+  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 BufferInfoMaliHisi::ConvertBoInfo(buffer_handle_t handle,
       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

+ 1 - 1
bufferinfo/legacy/BufferInfoMaliHisi.h

@@ -27,7 +27,7 @@ class BufferInfoMaliHisi : 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, bool is_rgb);

+ 15 - 15
bufferinfo/legacy/BufferInfoMaliMediatek.cpp

@@ -32,26 +32,26 @@ namespace android {
 
 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;
-
-  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;
-
-  return 0;
+    return {};
+
+  BufferInfo bi{};
+
+  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

+ 1 - 1
bufferinfo/legacy/BufferInfoMaliMediatek.h

@@ -27,7 +27,7 @@ class BufferInfoMaliMediatek : 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;
 };
 }  // namespace android
 

+ 15 - 15
bufferinfo/legacy/BufferInfoMaliMeson.cpp

@@ -61,32 +61,32 @@ uint64_t BufferInfoMaliMeson::ConvertGrallocFormatToDrmModifiers(
 }
 #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

+ 1 - 1
bufferinfo/legacy/BufferInfoMaliMeson.h

@@ -26,7 +26,7 @@ namespace android {
 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);

+ 17 - 17
bufferinfo/legacy/BufferInfoMinigbm.cpp

@@ -43,11 +43,14 @@ struct cros_gralloc0_buffer_info {
   int stride[4];
 };
 
-int BufferInfoMinigbm::ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) {
+auto BufferInfoMinigbm::GetBoInfo(buffer_handle_t handle)
+    -> std::optional<BufferInfo> {
   if (handle == nullptr) {
-    return -EINVAL;
+    return {};
   }
 
+  BufferInfo bi{};
+
   uint32_t width{};
   uint32_t height{};
   if (gralloc_->perform(gralloc_, CROS_GRALLOC_DRM_GET_DIMENSIONS, handle,
@@ -55,7 +58,7 @@ int BufferInfoMinigbm::ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) {
     ALOGE(
         "CROS_GRALLOC_DRM_GET_DIMENSIONS operation has failed. "
         "Please ensure you are using the latest minigbm.");
-    return -EINVAL;
+    return {};
   }
 
   int32_t droid_format{};
@@ -64,7 +67,7 @@ int BufferInfoMinigbm::ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) {
     ALOGE(
         "CROS_GRALLOC_DRM_GET_FORMAT operation has failed. "
         "Please ensure you are using the latest minigbm.");
-    return -EINVAL;
+    return {};
   }
 
   uint32_t usage{};
@@ -73,7 +76,7 @@ int BufferInfoMinigbm::ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) {
     ALOGE(
         "CROS_GRALLOC_DRM_GET_USAGE operation has failed. "
         "Please ensure you are using the latest minigbm.");
-    return -EINVAL;
+    return {};
   }
 
   struct cros_gralloc0_buffer_info info {};
@@ -82,25 +85,22 @@ int BufferInfoMinigbm::ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) {
     ALOGE(
         "CROS_GRALLOC_DRM_GET_BUFFER_INFO operation has failed. "
         "Please ensure you are using the latest minigbm.");
-    return -EINVAL;
+    return {};
   }
 
-  bo->width = width;
-  bo->height = height;
+  bi.width = width;
+  bi.height = height;
 
-  bo->hal_format = droid_format;
-
-  bo->format = info.drm_fourcc;
-  bo->usage = usage;
+  bi.format = info.drm_fourcc;
 
   for (int i = 0; i < info.num_fds; i++) {
-    bo->modifiers[i] = info.modifier;
-    bo->prime_fds[i] = info.fds[i];
-    bo->pitches[i] = info.stride[i];
-    bo->offsets[i] = info.offset[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 0;
+  return bi;
 }
 
 constexpr char cros_gralloc_module_name[] = "CrOS Gralloc";

+ 1 - 1
bufferinfo/legacy/BufferInfoMinigbm.h

@@ -26,7 +26,7 @@ namespace android {
 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;
 };
 

+ 1 - 1
compositor/DrmKmsPlan.cpp

@@ -24,7 +24,7 @@
 
 namespace android {
 auto DrmKmsPlan::CreateDrmKmsPlan(DrmDisplayPipeline &pipe,
-                                  std::vector<DrmHwcLayer> composition)
+                                  std::vector<LayerData> composition)
     -> std::unique_ptr<DrmKmsPlan> {
   auto plan = std::make_unique<DrmKmsPlan>();
 

+ 3 - 3
compositor/DrmKmsPlan.h

@@ -20,7 +20,7 @@
 #include <memory>
 #include <vector>
 
-#include "drmhwcomposer.h"
+#include "LayerData.h"
 
 namespace android {
 
@@ -28,7 +28,7 @@ class DrmDevice;
 
 struct DrmKmsPlan {
   struct LayerToPlaneJoining {
-    DrmHwcLayer layer;
+    LayerData layer;
     std::shared_ptr<BindingOwner<DrmPlane>> plane;
     int z_pos;
   };
@@ -36,7 +36,7 @@ struct DrmKmsPlan {
   std::vector<LayerToPlaneJoining> plan;
 
   static auto CreateDrmKmsPlan(DrmDisplayPipeline &pipe,
-                               std::vector<DrmHwcLayer> composition)
+                               std::vector<LayerData> composition)
       -> std::unique_ptr<DrmKmsPlan>;
 };
 

+ 81 - 0
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

+ 118 - 19
drm/DrmAtomicStateManager.cpp

@@ -14,6 +14,8 @@
  * 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"
 
@@ -26,6 +28,7 @@
 #include <utils/Trace.h>
 
 #include <array>
+#include <cassert>
 #include <cstdlib>
 #include <ctime>
 #include <sstream>
@@ -70,13 +73,15 @@ auto DrmAtomicStateManager::CommitFrame(AtomicCommitArgs &args) -> int {
     return -ENOMEM;
   }
 
-  int64_t out_fence = -1;
-  if (crtc->GetOutFencePtrProperty() &&
-      !crtc->GetOutFencePtrProperty().AtomicSet(*pset, uint64_t(&out_fence))) {
+  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())) {
@@ -100,14 +105,13 @@ auto DrmAtomicStateManager::CommitFrame(AtomicCommitArgs &args) -> int {
   auto unused_planes = new_frame_state.used_planes;
 
   if (args.composition) {
-    new_frame_state.used_framebuffers.clear();
     new_frame_state.used_planes.clear();
 
     for (auto &joining : args.composition->plan) {
       DrmPlane *plane = joining.plane->Get();
-      DrmHwcLayer &layer = joining.layer;
+      LayerData &layer = joining.layer;
 
-      new_frame_state.used_framebuffers.emplace_back(layer.fb_id_handle);
+      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 */
@@ -130,31 +134,126 @@ auto DrmAtomicStateManager::CommitFrame(AtomicCommitArgs &args) -> int {
   }
 
   uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
-  if (args.test_only)
-    flags |= DRM_MODE_ATOMIC_TEST_ONLY;
+
+  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) {
-    if (!args.test_only)
-      ALOGE("Failed to commit pset ret=%d\n", err);
+    ALOGE("Failed to commit pset ret=%d\n", err);
     return err;
   }
 
-  if (!args.test_only) {
-    if (args.display_mode) {
-      /* TODO(nobody): we still need this for synthetic vsync, remove after
-       * vsync reworked */
-      connector->SetActiveMode(*args.display_mode);
+  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;
+      }
     }
 
-    active_frame_state_ = std::move(new_frame_state);
+    {
+      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);
+      }
+    }
 
-    if (crtc->GetOutFencePtrProperty()) {
-      args.out_fence = UniqueFd((int)out_fence);
+    {
+      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();
+      }
     }
   }
+}
 
-  return 0;
+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 {

+ 52 - 6
drm/DrmAtomicStateManager.h

@@ -26,10 +26,10 @@
 #include <tuple>
 
 #include "compositor/DrmKmsPlan.h"
+#include "compositor/LayerData.h"
 #include "drm/DrmPlane.h"
 #include "drm/ResourceManager.h"
 #include "drm/VSyncWorker.h"
-#include "drmhwcomposer.h"
 
 namespace android {
 
@@ -49,11 +49,45 @@ struct AtomicCommitArgs {
   }
 };
 
+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){};
+  explicit DrmAtomicStateManager(DrmDisplayPipeline *pipe)
+      : pipe_(pipe),
+        ptt_(std::make_unique<PresentTrackerThread>(this).release()){};
+
   DrmAtomicStateManager(const DrmAtomicStateManager &) = delete;
-  ~DrmAtomicStateManager() = default;
+  ~DrmAtomicStateManager() {
+    ptt_->Stop();
+  }
 
   auto ExecuteAtomicCommit(AtomicCommitArgs &args) -> int;
   auto ActivateDisplayUsingDPMS() -> int;
@@ -70,20 +104,32 @@ class DrmAtomicStateManager {
 
     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 = active_frame_state_.used_planes,
-        .used_framebuffers = active_frame_state_.used_framebuffers,
-        .crtc_active_state = active_frame_state_.crtc_active_state,
+        .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_

+ 18 - 2
drm/DrmDevice.cpp

@@ -18,7 +18,6 @@
 
 #include "DrmDevice.h"
 
-#include <fcntl.h>
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 
@@ -28,12 +27,29 @@
 
 #include "drm/DrmAtomicStateManager.h"
 #include "drm/DrmPlane.h"
+#include "drm/ResourceManager.h"
 #include "utils/log.h"
 #include "utils/properties.h"
 
 namespace android {
 
-DrmDevice::DrmDevice() {
+auto DrmDevice::CreateInstance(std::string const &path,
+                               ResourceManager *res_man)
+    -> std::unique_ptr<DrmDevice> {
+  if (!IsKMSDev(path.c_str())) {
+    return {};
+  }
+
+  auto device = std::unique_ptr<DrmDevice>(new DrmDevice(res_man));
+
+  if (device->Init(path.c_str()) != 0) {
+    return {};
+  }
+
+  return device;
+}
+
+DrmDevice::DrmDevice(ResourceManager *res_man) : res_man_(res_man) {
   drm_fb_importer_ = std::make_unique<DrmFbImporter>(*this);
 }
 

+ 14 - 4
drm/DrmDevice.h

@@ -31,18 +31,23 @@ namespace android {
 
 class DrmFbImporter;
 class DrmPlane;
+class ResourceManager;
 
 class DrmDevice {
  public:
-  DrmDevice();
   ~DrmDevice() = default;
 
-  auto Init(const char *path) -> int;
+  static auto CreateInstance(std::string const &path, ResourceManager *res_man)
+      -> std::unique_ptr<DrmDevice>;
 
   auto GetFd() const {
     return fd_.Get();
   }
 
+  auto &GetResMan() {
+    return *res_man_;
+  }
+
   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>> &;
@@ -69,8 +74,6 @@ class DrmDevice {
     return *drm_fb_importer_;
   }
 
-  static auto IsKMSDev(const char *path) -> bool;
-
   auto FindCrtcById(uint32_t id) const -> DrmCrtc * {
     for (const auto &crtc : crtcs_) {
       if (crtc->GetId() == id) {
@@ -95,6 +98,11 @@ class DrmDevice {
                   DrmProperty *property) const;
 
  private:
+  explicit DrmDevice(ResourceManager *res_man);
+  auto Init(const char *path) -> int;
+
+  static auto IsKMSDev(const char *path) -> bool;
+
   UniqueFd fd_;
 
   std::vector<std::unique_ptr<DrmConnector>> connectors_;
@@ -109,6 +117,8 @@ class DrmDevice {
   bool HasAddFb2ModifiersSupport_{};
 
   std::unique_ptr<DrmFbImporter> drm_fb_importer_;
+
+  ResourceManager *const res_man_;
 };
 }  // namespace android
 

+ 11 - 4
drm/DrmFbImporter.cpp

@@ -14,12 +14,15 @@
  * limitations under the License.
  */
 
+// 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,
+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));
 
@@ -69,11 +74,11 @@ auto DrmFbIdHandle::CreateInstance(hwc_drm_bo_t *bo, GemHandle first_gem_handle,
   /* Create framebuffer object */
   if (!has_modifiers) {
     err = drmModeAddFB2(drm.GetFd(), bo->width, bo->height, bo->format,
-                        &local->gem_handles_[0], &bo->pitches[0],
+                        local->gem_handles_.data(), &bo->pitches[0],
                         &bo->offsets[0], &local->fb_id_, 0);
   } else {
     err = drmModeAddFB2WithModifiers(drm.GetFd(), bo->width, bo->height,
-                                     bo->format, &local->gem_handles_[0],
+                                     bo->format, local->gem_handles_.data(),
                                      &bo->pitches[0], &bo->offsets[0],
                                      &bo->modifiers[0], &local->fb_id_,
                                      DRM_MODE_FB_MODIFIERS);
@@ -87,6 +92,8 @@ auto DrmFbIdHandle::CreateInstance(hwc_drm_bo_t *bo, GemHandle first_gem_handle,
 }
 
 DrmFbIdHandle::~DrmFbIdHandle() {
+  ATRACE_NAME("Close FB and dmabufs");
+
   /* Destroy framebuffer object */
   if (drmModeRmFB(drm_->GetFd(), fb_id_) != 0) {
     ALOGE("Failed to rm fb");
@@ -116,7 +123,7 @@ DrmFbIdHandle::~DrmFbIdHandle() {
   }
 }
 
-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;

+ 4 - 4
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,7 +36,7 @@ namespace android {
 
 class DrmFbIdHandle {
  public:
-  static auto CreateInstance(hwc_drm_bo_t *bo, GemHandle first_gem_handle,
+  static auto CreateInstance(BufferInfo *bo, GemHandle first_gem_handle,
                              DrmDevice &drm) -> std::shared_ptr<DrmFbIdHandle>;
 
   ~DrmFbIdHandle();
@@ -55,7 +55,7 @@ class DrmFbIdHandle {
   DrmDevice *const drm_;
 
   uint32_t fb_id_{};
-  std::array<GemHandle, kHwcDrmBoMaxPlanes> gem_handles_{};
+  std::array<GemHandle, kBufferMaxPlanes> gem_handles_{};
 };
 
 class DrmFbImporter {
@@ -67,7 +67,7 @@ class DrmFbImporter {
   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() {

+ 50 - 51
drm/DrmPlane.cpp

@@ -91,17 +91,17 @@ int DrmPlane::Init() {
   GetPlaneProperty("zpos", zpos_property_, Presence::kOptional);
 
   if (GetPlaneProperty("rotation", rotation_property_, Presence::kOptional)) {
-    rotation_property_.AddEnumToMap("rotate-0", DrmHwcTransform::kIdentity,
+    rotation_property_.AddEnumToMap("rotate-0", LayerTransform::kIdentity,
                                     transform_enum_map_);
-    rotation_property_.AddEnumToMap("rotate-90", DrmHwcTransform::kRotate90,
+    rotation_property_.AddEnumToMap("rotate-90", LayerTransform::kRotate90,
                                     transform_enum_map_);
-    rotation_property_.AddEnumToMap("rotate-180", DrmHwcTransform::kRotate180,
+    rotation_property_.AddEnumToMap("rotate-180", LayerTransform::kRotate180,
                                     transform_enum_map_);
-    rotation_property_.AddEnumToMap("rotate-270", DrmHwcTransform::kRotate270,
+    rotation_property_.AddEnumToMap("rotate-270", LayerTransform::kRotate270,
                                     transform_enum_map_);
-    rotation_property_.AddEnumToMap("reflect-x", DrmHwcTransform::kFlipH,
+    rotation_property_.AddEnumToMap("reflect-x", LayerTransform::kFlipH,
                                     transform_enum_map_);
-    rotation_property_.AddEnumToMap("reflect-y", DrmHwcTransform::kFlipV,
+    rotation_property_.AddEnumToMap("reflect-y", LayerTransform::kFlipV,
                                     transform_enum_map_);
   }
 
@@ -109,11 +109,11 @@ int DrmPlane::Init() {
 
   if (GetPlaneProperty("pixel blend mode", blend_property_,
                        Presence::kOptional)) {
-    blend_property_.AddEnumToMap("Pre-multiplied", DrmHwcBlending::kPreMult,
+    blend_property_.AddEnumToMap("Pre-multiplied", BufferBlendMode::kPreMult,
                                  blending_enum_map_);
-    blend_property_.AddEnumToMap("Coverage", DrmHwcBlending::kCoverage,
+    blend_property_.AddEnumToMap("Coverage", BufferBlendMode::kCoverage,
                                  blending_enum_map_);
-    blend_property_.AddEnumToMap("None", DrmHwcBlending::kNone,
+    blend_property_.AddEnumToMap("None", BufferBlendMode::kNone,
                                  blending_enum_map_);
   }
 
@@ -123,23 +123,23 @@ int DrmPlane::Init() {
     if (GetPlaneProperty("COLOR_ENCODING", color_encoding_propery_,
                          Presence::kOptional)) {
       color_encoding_propery_.AddEnumToMap("ITU-R BT.709 YCbCr",
-                                           DrmHwcColorSpace::kItuRec709,
+                                           BufferColorSpace::kItuRec709,
                                            color_encoding_enum_map_);
       color_encoding_propery_.AddEnumToMap("ITU-R BT.601 YCbCr",
-                                           DrmHwcColorSpace::kItuRec601,
+                                           BufferColorSpace::kItuRec601,
                                            color_encoding_enum_map_);
       color_encoding_propery_.AddEnumToMap("ITU-R BT.2020 YCbCr",
-                                           DrmHwcColorSpace::kItuRec2020,
+                                           BufferColorSpace::kItuRec2020,
                                            color_encoding_enum_map_);
     }
 
     if (GetPlaneProperty("COLOR_RANGE", color_range_property_,
                          Presence::kOptional)) {
       color_range_property_.AddEnumToMap("YCbCr full range",
-                                         DrmHwcSampleRange::kFullRange,
+                                         BufferSampleRange::kFullRange,
                                          color_range_enum_map_);
       color_range_property_.AddEnumToMap("YCbCr limited range",
-                                         DrmHwcSampleRange::kLimitedRange,
+                                         BufferSampleRange::kLimitedRange,
                                          color_range_enum_map_);
     }
   }
@@ -151,32 +151,32 @@ bool DrmPlane::IsCrtcSupported(const DrmCrtc &crtc) const {
   return ((1 << crtc.GetIndexInResArray()) & plane_->possible_crtcs) != 0;
 }
 
-bool DrmPlane::IsValidForLayer(DrmHwcLayer *layer) {
+bool DrmPlane::IsValidForLayer(LayerData *layer) {
   if (!rotation_property_) {
-    if (layer->transform != DrmHwcTransform::kIdentity) {
+    if (layer->pi.transform != LayerTransform::kIdentity) {
       ALOGV("No rotation property on plane %d", GetId());
       return false;
     }
   } else {
-    if (transform_enum_map_.count(layer->transform) == 0) {
+    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 != UINT16_MAX) {
+  if (alpha_property_.id() == 0 && layer->pi.alpha != UINT16_MAX) {
     ALOGV("Alpha is not supported on plane %d", GetId());
     return false;
   }
 
-  if (blending_enum_map_.count(layer->blending) == 0 &&
-      layer->blending != DrmHwcBlending::kNone &&
-      layer->blending != DrmHwcBlending::kPreMult) {
+  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", GetId(), format,
           format >> 8, format >> 16, format >> 24);
@@ -198,17 +198,17 @@ bool DrmPlane::HasNonRgbFormat() const {
                           }) != std::end(formats_);
 }
 
-static uint64_t ToDrmRotation(DrmHwcTransform transform) {
+static uint64_t ToDrmRotation(LayerTransform transform) {
   uint64_t rotation = 0;
-  if ((transform & DrmHwcTransform::kFlipH) != 0)
+  if ((transform & LayerTransform::kFlipH) != 0)
     rotation |= DRM_MODE_REFLECT_X;
-  if ((transform & DrmHwcTransform::kFlipV) != 0)
+  if ((transform & LayerTransform::kFlipV) != 0)
     rotation |= DRM_MODE_REFLECT_Y;
-  if ((transform & DrmHwcTransform::kRotate90) != 0)
+  if ((transform & LayerTransform::kRotate90) != 0)
     rotation |= DRM_MODE_ROTATE_90;
-  else if ((transform & DrmHwcTransform::kRotate180) != 0)
+  else if ((transform & LayerTransform::kRotate180) != 0)
     rotation |= DRM_MODE_ROTATE_180;
-  else if ((transform & DrmHwcTransform::kRotate270) != 0)
+  else if ((transform & LayerTransform::kRotate270) != 0)
     rotation |= DRM_MODE_ROTATE_270;
   else
     rotation |= DRM_MODE_ROTATE_0;
@@ -222,9 +222,9 @@ static int To1616FixPt(float in) {
   return int(in * (1 << kBitShift));
 }
 
-auto DrmPlane::AtomicSetState(drmModeAtomicReq &pset, DrmHwcLayer &layer,
+auto DrmPlane::AtomicSetState(drmModeAtomicReq &pset, LayerData &layer,
                               uint32_t zpos, uint32_t crtc_id) -> int {
-  if (!layer.fb_id_handle) {
+  if (!layer.fb) {
     ALOGE("Expected a valid framebuffer for pset");
     return -EINVAL;
   }
@@ -245,46 +245,45 @@ auto DrmPlane::AtomicSetState(drmModeAtomicReq &pset, DrmHwcLayer &layer,
     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_id_handle->GetFbId()) ||
-      !crtc_x_property_.AtomicSet(pset, layer.display_frame.left) ||
-      !crtc_y_property_.AtomicSet(pset, layer.display_frame.top) ||
-      !crtc_w_property_.AtomicSet(pset, layer.display_frame.right -
-                                            layer.display_frame.left) ||
-      !crtc_h_property_.AtomicSet(pset, layer.display_frame.bottom -
-                                            layer.display_frame.top) ||
-      !src_x_property_.AtomicSet(pset, To1616FixPt(layer.source_crop.left)) ||
-      !src_y_property_.AtomicSet(pset, To1616FixPt(layer.source_crop.top)) ||
-      !src_w_property_.AtomicSet(pset, To1616FixPt(layer.source_crop.right -
-                                                   layer.source_crop.left)) ||
-      !src_h_property_.AtomicSet(pset, To1616FixPt(layer.source_crop.bottom -
-                                                   layer.source_crop.top))) {
+      !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.transform))) {
+      !rotation_property_.AtomicSet(pset, ToDrmRotation(layer.pi.transform))) {
     return -EINVAL;
   }
 
-  if (alpha_property_ && !alpha_property_.AtomicSet(pset, layer.alpha)) {
+  if (alpha_property_ && !alpha_property_.AtomicSet(pset, layer.pi.alpha)) {
     return -EINVAL;
   }
 
-  if (blending_enum_map_.count(layer.blending) != 0 &&
-      !blend_property_.AtomicSet(pset, blending_enum_map_[layer.blending])) {
+  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.color_space) != 0 &&
+  if (color_encoding_enum_map_.count(layer.bi->color_space) != 0 &&
       !color_encoding_propery_
-           .AtomicSet(pset, color_encoding_enum_map_[layer.color_space])) {
+           .AtomicSet(pset, color_encoding_enum_map_[layer.bi->color_space])) {
     return -EINVAL;
   }
 
-  if (color_range_enum_map_.count(layer.sample_range) != 0 &&
+  if (color_range_enum_map_.count(layer.bi->sample_range) != 0 &&
       !color_range_property_
-           .AtomicSet(pset, color_range_enum_map_[layer.sample_range])) {
+           .AtomicSet(pset, color_range_enum_map_[layer.bi->sample_range])) {
     return -EINVAL;
   }
 

+ 8 - 8
drm/DrmPlane.h

@@ -24,12 +24,12 @@
 
 #include "DrmCrtc.h"
 #include "DrmProperty.h"
-#include "drmhwcomposer.h"
+#include "compositor/LayerData.h"
 
 namespace android {
 
 class DrmDevice;
-struct DrmHwcLayer;
+struct LayerData;
 
 class DrmPlane : public PipelineBindable<DrmPlane> {
  public:
@@ -40,7 +40,7 @@ class DrmPlane : public PipelineBindable<DrmPlane> {
       -> std::unique_ptr<DrmPlane>;
 
   bool IsCrtcSupported(const DrmCrtc &crtc) const;
-  bool IsValidForLayer(DrmHwcLayer *layer);
+  bool IsValidForLayer(LayerData *layer);
 
   auto GetType() const {
     return type_;
@@ -49,7 +49,7 @@ class DrmPlane : public PipelineBindable<DrmPlane> {
   bool IsFormatSupported(uint32_t format) const;
   bool HasNonRgbFormat() const;
 
-  auto AtomicSetState(drmModeAtomicReq &pset, DrmHwcLayer &layer, uint32_t zpos,
+  auto AtomicSetState(drmModeAtomicReq &pset, LayerData &layer, uint32_t zpos,
                       uint32_t crtc_id) -> int;
   auto AtomicDisablePlane(drmModeAtomicReq &pset) -> int;
   auto &GetZPosProperty() const {
@@ -94,10 +94,10 @@ class DrmPlane : public PipelineBindable<DrmPlane> {
   DrmProperty color_encoding_propery_;
   DrmProperty color_range_property_;
 
-  std::map<DrmHwcBlending, uint64_t> blending_enum_map_;
-  std::map<DrmHwcColorSpace, uint64_t> color_encoding_enum_map_;
-  std::map<DrmHwcSampleRange, uint64_t> color_range_enum_map_;
-  std::map<DrmHwcTransform, uint64_t> transform_enum_map_;
+  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
 

+ 11 - 13
drm/ResourceManager.cpp

@@ -18,7 +18,6 @@
 
 #include "ResourceManager.h"
 
-#include <fcntl.h>
 #include <sys/stat.h>
 
 #include <ctime>
@@ -58,7 +57,10 @@ void ResourceManager::Init() {
   int path_len = property_get("vendor.hwc.drm.device", path_pattern,
                               "/dev/dri/card%");
   if (path_pattern[path_len - 1] != '%') {
-    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;; ++idx) {
@@ -69,8 +71,9 @@ void ResourceManager::Init() {
       if (stat(path.str().c_str(), &buf) != 0)
         break;
 
-      if (DrmDevice::IsKMSDev(path.str().c_str())) {
-        AddDrmDevice(path.str());
+      auto dev = DrmDevice::CreateInstance(path.str(), this);
+      if (dev) {
+        drms_.emplace_back(std::move(dev));
       }
     }
   }
@@ -108,13 +111,6 @@ void ResourceManager::DeInit() {
   initialized_ = false;
 }
 
-int ResourceManager::AddDrmDevice(const std::string &path) {
-  auto drm = std::make_unique<DrmDevice>();
-  int ret = drm->Init(path.c_str());
-  drms_.push_back(std::move(drm));
-  return ret;
-}
-
 auto ResourceManager::GetTimeMonotonicNs() -> int64_t {
   struct timespec ts {};
   clock_gettime(CLOCK_MONOTONIC, &ts);
@@ -136,8 +132,10 @@ void ResourceManager::UpdateFrontendDisplays() {
 
       if (connected) {
         auto pipeline = DrmDisplayPipeline::CreatePipeline(*conn);
-        frontend_interface_->BindDisplay(pipeline.get());
-        attached_pipelines_[conn] = std::move(pipeline);
+        if (pipeline) {
+          frontend_interface_->BindDisplay(pipeline.get());
+          attached_pipelines_[conn] = std::move(pipeline);
+        }
       } else {
         auto &pipeline = attached_pipelines_[conn];
         frontend_interface_->UnbindDisplay(pipeline.get());

+ 0 - 1
drm/ResourceManager.h

@@ -59,7 +59,6 @@ class ResourceManager {
   static auto GetTimeMonotonicNs() -> int64_t;
 
  private:
-  auto AddDrmDevice(std::string const &path) -> int;
   auto GetOrderedConnectors() -> std::vector<DrmConnector *>;
   void UpdateFrontendDisplays();
   void DetachAllFrontendDisplays();

+ 1 - 1
drm/VSyncWorker.cpp

@@ -92,7 +92,7 @@ int VSyncWorker::SyntheticWaitVBlank(int64_t *timestamp) {
   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;
 

+ 8 - 2
hwc2_device/DrmHwcTwo.cpp

@@ -177,8 +177,14 @@ HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
         resource_manager_.Init();
       } else {
         resource_manager_.DeInit();
-        /* Headless display may still be here, remove it */
-        displays_.erase(kPrimaryDisplay);
+        /* 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;
     }

+ 116 - 51
hwc2_device/HwcDisplay.cpp

@@ -90,6 +90,7 @@ HwcDisplay::HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type,
     : 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,
@@ -102,24 +103,51 @@ HwcDisplay::HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type,
 HwcDisplay::~HwcDisplay() = default;
 
 void HwcDisplay::SetPipeline(DrmDisplayPipeline *pipeline) {
+  Deinit();
+
   pipeline_ = pipeline;
 
-  if (pipeline != nullptr) {
-    ChosePreferredConfig();
+  if (pipeline != nullptr || handle_ == kPrimaryDisplay) {
     Init();
-
     hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ true);
   } else {
-    backend_.reset();
+    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) {});
-    SetClientTarget(nullptr, -1, 0, {});
-    if (handle_ != kPrimaryDisplay) {
-      hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ false);
-    }
+    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_) {
@@ -176,7 +204,7 @@ HWC2::Error HwcDisplay::AcceptDisplayChanges() {
 }
 
 HWC2::Error HwcDisplay::CreateLayer(hwc2_layer_t *layer) {
-  layers_.emplace(static_cast<hwc2_layer_t>(layer_idx_), HwcLayer());
+  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;
@@ -379,6 +407,9 @@ HWC2::Error HwcDisplay::GetHdrCapabilities(uint32_t *num_types,
 
 /* 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,
@@ -390,8 +421,13 @@ HWC2::Error HwcDisplay::GetReleaseFences(uint32_t *num_elements,
 
   uint32_t num_layers = 0;
 
-  for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) {
+  for (auto &l : layers_) {
+    if (!l.second.GetPriorBufferScanOutFlag() || !present_fence_) {
+      continue;
+    }
+
     ++num_layers;
+
     if (layers == nullptr || fences == nullptr)
       continue;
 
@@ -401,9 +437,10 @@ HWC2::Error HwcDisplay::GetReleaseFences(uint32_t *num_elements,
     }
 
     layers[num_layers - 1] = l.first;
-    fences[num_layers - 1] = l.second.GetReleaseFence().Release();
+    fences[num_layers - 1] = UniqueFd::Dup(present_fence_.Get()).Release();
   }
   *num_elements = num_layers;
+
   return HWC2::Error::None;
 }
 
@@ -457,18 +494,26 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
   if (z_map.empty())
     return HWC2::Error::BadLayer;
 
-  std::vector<DrmHwcLayer> composition_layers;
+  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) {
-    DrmHwcLayer layer;
-    l.second->PopulateDrmLayer(&layer);
-    int ret = layer.ImportBuffer(GetPipe().device);
-    if (ret) {
-      ALOGE("Failed to import layer, ret=%d", ret);
-      return HWC2::Error::NoResources;
+    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(std::move(layer));
+    composition_layers.emplace_back(l.second->GetLayerData().Clone());
   }
 
   /* Store plan to ensure shared planes won't be stolen by other display
@@ -508,9 +553,9 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
 /* 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 *present_fence) {
+HWC2::Error HwcDisplay::PresentDisplay(int32_t *out_present_fence) {
   if (IsInHeadlessMode()) {
-    *present_fence = -1;
+    *out_present_fence = -1;
     return HWC2::Error::None;
   }
   HWC2::Error ret{};
@@ -525,13 +570,14 @@ HWC2::Error HwcDisplay::PresentDisplay(int32_t *present_fence) {
 
   if (ret == HWC2::Error::BadLayer) {
     // Can we really have no client or device layers?
-    *present_fence = -1;
+    *out_present_fence = -1;
     return HWC2::Error::None;
   }
   if (ret != HWC2::Error::None)
     return ret;
 
-  *present_fence = a_args.out_fence.Release();
+  this->present_fence_ = UniqueFd::Dup(a_args.out_fence.Get());
+  *out_present_fence = a_args.out_fence.Release();
 
   ++frame_no_;
   return HWC2::Error::None;
@@ -571,18 +617,25 @@ HWC2::Error HwcDisplay::SetClientTarget(buffer_handle_t target,
    * 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;
   }
 
-  /* TODO: Do not update source_crop every call.
-   * It makes sense to do it once after every hotplug event. */
-  HwcDrmBo bo{};
-  BufferInfoGetter::GetInstance()->ConvertBoInfo(target, &bo);
+  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>(bo.width),
-                             .bottom = static_cast<float>(bo.height)};
+                             .right = static_cast<float>(bi->width),
+                             .bottom = static_cast<float>(bi->height)};
   client_layer_.SetLayerSourceCrop(source_crop);
 
   return HWC2::Error::None;
@@ -621,11 +674,8 @@ HWC2::Error HwcDisplay::SetOutputBuffer(buffer_handle_t /*buffer*/,
 }
 
 HWC2::Error HwcDisplay::SetPowerMode(int32_t mode_in) {
-  if (IsInHeadlessMode()) {
-    return HWC2::Error::None;
-  }
-
   auto mode = static_cast<HWC2::PowerMode>(mode_in);
+
   AtomicCommitArgs a_args{};
 
   switch (mode) {
@@ -633,22 +683,30 @@ HWC2::Error HwcDisplay::SetPowerMode(int32_t mode_in) {
       a_args.active = false;
       break;
     case HWC2::PowerMode::On:
-      /*
-       * 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;
+      a_args.active = true;
       break;
     case HWC2::PowerMode::Doze:
     case HWC2::PowerMode::DozeSuspend:
       return HWC2::Error::Unsupported;
     default:
-      ALOGI("Power mode %d is unsupported\n", mode);
+      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);
@@ -673,6 +731,16 @@ HWC2::Error HwcDisplay::ValidateDisplay(uint32_t *num_types,
     *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);
 }
 
@@ -782,19 +850,16 @@ HWC2::Error HwcDisplay::GetDisplayIdentificationData(uint8_t *outPort,
                                                      uint32_t *outDataSize,
                                                      uint8_t *outData) {
   if (IsInHeadlessMode()) {
-    return HWC2::Error::None;
+    return HWC2::Error::Unsupported;
   }
-  auto blob = GetPipe().connector->Get()->GetEdidBlob();
-
-  *outPort = handle_ - 1;
 
+  auto blob = GetPipe().connector->Get()->GetEdidBlob();
   if (!blob) {
-    if (outData == nullptr) {
-      *outDataSize = 0;
-    }
-    return HWC2::Error::None;
+    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);

+ 6 - 2
hwc2_device/HwcDisplay.h

@@ -22,10 +22,10 @@
 #include <optional>
 
 #include "HwcDisplayConfigs.h"
+#include "compositor/LayerData.h"
 #include "drm/DrmAtomicStateManager.h"
 #include "drm/ResourceManager.h"
 #include "drm/VSyncWorker.h"
-#include "drmhwcomposer.h"
 #include "hwc2_device/HwcLayer.h"
 
 namespace android {
@@ -106,7 +106,7 @@ class HwcDisplay {
                                  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 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,
@@ -180,6 +180,8 @@ class HwcDisplay {
     return !pipeline_;
   }
 
+  void Deinit();
+
  private:
   enum ClientFlattenningState : int32_t {
     Disabled = -3,
@@ -197,6 +199,8 @@ class HwcDisplay {
 
   DrmHwcTwo *const hwc2_;
 
+  UniqueFd present_fence_;
+
   std::optional<DrmMode> staged_mode_;
   int64_t staged_mode_change_time_{};
   uint32_t staged_mode_config_id_{};

+ 150 - 36
hwc2_device/HwcLayer.cpp

@@ -18,8 +18,8 @@
 
 #include "HwcLayer.h"
 
-#include <fcntl.h>
-
+#include "HwcDisplay.h"
+#include "bufferinfo/BufferInfoGetter.h"
 #include "utils/log.h"
 
 namespace android {
@@ -32,17 +32,17 @@ HWC2::Error HwcLayer::SetCursorPosition(int32_t /*x*/, int32_t /*y*/) {
 HWC2::Error HwcLayer::SetLayerBlendMode(int32_t mode) {
   switch (static_cast<HWC2::BlendMode>(mode)) {
     case HWC2::BlendMode::None:
-      blending_ = DrmHwcBlending::kNone;
+      blend_mode_ = BufferBlendMode::kNone;
       break;
     case HWC2::BlendMode::Premultiplied:
-      blending_ = DrmHwcBlending::kPreMult;
+      blend_mode_ = BufferBlendMode::kPreMult;
       break;
     case HWC2::BlendMode::Coverage:
-      blending_ = DrmHwcBlending::kCoverage;
+      blend_mode_ = BufferBlendMode::kCoverage;
       break;
     default:
-      ALOGE("Unknown blending mode b=%d", blending_);
-      blending_ = DrmHwcBlending::kNone;
+      ALOGE("Unknown blending mode b=%d", blend_mode_);
+      blend_mode_ = BufferBlendMode::kUndefined;
       break;
   }
   return HWC2::Error::None;
@@ -53,8 +53,10 @@ HWC2::Error HwcLayer::SetLayerBlendMode(int32_t mode) {
  */
 HWC2::Error HwcLayer::SetLayerBuffer(buffer_handle_t buffer,
                                      int32_t acquire_fence) {
-  buffer_ = buffer;
   acquire_fence_ = UniqueFd(acquire_fence);
+  buffer_handle_ = buffer;
+  buffer_handle_updated_ = true;
+
   return HWC2::Error::None;
 }
 
@@ -72,54 +74,54 @@ HWC2::Error HwcLayer::SetLayerCompositionType(int32_t type) {
 HWC2::Error HwcLayer::SetLayerDataspace(int32_t dataspace) {
   switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
     case HAL_DATASPACE_STANDARD_BT709:
-      color_space_ = DrmHwcColorSpace::kItuRec709;
+      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_ = DrmHwcColorSpace::kItuRec601;
+      color_space_ = BufferColorSpace::kItuRec601;
       break;
     case HAL_DATASPACE_STANDARD_BT2020:
     case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
-      color_space_ = DrmHwcColorSpace::kItuRec2020;
+      color_space_ = BufferColorSpace::kItuRec2020;
       break;
     default:
-      color_space_ = DrmHwcColorSpace::kUndefined;
+      color_space_ = BufferColorSpace::kUndefined;
   }
 
   switch (dataspace & HAL_DATASPACE_RANGE_MASK) {
     case HAL_DATASPACE_RANGE_FULL:
-      sample_range_ = DrmHwcSampleRange::kFullRange;
+      sample_range_ = BufferSampleRange::kFullRange;
       break;
     case HAL_DATASPACE_RANGE_LIMITED:
-      sample_range_ = DrmHwcSampleRange::kLimitedRange;
+      sample_range_ = BufferSampleRange::kLimitedRange;
       break;
     default:
-      sample_range_ = DrmHwcSampleRange::kUndefined;
+      sample_range_ = BufferSampleRange::kUndefined;
   }
   return HWC2::Error::None;
 }
 
 HWC2::Error HwcLayer::SetLayerDisplayFrame(hwc_rect_t frame) {
-  display_frame_ = frame;
+  layer_data_.pi.display_frame = frame;
   return HWC2::Error::None;
 }
 
 HWC2::Error HwcLayer::SetLayerPlaneAlpha(float alpha) {
-  alpha_ = 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*/) {
+    const native_handle_t* /*stream*/) {
   // TODO(nobody): We don't support sideband
   return HWC2::Error::Unsupported;
 }
 
 HWC2::Error HwcLayer::SetLayerSourceCrop(hwc_frect_t crop) {
-  source_crop_ = crop;
+  layer_data_.pi.source_crop = crop;
   return HWC2::Error::None;
 }
 
@@ -137,19 +139,19 @@ HWC2::Error HwcLayer::SetLayerTransform(int32_t transform) {
   // redundant in this case. 90* rotation can be combined with either horizontal
   // flip or vertical flip, so treat it differently
   if (transform == HWC_TRANSFORM_ROT_270) {
-    l_transform = DrmHwcTransform::kRotate270;
+    l_transform = LayerTransform::kRotate270;
   } else if (transform == HWC_TRANSFORM_ROT_180) {
-    l_transform = DrmHwcTransform::kRotate180;
+    l_transform = LayerTransform::kRotate180;
   } else {
     if ((transform & HWC_TRANSFORM_FLIP_H) != 0)
-      l_transform |= DrmHwcTransform::kFlipH;
+      l_transform |= LayerTransform::kFlipH;
     if ((transform & HWC_TRANSFORM_FLIP_V) != 0)
-      l_transform |= DrmHwcTransform::kFlipV;
+      l_transform |= LayerTransform::kFlipV;
     if ((transform & HWC_TRANSFORM_ROT_90) != 0)
-      l_transform |= DrmHwcTransform::kRotate90;
+      l_transform |= LayerTransform::kRotate90;
   }
 
-  transform_ = static_cast<DrmHwcTransform>(l_transform);
+  layer_data_.pi.transform = static_cast<LayerTransform>(l_transform);
   return HWC2::Error::None;
 }
 
@@ -164,17 +166,129 @@ HWC2::Error HwcLayer::SetLayerZOrder(uint32_t order) {
   return HWC2::Error::None;
 }
 
-void HwcLayer::PopulateDrmLayer(DrmHwcLayer *layer) {
-  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 = std::lround(alpha_ * UINT16_MAX);
-  layer->blending = blending_;
-  layer->source_crop = source_crop_;
-  layer->transform = transform_;
-  layer->color_space = color_space_;
-  layer->sample_range = sample_range_;
+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

+ 62 - 41
hwc2_device/HwcLayer.h

@@ -19,14 +19,17 @@
 
 #include <hardware/hwcomposer2.h>
 
-#include <cmath>
-
-#include "drmhwcomposer.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_;
   }
@@ -43,35 +46,20 @@ class HwcLayer {
     return sf_type_ != validated_type_;
   }
 
-  uint32_t GetZOrder() const {
-    return z_order_;
-  }
-
-  buffer_handle_t GetBuffer() {
-    return buffer_;
+  bool GetPriorBufferScanOutFlag() const {
+    return prior_buffer_scanout_flag_;
   }
 
-  hwc_rect_t GetDisplayFrame() {
-    return display_frame_;
+  void SetPriorBufferScanOutFlag(bool state) {
+    prior_buffer_scanout_flag_ = state;
   }
 
-  UniqueFd GetReleaseFence() {
-    return std::move(release_fence_);
+  uint32_t GetZOrder() const {
+    return z_order_;
   }
 
-  void PopulateDrmLayer(DrmHwcLayer *layer);
-
-  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;
+  auto &GetLayerData() {
+    return layer_data_;
   }
 
   // Layer hooks
@@ -96,26 +84,59 @@ class HwcLayer {
   HWC2::Composition sf_type_ = HWC2::Composition::Invalid;
   HWC2::Composition validated_type_ = HWC2::Composition::Invalid;
 
-  buffer_handle_t buffer_ = nullptr;
-  hwc_rect_t display_frame_;
-  static constexpr float kOpaqueFloat = 1.0F;
-  float alpha_ = kOpaqueFloat;
-  hwc_frect_t source_crop_;
-  DrmHwcTransform transform_ = DrmHwcTransform::kIdentity;
   uint32_t z_order_ = 0;
-  DrmHwcBlending blending_ = DrmHwcBlending::kNone;
-  DrmHwcColorSpace color_space_ = DrmHwcColorSpace::kUndefined;
-  DrmHwcSampleRange sample_range_ = DrmHwcSampleRange::kUndefined;
+  LayerData layer_data_;
 
+  /* Should be populated to layer_data_.acquire_fence only before presenting */
   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.
+  /* 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
    */
-  UniqueFd release_fence_;
+  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

+ 0 - 42
include/drmhwcgralloc.h

@@ -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.
- */
-
-#ifndef ANDROID_DRMHWCGRALLOC_H_
-#define ANDROID_DRMHWCGRALLOC_H_
-
-#include <cstdint>
-
-constexpr int kHwcDrmBoMaxPlanes = 4;
-
-struct HwcDrmBo {
-  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[kHwcDrmBoMaxPlanes];
-  uint32_t offsets[kHwcDrmBoMaxPlanes];
-  /* sizes[] is used only by mapper@4 metadata getter for internal purposes */
-  uint32_t sizes[kHwcDrmBoMaxPlanes];
-  int prime_fds[kHwcDrmBoMaxPlanes];
-  uint64_t modifiers[kHwcDrmBoMaxPlanes];
-  int acquire_fence_fd;
-};
-
-// NOLINTNEXTLINE(readability-identifier-naming)
-using hwc_drm_bo_t = HwcDrmBo;
-
-#endif  // ANDROID_DRMHWCGRALLOC_H_

+ 0 - 89
include/drmhwcomposer.h

@@ -1,89 +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 <cstdbool>
-#include <cstdint>
-#include <vector>
-
-#include "drm/DrmFbImporter.h"
-#include "drmhwcgralloc.h"
-#include "utils/UniqueFd.h"
-
-namespace android {
-
-class DrmFbIdHandle;
-
-enum class DrmHwcColorSpace : int32_t {
-  kUndefined,
-  kItuRec601,
-  kItuRec709,
-  kItuRec2020,
-};
-
-enum class DrmHwcSampleRange : int32_t {
-  kUndefined,
-  kFullRange,
-  kLimitedRange,
-};
-
-enum DrmHwcTransform : uint32_t {
-  kIdentity = 0,
-  kFlipH = 1 << 0,
-  kFlipV = 1 << 1,
-  kRotate90 = 1 << 2,
-  kRotate180 = 1 << 3,
-  kRotate270 = 1 << 4,
-};
-
-enum class DrmHwcBlending : int32_t {
-  kNone,
-  kPreMult,
-  kCoverage,
-};
-
-struct DrmHwcLayer {
-  buffer_handle_t sf_handle = nullptr;
-  hwc_drm_bo_t buffer_info{};
-  std::shared_ptr<DrmFbIdHandle> fb_id_handle;
-
-  int gralloc_buffer_usage = 0;
-  DrmHwcTransform transform{};
-  DrmHwcBlending blending = DrmHwcBlending::kNone;
-  uint16_t alpha = UINT16_MAX;
-  hwc_frect_t source_crop;
-  hwc_rect_t display_frame;
-  DrmHwcColorSpace color_space;
-  DrmHwcSampleRange sample_range;
-
-  UniqueFd acquire_fence;
-
-  int ImportBuffer(DrmDevice *drm_device);
-
-  bool IsProtected() const {
-    return (gralloc_buffer_usage & GRALLOC_USAGE_PROTECTED) ==
-           GRALLOC_USAGE_PROTECTED;
-  }
-};
-
-}  // namespace android
-
-#endif

+ 1 - 4
tests/Android.bp

@@ -37,10 +37,7 @@ cc_test {
     header_libs: ["libhardware_headers"],
     static_libs: ["libdrmhwc_utils"],
     shared_libs: ["hwcomposer.drm"],
-    include_dirs: [
-        "external/drm_hwcomposer",
-        "external/drm_hwcomposer/include",
-    ],
+    include_dirs: ["external/drm_hwcomposer"],
 }
 
 // Tool for listening and dumping uevents

+ 6 - 0
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 @@ class UniqueFd {
     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;
   }

+ 2 - 1
utils/Worker.h

@@ -44,9 +44,10 @@ class Worker {
     return initialized_;
   }
 
+  virtual ~Worker();
+
  protected:
   Worker(const char *name, int priority);
-  virtual ~Worker();
 
   int InitWorker();
   virtual void Routine() = 0;

+ 0 - 49
utils/hwcutils.cpp

@@ -1,49 +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 <utils/log.h>
-
-#include <cerrno>
-
-#include "bufferinfo/BufferInfoGetter.h"
-#include "drm/DrmFbImporter.h"
-#include "drmhwcomposer.h"
-
-namespace android {
-
-int DrmHwcLayer::ImportBuffer(DrmDevice *drm_device) {
-  buffer_info = hwc_drm_bo_t{};
-
-  int ret = BufferInfoGetter::GetInstance()->ConvertBoInfo(sf_handle,
-                                                           &buffer_info);
-  if (ret != 0) {
-    ALOGE("Failed to convert buffer info %d", ret);
-    return ret;
-  }
-
-  fb_id_handle = drm_device->GetDrmFbImporter().GetOrCreateFbId(&buffer_info);
-  if (!fb_id_handle) {
-    ALOGE("Failed to import buffer");
-    return -EINVAL;
-  }
-
-  return 0;
-}
-
-}  // namespace android