Merge "hwc: Disable 8 bit rounding in the PGC" into qt-qpr1-dev
diff --git a/config/display-product.mk b/config/display-product.mk
index c309e81..7ffa961 100644
--- a/config/display-product.mk
+++ b/config/display-product.mk
@@ -22,6 +22,7 @@
     [email protected] \
     [email protected] \
     [email protected] \
+    [email protected] \
     modetest
 
 PRODUCT_PROPERTY_OVERRIDES += \
diff --git a/gralloc/QtiMapperExtensions.cpp b/gralloc/QtiMapperExtensions.cpp
index cace7ba..33cd23d 100644
--- a/gralloc/QtiMapperExtensions.cpp
+++ b/gralloc/QtiMapperExtensions.cpp
@@ -344,7 +344,7 @@
                                                   getFormatLayout_cb hidl_cb) {
   ALOGD_IF(DEBUG, "%s: Input parameters - wxh: %dx%d usage: 0x%" PRIu64 " format: %d", __FUNCTION__,
            width, height, usage, format);
-  auto err = Error::BAD_BUFFER;
+  auto err = Error::NONE;
   hidl_vec<PlaneLayout> plane_info;
   unsigned int alignedw = 0, alignedh = 0;
   int plane_count = 0;
@@ -353,34 +353,41 @@
   BufferInfo info(width, height, custom_format, usage);
   gralloc::GetAlignedWidthAndHeight(info, &alignedw, &alignedh);
   size = gralloc::GetSize(info, alignedw, alignedh);
+  gralloc::PlaneLayoutInfo plane_layout[8] = {};
   ALOGD_IF(DEBUG, "%s: Aligned width and height - wxh: %ux%u custom_format = %d", __FUNCTION__,
            alignedw, alignedh, custom_format);
   if (gralloc::IsYuvFormat(custom_format)) {
-    gralloc::PlaneLayoutInfo yuv_plane_info[8] = {};
     gralloc::GetYUVPlaneInfo(info, custom_format, alignedw, alignedh, flags, &plane_count,
-                             yuv_plane_info);
-    ALOGD_IF(DEBUG, "%s: Number of plane - %d, custom_format - %d", __FUNCTION__, plane_count,
-             custom_format);
-    plane_info.resize(plane_count);
-    for (int i = 0; i < plane_count; i++) {
-      plane_info[i].component = yuv_plane_info[i].component;
-      plane_info[i].h_subsampling = yuv_plane_info[i].h_subsampling;
-      plane_info[i].v_subsampling = yuv_plane_info[i].v_subsampling;
-      plane_info[i].offset = yuv_plane_info[i].offset;
-      plane_info[i].pixel_increment = yuv_plane_info[i].step;
-      plane_info[i].stride = yuv_plane_info[i].stride;
-      plane_info[i].stride_bytes = yuv_plane_info[i].stride_bytes;
-      plane_info[i].scanlines = yuv_plane_info[i].scanlines;
-      plane_info[i].size = yuv_plane_info[i].size;
-      ALOGD_IF(DEBUG, "%s: plane info: component - %d", __FUNCTION__, plane_info[i].component);
-      ALOGD_IF(DEBUG, "h_subsampling - %u, v_subsampling - %u, offset - %u, pixel_increment - %d",
-               plane_info[i].h_subsampling, plane_info[i].v_subsampling, plane_info[i].offset,
-               plane_info[i].pixel_increment);
-      ALOGD_IF(DEBUG, "stride_pixel - %d, stride_bytes - %d, scanlines - %d, size - %u",
-               plane_info[i].stride, plane_info[i].stride_bytes, plane_info[i].scanlines,
-               plane_info[i].size);
-    }
-    err = Error::NONE;
+                             plane_layout);
+  } else if (gralloc::IsUncompressedRGBFormat(custom_format) ||
+             gralloc::IsCompressedRGBFormat(custom_format)) {
+    gralloc::GetRGBPlaneInfo(info, custom_format, alignedw, alignedh, flags, &plane_count,
+                             plane_layout);
+  } else {
+    err = Error::BAD_BUFFER;
+    hidl_cb(err, size, plane_info);
+    return Void();
+  }
+  ALOGD_IF(DEBUG, "%s: Number of plane - %d, custom_format - %d", __FUNCTION__, plane_count,
+           custom_format);
+  plane_info.resize(plane_count);
+  for (int i = 0; i < plane_count; i++) {
+    plane_info[i].component = plane_layout[i].component;
+    plane_info[i].h_subsampling = plane_layout[i].h_subsampling;
+    plane_info[i].v_subsampling = plane_layout[i].v_subsampling;
+    plane_info[i].offset = plane_layout[i].offset;
+    plane_info[i].pixel_increment = plane_layout[i].step;
+    plane_info[i].stride = plane_layout[i].stride;
+    plane_info[i].stride_bytes = plane_layout[i].stride_bytes;
+    plane_info[i].scanlines = plane_layout[i].scanlines;
+    plane_info[i].size = plane_layout[i].size;
+    ALOGD_IF(DEBUG, "%s: plane info: component - %d", __FUNCTION__, plane_info[i].component);
+    ALOGD_IF(DEBUG, "h_subsampling - %u, v_subsampling - %u, offset - %u, pixel_increment - %d",
+             plane_info[i].h_subsampling, plane_info[i].v_subsampling, plane_info[i].offset,
+             plane_info[i].pixel_increment);
+    ALOGD_IF(DEBUG, "stride_pixel - %d, stride_bytes - %d, scanlines - %d, size - %u",
+             plane_info[i].stride, plane_info[i].stride_bytes, plane_info[i].scanlines,
+             plane_info[i].size);
   }
   hidl_cb(err, size, plane_info);
   return Void();
diff --git a/gralloc/gr_utils.cpp b/gralloc/gr_utils.cpp
index 263eb3e..2f8f550 100644
--- a/gralloc/gr_utils.cpp
+++ b/gralloc/gr_utils.cpp
@@ -794,6 +794,28 @@
   return size;
 }
 
+unsigned int GetRgbMetaSize(int format, uint32_t width, uint32_t height, uint64_t usage) {
+  unsigned int meta_size = 0;
+  if (!IsUBwcEnabled(format, usage)) {
+    return meta_size;
+  }
+  uint32_t bpp = GetBppForUncompressedRGB(format);
+  switch (format) {
+    case HAL_PIXEL_FORMAT_BGR_565:
+    case HAL_PIXEL_FORMAT_RGBA_8888:
+    case HAL_PIXEL_FORMAT_RGBX_8888:
+    case HAL_PIXEL_FORMAT_RGBA_1010102:
+    case HAL_PIXEL_FORMAT_RGBX_1010102:
+    case HAL_PIXEL_FORMAT_RGBA_FP16:
+      meta_size = GetRgbUBwcMetaBufferSize(width, height, bpp);
+      break;
+    default:
+      ALOGE("%s:Unsupported RGB format: 0x%x", __FUNCTION__, format);
+      break;
+  }
+  return meta_size;
+}
+
 int GetRgbDataAddress(private_handle_t *hnd, void **rgb_data) {
   int err = 0;
 
@@ -807,22 +829,8 @@
     *rgb_data = reinterpret_cast<void *>(hnd->base);
     return err;
   }
+  unsigned int meta_size = GetRgbMetaSize(hnd->format, hnd->width, hnd->height, hnd->usage);
 
-  unsigned int meta_size = 0;
-  uint32_t bpp = GetBppForUncompressedRGB(hnd->format);
-  switch (hnd->format) {
-    case HAL_PIXEL_FORMAT_BGR_565:
-    case HAL_PIXEL_FORMAT_RGBA_8888:
-    case HAL_PIXEL_FORMAT_RGBX_8888:
-    case HAL_PIXEL_FORMAT_RGBA_1010102:
-    case HAL_PIXEL_FORMAT_RGBX_1010102:
-      meta_size = GetRgbUBwcMetaBufferSize(hnd->width, hnd->height, bpp);
-      break;
-    default:
-      ALOGE("%s:Unsupported RGB format: 0x%x", __FUNCTION__, hnd->format);
-      err = -EINVAL;
-      break;
-  }
   *rgb_data = reinterpret_cast<void *>(hnd->base + meta_size);
 
   return err;
@@ -1566,4 +1574,44 @@
   }
 }
 
+bool HasAlphaComponent(int32_t format) {
+  switch (format) {
+    case HAL_PIXEL_FORMAT_RGBA_8888:
+    case HAL_PIXEL_FORMAT_BGRA_8888:
+    case HAL_PIXEL_FORMAT_RGBA_5551:
+    case HAL_PIXEL_FORMAT_RGBA_4444:
+    case HAL_PIXEL_FORMAT_RGBA_1010102:
+    case HAL_PIXEL_FORMAT_ARGB_2101010:
+    case HAL_PIXEL_FORMAT_BGRA_1010102:
+    case HAL_PIXEL_FORMAT_ABGR_2101010:
+    case HAL_PIXEL_FORMAT_RGBA_FP16:
+      return true;
+    default:
+      return false;
+  }
+}
+
+void GetRGBPlaneInfo(const BufferInfo &info, int32_t format, int32_t width, int32_t height,
+                     int32_t /* flags */, int *plane_count, PlaneLayoutInfo *plane_info) {
+  uint64_t usage = info.usage;
+  *plane_count = 1;
+  uint32_t bpp = 0;
+  if (IsUncompressedRGBFormat(format)) {
+    bpp = GetBppForUncompressedRGB(format);
+  }
+  plane_info->component =
+      (PlaneComponent)(PLANE_COMPONENT_R | PLANE_COMPONENT_G | PLANE_COMPONENT_B);
+  if (HasAlphaComponent(format)) {
+    plane_info->component = (PlaneComponent)(plane_info->component | PLANE_COMPONENT_A);
+  }
+  plane_info->size = GetSize(info, width, height);
+  plane_info->step = bpp;
+  plane_info->offset = GetRgbMetaSize(format, width, height, usage);
+  plane_info->h_subsampling = 0;
+  plane_info->v_subsampling = 0;
+  plane_info->stride = width;
+  plane_info->stride_bytes = width * plane_info->step;
+  plane_info->scanlines = height;
+}
+
 }  // namespace gralloc
diff --git a/gralloc/gr_utils.h b/gralloc/gr_utils.h
index 8ecb90f..39d7e9b 100644
--- a/gralloc/gr_utils.h
+++ b/gralloc/gr_utils.h
@@ -144,6 +144,9 @@
 int GetYUVPlaneInfo(const private_handle_t *hnd, struct android_ycbcr ycbcr[2]);
 int GetYUVPlaneInfo(const BufferInfo &info, int32_t format, int32_t width, int32_t height,
                     int32_t flags, int *plane_count, PlaneLayoutInfo plane_info[8]);
+void GetRGBPlaneInfo(const BufferInfo &info, int32_t format, int32_t width, int32_t height,
+                     int32_t flags, int *plane_count, PlaneLayoutInfo *plane_info);
+unsigned int GetRgbMetaSize(int format, uint32_t width, uint32_t height, uint64_t usage);
 void GetYuvSubSamplingFactor(int32_t format, int *h_subsampling, int *v_subsampling);
 void CopyPlaneLayoutInfotoAndroidYcbcr(uint64_t base, int plane_count, PlaneLayoutInfo *plane_info,
                                        struct android_ycbcr *ycbcr);
@@ -178,6 +181,7 @@
 int GetCustomFormatFlags(int format, uint64_t usage, int *custom_format, uint64_t *priv_flags);
 int GetBufferType(int inputFormat);
 bool IsGPUFlagSupported(uint64_t usage);
+bool HasAlphaComponent(int32_t format);
 }  // namespace gralloc
 
 #endif  // __GR_UTILS_H__
diff --git a/sdm/libs/hwc2/Android.mk b/sdm/libs/hwc2/Android.mk
index 353a51e..4d42327 100644
--- a/sdm/libs/hwc2/Android.mk
+++ b/sdm/libs/hwc2/Android.mk
@@ -27,6 +27,7 @@
                                  [email protected] \
                                  [email protected] \
                                  [email protected] \
+                                 [email protected] \
                                  [email protected] \
                                  libdrm.vendor
 
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index 2df90fd..597ade1 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -1107,20 +1107,14 @@
   if (out_num_keys == nullptr) {
     return HWC2::Error::BadParameter;
   }
-  *out_num_keys = UINT32(PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL) + 1;
-  if (out_keys != nullptr) {
-    out_keys[0] = PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X;
-    out_keys[1] = PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y;
-    out_keys[2] = PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X;
-    out_keys[3] = PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y;
-    out_keys[4] = PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X;
-    out_keys[5] = PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y;
-    out_keys[6] = PerFrameMetadataKey::WHITE_POINT_X;
-    out_keys[7] = PerFrameMetadataKey::WHITE_POINT_Y;
-    out_keys[8] = PerFrameMetadataKey::MAX_LUMINANCE;
-    out_keys[9] = PerFrameMetadataKey::MIN_LUMINANCE;
-    out_keys[10] = PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL;
-    out_keys[11] = PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL;
+  const uint32_t num_keys = UINT32(PerFrameMetadataKey::HDR10_PLUS_SEI) + 1;
+  if (out_keys == nullptr) {
+    *out_num_keys = num_keys;
+  } else {
+    uint32_t max_out_key_elements = std::min(*out_num_keys, num_keys);
+    for (int32_t i = 0; i < max_out_key_elements; i++) {
+      out_keys[i] = static_cast<PerFrameMetadataKey>(i);
+    }
   }
   return HWC2::Error::None;
 }
@@ -1465,12 +1459,13 @@
   }
 
   if (out_types == nullptr) {
-    // We support HDR10 and HLG
-    *out_num_types = 2;
+    // We support HDR10, HLG and HDR10_PLUS.
+    *out_num_types = 3;
   } else {
-    // HDR10 and HLG are supported
+    // HDR10, HLG and HDR10_PLUS are supported.
     out_types[0] = HAL_HDR_HDR10;
     out_types[1] = HAL_HDR_HLG;
+    out_types[2] = HAL_HDR_HDR10_PLUS;
     *out_max_luminance = fixed_info.max_luminance;
     *out_max_average_luminance = fixed_info.average_luminance;
     *out_min_luminance = fixed_info.min_luminance;
diff --git a/sdm/libs/hwc2/hwc_display_builtin.cpp b/sdm/libs/hwc2/hwc_display_builtin.cpp
index 6886643..96061bd 100644
--- a/sdm/libs/hwc2/hwc_display_builtin.cpp
+++ b/sdm/libs/hwc2/hwc_display_builtin.cpp
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -234,6 +234,11 @@
       layer_stack_.flags.post_processed_output = post_processed_output_;
     }
   }
+  // Todo: relook this case
+  if (layer_stack_.flags.hdr_present != hdr_present_) {
+    error = display_intf_->ControlIdlePowerCollapse(!layer_stack_.flags.hdr_present, true);
+    hdr_present_ = layer_stack_.flags.hdr_present;
+  }
 
   uint32_t num_updating_layers = GetUpdatingLayersCount();
   bool one_updating_layer = (num_updating_layers == 1);
diff --git a/sdm/libs/hwc2/hwc_display_builtin.h b/sdm/libs/hwc2/hwc_display_builtin.h
index 9b72bf3..3298561 100644
--- a/sdm/libs/hwc2/hwc_display_builtin.h
+++ b/sdm/libs/hwc2/hwc_display_builtin.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -156,6 +156,7 @@
   int default_mode_status_ = 0;
   bool pending_refresh_ = true;
   bool enable_drop_refresh_ = false;
+  bool hdr_present_ = false;
 
   // Members for 1 frame capture in a client provided buffer
   bool frame_capture_buffer_queued_ = false;
diff --git a/sdm/libs/hwc2/hwc_layers.cpp b/sdm/libs/hwc2/hwc_layers.cpp
index 6b345b1..f288a3d 100644
--- a/sdm/libs/hwc2/hwc_layers.cpp
+++ b/sdm/libs/hwc2/hwc_layers.cpp
@@ -270,12 +270,11 @@
   layer_buffer->unaligned_width = UINT32(handle->unaligned_width);
   layer_buffer->unaligned_height = UINT32(handle->unaligned_height);
 
+  layer_buffer->flags.video = (handle->buffer_type == BUFFER_TYPE_VIDEO) ? true : false;
   if (SetMetaData(const_cast<private_handle_t *>(handle), layer_) != kErrorNone) {
     return HWC2::Error::BadLayer;
   }
 
-  layer_buffer->flags.video = (handle->buffer_type == BUFFER_TYPE_VIDEO) ? true : false;
-
   // TZ Protected Buffer - L1
   bool secure = (handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER);
   bool secure_camera = secure && (handle->flags & private_handle_t::PRIV_FLAGS_CAMERA_WRITE);
@@ -549,6 +548,8 @@
 HWC2::Error HWCLayer::SetLayerPerFrameMetadata(uint32_t num_elements,
                                                const PerFrameMetadataKey *keys,
                                                const float *metadata) {
+  auto old_mastering_display = layer_->input_buffer.color_metadata.masteringDisplayInfo;
+  auto old_content_light = layer_->input_buffer.color_metadata.contentLightLevel;
   auto &mastering_display = layer_->input_buffer.color_metadata.masteringDisplayInfo;
   auto &content_light = layer_->input_buffer.color_metadata.contentLightLevel;
   for (uint32_t i = 0; i < num_elements; i++) {
@@ -591,6 +592,51 @@
       case PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL:
         content_light.minPicAverageLightLevel = UINT32(metadata[i] * 10000);
         break;
+      default:
+        break;
+    }
+  }
+  if ((!SameConfig(&old_mastering_display, &mastering_display, UINT32(sizeof(MasteringDisplay)))) ||
+       (!SameConfig(&old_content_light, &content_light, UINT32(sizeof(ContentLightLevel))))) {
+    per_frame_hdr_metadata_ = true;
+    layer_->update_mask.set(kMetadataUpdate);
+    geometry_changes_ |= kDataspace;
+  }
+  return HWC2::Error::None;
+}
+
+HWC2::Error HWCLayer::SetLayerPerFrameMetadataBlobs(uint32_t num_elements,
+                                                    const PerFrameMetadataKey *keys,
+                                                    const uint32_t *sizes,
+                                                    const uint8_t* metadata) {
+  if (!keys || !sizes || !metadata) {
+    DLOGE("metadata or sizes or keys is null");
+    return HWC2::Error::BadParameter;
+  }
+
+  ColorMetaData &color_metadata = layer_->input_buffer.color_metadata;
+  for (uint32_t i = 0; i < num_elements; i++) {
+    switch (keys[i]) {
+      case PerFrameMetadataKey::HDR10_PLUS_SEI:
+        if (sizes[i] > HDR_DYNAMIC_META_DATA_SZ) {
+          DLOGE("Size of HDR10_PLUS_SEI = %d", sizes[i]);
+          return HWC2::Error::BadParameter;
+        }
+        per_frame_hdr_metadata_ = false;
+        // if dynamic metadata changes, store and set needs validate
+        if (!SameConfig(static_cast<const uint8_t*>(color_metadata.dynamicMetaDataPayload),
+                        metadata, sizes[i])) {
+          geometry_changes_ |= kDataspace;
+          color_metadata.dynamicMetaDataValid = true;
+          color_metadata.dynamicMetaDataLen = sizes[i];
+          std::memcpy(color_metadata.dynamicMetaDataPayload, metadata, sizes[i]);
+          per_frame_hdr_metadata_ = true;
+          layer_->update_mask.set(kMetadataUpdate);
+        }
+        break;
+      default:
+        DLOGW("Invalid key = %d", keys[i]);
+        return HWC2::Error::BadParameter;
     }
   }
   return HWC2::Error::None;
@@ -934,7 +980,9 @@
      use_color_metadata = true;
   }
 
-  if (use_color_metadata) {
+  // Since client has set PerFrameMetadata, dataspace will be valid
+  // so we can skip reading from ColorMetaData.
+  if (use_color_metadata && !per_frame_hdr_metadata_) {
     ColorMetaData old_meta_data = layer_buffer->color_metadata;
     if (sdm::SetCSC(handle, &layer_buffer->color_metadata) == kErrorNone) {
       if ((layer_buffer->color_metadata.colorPrimaries != old_meta_data.colorPrimaries) ||
@@ -942,6 +990,9 @@
           (layer_buffer->color_metadata.range != old_meta_data.range)) {
         layer_->update_mask.set(kMetadataUpdate);
       }
+      DLOGV_IF(kTagClient, "Dynamic Metadata valid = %d size = %d",
+               layer_buffer->color_metadata.dynamicMetaDataValid,
+               layer_buffer->color_metadata.dynamicMetaDataLen);
       if (layer_buffer->color_metadata.dynamicMetaDataValid &&
           !SameConfig(layer_buffer->color_metadata.dynamicMetaDataPayload,
           old_meta_data.dynamicMetaDataPayload, HDR_DYNAMIC_META_DATA_SZ)) {
diff --git a/sdm/libs/hwc2/hwc_layers.h b/sdm/libs/hwc2/hwc_layers.h
index 362eaa9..538f4df 100644
--- a/sdm/libs/hwc2/hwc_layers.h
+++ b/sdm/libs/hwc2/hwc_layers.h
@@ -33,7 +33,7 @@
 #include <hardware/hwcomposer2.h>
 #undef HWC2_INCLUDE_STRINGIFICATION
 #undef HWC2_USE_CPP11
-#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
+#include <android/hardware/graphics/composer/2.3/IComposerClient.h>
 #include <deque>
 #include <map>
 #include <set>
@@ -41,7 +41,7 @@
 #include "hwc_buffer_allocator.h"
 
 using PerFrameMetadataKey =
-    android::hardware::graphics::composer::V2_2::IComposerClient::PerFrameMetadataKey;
+    android::hardware::graphics::composer::V2_3::IComposerClient::PerFrameMetadataKey;
 
 namespace sdm {
 
@@ -91,6 +91,8 @@
   HWC2::Error SetLayerVisibleRegion(hwc_region_t visible);
   HWC2::Error SetLayerPerFrameMetadata(uint32_t num_elements, const PerFrameMetadataKey *keys,
                                        const float *metadata);
+  HWC2::Error SetLayerPerFrameMetadataBlobs(uint32_t num_elements, const PerFrameMetadataKey *keys,
+                                            const uint32_t *sizes, const uint8_t* metadata);
   HWC2::Error SetLayerZOrder(uint32_t z);
   void SetComposition(const LayerComposition &sdm_composition);
   HWC2::Composition GetClientRequestedCompositionType() { return client_requested_; }
@@ -137,6 +139,7 @@
   bool non_integral_source_crop_ = false;
   bool has_metadata_refresh_rate_ = false;
   bool buffer_flipped_ = false;
+  bool per_frame_hdr_metadata_ = false;  // used to track if perframe metadata and blob is set.
 
   // Composition requested by client(SF) Original
   HWC2::Composition client_requested_orig_ = HWC2::Composition::Device;
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index 976e646..11f9b0a 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -698,6 +698,16 @@
 #pragma clang diagnostic pop
 #endif
 
+static int32_t SetLayerPerFrameMetadataBlobs(hwc2_device_t *device, hwc2_display_t display,
+                                             hwc2_layer_t layer, uint32_t num_elements,
+                                             const int32_t *int_keys, const uint32_t *sizes,
+                                             const uint8_t *metadata) {
+  auto keys = reinterpret_cast<const PerFrameMetadataKey *>(int_keys);
+  return HWCSession::CallLayerFunction(device, display, layer,
+                                       &HWCLayer::SetLayerPerFrameMetadataBlobs,
+                                       num_elements, keys, sizes, metadata);
+}
+
 static int32_t GetDisplayAttribute(hwc2_device_t *device, hwc2_display_t display,
                                    hwc2_config_t config, int32_t int_attribute,
                                    int32_t *out_value) {
@@ -1249,6 +1259,8 @@
       return AsFP<HWC2_PFN_GET_PER_FRAME_METADATA_KEYS>(GetPerFrameMetadataKeys);
     case HWC2::FunctionDescriptor::SetLayerPerFrameMetadata:
       return AsFP<HWC2_PFN_SET_LAYER_PER_FRAME_METADATA>(SetLayerPerFrameMetadata);
+    case HWC2::FunctionDescriptor::SetLayerPerFrameMetadataBlobs:
+      return AsFP<HWC2_PFN_SET_LAYER_PER_FRAME_METADATA_BLOBS>(SetLayerPerFrameMetadataBlobs);
     case HWC2::FunctionDescriptor::GetDisplayIdentificationData:
       return AsFP<HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA>
              (HWCSession::GetDisplayIdentificationData);