sde: Add support for virtual display

1. Create virtual display, if the current virtual display list is
   valid and the output buffer handle is not NULL.
2. Configure input and output layers of writeback for the composition
   using writeback.
3. Propagate the retire fence back to framework, so that the consumer
   will wait for retire fence before it consumes the output buffer.
4. Recreate the virtual display, if the width, height or format of the
   output buffer changes.
5. Destroy virtual display, if the current virtual display list is
   invalid or the output buffer handle is NULL.

Change-Id: I096575381da3db1d0c7b7270bc55c5d936b9f5a8
diff --git a/displayengine/include/core/debug_interface.h b/displayengine/include/core/debug_interface.h
index b01e086..c90e1ff 100644
--- a/displayengine/include/core/debug_interface.h
+++ b/displayengine/include/core/debug_interface.h
@@ -44,6 +44,7 @@
   kTagNone,             //!< Debug log is not tagged. This type of logs should always be printed.
   kTagResources,        //!< Debug log is tagged for resource management.
   kTagStrategy,         //!< Debug log is tagged for strategy decisions.
+  kTagCompManager,      //!< Debug log is tagged for composition manager.
   kTagDriverConfig,     //!< Debug log is tagged for driver config.
   kTagBufferManager,    //!< Debug log is tagged for buffer manager state transitions.
   kTagOfflineCtrl,      //!< Debug log is tagged for offline controller.
diff --git a/displayengine/include/core/display_interface.h b/displayengine/include/core/display_interface.h
index 1e99d1a..c054fae 100644
--- a/displayengine/include/core/display_interface.h
+++ b/displayengine/include/core/display_interface.h
@@ -284,6 +284,14 @@
 
   /*! @brief Method to set active configuration for variable properties of the display device.
 
+    @param[in] variable_info \link DisplayConfigVariableInfo \endlink
+
+    @return \link DisplayError \endlink
+  */
+  virtual DisplayError SetActiveConfig(DisplayConfigVariableInfo *variable_info) = 0;
+
+  /*! @brief Method to set active configuration for variable properties of the display device.
+
     @param[in] index index of the mode corresponding to variable properties.
 
     @return \link DisplayError \endlink
diff --git a/displayengine/libs/core/comp_manager.cpp b/displayengine/libs/core/comp_manager.cpp
index a9b4e6c..c759ebb 100644
--- a/displayengine/libs/core/comp_manager.cpp
+++ b/displayengine/libs/core/comp_manager.cpp
@@ -129,6 +129,10 @@
   // resources for the added display is configured properly.
   safe_mode_ = true;
 
+  DLOGV_IF(kTagCompManager, "registered display bit mask 0x%x, configured display bit mask 0x%x, " \
+           "display type %d", registered_displays_, configured_displays_,
+           display_comp_ctx->display_type);
+
   return kErrorNone;
 }
 
@@ -144,6 +148,10 @@
   CLEAR_BIT(registered_displays_, display_comp_ctx->display_type);
   CLEAR_BIT(configured_displays_, display_comp_ctx->display_type);
 
+  DLOGV_IF(kTagCompManager, "registered display bit mask 0x%x, configured display bit mask 0x%x, " \
+           "display type %d", registered_displays_, configured_displays_,
+           display_comp_ctx->display_type);
+
   if (display_comp_ctx) {
     delete display_comp_ctx;
     display_comp_ctx = NULL;
@@ -265,6 +273,10 @@
 
   display_comp_ctx->idle_fallback = false;
 
+  DLOGV_IF(kTagCompManager, "registered display bit mask 0x%x, configured display bit mask 0x%x, " \
+           "display type %d", registered_displays_, configured_displays_,
+           display_comp_ctx->display_type);
+
   return kErrorNone;
 }
 
diff --git a/displayengine/libs/core/core_impl.cpp b/displayengine/libs/core/core_impl.cpp
index ccc9331..bd6ab9a 100644
--- a/displayengine/libs/core/core_impl.cpp
+++ b/displayengine/libs/core/core_impl.cpp
@@ -85,7 +85,7 @@
 }
 
 DisplayError CoreImpl::CreateDisplay(DisplayType type, DisplayEventHandler *event_handler,
-                                    DisplayInterface **intf) {
+                                     DisplayInterface **intf) {
   SCOPE_LOCK(locker_);
 
   if (UNLIKELY(!event_handler || !intf)) {
diff --git a/displayengine/libs/core/display_base.cpp b/displayengine/libs/core/display_base.cpp
index fcb4d56..058bacc 100644
--- a/displayengine/libs/core/display_base.cpp
+++ b/displayengine/libs/core/display_base.cpp
@@ -307,9 +307,14 @@
 
   switch (state) {
   case kStateOff:
-    hw_layers_.info.count = 0;
-    comp_manager_->Purge(display_comp_ctx_);
-    error = hw_intf_->PowerOff(hw_device_);
+    // Invoke flush during suspend for HDMI and virtual displays. StateOff is handled
+    // separately for primary in DisplayPrimary::SetDisplayState() function.
+    error = hw_intf_->Flush(hw_device_);
+    if (error == kErrorNone) {
+      comp_manager_->Purge(display_comp_ctx_);
+      state_ = state;
+      hw_layers_.info.count = 0;
+    }
     break;
 
   case kStateOn:
@@ -336,6 +341,36 @@
   return error;
 }
 
+DisplayError DisplayBase::SetActiveConfig(DisplayConfigVariableInfo *variable_info) {
+  SCOPE_LOCK(locker_);
+  DisplayError error = kErrorNone;
+
+  if (!variable_info) {
+    return kErrorParameters;
+  }
+
+  HWDisplayAttributes display_attributes = display_attributes_[active_mode_index_];
+
+  display_attributes.x_pixels = variable_info->x_pixels;
+  display_attributes.y_pixels = variable_info->y_pixels;
+  display_attributes.fps = variable_info->fps;
+
+  // if display is already connected, unregister display from composition manager and register
+  // the display with new configuration.
+  if (display_comp_ctx_) {
+    comp_manager_->UnregisterDisplay(display_comp_ctx_);
+  }
+
+  error = comp_manager_->RegisterDisplay(display_type_, display_attributes, &display_comp_ctx_);
+  if (error != kErrorNone) {
+    return error;
+  }
+
+  display_attributes_[active_mode_index_] = display_attributes;
+
+  return kErrorNone;
+}
+
 DisplayError DisplayBase::SetActiveConfig(uint32_t index) {
   SCOPE_LOCK(locker_);
   DisplayError error = kErrorNone;
@@ -346,9 +381,18 @@
 
   error = hw_intf_->SetDisplayAttributes(hw_device_, index);
   if (error != kErrorNone) {
-    active_mode_index_ = index;
+    return error;
   }
 
+  active_mode_index_ = index;
+
+  if (display_comp_ctx_) {
+    comp_manager_->UnregisterDisplay(display_comp_ctx_);
+  }
+
+  error = comp_manager_->RegisterDisplay(display_type_, display_attributes_[index],
+                                         &display_comp_ctx_);
+
   return error;
 }
 
diff --git a/displayengine/libs/core/display_base.h b/displayengine/libs/core/display_base.h
index 5f9a8c8..d2b67e3 100644
--- a/displayengine/libs/core/display_base.h
+++ b/displayengine/libs/core/display_base.h
@@ -56,6 +56,7 @@
   virtual DisplayError GetActiveConfig(uint32_t *index);
   virtual DisplayError GetVSyncState(bool *enabled);
   virtual DisplayError SetDisplayState(DisplayState state);
+  virtual DisplayError SetActiveConfig(DisplayConfigVariableInfo *variable_info);
   virtual DisplayError SetActiveConfig(uint32_t index);
   virtual DisplayError SetVSyncState(bool enable);
   virtual void SetIdleTimeoutMs(uint32_t timeout_ms);
diff --git a/displayengine/libs/core/display_hdmi.cpp b/displayengine/libs/core/display_hdmi.cpp
index a384385..ed2a859 100644
--- a/displayengine/libs/core/display_hdmi.cpp
+++ b/displayengine/libs/core/display_hdmi.cpp
@@ -76,29 +76,5 @@
   return best_config_mode;
 }
 
-DisplayError DisplayHDMI::SetDisplayState(DisplayState state) {
-  DisplayError error = kErrorNone;
-
-  DLOGI("Set state = %d", state);
-
-  if (state == kStateOff) {
-    SCOPE_LOCK(locker_);
-    if (state == state_) {
-      DLOGI("Same state transition is requested.");
-      return kErrorNone;
-    }
-    error = hw_intf_->Flush(hw_device_);
-    if (error == kErrorNone) {
-      comp_manager_->Purge(display_comp_ctx_);
-      state_ = state;
-      hw_layers_.info.count = 0;
-    }
-  } else {
-    error = DisplayBase::SetDisplayState(state);
-  }
-
-  return error;
-}
-
 }  // namespace sde
 
diff --git a/displayengine/libs/core/display_hdmi.h b/displayengine/libs/core/display_hdmi.h
index 94c40a1..91e4797 100644
--- a/displayengine/libs/core/display_hdmi.h
+++ b/displayengine/libs/core/display_hdmi.h
@@ -34,7 +34,6 @@
   DisplayHDMI(DisplayEventHandler *event_handler, HWInterface *hw_intf, CompManager *comp_manager,
               OfflineCtrl *offline_ctrl);
   virtual int GetBestConfig();
-  virtual DisplayError SetDisplayState(DisplayState state);
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/core/display_primary.cpp b/displayengine/libs/core/display_primary.cpp
index 8eed8ee..ac44fe3 100644
--- a/displayengine/libs/core/display_primary.cpp
+++ b/displayengine/libs/core/display_primary.cpp
@@ -35,5 +35,29 @@
                                CompManager *comp_manager, OfflineCtrl *offline_ctrl)
   : DisplayBase(kPrimary, event_handler, kDevicePrimary, hw_intf, comp_manager, offline_ctrl) { }
 
+DisplayError DisplayPrimary::SetDisplayState(DisplayState state) {
+  DisplayError error = kErrorNone;
+
+  DLOGI("Set state = %d", state);
+
+  if (state == kStateOff) {
+    SCOPE_LOCK(locker_);
+    if (state == state_) {
+      DLOGI("Same state transition is requested.");
+      return kErrorNone;
+    }
+    error = hw_intf_->PowerOff(hw_device_);
+    if (error == kErrorNone) {
+      comp_manager_->Purge(display_comp_ctx_);
+      state_ = state;
+      hw_layers_.info.count = 0;
+    }
+  } else {
+    error = DisplayBase::SetDisplayState(state);
+  }
+
+  return error;
+}
+
 }  // namespace sde
 
diff --git a/displayengine/libs/core/display_primary.h b/displayengine/libs/core/display_primary.h
index ea4cf2b..79fbddf 100644
--- a/displayengine/libs/core/display_primary.h
+++ b/displayengine/libs/core/display_primary.h
@@ -33,6 +33,7 @@
  public:
   DisplayPrimary(DisplayEventHandler *event_handler, HWInterface *hw_intf,
                  CompManager *comp_manager, OfflineCtrl *offline_ctrl);
+  virtual DisplayError SetDisplayState(DisplayState state);
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/core/hw_framebuffer.cpp b/displayengine/libs/core/hw_framebuffer.cpp
index 714e678..306857b 100644
--- a/displayengine/libs/core/hw_framebuffer.cpp
+++ b/displayengine/libs/core/hw_framebuffer.cpp
@@ -258,6 +258,7 @@
 
   switch (hw_context->type) {
   case kDevicePrimary:
+  case kDeviceVirtual:
     break;
   case kDeviceHDMI:
     hdmi_mode_count_ = 0;
@@ -279,6 +280,7 @@
 
   switch (hw_context->type) {
   case kDevicePrimary:
+  case kDeviceVirtual:
     *count = 1;
     break;
   case kDeviceHDMI:
@@ -370,6 +372,9 @@
     }
     break;
 
+  case kDeviceVirtual:
+    break;
+
   default:
     return kErrorParameters;
   }
@@ -385,6 +390,7 @@
 
   switch (hw_context->type) {
   case kDevicePrimary:
+  case kDeviceVirtual:
     break;
 
   case kDeviceHDMI:
@@ -657,7 +663,8 @@
   DLOGV_IF(kTagDriverConfig, "SDE layer count is %d", hw_layer_info.count);
 
   mdp_layer_commit_v1 &mdp_commit = hw_display->mdp_disp_commit.commit_v1;
-  mdp_input_layer *mdp_layers = hw_display->mdp_disp_layers;
+  mdp_input_layer *mdp_layers = hw_display->mdp_in_layers;
+  mdp_output_layer *mdp_out_layer = &hw_display->mdp_out_layer;
   uint32_t &mdp_layer_count = mdp_commit.input_layer_cnt;
 
   for (uint32_t i = 0; i < hw_layer_info.count; i++) {
@@ -729,6 +736,22 @@
     }
   }
 
+  if (hw_context->type == kDeviceVirtual) {
+    LayerBuffer *output_buffer = hw_layers->info.stack->output_buffer;
+    // TODO(user): Need to assign the writeback id from the resource manager, since the support
+    // has not been added hard coding it to 2 for now.
+    mdp_out_layer->writeback_ndx = 2;
+    mdp_out_layer->buffer.width = output_buffer->width;
+    mdp_out_layer->buffer.height = output_buffer->height;
+    SetFormat(output_buffer->format, &mdp_out_layer->buffer.format);
+
+    DLOGI_IF(kTagDriverConfig, "******************* Output buffer Info **********************");
+    DLOGI_IF(kTagDriverConfig, "out_w %d, out_h %d, out_f %d, wb_id %d",
+             mdp_out_layer->buffer.width, mdp_out_layer->buffer.height,
+             mdp_out_layer->buffer.format, mdp_out_layer->writeback_ndx);
+    DLOGI_IF(kTagDriverConfig, "*************************************************************");
+  }
+
   mdp_commit.flags |= MDP_VALIDATE_LAYER;
   if (ioctl_(hw_context->device_fd, MSMFB_ATOMIC_COMMIT, &hw_display->mdp_disp_commit) < 0) {
     IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, hw_context->type);
@@ -750,7 +773,8 @@
   DLOGV_IF(kTagDriverConfig, "SDE layer count is %d", hw_layer_info.count);
 
   mdp_layer_commit_v1 &mdp_commit = hw_display->mdp_disp_commit.commit_v1;
-  mdp_input_layer *mdp_layers = hw_display->mdp_disp_layers;
+  mdp_input_layer *mdp_layers = hw_display->mdp_in_layers;
+  mdp_output_layer *mdp_out_layer = &hw_display->mdp_out_layer;
   uint32_t mdp_layer_index = 0;
 
   for (uint32_t i = 0; i < hw_layer_info.count; i++) {
@@ -774,7 +798,8 @@
           mdp_buffer.plane_count = 1;
           mdp_buffer.planes[0].fd = input_buffer->planes[0].fd;
           mdp_buffer.planes[0].offset = input_buffer->planes[0].offset;
-          mdp_buffer.planes[0].stride = input_buffer->planes[0].stride;
+          SetStride(hw_context->type, input_buffer->format, input_buffer->planes[0].stride,
+                    &mdp_buffer.planes[0].stride);
         } else {
           DLOGW("Invalid buffer fd, setting plane count to 0");
           mdp_buffer.plane_count = 0;
@@ -785,7 +810,10 @@
 
         DLOGV_IF(kTagDriverConfig, "****************** Layer[%d] %s pipe Input *******************",
                  i, count ? "Right" : "Left");
-        DLOGV_IF(kTagDriverConfig, "in_buf_fd %d, in_buf_offset %d, in_buf_stride %d, " \
+        DLOGI_IF(kTagDriverConfig, "in_w %d, in_h %d, in_f %d, horz_deci %d, vert_deci %d",
+                 mdp_buffer.width, mdp_buffer.height, mdp_buffer.format, mdp_layer.horz_deci,
+                 mdp_layer.vert_deci);
+        DLOGI_IF(kTagDriverConfig, "in_buf_fd %d, in_buf_offset %d, in_buf_stride %d, " \
                  "in_plane_count %d, in_fence %d, layer count %d", mdp_buffer.planes[0].fd,
                  mdp_buffer.planes[0].offset, mdp_buffer.planes[0].stride, mdp_buffer.plane_count,
                  mdp_buffer.fence, mdp_commit.input_layer_cnt);
@@ -793,6 +821,28 @@
       }
     }
   }
+  if (hw_context->type == kDeviceVirtual) {
+    LayerBuffer *output_buffer = hw_layers->info.stack->output_buffer;
+
+    if (output_buffer->planes[0].fd >= 0) {
+      mdp_out_layer->buffer.planes[0].fd = output_buffer->planes[0].fd;
+      mdp_out_layer->buffer.planes[0].offset = output_buffer->planes[0].offset;
+      SetStride(hw_context->type, output_buffer->format, output_buffer->planes[0].stride,
+                &mdp_out_layer->buffer.planes[0].stride);
+      mdp_out_layer->buffer.plane_count = 1;
+    } else {
+      DLOGW("Invalid output buffer fd, setting plane count to 0");
+      mdp_out_layer->buffer.plane_count = 0;
+    }
+
+    mdp_out_layer->buffer.fence = output_buffer->acquire_fence_fd;
+
+    DLOGI_IF(kTagDriverConfig, "******************* Output buffer Info **********************");
+    DLOGI_IF(kTagDriverConfig, "out_fd %d, out_offset %d, out_stride %d, acquire_fence %d",
+             mdp_out_layer->buffer.planes[0].fd, mdp_out_layer->buffer.planes[0].offset,
+             mdp_out_layer->buffer.planes[0].stride,  mdp_out_layer->buffer.fence);
+    DLOGI_IF(kTagDriverConfig, "*************************************************************");
+  }
 
   mdp_commit.release_fence = -1;
   mdp_commit.flags &= ~MDP_VALIDATE_LAYER;
@@ -801,9 +851,10 @@
     return kErrorHardware;
   }
 
+  stack->retire_fence_fd = mdp_commit.retire_fence;
+
   // MDP returns only one release fence for the entire layer stack. Duplicate this fence into all
   // layers being composed by MDP.
-  stack->retire_fence_fd = mdp_commit.retire_fence;
   for (uint32_t i = 0; i < hw_layer_info.count; i++) {
     uint32_t layer_index = hw_layer_info.index[i];
     LayerBuffer *input_buffer = stack->layers[layer_index].input_buffer;
@@ -825,6 +876,11 @@
       }
     }
   }
+  DLOGI_IF(kTagDriverConfig, "*************************** %s Commit Input ************************",
+           GetDeviceString(hw_context->type));
+  DLOGI_IF(kTagDriverConfig, "retire_fence_fd %d", stack->retire_fence_fd);
+  DLOGI_IF(kTagDriverConfig, "*************************************************************");
+
   close_(mdp_commit.release_fence);
 
   return kErrorNone;
@@ -931,14 +987,15 @@
 
         mdp_rot_item->input.planes[0].fd = layer.input_buffer->planes[0].fd;
         mdp_rot_item->input.planes[0].offset = layer.input_buffer->planes[0].offset;
-        SetStride(layer.input_buffer->format, layer.input_buffer->width,
+        SetStride(hw_context->type, layer.input_buffer->format, layer.input_buffer->width,
                   &mdp_rot_item->input.planes[0].stride);
         mdp_rot_item->input.plane_count = 1;
         mdp_rot_item->input.fence = layer.input_buffer->acquire_fence_fd;
 
         mdp_rot_item->output.planes[0].fd = rot_buf_info->output_buffer.planes[0].fd;
         mdp_rot_item->output.planes[0].offset = rot_buf_info->output_buffer.planes[0].offset;
-        SetStride(rot_buf_info->output_buffer.format, rot_buf_info->output_buffer.planes[0].stride,
+        SetStride(hw_context->type, rot_buf_info->output_buffer.format,
+                  rot_buf_info->output_buffer.planes[0].stride,
                   &mdp_rot_item->output.planes[0].stride);
         mdp_rot_item->output.plane_count = 1;
         mdp_rot_item->output.fence = -1;
@@ -1036,7 +1093,15 @@
   return kErrorNone;
 }
 
-DisplayError HWFrameBuffer::SetStride(LayerBufferFormat format, uint32_t width, uint32_t *target) {
+DisplayError HWFrameBuffer::SetStride(HWDeviceType device_type, LayerBufferFormat format,
+                                      uint32_t width, uint32_t *target) {
+  // TODO(user): This SetStride function is an workaround to satisfy the driver expectation for
+  // rotator and virtual devices. Eventually this will be taken care in the driver.
+  if (device_type != kDeviceRotator && device_type != kDeviceVirtual) {
+    *target = width;
+    return kErrorNone;
+  }
+
   switch (format) {
   case kFormatARGB8888:
   case kFormatRGBA8888:
diff --git a/displayengine/libs/core/hw_framebuffer.h b/displayengine/libs/core/hw_framebuffer.h
index d6b76b5..6df705d 100644
--- a/displayengine/libs/core/hw_framebuffer.h
+++ b/displayengine/libs/core/hw_framebuffer.h
@@ -66,20 +66,23 @@
  private:
   struct HWDisplay {
     mdp_layer_commit mdp_disp_commit;
-    mdp_input_layer mdp_disp_layers[kMaxSDELayers * 2];   // split panel (left + right)
+    mdp_input_layer mdp_in_layers[kMaxSDELayers * 2];   // split panel (left + right)
+    mdp_output_layer mdp_out_layer;
 
     HWDisplay() { Reset(); }
 
     void Reset() {
       memset(&mdp_disp_commit, 0, sizeof(mdp_disp_commit));
-      memset(&mdp_disp_layers, 0, sizeof(mdp_disp_layers));
+      memset(&mdp_in_layers, 0, sizeof(mdp_in_layers));
+      memset(&mdp_out_layer, 0, sizeof(mdp_out_layer));
 
       for (uint32_t i = 0; i < kMaxSDELayers * 2; i++) {
-        mdp_disp_layers[i].buffer.fence = -1;
+        mdp_in_layers[i].buffer.fence = -1;
       }
 
       mdp_disp_commit.version = MDP_COMMIT_VERSION_1_0;
-      mdp_disp_commit.commit_v1.input_layers = mdp_disp_layers;
+      mdp_disp_commit.commit_v1.input_layers = mdp_in_layers;
+      mdp_disp_commit.commit_v1.output_layer = &mdp_out_layer;
       mdp_disp_commit.commit_v1.release_fence = -1;
     }
   };
@@ -160,7 +163,8 @@
   DisplayError RotatorCommit(HWContext *device_ctx, HWLayers *hw_layers);
 
   inline DisplayError SetFormat(const LayerBufferFormat &source, uint32_t *target);
-  inline DisplayError SetStride(LayerBufferFormat format,  uint32_t width, uint32_t *target);
+  inline DisplayError SetStride(HWDeviceType device_type, LayerBufferFormat format,
+                                uint32_t width, uint32_t *target);
   inline void SetBlending(const LayerBlending &source, mdss_mdp_blend_op *target);
   inline void SetRect(const LayerRect &source, mdp_rect *target);
   inline void SyncMerge(const int &fd1, const int &fd2, int *target);
diff --git a/displayengine/libs/core/res_manager.cpp b/displayengine/libs/core/res_manager.cpp
index 7eb2b87..16fc8b4 100644
--- a/displayengine/libs/core/res_manager.cpp
+++ b/displayengine/libs/core/res_manager.cpp
@@ -376,6 +376,11 @@
 }
 
 bool ResManager::CheckBandwidth(DisplayResourceContext *display_ctx, HWLayers *hw_layers) {
+  // No need to check bandwidth for virtual displays
+  if (display_ctx->display_type == kVirtual) {
+    return true;
+  }
+
   float max_pipe_bw = FLOAT(hw_res_info_.max_pipe_bw) / 1000000;  // KBps to GBps
   float max_sde_clk = FLOAT(hw_res_info_.max_sde_clk) / 1000000;  // Hz to MHz
   const struct HWLayersInfo &layer_info = hw_layers->info;
diff --git a/displayengine/libs/hwc/hwc_debugger.cpp b/displayengine/libs/hwc/hwc_debugger.cpp
index 6a6cf08..d35e9cf 100644
--- a/displayengine/libs/hwc/hwc_debugger.cpp
+++ b/displayengine/libs/hwc/hwc_debugger.cpp
@@ -60,6 +60,14 @@
   }
 }
 
+void HWCDebugHandler::DebugCompManager(bool enable) {
+  if (enable) {
+    SET_BIT(debug_flags_, kTagCompManager);
+  } else {
+    CLEAR_BIT(debug_flags_, kTagCompManager);
+  }
+}
+
 void HWCDebugHandler::DebugDriverConfig(bool enable) {
   if (enable) {
     SET_BIT(debug_flags_, kTagDriverConfig);
diff --git a/displayengine/libs/hwc/hwc_debugger.h b/displayengine/libs/hwc/hwc_debugger.h
index 705ae3a..def31db 100644
--- a/displayengine/libs/hwc/hwc_debugger.h
+++ b/displayengine/libs/hwc/hwc_debugger.h
@@ -57,6 +57,7 @@
   static void DebugAll(bool enable);
   static void DebugResources(bool enable);
   static void DebugStrategy(bool enable);
+  static void DebugCompManager(bool enable);
   static void DebugDriverConfig(bool enable);
   static void DebugBufferManager(bool enable);
   static void DebugOfflineCtrl(bool enable);
diff --git a/displayengine/libs/hwc/hwc_display.cpp b/displayengine/libs/hwc/hwc_display.cpp
index a1f907c..d8c8a64 100644
--- a/displayengine/libs/hwc/hwc_display.cpp
+++ b/displayengine/libs/hwc/hwc_display.cpp
@@ -42,13 +42,14 @@
 HWCDisplay::HWCDisplay(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, DisplayType type,
                        int id)
   : core_intf_(core_intf), hwc_procs_(hwc_procs), type_(type), id_(id), display_intf_(NULL),
-    flush_(false) {
+    flush_(false), output_buffer_(NULL) {
 }
 
 int HWCDisplay::Init() {
   DisplayError error = core_intf_->CreateDisplay(type_, this, &display_intf_);
   if (UNLIKELY(error != kErrorNone)) {
-    DLOGE("Display create failed. Error = %d", error);
+    DLOGE("Display create failed. Error = %d display_type %d event_handler %p disp_intf %p",
+      error, type_, this, &display_intf_);
     return -EINVAL;
   }
 
@@ -181,6 +182,10 @@
   return index;
 }
 
+int HWCDisplay::SetActiveConfig(hwc_display_contents_1_t *content_list) {
+  return 0;
+}
+
 int HWCDisplay::SetActiveConfig(int index) {
   DisplayError error = kErrorNone;
 
@@ -303,7 +308,8 @@
     LayerBuffer *layer_buffer = layer.input_buffer;
 
     if (pvt_handle) {
-      if (SetFormat(pvt_handle->format, pvt_handle->flags, &layer_buffer->format)) {
+      layer_buffer->format = GetSDEFormat(pvt_handle->format, pvt_handle->flags);
+      if (layer_buffer->format == kFormatInvalid) {
         return -EINVAL;
       }
 
@@ -540,44 +546,46 @@
   }
 }
 
-int HWCDisplay::SetFormat(const int32_t &source, const int flags, LayerBufferFormat *target) {
-
-  if (flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) {
-    switch (source) {
-      case HAL_PIXEL_FORMAT_RGBA_8888:          *target = kFormatRGBA8888Ubwc;            break;
-      case HAL_PIXEL_FORMAT_RGB_565:            *target = kFormatRGB565Ubwc;              break;
-      case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
-      case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC:
-      case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:    *target = kFormatYCbCr420SPVenusUbwc;     break;
-      default:
-        DLOGE("Unsupported format type for UBWC %d", source);
-        return -EINVAL;
-    }
-    return 0;
-  }
-
-  switch (source) {
-  case HAL_PIXEL_FORMAT_RGBA_8888:            *target = kFormatRGBA8888;                  break;
-  case HAL_PIXEL_FORMAT_BGRA_8888:            *target = kFormatBGRA8888;                  break;
-  case HAL_PIXEL_FORMAT_RGBX_8888:            *target = kFormatRGBX8888;                  break;
-  case HAL_PIXEL_FORMAT_BGRX_8888:            *target = kFormatBGRX8888;                  break;
-  case HAL_PIXEL_FORMAT_RGB_888:              *target = kFormatRGB888;                    break;
-  case HAL_PIXEL_FORMAT_RGB_565:              *target = kFormatRGB565;                    break;
-  case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:   *target = kFormatYCbCr420SemiPlanarVenus;   break;
-  case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC:  *target = kFormatYCbCr420SPVenusUbwc;   break;
-  default:
-    DLOGW("Unsupported format type = %d", source);
-    return -EINVAL;
-  }
-
-  return 0;
-}
-
 void HWCDisplay::SetIdleTimeoutMs(uint32_t timeout_ms) {
   if (display_intf_) {
     display_intf_->SetIdleTimeoutMs(timeout_ms);
   }
 }
 
+LayerBufferFormat HWCDisplay::GetSDEFormat(const int32_t &source, const int flags) {
+  LayerBufferFormat format = kFormatInvalid;
+  if (flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) {
+    switch (source) {
+    case HAL_PIXEL_FORMAT_RGBA_8888:          format = kFormatRGBA8888Ubwc;            break;
+    case HAL_PIXEL_FORMAT_RGB_565:            format = kFormatRGB565Ubwc;              break;
+    case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+    case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC:
+    case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:    format = kFormatYCbCr420SPVenusUbwc;     break;
+    default:
+      DLOGE("Unsupported format type for UBWC %d", source);
+      return kFormatInvalid;
+    }
+    return format;
+  }
+
+  switch (source) {
+  case HAL_PIXEL_FORMAT_RGBA_8888:                format = kFormatRGBA8888;                 break;
+  case HAL_PIXEL_FORMAT_BGRA_8888:                format = kFormatBGRA8888;                 break;
+  case HAL_PIXEL_FORMAT_RGBX_8888:                format = kFormatRGBX8888;                 break;
+  case HAL_PIXEL_FORMAT_BGRX_8888:                format = kFormatBGRX8888;                 break;
+  case HAL_PIXEL_FORMAT_RGB_888:                  format = kFormatRGB888;                   break;
+  case HAL_PIXEL_FORMAT_RGB_565:                  format = kFormatRGB565;                   break;
+  case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
+  case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:       format = kFormatYCbCr420SemiPlanarVenus;  break;
+  case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC:  format = kFormatYCbCr420SPVenusUbwc;      break;
+  case HAL_PIXEL_FORMAT_YCrCb_420_SP:             format = kFormatYCrCb420SemiPlanar;       break;
+  default:
+    DLOGW("Unsupported format type = %d", source);
+    return kFormatInvalid;
+  }
+
+  return format;
+}
+
 }  // namespace sde
 
diff --git a/displayengine/libs/hwc/hwc_display.h b/displayengine/libs/hwc/hwc_display.h
index 262c719..9956504 100644
--- a/displayengine/libs/hwc/hwc_display.h
+++ b/displayengine/libs/hwc/hwc_display.h
@@ -43,6 +43,7 @@
   virtual int GetActiveConfig();
   virtual int SetActiveConfig(int index);
   virtual void SetIdleTimeoutMs(uint32_t timeout_ms);
+  virtual int SetActiveConfig(hwc_display_contents_1_t *content_list);
 
  protected:
   // Maximum number of layers supported by display engine.
@@ -88,7 +89,8 @@
   inline void SetComposition(const int32_t &source, LayerComposition *target);
   inline void SetComposition(const int32_t &source, int32_t *target);
   inline void SetBlending(const int32_t &source, LayerBlending *target);
-  inline int SetFormat(const int32_t &source, const int flags, LayerBufferFormat *target);
+  int SetFormat(const int32_t &source, const int flags, LayerBufferFormat *target);
+  LayerBufferFormat GetSDEFormat(const int32_t &source, const int flags);
 
   CoreInterface *core_intf_;
   hwc_procs_t const **hwc_procs_;
@@ -99,6 +101,7 @@
   LayerStack layer_stack_;
   LayerStackCache layer_stack_cache_;
   bool flush_;
+  LayerBuffer *output_buffer_;
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/hwc/hwc_display_virtual.cpp b/displayengine/libs/hwc/hwc_display_virtual.cpp
index 0da76df..a6d0f63 100644
--- a/displayengine/libs/hwc/hwc_display_virtual.cpp
+++ b/displayengine/libs/hwc/hwc_display_virtual.cpp
@@ -28,6 +28,7 @@
 */
 
 #include <utils/constants.h>
+#include <gralloc_priv.h>
 
 #include "hwc_display_virtual.h"
 #include "hwc_debugger.h"
@@ -40,13 +41,137 @@
   : HWCDisplay(core_intf, hwc_procs, kVirtual, HWC_DISPLAY_VIRTUAL) {
 }
 
+int HWCDisplayVirtual::Init() {
+  int status = 0;
+
+  output_buffer_ = new LayerBuffer();
+  if (!output_buffer_) {
+    return -ENOMEM;
+  }
+
+  return HWCDisplay::Init();
+}
+
+int HWCDisplayVirtual::Deinit() {
+  int status = 0;
+
+  status = HWCDisplay::Deinit();
+  if (status) {
+    return status;
+  }
+
+  if (output_buffer_) {
+    delete output_buffer_;
+  }
+
+  return status;
+}
+
 int HWCDisplayVirtual::Prepare(hwc_display_contents_1_t *content_list) {
+  int status = 0;
+  status = AllocateLayerStack(content_list);
+  if (status) {
+    return status;
+  }
+
+  status = SetOutputBuffer(content_list);
+  if (status) {
+    return status;
+  }
+
+  status = PrepareLayerStack(content_list);
+  if (status) {
+    return status;
+  }
+
   return 0;
 }
 
 int HWCDisplayVirtual::Commit(hwc_display_contents_1_t *content_list) {
+  int status = 0;
+
+  status = HWCDisplay::CommitLayerStack(content_list);
+  if (status) {
+    return status;
+  }
+
+  if (content_list->outbufAcquireFenceFd >= 0) {
+    close(content_list->outbufAcquireFenceFd);
+    content_list->outbufAcquireFenceFd = -1;
+  }
+
+  content_list->retireFenceFd = layer_stack_.retire_fence_fd;
+
   return 0;
 }
 
+int HWCDisplayVirtual::SetActiveConfig(hwc_display_contents_1_t *content_list) {
+  const private_handle_t *output_handle =
+        static_cast<const private_handle_t *>(content_list->outbuf);
+  DisplayError error = kErrorNone;
+  int status = 0;
+
+  if (output_handle) {
+    LayerBufferFormat format = GetSDEFormat(output_handle->format, output_handle->flags);
+    if (format == kFormatInvalid) {
+      return -EINVAL;
+    }
+
+    if ((output_handle->width != INT(output_buffer_->width)) ||
+        (output_handle->height != INT(output_buffer_->height)) ||
+        (format != output_buffer_->format)) {
+      DisplayConfigVariableInfo variable_info;
+
+      variable_info.x_pixels = output_handle->width;
+      variable_info.y_pixels = output_handle->height;
+      // TODO(user): Need to get the framerate of primary display and update it.
+      variable_info.fps = 60;
+
+      error = display_intf_->SetActiveConfig(&variable_info);
+      if (error != kErrorNone) {
+        return -EINVAL;
+      }
+
+      status = SetOutputBuffer(content_list);
+      if (status) {
+        return status;
+      }
+    }
+  }
+
+  return 0;
+}
+
+int HWCDisplayVirtual::SetOutputBuffer(hwc_display_contents_1_t *content_list) {
+  int status = 0;
+
+  const private_handle_t *output_handle =
+        static_cast<const private_handle_t *>(content_list->outbuf);
+
+  // Fill output buffer parameters (width, height, format, plane information, fence)
+  output_buffer_->acquire_fence_fd = content_list->outbufAcquireFenceFd;
+
+  if (output_handle) {
+    output_buffer_->format = GetSDEFormat(output_handle->format, output_handle->flags);
+    if (output_buffer_->format == kFormatInvalid) {
+      return -EINVAL;
+    }
+
+    output_buffer_->width = output_handle->width;
+    output_buffer_->height = output_handle->height;
+    output_buffer_->flags.secure = 0;
+    output_buffer_->flags.video = 0;
+
+    // ToDo: Need to extend for non-RGB formats
+    output_buffer_->planes[0].fd = output_handle->fd;
+    output_buffer_->planes[0].offset = output_handle->offset;
+    output_buffer_->planes[0].stride = output_handle->width;
+  }
+
+  layer_stack_.output_buffer = output_buffer_;
+
+  return status;
+}
+
 }  // namespace sde
 
diff --git a/displayengine/libs/hwc/hwc_display_virtual.h b/displayengine/libs/hwc/hwc_display_virtual.h
index 796ed32..775852a 100644
--- a/displayengine/libs/hwc/hwc_display_virtual.h
+++ b/displayengine/libs/hwc/hwc_display_virtual.h
@@ -32,8 +32,14 @@
 class HWCDisplayVirtual : public HWCDisplay {
  public:
   explicit HWCDisplayVirtual(CoreInterface *core_intf, hwc_procs_t const **hwc_procs);
+  virtual int Init();
+  virtual int Deinit();
   virtual int Prepare(hwc_display_contents_1_t *content_list);
   virtual int Commit(hwc_display_contents_1_t *content_list);
+  virtual int SetActiveConfig(hwc_display_contents_1_t *content_list);
+
+ private:
+  int SetOutputBuffer(hwc_display_contents_1_t *content_list);
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/hwc/hwc_session.cpp b/displayengine/libs/hwc/hwc_session.cpp
index e5fe4c7..0b2f484 100644
--- a/displayengine/libs/hwc/hwc_session.cpp
+++ b/displayengine/libs/hwc/hwc_session.cpp
@@ -65,8 +65,8 @@
 Locker HWCSession::locker_;
 
 HWCSession::HWCSession(const hw_module_t *module) : core_intf_(NULL), hwc_procs_(NULL),
-            display_primary_(NULL), display_external_(NULL), hotplug_thread_exit_(false),
-            hotplug_thread_name_("HWC_HotPlugThread") {
+            display_primary_(NULL), display_external_(NULL), display_virtual_(NULL),
+            hotplug_thread_exit_(false), hotplug_thread_name_("HWC_HotPlugThread") {
   hwc_composer_device_1_t::common.tag = HARDWARE_DEVICE_TAG;
   hwc_composer_device_1_t::common.version = HWC_DEVICE_API_VERSION_1_4;
   hwc_composer_device_1_t::common.module = const_cast<hw_module_t*>(module);
@@ -231,6 +231,15 @@
       }
       break;
     case HWC_DISPLAY_VIRTUAL:
+      if (hwc_session->ValidateContentList(content_list)) {
+        hwc_session->CreateVirtualDisplay(hwc_session, content_list);
+      } else {
+        hwc_session->DestroyVirtualDisplay(hwc_session);
+      }
+
+      if (hwc_session->display_virtual_) {
+        hwc_session->display_virtual_->Prepare(content_list);
+      }
       break;
     default:
       break;
@@ -266,6 +275,9 @@
       }
       break;
     case HWC_DISPLAY_VIRTUAL:
+      if (hwc_session->display_virtual_) {
+        hwc_session->display_virtual_->Commit(content_list);
+      }
       break;
     default:
       break;
@@ -295,6 +307,8 @@
       status = hwc_session->display_external_->EventControl(event, enable);
     }
     break;
+  case HWC_DISPLAY_VIRTUAL:
+    break;
   default:
     status = -EINVAL;
   }
@@ -321,6 +335,11 @@
       status = hwc_session->display_external_->SetPowerMode(mode);
     }
     break;
+  case HWC_DISPLAY_VIRTUAL:
+    if (hwc_session->display_virtual_) {
+      status = hwc_session->display_virtual_->SetPowerMode(mode);
+    }
+    break;
   default:
     status = -EINVAL;
   }
@@ -373,6 +392,11 @@
       status = hwc_session->display_external_->GetDisplayConfigs(configs, num_configs);
     }
     break;
+  case HWC_DISPLAY_VIRTUAL:
+    if (hwc_session->display_virtual_) {
+      status = hwc_session->display_virtual_->GetDisplayConfigs(configs, num_configs);
+    }
+    break;
   default:
     status = -EINVAL;
   }
@@ -398,6 +422,11 @@
       status = hwc_session->display_external_->GetDisplayAttributes(config, attributes, values);
     }
     break;
+  case HWC_DISPLAY_VIRTUAL:
+    if (hwc_session->display_virtual_) {
+      status = hwc_session->display_virtual_->GetDisplayAttributes(config, attributes, values);
+    }
+    break;
   default:
     status = -EINVAL;
   }
@@ -422,6 +451,11 @@
       active_config = hwc_session->display_external_->GetActiveConfig();
     }
     break;
+  case HWC_DISPLAY_VIRTUAL:
+    if (hwc_session->display_virtual_) {
+      active_config = hwc_session->display_virtual_->GetActiveConfig();
+    }
+    break;
   default:
     active_config = -1;
   }
@@ -447,6 +481,8 @@
       status = 0;  // hwc_session->display_external_->SetActiveConfig(index);
     }
     break;
+  case HWC_DISPLAY_VIRTUAL:
+    break;
   default:
     status = -EINVAL;
   }
@@ -454,6 +490,59 @@
   return status;
 }
 
+bool HWCSession::ValidateContentList(hwc_display_contents_1_t *content_list) {
+  return (content_list && content_list->numHwLayers > 0 && content_list->outbuf);
+}
+
+int HWCSession::CreateVirtualDisplay(HWCSession *hwc_session,
+                                     hwc_display_contents_1_t *content_list) {
+  int status = 0;
+
+  if (!hwc_session->display_virtual_) {
+    // Create virtual display device
+    hwc_session->display_virtual_ = new HWCDisplayVirtual(hwc_session->core_intf_,
+                                                          &hwc_session->hwc_procs_);
+    if (!hwc_session->display_virtual_) {
+      // This is not catastrophic. Leave a warning message for now.
+      DLOGW("Virtual Display creation failed");
+      return -ENOMEM;
+    }
+
+    status = hwc_session->display_virtual_->Init();
+    if (status) {
+      goto CleanupOnError;
+    }
+
+    status = hwc_session->display_virtual_->SetPowerMode(HWC_POWER_MODE_NORMAL);
+    if (status) {
+      goto CleanupOnError;
+    }
+  }
+
+  if (hwc_session->display_virtual_) {
+    status = hwc_session->display_virtual_->SetActiveConfig(content_list);
+  }
+
+  return status;
+
+CleanupOnError:
+  return hwc_session->DestroyVirtualDisplay(hwc_session);
+}
+
+int HWCSession::DestroyVirtualDisplay(HWCSession *hwc_session) {
+  int status = 0;
+
+  if (hwc_session->display_virtual_) {
+    status = hwc_session->display_virtual_->Deinit();
+    if (!status) {
+      delete hwc_session->display_virtual_;
+      hwc_session->display_virtual_ = NULL;
+    }
+  }
+
+  return status;
+}
+
 DisplayError HWCSession::Hotplug(const CoreEventHotplug &hotplug) {
   return kErrorNone;
 }
@@ -495,6 +584,7 @@
 
   case qService::IQService::DEBUG_MDPCOMP:
     HWCDebugHandler::DebugStrategy(enable);
+    HWCDebugHandler::DebugCompManager(enable);
     break;
 
   case qService::IQService::DEBUG_PIPE_LIFECYCLE:
@@ -569,7 +659,6 @@
   return -1;
 }
 
-
 int HWCSession::HotPlugHandler(bool connected) {
   if (!hwc_procs_) {
      DLOGW("Ignore hotplug - hwc_proc not registered");
diff --git a/displayengine/libs/hwc/hwc_session.h b/displayengine/libs/hwc/hwc_session.h
index e65d51a..2a7fe62 100644
--- a/displayengine/libs/hwc/hwc_session.h
+++ b/displayengine/libs/hwc/hwc_session.h
@@ -32,6 +32,7 @@
 
 #include "hwc_display_primary.h"
 #include "hwc_display_external.h"
+#include "hwc_display_virtual.h"
 
 namespace sde {
 
@@ -72,6 +73,9 @@
   void* HWCHotPlugThreadHandler();
   int GetHDMIConnectedState(const char *uevent_data, int length);
   int HotPlugHandler(bool connected);
+  bool ValidateContentList(hwc_display_contents_1_t *content_list);
+  int CreateVirtualDisplay(HWCSession *hwc_session, hwc_display_contents_1_t *content_list);
+  int DestroyVirtualDisplay(HWCSession *hwc_session);
 
   // CoreEventHandler methods
   virtual DisplayError Hotplug(const CoreEventHotplug &hotplug);
@@ -86,6 +90,7 @@
   hwc_procs_t const *hwc_procs_;
   HWCDisplayPrimary *display_primary_;
   HWCDisplayExternal *display_external_;
+  HWCDisplayVirtual *display_virtual_;
   pthread_t hotplug_thread_;
   bool hotplug_thread_exit_;
   const char *hotplug_thread_name_;