sde: Enable GPU mode composition for primary display.

1. Load sde core and create primary display in hwc session.
2. Prepare layer stack for primary display.
3. Open open fb node for primary display.
4. Add support to select a composition strategy using strategy
   interface and allocate mdss resources using resource manager
   in composition manager.
5. Manage mdss pipe state machine and configure pipes for layer
   stack in resource manager.
6. Add default strategy to select GPU composition.
7. Add support for hw layer to atomic commit translation.

Change-Id: I5a5537dbcb28727e16b0c055e17a387696f6dac8
diff --git a/displayengine/include/private/strategy_interface.h b/displayengine/include/private/strategy_interface.h
index 755af1d..7050929 100644
--- a/displayengine/include/private/strategy_interface.h
+++ b/displayengine/include/private/strategy_interface.h
@@ -104,7 +104,15 @@
                             //!< relies on the total flag count to check the number of strategies
                             //!< that are attempted for this layer stack.
 
-  HWLayersInfo() : stack(NULL), count(0), flags(0) { }
+  HWLayersInfo() {
+    Reset();
+  }
+
+  void Reset() {
+    stack = NULL;
+    count = 0;
+    flags = 0;
+  }
 };
 
 class StrategyInterface {
diff --git a/displayengine/libs/core/Android.mk b/displayengine/libs/core/Android.mk
index 519c404..6854c8c 100644
--- a/displayengine/libs/core/Android.mk
+++ b/displayengine/libs/core/Android.mk
@@ -17,6 +17,7 @@
                                  comp_manager.cpp \
                                  strategy_default.cpp \
                                  res_manager.cpp \
+                                 res_config.cpp \
                                  writeback_session.cpp \
                                  hw_interface.cpp \
                                  hw_framebuffer.cpp \
diff --git a/displayengine/libs/core/comp_manager.cpp b/displayengine/libs/core/comp_manager.cpp
index 3ca38bd..b264038 100644
--- a/displayengine/libs/core/comp_manager.cpp
+++ b/displayengine/libs/core/comp_manager.cpp
@@ -37,13 +37,155 @@
 CompManager::CompManager() : strategy_lib_(NULL), strategy_intf_(NULL) {
 }
 
-DisplayError CompManager::Init() {
+DisplayError CompManager::Init(const HWResourceInfo &hw_res_info) {
+  SCOPE_LOCK(locker_);
+
+  DisplayError error = kErrorNone;
+
+  error = res_mgr_.Init(hw_res_info);
+  if (UNLIKELY(error != kErrorNone)) {
+    return error;
+  }
+
+  // Try to load strategy library & get handle to its interface.
+  // Default to GPU only composition on failure.
+  strategy_lib_ = ::dlopen(STRATEGY_LIBRARY_NAME, RTLD_NOW);
+  if (UNLIKELY(!strategy_lib_)) {
+    DLOGW("Unable to load = %s", STRATEGY_LIBRARY_NAME);
+  } else {
+    GetStrategyInterface get_strategy_intf = NULL;
+    void **sym = reinterpret_cast<void **>(&get_strategy_intf);
+    *sym = ::dlsym(strategy_lib_, GET_STRATEGY_INTERFACE_NAME);
+    if (UNLIKELY(!get_strategy_intf)) {
+      DLOGW("Unable to find symbol for %s", GET_STRATEGY_INTERFACE_NAME);
+    } else if (UNLIKELY(get_strategy_intf(&strategy_intf_) != kErrorNone)) {
+      DLOGW("Unable to get handle to strategy interface");
+    }
+  }
+
+  if (UNLIKELY(!strategy_intf_)) {
+    DLOGI("Using GPU only composition");
+    if (strategy_lib_) {
+      ::dlclose(strategy_lib_);
+      strategy_lib_ = NULL;
+    }
+    strategy_intf_ = &strategy_default_;
+  }
+
   return kErrorNone;
 }
 
 DisplayError CompManager::Deinit() {
+  SCOPE_LOCK(locker_);
+
+  if (strategy_lib_) {
+    ::dlclose(strategy_lib_);
+  }
+  res_mgr_.Deinit();
+
   return kErrorNone;
 }
 
+DisplayError CompManager::RegisterDevice(DeviceType type, const HWDeviceAttributes &attributes,
+                                         Handle *device) {
+  SCOPE_LOCK(locker_);
+
+  DisplayError error = kErrorNone;
+
+  CompManagerDevice *comp_mgr_device = new CompManagerDevice();
+  if (!comp_mgr_device) {
+    return kErrorMemory;
+  }
+
+  error = res_mgr_.RegisterDevice(type, attributes, &comp_mgr_device->res_mgr_device);
+  if (error != kErrorNone) {
+    delete comp_mgr_device;
+    return error;
+  }
+
+  comp_mgr_device->device_type = type;
+  *device = comp_mgr_device;
+
+  return kErrorNone;
+}
+
+DisplayError CompManager::UnregisterDevice(Handle device) {
+  SCOPE_LOCK(locker_);
+
+  CompManagerDevice *comp_mgr_device = reinterpret_cast<CompManagerDevice *>(device);
+
+  res_mgr_.UnregisterDevice(comp_mgr_device->res_mgr_device);
+  delete comp_mgr_device;
+
+  return kErrorNone;
+}
+
+DisplayError CompManager::Prepare(Handle device, HWLayers *hw_layers) {
+  SCOPE_LOCK(locker_);
+
+  CompManagerDevice *comp_mgr_device = reinterpret_cast<CompManagerDevice *>(device);
+  Handle &res_mgr_device = comp_mgr_device->res_mgr_device;
+
+  DisplayError error = kErrorNone;
+
+  comp_mgr_device->constraints.gpu_only = false;
+
+  // If validation for the best available composition strategy with driver has failed, just
+  // fallback to GPU composition.
+  if (UNLIKELY(hw_layers->info.flags)) {
+    // Did driver reject GPU composition as well? This will never happen.
+    if (UNLIKELY(hw_layers->info.flags & kFlagGPU)) {
+      DLOGE("Unexpected error. GPU composition validation failed.");
+      return kErrorHardware;
+    }
+
+    comp_mgr_device->constraints.gpu_only = true;
+  }
+
+  // Select a composition strategy, and try to allocate resources for it.
+  res_mgr_.Start(res_mgr_device);
+  while (true) {
+    error = strategy_intf_->GetNextStrategy(&comp_mgr_device->constraints, &hw_layers->info);
+    if (UNLIKELY(error != kErrorNone)) {
+      // Composition strategies exhausted. Resource Manager could not allocate resources even for
+      // GPU composition. This will never happen.
+      DLOGE("Unexpected failure. Composition strategies exhausted.");
+      return error;
+    }
+
+    error = res_mgr_.Acquire(res_mgr_device, hw_layers);
+    if (error != kErrorNone) {
+      // Not enough resources, try next strategy.
+      continue;
+    } else {
+      // Successfully selected and configured a composition strategy.
+      break;
+    }
+  }
+  res_mgr_.Stop(res_mgr_device);
+
+  return kErrorNone;
+}
+
+void CompManager::PostPrepare(Handle device, HWLayers *hw_layers) {
+  SCOPE_LOCK(locker_);
+}
+
+void CompManager::PostCommit(Handle device, HWLayers *hw_layers) {
+  SCOPE_LOCK(locker_);
+
+  CompManagerDevice *comp_mgr_device = reinterpret_cast<CompManagerDevice *>(device);
+
+  res_mgr_.PostCommit(comp_mgr_device->res_mgr_device, hw_layers);
+}
+
+void CompManager::Purge(Handle device) {
+  SCOPE_LOCK(locker_);
+
+  CompManagerDevice *comp_mgr_device = reinterpret_cast<CompManagerDevice *>(device);
+
+  res_mgr_.Purge(comp_mgr_device->res_mgr_device);
+}
+
 }  // namespace sde
 
diff --git a/displayengine/libs/core/comp_manager.h b/displayengine/libs/core/comp_manager.h
index 318ddb4..1e1245d 100644
--- a/displayengine/libs/core/comp_manager.h
+++ b/displayengine/libs/core/comp_manager.h
@@ -36,10 +36,24 @@
 class CompManager {
  public:
   CompManager();
-  DisplayError Init();
+  DisplayError Init(const HWResourceInfo &hw_res_info_);
   DisplayError Deinit();
+  DisplayError RegisterDevice(DeviceType type, const HWDeviceAttributes &attributes,
+                              Handle *device);
+  DisplayError UnregisterDevice(Handle device);
+  DisplayError Prepare(Handle device, HWLayers *hw_layers);
+  void PostPrepare(Handle device, HWLayers *hw_layers);
+  void PostCommit(Handle device, HWLayers *hw_layers);
+  void Purge(Handle device);
 
  private:
+  struct CompManagerDevice {
+    StrategyConstraints constraints;
+    Handle res_mgr_device;
+    DeviceType device_type;
+  };
+
+  Locker locker_;
   void *strategy_lib_;
   StrategyInterface *strategy_intf_;
   StrategyDefault strategy_default_;
diff --git a/displayengine/libs/core/core_impl.cpp b/displayengine/libs/core/core_impl.cpp
index f8b07b3..cdbd414 100644
--- a/displayengine/libs/core/core_impl.cpp
+++ b/displayengine/libs/core/core_impl.cpp
@@ -32,6 +32,8 @@
 
 #include "core_impl.h"
 #include "device_primary.h"
+#include "device_hdmi.h"
+#include "device_virtual.h"
 
 namespace sde {
 
@@ -49,18 +51,33 @@
     return error;
   }
 
-  error = comp_mgr_.Init();
+  HWResourceInfo hw_res_info;
+  error = hw_intf_->GetHWCapabilities(&hw_res_info);
   if (UNLIKELY(error != kErrorNone)) {
     HWInterface::Destroy(hw_intf_);
     return error;
   }
 
+  error = comp_mgr_.Init(hw_res_info);
+  if (UNLIKELY(error != kErrorNone)) {
+    HWInterface::Destroy(hw_intf_);
+    return error;
+  }
+
+  error = wb_session_.Init(hw_intf_, hw_res_info);
+  if (UNLIKELY(error != kErrorNone)) {
+    comp_mgr_.Deinit();
+    HWInterface::Destroy(hw_intf_);
+    return error;
+  }
+
   return kErrorNone;
 }
 
 DisplayError CoreImpl::Deinit() {
   SCOPE_LOCK(locker_);
 
+  wb_session_.Deinit();
   comp_mgr_.Deinit();
   HWInterface::Destroy(hw_intf_);
 
@@ -75,6 +92,36 @@
     return kErrorParameters;
   }
 
+  DeviceBase *device_base = NULL;
+  switch (type) {
+  case kPrimary:
+    device_base = new DevicePrimary(event_handler, hw_intf_, &comp_mgr_);
+    break;
+
+  case kHWHDMI:
+    device_base = new DeviceHDMI(event_handler, hw_intf_, &comp_mgr_);
+    break;
+
+  case kVirtual:
+    device_base = new DeviceVirtual(event_handler, hw_intf_, &comp_mgr_);
+    break;
+
+  default:
+    DLOGE("Spurious device type %d", type);
+    return kErrorParameters;
+  }
+
+  if (UNLIKELY(!device_base)) {
+    return kErrorMemory;
+  }
+
+  DisplayError error = device_base->Init();
+  if (UNLIKELY(error != kErrorNone)) {
+    delete device_base;
+    return error;
+  }
+
+  *intf = device_base;
   return kErrorNone;
 }
 
@@ -85,6 +132,10 @@
     return kErrorParameters;
   }
 
+  DeviceBase *device_base = static_cast<DeviceBase *>(intf);
+  device_base->Deinit();
+  delete device_base;
+
   return kErrorNone;
 }
 
diff --git a/displayengine/libs/core/core_impl.h b/displayengine/libs/core/core_impl.h
index d4b2859..3509274 100644
--- a/displayengine/libs/core/core_impl.h
+++ b/displayengine/libs/core/core_impl.h
@@ -31,6 +31,7 @@
 
 #include "hw_interface.h"
 #include "comp_manager.h"
+#include "writeback_session.h"
 
 #define SET_REVISION(major, minor) ((major << 8) | minor)
 
@@ -60,6 +61,7 @@
   CoreEventHandler *event_handler_;
   HWInterface *hw_intf_;
   CompManager comp_mgr_;
+  WritebackSession wb_session_;
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/core/core_interface.cpp b/displayengine/libs/core/core_interface.cpp
index 7bb83ab..8cfd9e7 100644
--- a/displayengine/libs/core/core_interface.cpp
+++ b/displayengine/libs/core/core_interface.cpp
@@ -48,7 +48,7 @@
 } g_core;
 
 DisplayError CoreInterface::CreateCore(CoreEventHandler *event_handler, CoreInterface **interface,
-                                 uint32_t version) {
+                                 uint32_t client_version) {
   SCOPE_LOCK(g_core.locker);
 
   if (UNLIKELY(!event_handler || !interface)) {
@@ -59,11 +59,11 @@
   uint32_t lib_version = CORE_VERSION_TAG;
   if (UNLIKELY(!interface)) {
     return kErrorParameters;
-  } else if (UNLIKELY(GET_REVISION(version) > GET_REVISION(lib_version))) {
+  } else if (UNLIKELY(GET_REVISION(client_version) > GET_REVISION(lib_version))) {
     return kErrorVersion;
-  } else if (UNLIKELY(GET_DATA_ALIGNMENT(version) != GET_DATA_ALIGNMENT(lib_version))) {
+  } else if (UNLIKELY(GET_DATA_ALIGNMENT(client_version) != GET_DATA_ALIGNMENT(lib_version))) {
     return kErrorDataAlignment;
-  } else if (UNLIKELY(GET_INSTRUCTION_SET(version) != GET_INSTRUCTION_SET(lib_version))) {
+  } else if (UNLIKELY(GET_INSTRUCTION_SET(client_version) != GET_INSTRUCTION_SET(lib_version))) {
     return kErrorInstructionSet;
   }
 
@@ -74,7 +74,7 @@
   }
 
   // Create appropriate CoreImpl object based on client version.
-  if (GET_REVISION(version) == CoreImpl::kRevision) {
+  if (GET_REVISION(client_version) == CoreImpl::kRevision) {
     core_impl = new CoreImpl(event_handler);
   } else {
     return kErrorNotSupported;
diff --git a/displayengine/libs/core/device_base.cpp b/displayengine/libs/core/device_base.cpp
index 40d6649..a04bf45 100644
--- a/displayengine/libs/core/device_base.cpp
+++ b/displayengine/libs/core/device_base.cpp
@@ -33,33 +33,134 @@
 
 namespace sde {
 
-DeviceBase::DeviceBase(HWInterfaceType type, DeviceEventHandler *event_handler,
-                       HWInterface *hw_interface, CompManager *comp_manager)
-  : type_(type), event_handler_(event_handler), hw_intf_(hw_interface), comp_manager_(comp_manager),
-    state_(kStateOff) {
+DeviceBase::DeviceBase(DeviceType device_type, DeviceEventHandler *event_handler,
+             HWBlockType hw_block_type, HWInterface *hw_intf, CompManager *comp_manager)
+  : device_type_(device_type), event_handler_(event_handler), hw_block_type_(hw_block_type),
+    hw_intf_(hw_intf), comp_manager_(comp_manager), state_(kStateOff), hw_device_(0),
+    comp_mgr_device_(0), device_attributes_(NULL), num_modes_(0), active_mode_index_(0),
+    pending_commit_(false) {
 }
 
 DisplayError DeviceBase::Init() {
   SCOPE_LOCK(locker_);
 
+  DisplayError error = kErrorNone;
+
+  error = hw_intf_->Open(hw_block_type_, &hw_device_);
+  if (UNLIKELY(error != kErrorNone)) {
+    return error;
+  }
+
+  error = hw_intf_->GetNumDeviceAttributes(hw_device_, &num_modes_);
+  if (UNLIKELY(error != kErrorNone)) {
+    goto CleanupOnError;
+  }
+
+  device_attributes_ = new HWDeviceAttributes[num_modes_];
+  if (!device_attributes_) {
+    error = kErrorMemory;
+    goto CleanupOnError;
+  }
+
+  for (uint32_t i = 0; i < num_modes_; i++) {
+    error = hw_intf_->GetDeviceAttributes(hw_device_, &device_attributes_[i], i);
+    if (UNLIKELY(error != kErrorNone)) {
+      goto CleanupOnError;
+    }
+  }
+
+  active_mode_index_ = 0;
+
+  error = comp_manager_->RegisterDevice(device_type_, device_attributes_[active_mode_index_],
+                                        &comp_mgr_device_);
+  if (UNLIKELY(error != kErrorNone)) {
+    goto CleanupOnError;
+  }
+
   return kErrorNone;
+
+CleanupOnError:
+  comp_manager_->UnregisterDevice(comp_mgr_device_);
+
+  if (device_attributes_) {
+    delete[] device_attributes_;
+  }
+
+  hw_intf_->Close(hw_device_);
+
+  return error;
 }
 
 DisplayError DeviceBase::Deinit() {
   SCOPE_LOCK(locker_);
 
+  comp_manager_->UnregisterDevice(comp_mgr_device_);
+  delete[] device_attributes_;
+  hw_intf_->Close(hw_device_);
+
   return kErrorNone;
 }
 
 DisplayError DeviceBase::Prepare(LayerStack *layer_stack) {
   SCOPE_LOCK(locker_);
 
-  return kErrorNone;
+  DisplayError error = kErrorNone;
+
+  if (UNLIKELY(!layer_stack)) {
+    return kErrorParameters;
+  }
+
+  pending_commit_ = false;
+
+  if (LIKELY(state_ == kStateOn)) {
+    // Clean hw layers for reuse.
+    hw_layers_.info.Reset();
+    hw_layers_.info.stack = layer_stack;
+
+    while (true) {
+      error = comp_manager_->Prepare(comp_mgr_device_, &hw_layers_);
+      if (UNLIKELY(error != kErrorNone)) {
+        break;
+      }
+
+      error = hw_intf_->Validate(hw_device_, &hw_layers_);
+      if (LIKELY(error == kErrorNone)) {
+        // Strategy is successful now, wait for Commit().
+        comp_manager_->PostPrepare(comp_mgr_device_, &hw_layers_);
+        pending_commit_ = true;
+        break;
+      }
+    }
+  }
+
+  return error;
 }
 
 DisplayError DeviceBase::Commit(LayerStack *layer_stack) {
   SCOPE_LOCK(locker_);
 
+  DisplayError error = kErrorNone;
+
+  if (UNLIKELY(!layer_stack)) {
+    return kErrorParameters;
+  }
+
+  if (UNLIKELY(!pending_commit_)) {
+    DLOGE("Commit: Corresponding Prepare() is not called.");
+    return kErrorUndefined;
+  }
+
+  if (LIKELY(state_ == kStateOn)) {
+    error = hw_intf_->Commit(hw_device_, &hw_layers_);
+    if (LIKELY(error == kErrorNone)) {
+      comp_manager_->PostCommit(comp_mgr_device_, &hw_layers_);
+    } else {
+      DLOGE("Unexpected error. Commit failed on driver.");
+    }
+  }
+
+  pending_commit_ = false;
+
   return kErrorNone;
 }
 
@@ -81,6 +182,8 @@
     return kErrorParameters;
   }
 
+  *count = num_modes_;
+
   return kErrorNone;
 }
 
@@ -97,10 +200,12 @@
 DisplayError DeviceBase::GetConfig(DeviceConfigVariableInfo *variable_info, uint32_t mode) {
   SCOPE_LOCK(locker_);
 
-  if (UNLIKELY(!variable_info)) {
+  if (UNLIKELY(!variable_info || mode >= num_modes_)) {
     return kErrorParameters;
   }
 
+  *variable_info = device_attributes_[mode];
+
   return kErrorNone;
 }
 
@@ -117,7 +222,43 @@
 DisplayError DeviceBase::SetDeviceState(DeviceState state) {
   SCOPE_LOCK(locker_);
 
-  return kErrorNone;
+  DisplayError error = kErrorNone;
+
+  DLOGI("Set state: %d", state);
+
+  if (UNLIKELY(state == state_)) {
+    DLOGI("Same state transition is requested.");
+    return kErrorNone;
+  }
+
+  switch (state) {
+  case kStateOff:
+    comp_manager_->Purge(comp_mgr_device_);
+    error = hw_intf_->PowerOff(hw_device_);
+    break;
+
+  case kStateOn:
+    error = hw_intf_->PowerOn(hw_device_);
+    break;
+
+  case kStateDoze:
+    error = hw_intf_->Doze(hw_device_);
+    break;
+
+  case kStateStandby:
+    error = hw_intf_->Standby(hw_device_);
+    break;
+
+  default:
+    DLOGE("Spurious state %d transition requested.", state);
+    break;
+  }
+
+  if (UNLIKELY(error == kErrorNone)) {
+    state_ = state;
+  }
+
+  return error;
 }
 
 DisplayError DeviceBase::SetConfig(uint32_t mode) {
diff --git a/displayengine/libs/core/device_base.h b/displayengine/libs/core/device_base.h
index ce71ab9..fad3023 100644
--- a/displayengine/libs/core/device_base.h
+++ b/displayengine/libs/core/device_base.h
@@ -36,8 +36,8 @@
 
 class DeviceBase : public DeviceInterface {
  public:
-  DeviceBase(HWInterfaceType type, DeviceEventHandler *event_handler, HWInterface *hw_interface,
-             CompManager *comp_manager);
+  DeviceBase(DeviceType device_type, DeviceEventHandler *event_handler,
+             HWBlockType hw_block_type, HWInterface *hw_intf, CompManager *comp_manager);
   virtual ~DeviceBase() { }
   virtual DisplayError Init();
   virtual DisplayError Deinit();
@@ -54,11 +54,19 @@
 
  protected:
   Locker locker_;
-  HWInterfaceType type_;
+  DeviceType device_type_;
   DeviceEventHandler *event_handler_;
+  HWBlockType hw_block_type_;
   HWInterface *hw_intf_;
   CompManager *comp_manager_;
   DeviceState state_;
+  Handle hw_device_;
+  Handle comp_mgr_device_;
+  HWDeviceAttributes *device_attributes_;
+  uint32_t num_modes_;
+  uint32_t active_mode_index_;
+  HWLayers hw_layers_;
+  bool pending_commit_;
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/core/device_hdmi.cpp b/displayengine/libs/core/device_hdmi.cpp
index 87fe8db..1a7bf26 100644
--- a/displayengine/libs/core/device_hdmi.cpp
+++ b/displayengine/libs/core/device_hdmi.cpp
@@ -35,7 +35,7 @@
 
 DeviceHDMI::DeviceHDMI(DeviceEventHandler *event_handler, HWInterface *hw_intf,
                        CompManager *comp_manager)
-  : DeviceBase(kHWHDMI, event_handler, hw_intf, comp_manager) {
+  : DeviceBase(kHDMI, event_handler, kHWHDMI, hw_intf, comp_manager) {
 }
 
 }  // namespace sde
diff --git a/displayengine/libs/core/device_primary.cpp b/displayengine/libs/core/device_primary.cpp
index 9b99c3a..b10546f 100644
--- a/displayengine/libs/core/device_primary.cpp
+++ b/displayengine/libs/core/device_primary.cpp
@@ -35,7 +35,7 @@
 
 DevicePrimary::DevicePrimary(DeviceEventHandler *event_handler, HWInterface *hw_intf,
                              CompManager *comp_manager)
-  : DeviceBase(kHWPrimary, event_handler, hw_intf, comp_manager) {
+  : DeviceBase(kPrimary, event_handler, kHWPrimary, hw_intf, comp_manager) {
 }
 
 }  // namespace sde
diff --git a/displayengine/libs/core/device_virtual.cpp b/displayengine/libs/core/device_virtual.cpp
index 5632c81..9fc9df4 100644
--- a/displayengine/libs/core/device_virtual.cpp
+++ b/displayengine/libs/core/device_virtual.cpp
@@ -35,7 +35,7 @@
 
 DeviceVirtual::DeviceVirtual(DeviceEventHandler *event_handler, HWInterface *hw_intf,
                              CompManager *comp_manager)
-  : DeviceBase(kHWWriteback, event_handler, hw_intf, comp_manager) {
+  : DeviceBase(kVirtual, event_handler, kHWBlockMax, hw_intf, comp_manager) {
 }
 
 }  // namespace sde
diff --git a/displayengine/libs/core/hw_framebuffer.cpp b/displayengine/libs/core/hw_framebuffer.cpp
index 7d62310..41dd731 100644
--- a/displayengine/libs/core/hw_framebuffer.cpp
+++ b/displayengine/libs/core/hw_framebuffer.cpp
@@ -74,11 +74,25 @@
   return kErrorNone;
 }
 
-DisplayError HWFrameBuffer::GetCapabilities(HWResourceInfo *hw_res_info) {
+DisplayError HWFrameBuffer::GetHWCapabilities(HWResourceInfo *hw_res_info) {
+  // Hardcode for 8084 for now.
+  hw_res_info->mdp_version = 500;
+  hw_res_info->hw_revision = 0x10030001;
+  hw_res_info->num_dma_pipe = 2;
+  hw_res_info->num_vig_pipe = 4;
+  hw_res_info->num_rgb_pipe = 4;
+  hw_res_info->num_rotator = 2;
+  hw_res_info->num_control = 5;
+  hw_res_info->num_mixer_to_disp = 4;
+  hw_res_info->max_scale_up = 20;
+  hw_res_info->max_scale_down = 4;
+  hw_res_info->has_non_scalar_rgb = true;
+  hw_res_info->is_src_split = true;
+
   return kErrorNone;
 }
 
-DisplayError HWFrameBuffer::Open(HWInterfaceType type, Handle *device) {
+DisplayError HWFrameBuffer::Open(HWBlockType type, Handle *device) {
   DisplayError error = kErrorNone;
 
   HWContext *hw_context = new HWContext();
@@ -86,20 +100,86 @@
     return kErrorMemory;
   }
 
+  int device_id = 0;
+  switch (type) {
+  case kHWPrimary:
+    device_id = 0;
+    break;
+  default:
+    break;
+  }
+
+  char device_name[64] = {0};
+  snprintf(device_name, sizeof(device_name), "%s%d", "/dev/graphics/fb", device_id);
+
+  hw_context->device_fd = open_(device_name, O_RDWR);
+  if (UNLIKELY(hw_context->device_fd < 0)) {
+    DLOGE("open %s failed.", device_name);
+    error = kErrorResources;
+    delete hw_context;
+  }
+
   *device = hw_context;
-  return kErrorNone;
+  return error;
 }
 
 DisplayError HWFrameBuffer::Close(Handle device) {
   HWContext *hw_context = reinterpret_cast<HWContext *>(device);
 
+  close_(hw_context->device_fd);
   delete hw_context;
+
   return kErrorNone;
 }
 
-DisplayError HWFrameBuffer::GetConfig(Handle device, DeviceConfigVariableInfo *variable_info) {
+DisplayError HWFrameBuffer::GetNumDeviceAttributes(Handle device, uint32_t *count) {
   HWContext *hw_context = reinterpret_cast<HWContext *>(device);
 
+  // TODO(user): Query modes
+  *count = 1;
+
+  return kErrorNone;
+}
+
+DisplayError HWFrameBuffer::GetDeviceAttributes(Handle device,
+                                                HWDeviceAttributes *device_attributes,
+                                                uint32_t mode) {
+  HWContext *hw_context = reinterpret_cast<HWContext *>(device);
+  int &device_fd = hw_context->device_fd;
+
+  // TODO(user): Query for respective mode index.
+
+  // Variable screen info
+  STRUCT_VAR(fb_var_screeninfo, var_screeninfo);
+  if (UNLIKELY(ioctl_(device_fd, FBIOGET_VSCREENINFO, &var_screeninfo) == -1)) {
+    IOCTL_LOGE(FBIOGET_VSCREENINFO);
+    return kErrorHardware;
+  }
+
+  // Frame rate
+  STRUCT_VAR(msmfb_metadata, meta_data);
+  meta_data.op = metadata_op_frame_rate;
+  if (UNLIKELY(ioctl_(device_fd, MSMFB_METADATA_GET, &meta_data) == -1)) {
+    IOCTL_LOGE(MSMFB_METADATA_GET);
+    return kErrorHardware;
+  }
+
+  // If driver doesn't return width/height information, default to 160 dpi
+  if (INT(var_screeninfo.width) <= 0 || INT(var_screeninfo.height) <= 0) {
+    var_screeninfo.width  = INT((FLOAT(var_screeninfo.xres) * 25.4f)/160.0f + 0.5f);
+    var_screeninfo.height = INT((FLOAT(var_screeninfo.yres) * 25.4f)/160.0f + 0.5f);
+  }
+
+  device_attributes->x_pixels = var_screeninfo.xres;
+  device_attributes->y_pixels = var_screeninfo.yres;
+  device_attributes->x_dpi = (FLOAT(var_screeninfo.xres) * 25.4f) / FLOAT(var_screeninfo.width);
+  device_attributes->y_dpi = (FLOAT(var_screeninfo.yres) * 25.4f) / FLOAT(var_screeninfo.height);
+  device_attributes->vsync_period_ns = UINT32(1000000000L / FLOAT(meta_data.data.panel_frame_rate));
+
+  // TODO(user): set panel information from sysfs
+  device_attributes->is_device_split = true;
+  device_attributes->split_left = device_attributes->x_pixels / 2;
+
   return kErrorNone;
 }
 
@@ -117,6 +197,11 @@
 DisplayError HWFrameBuffer::PowerOff(Handle device) {
   HWContext *hw_context = reinterpret_cast<HWContext *>(device);
 
+  if (UNLIKELY(ioctl_(hw_context->device_fd, FBIOBLANK, FB_BLANK_POWERDOWN) == -1)) {
+    IOCTL_LOGE(FB_BLANK_POWERDOWN);
+    return kErrorHardware;
+  }
+
   return kErrorNone;
 }
 
@@ -132,7 +217,7 @@
   return kErrorNone;
 }
 
-DisplayError HWFrameBuffer::Prepare(Handle device, HWLayers *hw_layers) {
+DisplayError HWFrameBuffer::Validate(Handle device, HWLayers *hw_layers) {
   HWContext *hw_context = reinterpret_cast<HWContext *>(device);
 
   return kErrorNone;
@@ -141,8 +226,137 @@
 DisplayError HWFrameBuffer::Commit(Handle device, HWLayers *hw_layers) {
   HWContext *hw_context = reinterpret_cast<HWContext *>(device);
 
+  HWLayersInfo &hw_layer_info = hw_layers->info;
+
+  // Assuming left & right both pipe are required, maximum possible number of overlays.
+  uint32_t max_overlay_count = hw_layer_info.count * 2;
+
+  int acquire_fences[hw_layer_info.count];  // NOLINT
+  int release_fence = -1;
+  int retire_fence = -1;
+  uint32_t acquire_fence_count = 0;
+  STRUCT_VAR_ARRAY(mdp_overlay, overlay_array, max_overlay_count);
+  STRUCT_VAR_ARRAY(msmfb_overlay_data, data_array, max_overlay_count);
+
+  LayerStack *stack = hw_layer_info.stack;
+  uint32_t num_overlays = 0;
+  for (uint32_t i = 0; i < hw_layer_info.count; i++) {
+    uint32_t layer_index = hw_layer_info.index[i];
+    Layer &layer = stack->layers.layer[layer_index];
+    LayerBuffer *input_buffer = layer.input_buffer;
+    HWLayerConfig &config = hw_layers->config[i];
+    HWPipeInfo &left_pipe = config.left_pipe;
+
+    // Configure left pipe
+    mdp_overlay &left_overlay = overlay_array[num_overlays];
+    msmfb_overlay_data &left_data = data_array[num_overlays];
+
+    left_overlay.id = left_pipe.pipe_id;
+    left_overlay.flags |= MDP_BLEND_FG_PREMULT;
+    left_overlay.transp_mask = 0xffffffff;
+    left_overlay.z_order = i;
+    left_overlay.alpha = layer.plane_alpha;
+    left_overlay.src.width = input_buffer->planes[0].stride;
+    left_overlay.src.height = input_buffer->height;
+    SetBlending(&left_overlay.blend_op, layer.blending);
+    SetFormat(&left_overlay.src.format, layer.input_buffer->format);
+    SetRect(&left_overlay.src_rect, left_pipe.src_roi);
+    SetRect(&left_overlay.dst_rect, left_pipe.dst_roi);
+    left_data.id = left_pipe.pipe_id;
+    left_data.data.memory_id = input_buffer->planes[0].fd;
+    left_data.data.offset = input_buffer->planes[0].offset;
+
+    num_overlays++;
+
+    // Configure right pipe
+    if (config.is_right_pipe) {
+      HWPipeInfo &right_pipe = config.right_pipe;
+      mdp_overlay &right_overlay = overlay_array[num_overlays];
+      msmfb_overlay_data &right_data = data_array[num_overlays];
+
+      right_overlay = left_overlay;
+      right_data = left_data;
+      right_overlay.id = right_pipe.pipe_id;
+      right_data.id = right_pipe.pipe_id;
+      SetRect(&right_overlay.src_rect, right_pipe.src_roi);
+      SetRect(&right_overlay.dst_rect, right_pipe.dst_roi);
+
+      num_overlays++;
+    }
+
+    if (input_buffer->acquire_fence_fd >= 0) {
+      acquire_fences[acquire_fence_count] = input_buffer->acquire_fence_fd;
+      acquire_fence_count++;
+    }
+  }
+
+  mdp_overlay *overlay_list[num_overlays];
+  msmfb_overlay_data *data_list[num_overlays];
+  for (uint32_t i = 0; i < num_overlays; i++) {
+    overlay_list[i] = &overlay_array[i];
+    data_list[i] = &data_array[i];
+  }
+
+  // TODO(user): Replace with Atomic commit call.
+  STRUCT_VAR(mdp_atomic_commit, atomic_commit);
+  atomic_commit.overlay_list = overlay_list;
+  atomic_commit.data_list = data_list;
+  atomic_commit.num_overlays = num_overlays;
+  atomic_commit.buf_sync.acq_fen_fd = acquire_fences;
+  atomic_commit.buf_sync.acq_fen_fd_cnt = acquire_fence_count;
+  atomic_commit.buf_sync.rel_fen_fd = &release_fence;
+  atomic_commit.buf_sync.retire_fen_fd = &retire_fence;
+  atomic_commit.buf_sync.flags = MDP_BUF_SYNC_FLAG_RETIRE_FENCE;
+
+  if (UNLIKELY(ioctl_(hw_context->device_fd, MSMFB_ATOMIC_COMMIT, &atomic_commit) == -1)) {
+    IOCTL_LOGE(MSMFB_ATOMIC_COMMIT);
+    return kErrorHardware;
+  }
+
+  // MDP returns only one release fence for the entire layer stack. Duplicate this fence into all
+  // layers being composed by MDP.
+  stack->retire_fence_fd = retire_fence;
+  for (uint32_t i = 0; i < hw_layer_info.count; i++) {
+    uint32_t layer_index = hw_layer_info.index[i];
+    Layer &layer = stack->layers.layer[layer_index];
+    LayerBuffer *input_buffer = layer.input_buffer;
+    input_buffer->release_fence_fd = dup(release_fence);
+  }
+  close(release_fence);
+
   return kErrorNone;
 }
 
+void HWFrameBuffer::SetFormat(uint32_t *target, const LayerBufferFormat &source) {
+  switch (source) {
+  default:
+    *target = MDP_RGBA_8888;
+    break;
+  }
+}
+
+void HWFrameBuffer::SetBlending(uint32_t *target, const LayerBlending &source) {
+  switch (source) {
+  case kBlendingPremultiplied:
+    *target = BLEND_OP_PREMULTIPLIED;
+    break;
+
+  case kBlendingCoverage:
+    *target = BLEND_OP_COVERAGE;
+    break;
+
+  default:
+    *target = BLEND_OP_NOT_DEFINED;
+    break;
+  }
+}
+
+void HWFrameBuffer::SetRect(mdp_rect *target, const LayerRect &source) {
+  target->x = INT(ceilf(source.left));
+  target->y = INT(ceilf(source.top));
+  target->w = INT(floorf(source.right)) - target->x;
+  target->h = INT(floorf(source.bottom)) - target->y;
+}
+
 }  // namespace sde
 
diff --git a/displayengine/libs/core/hw_framebuffer.h b/displayengine/libs/core/hw_framebuffer.h
index 59bd52b..d0c43c7 100644
--- a/displayengine/libs/core/hw_framebuffer.h
+++ b/displayengine/libs/core/hw_framebuffer.h
@@ -31,7 +31,7 @@
 namespace sde {
 
 struct HWContext {
-  HWInterfaceType type;
+  HWBlockType type;
   int device_fd;
 };
 
@@ -40,18 +40,24 @@
   HWFrameBuffer();
   DisplayError Init();
   DisplayError Deinit();
-  virtual DisplayError GetCapabilities(HWResourceInfo *hw_res_info);
-  virtual DisplayError Open(HWInterfaceType type, Handle *device);
+  virtual DisplayError GetHWCapabilities(HWResourceInfo *hw_res_info);
+  virtual DisplayError Open(HWBlockType type, Handle *device);
   virtual DisplayError Close(Handle device);
-  virtual DisplayError GetConfig(Handle device, DeviceConfigVariableInfo *variable_info);
+  virtual DisplayError GetNumDeviceAttributes(Handle device, uint32_t *count);
+  virtual DisplayError GetDeviceAttributes(Handle device, HWDeviceAttributes *device_attributes,
+                                       uint32_t mode);
   virtual DisplayError PowerOn(Handle device);
   virtual DisplayError PowerOff(Handle device);
   virtual DisplayError Doze(Handle device);
   virtual DisplayError Standby(Handle device);
-  virtual DisplayError Prepare(Handle device, HWLayers *hw_layers);
+  virtual DisplayError Validate(Handle device, HWLayers *hw_layers);
   virtual DisplayError Commit(Handle device, HWLayers *hw_layers);
 
  private:
+  inline void SetFormat(uint32_t *target, const LayerBufferFormat &source);
+  inline void SetBlending(uint32_t *target, const LayerBlending &source);
+  inline void SetRect(mdp_rect *target, const LayerRect &source);
+
   // For dynamically linking virtual driver
   int (*ioctl_)(int, int, ...);
   int (*open_)(const char *, int, ...);
diff --git a/displayengine/libs/core/hw_interface.h b/displayengine/libs/core/hw_interface.h
index ce74660..9653424 100644
--- a/displayengine/libs/core/hw_interface.h
+++ b/displayengine/libs/core/hw_interface.h
@@ -31,31 +31,89 @@
 
 namespace sde {
 
-enum HWInterfaceType {
+enum HWBlockType {
   kHWPrimary,
   kHWHDMI,
-  kHWWriteback,
+  kHWWriteback0,
+  kHWWriteback1,
+  kHWWriteback2,
+  kHWBlockMax
 };
 
 struct HWResourceInfo {
+  uint32_t mdp_version;
+  uint32_t hw_revision;
+  uint32_t num_dma_pipe;
+  uint32_t num_vig_pipe;
+  uint32_t num_rgb_pipe;
+  uint32_t num_rotator;
+  uint32_t num_control;
+  uint32_t num_mixer_to_disp;
+  uint32_t smp_total;
+  uint32_t smp_size;
+  uint32_t num_smp_per_pipe;
+  uint32_t max_scale_up;
+  uint32_t max_scale_down;
+  uint32_t max_bandwidth_low;
+  uint32_t max_bandwidth_high;
+  bool has_bwc;
+  bool has_decimation;
+  bool has_non_scalar_rgb;
+  bool is_src_split;
+  bool has_microtile;
+
+  HWResourceInfo()
+    : mdp_version(0), hw_revision(0), num_dma_pipe(0), num_vig_pipe(0),
+      num_rgb_pipe(0), num_rotator(0), num_control(0), num_mixer_to_disp(0), smp_total(0),
+      smp_size(0), num_smp_per_pipe(0), max_scale_up(0), max_scale_down(0), max_bandwidth_low(0),
+      max_bandwidth_high(0), has_bwc(false), has_decimation(false), has_non_scalar_rgb(false),
+      is_src_split(false), has_microtile(false) { }
+};
+
+struct HWPipeInfo {
+  uint32_t pipe_id;
+  LayerRect src_roi;
+  LayerRect dst_roi;
+
+  HWPipeInfo() : pipe_id(0) { }
+};
+
+struct HWLayerConfig {
+  bool use_non_dma_pipe;
+  bool is_right_pipe;
+  HWPipeInfo left_pipe;
+  HWPipeInfo right_pipe;
+
+  HWLayerConfig() : use_non_dma_pipe(false), is_right_pipe(true) { }
 };
 
 struct HWLayers {
+  HWLayersInfo info;
+  HWLayerConfig config[kNumLayersMax];
+};
+
+struct HWDeviceAttributes : DeviceConfigVariableInfo {
+  bool is_device_split;
+  uint32_t split_left;
+
+  HWDeviceAttributes() : is_device_split(false), split_left(0) { }
 };
 
 class HWInterface {
  public:
   static DisplayError Create(HWInterface **intf);
   static DisplayError Destroy(HWInterface *intf);
-  virtual DisplayError GetCapabilities(HWResourceInfo *hw_res_info) = 0;
-  virtual DisplayError Open(HWInterfaceType type, Handle *device) = 0;
+  virtual DisplayError GetHWCapabilities(HWResourceInfo *hw_res_info) = 0;
+  virtual DisplayError Open(HWBlockType type, Handle *device) = 0;
   virtual DisplayError Close(Handle device) = 0;
-  virtual DisplayError GetConfig(Handle device, DeviceConfigVariableInfo *variable_info) = 0;
+  virtual DisplayError GetNumDeviceAttributes(Handle device, uint32_t *count) = 0;
+  virtual DisplayError GetDeviceAttributes(Handle device, HWDeviceAttributes *device_attributes,
+                                       uint32_t mode) = 0;
   virtual DisplayError PowerOn(Handle device) = 0;
   virtual DisplayError PowerOff(Handle device) = 0;
   virtual DisplayError Doze(Handle device) = 0;
   virtual DisplayError Standby(Handle device) = 0;
-  virtual DisplayError Prepare(Handle device, HWLayers *hw_layers) = 0;
+  virtual DisplayError Validate(Handle device, HWLayers *hw_layers) = 0;
   virtual DisplayError Commit(Handle device, HWLayers *hw_layers) = 0;
 
  protected:
diff --git a/displayengine/libs/core/res_config.cpp b/displayengine/libs/core/res_config.cpp
new file mode 100644
index 0000000..a4cc8a2
--- /dev/null
+++ b/displayengine/libs/core/res_config.cpp
@@ -0,0 +1,236 @@
+/*
+* Copyright (c) 2014, 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.
+*/
+
+// DISPLAY_LOG_TAG definition must precede logger.h include.
+#define DISPLAY_LOG_TAG kTagCore
+#define DISPLAY_MODULE_NAME "ResConfig"
+#include <utils/logger.h>
+
+#include <utils/constants.h>
+#include <math.h>
+
+#include "res_manager.h"
+
+namespace sde {
+
+DisplayError ResManager::Config(ResManagerDevice *res_mgr_device, HWLayers *hw_layers) {
+  HWBlockType hw_block_id = res_mgr_device->hw_block_id;
+  HWDeviceAttributes &device_attributes = res_mgr_device->device_attributes;
+  HWLayersInfo &layer_info = hw_layers->info;
+
+  for (uint32_t i = 0; i < layer_info.count; i++) {
+    Layer& layer = layer_info.stack->layers.layer[layer_info.index[i]];
+    float w_scale, h_scale;
+    if (!IsValidDimension(layer, &w_scale, &h_scale)) {
+      DLOGV("Invalid dimension");
+      return kErrorNotSupported;
+    }
+
+    LayerRect scissor;
+    scissor.right = FLOAT(device_attributes.split_left);
+    scissor.bottom = FLOAT(device_attributes.y_pixels);
+    LayerRect crop = layer.src_rect;
+    LayerRect dst = layer.dst_rect;
+    LayerRect cropRight = crop;
+    LayerRect dstRight = dst;
+    CalculateCropRects(&crop, &dst, scissor, layer.transform);
+    HWPipeInfo *pipe_info = &hw_layers->config[i].left_pipe;
+
+    pipe_info->src_roi = crop;
+    pipe_info->dst_roi = dst;
+
+    float crop_width = cropRight.right - cropRight.left;
+    pipe_info = &hw_layers->config[i].right_pipe;
+    if ((dstRight.right - dstRight.left) > kMaxInterfaceWidth ||
+         crop_width > kMaxInterfaceWidth ||
+        ((hw_block_id == kHWPrimary) && hw_res_info_.is_src_split &&
+         (crop_width > device_attributes.split_left))) {
+      scissor.left = FLOAT(device_attributes.split_left);
+      scissor.top = 0.0f;
+      scissor.right = FLOAT(device_attributes.x_pixels);
+      scissor.bottom = FLOAT(device_attributes.y_pixels);
+      CalculateCropRects(&cropRight, &dstRight, scissor, layer.transform);
+      pipe_info->src_roi = cropRight;
+      pipe_info->dst_roi = dstRight;
+      pipe_info->pipe_id = -1;
+    } else {
+      // need not right pipe
+      pipe_info->pipe_id = 0;
+    }
+  }
+
+  return kErrorNone;
+}
+
+bool ResManager::IsValidDimension(const Layer& layer, float *width_scale, float *height_scale) {
+  if (IsNonIntegralSrcCrop(layer.src_rect)) {
+    return false;
+  }
+
+  LayerRect crop;
+  LayerRect dst;
+  IntegerizeRect(&crop, layer.src_rect);
+  IntegerizeRect(&dst, layer.dst_rect);
+
+  bool rotated90 = (static_cast<int>(layer.transform.rotation) == 90);
+  float crop_w = rotated90 ? crop.bottom - crop.top : crop.right - crop.left;
+  float crop_h = rotated90 ? crop.right - crop.left : crop.bottom - crop.top;
+  float dst_w = dst.right - dst.left;
+  float dst_h = dst.bottom - dst.top;
+
+  if ((dst_w < 1) || (dst_h < 1)) {
+    return false;
+  }
+
+  float w_scale = crop_w / dst_w;
+  float h_scale = crop_h / dst_h;
+
+  if ((crop_w < kMaxCropWidth) ||(crop_h < kMaxCropHeight)) {
+    return false;
+  }
+
+  if ((w_scale > 1.0f) || (h_scale > 1.0f)) {
+    const uint32_t max_scale_down = hw_res_info_.max_scale_down;
+
+    if (!hw_res_info_.has_decimation) {
+      if (crop_w > kMaxSourcePipeWidth || w_scale > max_scale_down || h_scale > max_scale_down) {
+        return false;
+      }
+    } else {
+      if (w_scale > max_scale_down || h_scale > max_scale_down) {
+        return false;
+      }
+    }
+  }
+
+  if (((w_scale < 1.0f) || (h_scale < 1.0f)) && (w_scale > 0.0f) && (h_scale > 0.0f)) {
+    const uint32_t max_scale_up = hw_res_info_.max_scale_up;
+    const float w_uscale = 1.0f / w_scale;
+    const float h_uscale = 1.0f / h_scale;
+
+    if (w_uscale > max_scale_up || h_uscale > max_scale_up) {
+      return false;
+    }
+  }
+
+  *width_scale = w_scale;
+  *height_scale = h_scale;
+
+  return true;
+}
+
+void ResManager::CalculateCut(float *left_cut_ratio,
+    float *top_cut_ratio, float *right_cut_ratio, float *bottom_cut_ratio,
+    const LayerTransform& transform) {
+  if (transform.flip_horizontal) {
+    Swap(*left_cut_ratio, *right_cut_ratio);
+  }
+
+  if (transform.flip_vertical) {
+    Swap(*top_cut_ratio, *bottom_cut_ratio);
+  }
+
+  if (UINT32(transform.rotation) == 90) {
+    // Anti clock swapping
+    float tmp_cut_ratio = *left_cut_ratio;
+    *left_cut_ratio = *top_cut_ratio;
+    *top_cut_ratio = *right_cut_ratio;
+    *right_cut_ratio = *bottom_cut_ratio;
+    *bottom_cut_ratio = tmp_cut_ratio;
+  }
+}
+
+void ResManager::CalculateCropRects(LayerRect *crop, LayerRect *dst,
+    const LayerRect& scissor, const LayerTransform& transform) {
+  float& crop_l = crop->left;
+  float& crop_t = crop->top;
+  float& crop_r = crop->right;
+  float& crop_b = crop->bottom;
+  float crop_w = crop->right - crop->left;
+  float crop_h = crop->bottom - crop->top;
+
+  float& dst_l = dst->left;
+  float& dst_t = dst->top;
+  float& dst_r = dst->right;
+  float& dst_b = dst->bottom;
+  float dst_w = (dst->right > dst->left) ? dst->right - dst->left :
+    dst->left - dst->right;
+  float dst_h = (dst->bottom > dst->top) ? dst->bottom > dst->top :
+    dst->top > dst->bottom;
+
+  const float& sci_l = scissor.left;
+  const float& sci_t = scissor.top;
+  const float& sci_r = scissor.right;
+  const float& sci_b = scissor.bottom;
+
+  float left_cut_ratio = 0.0, right_cut_ratio = 0.0, top_cut_ratio = 0.0,
+    bottom_cut_ratio = 0.0;
+
+  if (dst_l < sci_l) {
+    left_cut_ratio = (sci_l - dst_l) / dst_w;
+    dst_l = sci_l;
+  }
+
+  if (dst_r > sci_r) {
+    right_cut_ratio = (dst_r - sci_r) / dst_w;
+    dst_r = sci_r;
+  }
+
+  if (dst_t < sci_t) {
+    top_cut_ratio = (sci_t - dst_t) / (dst_h);
+    dst_t = sci_t;
+  }
+
+  if (dst_b > sci_b) {
+    bottom_cut_ratio = (dst_b - sci_b) / (dst_h);
+    dst_b = sci_b;
+  }
+
+  CalculateCut(&left_cut_ratio, &top_cut_ratio, &right_cut_ratio, &bottom_cut_ratio, transform);
+  crop_l += crop_w * left_cut_ratio;
+  crop_t += crop_h * top_cut_ratio;
+  crop_r -= crop_w * right_cut_ratio;
+  crop_b -= crop_h * bottom_cut_ratio;
+}
+
+bool ResManager::IsNonIntegralSrcCrop(const LayerRect& crop) {
+  if (crop.left - roundf(crop.left)     ||
+      crop.top - roundf(crop.top)       ||
+      crop.right - roundf(crop.right)   ||
+      crop.bottom - roundf(crop.bottom)) {
+    return true;
+  } else {
+    return false;
+  }
+}
+
+void ResManager::IntegerizeRect(LayerRect *dst_rect, const LayerRect &src_rect) {
+  dst_rect->left = ceilf(src_rect.left);
+  dst_rect->top = ceilf(src_rect.top);
+  dst_rect->right = floorf(src_rect.right);
+  dst_rect->bottom = floorf(src_rect.bottom);
+}
+
+}  // namespace sde
+
diff --git a/displayengine/libs/core/res_manager.cpp b/displayengine/libs/core/res_manager.cpp
index 1c487bf..66a3ae3 100644
--- a/displayengine/libs/core/res_manager.cpp
+++ b/displayengine/libs/core/res_manager.cpp
@@ -33,7 +33,58 @@
 
 namespace sde {
 
-DisplayError ResManager::Init() {
+ResManager::ResManager()
+  : num_pipe_(0), vig_pipes_(NULL), rgb_pipes_(NULL), dma_pipes_(NULL), frame_start_(false) {
+}
+
+DisplayError ResManager::Init(const HWResourceInfo &hw_res_info) {
+  DLOGV("Init");
+
+  hw_res_info_ = hw_res_info;
+
+  DisplayError error = kErrorNone;
+
+  num_pipe_ = hw_res_info_.num_vig_pipe + hw_res_info_.num_rgb_pipe + hw_res_info_.num_dma_pipe;
+
+  if (UNLIKELY(num_pipe_ > kPipeIdMax)) {
+    DLOGE("Number of pipe is over the limit! %d", num_pipe_);
+    return kErrorParameters;
+  }
+
+  // Init pipe info
+  vig_pipes_ = &src_pipes_[0];
+  rgb_pipes_ = &src_pipes_[hw_res_info_.num_vig_pipe];
+  dma_pipes_ = &src_pipes_[hw_res_info_.num_vig_pipe + hw_res_info_.num_rgb_pipe];
+
+  for (uint32_t i = 0; i < hw_res_info_.num_vig_pipe; i++) {
+    vig_pipes_[i].type = kPipeTypeVIG;
+    vig_pipes_[i].index = i;
+    vig_pipes_[i].mdss_pipe_id = GetMdssPipeId(vig_pipes_[i].type, i);
+  }
+
+  for (uint32_t i = 0; i < hw_res_info_.num_rgb_pipe; i++) {
+    rgb_pipes_[i].type = kPipeTypeRGB;
+    rgb_pipes_[i].index = i + hw_res_info_.num_vig_pipe;
+    rgb_pipes_[i].mdss_pipe_id = GetMdssPipeId(rgb_pipes_[i].type, i);
+  }
+
+  for (uint32_t i = 0; i < hw_res_info_.num_dma_pipe; i++) {
+    dma_pipes_[i].type = kPipeTypeDMA;
+    dma_pipes_[i].index = i + hw_res_info_.num_vig_pipe + hw_res_info_.num_rgb_pipe;
+    dma_pipes_[i].mdss_pipe_id = GetMdssPipeId(dma_pipes_[i].type, i);
+  }
+
+  for (uint32_t i = 0; i < num_pipe_; i++) {
+    src_pipes_[i].priority = i;
+  }
+
+  DLOGI("hw_rev=%x, DMA=%d RGB=%d VIG=%d", hw_res_info_.hw_revision, hw_res_info_.num_dma_pipe,
+    hw_res_info_.num_rgb_pipe, hw_res_info_.num_vig_pipe);
+
+  // Used by splash screen
+  rgb_pipes_[0].state = kPipeStateOwnedByKernel;
+  rgb_pipes_[1].state = kPipeStateOwnedByKernel;
+
   return kErrorNone;
 }
 
@@ -41,5 +92,354 @@
   return kErrorNone;
 }
 
+DisplayError ResManager::RegisterDevice(DeviceType type, const HWDeviceAttributes &attributes,
+                                        Handle *device) {
+  DisplayError error = kErrorNone;
+
+  HWBlockType hw_block_id = kHWBlockMax;
+  switch (type) {
+  case kPrimary:
+    if (UNLIKELY(!hw_block_ctx_[kHWPrimary].is_in_use)) {
+      hw_block_id = kHWPrimary;
+    }
+    break;
+
+  case kHDMI:
+    if (UNLIKELY(!hw_block_ctx_[kHWHDMI].is_in_use)) {
+      hw_block_id = kHWHDMI;
+    }
+    break;
+
+  case kVirtual:
+    // assume only WB2 can be used for vitrual display
+    if (UNLIKELY(!hw_block_ctx_[kHWWriteback2].is_in_use)) {
+      hw_block_id = kHWWriteback2;
+    }
+    break;
+
+  default:
+    DLOGW("RegisterDevice, invalid type %d", type);
+    return kErrorParameters;
+  }
+
+  if (UNLIKELY(hw_block_id == kHWBlockMax)) {
+    return kErrorResources;
+  }
+
+  ResManagerDevice *res_mgr_device = new ResManagerDevice();
+  if (UNLIKELY(!res_mgr_device)) {
+    return kErrorMemory;
+  }
+
+  hw_block_ctx_[hw_block_id].is_in_use = true;
+
+  res_mgr_device->device_attributes = attributes;
+  res_mgr_device->device_type = type;
+  res_mgr_device->hw_block_id = hw_block_id;
+
+  *device = res_mgr_device;
+
+  return kErrorNone;
+}
+
+DisplayError ResManager::UnregisterDevice(Handle device) {
+  ResManagerDevice *res_mgr_device = reinterpret_cast<ResManagerDevice *>(device);
+
+  Purge(device);
+  hw_block_ctx_[res_mgr_device->hw_block_id].is_in_use = false;
+  delete res_mgr_device;
+
+  return kErrorNone;
+}
+
+
+DisplayError ResManager::Start(Handle device) {
+  locker_.Lock();
+
+  ResManagerDevice *res_mgr_device = reinterpret_cast<ResManagerDevice *>(device);
+
+  if (frame_start_) {
+    return kErrorNone;  // keep context locked.
+  }
+
+  // First call in the cycle
+  frame_start_ = true;
+  res_mgr_device->frame_count++;
+
+  // Release the pipes not used in the previous cycle
+  HWBlockType hw_block_id = res_mgr_device->hw_block_id;
+  for (uint32_t i = 0; i < num_pipe_; i++) {
+    if ((src_pipes_[i].hw_block_id == hw_block_id) &&
+        (src_pipes_[i].state == kPipeStateToRelease)) {
+      src_pipes_[i].state = kPipeStateIdle;
+    }
+  }
+  return kErrorNone;
+}
+
+DisplayError ResManager::Stop(Handle device) {
+  locker_.Unlock();
+
+  ResManagerDevice *res_mgr_device = reinterpret_cast<ResManagerDevice *>(device);
+
+  return kErrorNone;
+}
+
+DisplayError ResManager::Acquire(Handle device, HWLayers *hw_layers) {
+  ResManagerDevice *res_mgr_device = reinterpret_cast<ResManagerDevice *>(device);
+
+  DisplayError error = kErrorNone;
+  const struct HWLayersInfo &layer_info = hw_layers->info;
+
+  if (UNLIKELY(!layer_info.count)) {
+    return kErrorNone;
+  }
+
+  if (UNLIKELY(layer_info.count > num_pipe_)) {
+    return kErrorResources;
+  }
+
+  error = Config(res_mgr_device, hw_layers);
+  if (UNLIKELY(error != kErrorNone)) {
+    return error;
+  }
+
+  uint32_t left_index = 0;
+  bool need_scale = false;
+  HWBlockType hw_block_id = res_mgr_device->hw_block_id;
+
+  // Clear reserved marking
+  for (uint32_t i = 0; i < num_pipe_; i++) {
+    src_pipes_[i].reserved = false;
+  }
+
+  for (uint32_t i = 0; i < layer_info.count; i++) {
+    Layer &layer = layer_info.stack->layers.layer[layer_info.index[i]];
+    bool use_non_dma_pipe = hw_layers->config[i].use_non_dma_pipe;
+
+    // Temp setting, this should be set by comp_manager
+    if (hw_block_id == kHWPrimary) {
+      use_non_dma_pipe = true;
+    }
+
+    HWPipeInfo *pipe_info = &hw_layers->config[i].left_pipe;
+
+    need_scale = IsScalingNeeded(pipe_info);
+
+    // Should have a generic macro
+    bool is_yuv = (layer.input_buffer->format >= kFormatYCbCr420Planar);
+
+    left_index = GetPipe(hw_block_id, is_yuv, need_scale, false, use_non_dma_pipe);
+    if (left_index >= num_pipe_) {
+      goto Acquire_failed;
+    }
+
+    src_pipes_[left_index].reserved = true;
+
+    pipe_info =  &hw_layers->config[i].right_pipe;
+    if (pipe_info->pipe_id == 0) {
+      // assign single pipe
+      hw_layers->config[i].left_pipe.pipe_id = src_pipes_[left_index].mdss_pipe_id;
+      src_pipes_[left_index].at_right = false;
+      continue;
+    }
+
+    need_scale = IsScalingNeeded(pipe_info);
+
+    uint32_t right_index;
+    right_index = GetPipe(hw_block_id, is_yuv, need_scale, true, use_non_dma_pipe);
+    if (right_index >= num_pipe_) {
+      goto Acquire_failed;
+    }
+
+    if (src_pipes_[right_index].priority < src_pipes_[left_index].priority) {
+      // Swap pipe based on priority
+      Swap(left_index, right_index);
+    }
+
+    // assign dual pipes
+    hw_layers->config[i].right_pipe.pipe_id = src_pipes_[right_index].mdss_pipe_id;
+    src_pipes_[right_index].reserved = true;
+    src_pipes_[right_index].at_right = true;
+    src_pipes_[left_index].reserved = true;
+    src_pipes_[left_index].at_right = false;
+    hw_layers->config[i].left_pipe.pipe_id = src_pipes_[left_index].mdss_pipe_id;
+  }
+
+  return kErrorNone;
+
+Acquire_failed:
+  for (uint32_t i = 0; i < num_pipe_; i++)
+    src_pipes_[i].reserved = false;
+  return kErrorResources;
+}
+
+void ResManager::PostCommit(Handle device, HWLayers *hw_layers) {
+  ResManagerDevice *res_mgr_device = reinterpret_cast<ResManagerDevice *>(device);
+  HWBlockType hw_block_id = res_mgr_device->hw_block_id;
+  uint64_t frame_count = res_mgr_device->frame_count;
+
+  DLOGV("Resource for hw_block=%d frame_count=%d", hw_block_id, frame_count);
+
+  for (uint32_t i = 0; i < num_pipe_; i++) {
+    if (src_pipes_[i].reserved) {
+      src_pipes_[i].hw_block_id = hw_block_id;
+      src_pipes_[i].state = kPipeStateAcquired;
+      src_pipes_[i].state_frame_count = frame_count;
+      DLOGV("Pipe acquired index=%d type=%d pipe_id=%x", i, src_pipes_[i].type,
+            src_pipes_[i].mdss_pipe_id);
+    } else if ((src_pipes_[i].hw_block_id == hw_block_id) &&
+               (src_pipes_[i].state == kPipeStateAcquired)) {
+      src_pipes_[i].state = kPipeStateToRelease;
+      src_pipes_[i].state_frame_count = frame_count;
+      DLOGV("Pipe to release index=%d type=%d pipe_id=%x", i, src_pipes_[i].type,
+            src_pipes_[i].mdss_pipe_id);
+    }
+  }
+
+  // handoff pipes which are used by splash screen
+  if (UNLIKELY((frame_count == 1) && (hw_block_id == kHWPrimary))) {
+    for (uint32_t i = 0; i < num_pipe_; i++) {
+      if ((src_pipes_[i].state == kPipeStateOwnedByKernel)) {
+        src_pipes_[i].state = kPipeStateToRelease;
+        src_pipes_[i].hw_block_id = kHWPrimary;
+      }
+    }
+  }
+
+  frame_start_ = false;
+}
+
+void ResManager::Purge(Handle device) {
+  SCOPE_LOCK(locker_);
+
+  ResManagerDevice *res_mgr_device = reinterpret_cast<ResManagerDevice *>(device);
+  HWBlockType hw_block_id = res_mgr_device->hw_block_id;
+
+  for (uint32_t i = 0; i < num_pipe_; i++) {
+    if (src_pipes_[i].hw_block_id == hw_block_id)
+      src_pipes_[i].state = kPipeStateIdle;
+  }
+}
+
+
+uint32_t ResManager::GetMdssPipeId(PipeType type, uint32_t index) {
+  uint32_t mdss_id = kPipeIdMax;
+  switch (type) {
+  case kPipeTypeVIG:
+    if (index < 3) {
+      mdss_id = kPipeIdVIG0 + index;
+    } else if (index == 3) {
+      mdss_id = kPipeIdVIG3;
+    } else {
+      DLOGE("vig pipe index is over the limit! %d", index);
+    }
+    break;
+  case kPipeTypeRGB:
+    if (index < 3) {
+      mdss_id = kPipeIdRGB0 + index;
+    } else if (index == 3) {
+      mdss_id = kPipeIdRGB3;
+    } else {
+      DLOGE("rgb pipe index is over the limit! %d", index);
+    }
+    break;
+  case kPipeTypeDMA:
+    if (index < 2) {
+      mdss_id = kPipeIdDMA0 + index;
+    } else {
+      DLOGE("dma pipe index is over the limit! %d", index);
+    }
+    break;
+  default:
+    DLOGE("wrong pipe type! %d", type);
+    break;
+  }
+
+  return (1 << mdss_id);
+}
+
+uint32_t ResManager::NextPipe(PipeType type, HWBlockType hw_block_id, bool at_right) {
+  uint32_t num_pipe = 0;
+  uint32_t index = kPipeIdMax;
+  SourcePipe *src_pipe = NULL;
+
+  switch (type) {
+  case kPipeTypeVIG:
+    src_pipe = vig_pipes_;
+    num_pipe = hw_res_info_.num_vig_pipe;
+    break;
+  case kPipeTypeRGB:
+    src_pipe = rgb_pipes_;
+    num_pipe = hw_res_info_.num_rgb_pipe;
+    break;
+  case kPipeTypeDMA:
+  default:
+    src_pipe = dma_pipes_;
+    num_pipe = hw_res_info_.num_dma_pipe;
+    break;
+  }
+
+  // search the pipe being used
+  for (uint32_t i = 0; i < num_pipe; i++) {
+    if (!src_pipe[i].reserved &&
+        (src_pipe[i].state == kPipeStateAcquired) &&
+        (src_pipe[i].hw_block_id == hw_block_id) &&
+        (src_pipe[i].at_right == at_right)) {
+      index = src_pipe[i].index;
+      break;
+    }
+  }
+
+  // found
+  if (index < num_pipe_) {
+    return index;
+  }
+
+  for (uint32_t i = 0; i < num_pipe; i++) {
+    if (!src_pipe[i].reserved &&
+        ((src_pipe[i].state == kPipeStateIdle) ||
+         ((src_pipe[i].state == kPipeStateAcquired) &&
+         (src_pipe[i].hw_block_id == hw_block_id)))) {
+      index = src_pipe[i].index;
+      break;
+    }
+  }
+
+  return index;
+}
+
+uint32_t ResManager::GetPipe(HWBlockType hw_block_id, bool is_yuv, bool need_scale, bool at_right,
+                             bool use_non_dma_pipe) {
+  uint32_t index = kPipeIdMax;
+
+  // The default behavior is to assume RGB and VG pipes have scalars
+  if (is_yuv) {
+    return NextPipe(kPipeTypeVIG, hw_block_id, at_right);
+  } else {
+    if (!need_scale && !use_non_dma_pipe) {
+      index = NextPipe(kPipeTypeDMA, hw_block_id, at_right);
+    }
+
+    if ((index >= num_pipe_) && (!need_scale || hw_res_info_.has_non_scalar_rgb)) {
+      index = NextPipe(kPipeTypeRGB, hw_block_id, at_right);
+    }
+
+    if (index >= num_pipe_) {
+      index = NextPipe(kPipeTypeVIG, hw_block_id, at_right);
+    }
+  }
+
+  return index;
+}
+
+bool ResManager::IsScalingNeeded(const HWPipeInfo *pipe_info) {
+  const LayerRect &src_roi = pipe_info->src_roi;
+  const LayerRect &dst_roi = pipe_info->dst_roi;
+
+  return ((dst_roi.right - dst_roi.left) != (src_roi.right - src_roi.left)) ||
+          ((dst_roi.bottom - dst_roi.top) != (src_roi.bottom - src_roi.top));
+}
+
 }  // namespace sde
 
diff --git a/displayengine/libs/core/res_manager.h b/displayengine/libs/core/res_manager.h
index 9fa7657..9199c15 100644
--- a/displayengine/libs/core/res_manager.h
+++ b/displayengine/libs/core/res_manager.h
@@ -34,10 +34,116 @@
 
 class ResManager {
  public:
-  DisplayError Init();
+  ResManager();
+  DisplayError Init(const HWResourceInfo &hw_res_info);
   DisplayError Deinit();
+  DisplayError RegisterDevice(DeviceType type, const HWDeviceAttributes &attributes,
+                              Handle *device);
+  DisplayError UnregisterDevice(Handle device);
+  DisplayError Start(Handle device);
+  DisplayError Stop(Handle device);
+  DisplayError Acquire(Handle device, HWLayers *hw_layers);
+  void PostCommit(Handle device, HWLayers *hw_layers);
+  void Purge(Handle device);
 
  private:
+  enum PipeId {
+    kPipeIdVIG0,
+    kPipeIdVIG1,
+    kPipeIdVIG2,
+    kPipeIdRGB0,
+    kPipeIdRGB1,
+    kPipeIdRGB2,
+    kPipeIdDMA0,
+    kPipeIdDMA1,
+    kPipeIdVIG3,
+    kPipeIdRGB3,
+    kPipeIdMax,
+  };
+
+  enum PipeType {
+    kPipeTypeUnused,
+    kPipeTypeVIG,
+    kPipeTypeRGB,
+    kPipeTypeDMA,
+    kPipeTypeMax,
+  };
+
+  enum PipeState {
+    kPipeStateIdle,           // Pipe state when it is available for reservation
+    kPipeStateAcquired,       // Pipe state after successful commit
+    kPipeStateToRelease,      // Pipe state that can be moved to Idle when releasefence is signaled
+    kPipeStateOwnedByKernel,  // Pipe state when pipe is owned by kernel
+  };
+
+  enum {
+    kMaxSourcePipeWidth = 2048,
+    kMaxInterfaceWidth = 2048,
+    kMaxCropWidth = 5,
+    kMaxCropHeight = 5,
+  };
+
+  struct SourcePipe {
+    PipeType type;
+    uint32_t mdss_pipe_id;
+    uint32_t index;
+    PipeState state;
+    HWBlockType hw_block_id;
+    bool at_right;
+    uint64_t state_frame_count;
+    int priority;
+    bool reserved;
+
+    SourcePipe() : type(kPipeTypeUnused), mdss_pipe_id(kPipeIdMax), index(0), state(kPipeStateIdle),
+                   hw_block_id(kHWBlockMax), at_right(false), state_frame_count(0), priority(0),
+                   reserved(false) { }
+  };
+
+  struct ResManagerDevice {
+    HWDeviceAttributes device_attributes;
+    DeviceType device_type;
+    HWBlockType hw_block_id;
+    uint64_t frame_count;
+    int32_t session_id;  // applicable for virtual display sessions only
+
+    ResManagerDevice() : hw_block_id(kHWBlockMax), frame_count(0), session_id(-1) { }
+  };
+
+  struct HWBlockContext {
+    bool is_in_use;
+    HWBlockContext() : is_in_use(false) { }
+  };
+
+  uint32_t GetMdssPipeId(PipeType pipe_type, uint32_t index);
+  uint32_t NextPipe(PipeType pipe_type, HWBlockType hw_block_id, bool at_right);
+  uint32_t GetPipe(HWBlockType hw_block_id, bool is_yuv, bool need_scale, bool at_right,
+                   bool use_non_dma_pipe);
+  bool IsScalingNeeded(const HWPipeInfo *pipe_info);
+  DisplayError Config(ResManagerDevice *res_mgr_device, HWLayers *hw_layers);
+  bool IsValidDimension(const Layer &layer, float *width_scale, float *height_scale);
+  void CalculateCut(float *left_cut_ratio, float *top_cut_ratio, float *right_cut_ratio,
+                    float *bottom_cut_ratio, const LayerTransform &transform);
+  void CalculateCropRects(LayerRect *crop, LayerRect *dst,
+                          const LayerRect &scissor, const LayerTransform &transform);
+  bool IsNonIntegralSrcCrop(const LayerRect &crop);
+  void IntegerizeRect(LayerRect *dst_rect, const LayerRect &src_rect);
+
+  template <class T>
+  inline void Swap(T &a, T &b) {
+    T c(a);
+    a = b;
+    b = c;
+  }
+
+  Locker locker_;
+  HWResourceInfo hw_res_info_;
+  HWBlockContext hw_block_ctx_[kHWBlockMax];
+  SourcePipe src_pipes_[kPipeIdMax];
+  uint32_t num_pipe_;
+  SourcePipe *vig_pipes_;
+  SourcePipe *rgb_pipes_;
+  SourcePipe *dma_pipes_;
+  bool frame_start_;
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/core/strategy_default.cpp b/displayengine/libs/core/strategy_default.cpp
index ba5ae99..4e824d5 100644
--- a/displayengine/libs/core/strategy_default.cpp
+++ b/displayengine/libs/core/strategy_default.cpp
@@ -35,6 +35,27 @@
 
 DisplayError StrategyDefault::GetNextStrategy(StrategyConstraints *constraints,
                                               HWLayersInfo *hw_layers_info) {
+  // Mark all layers for GPU composition. Find GPU target buffer and store its index for programming
+  // the hardware.
+  LayerArray &layer_array = hw_layers_info->stack->layers;
+  uint32_t &hw_layer_count = hw_layers_info->count;
+
+  hw_layer_count = 0;
+  for (uint32_t i = 0; i < layer_array.count; i++) {
+    LayerComposition &composition = layer_array.layer[i].composition;
+    if (composition != kCompositionGPUTarget) {
+      composition = kCompositionGPU;
+    } else {
+      hw_layers_info->index[hw_layer_count++] = i;
+    }
+  }
+
+  // There can be one and only one GPU target buffer.
+  if (hw_layer_count != 1) {
+    return kErrorParameters;
+  }
+
+  hw_layers_info->flags |= kFlagGPU;
 
   return kErrorNone;
 }
diff --git a/displayengine/libs/core/writeback_session.cpp b/displayengine/libs/core/writeback_session.cpp
index 53eb4ec..d49381a 100644
--- a/displayengine/libs/core/writeback_session.cpp
+++ b/displayengine/libs/core/writeback_session.cpp
@@ -33,7 +33,11 @@
 
 namespace sde {
 
-DisplayError WritebackSession::Init() {
+WritebackSession::WritebackSession() : hw_intf_(NULL) {
+}
+
+DisplayError WritebackSession::Init(HWInterface *hw_intf, HWResourceInfo hw_res_info) {
+  hw_intf_ = hw_intf;
   return kErrorNone;
 }
 
diff --git a/displayengine/libs/core/writeback_session.h b/displayengine/libs/core/writeback_session.h
index daf18c3..ed6b938 100644
--- a/displayengine/libs/core/writeback_session.h
+++ b/displayengine/libs/core/writeback_session.h
@@ -33,10 +33,12 @@
 
 class WritebackSession {
  public:
-  DisplayError Init();
+  WritebackSession();
+  DisplayError Init(HWInterface *hw_intf, HWResourceInfo hw_res_info);
   DisplayError Deinit();
 
  private:
+  HWInterface *hw_intf_;
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/hwc/hwc_session.cpp b/displayengine/libs/hwc/hwc_session.cpp
index 10e99b4..b9f9994 100644
--- a/displayengine/libs/hwc/hwc_session.cpp
+++ b/displayengine/libs/hwc/hwc_session.cpp
@@ -66,41 +66,199 @@
 }
 
 int HWCSession::Init() {
+  DisplayError error = CoreInterface::CreateCore(this, &core_intf_);
+  if (UNLIKELY(error != kErrorNone)) {
+    DLOGE("Display core initialization failed. Error = %d", error);
+    return -EINVAL;
+  }
+
+  int status = -EINVAL;
+
+  // Create and power on primary display
+  sink_primary_ = new HWCSinkPrimary(core_intf_, &hwc_procs_);
+  if (UNLIKELY(!sink_primary_)) {
+    CoreInterface::DestroyCore();
+    return -ENOMEM;
+  }
+
+  status = sink_primary_->Init();
+  if (UNLIKELY(status)) {
+    CoreInterface::DestroyCore();
+    delete sink_primary_;
+    return status;
+  }
+
+  status = sink_primary_->PowerOn();
+  if (UNLIKELY(status)) {
+    CoreInterface::DestroyCore();
+    sink_primary_->Deinit();
+    delete sink_primary_;
+    return status;
+  }
+
   return 0;
 }
 
 int HWCSession::Deinit() {
+  sink_primary_->PowerOff();
+  sink_primary_->Deinit();
+  delete sink_primary_;
+
+  DisplayError error = CoreInterface::DestroyCore();
+  if (error != kErrorNone) {
+    DLOGE("Display core de-initialization failed. Error = %d", error);
+  }
+
   return 0;
 }
 
 int HWCSession::Open(const hw_module_t *module, const char *name, hw_device_t **device) {
+  if (UNLIKELY(!module || !name || !device)) {
+    DLOGE("::%s Invalid parameters.", __FUNCTION__);
+    return -EINVAL;
+  }
+
+  if (LIKELY(!strcmp(name, HWC_HARDWARE_COMPOSER))) {
+    HWCSession *hwc_session = new HWCSession(module);
+    if (UNLIKELY(!hwc_session)) {
+      return -ENOMEM;
+    }
+
+    int status = hwc_session->Init();
+    if (UNLIKELY(status != 0)) {
+      delete hwc_session;
+      return status;
+    }
+
+    hwc_composer_device_1_t *composer_device = hwc_session;
+    *device = reinterpret_cast<hw_device_t *>(composer_device);
+  }
+
   return 0;
 }
 
 int HWCSession::Close(hw_device_t *device) {
+  if (UNLIKELY(!device)) {
+    return -EINVAL;
+  }
+
+  hwc_composer_device_1_t *composer_device = reinterpret_cast<hwc_composer_device_1_t *>(device);
+  HWCSession *hwc_session = static_cast<HWCSession *>(composer_device);
+
+  hwc_session->Deinit();
+  delete hwc_session;
+
   return 0;
 }
 
 int HWCSession::Prepare(hwc_composer_device_1 *device, size_t num_displays,
                         hwc_display_contents_1_t **displays) {
-  return 0;
+  if (UNLIKELY(!device || !displays)) {
+    return -EINVAL;
+  }
+
+  HWCSession *hwc_session = static_cast<HWCSession *>(device);
+  int status = -EINVAL;
+
+  for (size_t i = 0; i < num_displays; i++) {
+    hwc_display_contents_1_t *content_list = displays[i];
+    if (UNLIKELY(!content_list || !content_list->numHwLayers)) {
+      DLOGE("::%s Invalid content list.", __FUNCTION__);
+      return -EINVAL;
+    }
+
+    switch (i) {
+    case HWC_DISPLAY_PRIMARY:
+      status = hwc_session->sink_primary_->Prepare(content_list);
+      break;
+    default:
+      status = -EINVAL;
+    }
+
+    if (UNLIKELY(!status)) {
+      break;
+    }
+  }
+
+  return status;
 }
 
 int HWCSession::Set(hwc_composer_device_1 *device, size_t num_displays,
                     hwc_display_contents_1_t **displays) {
-  return 0;
+  if (UNLIKELY(!device || !displays)) {
+    return -EINVAL;
+  }
+
+  HWCSession *hwc_session = static_cast<HWCSession *>(device);
+  int status = -EINVAL;
+
+  for (size_t i = 0; i < num_displays; i++) {
+    hwc_display_contents_1_t *content_list = displays[i];
+    if (UNLIKELY(!content_list || !content_list->numHwLayers)) {
+      DLOGE("::%s Invalid content list.", __FUNCTION__);
+      return -EINVAL;
+    }
+
+    switch (i) {
+    case HWC_DISPLAY_PRIMARY:
+      status = hwc_session->sink_primary_->Commit(content_list);
+      break;
+    default:
+      status = -EINVAL;
+    }
+
+    if (UNLIKELY(!status)) {
+      break;
+    }
+  }
+
+  return status;
 }
 
 int HWCSession::EventControl(hwc_composer_device_1 *device, int disp, int event, int enable) {
+  if (UNLIKELY(!device)) {
+    return -EINVAL;
+  }
+
+  HWCSession *hwc_session = static_cast<HWCSession *>(device);
+  int status = -EINVAL;
+
+  switch (disp) {
+  case HWC_DISPLAY_PRIMARY:
+    status = hwc_session->sink_primary_->EventControl(event, enable);
+    break;
+  default:
+    status = -EINVAL;
+  }
+
   return 0;
 }
 
 int HWCSession::Blank(hwc_composer_device_1 *device, int disp, int blank) {
-  return 0;
+  if (UNLIKELY(!device)) {
+    return -EINVAL;
+  }
+
+  HWCSession *hwc_session = static_cast<HWCSession *>(device);
+  int status = -EINVAL;
+
+  switch (disp) {
+  case HWC_DISPLAY_PRIMARY:
+    status = hwc_session->sink_primary_->Blank(blank);
+    break;
+  default:
+    status = -EINVAL;
+  }
+
+  return status;
 }
 
 int HWCSession::Query(hwc_composer_device_1 *device, int param, int *value) {
-  return 0;
+  if (UNLIKELY(!device || !value)) {
+    return -EINVAL;
+  }
+
+  return -EINVAL;
 }
 
 void HWCSession::RegisterProcs(hwc_composer_device_1 *device, hwc_procs_t const *procs) {
@@ -113,16 +271,51 @@
 }
 
 void HWCSession::Dump(hwc_composer_device_1 *device, char *buffer, int length) {
+  if (UNLIKELY(!device || !buffer || !length)) {
+    return;
+  }
+
+  DebugInterface::GetDump(reinterpret_cast<uint8_t *>(buffer), length);
 }
 
 int HWCSession::GetDisplayConfigs(hwc_composer_device_1 *device, int disp, uint32_t *configs,
                                   size_t *num_configs) {
-  return 0;
+  if (UNLIKELY(!device || !configs || !num_configs)) {
+    return -EINVAL;
+  }
+
+  HWCSession *hwc_session = static_cast<HWCSession *>(device);
+  int status = -EINVAL;
+
+  switch (disp) {
+  case HWC_DISPLAY_PRIMARY:
+    status = hwc_session->sink_primary_->GetDisplayConfigs(configs, num_configs);
+    break;
+  default:
+    status = -EINVAL;
+  }
+
+  return status;
 }
 
 int HWCSession::GetDisplayAttributes(hwc_composer_device_1 *device, int disp, uint32_t config,
                                      const uint32_t *attributes, int32_t *values) {
-  return 0;
+  if (UNLIKELY(!device || !attributes || !values)) {
+    return -EINVAL;
+  }
+
+  HWCSession *hwc_session = static_cast<HWCSession *>(device);
+  int status = -EINVAL;
+
+  switch (disp) {
+  case HWC_DISPLAY_PRIMARY:
+    status = hwc_session->sink_primary_->GetDisplayAttributes(config, attributes, values);
+    break;
+  default:
+    status = -EINVAL;
+  }
+
+  return status;
 }
 
 DisplayError HWCSession::Hotplug(const CoreEventHotplug &hotplug) {
diff --git a/displayengine/libs/hwc/hwc_sink.cpp b/displayengine/libs/hwc/hwc_sink.cpp
index 6aee841..33ba62d 100644
--- a/displayengine/libs/hwc/hwc_sink.cpp
+++ b/displayengine/libs/hwc/hwc_sink.cpp
@@ -34,38 +34,366 @@
 
 namespace sde {
 
-HWCSink::HWCSink(CoreInterface *core_intf, hwc_procs_t const *hwc_procs, DeviceType type, int id)
-  : core_intf_(core_intf), hwc_procs_(hwc_procs), type_(type), id_(id),
-    device_intf_(NULL) {
+HWCSink::HWCSink(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, DeviceType type, int id)
+  : core_intf_(core_intf), hwc_procs_(hwc_procs), type_(type), id_(id), device_intf_(NULL) {
 }
 
 int HWCSink::Init() {
+  DisplayError error = core_intf_->CreateDevice(type_, this, &device_intf_);
+  if (UNLIKELY(error != kErrorNone)) {
+    DLOGE("Display device create failed. Error = %d", error);
+    return -EINVAL;
+  }
+
   return 0;
 }
 
 int HWCSink::Deinit() {
+  DisplayError error = core_intf_->DestroyDevice(device_intf_);
+  if (UNLIKELY(error != kErrorNone)) {
+    DLOGE("Display device destroy failed. Error = %d", error);
+    return -EINVAL;
+  }
+
+  if (LIKELY(layer_stack_.raw)) {
+    delete[] layer_stack_.raw;
+  }
+
+  return 0;
+}
+
+int HWCSink::EventControl(int event, int enable) {
+  DisplayError error = kErrorNone;
+
+  switch (event) {
+  case HWC_EVENT_VSYNC:
+    error = device_intf_->SetVSyncState(enable);
+    break;
+
+  default:
+    DLOGE("Unsupported event control type : %d", event);
+  }
+
+  if (UNLIKELY(error != kErrorNone)) {
+    DLOGE("EventControl failed. event = %d, enable = %d, error = %d", event, enable, error);
+    return -EINVAL;
+  }
+
   return 0;
 }
 
 int HWCSink::Blank(int blank) {
-  return 0;
+  DLOGI("Blank : %d, display : %d", blank, id_);
+  DeviceState state = blank ? kStateOff : kStateOn;
+  return SetState(state);
 }
 
 int HWCSink::GetDisplayConfigs(uint32_t *configs, size_t *num_configs) {
+  if (*num_configs > 0) {
+    configs[0] = 0;
+    *num_configs = 1;
+  }
+
   return 0;
 }
 
 int HWCSink::GetDisplayAttributes(uint32_t config, const uint32_t *attributes, int32_t *values) {
+  DisplayError error = kErrorNone;
+
+  DeviceConfigVariableInfo variable_config;
+  error = device_intf_->GetConfig(&variable_config, 0);
+  if (UNLIKELY(error != kErrorNone)) {
+    DLOGE("GetConfig variable info failed. Error = %d", error);
+    return -EINVAL;
+  }
+
+  for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) {
+    switch (attributes[i]) {
+    case HWC_DISPLAY_VSYNC_PERIOD:
+      values[i] = variable_config.vsync_period_ns;
+      break;
+    case HWC_DISPLAY_WIDTH:
+      values[i] = variable_config.x_pixels;
+      break;
+    case HWC_DISPLAY_HEIGHT:
+      values[i] = variable_config.y_pixels;
+      break;
+    case HWC_DISPLAY_DPI_X:
+      values[i] = INT32(variable_config.x_dpi * 1000.0f);
+      break;
+    case HWC_DISPLAY_DPI_Y:
+      values[i] = INT32(variable_config.y_dpi * 1000.0f);
+      break;
+    default:
+      DLOGE("Spurious attribute type %d", attributes[i]);
+      return -EINVAL;
+    }
+  }
+
+  return 0;
+}
+
+int HWCSink::SetState(DeviceState state) {
+  DisplayError error = device_intf_->SetDeviceState(state);
+  if (UNLIKELY(error != kErrorNone)) {
+    DLOGE("Set state failed. Error = %d", error);
+    return -EINVAL;
+  }
+
   return 0;
 }
 
 DisplayError HWCSink::VSync(const DeviceEventVSync &vsync) {
+  (*hwc_procs_)->vsync(*hwc_procs_, id_, vsync.timestamp);
   return kErrorNone;
 }
 
 DisplayError HWCSink::Refresh() {
+  (*hwc_procs_)->invalidate(*hwc_procs_);
   return kErrorNone;
 }
 
+int HWCSink::AllocateLayerStack(hwc_display_contents_1_t *content_list) {
+  size_t num_hw_layers = content_list->numHwLayers;
+
+  // Allocate memory for a) total number of layers b) buffer handle for each layer c) number of
+  // visible rectangles in each layer d) dirty rectangle for each layer
+  size_t required_size = num_hw_layers * (sizeof(Layer) + sizeof(LayerBuffer));
+  for (size_t i = 0; i < num_hw_layers; i++) {
+    // visible rectangles + 1 dirty rectangle
+    size_t num_rects = content_list->hwLayers[i].visibleRegionScreen.numRects + 1;
+    required_size += num_rects * sizeof(LayerRect);
+  }
+
+  // Layer array may be large enough to hold current number of layers.
+  // If not, re-allocate it now.
+  if (UNLIKELY(layer_stack_.size < required_size)) {
+    if (LIKELY(layer_stack_.raw)) {
+      delete[] layer_stack_.raw;
+      layer_stack_.size = 0;
+    }
+
+    // Allocate in multiple of kSizeSteps.
+    required_size = ROUND_UP(required_size, layer_stack_.kSizeSteps);
+
+    layer_stack_.raw = new uint8_t[required_size];
+    if (UNLIKELY(!layer_stack_.raw)) {
+      return -ENOMEM;
+    }
+
+    layer_stack_.size = required_size;
+  }
+
+  // Assign memory addresses now.
+  uint8_t *current_address = layer_stack_.raw;
+
+  // Layer array address
+  layer_stack_.layers.layer = reinterpret_cast<Layer *>(current_address);
+  layer_stack_.layers.count = num_hw_layers;
+  current_address += num_hw_layers * sizeof(Layer);
+
+  for (size_t i = 0; i < num_hw_layers; i++) {
+    hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
+    Layer &layer = layer_stack_.layers.layer[i];
+
+    // Layer buffer handle address
+    layer.input_buffer = reinterpret_cast<LayerBuffer *>(current_address);
+    current_address += sizeof(LayerBuffer);
+
+    // Visible rectangle address
+    layer.visible_regions.rect = reinterpret_cast<LayerRect *>(current_address);
+    layer.visible_regions.count = hwc_layer.visibleRegionScreen.numRects;
+    current_address += hwc_layer.visibleRegionScreen.numRects * sizeof(LayerRect);
+
+    // Dirty rectangle address
+    layer.dirty_regions.rect = reinterpret_cast<LayerRect *>(current_address);
+    layer.dirty_regions.count = 1;
+    current_address += sizeof(LayerRect);
+  }
+
+  return 0;
+}
+
+int HWCSink::PrepareLayerStack(hwc_display_contents_1_t *content_list) {
+  size_t num_hw_layers = content_list->numHwLayers;
+  if (UNLIKELY(num_hw_layers <= 1)) {
+    return 0;
+  }
+
+  // Configure each layer
+  for (size_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);
+
+    Layer &layer = layer_stack_.layers.layer[i];
+    LayerBuffer *layer_buffer = layer.input_buffer;
+
+    if (pvt_handle) {
+      if (UNLIKELY(SetFormat(&layer_buffer->format, pvt_handle->format))) {
+        return -EINVAL;
+      }
+
+      layer_buffer->width = pvt_handle->width;
+      layer_buffer->height = pvt_handle->height;
+      layer_buffer->planes[0].fd = pvt_handle->fd;
+      layer_buffer->planes[0].offset = pvt_handle->offset;
+      layer_buffer->planes[0].stride = pvt_handle->width;
+    }
+
+    SetRect(&layer.dst_rect, hwc_layer.displayFrame);
+    SetRect(&layer.src_rect, hwc_layer.sourceCropf);
+    for (size_t j = 0; j < hwc_layer.visibleRegionScreen.numRects; j++) {
+        SetRect(&layer.visible_regions.rect[j], hwc_layer.visibleRegionScreen.rects[j]);
+    }
+    SetRect(&layer.dirty_regions.rect[0], hwc_layer.dirtyRect);
+
+    SetComposition(&layer.composition, hwc_layer.compositionType);
+    SetBlending(&layer.blending, hwc_layer.blending);
+
+    LayerTransform &layer_transform = layer.transform;
+    uint32_t &hwc_transform = hwc_layer.transform;
+    layer_transform.flip_horizontal = ((hwc_transform & HWC_TRANSFORM_FLIP_H) > 0);
+    layer_transform.flip_vertical = ((hwc_transform & HWC_TRANSFORM_FLIP_V) > 0);
+    layer_transform.rotation = ((hwc_transform& HWC_TRANSFORM_ROT_90) ? 90.0f : 0.0f);
+
+    layer.plane_alpha = hwc_layer.planeAlpha;
+    layer.flags.skip = ((hwc_layer.flags & HWC_SKIP_LAYER) > 0);
+  }
+
+  // Configure layer stack
+  layer_stack_.flags.geometry_changed = ((content_list->flags & HWC_GEOMETRY_CHANGED) > 0);
+
+  DisplayError error = device_intf_->Prepare(&layer_stack_);
+  if (UNLIKELY(error != kErrorNone)) {
+    DLOGE("Prepare failed. Error = %d", error);
+    return -EINVAL;
+  }
+
+  for (size_t i = 0; i < num_hw_layers; i++) {
+    hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
+    Layer &layer = layer_stack_.layers.layer[i];
+    SetComposition(&hwc_layer.compositionType, layer.composition);
+  }
+
+  return 0;
+}
+
+int HWCSink::CommitLayerStack(hwc_display_contents_1_t *content_list) {
+  size_t num_hw_layers = content_list->numHwLayers;
+  if (UNLIKELY(num_hw_layers <= 1)) {
+    return 0;
+  }
+
+  for (size_t i = 0; i < num_hw_layers; i++) {
+    hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
+    LayerBuffer *layer_buffer = layer_stack_.layers.layer[i].input_buffer;
+
+    layer_buffer->acquire_fence_fd = hwc_layer.acquireFenceFd;
+  }
+
+  DisplayError error = device_intf_->Commit(&layer_stack_);
+  if (UNLIKELY(error != kErrorNone)) {
+    DLOGE("Commit failed. Error = %d", error);
+    return -EINVAL;
+  }
+
+  for (size_t i = 0; i < num_hw_layers; i++) {
+    hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
+    Layer &layer = layer_stack_.layers.layer[i];
+    LayerBuffer *layer_buffer = layer_stack_.layers.layer[i].input_buffer;
+
+    if (layer.composition == kCompositionSDE || layer.composition == kCompositionGPUTarget) {
+      hwc_layer.releaseFenceFd = layer_buffer->release_fence_fd;
+    }
+
+    if (hwc_layer.acquireFenceFd >= 0) {
+      close(hwc_layer.acquireFenceFd);
+    }
+  }
+
+  return 0;
+}
+
+void HWCSink::SetRect(LayerRect *target, const hwc_rect_t &source) {
+  target->left = FLOAT(source.left);
+  target->top = FLOAT(source.top);
+  target->right = FLOAT(source.right);
+  target->bottom = FLOAT(source.bottom);
+}
+
+void HWCSink::SetRect(LayerRect *target, const hwc_frect_t &source) {
+  target->left = source.left;
+  target->top = source.top;
+  target->right = source.right;
+  target->bottom = source.bottom;
+}
+
+void HWCSink::SetComposition(LayerComposition *target, const int32_t &source) {
+  switch (source) {
+  case HWC_FRAMEBUFFER_TARGET:
+    *target = kCompositionGPUTarget;
+    break;
+  default:
+    *target = kCompositionSDE;
+    break;
+  }
+}
+
+void HWCSink::SetComposition(int32_t *target, const LayerComposition &source) {
+  switch (source) {
+  case kCompositionGPUTarget:
+    *target = HWC_FRAMEBUFFER_TARGET;
+    break;
+  case kCompositionSDE:
+    *target = HWC_OVERLAY;
+    break;
+  default:
+    *target = HWC_FRAMEBUFFER;
+    break;
+  }
+}
+
+void HWCSink::SetBlending(LayerBlending *target, const int32_t &source) {
+  switch (source) {
+  case HWC_BLENDING_PREMULT:
+    *target = kBlendingPremultiplied;
+    break;
+  case HWC_BLENDING_COVERAGE:
+    *target = kBlendingCoverage;
+    break;
+  default:
+    *target = kBlendingNone;
+    break;
+  }
+}
+
+int HWCSink::SetFormat(LayerBufferFormat *target, const int &source) {
+  switch (source) {
+  case HAL_PIXEL_FORMAT_RGBA_8888:
+    *target = kFormatRGBA8888;
+    break;
+  case HAL_PIXEL_FORMAT_BGRA_8888:
+    *target = kFormatBGRA8888;
+    break;
+  case HAL_PIXEL_FORMAT_RGBX_8888:
+    *target = kFormatRGBX8888;
+    break;
+  case HAL_PIXEL_FORMAT_BGRX_8888:
+    *target = kFormatBGRX8888;
+    break;
+  case HAL_PIXEL_FORMAT_RGB_888:
+    *target = kFormatRGB888;
+    break;
+  case HAL_PIXEL_FORMAT_RGB_565:
+    *target = kFormatRGB565;
+    break;
+  default:
+    DLOGE("Unsupported format type %d", source);
+    return -EINVAL;
+  }
+
+  return 0;
+}
+
 }  // namespace sde
 
diff --git a/displayengine/libs/hwc/hwc_sink.h b/displayengine/libs/hwc/hwc_sink.h
index 97e07c5..340aabd 100644
--- a/displayengine/libs/hwc/hwc_sink.h
+++ b/displayengine/libs/hwc/hwc_sink.h
@@ -36,20 +36,39 @@
   virtual int Deinit();
   virtual int Prepare(hwc_display_contents_1_t *content_list) = 0;
   virtual int Commit(hwc_display_contents_1_t *content_list) = 0;
+  virtual int EventControl(int event, int enable);
   virtual int Blank(int blank);
   virtual int GetDisplayConfigs(uint32_t *configs, size_t *num_configs);
   virtual int GetDisplayAttributes(uint32_t config, const uint32_t *attributes, int32_t *values);
+  int SetState(DeviceState state);
 
  protected:
-  HWCSink(CoreInterface *core_intf, hwc_procs_t const *hwc_procs, DeviceType type, int id);
+  HWCSink(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, DeviceType type, int id);
   virtual ~HWCSink() { }
 
   // DeviceEventHandler methods
   virtual DisplayError VSync(const DeviceEventVSync &vsync);
   virtual DisplayError Refresh();
 
+  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);
+  inline void SetRect(LayerRect *target, const hwc_rect_t &source);
+  inline void SetRect(LayerRect *target, const hwc_frect_t &source);
+  inline void SetComposition(LayerComposition *target, const int32_t &source);
+  inline void SetComposition(int32_t *target, const LayerComposition &source);
+  inline void SetBlending(LayerBlending *target, const int32_t &source);
+  inline int SetFormat(LayerBufferFormat *target, const int &source);
+
+  // Structure to track memory allocation for layer stack (layers, rectangles) object.
+  struct LayerStackMemory : LayerStack {
+    static const size_t kSizeSteps = 4096;  // Default memory allocation.
+    uint8_t *raw;  // Pointer to byte array.
+    size_t size;  // Current number of allocated bytes.
+  } layer_stack_;
+
   CoreInterface *core_intf_;
-  hwc_procs_t const *hwc_procs_;
+  hwc_procs_t const **hwc_procs_;
   DeviceType type_;
   int id_;
   DeviceInterface *device_intf_;
diff --git a/displayengine/libs/hwc/hwc_sink_external.cpp b/displayengine/libs/hwc/hwc_sink_external.cpp
index 977b26e..d506194 100644
--- a/displayengine/libs/hwc/hwc_sink_external.cpp
+++ b/displayengine/libs/hwc/hwc_sink_external.cpp
@@ -32,7 +32,7 @@
 
 namespace sde {
 
-HWCSinkExternal::HWCSinkExternal(CoreInterface *core_intf, hwc_procs_t const *hwc_procs)
+HWCSinkExternal::HWCSinkExternal(CoreInterface *core_intf, hwc_procs_t const **hwc_procs)
   : HWCSink(core_intf, hwc_procs, kHDMI, HWC_DISPLAY_EXTERNAL) {
 }
 
diff --git a/displayengine/libs/hwc/hwc_sink_external.h b/displayengine/libs/hwc/hwc_sink_external.h
index 1c0abce..c0eab7f 100644
--- a/displayengine/libs/hwc/hwc_sink_external.h
+++ b/displayengine/libs/hwc/hwc_sink_external.h
@@ -31,7 +31,7 @@
 
 class HWCSinkExternal : public HWCSink {
  public:
-  explicit HWCSinkExternal(CoreInterface *core_intf, hwc_procs_t const *hwc_procs);
+  explicit HWCSinkExternal(CoreInterface *core_intf, hwc_procs_t const **hwc_procs);
   virtual int Init();
   virtual int Deinit();
   virtual int Prepare(hwc_display_contents_1_t *content_list);
diff --git a/displayengine/libs/hwc/hwc_sink_primary.cpp b/displayengine/libs/hwc/hwc_sink_primary.cpp
index 36d7b29..a9b74bf 100644
--- a/displayengine/libs/hwc/hwc_sink_primary.cpp
+++ b/displayengine/libs/hwc/hwc_sink_primary.cpp
@@ -32,32 +32,53 @@
 
 namespace sde {
 
-HWCSinkPrimary::HWCSinkPrimary(CoreInterface *core_intf, hwc_procs_t const *hwc_procs)
+HWCSinkPrimary::HWCSinkPrimary(CoreInterface *core_intf, hwc_procs_t const **hwc_procs)
   : HWCSink(core_intf, hwc_procs, kPrimary, HWC_DISPLAY_PRIMARY) {
 }
 
 int HWCSinkPrimary::Init() {
-  return 0;
+  return HWCSink::Init();
 }
 
 int HWCSinkPrimary::Deinit() {
-  return 0;
+  return HWCSink::Deinit();
 }
 
 int HWCSinkPrimary::Prepare(hwc_display_contents_1_t *content_list) {
+  int status = 0;
+
+  status = AllocateLayerStack(content_list);
+  if (UNLIKELY(status)) {
+    return status;
+  }
+
+  status = PrepareLayerStack(content_list);
+  if (UNLIKELY(status)) {
+    return status;
+  }
+
   return 0;
 }
 
 int HWCSinkPrimary::Commit(hwc_display_contents_1_t *content_list) {
+  int status = 0;
+
+  status = HWCSink::CommitLayerStack(content_list);
+  if (UNLIKELY(status)) {
+    return status;
+  }
+
+  content_list->retireFenceFd = layer_stack_.retire_fence_fd;
+
   return 0;
 }
 
 int HWCSinkPrimary::PowerOn() {
-  return 0;
+  return SetState(kStateOn);
 }
 
 int HWCSinkPrimary::PowerOff() {
-  return 0;
+  return SetState(kStateOff);
 }
 
 }  // namespace sde
diff --git a/displayengine/libs/hwc/hwc_sink_primary.h b/displayengine/libs/hwc/hwc_sink_primary.h
index a4eef22..f16c5a6 100644
--- a/displayengine/libs/hwc/hwc_sink_primary.h
+++ b/displayengine/libs/hwc/hwc_sink_primary.h
@@ -31,7 +31,7 @@
 
 class HWCSinkPrimary : public HWCSink {
  public:
-  explicit HWCSinkPrimary(CoreInterface *core_intf, hwc_procs_t const *hwc_procs);
+  explicit HWCSinkPrimary(CoreInterface *core_intf, hwc_procs_t const **hwc_procs);
   virtual int Init();
   virtual int Deinit();
   virtual int Prepare(hwc_display_contents_1_t *content_list);
diff --git a/displayengine/libs/hwc/hwc_sink_virtual.cpp b/displayengine/libs/hwc/hwc_sink_virtual.cpp
index f692552..49334a3 100644
--- a/displayengine/libs/hwc/hwc_sink_virtual.cpp
+++ b/displayengine/libs/hwc/hwc_sink_virtual.cpp
@@ -32,7 +32,7 @@
 
 namespace sde {
 
-HWCSinkVirtual::HWCSinkVirtual(CoreInterface *core_intf, hwc_procs_t const *hwc_procs)
+HWCSinkVirtual::HWCSinkVirtual(CoreInterface *core_intf, hwc_procs_t const **hwc_procs)
   : HWCSink(core_intf, hwc_procs, kVirtual, HWC_DISPLAY_VIRTUAL) {
 }
 
diff --git a/displayengine/libs/hwc/hwc_sink_virtual.h b/displayengine/libs/hwc/hwc_sink_virtual.h
index 41c1d0d..381c1e3 100644
--- a/displayengine/libs/hwc/hwc_sink_virtual.h
+++ b/displayengine/libs/hwc/hwc_sink_virtual.h
@@ -31,7 +31,7 @@
 
 class HWCSinkVirtual : public HWCSink {
  public:
-  explicit HWCSinkVirtual(CoreInterface *core_intf, hwc_procs_t const *hwc_procs);
+  explicit HWCSinkVirtual(CoreInterface *core_intf, hwc_procs_t const **hwc_procs);
   virtual int Init();
   virtual int Deinit();
   virtual int Prepare(hwc_display_contents_1_t *content_list);