drm_hwcomposer: add scene flattening

Flattening of a scene is triggered if it doesn't change for a while.
As of now there is a separate thread which triggers flattening if the
scene did not change in last 60 vsyncs.

There are two options for flattening a scene:
* Serial, by using a writeback connector attached to the same crtc as
  the one driving the display. This happens only if possible_clones
  mask reports that the display encoder and writeback encoder could
  work simultaneously.
The steps for achieving this are:
1. Build a commit that enables writeback connector, we don't need to
   build a commit that contains the entire active_composition, just
   set the writeback specific properties a let the kernel duplicate
   the rest of the state.
2. Commit and wait for writeback_fence to fire.
3. Setup a composition with just one plane enabled.
4. Apply the composition if a new one has not been applied meanwhile.

* Concurrent, by comitting the scene to a new unused crtc (state !=
  DRM_MODE_CONNECTED) and getting the result back through a writeback
  connector.
The steps for achieving this are:
1. Copy layers from active composition.
2. Plan layers of copy on the unused crtc. This is realized by using a
   newly created DrmDisplayCompositor object.
3. Commit copy to the unsed crtc and get the result as a drmhwclayer.
4. Setup a composition with just one plane enabled. Re-importing the
   buffers might be needed since we might have been using a different
   dri node.
5. Apply the composition if a new one has not been applied while doing
   the flattening

Signed-off-by: Alexandru Gheorghe <alexandru-cosmin.gheorghe@arm.com>
diff --git a/drmdisplaycompositor.h b/drmdisplaycompositor.h
index bc13d4c..7d46416 100644
--- a/drmdisplaycompositor.h
+++ b/drmdisplaycompositor.h
@@ -21,6 +21,7 @@
 #include "drmdisplaycomposition.h"
 #include "drmframebuffer.h"
 #include "resourcemanager.h"
+#include "vsyncworker.h"
 
 #include <pthread.h>
 #include <memory>
@@ -34,6 +35,10 @@
 // squash a frame that the hw can't display with hw overlays.
 #define DRM_DISPLAY_BUFFERS 3
 
+// If a scene is still for this number of vblanks flatten it to reduce power
+// consumption.
+#define FLATTEN_COUNTDOWN_INIT 60
+
 namespace android {
 
 class DrmDisplayCompositor {
@@ -44,10 +49,12 @@
   int Init(ResourceManager *resource_manager, int display);
 
   std::unique_ptr<DrmDisplayComposition> CreateComposition() const;
+  std::unique_ptr<DrmDisplayComposition> CreateInitializedComposition() const;
   int ApplyComposition(std::unique_ptr<DrmDisplayComposition> composition);
   int TestComposition(DrmDisplayComposition *composition);
   int Composite();
   void Dump(std::ostringstream *out) const;
+  void Vsync(int display, int64_t timestamp);
 
   std::tuple<uint32_t, uint32_t, int> GetActiveModeResolution();
 
@@ -66,16 +73,26 @@
   static const int kAcquireWaitTries = 5;
   static const int kAcquireWaitTimeoutMs = 100;
 
-  int PrepareFramebuffer(DrmFramebuffer &fb,
-                         DrmDisplayComposition *display_comp);
-  int PrepareFrame(DrmDisplayComposition *display_comp);
-  int CommitFrame(DrmDisplayComposition *display_comp, bool test_only);
+  int CommitFrame(DrmDisplayComposition *display_comp, bool test_only,
+                  DrmConnector *writeback_conn = NULL,
+                  DrmHwcBuffer *writeback_buffer = NULL);
+  int SetupWritebackCommit(drmModeAtomicReqPtr pset, uint32_t crtc_id,
+                           DrmConnector *writeback_conn,
+                           DrmHwcBuffer *writeback_buffer);
   int ApplyDpms(DrmDisplayComposition *display_comp);
   int DisablePlanes(DrmDisplayComposition *display_comp);
 
   void ClearDisplay();
   void ApplyFrame(std::unique_ptr<DrmDisplayComposition> composition,
-                  int status);
+                  int status, bool writeback = false);
+  int FlattenActiveComposition();
+  int FlattenSerial(DrmConnector *writeback_conn);
+  int FlattenConcurrent(DrmConnector *writeback_conn);
+  int FlattenOnDisplay(std::unique_ptr<DrmDisplayComposition> &src,
+                       DrmConnector *writeback_conn, DrmMode &src_mode,
+                       DrmHwcLayer *writeback_layer);
+
+  bool CountdownExpired() const;
 
   std::tuple<int, uint32_t> CreateModeBlob(const DrmMode &mode);
 
@@ -100,6 +117,10 @@
   // we need to reset them on every Dump() call.
   mutable uint64_t dump_frames_composited_;
   mutable uint64_t dump_last_timestamp_ns_;
+  VSyncWorker vsync_worker_;
+  int64_t flatten_countdown_;
+  std::unique_ptr<Planner> planner_;
+  int writeback_fence_;
 };
 }