OSDN Git Service

Fall back to single plane composition in Idle case.
authorKalyan Kondapally <kalyan.kondapally@intel.com>
Sun, 28 May 2017 08:14:12 +0000 (01:14 -0700)
committerKalyan Kondapally <kalyan.kondapally@intel.com>
Sun, 4 Jun 2017 09:06:25 +0000 (02:06 -0700)
There is no need to continue using different planes for composition
in case the system is not really updating any new content. We now
track this and if we haven't updated content for the previous three
vblanks, we fall back to single plane composition for the current
content on screen.

Jira: None.
Test: Power consumption is minimum in idle case scenarious.
Signed-off-by: Kalyan Kondapally <kalyan.kondapally@intel.com>
21 files changed:
common/compositor/compositor.cpp
common/compositor/compositor.h
common/compositor/gl/egloffscreencontext.cpp
common/compositor/gl/egloffscreencontext.h
common/compositor/gl/glrenderer.cpp
common/compositor/gl/glrenderer.h
common/compositor/renderer.h
common/compositor/scopedrendererstate.cpp
common/compositor/scopedrendererstate.h
common/compositor/vk/vkrenderer.cpp
common/compositor/vk/vkrenderer.h
common/display/displayplane.cpp
common/display/displayplanemanager.cpp
common/display/displayplanemanager.h
common/display/displayqueue.cpp
common/display/displayqueue.h
common/display/vblankeventhandler.cpp
common/display/vblankeventhandler.h
os/android/grallocbufferhandler.cpp
public/hwcbuffer.h
tests/jsonconfigs/multiplelayers_idle.json [new file with mode: 0644]

index c44d6b1..4ed7b86 100644 (file)
@@ -154,6 +154,55 @@ bool Compositor::DrawOffscreen(std::vector<OverlayLayer> &layers,
   return true;
 }
 
+bool Compositor::DrawIdleState(DisplayPlaneStateList &comp_planes,
+                               std::vector<OverlayLayer> &layers,
+                               const std::vector<HwcRect<int>> &display_frame) {
+  CTRACE();
+  const DisplayPlaneState *comp = NULL;
+  std::vector<size_t> dedicated_layers;
+  ScopedIdleRendererState state(renderer_.get());
+  if (!state.IsValid()) {
+    ETRACE("Failed to draw as Renderer doesnt have a valid context.");
+    return false;
+  }
+
+  if (!gpu_resource_handler_->PrepareResources(layers)) {
+    ETRACE(
+        "Failed to prepare GPU resources for compositing the frame, "
+        "error: %s",
+        PRINTERROR());
+    return false;
+  }
+
+  for (DisplayPlaneState &plane : comp_planes) {
+    if (plane.GetCompositionState() == DisplayPlaneState::State::kScanout) {
+      dedicated_layers.insert(dedicated_layers.end(),
+                              plane.source_layers().begin(),
+                              plane.source_layers().end());
+    } else if (plane.GetCompositionState() ==
+               DisplayPlaneState::State::kRender) {
+      comp = &plane;
+      std::vector<CompositionRegion> &comp_regions =
+          plane.GetCompositionRegion();
+      if (comp_regions.empty()) {
+        SeparateLayers(dedicated_layers, comp->source_layers(), display_frame,
+                       comp_regions);
+      }
+
+      std::vector<size_t>().swap(dedicated_layers);
+      if (comp_regions.empty())
+        continue;
+
+      if (!Render(layers, plane.GetOffScreenTarget(), comp_regions)) {
+        ETRACE("Failed to Render layer.");
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
 void Compositor::InsertFence(uint64_t fence) {
   renderer_->InsertFence(fence);
 }
index b321786..c4a9aed 100644 (file)
@@ -50,6 +50,9 @@ class Compositor {
                      OverlayBufferManager *buffer_manager, uint32_t width,
                      uint32_t height, HWCNativeHandle output_handle,
                      int32_t *retire_fence);
+  bool DrawIdleState(DisplayPlaneStateList &comp_planes,
+                     std::vector<OverlayLayer> &layers,
+                     const std::vector<HwcRect<int>> &display_frame);
   void InsertFence(uint64_t fence);
 
  private:
index e9399aa..e596457 100644 (file)
@@ -23,6 +23,8 @@ namespace hwcomposer {
 EGLOffScreenContext::EGLOffScreenContext()
     : egl_display_(EGL_NO_DISPLAY),
       egl_ctx_(EGL_NO_CONTEXT),
+      egl_idle_display_(EGL_NO_DISPLAY),
+      egl_idle_ctx_(EGL_NO_CONTEXT),
       restore_context_(false) {
 }
 
@@ -30,6 +32,10 @@ EGLOffScreenContext::~EGLOffScreenContext() {
   if (egl_display_ != EGL_NO_DISPLAY && egl_ctx_ != EGL_NO_CONTEXT)
     if (eglDestroyContext(egl_display_, egl_ctx_) == EGL_FALSE)
       ETRACE("Failed to destroy OpenGL ES Context.");
+
+  if (egl_idle_display_ != EGL_NO_DISPLAY && egl_idle_ctx_ != EGL_NO_CONTEXT)
+    if (eglDestroyContext(egl_idle_display_, egl_idle_ctx_) == EGL_FALSE)
+      ETRACE("Failed to destroy Idle OpenGL ES Context.");
 }
 
 bool EGLOffScreenContext::Init() {
@@ -69,6 +75,49 @@ bool EGLOffScreenContext::Init() {
   return true;
 }
 
+bool EGLOffScreenContext::InitIdleContext() {
+  EGLint num_configs;
+  EGLConfig egl_config;
+  static const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3,
+                                           EGL_NONE};
+
+  static const EGLint config_attribs[] = {EGL_SURFACE_TYPE, EGL_DONT_CARE,
+                                          EGL_NONE};
+
+  egl_idle_display_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+  if (egl_idle_display_ == EGL_NO_DISPLAY) {
+    ETRACE("Failed to get egl display");
+    return false;
+  }
+
+  if (!eglInitialize(egl_idle_display_, NULL, NULL)) {
+    ETRACE("Egl Initialization failed.");
+    return false;
+  }
+
+  if (!eglChooseConfig(egl_idle_display_, config_attribs, &egl_config, 1,
+                       &num_configs)) {
+    ETRACE("Failed to choose a valid EGLConfig.");
+    return false;
+  }
+
+  egl_idle_ctx_ = eglCreateContext(egl_idle_display_, egl_config,
+                                   EGL_NO_CONTEXT, context_attribs);
+
+  if (egl_idle_ctx_ == EGL_NO_CONTEXT) {
+    ETRACE("Failed to create EGL Context.");
+    return false;
+  }
+
+  if (!eglMakeCurrent(egl_idle_display_, EGL_NO_SURFACE, EGL_NO_SURFACE,
+                      egl_idle_ctx_)) {
+    ETRACE("failed to make context current");
+    return false;
+  }
+
+  return true;
+}
+
 bool EGLOffScreenContext::MakeCurrent() {
   saved_egl_display_ = eglGetCurrentDisplay();
   saved_egl_ctx_ = eglGetCurrentContext();
@@ -90,6 +139,14 @@ bool EGLOffScreenContext::MakeCurrent() {
   return true;
 }
 
+bool EGLOffScreenContext::MakeCurrentIdle() {
+  if (egl_idle_display_ == EGL_NO_DISPLAY) {
+    return InitIdleContext();
+  }
+
+  return true;
+}
+
 void EGLOffScreenContext::RestoreState() {
   if (!restore_context_)
     return;
index 4453b53..cd68c8e 100644 (file)
@@ -36,11 +36,16 @@ class EGLOffScreenContext {
 
   bool MakeCurrent();
 
+  bool MakeCurrentIdle();
+
   void RestoreState();
 
  private:
+  bool InitIdleContext();
   EGLDisplay egl_display_;
   EGLContext egl_ctx_;
+  EGLDisplay egl_idle_display_;
+  EGLContext egl_idle_ctx_;
   EGLDisplay saved_egl_display_ = EGL_NO_DISPLAY;
   EGLContext saved_egl_ctx_ = EGL_NO_CONTEXT;
   EGLSurface saved_egl_read_ = EGL_NO_SURFACE;
index 670d199..ba375de 100644 (file)
@@ -128,6 +128,10 @@ bool GLRenderer::MakeCurrent() {
   return context_.MakeCurrent();
 }
 
+bool GLRenderer::MakeCurrentIdle() {
+  return context_.MakeCurrentIdle();
+}
+
 void GLRenderer::InsertFence(uint64_t kms_fence) {
   if (kms_fence > 0) {
     EGLint attrib_list[] = {
index 30653f6..4f98f66 100644 (file)
@@ -42,6 +42,8 @@ class GLRenderer : public Renderer {
 
   bool MakeCurrent() override;
 
+  bool MakeCurrentIdle() override;
+
   void SetExplicitSyncSupport(bool disable_explicit_sync) override;
 
  private:
index d6c2e44..478df33 100644 (file)
@@ -44,6 +44,8 @@ class Renderer {
 
   virtual bool MakeCurrent() = 0;
 
+  virtual bool MakeCurrentIdle() = 0;
+
   virtual void SetExplicitSyncSupport(bool disable_explicit_sync) = 0;
 };
 
index 0af24fb..c445617 100644 (file)
@@ -30,4 +30,11 @@ ScopedRendererState::~ScopedRendererState() {
     renderer_->RestoreState();
 }
 
+ScopedIdleRendererState::ScopedIdleRendererState(Renderer* renderer) {
+  is_valid_ = renderer->MakeCurrentIdle();
+}
+
+ScopedIdleRendererState::~ScopedIdleRendererState() {
+}
+
 }  // namespace hwcomposer
index 6f088b4..a97fe24 100644 (file)
@@ -39,5 +39,22 @@ struct ScopedRendererState {
   bool is_valid_;
 };
 
+struct ScopedIdleRendererState {
+  ScopedIdleRendererState(Renderer* renderer);
+
+  ScopedIdleRendererState(const ScopedRendererState& rhs) = delete;
+
+  ~ScopedIdleRendererState();
+
+  ScopedIdleRendererState& operator=(const ScopedRendererState& rhs) = delete;
+
+  bool IsValid() const {
+    return is_valid_;
+  }
+
+ private:
+  bool is_valid_;
+};
+
 }  // namespace hwcomposer
 #endif  // SCOPED_RENDERER_STATE_H_
index 5394cc0..25602e2 100644 (file)
@@ -691,6 +691,10 @@ bool VKRenderer::MakeCurrent() {
   return true;
 }
 
+bool VKRenderer::MakeCurrentIdle() {
+  return true;
+}
+
 void VKRenderer::SetExplicitSyncSupport(bool disable_explicit_sync) {
 }
 
index 1e5f5b7..09c9636 100644 (file)
@@ -34,6 +34,7 @@ class VKRenderer : public Renderer {
   void InsertFence(uint64_t kms_fence) override;
   void RestoreState() override;
   bool MakeCurrent() override;
+  bool MakeCurrentIdle() override;
   void SetExplicitSyncSupport(bool disable_explicit_sync) override;
 
  private:
index dd116df..f6c48a4 100644 (file)
@@ -215,9 +215,21 @@ bool DisplayPlane::Disable(drmModeAtomicReqPtr property_set) {
   int success =
       drmModeAtomicAddProperty(property_set, id_, crtc_prop_.id, 0) < 0;
   success |= drmModeAtomicAddProperty(property_set, id_, fb_prop_.id, 0) < 0;
+  success |=
+      drmModeAtomicAddProperty(property_set, id_, crtc_x_prop_.id, 0) < 0;
+  success |=
+      drmModeAtomicAddProperty(property_set, id_, crtc_y_prop_.id, 0) < 0;
+  success |=
+      drmModeAtomicAddProperty(property_set, id_, crtc_w_prop_.id, 0) < 0;
+  success |=
+      drmModeAtomicAddProperty(property_set, id_, crtc_h_prop_.id, 0) < 0;
+  success |= drmModeAtomicAddProperty(property_set, id_, src_x_prop_.id, 0) < 0;
+  success |= drmModeAtomicAddProperty(property_set, id_, src_y_prop_.id, 0) < 0;
+  success |= drmModeAtomicAddProperty(property_set, id_, src_w_prop_.id, 0) < 0;
+  success |= drmModeAtomicAddProperty(property_set, id_, src_h_prop_.id, 0) < 0;
 
   if (success) {
-    ETRACE("Failed to disable plane with id: %d", id_);
+    ETRACE("Could not update properties for plane with id: %d", id_);
     return false;
   }
 
index 8b07b2a..3895b2f 100644 (file)
@@ -287,6 +287,17 @@ void DisplayPlaneManager::DisablePipe(drmModeAtomicReqPtr property_set) {
   std::vector<std::unique_ptr<NativeSurface>>().swap(surfaces_);
 }
 
+void DisplayPlaneManager::ReleaseFreeOffScreenTargets() {
+  std::vector<std::unique_ptr<NativeSurface>> surfaces;
+  for (auto &fb : surfaces_) {
+    if (fb->InUse()) {
+      surfaces.emplace_back(fb.release());
+    }
+  }
+
+  surfaces.swap(surfaces_);
+}
+
 bool DisplayPlaneManager::TestCommit(
     const std::vector<OverlayPlane> &commit_planes) const {
   ScopedDrmAtomicReqPtr pset(drmModeAtomicAlloc());
index 9caee89..fc4a785 100644 (file)
@@ -62,6 +62,8 @@ class DisplayPlaneManager {
 
   void EnsureOffScreenTarget(DisplayPlaneState &plane);
 
+  void ReleaseFreeOffScreenTargets();
+
  protected:
   struct OverlayPlane {
    public:
index da2140d..315e0a9 100644 (file)
@@ -63,7 +63,7 @@ DisplayQueue::DisplayQueue(uint32_t gpu_fd, uint32_t crtc_id,
   display_plane_manager_.reset(
       new DisplayPlaneManager(gpu_fd_, crtc_id_, buffer_manager_));
 
-  vblank_handler_.reset(new VblankEventHandler());
+  vblank_handler_.reset(new VblankEventHandler(this));
 
   kms_fence_handler_.reset(new KMSFenceEventHandler(this));
   /* use 0x80 as default brightness for all colors */
@@ -191,7 +191,8 @@ bool DisplayQueue::SetPowerMode(uint32_t power_mode) {
     case kOn:
       needs_modeset_ = true;
       needs_color_correction_ = true;
-      flags_ = DRM_MODE_ATOMIC_ALLOW_MODESET;
+      flags_ = 0;
+      flags_ |= DRM_MODE_ATOMIC_ALLOW_MODESET;
       drmModeConnectorSetProperty(gpu_fd_, connector_, dpms_prop_,
                                   DRM_MODE_DPMS_ON);
 
@@ -252,6 +253,7 @@ void DisplayQueue::GetCachedLayers(const std::vector<OverlayLayer>& layers,
 bool DisplayQueue::QueueUpdate(std::vector<HwcLayer*>& source_layers,
                                int32_t* retire_fence) {
   CTRACE();
+  ScopedIdleStateTracker tracker(idle_tracker_);
   size_t size = source_layers.size();
   size_t previous_size = previous_layers_.size();
   std::vector<OverlayLayer> layers;
@@ -400,6 +402,8 @@ bool DisplayQueue::QueueUpdate(std::vector<HwcLayer*>& source_layers,
     }
   }
 
+  previous_layers_rects_.swap(layers_rects);
+
   return true;
 }
 
@@ -431,10 +435,15 @@ void DisplayQueue::HandleExit() {
   display_plane_manager_->DisablePipe(pset.get());
   drmModeConnectorSetProperty(gpu_fd_, connector_, dpms_prop_,
                               DRM_MODE_DPMS_OFF);
+  buffer_manager_->UnRegisterLayerBuffers(previous_layers_);
   std::vector<OverlayLayer>().swap(previous_layers_);
   previous_plane_state_.clear();
+  std::vector<HwcRect<int>>().swap(previous_layers_rects_);
+  previous_plane_state_.clear();
   compositor_.Reset();
   vblank_handler_->SetPowerMode(kOff);
+  idle_tracker_.preparing_composition_ = false;
+  idle_tracker_.idle_frames_ = 0;
 }
 
 void DisplayQueue::GetDrmObjectProperty(const char* name,
@@ -646,4 +655,86 @@ void DisplayQueue::VSyncControl(bool enabled) {
   vblank_handler_->VSyncControl(enabled);
 }
 
+void DisplayQueue::HandleIdleCase() {
+  idle_tracker_.idle_lock_.lock();
+  if (idle_tracker_.preparing_composition_) {
+    idle_tracker_.idle_lock_.unlock();
+    return;
+  }
+
+  if (previous_plane_state_.size() <= 1) {
+    idle_tracker_.idle_lock_.unlock();
+    return;
+  }
+
+  if (idle_tracker_.idle_frames_ > 5) {
+    idle_tracker_.idle_lock_.unlock();
+    return;
+  }
+
+  if (idle_tracker_.idle_frames_ < 5) {
+    idle_tracker_.idle_frames_++;
+    idle_tracker_.idle_lock_.unlock();
+    return;
+  }
+
+  idle_tracker_.idle_frames_++;
+  DisplayPlaneStateList current_composition_planes;
+  bool render_layers;
+  std::tie(render_layers, current_composition_planes) =
+      display_plane_manager_->ValidateLayers(previous_layers_, false, true);
+
+  if (render_layers) {
+    if (!compositor_.BeginFrame(true)) {
+      ETRACE("Failed to initialize compositor.");
+      idle_tracker_.idle_lock_.unlock();
+      return;
+    }
+
+    // Prepare for final composition.
+    if (!compositor_.DrawIdleState(current_composition_planes, previous_layers_,
+                                   previous_layers_rects_)) {
+      ETRACE("Failed to prepare for the frame composition. ");
+      idle_tracker_.idle_lock_.unlock();
+      return;
+    }
+  }
+
+  // Do the actual commit.
+  ScopedDrmAtomicReqPtr pset(drmModeAtomicAlloc());
+
+  if (!pset) {
+    ETRACE("Failed to allocate property set %d", -ENOMEM);
+    idle_tracker_.idle_lock_.unlock();
+    return;
+  }
+
+  uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
+
+  kms_fence_handler_->EnsureReadyForNextFrame();
+
+  if (!display_plane_manager_->CommitFrame(current_composition_planes,
+                                           pset.get(), flags)) {
+    ETRACE("Failed to Commit layers.");
+    idle_tracker_.idle_lock_.unlock();
+    return;
+  }
+
+  for (NativeSurface* surface : in_flight_surfaces_) {
+    surface->SetInUse(false);
+  }
+
+  std::vector<NativeSurface*>().swap(in_flight_surfaces_);
+
+  for (DisplayPlaneState& plane_state : previous_plane_state_) {
+    if (plane_state.GetCompositionState() ==
+        DisplayPlaneState::State::kRender) {
+      in_flight_surfaces_.emplace_back(plane_state.GetOffScreenTarget());
+    }
+  }
+
+  display_plane_manager_->ReleaseFreeOffScreenTargets();
+  idle_tracker_.idle_lock_.unlock();
+}
+
 }  // namespace hwcomposer
index 5b909c8..7e154d2 100644 (file)
@@ -75,7 +75,34 @@ class DisplayQueue {
 
   void VSyncControl(bool enabled);
 
+  void HandleIdleCase();
+
  private:
+  struct IdleFrameTracker {
+    uint32_t idle_frames_ = 0;
+    SpinLock idle_lock_;
+    bool preparing_composition_ = true;
+  };
+
+  struct ScopedIdleStateTracker {
+    ScopedIdleStateTracker(struct IdleFrameTracker& tracker)
+        : tracker_(tracker) {
+      tracker_.idle_lock_.lock();
+      tracker_.idle_frames_ = 0;
+      tracker_.preparing_composition_ = true;
+      tracker_.idle_lock_.unlock();
+    }
+
+    ~ScopedIdleStateTracker() {
+      tracker_.idle_lock_.lock();
+      tracker_.preparing_composition_ = false;
+      tracker_.idle_lock_.unlock();
+    }
+
+   private:
+    struct IdleFrameTracker& tracker_;
+  };
+
   bool ApplyPendingModeset(drmModeAtomicReqPtr property_set);
   void GetCachedLayers(const std::vector<OverlayLayer>& layers,
                        DisplayPlaneStateList* composition, bool* render_layers);
@@ -126,9 +153,11 @@ class DisplayQueue {
   std::unique_ptr<KMSFenceEventHandler> kms_fence_handler_;
   std::unique_ptr<DisplayPlaneManager> display_plane_manager_;
   std::vector<OverlayLayer> previous_layers_;
+  std::vector<HwcRect<int>> previous_layers_rects_;
   DisplayPlaneStateList previous_plane_state_;
   OverlayBufferManager* buffer_manager_;
   std::vector<NativeSurface*> in_flight_surfaces_;
+  IdleFrameTracker idle_tracker_;
   SpinLock spin_lock_;
 };
 
index cda8a7a..ed5ec23 100644 (file)
 
 #include <memory>
 
+#include "displayqueue.h"
 #include "hwctrace.h"
 
 namespace hwcomposer {
 
 static const int64_t kOneSecondNs = 1 * 1000 * 1000 * 1000;
 
-VblankEventHandler::VblankEventHandler()
+VblankEventHandler::VblankEventHandler(DisplayQueue* queue)
     : HWCThread(-8, "VblankEventHandler"),
       display_(0),
       enabled_(false),
       refresh_(0.0),
       fd_(-1),
       pipe_(-1),
-      last_timestamp_(-1) {
+      last_timestamp_(-1),
+      queue_(queue) {
 }
 
 VblankEventHandler::~VblankEventHandler() {
@@ -47,12 +49,15 @@ void VblankEventHandler::Init(float refresh, int fd, int pipe) {
   refresh_ = refresh;
   fd_ = fd;
   pipe_ = pipe;
+
+  if (!InitWorker()) {
+    ETRACE("Failed to initalize thread for VblankEventHandler. %s",
+           PRINTERROR());
+  }
 }
 
 bool VblankEventHandler::SetPowerMode(uint32_t power_mode) {
-  if (power_mode == kOn && enabled_) {
-    VSyncControl(enabled_);
-  } else {
+  if (power_mode != kOn) {
     Exit();
   }
 
@@ -82,15 +87,6 @@ int VblankEventHandler::VSyncControl(bool enabled) {
 
   ScopedSpinLock lock(spin_lock_);
   enabled_ = enabled;
-  if (enabled_ && callback_) {
-    if (!InitWorker()) {
-      ETRACE("Failed to initalize thread for VblankEventHandler. %s",
-             PRINTERROR());
-    }
-  } else {
-    Exit();
-  }
-
   last_timestamp_ = -1;
 
   return 0;
@@ -124,6 +120,8 @@ void VblankEventHandler::HandleRoutine() {
 
   spin_lock_.unlock();
 
+  queue_->HandleIdleCase();
+
   if (!enabled)
     return;
 
index 6793d7e..831cb19 100644 (file)
 
 namespace hwcomposer {
 
+class DisplayQueue;
+
 class VblankEventHandler : public HWCThread {
  public:
-  VblankEventHandler();
+  VblankEventHandler(DisplayQueue* queue);
   ~VblankEventHandler() override;
 
   void Init(float refresh, int fd, int pipe);
@@ -61,6 +63,7 @@ class VblankEventHandler : public HWCThread {
   int fd_;
   int pipe_;
   int64_t last_timestamp_;
+  DisplayQueue* queue_;
 };
 
 }  // namespace hwcomposer
index 0a4a742..cdc788a 100644 (file)
@@ -91,6 +91,9 @@ bool GrallocBufferHandler::DestroyBuffer(HWCNativeHandle handle) {
 
   if (handle->handle_) {
     gralloc_->unregisterBuffer(gralloc_, handle->handle_);
+  }
+
+  if (handle->buffer_.get()) {
     handle->buffer_.clear();
   }
 
@@ -101,12 +104,12 @@ bool GrallocBufferHandler::DestroyBuffer(HWCNativeHandle handle) {
 }
 #ifdef USE_MINIGBM
 bool GrallocBufferHandler::ImportBuffer(HWCNativeHandle handle, HwcBuffer *bo) {
-  auto gr_handle = (struct cros_gralloc_handle *)handle->handle_;
-  if (!gr_handle) {
+  if (!handle->handle_) {
     ETRACE("could not find gralloc drm handle");
     return false;
   }
 
+  auto gr_handle = (struct cros_gralloc_handle *)handle->handle_;
   memset(bo, 0, sizeof(struct HwcBuffer));
   bo->format = gr_handle->format;
   bo->width = gr_handle->width;
index 69c033e..6aabb35 100644 (file)
@@ -18,6 +18,7 @@
 #define PUBLIC_HWCBUFFER_H_
 
 #include <stdint.h>
+#include <unistd.h>
 
 struct HwcBuffer {
   uint32_t width;
@@ -26,7 +27,7 @@ struct HwcBuffer {
   uint32_t pitches[4];
   uint32_t offsets[4];
   uint32_t gem_handles[4];
-  uint32_t prime_fd;
+  uint32_t prime_fd = 0;
   uint32_t usage;
 };
 
diff --git a/tests/jsonconfigs/multiplelayers_idle.json b/tests/jsonconfigs/multiplelayers_idle.json
new file mode 100644 (file)
index 0000000..95f635f
--- /dev/null
@@ -0,0 +1,71 @@
+{
+  "power_mode":"dozesuspend",
+  "layers_parameters": [
+    {
+      "format": 25,
+      "frame": {
+        "height": 500,
+        "width": 500,
+        "x": 0,
+        "y": 0
+      },
+      "resource_path": "",
+      "source": {
+        "crop": {
+          "height": 1080,
+          "width": 1920,
+          "x": 0,
+          "y": 0
+        },
+        "height": 1080,
+        "width": 1920
+      },
+      "transform": 0,
+      "type": 0
+    },
+    {
+      "format": 25,
+      "frame": {
+        "height": 700,
+        "width": 900,
+        "x": 300,
+        "y": 100
+      },
+      "resource_path": "",
+      "source": {
+        "crop": {
+          "height": 1080,
+          "width": 1920,
+          "x": 0,
+          "y": 0
+        },
+        "height": 1080,
+        "width": 1920
+      },
+      "transform": 0,
+      "type": 3
+    },
+    {
+      "format": 25,
+      "frame": {
+        "height": 900,
+        "width": 1920,
+        "x": 1200,
+        "y": 400
+      },
+      "resource_path": "",
+      "source": {
+        "crop": {
+          "height": 1080,
+          "width": 1920,
+          "x": 0,
+          "y": 0
+        },
+        "height": 1080,
+        "width": 1920
+      },
+      "transform": 0,
+      "type": 3
+    }
+  ]
+}