Merge "sdm: Add support for inline rotator"
diff --git a/sdm/include/private/color_params.h b/sdm/include/private/color_params.h
index 0a53832..08895ee 100644
--- a/sdm/include/private/color_params.h
+++ b/sdm/include/private/color_params.h
@@ -578,9 +578,13 @@
   // from ColorManager, containing all physical features to be programmed and also compute
   // metadata/populate into T.
   inline DisplayError AddFeature(uint32_t feature_id, PPFeatureInfo *feature) {
-    if (feature_id < kMaxNumPPFeatures)
+    if (feature_id < kMaxNumPPFeatures) {
+      if (feature_[feature_id]) {
+        delete feature_[feature_id];
+        feature_[feature_id] = NULL;
+      }
       feature_[feature_id] = feature;
-
+    }
     return kErrorNone;
   }
 
diff --git a/sdm/include/utils/sync_task.h b/sdm/include/utils/sync_task.h
new file mode 100644
index 0000000..725460a
--- /dev/null
+++ b/sdm/include/utils/sync_task.h
@@ -0,0 +1,143 @@
+/*
+* Copyright (c) 2017, 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.
+*/
+
+#ifndef __SYNC_TASK_H__
+#define __SYNC_TASK_H__
+
+#include <thread>
+#include <mutex>
+#include <condition_variable>   // NOLINT
+
+namespace sdm {
+
+template <class TaskCode>
+class SyncTask {
+ public:
+  // This class need to be overridden by caller to pass on a task context.
+  class TaskContext {
+   public:
+    virtual ~TaskContext() { }
+  };
+
+  // Methods to callback into caller for command codes executions in worker thread.
+  class TaskHandler {
+   public:
+    virtual ~TaskHandler() { }
+    virtual void OnTask(const TaskCode &task_code, TaskContext *task_context) = 0;
+  };
+
+  explicit SyncTask(TaskHandler &task_handler) : task_handler_(task_handler) {
+    // Block caller thread until worker thread has started and ready to listen to task commands.
+    // Worker thread will signal as soon as callback is received in the new thread.
+    std::unique_lock<std::mutex> caller_lock(caller_mutex_);
+    std::thread worker_thread(SyncTaskThread, this);
+    worker_thread_.swap(worker_thread);
+    caller_cv_.wait(caller_lock);
+  }
+
+  ~SyncTask() {
+    // Task code does not matter here.
+    PerformTask(task_code_, nullptr, true);
+    worker_thread_.join();
+  }
+
+  void PerformTask(const TaskCode &task_code, TaskContext *task_context) {
+    PerformTask(task_code, task_context, false);
+  }
+
+ private:
+  void PerformTask(const TaskCode &task_code, TaskContext *task_context, bool terminate) {
+    std::unique_lock<std::mutex> caller_lock(caller_mutex_);
+
+    // New scope to limit scope of worker lock to this block.
+    {
+      // Set task command code and notify worker thread.
+      std::unique_lock<std::mutex> worker_lock(worker_mutex_);
+      task_code_ = task_code;
+      task_context_ = task_context;
+      worker_thread_exit_ = terminate;
+      pending_code_ = true;
+      worker_cv_.notify_one();
+    }
+
+    // Wait for worker thread to finish and signal.
+    caller_cv_.wait(caller_lock);
+  }
+
+  static void SyncTaskThread(SyncTask *sync_task) {
+    if (sync_task) {
+      sync_task->OnThreadCallback();
+    }
+  }
+
+  void OnThreadCallback() {
+    // Acquire worker lock and start waiting for events.
+    // Wait must start before caller thread can post events, otherwise posted events will be lost.
+    // Caller thread will be blocked until worker thread signals readiness.
+    std::unique_lock<std::mutex> worker_lock(worker_mutex_);
+
+    // New scope to limit scope of caller lock to this block.
+    {
+      // Signal caller thread that worker thread is ready to listen to events.
+      std::unique_lock<std::mutex> caller_lock(caller_mutex_);
+      caller_cv_.notify_one();
+    }
+
+    while (!worker_thread_exit_) {
+      // Add predicate to handle spurious interrupts.
+      // Wait for caller thread to signal new command codes.
+      worker_cv_.wait(worker_lock, [this] { return pending_code_; });
+
+      // Call task handler which is implemented by the caller.
+      if (!worker_thread_exit_) {
+        task_handler_.OnTask(task_code_, task_context_);
+      }
+
+      pending_code_ = false;
+      // Notify completion of current task to the caller thread which is blocked.
+      std::unique_lock<std::mutex> caller_lock(caller_mutex_);
+      caller_cv_.notify_one();
+    }
+  }
+
+  TaskHandler &task_handler_;
+  TaskCode task_code_;
+  TaskContext *task_context_ = nullptr;
+  std::thread worker_thread_;
+  std::mutex caller_mutex_;
+  std::mutex worker_mutex_;
+  std::condition_variable caller_cv_;
+  std::condition_variable worker_cv_;
+  bool worker_thread_exit_ = false;
+  bool pending_code_ = false;
+};
+
+}  // namespace sdm
+
+#endif  // __SYNC_TASK_H__
diff --git a/sdm/libs/core/hw_interface.cpp b/sdm/libs/core/hw_interface.cpp
index a27c5f8..a7bcabd 100644
--- a/sdm/libs/core/hw_interface.cpp
+++ b/sdm/libs/core/hw_interface.cpp
@@ -70,7 +70,7 @@
       break;
     case kVirtual:
       if (driver_type == DriverType::FB) {
-        hw = new HWVirtual(buffer_sync_handler,hw_info_intf);
+        hw = new HWVirtual(buffer_sync_handler, hw_info_intf);
       } else {
 #ifdef COMPILE_DRM
         hw = new HWVirtualDRM(buffer_sync_handler, buffer_allocator, hw_info_intf);
diff --git a/sdm/libs/utils/Android.mk b/sdm/libs/utils/Android.mk
index fe89104..09e1414 100644
--- a/sdm/libs/utils/Android.mk
+++ b/sdm/libs/utils/Android.mk
@@ -25,6 +25,7 @@
                                  $(SDM_HEADER_PATH)/utils/locker.h \
                                  $(SDM_HEADER_PATH)/utils/rect.h \
                                  $(SDM_HEADER_PATH)/utils/sys.h \
+                                 $(SDM_HEADER_PATH)/utils/sync_task.h \
                                  $(SDM_HEADER_PATH)/utils/utils.h \
                                  $(SDM_HEADER_PATH)/utils/factory.h