Upgrade drm_hwcomposer to 12d302c4abcef99ab28c94c3fef709754fac48e2

This project was upgraded with external_updater.
Usage: tools/external_updater/updater.sh update external/drm_hwcomposer
For more info, check https://cs.android.com/android/platform/superproject/main/+/main:tools/external_updater/README.md

Test: TreeHugger
Change-Id: I58953e268a57e1af8bc75d0e2ee6609a8c77d410
diff --git a/.clang-tidy b/.clang-tidy
index 8336d3f..0fe4ea1 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -1,6 +1,3 @@
-# Turn all the warnings from the checks above into errors.
-WarningsAsErrors: "*"
-
 #HeaderFilterRegex: "^.*external/drm_hwcomposer/.*.h$"
 
 FormatStyle: google
diff --git a/Android.bp b/Android.bp
index a480951..47b2cd8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12,6 +12,23 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["external_drm_hwcomposer_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "external_drm_hwcomposer_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_library_headers {
     name: "drm_hwcomposer_headers",
     vendor: true,
@@ -151,7 +168,7 @@
     ],
 
     shared_libs: [
-        "android.hardware.graphics.composer3-V3-ndk",
+        "android.hardware.graphics.composer3-V4-ndk",
         "libbase",
         "libbinder_ndk",
         "liblog",
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..c577677
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,19 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update external/drm_hwcomposer
+# For more info, check https://cs.android.com/android/platform/superproject/main/+/main:tools/external_updater/README.md
+
+name: "drm_hwcomposer"
+description: "KMS-based HWComposer implementation."
+third_party {
+  license_type: NOTICE
+  last_upgrade_date {
+    year: 2025
+    month: 3
+    day: 21
+  }
+  identifier {
+    type: "Git"
+    value: "https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer"
+    version: "12d302c4abcef99ab28c94c3fef709754fac48e2"
+  }
+}
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..78b324f
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,5 @@
+adelva@google.com
+ddavenport@google.com
+jstultz@google.com
+seanpaul@google.com
+include platform/system/core:/janitors/OWNERS #{LAST_RESORT_SUGGESTION}
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
new file mode 100644
index 0000000..1f413f7
--- /dev/null
+++ b/PREUPLOAD.cfg
@@ -0,0 +1,3 @@
+[Hook Scripts]
+
+check hooks installed = hooks/check-hooks-installed
\ No newline at end of file
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..305410c
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "VtsHalGraphicsComposer3_TargetTest"
+    }
+  ],
+  "desktop-presubmit": [
+    {
+      "name": "VtsHalGraphicsComposer3_TargetTest"
+    }
+  ]
+}
diff --git a/drm/DrmAtomicStateManager.cpp b/drm/DrmAtomicStateManager.cpp
index 299d30c..4e4be80 100644
--- a/drm/DrmAtomicStateManager.cpp
+++ b/drm/DrmAtomicStateManager.cpp
@@ -170,6 +170,23 @@
       return -EINVAL;
   }
 
+  if (args.min_bpc && connector->GetMinBpcProperty()) {
+    int err;
+    uint64_t range_min, range_max = 0;
+    std::tie(err, range_min) = connector->GetMinBpcProperty().RangeMin();
+    if (err)
+      return err;
+    std::tie(err, range_max) = connector->GetMinBpcProperty().RangeMax();
+    if (err)
+      return err;
+
+    // Adjust requested min bpc to be within the property range
+    int32_t min_bpc_val = std::max(args.min_bpc.value(), static_cast<int32_t>(range_min));
+    min_bpc_val = std::min(min_bpc_val, static_cast<int32_t>(range_max));
+    if (!connector->GetMinBpcProperty().AtomicSet(*pset, min_bpc_val))
+      return -EINVAL;
+  }
+
   auto unused_planes = new_frame_state.used_planes;
 
   if (args.composition) {
diff --git a/drm/DrmAtomicStateManager.h b/drm/DrmAtomicStateManager.h
index f97a488..e4fff56 100644
--- a/drm/DrmAtomicStateManager.h
+++ b/drm/DrmAtomicStateManager.h
@@ -41,6 +41,7 @@
   std::optional<Colorspace> colorspace;
   std::optional<int32_t> content_type;
   std::shared_ptr<hdr_output_metadata> hdr_metadata;
+  std::optional<int32_t> min_bpc;
 
   std::shared_ptr<DrmFbIdHandle> writeback_fb;
   SharedFd writeback_release_fence;
diff --git a/drm/DrmConnector.cpp b/drm/DrmConnector.cpp
index 37e1be4..82a109b 100644
--- a/drm/DrmConnector.cpp
+++ b/drm/DrmConnector.cpp
@@ -146,6 +146,8 @@
   GetOptionalConnectorProperty("HDR_OUTPUT_METADATA",
                                &hdr_output_metadata_property_);
 
+  GetOptionalConnectorProperty("min bpc", &min_bpc_property_);
+
   if (GetOptionalConnectorProperty("panel orientation", &panel_orientation_)) {
     panel_orientation_
         .AddEnumToMapReverse("Normal",
diff --git a/drm/DrmConnector.h b/drm/DrmConnector.h
index c22d059..4d4f070 100644
--- a/drm/DrmConnector.h
+++ b/drm/DrmConnector.h
@@ -115,6 +115,10 @@
     return content_type_property_;
   }
 
+  auto &GetMinBpcProperty() const {
+    return min_bpc_property_;
+  }
+
   auto &GetHdrOutputMetadataProperty() const {
     return hdr_output_metadata_property_;
   }
@@ -173,6 +177,7 @@
   DrmProperty edid_property_;
   DrmProperty colorspace_property_;
   DrmProperty content_type_property_;
+  DrmProperty min_bpc_property_;
   DrmProperty hdr_output_metadata_property_;
 
   DrmProperty link_status_property_;
diff --git a/hooks/check-hooks-installed b/hooks/check-hooks-installed
new file mode 100755
index 0000000..45e5c73
--- /dev/null
+++ b/hooks/check-hooks-installed
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+# Gerrit hook that runs on repo upload. Checks to ensure that the pre-upload hook
+# has been installed.
+
+cmd=$(git config hookcmd.check-non-public-commits.command)
+if [ -z "$cmd" ]; then
+  echo "Please install hooks by running: hooks/install-hooks.sh"
+  exit 1
+fi
\ No newline at end of file
diff --git a/hooks/check-non-public-commits b/hooks/check-non-public-commits
new file mode 100755
index 0000000..1e8e997
--- /dev/null
+++ b/hooks/check-non-public-commits
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+# git pre-push hook to detect whether a developer is attempting to push
+# non-public commits to a public repository.
+
+remote="$1"
+url="$2"
+
+# Don't bother checking if this is being pushed to gerrit.
+if [[ "$url" = "sso://googleplex-android/platform/external/drm_hwcomposer" ]] ||
+   [[ "$url" = "sso://android.googlesource.com/platform/external/drm_hwcomposer" ]] ||
+   [[ "$url" = "sso://android/platform/external/drm_hwcomposer" ]]
+then
+  exit 0
+fi
+
+while read local_ref local_sha remote_ref remote_sha
+do
+  # Gather a list of all commits that are to be pushed to the remote.
+  # remote_sha will be 000000 if there is no corresponding remote branch.
+  if [[ "$remote_sha" =~ "0000000000" ]]; then
+    commits=$(git rev-list $local_sha --not --remotes=$remote)
+  else
+    commits=$(git rev-list $remote_sha..$local_sha)
+  fi
+
+  # Check each commit message for the prohibited prefix.
+  for commit in $commits; do
+    # Get the commit message.
+    message=$(git log -1 --pretty=%B $commit)
+
+    # Check if the commit message starts with "ANDROID:"
+    if [[ "$message" == "ANDROID"* ]] ||
+       [[ "$message" == "INTERNAL"* ]] ||
+       [[ "$message" == "DO NOT MERGE"* ]]; then
+      echo "Error: Commit message starts with downstream tag:"
+      echo "$message"
+      echo "It looks like you're trying to push internal changes to an externally "
+      echo "visible repository: $url"
+      exit 1
+    fi
+  done
+done
+
+exit 0
diff --git a/hooks/install-hooks.sh b/hooks/install-hooks.sh
new file mode 100755
index 0000000..cc5d967
--- /dev/null
+++ b/hooks/install-hooks.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+# Install hooks.
+git config --add hookcmd.check-non-public-commits.command "[ ! -d hooks ] || hooks/check-non-public-commits"
+git config --add hook.pre-push.command check-non-public-commits
\ No newline at end of file
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index 02e3b0c..2a47a2a 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -198,6 +198,43 @@
   return GetConfig(staged_mode_config_id_.value_or(configs_.active_config_id));
 }
 
+HWC2::Error HwcDisplay::SetOutputType(uint32_t hdr_output_type) {
+  switch (hdr_output_type) {
+    case 3: { // HDR10
+      auto ret = SetHdrOutputMetadata(ui::Hdr::HDR10);
+      if (ret != HWC2::Error::None)
+        return ret;
+      min_bpc_ = 8;
+      colorspace_ = Colorspace::kBt2020Rgb;
+      break;
+    }
+    case 1: { // SYSTEM
+      std::vector<ui::Hdr> hdr_types;
+      GetEdid()->GetSupportedHdrTypes(hdr_types);
+      if (!hdr_types.empty()) {
+        auto ret = SetHdrOutputMetadata(hdr_types.front());
+        if (ret != HWC2::Error::None)
+          return ret;
+        min_bpc_ = 8;
+        colorspace_ = Colorspace::kBt2020Rgb;
+        break;
+      } else {
+        [[fallthrough]];
+      }
+    }
+    case 0:  // INVALID
+      [[fallthrough]];
+    case 2:  // SDR
+      [[fallthrough]];
+    default:
+      hdr_metadata_ = std::make_shared<hdr_output_metadata>();
+      min_bpc_ = 6;
+      colorspace_ = Colorspace::kDefault;
+  }
+
+  return HWC2::Error::None;
+}
+
 HwcDisplay::ConfigError HwcDisplay::SetConfig(hwc2_config_t config) {
   const HwcDisplayConfig *new_config = GetConfig(config);
   if (new_config == nullptr) {
@@ -241,6 +278,8 @@
   }
 
   ALOGV("Create modeset commit.");
+  SetOutputType(new_config->output_type);
+
   // Create atomic commit args for a blocking modeset. There's no need to do a
   // separate test commit, since the commit does a test anyways.
   AtomicCommitArgs commit_args = CreateModesetCommit(new_config,
@@ -250,7 +289,7 @@
 
   if (ret) {
     ALOGE("Blocking config failed: %d", ret);
-    return HwcDisplay::ConfigError::kBadConfig;
+    return HwcDisplay::ConfigError::kConfigFailed;
   }
 
   ALOGV("Blocking config succeeded.");
@@ -707,6 +746,7 @@
   args.content_type = content_type_;
   args.colorspace = colorspace_;
   args.hdr_metadata = hdr_metadata_;
+  args.min_bpc = min_bpc_;
 
   std::vector<LayerData> composition_layers;
   if (modeset_layer) {
@@ -771,6 +811,7 @@
   a_args.content_type = content_type_;
   a_args.colorspace = colorspace_;
   a_args.hdr_metadata = hdr_metadata_;
+  a_args.min_bpc = min_bpc_;
 
   uint32_t prev_vperiod_ns = 0;
   GetDisplayVsyncPeriod(&prev_vperiod_ns);
@@ -921,6 +962,8 @@
 
   staged_mode_change_time_ = change_time;
   staged_mode_config_id_ = config;
+  if (const HwcDisplayConfig *new_config = GetConfig(config))
+    SetOutputType(new_config->output_type);
 
   return HWC2::Error::None;
 }
@@ -938,38 +981,24 @@
 
   switch (mode) {
     case HAL_COLOR_MODE_NATIVE:
-      hdr_metadata_ = std::make_shared<hdr_output_metadata>();
       colorspace_ = Colorspace::kDefault;
       break;
     case HAL_COLOR_MODE_STANDARD_BT601_625:
     case HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED:
     case HAL_COLOR_MODE_STANDARD_BT601_525:
     case HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED:
-      hdr_metadata_ = std::make_shared<hdr_output_metadata>();
       // The DP spec does not say whether this is the 525 or the 625 line version.
       colorspace_ = Colorspace::kBt601Ycc;
       break;
     case HAL_COLOR_MODE_STANDARD_BT709:
     case HAL_COLOR_MODE_SRGB:
-      hdr_metadata_ = std::make_shared<hdr_output_metadata>();
       colorspace_ = Colorspace::kBt709Ycc;
       break;
     case HAL_COLOR_MODE_DCI_P3:
     case HAL_COLOR_MODE_DISPLAY_P3:
-      hdr_metadata_ = std::make_shared<hdr_output_metadata>();
       colorspace_ = Colorspace::kDciP3RgbD65;
       break;
-    case HAL_COLOR_MODE_DISPLAY_BT2020: {
-      std::vector<ui::Hdr> hdr_types;
-      GetEdid()->GetSupportedHdrTypes(hdr_types);
-      if (!hdr_types.empty()) {
-        auto ret = SetHdrOutputMetadata(hdr_types.front());
-        if (ret != HWC2::Error::None)
-          return ret;
-      }
-      colorspace_ = Colorspace::kBt2020Rgb;
-      break;
-    }
+    case HAL_COLOR_MODE_DISPLAY_BT2020:
     case HAL_COLOR_MODE_ADOBE_RGB:
     case HAL_COLOR_MODE_BT2020:
     case HAL_COLOR_MODE_BT2100_PQ:
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
index 58ab6f6..d493597 100644
--- a/hwc2_device/HwcDisplay.h
+++ b/hwc2_device/HwcDisplay.h
@@ -52,7 +52,8 @@
     kNone,
     kBadConfig,
     kSeamlessNotAllowed,
-    kSeamlessNotPossible
+    kSeamlessNotPossible,
+    kConfigFailed,
   };
 
   HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type, DrmHwc *hwc);
@@ -291,6 +292,7 @@
   bool ctm_has_offset_ = false;
   int32_t content_type_{};
   Colorspace colorspace_{};
+  int32_t min_bpc_{};
   std::shared_ptr<hdr_output_metadata> hdr_metadata_;
 
   std::shared_ptr<DrmKmsPlan> current_plan_;
@@ -306,6 +308,8 @@
 
   HWC2::Error SetActiveConfigInternal(uint32_t config, int64_t change_time);
   HWC2::Error SetHdrOutputMetadata(ui::Hdr hdrType);
+  HWC2::Error SetOutputType(uint32_t hdr_output_type);
+
   auto GetEdid() -> EdidWrapperUnique & {
     return GetPipe().connector->Get()->GetParsedEdid();
   }
diff --git a/hwc2_device/HwcDisplayConfigs.cpp b/hwc2_device/HwcDisplayConfigs.cpp
index fa1d2a9..ca70c14 100644
--- a/hwc2_device/HwcDisplayConfigs.cpp
+++ b/hwc2_device/HwcDisplayConfigs.cpp
@@ -147,6 +147,7 @@
         .group_id = group_found,
         .mode = mode,
         .disabled = disabled,
+        .output_type = 1,  // OutputType::SYSTEM
     };
 
     /* Chwck if the mode is preferred */
diff --git a/hwc2_device/HwcDisplayConfigs.h b/hwc2_device/HwcDisplayConfigs.h
index 33dcb81..8fc89bf 100644
--- a/hwc2_device/HwcDisplayConfigs.h
+++ b/hwc2_device/HwcDisplayConfigs.h
@@ -31,6 +31,7 @@
   uint32_t group_id{};
   DrmMode mode{};
   bool disabled{};
+  uint32_t output_type{};
 
   bool IsInterlaced() const {
     return (mode.GetRawMode().flags & DRM_MODE_FLAG_INTERLACE) != 0;
diff --git a/hwc3/ComposerClient.cpp b/hwc3/ComposerClient.cpp
index 96f9eed..bc5932b 100644
--- a/hwc3/ComposerClient.cpp
+++ b/hwc3/ComposerClient.cpp
@@ -30,6 +30,8 @@
 #include <aidl/android/hardware/graphics/composer3/Composition.h>
 #include <aidl/android/hardware/graphics/composer3/DisplayRequest.h>
 #include <aidl/android/hardware/graphics/composer3/IComposerClient.h>
+#include <aidl/android/hardware/graphics/composer3/Luts.h>
+#include <aidl/android/hardware/graphics/composer3/OutputType.h>
 #include <aidl/android/hardware/graphics/composer3/PowerMode.h>
 #include <aidl/android/hardware/graphics/composer3/PresentOrValidate.h>
 #include <aidl/android/hardware/graphics/composer3/RenderIntent.h>
@@ -279,7 +281,8 @@
        .width = config.mode.GetRawMode().hdisplay,
        .height = config.mode.GetRawMode().vdisplay,
        .configGroup = static_cast<int32_t>(config.group_id),
-       .vsyncPeriod = config.mode.GetVSyncPeriodNs()};
+       .vsyncPeriod = config.mode.GetVSyncPeriodNs(),
+       .hdrOutputType = static_cast<OutputType>(config.output_type)};
 
   if (width > 0) {
     static const float kMmPerInch = 25.4;
@@ -660,6 +663,9 @@
   if (command.sidebandStream) {
     cmd_result_writer_->AddError(hwc3::Error::kUnsupported);
   }
+  if (command.luts) {
+    cmd_result_writer_->AddError(hwc3::Error::kUnsupported);
+  }
   // TODO: Blocking region handling missing.
   // TODO: Layer surface damage.
   // TODO: Layer visible region.
@@ -1293,6 +1299,8 @@
       return ToBinderStatus(hwc3::Error::kSeamlessNotAllowed);
     case HwcDisplay::ConfigError::kSeamlessNotPossible:
       return ToBinderStatus(hwc3::Error::kSeamlessNotPossible);
+    case HwcDisplay::ConfigError::kConfigFailed:
+      return ToBinderStatus(hwc3::Error::kConfigFailed);
     case HwcDisplay::ConfigError::kNone:
       return ndk::ScopedAStatus::ok();
   }
@@ -1469,8 +1477,22 @@
   return ToBinderStatus(hwc3::Error::kUnsupported);
 }
 
+ndk::ScopedAStatus ComposerClient::startHdcpNegotiation(
+    int64_t /*display*/, const AidlHdcpLevels& /*levels*/) {
+  return ToBinderStatus(hwc3::Error::kUnsupported);
+}
+
 #endif
 
+ndk::ScopedAStatus ComposerClient::getMaxLayerPictureProfiles(int64_t, int32_t*) {
+  return ToBinderStatus(hwc3::Error::kUnsupported);
+}
+
+ndk::ScopedAStatus ComposerClient::getLuts(int64_t, const std::vector<Buffer>&,
+    std::vector<Luts>*) {
+  return ToBinderStatus(hwc3::Error::kUnsupported);
+}
+
 std::string ComposerClient::Dump() {
   uint32_t size = 0;
   hwc_->Dump(&size, nullptr);
diff --git a/hwc3/ComposerClient.h b/hwc3/ComposerClient.h
index 25dc0ca..ed47cd6 100644
--- a/hwc3/ComposerClient.h
+++ b/hwc3/ComposerClient.h
@@ -25,6 +25,7 @@
 #include "hwc3/Utils.h"
 #include "utils/Mutex.h"
 
+using AidlHdcpLevels = aidl::android::hardware::drm::HdcpLevels;
 using AidlPixelFormat = aidl::android::hardware::graphics::common::PixelFormat;
 using AidlNativeHandle = aidl::android::hardware::common::NativeHandle;
 
@@ -151,9 +152,16 @@
   ndk::ScopedAStatus notifyExpectedPresent(
       int64_t display, const ClockMonotonicTimestamp& expected_present_time,
       int32_t frame_interval_ns) override;
+  ndk::ScopedAStatus startHdcpNegotiation(int64_t display,
+      const AidlHdcpLevels& levels) override;
 
 #endif
 
+  ndk::ScopedAStatus getMaxLayerPictureProfiles(
+      int64_t display, int32_t* maxProfiles) override;
+  ndk::ScopedAStatus getLuts(int64_t, const std::vector<Buffer>&,
+                             std::vector<Luts>* out_luts) override;
+
  protected:
   ::ndk::SpAIBinder createBinder() override;
 
diff --git a/hwc3/Utils.h b/hwc3/Utils.h
index e892832..89767c8 100644
--- a/hwc3/Utils.h
+++ b/hwc3/Utils.h
@@ -40,6 +40,7 @@
   kUnsupported = IComposerClient::EX_UNSUPPORTED,
   kSeamlessNotAllowed = IComposerClient::EX_SEAMLESS_NOT_ALLOWED,
   kSeamlessNotPossible = IComposerClient::EX_SEAMLESS_NOT_POSSIBLE,
+  kConfigFailed = IComposerClient::EX_CONFIG_FAILED,
 };
 }  // namespace hwc3
 
diff --git a/hwc3/hwc3-drm.xml b/hwc3/hwc3-drm.xml
index 911f7f8..7debcf9 100644
--- a/hwc3/hwc3-drm.xml
+++ b/hwc3/hwc3-drm.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.graphics.composer3</name>
-        <version>3</version>
+        <version>4</version>
         <interface>
             <name>IComposer</name>
             <instance>default</instance>
diff --git a/tests/Android.bp b/tests/Android.bp
index 6f44b9c..43fd3fa 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -19,6 +19,15 @@
     ],
 }
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "external_drm_hwcomposer_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["external_drm_hwcomposer_license"],
+}
+
 // Tool for listening and dumping uevents
 cc_test {
     name: "hwc-drm-uevent-print",