Merge "gralloc: Add UBWC support for Camera"
diff --git a/displayengine/include/utils/locker.h b/displayengine/include/utils/locker.h
index 2c1ef9a..549a282 100644
--- a/displayengine/include/utils/locker.h
+++ b/displayengine/include/utils/locker.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014 - 2015, 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:
@@ -28,7 +28,11 @@
 #include <stdint.h>
 #include <pthread.h>
 
-#define SCOPE_LOCK(locker) Locker::ScopeLock scopeLock(locker)
+#define SCOPE_LOCK(locker) Locker::ScopeLock lock(locker)
+#define SEQUENCE_ENTRY_SCOPE_LOCK(locker) Locker::SequenceEntryScopeLock lock(locker)
+#define SEQUENCE_EXIT_SCOPE_LOCK(locker) Locker::SequenceExitScopeLock lock(locker)
+#define SEQUENCE_WAIT_SCOPE_LOCK(locker) Locker::SequenceWaitScopeLock lock(locker)
+#define SEQUENCE_CANCEL_SCOPE_LOCK(locker) Locker::SequenceCancelScopeLock lock(locker)
 
 namespace sde {
 
@@ -48,7 +52,78 @@
     Locker &locker_;
   };
 
-  Locker() {
+  class SequenceEntryScopeLock {
+   public:
+    explicit SequenceEntryScopeLock(Locker& locker) : locker_(locker) {
+      locker_.Lock();
+      locker_.sequence_wait_ = 1;
+    }
+
+    ~SequenceEntryScopeLock() {
+      locker_.Unlock();
+    }
+
+   private:
+    Locker &locker_;
+  };
+
+  class SequenceExitScopeLock {
+   public:
+    explicit SequenceExitScopeLock(Locker& locker) : locker_(locker) {
+      locker_.Lock();
+      locker_.sequence_wait_ = 0;
+    }
+
+    ~SequenceExitScopeLock() {
+      locker_.Broadcast();
+      locker_.Unlock();
+    }
+
+   private:
+    Locker &locker_;
+  };
+
+  class SequenceWaitScopeLock {
+   public:
+    explicit SequenceWaitScopeLock(Locker& locker) : locker_(locker), error_(false) {
+      locker_.Lock();
+
+      if (locker_.sequence_wait_ == 1) {
+        locker_.Wait();
+        error_ = (locker_.sequence_wait_ == -1);
+      }
+    }
+
+    ~SequenceWaitScopeLock() {
+      locker_.Unlock();
+    }
+
+    bool IsError() {
+      return error_;
+    }
+
+   private:
+    Locker &locker_;
+    bool error_;
+  };
+
+  class SequenceCancelScopeLock {
+   public:
+    explicit SequenceCancelScopeLock(Locker& locker) : locker_(locker) {
+      locker_.Lock();
+      locker_.sequence_wait_ = -1;
+    }
+
+    ~SequenceCancelScopeLock() {
+      locker_.Broadcast();
+      locker_.Unlock();
+    }
+
+   private:
+    Locker &locker_;
+  };
+
+  Locker() : sequence_wait_(0) {
     pthread_mutex_init(&mutex_, 0);
     pthread_cond_init(&condition_, 0);
   }
@@ -63,7 +138,7 @@
   void Signal() { pthread_cond_signal(&condition_); }
   void Broadcast() { pthread_cond_broadcast(&condition_); }
   void Wait() { pthread_cond_wait(&condition_, &mutex_); }
-  int WaitFinite(long int ms) {
+  int WaitFinite(int ms) {
     struct timespec ts;
     struct timeval tv;
     gettimeofday(&tv, NULL);
@@ -77,6 +152,11 @@
  private:
   pthread_mutex_t mutex_;
   pthread_cond_t condition_;
+  int sequence_wait_;   // This flag is set to 1 on sequence entry, 0 on exit, and -1 on cancel.
+                        // Some routines will wait for sequence of function calls to finish
+                        // so that capturing a transitionary snapshot of context is prevented.
+                        // If flag is set to -1, these routines will exit without doing any
+                        // further processing.
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/core/comp_manager.cpp b/displayengine/libs/core/comp_manager.cpp
index c759ebb..7e888ee 100644
--- a/displayengine/libs/core/comp_manager.cpp
+++ b/displayengine/libs/core/comp_manager.cpp
@@ -125,9 +125,11 @@
   SET_BIT(registered_displays_, type);
   display_comp_ctx->display_type = type;
   *display_ctx = display_comp_ctx;
-  // New display device has been added, so move the composition mode to safe mode until unless
+  // New non-primary display device has been added, so move the composition mode to safe mode until
   // resources for the added display is configured properly.
-  safe_mode_ = true;
+  if (type != kPrimary) {
+    safe_mode_ = true;
+  }
 
   DLOGV_IF(kTagCompManager, "registered display bit mask 0x%x, configured display bit mask 0x%x, " \
            "display type %d", registered_displays_, configured_displays_,
diff --git a/displayengine/libs/core/hw_framebuffer.cpp b/displayengine/libs/core/hw_framebuffer.cpp
index 306857b..5d1f725 100644
--- a/displayengine/libs/core/hw_framebuffer.cpp
+++ b/displayengine/libs/core/hw_framebuffer.cpp
@@ -172,6 +172,10 @@
     goto CleanupOnError;
   }
 
+  // Disable HPD at start if HDMI is external, it will be enabled later when the display powers on
+  // This helps for framework reboot or adb shell stop/start
+  EnableHotPlugDetection(0);
+
   return kErrorNone;
 
 CleanupOnError:
diff --git a/displayengine/libs/hwc/hwc_display.cpp b/displayengine/libs/hwc/hwc_display.cpp
index d8c8a64..452bff1 100644
--- a/displayengine/libs/hwc/hwc_display.cpp
+++ b/displayengine/libs/hwc/hwc_display.cpp
@@ -31,6 +31,7 @@
 #include <gralloc_priv.h>
 #include <utils/constants.h>
 #include <qdMetaData.h>
+#include <sync/sync.h>
 
 #include "hwc_display.h"
 #include "hwc_debugger.h"
@@ -42,7 +43,8 @@
 HWCDisplay::HWCDisplay(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, DisplayType type,
                        int id)
   : core_intf_(core_intf), hwc_procs_(hwc_procs), type_(type), id_(id), display_intf_(NULL),
-    flush_(false), output_buffer_(NULL) {
+    flush_(false), output_buffer_(NULL), dump_frame_count_(0), dump_frame_index_(0),
+    dump_input_layers_(false) {
 }
 
 int HWCDisplay::Init() {
@@ -198,6 +200,14 @@
   return 0;
 }
 
+void HWCDisplay::SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type) {
+  dump_frame_count_ = count;
+  dump_frame_index_ = 0;
+  dump_input_layers_ = ((bit_mask_layer_type & (1 << INPUT_LAYER_DUMP)) != 0);
+
+  DLOGI("num_frame_dump %d, input_layer_dump_enable %d", dump_frame_count_, dump_input_layers_);
+}
+
 DisplayError HWCDisplay::VSync(const DisplayEventVSync &vsync) {
   if (*hwc_procs_) {
     (*hwc_procs_)->vsync(*hwc_procs_, id_, vsync.timestamp);
@@ -406,6 +416,8 @@
 
   size_t num_hw_layers = content_list->numHwLayers;
 
+  DumpInputBuffers(content_list);
+
   if (!flush_) {
     for (size_t i = 0; i < num_hw_layers; i++) {
       hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
@@ -431,13 +443,18 @@
     }
   }
 
+  return status;
+}
+
+int HWCDisplay::PostCommitLayerStack(hwc_display_contents_1_t *content_list) {
+  size_t num_hw_layers = content_list->numHwLayers;
+  int status = 0;
+
   if (flush_) {
     DisplayError error = display_intf_->Flush();
     if (error != kErrorNone) {
       DLOGE("Flush failed. Error = %d", error);
     }
-
-    flush_ = false;
   }
 
   for (size_t i = 0; i < num_hw_layers; i++) {
@@ -445,7 +462,7 @@
     Layer &layer = layer_stack_.layers[i];
     LayerBuffer *layer_buffer = layer_stack_.layers[i].input_buffer;
 
-    if ((status == 0) && (layer.composition == kCompositionSDE ||
+    if (!flush_ && (layer.composition == kCompositionSDE ||
                          layer.composition == kCompositionGPUTarget)) {
       hwc_layer.releaseFenceFd = layer_buffer->release_fence_fd;
     }
@@ -455,9 +472,21 @@
     }
   }
 
+  if (!flush_) {
+    content_list->retireFenceFd = layer_stack_.retire_fence_fd;
+
+    if (dump_frame_count_) {
+      dump_frame_count_--;
+      dump_frame_index_++;
+    }
+  }
+
+  flush_ = false;
+
   return status;
 }
 
+
 bool HWCDisplay::NeedsFrameBufferRefresh(hwc_display_contents_1_t *content_list) {
   uint32_t layer_count = layer_stack_.layer_count;
 
@@ -587,5 +616,119 @@
   return format;
 }
 
+void HWCDisplay::DumpInputBuffers(hwc_display_contents_1_t *content_list) {
+  size_t num_hw_layers = content_list->numHwLayers;
+  char dir_path[PATH_MAX];
+
+  if (!dump_frame_count_ || flush_ || !dump_input_layers_) {
+    return;
+  }
+
+  snprintf(dir_path, sizeof(dir_path), "/data/misc/display/frame_dump_%s", GetDisplayString());
+
+  if (mkdir(dir_path, 0777) != 0 && errno != EEXIST) {
+    DLOGW("Failed to create %s directory errno = %d, desc = %s", dir_path, errno, strerror(errno));
+    return;
+  }
+
+  // if directory exists already, need to explicitly change the permission.
+  if (errno == EEXIST && chmod(dir_path, 0777) != 0) {
+    DLOGW("Failed to change permissions on %s directory", dir_path);
+    return;
+  }
+
+  for (uint32_t i = 0; i < num_hw_layers; i++) {
+    hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
+    const private_handle_t *pvt_handle = static_cast<const private_handle_t *>(hwc_layer.handle);
+
+    if (hwc_layer.acquireFenceFd >= 0) {
+      int error = sync_wait(hwc_layer.acquireFenceFd, 1000);
+      if (error < 0) {
+        DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
+        return;
+      }
+    }
+
+    if (pvt_handle && pvt_handle->base) {
+      char dump_file_name[PATH_MAX];
+      size_t result = 0;
+
+      snprintf(dump_file_name, sizeof(dump_file_name), "%s/input_layer%d_%dx%d_%s_frame%d.raw",
+               dir_path, i, pvt_handle->width, pvt_handle->height,
+               GetHALPixelFormatString(pvt_handle->format), dump_frame_index_);
+
+      FILE* fp = fopen(dump_file_name, "w+");
+      if (fp) {
+        result = fwrite(reinterpret_cast<void *>(pvt_handle->base), pvt_handle->size, 1, fp);
+        fclose(fp);
+      }
+
+      DLOGI("Frame Dump %s: is %s", dump_file_name, result ? "Successful" : "Failed");
+    }
+  }
+}
+
+const char *HWCDisplay::GetHALPixelFormatString(int format) {
+  switch (format) {
+  case HAL_PIXEL_FORMAT_RGBA_8888:
+    return "RGBA_8888";
+  case HAL_PIXEL_FORMAT_RGBX_8888:
+    return "RGBX_8888";
+  case HAL_PIXEL_FORMAT_RGB_888:
+    return "RGB_888";
+  case HAL_PIXEL_FORMAT_RGB_565:
+    return "RGB_565";
+  case HAL_PIXEL_FORMAT_BGRA_8888:
+    return "BGRA_8888";
+  case HAL_PIXEL_FORMAT_RGBA_5551:
+    return "RGBA_5551";
+  case HAL_PIXEL_FORMAT_RGBA_4444:
+    return "RGBA_4444";
+  case HAL_PIXEL_FORMAT_YV12:
+    return "YV12";
+  case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+    return "YCbCr_422_SP_NV16";
+  case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+    return "YCrCb_420_SP_NV21";
+  case HAL_PIXEL_FORMAT_YCbCr_422_I:
+    return "YCbCr_422_I_YUY2";
+  case HAL_PIXEL_FORMAT_YCrCb_422_I:
+    return "YCrCb_422_I_YVYU";
+  case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
+    return "NV12_ENCODEABLE";
+  case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
+    return "YCbCr_420_SP_TILED_TILE_4x2";
+  case HAL_PIXEL_FORMAT_YCbCr_420_SP:
+    return "YCbCr_420_SP";
+  case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO:
+    return "YCrCb_420_SP_ADRENO";
+  case HAL_PIXEL_FORMAT_YCrCb_422_SP:
+    return "YCrCb_422_SP";
+  case HAL_PIXEL_FORMAT_R_8:
+    return "R_8";
+  case HAL_PIXEL_FORMAT_RG_88:
+    return "RG_88";
+  case HAL_PIXEL_FORMAT_INTERLACE:
+    return "INTERLACE";
+  case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+    return "YCbCr_420_SP_VENUS";
+  default:
+    return "Unknown pixel format";
+  }
+}
+
+const char *HWCDisplay::GetDisplayString() {
+  switch (type_) {
+  case kPrimary:
+    return "primary";
+  case kHDMI:
+    return "hdmi";
+  case kVirtual:
+    return "virtual";
+  default:
+    return "invalid";
+  }
+}
+
 }  // namespace sde
 
diff --git a/displayengine/libs/hwc/hwc_display.h b/displayengine/libs/hwc/hwc_display.h
index 9956504..3934078 100644
--- a/displayengine/libs/hwc/hwc_display.h
+++ b/displayengine/libs/hwc/hwc_display.h
@@ -44,6 +44,7 @@
   virtual int SetActiveConfig(int index);
   virtual void SetIdleTimeoutMs(uint32_t timeout_ms);
   virtual int SetActiveConfig(hwc_display_contents_1_t *content_list);
+  virtual void SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type);
 
  protected:
   // Maximum number of layers supported by display engine.
@@ -82,6 +83,7 @@
   virtual int AllocateLayerStack(hwc_display_contents_1_t *content_list);
   virtual int PrepareLayerStack(hwc_display_contents_1_t *content_list);
   virtual int CommitLayerStack(hwc_display_contents_1_t *content_list);
+  virtual int PostCommitLayerStack(hwc_display_contents_1_t *content_list);
   bool NeedsFrameBufferRefresh(hwc_display_contents_1_t *content_list);
   void CacheLayerStackInfo(hwc_display_contents_1_t *content_list);
   inline void SetRect(const hwc_rect_t &source, LayerRect *target);
@@ -91,6 +93,14 @@
   inline void SetBlending(const int32_t &source, LayerBlending *target);
   int SetFormat(const int32_t &source, const int flags, LayerBufferFormat *target);
   LayerBufferFormat GetSDEFormat(const int32_t &source, const int flags);
+  void DumpInputBuffers(hwc_display_contents_1_t *content_list);
+  const char *GetHALPixelFormatString(int format);
+  const char *GetDisplayString();
+
+  enum {
+    INPUT_LAYER_DUMP,
+    OUTPUT_LAYER_DUMP,
+  };
 
   CoreInterface *core_intf_;
   hwc_procs_t const **hwc_procs_;
@@ -102,6 +112,9 @@
   LayerStackCache layer_stack_cache_;
   bool flush_;
   LayerBuffer *output_buffer_;
+  uint32_t dump_frame_count_;
+  uint32_t dump_frame_index_;
+  bool dump_input_layers_;
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/hwc/hwc_display_external.cpp b/displayengine/libs/hwc/hwc_display_external.cpp
index da5ea4d..2758e3a 100644
--- a/displayengine/libs/hwc/hwc_display_external.cpp
+++ b/displayengine/libs/hwc/hwc_display_external.cpp
@@ -64,7 +64,10 @@
     return status;
   }
 
-  content_list->retireFenceFd = layer_stack_.retire_fence_fd;
+  status = HWCDisplay::PostCommitLayerStack(content_list);
+  if (status) {
+    return status;
+  }
 
   return 0;
 }
diff --git a/displayengine/libs/hwc/hwc_display_primary.cpp b/displayengine/libs/hwc/hwc_display_primary.cpp
index aeb56f4..6dbb723 100644
--- a/displayengine/libs/hwc/hwc_display_primary.cpp
+++ b/displayengine/libs/hwc/hwc_display_primary.cpp
@@ -64,7 +64,10 @@
     return status;
   }
 
-  content_list->retireFenceFd = layer_stack_.retire_fence_fd;
+  status = HWCDisplay::PostCommitLayerStack(content_list);
+  if (status) {
+    return status;
+  }
 
   return 0;
 }
diff --git a/displayengine/libs/hwc/hwc_display_virtual.cpp b/displayengine/libs/hwc/hwc_display_virtual.cpp
index a6d0f63..9601e63 100644
--- a/displayengine/libs/hwc/hwc_display_virtual.cpp
+++ b/displayengine/libs/hwc/hwc_display_virtual.cpp
@@ -29,6 +29,7 @@
 
 #include <utils/constants.h>
 #include <gralloc_priv.h>
+#include <sync/sync.h>
 
 #include "hwc_display_virtual.h"
 #include "hwc_debugger.h"
@@ -38,7 +39,8 @@
 namespace sde {
 
 HWCDisplayVirtual::HWCDisplayVirtual(CoreInterface *core_intf, hwc_procs_t const **hwc_procs)
-  : HWCDisplay(core_intf, hwc_procs, kVirtual, HWC_DISPLAY_VIRTUAL) {
+  : HWCDisplay(core_intf, hwc_procs, kVirtual, HWC_DISPLAY_VIRTUAL),
+    dump_output_layer_(false) {
 }
 
 int HWCDisplayVirtual::Init() {
@@ -95,13 +97,18 @@
     return status;
   }
 
+  DumpOutputBuffer(content_list);
+
+  status = HWCDisplay::PostCommitLayerStack(content_list);
+  if (status) {
+    return status;
+  }
+
   if (content_list->outbufAcquireFenceFd >= 0) {
     close(content_list->outbufAcquireFenceFd);
     content_list->outbufAcquireFenceFd = -1;
   }
 
-  content_list->retireFenceFd = layer_stack_.retire_fence_fd;
-
   return 0;
 }
 
@@ -173,5 +180,59 @@
   return status;
 }
 
+void HWCDisplayVirtual::DumpOutputBuffer(hwc_display_contents_1_t *content_list) {
+  const private_handle_t *output_handle = (const private_handle_t *)(content_list->outbuf);
+  char dir_path[PATH_MAX];
+
+  if (!dump_frame_count_ || flush_ || !dump_output_layer_) {
+    return;
+  }
+
+  snprintf(dir_path, sizeof(dir_path), "/data/misc/display/frame_dump_%s", GetDisplayString());
+
+  if (mkdir(dir_path, 777) != 0 && errno != EEXIST) {
+    DLOGW("Failed to create %s directory errno = %d, desc = %s", dir_path, errno, strerror(errno));
+    return;
+  }
+
+  // if directory exists already, need to explicitly change the permission.
+  if (errno == EEXIST && chmod(dir_path, 0777) != 0) {
+    DLOGW("Failed to change permissions on %s directory", dir_path);
+    return;
+  }
+
+  if (output_handle && output_handle->base) {
+    char dump_file_name[PATH_MAX];
+    size_t result = 0;
+
+    if (content_list->outbufAcquireFenceFd >= 0) {
+      int error = sync_wait(content_list->outbufAcquireFenceFd, 1000);
+      if (error < 0) {
+        DLOGW("sync_wait error errno = %d, desc = %s", errno,  strerror(errno));
+        return;
+      }
+    }
+
+    snprintf(dump_file_name, sizeof(dump_file_name), "%s/output_layer_%dx%d_%s_frame%d.raw",
+             dir_path, output_handle->width, output_handle->height,
+             GetHALPixelFormatString(output_handle->format), dump_frame_index_);
+
+    FILE* fp = fopen(dump_file_name, "w+");
+    if (fp) {
+      result = fwrite(reinterpret_cast<void *>(output_handle->base), output_handle->size, 1, fp);
+      fclose(fp);
+    }
+
+    DLOGI("Frame Dump of %s is %s", dump_file_name, result ? "Successful" : "Failed");
+  }
+}
+
+void HWCDisplayVirtual::SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type) {
+  HWCDisplay::SetFrameDumpConfig(count, bit_mask_layer_type);
+  dump_output_layer_ = ((bit_mask_layer_type & (1 << OUTPUT_LAYER_DUMP)) != 0);
+
+  DLOGI("output_layer_dump_enable %d", dump_output_layer_);
+}
+
 }  // namespace sde
 
diff --git a/displayengine/libs/hwc/hwc_display_virtual.h b/displayengine/libs/hwc/hwc_display_virtual.h
index 775852a..7ac7c22 100644
--- a/displayengine/libs/hwc/hwc_display_virtual.h
+++ b/displayengine/libs/hwc/hwc_display_virtual.h
@@ -37,9 +37,13 @@
   virtual int Prepare(hwc_display_contents_1_t *content_list);
   virtual int Commit(hwc_display_contents_1_t *content_list);
   virtual int SetActiveConfig(hwc_display_contents_1_t *content_list);
+  virtual void SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type);
 
  private:
   int SetOutputBuffer(hwc_display_contents_1_t *content_list);
+  void DumpOutputBuffer(hwc_display_contents_1_t *content_list);
+
+  bool dump_output_layer_;
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/hwc/hwc_session.cpp b/displayengine/libs/hwc/hwc_session.cpp
index 0b2f484..3bc4fd1 100644
--- a/displayengine/libs/hwc/hwc_session.cpp
+++ b/displayengine/libs/hwc/hwc_session.cpp
@@ -210,7 +210,7 @@
                         hwc_display_contents_1_t **displays) {
   DTRACE_SCOPED();
 
-  SCOPE_LOCK(locker_);
+  SEQUENCE_ENTRY_SCOPE_LOCK(locker_);
 
   if (!device || !displays) {
     return -EINVAL;
@@ -254,7 +254,7 @@
                     hwc_display_contents_1_t **displays) {
   DTRACE_SCOPED();
 
-  SCOPE_LOCK(locker_);
+  SEQUENCE_EXIT_SCOPE_LOCK(locker_);
 
   if (!device || !displays) {
     return -EINVAL;
@@ -289,7 +289,7 @@
 }
 
 int HWCSession::EventControl(hwc_composer_device_1 *device, int disp, int event, int enable) {
-  SCOPE_LOCK(locker_);
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
 
   if (!device) {
     return -EINVAL;
@@ -317,7 +317,7 @@
 }
 
 int HWCSession::SetPowerMode(hwc_composer_device_1 *device, int disp, int mode) {
-  SCOPE_LOCK(locker_);
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
 
   if (!device) {
     return -EINVAL;
@@ -348,6 +348,8 @@
 }
 
 int HWCSession::Query(hwc_composer_device_1 *device, int param, int *value) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   if (!device || !value) {
     return -EINVAL;
   }
@@ -365,7 +367,7 @@
 }
 
 void HWCSession::Dump(hwc_composer_device_1 *device, char *buffer, int length) {
-  SCOPE_LOCK(locker_);
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
 
   if (!device || !buffer || !length) {
     return;
@@ -376,6 +378,8 @@
 
 int HWCSession::GetDisplayConfigs(hwc_composer_device_1 *device, int disp, uint32_t *configs,
                                   size_t *num_configs) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   if (!device || !configs || !num_configs) {
     return -EINVAL;
   }
@@ -406,6 +410,8 @@
 
 int HWCSession::GetDisplayAttributes(hwc_composer_device_1 *device, int disp, uint32_t config,
                                      const uint32_t *attributes, int32_t *values) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   if (!device || !attributes || !values) {
     return -EINVAL;
   }
@@ -435,6 +441,8 @@
 }
 
 int HWCSession::GetActiveConfig(hwc_composer_device_1 *device, int disp) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   if (!device) {
     return -1;
   }
@@ -464,6 +472,8 @@
 }
 
 int HWCSession::SetActiveConfig(hwc_composer_device_1 *device, int disp, int index) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   if (!device) {
     return -EINVAL;
   }
@@ -549,6 +559,8 @@
 
 android::status_t HWCSession::notifyCallback(uint32_t command, const android::Parcel *input_parcel,
                                              android::Parcel */*output_parcel*/) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   switch (command) {
   case qService::IQService::DYNAMIC_DEBUG:
     DynamicDebug(input_parcel);
@@ -564,6 +576,11 @@
       display_primary_->SetIdleTimeoutMs(timeout);
     }
     break;
+
+  case qService::IQService::SET_FRAME_DUMP_CONFIG:
+    SetFrameDumpConfig(input_parcel);
+    break;
+
   default:
     DLOGW("QService command = %d is not supported", command);
     return -EINVAL;
@@ -572,6 +589,30 @@
   return 0;
 }
 
+void HWCSession::SetFrameDumpConfig(const android::Parcel *input_parcel) {
+  uint32_t frame_dump_count = UINT32(input_parcel->readInt32());
+  uint32_t bit_mask_display_type = UINT32(input_parcel->readInt32());
+  uint32_t bit_mask_layer_type = UINT32(input_parcel->readInt32());
+
+  if (bit_mask_display_type & (1 << qService::IQService::DUMP_PRIMARY_DISPLAY)) {
+    if (display_primary_) {
+      display_primary_->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
+    }
+  }
+
+  if (bit_mask_display_type & (1 << qService::IQService::DUMP_HDMI_DISPLAY)) {
+    if (display_external_) {
+      display_external_->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
+    }
+  }
+
+  if (bit_mask_display_type & (1 << qService::IQService::DUMP_VIRTUAL_DISPLAY)) {
+    if (display_virtual_) {
+      display_virtual_->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
+    }
+  }
+}
+
 void HWCSession::DynamicDebug(const android::Parcel *input_parcel) {
   int type = input_parcel->readInt32();
   bool enable = (input_parcel->readInt32() > 0);
@@ -666,7 +707,7 @@
   }
 
   if (connected) {
-    SCOPE_LOCK(locker_);
+    SEQUENCE_WAIT_SCOPE_LOCK(locker_);
     if (display_external_) {
      DLOGE("HDMI already connected");
      return -1;
@@ -683,7 +724,7 @@
       return -1;
     }
   } else {
-    SCOPE_LOCK(locker_);
+    SEQUENCE_WAIT_SCOPE_LOCK(locker_);
     if (!display_external_) {
      DLOGE("HDMI not connected");
      return -1;
diff --git a/displayengine/libs/hwc/hwc_session.h b/displayengine/libs/hwc/hwc_session.h
index 2a7fe62..4b8c8ce 100644
--- a/displayengine/libs/hwc/hwc_session.h
+++ b/displayengine/libs/hwc/hwc_session.h
@@ -84,6 +84,7 @@
   virtual android::status_t notifyCallback(uint32_t command, const android::Parcel *input_parcel,
                                            android::Parcel *output_parcel);
   void DynamicDebug(const android::Parcel *input_parcel);
+  void SetFrameDumpConfig(const android::Parcel *input_parcel);
 
   static Locker locker_;
   CoreInterface *core_intf_;
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index ee5b3b7..f1edf5d 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -131,6 +131,21 @@
     return renderArea;
 }
 
+bool CopyBit::isLayerChanging(hwc_display_contents_1_t *list, int k) {
+    if((mLayerCache.hnd[k] != list->hwLayers[k].handle) ||
+            (mLayerCache.displayFrame[k].left !=
+                         list->hwLayers[k].displayFrame.left) ||
+            (mLayerCache.displayFrame[k].top !=
+                         list->hwLayers[k].displayFrame.top) ||
+            (mLayerCache.displayFrame[k].right !=
+                         list->hwLayers[k].displayFrame.right) ||
+            (mLayerCache.displayFrame[k].bottom !=
+                         list->hwLayers[k].displayFrame.bottom)) {
+        return 1;
+    }
+    return 0;
+}
+
 int CopyBit::getLayersChanging(hwc_context_t *ctx,
                       hwc_display_contents_1_t *list,
                       int dpy){
@@ -146,7 +161,7 @@
     int updatingLayerCount = 0;
     for (int k = ctx->listStats[dpy].numAppLayers-1; k >= 0 ; k--){
        //swap rect will kick in only for single updating layer
-       if(mLayerCache.hnd[k] != list->hwLayers[k].handle){
+       if(isLayerChanging(list, k)) {
            updatingLayerCount ++;
            if(updatingLayerCount == 1)
              changingLayerIndex = k;
@@ -163,19 +178,20 @@
        dirtyRect = list->hwLayers[changingLayerIndex].dirtyRect;
 #endif
 
-       for (int k = ctx->listStats[dpy].numAppLayers-1; k >= 0 ; k--){
-            //disable swap rect for overlapping visible layer(s)
-            hwc_rect_t displayFrame = list->hwLayers[k].displayFrame;
-            hwc_rect_t result = getIntersection(displayFrame,dirtyRect);
-            if((k != changingLayerIndex) && isValidRect(result)){
-              return -1;
+       for (int k = ctx->listStats[dpy].numAppLayers-1; k >= 0 ; k--) {
+           //disable swap rect in case of scaling and video .
+           private_handle_t *hnd =(private_handle_t *)list->hwLayers[k].handle;
+           if(needsScaling(&list->hwLayers[k])||( hnd && isYuvBuffer(hnd))) {
+               mFbCache.reset();
+               return -1;
            }
        }
-       mFbCache.insertAndUpdateFbCache(dirtyRect);
        if(mFbCache.getUnchangedFbDRCount(dirtyRect) <
-                                             NUM_RENDER_BUFFERS)
+                                             NUM_RENDER_BUFFERS) {
+               mFbCache.insertAndUpdateFbCache(dirtyRect);
               changingLayerIndex =  -1;
-    }else {
+       }
+    } else {
        mFbCache.reset();
        changingLayerIndex =  -1;
     }
@@ -189,23 +205,11 @@
 
    //dirty rect will enable only if
    //1.Only single layer is updating.
-   //2.No overlapping
-   //3.No scaling
-   //4.No video layer
+   //2.No scaling
+   //3.No video layer
    if(mSwapRectEnable == false)
       return -1;
-   int changingLayerIndex =  getLayersChanging(ctx, list, dpy);
-   //swap rect will kick in only for single updating layer
-   if(changingLayerIndex == -1){
-      return -1;
-   }
-   if(!needsScaling(&list->hwLayers[changingLayerIndex])){
-     private_handle_t *hnd =
-         (private_handle_t *)list->hwLayers[changingLayerIndex].handle;
-      if( hnd && !isYuvBuffer(hnd))
-           return  changingLayerIndex;
-   }
-   return -1;
+   return getLayersChanging(ctx, list, dpy);
 }
 
 bool CopyBit::prepareOverlap(hwc_context_t *ctx,
@@ -472,6 +476,7 @@
              list->hwLayers[abcRenderBufIdx].acquireFenceFd);
           }
           for(int i = abcRenderBufIdx + 1; i < layerCount; i++){
+             mDirtyLayerIndex = -1;
              int retVal = drawLayerUsingCopybit(ctx,
                &(list->hwLayers[i]),renderBuffer, 0);
              if(retVal < 0) {
@@ -480,8 +485,8 @@
           }
           // Get Release Fence FD of copybit for the App layer(s)
           copybit->flush_get_fence(copybit, copybitFd);
-          close(list->hwLayers[abcRenderBufIdx].acquireFenceFd);
-          list->hwLayers[abcRenderBufIdx].acquireFenceFd = -1;
+          close(list->hwLayers[last].acquireFenceFd);
+          list->hwLayers[last].acquireFenceFd = -1;
           return true;
        }
     }
@@ -533,21 +538,16 @@
     }
 
     mDirtyLayerIndex =  checkDirtyRect(ctx, list, dpy);
+    ALOGD_IF (DEBUG_COPYBIT, "%s:Dirty Layer Index: %d",
+                                       __FUNCTION__, mDirtyLayerIndex);
     hwc_rect_t clearRegion = {0,0,0,0};
-    if (CBUtils::getuiClearRegion(list, clearRegion, layerProp)){
-        if (mDirtyLayerIndex != -1){
-            hwc_layer_1_t *layer = &list->hwLayers[mDirtyLayerIndex];
-#ifdef QCOM_BSP
-             hwc_rect_t result = getIntersection(layer->dirtyRect,clearRegion);
-             if(isValidRect(result))
-               clear(renderBuffer,result);
-#else
-             clear(renderBuffer,clearRegion);
-#endif
-        } else {
+    mDirtyRect = list->hwLayers[last].displayFrame;
+    if (mDirtyLayerIndex != -1)
+        mDirtyRect = list->hwLayers[mDirtyLayerIndex].displayFrame;
+
+    if (CBUtils::getuiClearRegion(list, clearRegion, layerProp,
+                                                       mDirtyLayerIndex))
              clear(renderBuffer, clearRegion);
-        }
-    }
     // numAppLayers-1, as we iterate from 0th layer index with HWC_COPYBIT flag
     for (int i = 0; i <= (ctx->listStats[dpy].numAppLayers-1); i++) {
         if(!(layerProp[i].mFlags & HWC_COPYBIT)) {
@@ -557,9 +557,6 @@
         if(ctx->copybitDrop[i]) {
             continue;
         }
-        //skip non updating layers
-        if((mDirtyLayerIndex != -1) && (mDirtyLayerIndex != i) )
-            continue;
         int ret = -1;
         if (list->hwLayers[i].acquireFenceFd != -1
                 && ctx->mMDP.version >= qdutils::MDP_V4_0) {
@@ -859,11 +856,18 @@
 #ifdef QCOM_BSP
     //change src and dst with dirtyRect
     if(mDirtyLayerIndex != -1) {
-      srcRect.l = layer->dirtyRect.left;
-      srcRect.t = layer->dirtyRect.top;
-      srcRect.r = layer->dirtyRect.right;
-      srcRect.b = layer->dirtyRect.bottom;
-      dstRect = srcRect;
+      hwc_rect_t result = getIntersection(displayFrame, mDirtyRect);
+      if(!isValidRect(result))
+             return true;
+      dstRect.l = result.left;
+      dstRect.t = result.top;
+      dstRect.r = result.right;
+      dstRect.b = result.bottom;
+
+      srcRect.l += (result.left - displayFrame.left);
+      srcRect.t += (result.top - displayFrame.top);
+      srcRect.r -= (displayFrame.right - result.right);
+      srcRect.b -= (displayFrame.bottom - result.bottom);
     }
 #endif
     // Copybit dst
@@ -1215,6 +1219,7 @@
    layerCount = ctx->listStats[dpy].numAppLayers;
    for (int i=0; i<ctx->listStats[dpy].numAppLayers; i++){
       hnd[i] = list->hwLayers[i].handle;
+      displayFrame[i] = list->hwLayers[i].displayFrame;
    }
 }
 
diff --git a/libhwcomposer/hwc_copybit.h b/libhwcomposer/hwc_copybit.h
index a7ce43e..6ead4a7 100644
--- a/libhwcomposer/hwc_copybit.h
+++ b/libhwcomposer/hwc_copybit.h
@@ -60,6 +60,7 @@
     struct LayerCache {
       int layerCount;
       buffer_handle_t hnd[MAX_NUM_APP_LAYERS];
+      hwc_rect_t displayFrame[MAX_NUM_APP_LAYERS];
       /* c'tor */
       LayerCache();
       /* clear caching info*/
@@ -129,10 +130,12 @@
     int mDirtyLayerIndex;
     LayerCache mLayerCache;
     FbCache mFbCache;
+    hwc_rect_t mDirtyRect;
     int getLayersChanging(hwc_context_t *ctx, hwc_display_contents_1_t *list,
                   int dpy);
     int checkDirtyRect(hwc_context_t *ctx, hwc_display_contents_1_t *list,
                   int dpy);
+    bool isLayerChanging(hwc_display_contents_1_t *list, int k);
 };
 
 }; //namespace qhwc
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index ca599ed..a34e599 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -306,14 +306,20 @@
         if(leftType == rightType) {
             //Safe. Onus on driver to assign correct pipes within same type
             return false;
-        } else if(leftType == OV_MDP_PIPE_DMA or rightType == OV_MDP_PIPE_VG) {
-            //If we are here, right is definitely a higher prio type.
+        } else {
             //This check takes advantage of having only 3 types and avoids 3
             //different failure combination checks.
-            return true;
-        } else {
-            //Types are correct priority-wise
-            return false;
+            // Swap IF:
+            // ----------------
+            // | Left | Right |
+            // ================
+            // | DMA  | ViG   |
+            // ----------------
+            // | DMA  | RGB   |
+            // ----------------
+            // | RGB  | ViG   |
+            // ----------------
+            return (leftType == OV_MDP_PIPE_DMA or rightType == OV_MDP_PIPE_VG);
         }
     } else if(pipe1Id < 0) {
         //LEFT needs new allocation.
@@ -321,8 +327,7 @@
             // If RIGHT has highest priority(lowest id), swap it.
             return (pipe2Id == PipeBook::pipeMinID[leftType]);
         } else {
-            // Swap if needs lowest priority type pipe.
-            return (leftType == OV_MDP_PIPE_DMA);
+            return (leftType == OV_MDP_PIPE_DMA or rightType == OV_MDP_PIPE_VG);
         }
     } else { /* if (pipe2Id < 0) */
         // RIGHT needs new allocation.
@@ -330,8 +335,7 @@
             // If LEFT has lowest priority(highest id), swap it.
             return (pipe1Id == PipeBook::pipeMaxID[leftType]);
         } else {
-            // Swap if needs highest  priority type pipe.
-            return (rightType == OV_MDP_PIPE_VG);
+            return (leftType == OV_MDP_PIPE_DMA or rightType == OV_MDP_PIPE_VG);
         }
     }
 }
diff --git a/libqdutils/cb_utils.cpp b/libqdutils/cb_utils.cpp
index ef66ac6..c17842a 100644
--- a/libqdutils/cb_utils.cpp
+++ b/libqdutils/cb_utils.cpp
@@ -41,13 +41,36 @@
 namespace qdutils {
 
 int CBUtils::getuiClearRegion(hwc_display_contents_1_t* list,
-          hwc_rect_t &clearWormholeRect, LayerProp *layerProp) {
+          hwc_rect_t &clearWormholeRect, LayerProp *layerProp, int dirtyIndex) {
 
     size_t last = list->numHwLayers - 1;
     hwc_rect_t fbFrame = list->hwLayers[last].displayFrame;
     Rect fbFrameRect(fbFrame.left,fbFrame.top,fbFrame.right,fbFrame.bottom);
     Region wormholeRegion(fbFrameRect);
 
+   if (dirtyIndex != -1) {
+#ifdef QCOM_BSP
+      /*
+       * 1. Map dirty rect of updating layer to its display frame.
+       * 2. Use this display frame as wormholeRegion instead of full Frame
+       * */
+      hwc_rect_t dirtyRect = list->hwLayers[dirtyIndex].dirtyRect;
+      hwc_rect_t displayFrame = list->hwLayers[dirtyIndex].displayFrame;
+      hwc_frect_t sCropF = list->hwLayers[dirtyIndex].sourceCropf;
+      hwc_rect_t srcRect = {int(ceilf(sCropF.left)), int(ceilf(sCropF.top)),
+                           int(ceilf(sCropF.right)), int(ceilf(sCropF.bottom))};
+
+      displayFrame.left += dirtyRect.left - srcRect.left;
+      displayFrame.top += dirtyRect.top - srcRect.top;
+      displayFrame.right -= srcRect.right - dirtyRect.right;
+      displayFrame.bottom -= srcRect.bottom - dirtyRect.bottom;
+
+      Rect tmpRect(displayFrame.left,displayFrame.top,displayFrame.right,
+            displayFrame.bottom);
+      Region tmpRegion(tmpRect);
+      wormholeRegion = wormholeRegion.intersect(tmpRegion);
+#endif
+   }
     if(cb_swap_rect::getInstance().checkSwapRectFeature_on() == true){
       wormholeRegion.set(0,0);
       for(size_t i = 0 ; i < last; i++) {
diff --git a/libqdutils/cb_utils.h b/libqdutils/cb_utils.h
index 85dd78f..59f452b 100644
--- a/libqdutils/cb_utils.h
+++ b/libqdutils/cb_utils.h
@@ -38,7 +38,7 @@
 public:
 static int getuiClearRegion(hwc_display_contents_1_t* list,
                               hwc_rect_t &clearWormholeRec,
-                                      LayerProp *layerProp);
+                              LayerProp *layerProp, int dirtyIndex = -1);
 };
 }//namespace qdutils
 #endif /* end of include guard: CB_UTIL_H*/
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index e5fc2a8..cd2d116 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -59,6 +59,7 @@
         CONFIGURE_DYN_REFRESH_RATE = 18,
         SET_PARTIAL_UPDATE = 19,   // Preference on partial update feature
         TOGGLE_SCREEN_UPDATE = 20, // Provides ability to disable screen updates
+        SET_FRAME_DUMP_CONFIG = 21,  // Provides ability to set the frame dump config
         COMMAND_LIST_END = 400,
     };
 
@@ -77,6 +78,12 @@
         DEBUG_ROTATOR,
     };
 
+    enum {
+        DUMP_PRIMARY_DISPLAY,
+        DUMP_HDMI_DISPLAY,
+        DUMP_VIRTUAL_DISPLAY,
+    };
+
     // Register a client that can be notified
     virtual void connect(const android::sp<qClient::IQClient>& client) = 0;
     // Generic function to dispatch binder commands