hwc2: Enable virtual display

* Create output buffer
* Set DisplayConfig on virtual display from provided width/height
* Handle virtual display fences correctly
* Take lock when creating/destroying virtual displays

Change-Id: I9556f12b69bfea56e18f0e3721a9e03d553468f0
CRs-fixed: 1012677
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index f9cb466..e241402 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -1214,7 +1214,7 @@
 
 int HWCDisplay::SetFrameBufferResolution(uint32_t x_pixels, uint32_t y_pixels) {
   if (x_pixels <= 0 || y_pixels <= 0) {
-    DLOGV("Unsupported config: x_pixels=%d, y_pixels=%d", x_pixels, y_pixels);
+    DLOGW("Unsupported config: x_pixels=%d, y_pixels=%d", x_pixels, y_pixels);
     return -EINVAL;
   }
 
diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h
index a5ef7eb..69a2dea 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -255,13 +255,13 @@
   bool validated_ = false;
   bool color_tranform_failed_ = false;
   HWCColorMode *color_mode_ = NULL;
+  int32_t stored_retire_fence_ = -1;
 
  private:
   void DumpInputBuffers(void);
   BlitEngine *blit_engine_ = NULL;
   qService::QService *qservice_ = NULL;
   DisplayClass display_class_;
-  int32_t stored_retire_fence_ = -1;
   uint32_t geometry_changes_ = GeometryChanges::kNone;
 };
 
diff --git a/sdm/libs/hwc2/hwc_display_virtual.cpp b/sdm/libs/hwc2/hwc_display_virtual.cpp
index e81781f..89f313a 100644
--- a/sdm/libs/hwc2/hwc_display_virtual.cpp
+++ b/sdm/libs/hwc2/hwc_display_virtual.cpp
@@ -44,27 +44,29 @@
                               uint32_t height, int32_t *format, HWCDisplay **hwc_display) {
   int status = 0;
   HWCDisplayVirtual *hwc_display_virtual = new HWCDisplayVirtual(core_intf, callbacks);
-  uint32_t virtual_width = 0, virtual_height = 0;
 
   // TODO(user): Populate format correctly
+  DLOGI("Creating virtual display: w: %d h:%d format:0x%x", width, height, *format);
 
   status = hwc_display_virtual->Init();
   if (status) {
+    DLOGW("Failed to initialize virtual display");
     delete hwc_display_virtual;
     return status;
   }
 
   status = INT32(hwc_display_virtual->SetPowerMode(HWC2::PowerMode::On));
   if (status) {
+    DLOGW("Failed to set power mode on virtual display");
     Destroy(hwc_display_virtual);
     return status;
   }
 
-  hwc_display_virtual->GetMixerResolution(&virtual_width, &virtual_height);
-
+  // TODO(user): Validate that we support this width/height
   status = hwc_display_virtual->SetFrameBufferResolution(width, height);
 
   if (status) {
+    DLOGW("Failed to set virtual display FB resolution");
     Destroy(hwc_display_virtual);
     return status;
   }
@@ -85,12 +87,16 @@
 }
 
 int HWCDisplayVirtual::Init() {
+  output_buffer_ = new LayerBuffer();
   return HWCDisplay::Init();
 }
 
 int HWCDisplayVirtual::Deinit() {
   int status = 0;
-
+  if (output_buffer_) {
+    delete output_buffer_;
+    output_buffer_ = nullptr;
+  }
   status = HWCDisplay::Deinit();
 
   return status;
@@ -105,6 +111,7 @@
   }
 
   BuildLayerStack();
+  layer_stack_.output_buffer = output_buffer_;
   status = PrepareLayerStack(out_num_types, out_num_requests);
   return status;
 }
@@ -135,6 +142,13 @@
       }
 
       status = HWCDisplay::PostCommitLayerStack(out_retire_fence);
+      // On Virtual displays, use the output buffer release fence as the retire fence
+      // Close the layer stack retire fence as it is unused
+      if (layer_stack_.output_buffer) {
+        stored_retire_fence_ = layer_stack_.output_buffer->release_fence_fd;
+        close(layer_stack_.retire_fence_fd);
+        layer_stack_.retire_fence_fd = -1;
+      }
     }
   }
   CloseAcquireFds();
@@ -142,6 +156,9 @@
 }
 
 HWC2::Error HWCDisplayVirtual::SetOutputBuffer(buffer_handle_t buf, int32_t release_fence) {
+  if (buf == nullptr || release_fence == 0) {
+    return HWC2::Error::BadParameter;
+  }
   const private_handle_t *output_handle = static_cast<const private_handle_t *>(buf);
 
   // Fill output buffer parameters (width, height, format, plane information, fence)
@@ -182,7 +199,6 @@
     output_buffer_->planes[0].stride = UINT32(output_handle->width);
   }
 
-  layer_stack_.output_buffer = output_buffer_;
   return HWC2::Error::None;
 }
 
diff --git a/sdm/libs/hwc2/hwc_display_virtual.h b/sdm/libs/hwc2/hwc_display_virtual.h
index 0ca2fd1..a68ac65 100644
--- a/sdm/libs/hwc2/hwc_display_virtual.h
+++ b/sdm/libs/hwc2/hwc_display_virtual.h
@@ -38,8 +38,8 @@
 
 class HWCDisplayVirtual : public HWCDisplay {
  public:
-  static int Create(CoreInterface *core_intf, HWCCallbacks *callbacks, uint32_t primary_width,
-                    uint32_t primary_height, int32_t *format, HWCDisplay **hwc_display);
+  static int Create(CoreInterface *core_intf, HWCCallbacks *callbacks, uint32_t width,
+                    uint32_t height, int32_t *format, HWCDisplay **hwc_display);
   static void Destroy(HWCDisplay *hwc_display);
   virtual int Init();
   virtual int Deinit();
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index 7e87b10..f75e6b8 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -237,6 +237,8 @@
 
 int32_t HWCSession::CreateVirtualDisplay(hwc2_device_t *device, uint32_t width, uint32_t height,
                                          int32_t *format, hwc2_display_t *out_display_id) {
+  // TODO(user): Handle concurrency with HDMI
+  SCOPE_LOCK(locker_);
   if (!device) {
     return HWC2_ERROR_BAD_DISPLAY;
   }
@@ -245,6 +247,7 @@
   auto status = hwc_session->CreateVirtualDisplayObject(width, height, format);
   if (status == HWC2::Error::None)
     *out_display_id = HWC_DISPLAY_VIRTUAL;
+  DLOGI("Created virtual display id:% " PRIu64 " with res: %dx%d", *out_display_id, width, height);
   return INT32(status);
 }
 
@@ -255,10 +258,12 @@
 }
 
 int32_t HWCSession::DestroyVirtualDisplay(hwc2_device_t *device, hwc2_display_t display) {
+  SCOPE_LOCK(locker_);
   if (!device) {
     return HWC2_ERROR_BAD_DISPLAY;
   }
 
+  DLOGI("Destroying virtual display id:%" PRIu64, display);
   auto *hwc_session = static_cast<HWCSession *>(device);
 
   if (hwc_session->hwc_display_[display]) {