sdm: Add support for draw cycles without GPUTarget layer.

- Make GPUTarget layer optional. Return error upon Prepare() call if
  draw cycle is not feasible without GPU support.
- Fix interface documentation.

CRs-Fixed: 1054762
Change-Id: I107a3bfbd1849804467a8f09c5d8702cb31dd5ea
diff --git a/sdm/include/core/layer_stack.h b/sdm/include/core/layer_stack.h
index 39b54c7..0fcab25 100644
--- a/sdm/include/core/layer_stack.h
+++ b/sdm/include/core/layer_stack.h
@@ -64,39 +64,65 @@
   @sa Layer
 */
 enum LayerComposition {
+  /* ==== List of composition types set by SDM === */
+  /* These composition types represent SDM composition decision for the layers which need to
+     be blended. Composition types are set during Prepare() by SDM.
+     Client can set default composition type to any of the below before calling into Prepare(),
+     however client's input value is ignored and does not play any role in composition decision.
+  */
   kCompositionGPU,          //!< This layer will be drawn onto the target buffer by GPU. Display
-                            //!< device will mark the layer for GPU composition if it can not handle
-                            //!< it completely.
+                            //!< device will mark the layer for GPU composition if it can not
+                            //!< handle composition for it.
+                            //!< This composition type is used only if GPUTarget layer is provided
+                            //!< in a composition cycle.
 
   kCompositionGPUS3D,       //!< This layer will be drawn onto the target buffer in s3d mode by GPU.
-                            //!< Display device should mark the layer for GPU composition if it can
-                            //!< not handle it completely.
+                            //!< Display device will mark the layer for GPU composition if it can
+                            //!< not handle composition for it.
+                            //!< This composition type is used only if GPUTarget layer is provided
+                            //!< in a composition cycle.
 
-  kCompositionSDE,          //!< This layer will be handled by SDE. It must not be composed by GPU.
+  kCompositionSDE,          //!< This layer will be composed by SDE. It must not be composed by
+                            //!< GPU or Blit.
 
-  kCompositionHWCursor,     //!< This layer will be handled by SDE using HWCursor. It must not be
-                            //!< composed by GPU
+  kCompositionHWCursor,     //!< This layer will be composed by SDE using HW Cursor. It must not be
+                            //!< composed by GPU or Blit.
 
-  kCompositionHybrid,       //!< This layer will be drawn by a blit engine and SDE together. Display
-                            //!< device will split the layer, update the blit rectangle that
-                            //!< need to be composed by a blit engine and update original source
-                            //!< rectangle that will be composed by SDE.
+  kCompositionHybrid,       //!< This layer will be drawn by a blit engine and SDE together.
+                            //!< Display device will split the layer, update the blit rectangle
+                            //!< that need to be composed by a blit engine and update original
+                            //!< source rectangle that will be composed by SDE.
+                            //!< This composition type is used only if GPUTarget and BlitTarget
+                            //!< layers are provided in a composition cycle.
 
-  kCompositionBlit,         //!< This layer will be composed using Blit Engine
+  kCompositionBlit,         //!< This layer will be composed using Blit Engine.
+                            //!< This composition type is used only if BlitTarget layer is provided
+                            //!< in a composition cycle.
 
+  /* === List of composition types set by Client === */
+  /* These composition types represent target buffer layers onto which GPU or Blit will draw if SDM
+     decide to have some or all layers drawn by respective composition engine.
+     If client does not provide a target buffer layer, SDM will assume that respective composition
+     engine is not available and will not mark any layer for such a composition. If SDM is unable
+     to handle layers without support of such a composition engine, Prepare() call will return
+     failure.
+  */
   kCompositionGPUTarget,    //!< This layer will hold result of composition for layers marked for
                             //!< GPU composition.
-                            //!< If display device does not set any layer for SDE composition then
-                            //!< this would be ignored during Commit().
+                            //!< If display device does not set any layer for GPU composition then
+                            //!< this layer would be ignored. Else, this layer will be composed
+                            //!< with other layers marked for SDE composition by SDE.
                             //!< Only one layer shall be marked as target buffer by the caller.
-                            //!< GPU target layer shall be after application layers in layer stack.
+                            //!< GPU target layer shall be placed after all application layers
+                            //!< in the layer stack.
 
   kCompositionBlitTarget,   //!< This layer will hold result of composition for blit rectangles
                             //!< from the layers marked for hybrid composition. Nth blit rectangle
                             //!< in a layer shall be composed onto Nth blit target.
                             //!< If display device does not set any layer for hybrid composition
-                            //!< then this would be ignored during Commit().
-                            //!< Blit target layers shall be after GPU target layer in layer stack.
+                            //!< then this would be ignored.
+                            //!< Blit target layers shall be placed after GPUTarget in the layer
+                            //!< stack.
 };
 
 /*! @brief This structure defines rotation and flip values for a display layer.
diff --git a/sdm/include/private/hw_info_types.h b/sdm/include/private/hw_info_types.h
index fd84fc1..4ae696d 100644
--- a/sdm/include/private/hw_info_types.h
+++ b/sdm/include/private/hw_info_types.h
@@ -418,6 +418,8 @@
 
 struct HWLayersInfo {
   LayerStack *stack = NULL;        // Input layer stack. Set by the caller.
+  uint32_t app_layer_count = 0;    // Total number of app layers. Must not be 0.
+  uint32_t gpu_target_index = 0;   // GPU target layer index. 0 if not present.
 
   uint32_t index[kMaxSDELayers];   // Indexes of the layers from the layer stack which need to be
                                    // programmed on hardware.
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index 0e48f2c..b1a34d1 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -136,28 +136,39 @@
   return kErrorNone;
 }
 
-DisplayError DisplayBase::ValidateGPUTarget(LayerStack *layer_stack) {
-  uint32_t i = 0;
-  std::vector<Layer *>layers = layer_stack->layers;
+DisplayError DisplayBase::BuildLayerStackStats(LayerStack *layer_stack) {
+  std::vector<Layer *> &layers = layer_stack->layers;
+  HWLayersInfo &hw_layers_info = hw_layers_.info;
 
-  // TODO(user): Remove this check once we have query display attributes on virtual display
-  if (display_type_ == kVirtual) {
-    return kErrorNone;
-  }
-  uint32_t layer_count = UINT32(layers.size());
-  while ((i < layer_count) && (layers.at(i)->composition != kCompositionGPUTarget)) {
-    i++;
+  hw_layers_info.stack = layer_stack;
+
+  for (auto &layer : layers) {
+    if (layer->composition == kCompositionGPUTarget) {
+      hw_layers_info.gpu_target_index = hw_layers_info.app_layer_count;
+      break;
+    }
+    hw_layers_info.app_layer_count++;
   }
 
-  if (i >= layer_count) {
-    DLOGE("Either layer count is zero or GPU target layer is not present");
+  DLOGV_IF(kTagNone, "LayerStack layer_count: %d, app_layer_count: %d, gpu_target_index: %d, "
+           "display type: %d", layers.size(), hw_layers_info.app_layer_count,
+           hw_layers_info.gpu_target_index, display_type_);
+
+  if (!hw_layers_info.app_layer_count) {
+    DLOGE("Layer count is zero");
     return kErrorParameters;
   }
 
-  uint32_t gpu_target_index = i;
+  if (hw_layers_info.gpu_target_index) {
+    return ValidateGPUTargetParams();
+  }
 
-  // Check GPU target layer
-  Layer *gpu_target_layer = layers.at(gpu_target_index);
+  return kErrorNone;
+}
+
+DisplayError DisplayBase::ValidateGPUTargetParams() {
+  HWLayersInfo &hw_layers_info = hw_layers_.info;
+  Layer *gpu_target_layer = hw_layers_info.stack->layers.at(hw_layers_info.gpu_target_index);
 
   if (!IsValid(gpu_target_layer->src_rect)) {
     DLOGE("Invalid src rect for GPU target layer");
@@ -184,9 +195,9 @@
 
   if (gpu_target_layer_dst_xpixels > mixer_attributes_.width ||
     gpu_target_layer_dst_ypixels > mixer_attributes_.height) {
-    DLOGE("GPU target layer dst rect is not with in limits gpu wxh %fx%f mixer wxh %dx%d",
-    gpu_target_layer_dst_xpixels, gpu_target_layer_dst_ypixels, mixer_attributes_.width,
-    mixer_attributes_.height);
+    DLOGE("GPU target layer dst rect is not with in limits gpu wxh %fx%f, mixer wxh %dx%d",
+                  gpu_target_layer_dst_xpixels, gpu_target_layer_dst_ypixels,
+                  mixer_attributes_.width, mixer_attributes_.height);
     return kErrorParameters;
   }
 
@@ -205,7 +216,7 @@
     return kErrorParameters;
   }
 
-  error = ValidateGPUTarget(layer_stack);
+  error = BuildLayerStackStats(layer_stack);
   if (error != kErrorNone) {
     return error;
   }
@@ -219,9 +230,6 @@
     disable_pu_one_frame_ = false;
   }
 
-  hw_layers_.info.stack = layer_stack;
-  hw_layers_.output_compression = 1.0f;
-
   comp_manager_->PrePrepare(display_comp_ctx_, &hw_layers_);
   while (true) {
     error = comp_manager_->Prepare(display_comp_ctx_, &hw_layers_);
diff --git a/sdm/libs/core/display_base.h b/sdm/libs/core/display_base.h
index 91bbc37..2bc94b7 100644
--- a/sdm/libs/core/display_base.h
+++ b/sdm/libs/core/display_base.h
@@ -113,12 +113,14 @@
   virtual bool IsPrimaryDisplay();
 
  protected:
+  DisplayError BuildLayerStackStats(LayerStack *layer_stack);
+  virtual DisplayError ValidateGPUTargetParams();
+
   // DumpImpl method
   void AppendDump(char *buffer, uint32_t length);
 
   bool IsRotationRequired(HWLayers *hw_layers);
   const char *GetName(const LayerComposition &composition);
-  DisplayError ValidateGPUTarget(LayerStack *layer_stack);
   DisplayError ReconfigureDisplay();
   bool NeedsMixerReconfiguration(LayerStack *layer_stack, uint32_t *new_mixer_width,
                                  uint32_t *new_mixer_height);
diff --git a/sdm/libs/core/display_virtual.h b/sdm/libs/core/display_virtual.h
index 3207ec1..d6ce915 100644
--- a/sdm/libs/core/display_virtual.h
+++ b/sdm/libs/core/display_virtual.h
@@ -62,6 +62,11 @@
   virtual DisplayError SetDetailEnhancerData(const DisplayDetailEnhancerData &de_data) {
     return kErrorNotSupported;
   }
+  virtual DisplayError ValidateGPUTargetParams() {
+    // TODO(user): Validate GPU target for virtual display when query display attributes
+    // on virtual display is functional.
+    return kErrorNone;
+  }
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/core/strategy.cpp b/sdm/libs/core/strategy.cpp
index 8519f7e..7a983e5 100644
--- a/sdm/libs/core/strategy.cpp
+++ b/sdm/libs/core/strategy.cpp
@@ -80,19 +80,6 @@
   hw_layers_info_ = hw_layers_info;
   extn_start_success_ = false;
   tried_default_ = false;
-  uint32_t i = 0;
-  LayerStack *layer_stack = hw_layers_info_->stack;
-  uint32_t layer_count = UINT32(layer_stack->layers.size());
-  for (; i < layer_count; i++) {
-    if (layer_stack->layers.at(i)->composition == kCompositionGPUTarget) {
-      fb_layer_index_ = i;
-      break;
-    }
-  }
-
-  if (i == layer_count) {
-    return kErrorUndefined;
-  }
 
   if (partial_update_intf_) {
     partial_update_intf_->ControlPartialUpdate(partial_update_enable);
@@ -130,6 +117,11 @@
     }
   }
 
+  // Default composition is not possible if GPU composition is not supported.
+  if (!hw_layers_info_->gpu_target_index) {
+    return kErrorNotSupported;
+  }
+
   // Default composition is already tried.
   if (tried_default_) {
     return kErrorUndefined;
@@ -141,25 +133,17 @@
   uint32_t &hw_layer_count = hw_layers_info_->count;
   hw_layer_count = 0;
 
-  for (uint32_t i = 0; i < layer_stack->layers.size(); i++) {
-    Layer *layer = layer_stack->layers.at(i);
-    LayerComposition &composition = layer->composition;
-    if (composition == kCompositionGPUTarget) {
-      hw_layers_info_->updated_src_rect[hw_layer_count] = layer->src_rect;
-      hw_layers_info_->updated_dst_rect[hw_layer_count] = layer->dst_rect;
-      hw_layers_info_->index[hw_layer_count++] = i;
-    } else if (composition != kCompositionBlitTarget) {
-      composition = kCompositionGPU;
-    }
+  for (uint32_t i = 0; i < hw_layers_info_->app_layer_count; i++) {
+    layer_stack->layers.at(i)->composition = kCompositionGPU;
   }
 
+  Layer *gpu_target_layer = layer_stack->layers.at(hw_layers_info_->gpu_target_index);
+  hw_layers_info_->updated_src_rect[hw_layer_count] = gpu_target_layer->src_rect;
+  hw_layers_info_->updated_dst_rect[hw_layer_count] = gpu_target_layer->dst_rect;
+  hw_layers_info_->index[hw_layer_count++] = hw_layers_info_->gpu_target_index;
+
   tried_default_ = true;
 
-  // There can be one and only one GPU target buffer.
-  if (hw_layer_count != 1) {
-    return kErrorParameters;
-  }
-
   return kErrorNone;
 }
 
diff --git a/sdm/libs/core/strategy.h b/sdm/libs/core/strategy.h
index b284d61..8b4b6f4 100644
--- a/sdm/libs/core/strategy.h
+++ b/sdm/libs/core/strategy.h
@@ -62,7 +62,6 @@
   HWMixerAttributes mixer_attributes_ = {};
   HWDisplayAttributes display_attributes_ = {};
   DisplayConfigVariableInfo fb_config_ = {};
-  uint32_t fb_layer_index_ = 0;
   bool extn_start_success_ = false;
   bool tried_default_ = false;
 };