sdm: Add support for inline rotator

Add support to populate inline rotator caps and setup inline
rotator configuration during atomic commit.

Change-Id: I6504db71689a865c6edb15e12ab44a6740255cb5
CRs-fixed: 2017744
diff --git a/libdrmutils/drm_interface.h b/libdrmutils/drm_interface.h
index 71767e7..6e3b005 100644
--- a/libdrmutils/drm_interface.h
+++ b/libdrmutils/drm_interface.h
@@ -125,6 +125,12 @@
    */
   PLANE_SET_SCALER_CONFIG,
   /*
+   * Op: Sets plane rotation destination rect
+   * Arg: uint32_t - Plane ID
+   *      DRMRect - rotator dst Rectangle
+   */
+  PLANE_SET_ROTATION_DST_RECT,
+  /*
    * Op: Activate or deactivate a CRTC
    * Arg: uint32_t - CRTC ID
    *      uint32_t - 1 to enable, 0 to disable
@@ -315,6 +321,7 @@
   uint32_t max_horizontal_deci;
   uint32_t max_vertical_deci;
   uint64_t max_pipe_bandwidth;
+  uint32_t cache_size;  // cache size in bytes for inline rotation support.
 };
 
 // All DRM Planes as map<Plane_id , plane_type_info> listed from highest to lowest priority
diff --git a/sdm/include/core/sdm_types.h b/sdm/include/core/sdm_types.h
index fae1153..ce356bf 100644
--- a/sdm/include/core/sdm_types.h
+++ b/sdm/include/core/sdm_types.h
@@ -55,6 +55,7 @@
   kErrorShutDown,         //!< Driver is processing shutdown sequence
   kErrorPerfValidation,   //!< Bandwidth or Clock requirement validation failure.
   kErrorNoAppLayers,      //!< No App layer(s) in the draw cycle.
+  kErrorRotatorValidation,  //!< Rotator configuration validation failure.
 };
 
 /*! @brief This structure is defined for client and library compatibility check purpose only. This
diff --git a/sdm/include/private/hw_info_types.h b/sdm/include/private/hw_info_types.h
index cdfec2e..64e8454 100644
--- a/sdm/include/private/hw_info_types.h
+++ b/sdm/include/private/hw_info_types.h
@@ -205,6 +205,7 @@
   uint32_t undersized_prefill_lines = 0;
   CompRatioMap comp_ratio_rt_map;
   CompRatioMap comp_ratio_nrt_map;
+  uint32_t cache_size = 0;  // cache size in bytes
 
   void Reset() { *this = HWResourceInfo(); }
 };
@@ -321,6 +322,12 @@
   }
 };
 
+enum HWRotatorMode {
+  kRotatorNone,
+  kRotatorOffline,
+  kRotatorInline
+};
+
 struct HWRotateInfo {
   int pipe_id = -1;  // Not actual pipe id, but the relative DMA id
   int writeback_id = -1;  // Writeback block id, but this is the same as DMA id
@@ -342,6 +349,7 @@
   float input_compression = 1.0f;
   float output_compression = 1.0f;
   bool is_buffer_cached = false;
+  HWRotatorMode mode = kRotatorNone;
 };
 
 struct HWScaleLutInfo {
diff --git a/sdm/include/utils/formats.h b/sdm/include/utils/formats.h
index dd819dc..2d43850 100644
--- a/sdm/include/utils/formats.h
+++ b/sdm/include/utils/formats.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+* Copyright (c) 2016 - 2017, 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
@@ -34,10 +34,28 @@
 
 namespace sdm {
 
+struct FormatTileSize {
+  /*< Tile width in pixels. For YUV formats this will give only the
+      tile width for Y plane*/
+  uint32_t tile_width = 0;
+  /*< Tile height in pixels. For YUV formats this will give only the
+      tile height for Y plane*/
+  uint32_t tile_height = 0;
+
+  /*< Tile width in pixels. Only valid for YUV formats where this will
+      give tile width for UV plane*/
+  uint32_t uv_tile_width = 0;
+  /*< Tile height in pixels. Only valid for YUV formats where this will
+       give tile height for UV plane*/
+  uint32_t uv_tile_height = 0;
+};
+
 bool IsUBWCFormat(LayerBufferFormat format);
 bool Is10BitFormat(LayerBufferFormat format);
 const char *GetFormatString(const LayerBufferFormat &format);
 BufferLayout GetBufferLayout(LayerBufferFormat format);
+DisplayError GetBufferFormatTileSize(LayerBufferFormat format, FormatTileSize *tile_size);
+float GetBufferFormatBpp(LayerBufferFormat format);
 
 }  // namespace sdm
 
diff --git a/sdm/include/utils/rect.h b/sdm/include/utils/rect.h
index ea6edfb..303fc9f 100644
--- a/sdm/include/utils/rect.h
+++ b/sdm/include/utils/rect.h
@@ -60,6 +60,11 @@
   void TransformHV(const LayerRect &src_domain, const LayerRect &in_rect,
                    const LayerTransform &transform, LayerRect *out_rect);
   RectOrientation GetOrientation(const LayerRect &in_rect);
+  DisplayError GetCropAndDestination(const LayerRect &crop, const LayerRect &dst,
+                                     bool rotate90, float *crop_width, float *crop_height,
+                                     float *dst_width, float *dst_height);
+  DisplayError GetScaleFactor(const LayerRect &crop, const LayerRect &dst, bool rotate90,
+                              float *scale_x, float *scale_y);
 }  // namespace sdm
 
 #endif  // __RECT_H__
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index 618dd2e..f6540cd 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -590,21 +590,24 @@
     char idx[8] = { 0 };
     const char *comp_type = GetName(sdm_layer->composition);
     const char *buffer_format = GetFormatString(input_buffer->format);
-    const char *rotate_split[2] = { "Rot-1", "Rot-2" };
     const char *comp_split[2] = { "Comp-1", "Comp-2" };
 
     snprintf(idx, sizeof(idx), "%d", layer_index);
 
     for (uint32_t count = 0; count < hw_rotator_session.hw_block_count; count++) {
-      char writeback_id[8] = { 0 };
+      char writeback_id[8] = { "I" };
       HWRotateInfo &rotate = hw_rotator_session.hw_rotate_info[count];
       LayerRect &src_roi = rotate.src_roi;
       LayerRect &dst_roi = rotate.dst_roi;
+      const char *rotate_split[2] = { "Rot-1", "Rot-2" };
+      int pipe_id = 0;
 
-      snprintf(writeback_id, sizeof(writeback_id), "%d", rotate.writeback_id);
-
+      if (hw_rotator_session.mode == kRotatorOffline) {
+        snprintf(writeback_id, sizeof(writeback_id), "%d", rotate.writeback_id);
+        pipe_id = rotate.pipe_id;
+      }
       DumpImpl::AppendString(buffer, length, format, idx, comp_type, rotate_split[count],
-                             writeback_id, rotate.pipe_id, input_buffer->width,
+                             writeback_id, pipe_id, input_buffer->width,
                              input_buffer->height, buffer_format, INT(src_roi.left),
                              INT(src_roi.top), INT(src_roi.right), INT(src_roi.bottom),
                              INT(dst_roi.left), INT(dst_roi.top), INT(dst_roi.right),
@@ -633,8 +636,11 @@
         continue;
       }
 
-      LayerRect &src_roi = pipe.src_roi;
+      LayerRect src_roi = pipe.src_roi;
       LayerRect &dst_roi = pipe.dst_roi;
+      if (hw_rotator_session.mode == kRotatorInline) {
+        src_roi = hw_rotator_session.hw_rotate_info[count].dst_roi;
+      }
 
       snprintf(z_order, sizeof(z_order), "%d", pipe.z_order);
       snprintf(flags, sizeof(flags), "0x%08x", hw_layer.flags.flags);
diff --git a/sdm/libs/core/drm/hw_device_drm.cpp b/sdm/libs/core/drm/hw_device_drm.cpp
index 1028663..76df517 100644
--- a/sdm/libs/core/drm/hw_device_drm.cpp
+++ b/sdm/libs/core/drm/hw_device_drm.cpp
@@ -50,6 +50,7 @@
 #include <utils/sys.h>
 #include <drm/sde_drm.h>
 #include <private/color_params.h>
+#include <utils/rect.h>
 
 #include <algorithm>
 #include <string>
@@ -225,7 +226,7 @@
     HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session;
     HWRotateInfo *hw_rotate_info = &hw_rotator_session->hw_rotate_info[0];
 
-    if (hw_rotate_info->valid) {
+    if (hw_rotator_session->mode == kRotatorOffline && hw_rotate_info->valid) {
       input_buffer = &hw_rotator_session->output_buffer;
     }
 
@@ -652,15 +653,13 @@
     HWPipeInfo *left_pipe = &hw_layers->config[i].left_pipe;
     HWPipeInfo *right_pipe = &hw_layers->config[i].right_pipe;
     HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session;
-    bool needs_rotation = false;
 
     for (uint32_t count = 0; count < 2; count++) {
       HWPipeInfo *pipe_info = (count == 0) ? left_pipe : right_pipe;
       HWRotateInfo *hw_rotate_info = &hw_rotator_session->hw_rotate_info[count];
 
-      if (hw_rotate_info->valid) {
+      if (hw_rotator_session->mode == kRotatorOffline && hw_rotate_info->valid) {
         input_buffer = &hw_rotator_session->output_buffer;
-        needs_rotation = true;
       }
 
       uint32_t fb_id = registry_.GetFbId(input_buffer->planes[0].fd);
@@ -674,21 +673,17 @@
         DRMRect src = {};
         SetRect(pipe_info->src_roi, &src);
         drm_atomic_intf_->Perform(DRMOps::PLANE_SET_SRC_RECT, pipe_id, src);
+        DRMRect rot_dst = {0, 0, 0, 0};
+        if (hw_rotator_session->mode == kRotatorInline && hw_rotate_info->valid) {
+          SetRect(hw_rotate_info->dst_roi, &rot_dst);
+          drm_atomic_intf_->Perform(DRMOps::PLANE_SET_ROTATION_DST_RECT, pipe_id, rot_dst);
+        }
         DRMRect dst = {};
         SetRect(pipe_info->dst_roi, &dst);
         drm_atomic_intf_->Perform(DRMOps::PLANE_SET_DST_RECT, pipe_id, dst);
 
         uint32_t rot_bit_mask = 0;
-        // In case of rotation, rotator handles flips
-        if (!needs_rotation) {
-          if (layer.transform.flip_horizontal) {
-            rot_bit_mask |= UINT32(DRMRotation::FLIP_H);
-          }
-          if (layer.transform.flip_vertical) {
-            rot_bit_mask |= UINT32(DRMRotation::FLIP_V);
-          }
-        }
-
+        SetRotation(layer.transform, hw_rotator_session->mode, &rot_bit_mask);
         drm_atomic_intf_->Perform(DRMOps::PLANE_SET_ROTATION, pipe_id, rot_bit_mask);
         drm_atomic_intf_->Perform(DRMOps::PLANE_SET_H_DECIMATION, pipe_id,
                                   pipe_info->horizontal_decimation);
@@ -828,7 +823,7 @@
   for (uint32_t i = 0; i < hw_layer_info.hw_layers.size(); i++) {
     Layer &layer = hw_layer_info.hw_layers.at(i);
     HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session;
-    if (hw_rotator_session->hw_block_count) {
+    if (hw_rotator_session->mode == kRotatorOffline) {
       hw_rotator_session->output_buffer.release_fence_fd = Sys::dup_(release_fence);
     } else {
       layer.input_buffer.release_fence_fd = Sys::dup_(release_fence);
@@ -874,6 +869,36 @@
   target->bottom = UINT32(source.bottom);
 }
 
+void HWDeviceDRM::SetRotation(LayerTransform transform, const HWRotatorMode &mode,
+                              uint32_t* rot_bit_mask) {
+  // In offline rotation case, rotator will handle flips set via offline rotator interface.
+  if (mode == kRotatorOffline) {
+    *rot_bit_mask = 0;
+    return;
+  }
+
+  // In no rotation case or inline rotation case, plane will handle flips
+  // In DRM framework rotation is applied in counter-clockwise direction.
+  if (transform.rotation == 90) {
+    // a) rotate 90 clockwise = rotate 270 counter-clockwise in DRM
+    // rotate 270 is translated as hflip + vflip + rotate90
+    // b) rotate 270 clockwise = rotate 90 counter-clockwise in DRM
+    // c) hflip + rotate 90 clockwise = vflip + rotate 90 counter-clockwise in DRM
+    // d) vflip + rotate 90 clockwise = hflip + rotate 90 counter-clockwise in DRM
+    *rot_bit_mask = UINT32(DRMRotation::ROT_90);
+    transform.flip_horizontal = !transform.flip_horizontal;
+    transform.flip_vertical = !transform.flip_vertical;
+  }
+
+  if (transform.flip_horizontal) {
+    *rot_bit_mask |= UINT32(DRMRotation::FLIP_H);
+  }
+
+  if (transform.flip_vertical) {
+    *rot_bit_mask |= UINT32(DRMRotation::FLIP_V);
+  }
+}
+
 bool HWDeviceDRM::EnableHotPlugDetection(int enable) {
   return true;
 }
diff --git a/sdm/libs/core/drm/hw_device_drm.h b/sdm/libs/core/drm/hw_device_drm.h
index ad7a3e3..84f15d4 100644
--- a/sdm/libs/core/drm/hw_device_drm.h
+++ b/sdm/libs/core/drm/hw_device_drm.h
@@ -119,6 +119,7 @@
   void SetBlending(const LayerBlending &source, sde_drm::DRMBlendType *target);
   void SetSrcConfig(const LayerBuffer &input_buffer, uint32_t *config);
   void SetRect(const LayerRect &source, sde_drm::DRMRect *target);
+  void SetRotation(LayerTransform transform, const HWRotatorMode &mode, uint32_t* rot_bit_mask);
   DisplayError DefaultCommit(HWLayers *hw_layers);
   DisplayError AtomicCommit(HWLayers *hw_layers);
   void SetupAtomic(HWLayers *hw_layers, bool validate);
diff --git a/sdm/libs/core/drm/hw_info_drm.cpp b/sdm/libs/core/drm/hw_info_drm.cpp
index 6258d73..d5bd5cf 100644
--- a/sdm/libs/core/drm/hw_info_drm.cpp
+++ b/sdm/libs/core/drm/hw_info_drm.cpp
@@ -332,6 +332,7 @@
   hw_resource->max_scale_up = info.max_upscale;
   hw_resource->has_decimation = info.max_horizontal_deci > 1 && info.max_vertical_deci > 1;
   hw_resource->max_pipe_bw = info.max_pipe_bandwidth / kKiloUnit;
+  hw_resource->cache_size = info.cache_size;
 }
 
 void HWInfoDRM::PopulateSupportedFmts(HWSubBlockType sub_blk_type,
diff --git a/sdm/libs/utils/formats.cpp b/sdm/libs/utils/formats.cpp
index b7deb18..4b7190b 100644
--- a/sdm/libs/utils/formats.cpp
+++ b/sdm/libs/utils/formats.cpp
@@ -127,5 +127,87 @@
   }
 }
 
+float GetBufferFormatBpp(LayerBufferFormat format) {
+  float bpp = 0.0f;
+  switch (format) {
+    case kFormatARGB8888:
+    case kFormatRGBA8888:
+    case kFormatBGRA8888:
+    case kFormatXRGB8888:
+    case kFormatRGBX8888:
+    case kFormatBGRX8888:
+    case kFormatRGBA8888Ubwc:
+    case kFormatRGBX8888Ubwc:
+    case kFormatRGBA1010102:
+    case kFormatARGB2101010:
+    case kFormatRGBX1010102:
+    case kFormatXRGB2101010:
+    case kFormatBGRA1010102:
+    case kFormatABGR2101010:
+    case kFormatBGRX1010102:
+    case kFormatXBGR2101010:
+    case kFormatRGBA1010102Ubwc:
+    case kFormatRGBX1010102Ubwc:
+      return 4.0f;
+    case kFormatRGB888:
+    case kFormatBGR888:
+    case kFormatYCbCr420P010:
+    case kFormatYCbCr420P010Ubwc:
+      return 3.0f;
+    case kFormatRGB565:
+    case kFormatBGR565:
+    case kFormatRGBA5551:
+    case kFormatRGBA4444:
+    case kFormatBGR565Ubwc:
+    case kFormatYCbCr422H2V1Packed:
+    case kFormatCbYCrY422H2V1Packed:
+    case kFormatYCrCb422H2V1SemiPlanar:
+    case kFormatYCbCr422H2V1SemiPlanar:
+    case kFormatYCbCr420TP10Ubwc:
+    case kFormatYCbCr422H1V2SemiPlanar:
+    case kFormatYCrCb422H1V2SemiPlanar:
+      return 2.0f;
+    case kFormatYCbCr420Planar:
+    case kFormatYCrCb420Planar:
+    case kFormatYCrCb420PlanarStride16:
+    case kFormatYCbCr420SemiPlanar:
+    case kFormatYCrCb420SemiPlanar:
+    case kFormatYCbCr420SemiPlanarVenus:
+    case kFormatYCrCb420SemiPlanarVenus:
+    case kFormatYCbCr420SPVenusUbwc:
+      return 1.5f;
+    default:
+      return 0.0f;
+  }
+
+  return bpp;
+}
+
+DisplayError GetBufferFormatTileSize(LayerBufferFormat format, FormatTileSize *tile_size) {
+  switch (format) {
+  case kFormatYCbCr420SPVenusUbwc:
+    tile_size->tile_width = 32;
+    tile_size->tile_height = 8;
+    tile_size->uv_tile_width = 16;
+    tile_size->uv_tile_height = 8;
+    break;
+  case kFormatYCbCr420TP10Ubwc:
+    tile_size->tile_width = 48;
+    tile_size->tile_height = 4;
+    tile_size->uv_tile_width = 24;
+    tile_size->uv_tile_height = 4;
+    break;
+  case kFormatYCbCr420P010Ubwc:
+    tile_size->tile_width = 32;
+    tile_size->tile_height = 4;
+    tile_size->uv_tile_width = 16;
+    tile_size->uv_tile_height = 4;
+    break;
+  default:
+    return kErrorNotSupported;
+  }
+  return kErrorNone;
+}
+
 }  // namespace sdm
 
diff --git a/sdm/libs/utils/rect.cpp b/sdm/libs/utils/rect.cpp
index b0cd536..c227cb3 100644
--- a/sdm/libs/utils/rect.cpp
+++ b/sdm/libs/utils/rect.cpp
@@ -261,5 +261,47 @@
   return kOrientationLandscape;
 }
 
+DisplayError GetCropAndDestination(const LayerRect &crop, const LayerRect &dst,
+                                   const bool rotated90, float *crop_width,
+                                   float *crop_height, float *dst_width,
+                                   float *dst_height) {
+  if (!IsValid(crop)) {
+    Log(kTagResources, "Invalid crop rect", crop);
+    return kErrorNotSupported;
+  }
+
+  if (!IsValid(dst)) {
+    Log(kTagResources, "Invalid dst rect", dst);
+    return kErrorNotSupported;
+  }
+
+  *crop_width = crop.right - crop.left;
+  *crop_height = crop.bottom - crop.top;
+  if (rotated90) {
+    std::swap(*crop_width, *crop_height);
+  }
+
+  *dst_width = dst.right - dst.left;
+  *dst_height = dst.bottom - dst.top;
+
+  return kErrorNone;
+}
+
+DisplayError GetScaleFactor(const LayerRect &crop, const LayerRect &dst,
+                            bool rotated90, float *scale_x, float *scale_y) {
+  float crop_width = 1.0f, crop_height = 1.0f, dst_width = 1.0f, dst_height = 1.0f;
+
+  DisplayError error = GetCropAndDestination(crop, dst, rotated90, &crop_width, &crop_height,
+                                             &dst_width, &dst_height);
+  if (error != kErrorNone) {
+    return error;
+  }
+
+  *scale_x = crop_width / dst_width;
+  *scale_y = crop_height / dst_height;
+
+  return kErrorNone;
+}
+
 }  // namespace sdm