hwc: HWC 2.0 implementation

Add HWCLayer, HWCCallbacks and implement HWC2 layer functionality.

Change-Id: Ic7764e72f4cae534e68764df4cf80eb3db982071
diff --git a/sdm/libs/hwc2/hwc_display_primary.cpp b/sdm/libs/hwc2/hwc_display_primary.cpp
new file mode 100644
index 0000000..40ac723
--- /dev/null
+++ b/sdm/libs/hwc2/hwc_display_primary.cpp
@@ -0,0 +1,471 @@
+/*
+* Copyright (c) 2014 - 2016, 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
+* met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above
+*       copyright notice, this list of conditions and the following
+*       disclaimer in the documentation and/or other materials provided
+*       with the distribution.
+*     * Neither the name of The Linux Foundation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <cutils/properties.h>
+#include <sync/sync.h>
+#include <utils/constants.h>
+#include <utils/debug.h>
+#include <stdarg.h>
+#include <sys/mman.h>
+
+#include "hwc_display_primary.h"
+#include "hwc_debugger.h"
+
+#define __CLASS__ "HWCDisplayPrimary"
+
+namespace sdm {
+
+int HWCDisplayPrimary::Create(CoreInterface *core_intf, BufferAllocator *buffer_allocator,
+                              HWCCallbacks *callbacks, qService::QService *qservice,
+                              HWCDisplay **hwc_display) {
+  int status = 0;
+  uint32_t primary_width = 0;
+  uint32_t primary_height = 0;
+
+  HWCDisplay *hwc_display_primary =
+      new HWCDisplayPrimary(core_intf, buffer_allocator, callbacks, qservice);
+  status = hwc_display_primary->Init();
+  if (status) {
+    delete hwc_display_primary;
+    return status;
+  }
+
+  hwc_display_primary->GetPanelResolution(&primary_width, &primary_height);
+  int width = 0, height = 0;
+  HWCDebugHandler::Get()->GetProperty("sdm.fb_size_width", &width);
+  HWCDebugHandler::Get()->GetProperty("sdm.fb_size_height", &height);
+  if (width > 0 && height > 0) {
+    primary_width = UINT32(width);
+    primary_height = UINT32(height);
+  }
+
+  status = hwc_display_primary->SetFrameBufferResolution(primary_width, primary_height);
+  if (status) {
+    Destroy(hwc_display_primary);
+    return status;
+  }
+
+  *hwc_display = hwc_display_primary;
+
+  return status;
+}
+
+void HWCDisplayPrimary::Destroy(HWCDisplay *hwc_display) {
+  hwc_display->Deinit();
+  delete hwc_display;
+}
+
+HWCDisplayPrimary::HWCDisplayPrimary(CoreInterface *core_intf, BufferAllocator *buffer_allocator,
+                                     HWCCallbacks *callbacks, qService::QService *qservice)
+    : HWCDisplay(core_intf, callbacks, kPrimary, HWC_DISPLAY_PRIMARY, true, qservice,
+                 DISPLAY_CLASS_PRIMARY),
+      buffer_allocator_(buffer_allocator),
+      cpu_hint_(NULL) {
+}
+
+int HWCDisplayPrimary::Init() {
+  cpu_hint_ = new CPUHint();
+  if (cpu_hint_->Init(static_cast<HWCDebugHandler *>(HWCDebugHandler::Get())) != kErrorNone) {
+    delete cpu_hint_;
+    cpu_hint_ = NULL;
+  }
+
+  use_metadata_refresh_rate_ = true;
+  int disable_metadata_dynfps = 0;
+  HWCDebugHandler::Get()->GetProperty("persist.metadata_dynfps.disable", &disable_metadata_dynfps);
+  if (disable_metadata_dynfps) {
+    use_metadata_refresh_rate_ = false;
+  }
+
+  return HWCDisplay::Init();
+}
+
+void HWCDisplayPrimary::ProcessBootAnimCompleted() {
+  uint32_t numBootUpLayers = 0;
+  // TODO(user): Remove this hack
+
+  numBootUpLayers = static_cast<uint32_t>(Debug::GetBootAnimLayerCount());
+
+  if (numBootUpLayers == 0) {
+    numBootUpLayers = 2;
+  }
+  /* All other checks namely "init.svc.bootanim" or
+  * HWC_GEOMETRY_CHANGED fail in correctly identifying the
+  * exact bootup transition to homescreen
+  */
+  char cryptoState[PROPERTY_VALUE_MAX];
+  char voldDecryptState[PROPERTY_VALUE_MAX];
+  bool isEncrypted = false;
+  bool main_class_services_started = false;
+  if (property_get("ro.crypto.state", cryptoState, "unencrypted")) {
+    if (!strcmp(cryptoState, "encrypted")) {
+      isEncrypted = true;
+      if (property_get("vold.decrypt", voldDecryptState, "") &&
+          !strcmp(voldDecryptState, "trigger_restart_framework"))
+        main_class_services_started = true;
+    }
+  }
+  if ((!isEncrypted || (isEncrypted && main_class_services_started)) &&
+      (layer_set_.size() > numBootUpLayers)) {
+    boot_animation_completed_ = true;
+    // Applying default mode after bootanimation is finished And
+    // If Data is Encrypted, it is ready for access.
+    if (display_intf_)
+      display_intf_->ApplyDefaultDisplayMode();
+  }
+}
+
+HWC2::Error HWCDisplayPrimary::Validate(uint32_t *out_num_types, uint32_t *out_num_requests) {
+  auto status = HWC2::Error::None;
+  DisplayError error = kErrorNone;
+
+  if (!boot_animation_completed_)
+    ProcessBootAnimCompleted();
+
+  if (display_paused_) {
+    MarkLayersForGPUBypass();
+    return status;
+  }
+
+  // Fill in the remaining blanks in the layers and add them to the SDM layerstack
+  BuildLayerStack();
+
+  bool pending_output_dump = dump_frame_count_ && dump_output_to_file_;
+
+  if (frame_capture_buffer_queued_ || pending_output_dump) {
+    // RHS values were set in FrameCaptureAsync() called from a binder thread. They are picked up
+    // here in a subsequent draw round.
+    layer_stack_.output_buffer = &output_buffer_;
+    layer_stack_.flags.post_processed_output = post_processed_output_;
+  }
+
+  bool one_updating_layer = SingleLayerUpdating();
+  ToggleCPUHint(one_updating_layer);
+
+  uint32_t refresh_rate = GetOptimalRefreshRate(one_updating_layer);
+  if (current_refresh_rate_ != refresh_rate) {
+    error = display_intf_->SetRefreshRate(refresh_rate);
+  }
+
+  if (error == kErrorNone) {
+    // On success, set current refresh rate to new refresh rate
+    current_refresh_rate_ = refresh_rate;
+  }
+
+  if (handle_idle_timeout_) {
+    handle_idle_timeout_ = false;
+  }
+
+  // TODO(user): Validate this
+  if (layer_set_.empty()) {
+    flush_ = true;
+    return status;
+  }
+
+  status = PrepareLayerStack(out_num_types, out_num_requests);
+  return status;
+}
+
+HWC2::Error HWCDisplayPrimary::Present(int32_t *out_retire_fence) {
+  auto status = HWC2::Error::None;
+  if (display_paused_) {
+    // TODO(user): From old HWC implementation
+    // If we do not handle the frame set retireFenceFd to outbufAcquireFenceFd
+    // Revisit this when validating display_paused
+    DisplayError error = display_intf_->Flush();
+    if (error != kErrorNone) {
+      DLOGE("Flush failed. Error = %d", error);
+    }
+  } else {
+    status = HWCDisplay::CommitLayerStack();
+    if (status == HWC2::Error::None) {
+      HandleFrameOutput();
+      status = HWCDisplay::PostCommitLayerStack(out_retire_fence);
+    }
+  }
+  CloseAcquireFds();
+  return status;
+}
+
+int HWCDisplayPrimary::Perform(uint32_t operation, ...) {
+  va_list args;
+  va_start(args, operation);
+  int val = va_arg(args, int32_t);
+  va_end(args);
+  switch (operation) {
+    case SET_METADATA_DYN_REFRESH_RATE:
+      SetMetaDataRefreshRateFlag(val);
+      break;
+    case SET_BINDER_DYN_REFRESH_RATE:
+      ForceRefreshRate(UINT32(val));
+      break;
+    case SET_DISPLAY_MODE:
+      SetDisplayMode(UINT32(val));
+      break;
+    case SET_QDCM_SOLID_FILL_INFO:
+      SetQDCMSolidFillInfo(true, UINT32(val));
+      break;
+    case UNSET_QDCM_SOLID_FILL_INFO:
+      SetQDCMSolidFillInfo(false, UINT32(val));
+      break;
+    default:
+      DLOGW("Invalid operation %d", operation);
+      return -EINVAL;
+  }
+
+  return 0;
+}
+
+DisplayError HWCDisplayPrimary::SetDisplayMode(uint32_t mode) {
+  DisplayError error = kErrorNone;
+
+  if (display_intf_) {
+    error = display_intf_->SetDisplayMode(mode);
+  }
+
+  return error;
+}
+
+void HWCDisplayPrimary::SetMetaDataRefreshRateFlag(bool enable) {
+  int disable_metadata_dynfps = 0;
+
+  HWCDebugHandler::Get()->GetProperty("persist.metadata_dynfps.disable", &disable_metadata_dynfps);
+  if (disable_metadata_dynfps) {
+    return;
+  }
+  use_metadata_refresh_rate_ = enable;
+}
+
+void HWCDisplayPrimary::SetQDCMSolidFillInfo(bool enable, uint32_t color) {
+  solid_fill_enable_ = enable;
+  solid_fill_color_ = color;
+}
+
+void HWCDisplayPrimary::ToggleCPUHint(bool set) {
+  if (!cpu_hint_) {
+    return;
+  }
+
+  if (set) {
+    cpu_hint_->Set();
+  } else {
+    cpu_hint_->Reset();
+  }
+}
+
+void HWCDisplayPrimary::SetSecureDisplay(bool secure_display_active) {
+  if (secure_display_active_ != secure_display_active) {
+    // Skip Prepare and call Flush for null commit
+    DLOGI("SecureDisplay state changed from %d to %d Needs Flush!!", secure_display_active_,
+          secure_display_active);
+    secure_display_active_ = secure_display_active;
+    skip_prepare_ = true;
+  }
+  return;
+}
+
+void HWCDisplayPrimary::ForceRefreshRate(uint32_t refresh_rate) {
+  if ((refresh_rate && (refresh_rate < min_refresh_rate_ || refresh_rate > max_refresh_rate_)) ||
+      force_refresh_rate_ == refresh_rate) {
+    // Cannot honor force refresh rate, as its beyond the range or new request is same
+    return;
+  }
+
+  force_refresh_rate_ = refresh_rate;
+
+  callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
+
+  return;
+}
+
+uint32_t HWCDisplayPrimary::GetOptimalRefreshRate(bool one_updating_layer) {
+  if (force_refresh_rate_) {
+    return force_refresh_rate_;
+  } else if (handle_idle_timeout_) {
+    return min_refresh_rate_;
+  } else if (use_metadata_refresh_rate_ && one_updating_layer && metadata_refresh_rate_) {
+    return metadata_refresh_rate_;
+  }
+
+  return max_refresh_rate_;
+}
+
+DisplayError HWCDisplayPrimary::Refresh() {
+  DisplayError error = kErrorNone;
+
+  callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
+  handle_idle_timeout_ = true;
+
+  return error;
+}
+
+void HWCDisplayPrimary::SetIdleTimeoutMs(uint32_t timeout_ms) {
+  display_intf_->SetIdleTimeoutMs(timeout_ms);
+}
+
+static void SetLayerBuffer(const BufferInfo &output_buffer_info, LayerBuffer *output_buffer) {
+  output_buffer->width = output_buffer_info.buffer_config.width;
+  output_buffer->height = output_buffer_info.buffer_config.height;
+  output_buffer->format = output_buffer_info.buffer_config.format;
+  output_buffer->planes[0].fd = output_buffer_info.alloc_buffer_info.fd;
+  output_buffer->planes[0].stride = output_buffer_info.alloc_buffer_info.stride;
+}
+
+void HWCDisplayPrimary::HandleFrameOutput() {
+  if (frame_capture_buffer_queued_) {
+    HandleFrameCapture();
+  } else if (dump_output_to_file_) {
+    HandleFrameDump();
+  }
+}
+
+void HWCDisplayPrimary::HandleFrameCapture() {
+  if (output_buffer_.release_fence_fd >= 0) {
+    frame_capture_status_ = sync_wait(output_buffer_.release_fence_fd, 1000);
+    ::close(output_buffer_.release_fence_fd);
+    output_buffer_.release_fence_fd = -1;
+  }
+
+  frame_capture_buffer_queued_ = false;
+  post_processed_output_ = false;
+  output_buffer_ = {};
+
+  uint32_t pending = 0;  // Just a temporary to satisfy the API
+  ControlPartialUpdate(true /* enable */, &pending);
+}
+
+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 {
+      DumpOutputBuffer(output_buffer_info_, output_buffer_base_, layer_stack_.retire_fence_fd);
+    }
+  }
+
+  if (0 == dump_frame_count_) {
+    dump_output_to_file_ = false;
+    // Unmap and Free buffer
+    if (munmap(output_buffer_base_, output_buffer_info_.alloc_buffer_info.size) != 0) {
+      DLOGE("unmap failed with err %d", errno);
+    }
+    if (buffer_allocator_->FreeBuffer(&output_buffer_info_) != 0) {
+      DLOGE("FreeBuffer failed");
+    }
+
+    post_processed_output_ = false;
+    output_buffer_ = {};
+    output_buffer_info_ = {};
+    output_buffer_base_ = nullptr;
+
+    uint32_t pending = 0;  // Just a temporary to satisfy the API
+    ControlPartialUpdate(true /* enable */, &pending);
+  }
+}
+
+void HWCDisplayPrimary::SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type) {
+  HWCDisplay::SetFrameDumpConfig(count, bit_mask_layer_type);
+  dump_output_to_file_ = bit_mask_layer_type & (1 << OUTPUT_LAYER_DUMP);
+  DLOGI("output_layer_dump_enable %d", dump_output_to_file_);
+
+  if (!count || !dump_output_to_file_) {
+    return;
+  }
+
+  // Allocate and map output buffer
+  output_buffer_info_ = {};
+  // Since we dump DSPP output use Panel resolution.
+  GetPanelResolution(&output_buffer_info_.buffer_config.width,
+                     &output_buffer_info_.buffer_config.height);
+  output_buffer_info_.buffer_config.format = kFormatRGB888;
+  output_buffer_info_.buffer_config.buffer_count = 1;
+  if (buffer_allocator_->AllocateBuffer(&output_buffer_info_) != 0) {
+    DLOGE("Buffer allocation failed");
+    output_buffer_info_ = {};
+    return;
+  }
+
+  void *buffer = mmap(NULL, output_buffer_info_.alloc_buffer_info.size, PROT_READ | PROT_WRITE,
+                      MAP_SHARED, output_buffer_info_.alloc_buffer_info.fd, 0);
+
+  if (buffer == MAP_FAILED) {
+    DLOGE("mmap failed with err %d", errno);
+    buffer_allocator_->FreeBuffer(&output_buffer_info_);
+    output_buffer_info_ = {};
+    return;
+  }
+
+  output_buffer_base_ = buffer;
+  post_processed_output_ = true;
+  uint32_t pending = 0;  // Just a temporary to satisfy the API
+  ControlPartialUpdate(false /* enable */, &pending);
+}
+
+int HWCDisplayPrimary::FrameCaptureAsync(const BufferInfo &output_buffer_info,
+                                         bool post_processed_output) {
+  // Note: This function is called in context of a binder thread and a lock is already held
+  if (output_buffer_info.alloc_buffer_info.fd < 0) {
+    DLOGE("Invalid fd %d", output_buffer_info.alloc_buffer_info.fd);
+    return -1;
+  }
+
+  auto panel_width = 0u;
+  auto panel_height = 0u;
+  auto fb_width = 0u;
+  auto fb_height = 0u;
+
+  GetPanelResolution(&panel_width, &panel_height);
+  GetFrameBufferResolution(&fb_width, &fb_height);
+
+  if (post_processed_output && (output_buffer_info_.buffer_config.width < panel_width ||
+                                output_buffer_info_.buffer_config.height < panel_height)) {
+    DLOGE("Buffer dimensions should not be less than panel resolution");
+    return -1;
+  } else if (!post_processed_output && (output_buffer_info_.buffer_config.width < fb_width ||
+                                        output_buffer_info_.buffer_config.height < fb_height)) {
+    DLOGE("Buffer dimensions should not be less than FB resolution");
+    return -1;
+  }
+
+  SetLayerBuffer(output_buffer_info, &output_buffer_);
+  post_processed_output_ = post_processed_output;
+  frame_capture_buffer_queued_ = true;
+  // Status is only cleared on a new call to dump and remains valid otherwise
+  frame_capture_status_ = -EAGAIN;
+
+  uint32_t pending = 0;  // Just a temporary to satisfy the API
+  ControlPartialUpdate(false /* enable */, &pending);
+
+  return 0;
+}
+
+}  // namespace sdm