OSDN Git Service

Move Display Commits to a separate thread.
authorKalyan Kondapally <kalyan.kondapally@intel.com>
Sun, 19 Feb 2017 22:50:46 +0000 (14:50 -0800)
committerKalyan Kondapally <kalyan.kondapally@intel.com>
Wed, 22 Feb 2017 09:44:59 +0000 (01:44 -0800)
This should ensure that any waits we do on KMS Fences doesn't
block the main thread.

Jira: None.
Test: No regressions on Linux and Android.

Signed-off-by: Kalyan Kondapally <kalyan.kondapally@intel.com>
15 files changed:
Android.mk
Makefile.sources
common/compositor/gl/egloffscreencontext.cpp
common/core/gpudevice.cpp
common/display/display.cpp
common/display/display.h
common/display/displayplanemanager.cpp
common/display/displayqueue.cpp [new file with mode: 0644]
common/display/displayqueue.h [new file with mode: 0644]
common/display/headless.h
common/display/pageflipeventhandler.h
common/display/virtualdisplay.h
common/utils/hwcthread.cpp
common/utils/hwcthread.h
public/spinlock.h

index 774730a..e5cb23b 100644 (file)
@@ -58,6 +58,7 @@ LOCAL_SRC_FILES := \
        common/display/display.cpp \
        common/display/displayplane.cpp \
        common/display/displayplanemanager.cpp \
+       common/display/displayqueue.cpp \
        common/display/headless.cpp \
        common/display/pageflipeventhandler.cpp \
        common/display/virtualdisplay.cpp \
index fb828a1..96ea15d 100644 (file)
@@ -10,6 +10,7 @@ common_SOURCES =              \
     common/core/overlaybuffer.cpp \
     common/core/overlaylayer.cpp \
     common/display/display.cpp \
+    common/display/displayqueue.cpp \
     common/display/displayplane.cpp \
     common/display/displayplanemanager.cpp \
     common/display/headless.cpp \
index 8c78d82..b0de404 100644 (file)
@@ -114,6 +114,9 @@ EGLint EGLOffScreenContext::GetSyncFD() {
   }
 
   eglDestroySyncKHR(egl_display_, egl_sync);
+#else
+  // Lets ensure every thing is flushed.
+  eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE, egl_ctx_);
 #endif
   return sync_fd;
 }
index 465cb69..614e563 100644 (file)
@@ -51,7 +51,7 @@ namespace hwcomposer {
 class GpuDevice::DisplayManager : public HWCThread {
  public:
   DisplayManager();
-  ~DisplayManager();
+  ~DisplayManager() override;
 
   bool Init(uint32_t fd);
 
index 5b2585d..096e655 100644 (file)
@@ -20,9 +20,7 @@
 #include <hwclayer.h>
 #include <hwctrace.h>
 
-#include "displayplanemanager.h"
-#include "nativesync.h"
-#include "overlaylayer.h"
+#include "displayqueue.h"
 
 namespace hwcomposer {
 
@@ -34,32 +32,19 @@ Display::Display(uint32_t gpu_fd, NativeBufferHandler &buffer_handler,
       crtc_id_(crtc_id),
       pipe_(pipe_id),
       connector_(0),
-      blob_id_(0),
-      old_blob_id_(0),
       gpu_fd_(gpu_fd),
       is_connected_(false),
       is_powered_off_(true) {
 }
 
 Display::~Display() {
-  if (blob_id_)
-    drmModeDestroyPropertyBlob(gpu_fd_, blob_id_);
-
-  if (old_blob_id_)
-    drmModeDestroyPropertyBlob(gpu_fd_, old_blob_id_);
+  display_queue_->Exit();
 }
 
 bool Display::Initialize() {
-  ScopedDrmObjectPropertyPtr crtc_props(
-      drmModeObjectGetProperties(gpu_fd_, crtc_id_, DRM_MODE_OBJECT_CRTC));
-  GetDrmObjectProperty("ACTIVE", crtc_props, &active_prop_);
-  GetDrmObjectProperty("MODE_ID", crtc_props, &mode_id_prop_);
-#ifndef DISABLE_EXPLICIT_SYNC
-  GetDrmObjectProperty("OUT_FENCE_PTR", crtc_props, &out_fence_ptr_prop_);
-#endif
   frame_ = 0;
   flip_handler_.reset(new PageFlipEventHandler());
-  compositor_.Init();
+  display_queue_.reset(new DisplayQueue(gpu_fd_, crtc_id_));
 
   return true;
 }
@@ -73,42 +58,27 @@ bool Display::Connect(const drmModeModeInfo &mode_info,
     is_connected_ = true;
     return true;
   }
-  ScopedSpinLock lock(spin_lock_);
+
   IHOTPLUGEVENTTRACE("Display is being connected to a new connector.");
-  mode_ = mode_info;
   connector_ = connector->connector_id;
-  width_ = mode_.hdisplay;
-  height_ = mode_.vdisplay;
-  refresh_ = (mode_.clock * 1000.0f) / (mode_.htotal * mode_.vtotal);
+  width_ = mode_info.hdisplay;
+  height_ = mode_info.vdisplay;
+  refresh_ =
+      (mode_info.clock * 1000.0f) / (mode_info.htotal * mode_info.vtotal);
   dpix_ = connector->mmWidth ? (width_ * kUmPerInch) / connector->mmWidth : -1;
   dpiy_ =
       connector->mmHeight ? (height_ * kUmPerInch) / connector->mmHeight : -1;
 
-  ScopedDrmObjectPropertyPtr connector_props(drmModeObjectGetProperties(
-      gpu_fd_, connector_, DRM_MODE_OBJECT_CONNECTOR));
-  if (!connector_props) {
-    ETRACE("Unable to get connector properties.");
-    return false;
-  }
-
-  GetDrmObjectProperty("DPMS", connector_props, &dpms_prop_);
-  GetDrmObjectProperty("CRTC_ID", connector_props, &crtc_prop_);
   is_powered_off_ = false;
   is_connected_ = true;
-  display_plane_manager_.reset(
-      new DisplayPlaneManager(gpu_fd_, pipe_, crtc_id_));
 
-  if (!display_plane_manager_->Initialize(&buffer_handler_, width_, height_)) {
-    ETRACE("Failed to initialize Display Manager.");
+  if (!display_queue_->Initialize(width_, height_, pipe_, connector_, mode_info,
+                                  &buffer_handler_)) {
+    ETRACE("Failed to initialize Display Queue.");
     return false;
   }
 
   flip_handler_->Init(refresh_, gpu_fd_, pipe_);
-  dpms_mode_ = DRM_MODE_DPMS_ON;
-  drmModeConnectorSetProperty(gpu_fd_, connector_, dpms_prop_,
-                              DRM_MODE_DPMS_ON);
-  pending_operations_ |= PendingModeset::kModeset;
-
   return true;
 }
 
@@ -120,31 +90,10 @@ void Display::DisConnect() {
 void Display::ShutDown() {
   if (is_powered_off_)
     return;
-  ScopedSpinLock lock(spin_lock_);
+
   IHOTPLUGEVENTTRACE("Display::ShutDown recieved.");
+  display_queue_->Exit();
   is_powered_off_ = true;
-  dpms_mode_ = DRM_MODE_DPMS_OFF;
-  drmModeConnectorSetProperty(gpu_fd_, connector_, dpms_prop_,
-                              DRM_MODE_DPMS_OFF);
-  previous_layers_.clear();
-  previous_plane_state_.clear();
-
-  ScopedDrmAtomicReqPtr pset(drmModeAtomicAlloc());
-  if (!pset) {
-    ETRACE("Failed to allocate property set %d", -ENOMEM);
-    return;
-  }
-
-  bool active = false;
-  int ret =
-      drmModeAtomicAddProperty(pset.get(), crtc_id_, active_prop_, active) < 0;
-  if (ret) {
-    ETRACE("Failed to set display to inactive");
-    return;
-  }
-
-  display_plane_manager_->DisablePipe(pset.get());
-  display_plane_manager_.reset(nullptr);
 }
 
 bool Display::GetDisplayAttribute(uint32_t /*config*/,
@@ -216,181 +165,12 @@ bool Display::GetActiveConfig(uint32_t *config) {
 }
 
 bool Display::SetDpmsMode(uint32_t dpms_mode) {
-  ScopedSpinLock lock(spin_lock_);
-  if (dpms_mode_ == dpms_mode)
-    return true;
-
-  dpms_mode_ = dpms_mode;
-  drmModeConnectorSetProperty(gpu_fd_, connector_, dpms_prop_, dpms_mode);
-  return true;
-}
-
-bool Display::ApplyPendingModeset(drmModeAtomicReqPtr property_set,
-                                  NativeSync *sync, uint64_t *out_fence) {
-  if (pending_operations_ & kModeset) {
-    if (old_blob_id_) {
-      drmModeDestroyPropertyBlob(gpu_fd_, old_blob_id_);
-      old_blob_id_ = 0;
-    }
-
-    drmModeCreatePropertyBlob(gpu_fd_, &mode_, sizeof(drmModeModeInfo),
-                              &blob_id_);
-    if (blob_id_ == 0)
-      return false;
-
-    bool active = true;
-
-    int ret = drmModeAtomicAddProperty(property_set, crtc_id_, mode_id_prop_,
-                                       blob_id_) < 0 ||
-              drmModeAtomicAddProperty(property_set, connector_, crtc_prop_,
-                                       crtc_id_) < 0 ||
-              drmModeAtomicAddProperty(property_set, crtc_id_, active_prop_,
-                                       active) < 0;
-    if (ret) {
-      ETRACE("Failed to add blob %d to pset", blob_id_);
-      return false;
-    }
-
-    pending_operations_ &= ~kModeset;
-    old_blob_id_ = blob_id_;
-    blob_id_ = 0;
-  } else {
-#ifndef DISABLE_EXPLICIT_SYNC
-    if (out_fence_ptr_prop_ != 0) {
-      int ret = drmModeAtomicAddProperty(
-          property_set, crtc_id_, out_fence_ptr_prop_, (uintptr_t)out_fence);
-      if (ret < 0) {
-        ETRACE("Failed to add OUT_FENCE_PTR property to pset: %d", ret);
-        return false;
-      }
-    }
-#else
-    *out_fence = sync->CreateNextTimelineFence();
-#endif
-  }
-
-  return true;
-}
-
-void Display::GetDrmObjectProperty(const char *name,
-                                   const ScopedDrmObjectPropertyPtr &props,
-                                   uint32_t *id) const {
-  uint32_t count_props = props->count_props;
-  for (uint32_t i = 0; i < count_props; i++) {
-    ScopedDrmPropertyPtr property(drmModeGetProperty(gpu_fd_, props->props[i]));
-    if (property && !strcmp(property->name, name)) {
-      *id = property->prop_id;
-      break;
-    }
-  }
-  if (!(*id))
-    ETRACE("Could not find property %s", name);
+  return display_queue_->SetDpmsMode(dpms_mode);
 }
 
 bool Display::Present(std::vector<HwcLayer *> &source_layers) {
   CTRACE();
-  ScopedSpinLock lock(spin_lock_);
-  if (is_powered_off_) {
-    IHOTPLUGEVENTTRACE("Trying to update an Disconnected Display.");
-    return false;
-  }
-
-  bool needs_modeset = pending_operations_ & kModeset;
-  // Create a Sync object for this Composition.
-  std::unique_ptr<NativeSync> sync_object(new NativeSync());
-  if (!sync_object->Init()) {
-    ETRACE("Failed to create sync object.");
-    return false;
-  }
-
-  std::vector<OverlayLayer> layers;
-  std::vector<HwcRect<int>> layers_rects;
-
-  int ret = 0;
-  size_t size = source_layers.size();
-  for (size_t layer_index = 0; layer_index < size; layer_index++) {
-    HwcLayer *layer = source_layers.at(layer_index);
-    layers.emplace_back();
-    OverlayLayer &overlay_layer = layers.back();
-    overlay_layer.SetNativeHandle(layer->GetNativeHandle());
-    overlay_layer.SetTransform(layer->GetTransform());
-    overlay_layer.SetAlpha(layer->GetAlpha());
-    overlay_layer.SetBlending(layer->GetBlending());
-    overlay_layer.SetSourceCrop(layer->GetSourceCrop());
-    overlay_layer.SetDisplayFrame(layer->GetDisplayFrame());
-    overlay_layer.SetIndex(layer_index);
-    overlay_layer.SetAcquireFence(layer->acquire_fence.Release());
-    layers_rects.emplace_back(layer->GetDisplayFrame());
-    int ret =
-       layer->release_fence.Reset(sync_object->CreateNextTimelineFence());
-    if (ret < 0)
-      ETRACE("Failed to create fence for layer, error: %s", PRINTERROR());
-  }
-
-  // Reset any Display Manager and Compositor state.
-  if (!display_plane_manager_->BeginFrameUpdate(layers)) {
-    ETRACE("Failed to import needed buffers in DisplayManager.");
-    return false;
-  }
-
-  DisplayPlaneStateList current_composition_planes;
-  bool render_layers;
-  // Validate Overlays and Layers usage.
-  std::tie(render_layers, current_composition_planes) =
-      display_plane_manager_->ValidateLayers(
-          layers, previous_layers_, previous_plane_state_, needs_modeset);
-
-  DUMP_CURRENT_COMPOSITION_PLANES();
-
-  if (!compositor_.BeginFrame()) {
-    ETRACE("Failed to initialize compositor.");
-    return false;
-  }
-
-  if (render_layers) {
-    // Prepare for final composition.
-    if (!compositor_.Draw(current_composition_planes, layers, layers_rects)) {
-      ETRACE("Failed to prepare for the frame composition ret=%d", ret);
-      return false;
-    }
-  }
-
-  // Do the actual commit.
-  ScopedDrmAtomicReqPtr pset(drmModeAtomicAlloc());
-
-  if (!pset) {
-    ETRACE("Failed to allocate property set %d", -ENOMEM);
-    return false;
-  }
-
-  uint64_t fence = 0;
-  if (!ApplyPendingModeset(pset.get(), sync_object.get(), &fence)) {
-    ETRACE("Failed to Modeset");
-    return false;
-  }
-
-  bool succesful_commit = true;
-
-  if (!display_plane_manager_->CommitFrame(current_composition_planes,
-                                           pset.get(), needs_modeset,
-                                           sync_object, out_fence_)) {
-    succesful_commit = false;
-  } else {
-    display_plane_manager_->EndFrameUpdate();
-    previous_layers_.swap(layers);
-    previous_plane_state_.swap(current_composition_planes);
-  }
-
-  if (!succesful_commit || needs_modeset)
-    return succesful_commit;
-
-
-  compositor_.InsertFence(dup(fence));
-
-  if (fence > 0)
-    out_fence_.Reset(fence);
-
-  return true;
+  return display_queue_->QueueUpdate(source_layers);
 }
 
 int Display::RegisterVsyncCallback(std::shared_ptr<VsyncCallback> callback,
index 523fac7..a2a92a1 100644 (file)
 // limitations under the License.
 */
 
-#ifndef INTERNAL_DISPLAY_H_
-#define INTERNAL_DISPLAY_H_
+#ifndef DISPLAY_H_
+#define DISPLAY_H_
 
 #include "platformdefines.h"
 
-#include <mutex>
 #include <stdint.h>
 #include <xf86drmMode.h>
 
 #include <nativedisplay.h>
 #include <nativebufferhandler.h>
 
-#include "compositor.h"
 #include "pageflipeventhandler.h"
 #include "scopedfd.h"
-#include "spinlock.h"
 
 namespace hwcomposer {
 class DisplayPlaneState;
 class DisplayPlaneManager;
+class DisplayQueue;
 class GpuDevice;
 class NativeSync;
 struct HwcLayer;
@@ -43,7 +41,7 @@ class Display : public NativeDisplay {
  public:
   Display(uint32_t gpu_fd, NativeBufferHandler &handler, uint32_t pipe_id,
           uint32_t crtc_id);
-  ~Display();
+  ~Display() override;
 
   bool Initialize() override;
 
@@ -101,33 +99,13 @@ class Display : public NativeDisplay {
   void ShutDown() override;
 
  private:
-  enum PendingModeset { kNone = 0, kModeset = 1 << 0 };
-
   void ShutDownPipe();
-  void InitializeResources();
-  bool ApplyPendingModeset(drmModeAtomicReqPtr property_set, NativeSync *sync,
-                           uint64_t *out_fence);
-
-  void GetDrmObjectProperty(const char *name,
-                            const ScopedDrmObjectPropertyPtr &props,
-                            uint32_t *id) const;
 
   NativeBufferHandler &buffer_handler_;
-  Compositor compositor_;
-  drmModeModeInfo mode_;
   uint32_t frame_;
-  uint32_t dpms_prop_;
-  uint32_t crtc_prop_;
-  uint32_t active_prop_;
-  uint32_t mode_id_prop_;
-  uint32_t out_fence_ptr_prop_;
   uint32_t crtc_id_;
   uint32_t pipe_;
-  uint32_t dpms_mode_ = DRM_MODE_DPMS_ON;
   uint32_t connector_;
-  uint32_t pending_operations_ = kNone;
-  uint32_t blob_id_ = 0;
-  uint32_t old_blob_id_ = 0;
   int32_t width_;
   int32_t height_;
   int32_t dpix_;
@@ -136,13 +114,9 @@ class Display : public NativeDisplay {
   bool is_connected_;
   bool is_powered_off_;
   float refresh_;
-  ScopedFd out_fence_ = -1;
   std::unique_ptr<PageFlipEventHandler> flip_handler_;
-  std::unique_ptr<DisplayPlaneManager> display_plane_manager_;
-  SpinLock spin_lock_;
-  std::vector<OverlayLayer> previous_layers_;
-  DisplayPlaneStateList previous_plane_state_;
+  std::unique_ptr<DisplayQueue> display_queue_;
 };
 
 }  // namespace hwcomposer
-#endif  // INTERNAL_DISPLAY_H_
+#endif  // DISPLAY_H_
index f8b8593..38d65eb 100644 (file)
@@ -328,8 +328,9 @@ bool DisplayPlaneManager::CommitFrame(DisplayPlaneStateList &comp_planes,
     }
   }
 
+#ifndef DISABLE_EXPLICIT_SYNC
   fence.Close();
-
+#endif
   if (ret) {
     ETRACE("Failed to commit pset ret=%s\n", PRINTERROR());
     return false;
diff --git a/common/display/displayqueue.cpp b/common/display/displayqueue.cpp
new file mode 100644 (file)
index 0000000..9f41310
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include "displayqueue.h"
+
+#include <hwcdefs.h>
+#include <hwclayer.h>
+#include <hwctrace.h>
+
+#include <nativebufferhandler.h>
+
+#include "displayplanemanager.h"
+#include "overlaylayer.h"
+#include "pageflipeventhandler.h"
+
+namespace hwcomposer {
+
+DisplayQueue::DisplayQueue(uint32_t gpu_fd, uint32_t crtc_id)
+    : HWCThread(-8, "DisplayQueue"),
+      crtc_id_(crtc_id),
+      gpu_fd_(gpu_fd),
+      blob_id_(0),
+      old_blob_id_(0) {
+  compositor_.Init();
+  ScopedDrmObjectPropertyPtr crtc_props(
+      drmModeObjectGetProperties(gpu_fd_, crtc_id_, DRM_MODE_OBJECT_CRTC));
+  GetDrmObjectProperty("ACTIVE", crtc_props, &active_prop_);
+  GetDrmObjectProperty("MODE_ID", crtc_props, &mode_id_prop_);
+#ifndef DISABLE_EXPLICIT_SYNC
+  GetDrmObjectProperty("OUT_FENCE_PTR", crtc_props, &out_fence_ptr_prop_);
+#endif
+}
+
+DisplayQueue::~DisplayQueue() {
+  if (blob_id_)
+    drmModeDestroyPropertyBlob(gpu_fd_, blob_id_);
+
+  if (old_blob_id_)
+    drmModeDestroyPropertyBlob(gpu_fd_, old_blob_id_);
+}
+
+bool DisplayQueue::Initialize(uint32_t width, uint32_t height, uint32_t pipe,
+                              uint32_t connector,
+                              const drmModeModeInfo& mode_info,
+                              NativeBufferHandler* buffer_handler) {
+  ScopedSpinLock lock(spin_lock_);
+  frame_ = 0;
+  previous_layers_.clear();
+  previous_plane_state_.clear();
+  display_plane_manager_.reset(
+      new DisplayPlaneManager(gpu_fd_, pipe, crtc_id_));
+
+  if (!display_plane_manager_->Initialize(buffer_handler, width, height)) {
+    ETRACE("Failed to initialize DisplayQueue Manager.");
+    return false;
+  }
+
+  connector_ = connector;
+  mode_ = mode_info;
+
+  ScopedDrmObjectPropertyPtr connector_props(drmModeObjectGetProperties(
+      gpu_fd_, connector_, DRM_MODE_OBJECT_CONNECTOR));
+  if (!connector_props) {
+    ETRACE("Unable to get connector properties.");
+    return false;
+  }
+
+  GetDrmObjectProperty("DPMS", connector_props, &dpms_prop_);
+  GetDrmObjectProperty("CRTC_ID", connector_props, &crtc_prop_);
+
+  dpms_mode_ = DRM_MODE_DPMS_ON;
+  drmModeConnectorSetProperty(gpu_fd_, connector_, dpms_prop_,
+                              DRM_MODE_DPMS_ON);
+
+  needs_modeset_ = true;
+  lock.Reset();
+  if (!InitWorker()) {
+    ETRACE("Failed to initalize thread for DisplayQueue. %s", PRINTERROR());
+    return false;
+  }
+
+  return true;
+}
+
+void DisplayQueue::Exit() {
+  IHOTPLUGEVENTTRACE("DisplayQueue::Exit recieved.");
+  HWCThread::Exit();
+}
+
+bool DisplayQueue::GetFence(ScopedDrmAtomicReqPtr& property_set,
+                            uint64_t* out_fence) {
+#ifndef DISABLE_EXPLICIT_SYNC
+  if (out_fence_ptr_prop_ != 0) {
+    int ret =
+        drmModeAtomicAddProperty(property_set.get(), crtc_id_,
+                                 out_fence_ptr_prop_, (uintptr_t)out_fence);
+    if (ret < 0) {
+      ETRACE("Failed to add OUT_FENCE_PTR property to pset: %d", ret);
+      return false;
+    }
+  }
+#else
+  *out_fence = -1;
+#endif
+
+  return true;
+}
+
+bool DisplayQueue::ApplyPendingModeset(drmModeAtomicReqPtr property_set) {
+  if (old_blob_id_) {
+    drmModeDestroyPropertyBlob(gpu_fd_, old_blob_id_);
+    old_blob_id_ = 0;
+  }
+
+  drmModeCreatePropertyBlob(gpu_fd_, &mode_, sizeof(drmModeModeInfo),
+                            &blob_id_);
+  if (blob_id_ == 0)
+    return false;
+
+  bool active = true;
+
+  int ret = drmModeAtomicAddProperty(property_set, crtc_id_, mode_id_prop_,
+                                     blob_id_) < 0 ||
+            drmModeAtomicAddProperty(property_set, connector_, crtc_prop_,
+                                     crtc_id_) < 0 ||
+            drmModeAtomicAddProperty(property_set, crtc_id_, active_prop_,
+                                     active) < 0;
+  if (ret) {
+    ETRACE("Failed to add blob %d to pset", blob_id_);
+    return false;
+  }
+
+  old_blob_id_ = blob_id_;
+  blob_id_ = 0;
+
+  return true;
+}
+
+bool DisplayQueue::SetDpmsMode(uint32_t dpms_mode) {
+  ScopedSpinLock lock(spin_lock_);
+  if (dpms_mode_ == dpms_mode)
+    return true;
+
+  dpms_mode_ = dpms_mode;
+  if (dpms_mode_ == DRM_MODE_DPMS_OFF) {
+    Exit();
+    return true;
+  }
+
+  if (dpms_mode_ == DRM_MODE_DPMS_ON) {
+    needs_modeset_ = true;
+    if (!InitWorker()) {
+      ETRACE("Failed to initalize thread for DisplayQueue. %s", PRINTERROR());
+      return false;
+    }
+  }
+
+  drmModeConnectorSetProperty(gpu_fd_, connector_, dpms_prop_, dpms_mode);
+
+  return true;
+}
+
+bool DisplayQueue::QueueUpdate(std::vector<HwcLayer*>& source_layers) {
+  CTRACE();
+  ScopedSpinLock lock(display_queue_);
+  if (!display_plane_manager_) {
+    IHOTPLUGEVENTTRACE("Trying to update an Disconnected Display.");
+    return false;
+  }
+
+  queue_.emplace();
+  DisplayQueueItem& queue_item = queue_.back();
+  // Create a Sync object for this Composition.
+  queue_item.sync_object_.reset(new NativeSync());
+  if (!queue_item.sync_object_->Init()) {
+    ETRACE("Failed to create sync object.");
+    return false;
+  }
+
+  size_t size = source_layers.size();
+
+  for (size_t layer_index = 0; layer_index < size; layer_index++) {
+    HwcLayer* layer = source_layers.at(layer_index);
+    queue_item.layers_.emplace_back();
+    OverlayLayer& overlay_layer = queue_item.layers_.back();
+    overlay_layer.SetNativeHandle(layer->GetNativeHandle());
+    overlay_layer.SetTransform(layer->GetTransform());
+    overlay_layer.SetAlpha(layer->GetAlpha());
+    overlay_layer.SetBlending(layer->GetBlending());
+    overlay_layer.SetSourceCrop(layer->GetSourceCrop());
+    overlay_layer.SetDisplayFrame(layer->GetDisplayFrame());
+    overlay_layer.SetIndex(layer_index);
+    overlay_layer.SetAcquireFence(layer->acquire_fence.Release());
+    queue_item.layers_rects_.emplace_back(layer->GetDisplayFrame());
+    int ret = layer->release_fence.Reset(
+        queue_item.sync_object_->CreateNextTimelineFence());
+    if (ret < 0)
+      ETRACE("Failed to create fence for layer, error: %s", PRINTERROR());
+  }
+
+  Resume();
+  return true;
+}
+
+void DisplayQueue::HandleUpdateRequest(DisplayQueueItem& queue_item) {
+  CTRACE();
+  ScopedSpinLock lock(spin_lock_);
+  // Reset any DisplayQueue Manager and Compositor state.
+  if (!display_plane_manager_->BeginFrameUpdate(queue_item.layers_)) {
+    ETRACE("Failed to import needed buffers in DisplayQueueManager.");
+    return;
+  }
+
+  bool needs_modeset = needs_modeset_;
+  needs_modeset_ = false;
+
+  DisplayPlaneStateList current_composition_planes;
+  bool render_layers;
+  // Validate Overlays and Layers usage.
+  std::tie(render_layers, current_composition_planes) =
+      display_plane_manager_->ValidateLayers(
+          queue_item.layers_, previous_layers_, previous_plane_state_,
+          needs_modeset);
+
+  DUMP_CURRENT_COMPOSITION_PLANES();
+
+  if (!compositor_.BeginFrame()) {
+    ETRACE("Failed to initialize compositor.");
+    return;
+  }
+
+  if (render_layers) {
+    // Prepare for final composition.
+    if (!compositor_.Draw(current_composition_planes, queue_item.layers_,
+                          queue_item.layers_rects_)) {
+      ETRACE("Failed to prepare for the frame composition. ");
+      return;
+    }
+  }
+
+  // Do the actual commit.
+  bool succesful_commit = true;
+  uint64_t fence = 0;
+  // Do the actual commit.
+  ScopedDrmAtomicReqPtr pset(drmModeAtomicAlloc());
+
+  if (!pset) {
+    ETRACE("Failed to allocate property set %d", -ENOMEM);
+    return;
+  }
+
+  if (needs_modeset && !ApplyPendingModeset(pset.get())) {
+    ETRACE("Failed to Modeset.");
+    return;
+  }
+
+  GetFence(pset, &fence);
+  if (!display_plane_manager_->CommitFrame(
+          current_composition_planes, pset.get(), needs_modeset,
+          queue_item.sync_object_, out_fence_)) {
+    succesful_commit = false;
+  } else {
+    display_plane_manager_->EndFrameUpdate();
+    previous_layers_.swap(queue_item.layers_);
+    previous_plane_state_.swap(current_composition_planes);
+  }
+
+  if (!succesful_commit || needs_modeset)
+    return;
+
+  compositor_.InsertFence(dup(fence));
+
+  if (fence > 0)
+    out_fence_.Reset(fence);
+}
+
+void DisplayQueue::HandleRoutine() {
+  display_queue_.lock();
+  size_t size = queue_.size();
+
+  if (size <= 0) {
+    display_queue_.unlock();
+    ConditionalSuspend();
+    return;
+  }
+
+  DisplayQueueItem& queue_item = queue_.front();
+  DisplayQueueItem item;
+  item.layers_.swap(queue_item.layers_);
+  item.layers_rects_.swap(queue_item.layers_rects_);
+  item.sync_object_.reset(queue_item.sync_object_.release());
+  queue_.pop();
+  display_queue_.unlock();
+
+  HandleUpdateRequest(item);
+}
+
+void DisplayQueue::HandleExit() {
+  ScopedSpinLocks lock(spin_lock_, display_queue_);
+  ScopedDrmAtomicReqPtr pset(drmModeAtomicAlloc());
+  if (!pset) {
+    ETRACE("Failed to allocate property set %d", -ENOMEM);
+    return;
+  }
+
+  bool active = false;
+  int ret =
+      drmModeAtomicAddProperty(pset.get(), crtc_id_, active_prop_, active) < 0;
+  if (ret) {
+    ETRACE("Failed to set display to inactive");
+    return;
+  }
+  display_plane_manager_->DisablePipe(pset.get());
+  dpms_mode_ = DRM_MODE_DPMS_OFF;
+  drmModeConnectorSetProperty(gpu_fd_, connector_, dpms_prop_,
+                              DRM_MODE_DPMS_OFF);
+  previous_layers_.clear();
+  previous_plane_state_.clear();
+  display_plane_manager_.reset(nullptr);
+  std::queue<DisplayQueueItem>().swap(queue_);
+}
+
+void DisplayQueue::GetDrmObjectProperty(const char* name,
+                                        const ScopedDrmObjectPropertyPtr& props,
+                                        uint32_t* id) const {
+  uint32_t count_props = props->count_props;
+  for (uint32_t i = 0; i < count_props; i++) {
+    ScopedDrmPropertyPtr property(drmModeGetProperty(gpu_fd_, props->props[i]));
+    if (property && !strcmp(property->name, name)) {
+      *id = property->prop_id;
+      break;
+    }
+  }
+  if (!(*id))
+    ETRACE("Could not find property %s", name);
+}
+
+}  // namespace hwcomposer
diff --git a/common/display/displayqueue.h b/common/display/displayqueue.h
new file mode 100644 (file)
index 0000000..5574409
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef DISPLAY_QUEUE_H_
+#define DISPLAY_QUEUE_H_
+
+#include <queue>
+
+#include "platformdefines.h"
+
+#include <drmscopedtypes.h>
+
+#include "compositor.h"
+#include "hwcthread.h"
+#include "nativesync.h"
+#include "scopedfd.h"
+#include "spinlock.h"
+
+namespace hwcomposer {
+class DisplayPlaneManager;
+struct HwcLayer;
+class NativeBufferHandler;
+class PageFlipEventHandler;
+
+class DisplayQueue : public HWCThread {
+ public:
+  DisplayQueue(uint32_t gpu_fd, uint32_t crtc_id);
+  ~DisplayQueue() override;
+
+  bool Initialize(uint32_t width, uint32_t height, uint32_t pipe,
+                  uint32_t connector, const drmModeModeInfo& mode_info,
+                  NativeBufferHandler* buffer_handler);
+
+  void Exit();
+
+  bool QueueUpdate(std::vector<HwcLayer*>& source_layers);
+  bool SetDpmsMode(uint32_t dpms_mode);
+
+ protected:
+  void HandleRoutine() override;
+  void HandleExit() override;
+
+ private:
+  struct DisplayQueueItem {
+    std::vector<OverlayLayer> layers_;
+    std::vector<HwcRect<int>> layers_rects_;
+    std::unique_ptr<NativeSync> sync_object_;
+  };
+
+  void HandleUpdateRequest(DisplayQueueItem& queue_item);
+  bool ApplyPendingModeset(drmModeAtomicReqPtr property_set);
+  bool GetFence(ScopedDrmAtomicReqPtr& property_set, uint64_t* out_fence);
+  void GetDrmObjectProperty(const char* name,
+                            const ScopedDrmObjectPropertyPtr& props,
+                            uint32_t* id) const;
+
+  Compositor compositor_;
+  drmModeModeInfo mode_;
+  uint32_t frame_;
+  uint32_t dpms_prop_;
+  uint32_t dpms_mode_ = DRM_MODE_DPMS_ON;
+  uint32_t out_fence_ptr_prop_;
+  uint32_t active_prop_;
+  uint32_t mode_id_prop_;
+  uint32_t crtc_id_;
+  uint32_t connector_;
+  uint32_t crtc_prop_;
+  uint32_t blob_id_ = 0;
+  uint32_t old_blob_id_ = 0;
+  uint32_t gpu_fd_;
+  bool needs_modeset_ = false;
+  std::unique_ptr<PageFlipEventHandler> flip_handler_;
+  std::unique_ptr<DisplayPlaneManager> display_plane_manager_;
+  SpinLock spin_lock_;
+  SpinLock display_queue_;
+  std::queue<DisplayQueueItem> queue_;
+  std::vector<OverlayLayer> previous_layers_;
+  DisplayPlaneStateList previous_plane_state_;
+  ScopedFd out_fence_ = -1;
+};
+
+}  // namespace hwcomposer
+#endif  // DISPLAY_QUEUE_H_
index cfd5281..9bade7c 100644 (file)
@@ -27,7 +27,7 @@ class Headless : public NativeDisplay {
  public:
   Headless(uint32_t gpu_fd, NativeBufferHandler &handler, uint32_t pipe_id,
            uint32_t crtc_id);
-  ~Headless();
+  ~Headless() override;
 
   bool Initialize() override;
 
index 260db72..eeeb6e0 100644 (file)
@@ -29,7 +29,7 @@ namespace hwcomposer {
 class PageFlipEventHandler : public HWCThread {
  public:
   PageFlipEventHandler();
-  ~PageFlipEventHandler();
+  ~PageFlipEventHandler() override;
 
   void Init(float refresh, int fd, int pipe);
 
index a2e0622..92288f6 100644 (file)
@@ -30,7 +30,7 @@ class VirtualDisplay : public Headless {
  public:
   VirtualDisplay(uint32_t gpu_fd, NativeBufferHandler &handler,
                  uint32_t pipe_id, uint32_t crtc_id);
-  ~VirtualDisplay();
+  ~VirtualDisplay() override;
 
   void InitVirtualDisplay(uint32_t width, uint32_t height) override;
 
index fb00147..d5b05d1 100644 (file)
@@ -36,34 +36,62 @@ bool HWCThread::InitWorker() {
   if (initialized_)
     return true;
 
+  initialized_ = true;
+  exit_ = false;
   thread_ = std::unique_ptr<std::thread>(
       new std::thread(&HWCThread::ProcessThread, this));
-  initialized_ = true;
+
   return true;
 }
 
+void HWCThread::Resume() {
+  if (!suspended_ || exit_)
+    return;
+
+  mutex_.lock();
+  suspended_ = false;
+  mutex_.unlock();
+
+  cond_.notify_one();
+}
+
 void HWCThread::Exit() {
-  ScopedSpinLock lock(spin_lock_);
   if (!initialized_)
     return;
 
-  thread_->join();
+  mutex_.lock();
   initialized_ = false;
   exit_ = true;
+  mutex_.unlock();
+
+  cond_.notify_one();
+  thread_->join();
+}
+
+void HWCThread::HandleExit() {
 }
 
 void HWCThread::ProcessThread() {
   setpriority(PRIO_PROCESS, 0, priority_);
   prctl(PR_SET_NAME, name_.c_str());
 
+  std::unique_lock<std::mutex> lk(mutex_, std::defer_lock);
   while (true) {
-    spin_lock_.lock();
-    if (exit_)
+    lk.lock();
+    if (exit_) {
+      HandleExit();
       return;
-    spin_lock_.unlock();
+    }
 
+    if (suspended_) {
+      cond_.wait(lk);
+    }
+    lk.unlock();
     HandleRoutine();
   }
 }
 
+void HWCThread::ConditionalSuspend() {
+  suspended_ = true;
+}
 }
index 7864069..51487a3 100644 (file)
@@ -17,6 +17,7 @@
 #ifndef HWC_THREAD_H_
 #define HWC_THREAD_H_
 
+#include <condition_variable>
 #include <thread>
 #include <string>
 
@@ -31,9 +32,12 @@ class HWCThread {
 
   bool InitWorker();
 
+  void Resume();
   void Exit();
+  void ConditionalSuspend();
 
   virtual void HandleRoutine() = 0;
+  virtual void HandleExit();
 
   bool initialized_;
 
@@ -42,8 +46,10 @@ class HWCThread {
 
   int priority_;
   std::string name_;
-  bool exit_;
-  SpinLock spin_lock_;
+  bool exit_ = false;
+  bool suspended_ = false;
+  std::mutex mutex_;
+  std::condition_variable cond_;
 
   std::unique_ptr<std::thread> thread_;
 };
index bc0005b..121c23e 100644 (file)
@@ -18,6 +18,7 @@
 #define SPIN_LOCK_H_
 
 #include <atomic>
+#include <hwctrace.h>
 
 namespace hwcomposer {
 
@@ -40,14 +41,41 @@ class ScopedSpinLock {
  public:
   ScopedSpinLock(SpinLock& lock) : lock_(lock) {
     lock_.lock();
+    locked_ = true;
   }
 
   ~ScopedSpinLock() {
-    lock_.unlock();
+    Reset();
+  }
+
+  void Reset() {
+    if (locked_) {
+      lock_.unlock();
+      locked_ = false;
+    }
   }
 
  private:
   SpinLock& lock_;
+  bool locked_;
+};
+
+class ScopedSpinLocks {
+ public:
+  ScopedSpinLocks(SpinLock& lock1, SpinLock& lock2)
+      : lock1_(lock1), lock2_(lock2) {
+    lock1_.lock();
+    lock2_.lock();
+  }
+
+  ~ScopedSpinLocks() {
+    lock1_.unlock();
+    lock2_.unlock();
+  }
+
+ private:
+  SpinLock& lock1_;
+  SpinLock& lock2_;
 };
 
 }  // namespace hwcomposer