hwc2: null display mode support

Adds null display support at HWC level. HWCDisplay will internally use
DisplayNull object as display_intf_ when in null display mode via sdm
debug property

Change-Id: I160caff9c354e23e6c5849b661dc3c3bf6c41d20
CRs-Fixed: 2186932
diff --git a/sdm/libs/hwc2/display_null.cpp b/sdm/libs/hwc2/display_null.cpp
index 16f4da6..9e3dc98 100644
--- a/sdm/libs/hwc2/display_null.cpp
+++ b/sdm/libs/hwc2/display_null.cpp
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+* Copyright (c) 2017-2018, 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
@@ -33,7 +33,100 @@
 
 namespace sdm {
 
-DisplayError DisplayNull::Commit(LayerStack *layer_stack) {
+DisplayError DisplayNull::Init() {
+  default_variable_config_.vsync_period_ns = 16600000;
+  default_variable_config_.x_pixels = 1080;
+  default_variable_config_.y_pixels = 1920;
+  default_variable_config_.x_dpi = 300;
+  default_variable_config_.y_dpi = 300;
+  default_variable_config_.fps = 60;
+  default_variable_config_.is_yuv = false;
+
+  return kErrorNone;
+}
+
+DisplayError DisplayNull::GetMixerResolution(uint32_t *width, uint32_t *height) {
+  if (!width || !height) {
+    return kErrorParameters;
+  }
+
+  *width = default_variable_config_.x_pixels;
+  *height = default_variable_config_.y_pixels;
+  return kErrorNone;
+}
+
+DisplayError DisplayNull::GetFrameBufferConfig(DisplayConfigVariableInfo *variable_info) {
+  if (!variable_info) {
+    return kErrorParameters;
+  }
+
+  *variable_info = default_variable_config_;
+  return kErrorNone;
+}
+
+DisplayError DisplayNull::GetConfig(uint32_t index, DisplayConfigVariableInfo *disp_attr) {
+  if (!disp_attr) {
+    return kErrorParameters;
+  }
+
+  *disp_attr = default_variable_config_;
+  return kErrorNone;
+}
+
+DisplayError DisplayNull::GetConfig(DisplayConfigFixedInfo *fixed_info) {
+  if (!fixed_info) {
+    return kErrorParameters;
+  }
+
+  *fixed_info = default_fixed_config_;
+  return kErrorNone;
+}
+
+DisplayError DisplayNull::GetRefreshRateRange(uint32_t *min_refresh_rate,
+                                              uint32_t *max_refresh_rate) {
+  if (!min_refresh_rate || !max_refresh_rate) {
+    return kErrorParameters;
+  }
+
+  *min_refresh_rate = 60;
+  *max_refresh_rate = 60;
+  return kErrorNone;
+}
+
+DisplayError DisplayNull::GetActiveConfig(uint32_t *config) {
+  if (!config) {
+    return kErrorParameters;
+  }
+
+  *config = 0;
+  return kErrorNone;
+}
+
+DisplayError DisplayNull::GetNumVariableInfoConfigs(uint32_t *count) {
+  if (!count) {
+    return kErrorParameters;
+  }
+
+  *count = 1;
+  return kErrorNone;
+}
+
+DisplayError DisplayNull::Prepare(LayerStack *layer_stack) {
+  if (!layer_stack) {
+    return kErrorParameters;
+  }
+
+  for (auto layer : layer_stack->layers) {
+    layer->composition = kCompositionGPU;
+  }
+  return kErrorNone;
+}
+
+DisplayError DisplayNullExternal::Commit(LayerStack *layer_stack) {
+  if (!layer_stack) {
+    return kErrorParameters;
+  }
+
   for (Layer *layer : layer_stack->layers) {
     if (layer->composition != kCompositionGPUTarget) {
       layer->composition = kCompositionSDE;
@@ -41,26 +134,34 @@
     }
   }
   layer_stack->retire_fence_fd = -1;
-
   return kErrorNone;
 }
 
-DisplayError DisplayNull::GetDisplayState(DisplayState *state) {
+DisplayError DisplayNullExternal::GetDisplayState(DisplayState *state) {
+  if (!state) {
+    return kErrorParameters;
+  }
+
   *state = state_;
   return kErrorNone;
 }
 
-DisplayError DisplayNull::SetDisplayState(DisplayState state) {
+DisplayError DisplayNullExternal::SetDisplayState(DisplayState state) {
   state_ = state;
   return kErrorNone;
 }
 
-DisplayError DisplayNull::SetFrameBufferConfig(const DisplayConfigVariableInfo &variable_info) {
+DisplayError DisplayNullExternal::SetFrameBufferConfig(const DisplayConfigVariableInfo
+                                                       &variable_info) {
   fb_config_ = variable_info;
   return kErrorNone;
 }
 
-DisplayError DisplayNull::GetFrameBufferConfig(DisplayConfigVariableInfo *variable_info) {
+DisplayError DisplayNullExternal::GetFrameBufferConfig(DisplayConfigVariableInfo *variable_info) {
+  if (!variable_info) {
+    return kErrorParameters;
+  }
+
   *variable_info = fb_config_;
   return kErrorNone;
 }
diff --git a/sdm/libs/hwc2/display_null.h b/sdm/libs/hwc2/display_null.h
index f6c0dda..ea287d9 100644
--- a/sdm/libs/hwc2/display_null.h
+++ b/sdm/libs/hwc2/display_null.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+* Copyright (c) 2017-2018, 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
@@ -36,35 +36,31 @@
 
 namespace sdm {
 
-#define MAKE_NO_OP(virtual_method_name) \
-      virtual DisplayError virtual_method_name { return kErrorNone; }
+#define MAKE_NO_OP(virtual_method_signature) \
+      virtual DisplayError virtual_method_signature { return kErrorNone; }
 
 class DisplayNull : public DisplayInterface {
  public:
   virtual ~DisplayNull() { }
-  virtual DisplayError Commit(LayerStack *layer_stack);
-  virtual DisplayError GetDisplayState(DisplayState *state);
-  virtual DisplayError SetDisplayState(DisplayState state);
-  virtual DisplayError SetFrameBufferConfig(const DisplayConfigVariableInfo &variable_info);
+  virtual DisplayError Init();
+  virtual DisplayError GetMixerResolution(uint32_t *width, uint32_t *height);
   virtual DisplayError GetFrameBufferConfig(DisplayConfigVariableInfo *variable_info);
+  virtual DisplayError GetConfig(uint32_t index, DisplayConfigVariableInfo *disp_attr);
+  virtual DisplayError GetConfig(DisplayConfigFixedInfo *fixed_info);
+  virtual DisplayError GetRefreshRateRange(uint32_t *min_refresh_rate, uint32_t *max_refresh_rate);
+  virtual DisplayError GetActiveConfig(uint32_t *config);
+  virtual DisplayError GetNumVariableInfoConfigs(uint32_t *count);
+  virtual DisplayError Prepare(LayerStack *layer_stack);
+  virtual bool IsPrimaryDisplay() { return true; }
   virtual bool IsUnderscanSupported() { return true; }
   virtual void SetIdleTimeoutMs(uint32_t active_ms) { }
-  virtual bool IsPrimaryDisplay() { return true; }
+  virtual std::string Dump() { return ""; }
 
-  void SetActive(bool active) {
-    active_ = active;
-  }
-
-  bool IsActive() {
-    return active_;
-  }
-
-  MAKE_NO_OP(Prepare(LayerStack *))
+  MAKE_NO_OP(Commit(LayerStack *))
+  MAKE_NO_OP(GetDisplayState(DisplayState *))
+  MAKE_NO_OP(SetDisplayState(DisplayState))
+  MAKE_NO_OP(SetFrameBufferConfig(const DisplayConfigVariableInfo &))
   MAKE_NO_OP(Flush())
-  MAKE_NO_OP(GetNumVariableInfoConfigs(uint32_t *))
-  MAKE_NO_OP(GetConfig(uint32_t, DisplayConfigVariableInfo *))
-  MAKE_NO_OP(GetConfig(DisplayConfigFixedInfo *))
-  MAKE_NO_OP(GetActiveConfig(uint32_t *))
   MAKE_NO_OP(GetVSyncState(bool *))
   MAKE_NO_OP(SetActiveConfig(uint32_t))
   MAKE_NO_OP(SetActiveConfig(DisplayConfigVariableInfo *))
@@ -86,18 +82,29 @@
   MAKE_NO_OP(GetDefaultColorMode(std::string *))
   MAKE_NO_OP(ApplyDefaultDisplayMode())
   MAKE_NO_OP(SetCursorPosition(int, int))
-  MAKE_NO_OP(GetRefreshRateRange(uint32_t *, uint32_t *))
   MAKE_NO_OP(SetRefreshRate(uint32_t, bool))
   MAKE_NO_OP(GetPanelBrightness(int *))
   MAKE_NO_OP(SetVSyncState(bool))
   MAKE_NO_OP(SetMixerResolution(uint32_t, uint32_t))
-  MAKE_NO_OP(GetMixerResolution(uint32_t *, uint32_t *))
   MAKE_NO_OP(SetDetailEnhancerData(const DisplayDetailEnhancerData &))
   MAKE_NO_OP(GetDisplayPort(DisplayPort *))
   MAKE_NO_OP(SetCompositionState(LayerComposition, bool))
   MAKE_NO_OP(GetClientTargetSupport(uint32_t, uint32_t, LayerBufferFormat,
                                     const ColorMetaData &))
-  std::string Dump() { return ""; }
+
+  DisplayConfigVariableInfo default_variable_config_ = {};
+  DisplayConfigFixedInfo default_fixed_config_ = {};
+};
+
+class DisplayNullExternal : public DisplayNull {
+ public:
+  virtual DisplayError Commit(LayerStack *layer_stack);
+  virtual DisplayError GetDisplayState(DisplayState *state);
+  virtual DisplayError SetDisplayState(DisplayState state);
+  virtual DisplayError SetFrameBufferConfig(const DisplayConfigVariableInfo &variable_info);
+  virtual DisplayError GetFrameBufferConfig(DisplayConfigVariableInfo *variable_info);
+  void SetActive(bool active) { active_ = active; }
+  bool IsActive() { return active_; }
 
  private:
   bool active_ = false;
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index 870b8b6..3236c4a 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright 2015 The Android Open Source Project
@@ -360,11 +360,23 @@
 }
 
 int HWCDisplay::Init() {
-  DisplayError error = core_intf_->CreateDisplay(type_, this, &display_intf_);
-  if (error != kErrorNone) {
-    DLOGE("Display create failed. Error = %d display_type %d event_handler %p disp_intf %p", error,
-          type_, this, &display_intf_);
-    return -EINVAL;
+  DisplayError error = kErrorNone;
+
+  HWCDebugHandler::Get()->GetProperty("sdm.debug.enable_null_display", &null_display_mode_);
+
+  if (null_display_mode_) {
+    DisplayNull *disp_null = new DisplayNull();
+    disp_null->Init();
+    use_metadata_refresh_rate_ = false;
+    display_intf_ = disp_null;
+    ALOGI("Enabling null display mode for display type %d", type_);
+  } else {
+    error = core_intf_->CreateDisplay(type_, this, &display_intf_);
+    if (error != kErrorNone) {
+      DLOGE("Display create failed. Error = %d display_type %d event_handler %p disp_intf %p",
+            error, type_, this, &display_intf_);
+      return -EINVAL;
+    }
   }
 
   validated_ = false;
@@ -405,10 +417,15 @@
 }
 
 int HWCDisplay::Deinit() {
-  DisplayError error = core_intf_->DestroyDisplay(display_intf_);
-  if (error != kErrorNone) {
-    DLOGE("Display destroy failed. Error = %d", error);
-    return -EINVAL;
+  if (null_display_mode_) {
+    delete static_cast<DisplayNull *>(display_intf_);
+    display_intf_ = nullptr;
+  } else {
+    DisplayError error = core_intf_->DestroyDisplay(display_intf_);
+    if (error != kErrorNone) {
+      DLOGE("Display destroy failed. Error = %d", error);
+      return -EINVAL;
+    }
   }
 
   delete client_target_;
@@ -421,8 +438,10 @@
     delete color_mode_;
   }
 
-  delete tone_mapper_;
-  tone_mapper_ = nullptr;
+  if (tone_mapper_) {
+    delete tone_mapper_;
+    tone_mapper_ = nullptr;
+  }
 
   return 0;
 }
diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h
index a5e1457..1790257 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright 2015 The Android Open Source Project
@@ -36,6 +36,7 @@
 #include "hwc_buffer_allocator.h"
 #include "hwc_callbacks.h"
 #include "hwc_layers.h"
+#include "display_null.h"
 
 namespace sdm {
 
@@ -309,6 +310,7 @@
   uint32_t geometry_changes_ = GeometryChanges::kNone;
   bool skip_validate_ = false;
   bool animating_ = false;
+  int null_display_mode_ = 0;
 };
 
 inline int HWCDisplay::Perform(uint32_t operation, ...) {
diff --git a/sdm/libs/hwc2/hwc_display_external.h b/sdm/libs/hwc2/hwc_display_external.h
index fbee6a3..75e9387 100644
--- a/sdm/libs/hwc2/hwc_display_external.h
+++ b/sdm/libs/hwc2/hwc_display_external.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018, 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
@@ -58,7 +58,7 @@
   static void GetDownscaleResolution(uint32_t primary_width, uint32_t primary_height,
                                      uint32_t *virtual_width, uint32_t *virtual_height);
 
-  DisplayNull display_null_;
+  DisplayNullExternal display_null_;
   int underscan_width_ = 0;
   int underscan_height_ = 0;
 };
diff --git a/sdm/libs/hwc2/hwc_display_primary.cpp b/sdm/libs/hwc2/hwc_display_primary.cpp
index 1f2fdf6..21c958d 100644
--- a/sdm/libs/hwc2/hwc_display_primary.cpp
+++ b/sdm/libs/hwc2/hwc_display_primary.cpp
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014 - 2018, 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
@@ -475,13 +475,17 @@
 }
 
 void HWCDisplayPrimary::HandleFrameDump() {
-  if (dump_frame_count_ && output_buffer_.release_fence_fd >= 0) {
-    int ret = sync_wait(output_buffer_.release_fence_fd, 1000);
-    ::close(output_buffer_.release_fence_fd);
-    output_buffer_.release_fence_fd = -1;
-    if (ret < 0) {
-      DLOGE("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
-    } else {
+  if (dump_frame_count_) {
+    int ret = 0;
+    if (output_buffer_.release_fence_fd >= 0) {
+      ret = sync_wait(output_buffer_.release_fence_fd, 1000);
+      ::close(output_buffer_.release_fence_fd);
+      output_buffer_.release_fence_fd = -1;
+      if (ret < 0) {
+        DLOGE("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
+      }
+    }
+    if (ret >= 0) {
       DumpOutputBuffer(output_buffer_info_, output_buffer_base_, layer_stack_.retire_fence_fd);
     }
   }
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index 36b55d0..693e7ca 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright 2015 The Android Open Source Project
@@ -160,35 +160,44 @@
 
   StartServices();
 
+  HWCDebugHandler::Get()->GetProperty("sdm.debug.enable_null_display", &null_display_mode_);
+
   DisplayError error = buffer_allocator_.Init();
   if (error != kErrorNone) {
-    ALOGE("%s::%s: Buffer allocaor initialization failed. Error = %d",
+    ALOGE("%s::%s: Buffer allocator initialization failed. Error = %d",
           __CLASS__, __FUNCTION__, error);
     return -EINVAL;
   }
 
-  g_hwc_uevent_.Register(this);
+  HWDisplayInterfaceInfo hw_disp_info = {};
+  if (null_display_mode_) {
+    hw_disp_info.type = kPrimary;
+    hw_disp_info.is_connected = true;
+  } else {
+    g_hwc_uevent_.Register(this);
 
-  error = CoreInterface::CreateCore(HWCDebugHandler::Get(), &buffer_allocator_,
-                                    &buffer_sync_handler_, &socket_handler_, &core_intf_);
-  if (error != kErrorNone) {
-    buffer_allocator_.Deinit();
-    ALOGE("%s::%s: Display core initialization failed. Error = %d", __CLASS__, __FUNCTION__, error);
-    return -EINVAL;
+    error = CoreInterface::CreateCore(HWCDebugHandler::Get(), &buffer_allocator_,
+                                      &buffer_sync_handler_, &socket_handler_, &core_intf_);
+
+    if (error != kErrorNone) {
+      buffer_allocator_.Deinit();
+      ALOGE("%s::%s: Display core initialization failed. Error = %d", __CLASS__, __FUNCTION__,
+            error);
+      return -EINVAL;
+    }
+
+    error = core_intf_->GetFirstDisplayInterfaceType(&hw_disp_info);
+
+    if (error != kErrorNone) {
+      g_hwc_uevent_.Register(nullptr);
+      CoreInterface::DestroyCore();
+      buffer_allocator_.Deinit();
+      DLOGE("Primary display type not recognized. Error = %d", error);
+      return -EINVAL;
+    }
   }
 
-
   // If HDMI display is primary display, defer display creation until hotplug event is received.
-  HWDisplayInterfaceInfo hw_disp_info = {};
-  error = core_intf_->GetFirstDisplayInterfaceType(&hw_disp_info);
-  if (error != kErrorNone) {
-    g_hwc_uevent_.Register(nullptr);
-    CoreInterface::DestroyCore();
-    buffer_allocator_.Deinit();
-    DLOGE("Primary display type not recognized. Error = %d", error);
-    return -EINVAL;
-  }
-
   if (hw_disp_info.type == kHDMI) {
     status = 0;
     hdmi_is_primary_ = true;
@@ -246,11 +255,13 @@
     color_mgr_->DestroyColorManager();
   }
 
-  g_hwc_uevent_.Register(nullptr);
+  if (!null_display_mode_) {
+    g_hwc_uevent_.Register(nullptr);
 
-  DisplayError error = CoreInterface::DestroyCore();
-  if (error != kErrorNone) {
-    ALOGE("Display core de-initialization failed. Error = %d", error);
+    DisplayError error = CoreInterface::DestroyCore();
+    if (error != kErrorNone) {
+      ALOGE("Display core de-initialization failed. Error = %d", error);
+    }
   }
 
   return 0;
diff --git a/sdm/libs/hwc2/hwc_session.h b/sdm/libs/hwc2/hwc_session.h
index 8d25989..c979a77 100644
--- a/sdm/libs/hwc2/hwc_session.h
+++ b/sdm/libs/hwc2/hwc_session.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright 2015 The Android Open Source Project
@@ -267,6 +267,7 @@
   Locker callbacks_lock_;
   int hpd_bpp_ = 0;
   int hpd_pattern_ = 0;
+  int null_display_mode_ = 0;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_session_services.cpp b/sdm/libs/hwc2/hwc_session_services.cpp
index 6984711..f91b8f1 100644
--- a/sdm/libs/hwc2/hwc_session_services.cpp
+++ b/sdm/libs/hwc2/hwc_session_services.cpp
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+* Copyright (c) 2017-2018, 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
@@ -452,6 +452,10 @@
 Return<int32_t> HWCSession::setCameraLaunchStatus(uint32_t on) {
   SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
 
+  if (null_display_mode_) {
+    return 0;
+  }
+
   if (!core_intf_) {
     DLOGW("core_intf_ not initialized.");
     return -ENOENT;