sdm: Align to new SDM design.
- Align code base to new SDM design.
Change-Id: I38d7d138ae704cf036e2b96c16453aea63bc333f
diff --git a/sdm/libs/core/Android.mk b/sdm/libs/core/Android.mk
new file mode 100644
index 0000000..8831c3f
--- /dev/null
+++ b/sdm/libs/core/Android.mk
@@ -0,0 +1,30 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libsdmcore
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := hardware/qcom/display/sdm/include/ \
+ $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_CFLAGS := -Wno-missing-field-initializers -Wno-unused-parameter \
+ -Wconversion -Wall -Werror \
+ -DLOG_TAG=\"SDM\"
+LOCAL_HW_INTF_PATH := fb
+LOCAL_SHARED_LIBRARIES := libdl libsdmutils
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+LOCAL_SRC_FILES := core_interface.cpp \
+ core_impl.cpp \
+ display_base.cpp \
+ display_primary.cpp \
+ display_hdmi.cpp \
+ display_virtual.cpp \
+ comp_manager.cpp \
+ strategy.cpp \
+ resource_default.cpp \
+ dump_impl.cpp \
+ $(LOCAL_HW_INTF_PATH)/hw_info.cpp \
+ $(LOCAL_HW_INTF_PATH)/hw_device.cpp \
+ $(LOCAL_HW_INTF_PATH)/hw_primary.cpp \
+ $(LOCAL_HW_INTF_PATH)/hw_hdmi.cpp \
+ $(LOCAL_HW_INTF_PATH)/hw_virtual.cpp
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/sdm/libs/core/comp_manager.cpp b/sdm/libs/core/comp_manager.cpp
new file mode 100644
index 0000000..69e3ec7
--- /dev/null
+++ b/sdm/libs/core/comp_manager.cpp
@@ -0,0 +1,359 @@
+/*
+* 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:
+* * 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.
+*/
+
+#include <utils/constants.h>
+#include <utils/debug.h>
+#include <core/buffer_allocator.h>
+
+#include "comp_manager.h"
+#include "strategy.h"
+
+#define __CLASS__ "CompManager"
+
+namespace sdm {
+
+CompManager::CompManager()
+ : resource_intf_(NULL), registered_displays_(0), configured_displays_(0), safe_mode_(false),
+ extension_intf_(NULL) {
+}
+
+DisplayError CompManager::Init(const HWResourceInfo &hw_res_info,
+ ExtensionInterface *extension_intf) {
+ SCOPE_LOCK(locker_);
+
+ DisplayError error = kErrorNone;
+
+ if (extension_intf) {
+ error = extension_intf->CreateResourceExtn(hw_res_info, &resource_intf_);
+ } else {
+ resource_intf_ = &resource_default_;
+ error = resource_default_.Init(hw_res_info);
+ }
+
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ hw_res_info_ = hw_res_info;
+ extension_intf_ = extension_intf;
+
+ return error;
+}
+
+DisplayError CompManager::Deinit() {
+ SCOPE_LOCK(locker_);
+
+ if (extension_intf_) {
+ extension_intf_->DestroyResourceExtn(resource_intf_);
+ } else {
+ resource_default_.Deinit();
+ }
+
+ return kErrorNone;
+}
+
+DisplayError CompManager::RegisterDisplay(DisplayType type, const HWDisplayAttributes &attributes,
+ const HWPanelInfo &hw_panel_info, Handle *display_ctx) {
+ SCOPE_LOCK(locker_);
+
+ DisplayError error = kErrorNone;
+
+ DisplayCompositionContext *display_comp_ctx = new DisplayCompositionContext();
+ if (!display_comp_ctx) {
+ return kErrorMemory;
+ }
+
+ Strategy *&strategy = display_comp_ctx->strategy;
+ strategy = new Strategy(extension_intf_, type, hw_res_info_, hw_panel_info);
+ if (!strategy) {
+ DLOGE("Unable to create strategy");
+ delete display_comp_ctx;
+ return kErrorMemory;
+ }
+
+ error = strategy->Init();
+ if (error != kErrorNone) {
+ delete strategy;
+ delete display_comp_ctx;
+ return error;
+ }
+
+ error = resource_intf_->RegisterDisplay(type, attributes, hw_panel_info,
+ &display_comp_ctx->display_resource_ctx);
+ if (error != kErrorNone) {
+ strategy->Deinit();
+ delete strategy;
+ delete display_comp_ctx;
+ display_comp_ctx = NULL;
+ return error;
+ }
+
+ SET_BIT(registered_displays_, type);
+ display_comp_ctx->display_type = type;
+ *display_ctx = display_comp_ctx;
+ // 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.
+ 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_,
+ display_comp_ctx->display_type);
+
+ return kErrorNone;
+}
+
+DisplayError CompManager::UnregisterDisplay(Handle comp_handle) {
+ SCOPE_LOCK(locker_);
+
+ DisplayCompositionContext *display_comp_ctx =
+ reinterpret_cast<DisplayCompositionContext *>(comp_handle);
+
+ if (!display_comp_ctx) {
+ return kErrorParameters;
+ }
+
+ resource_intf_->UnregisterDisplay(display_comp_ctx->display_resource_ctx);
+
+ Strategy *&strategy = display_comp_ctx->strategy;
+ strategy->Deinit();
+ delete strategy;
+
+ CLEAR_BIT(registered_displays_, display_comp_ctx->display_type);
+ CLEAR_BIT(configured_displays_, display_comp_ctx->display_type);
+
+ DLOGV_IF(kTagCompManager, "registered display bit mask 0x%x, configured display bit mask 0x%x, " \
+ "display type %d", registered_displays_, configured_displays_,
+ display_comp_ctx->display_type);
+
+ delete display_comp_ctx;
+ display_comp_ctx = NULL;
+ return kErrorNone;
+}
+
+void CompManager::ReconfigureDisplay(Handle comp_handle, const HWDisplayAttributes &attributes,
+ const HWPanelInfo &hw_panel_info) {
+ DisplayCompositionContext *display_comp_ctx =
+ reinterpret_cast<DisplayCompositionContext *>(comp_handle);
+
+ resource_intf_->ReconfigureDisplay(display_comp_ctx->display_resource_ctx, attributes,
+ hw_panel_info);
+
+ // TODO(user): Need to reconfigure strategy with updated panel info
+}
+
+void CompManager::PrepareStrategyConstraints(Handle comp_handle, HWLayers *hw_layers) {
+ DisplayCompositionContext *display_comp_ctx =
+ reinterpret_cast<DisplayCompositionContext *>(comp_handle);
+ StrategyConstraints *constraints = &display_comp_ctx->constraints;
+
+ constraints->safe_mode = safe_mode_;
+
+ // Limit 2 layer SDE Comp on HDMI/Virtual
+ if (display_comp_ctx->display_type != kPrimary) {
+ constraints->max_layers = 2;
+ }
+
+ // If a strategy fails after successfully allocating resources, then set safe mode
+ if (display_comp_ctx->remaining_strategies != display_comp_ctx->max_strategies) {
+ constraints->safe_mode = true;
+ }
+
+ if (display_comp_ctx->idle_fallback || display_comp_ctx->fallback_) {
+ constraints->safe_mode = true;
+ }
+}
+
+void CompManager::PrePrepare(Handle display_ctx, HWLayers *hw_layers) {
+ SCOPE_LOCK(locker_);
+ DisplayCompositionContext *display_comp_ctx =
+ reinterpret_cast<DisplayCompositionContext *>(display_ctx);
+ display_comp_ctx->strategy->Start(&hw_layers->info, &display_comp_ctx->max_strategies);
+ display_comp_ctx->remaining_strategies = display_comp_ctx->max_strategies;
+
+ // Avoid idle fallback, if there is only one app layer.
+ // TODO(user): App layer count will change for hybrid composition
+ uint32_t app_layer_count = hw_layers->info.stack->layer_count - 1;
+ if (!display_comp_ctx->idle_fallback && app_layer_count > 1) {
+ display_comp_ctx->handle_idle_timeout = true;
+ }
+}
+
+DisplayError CompManager::Prepare(Handle display_ctx, HWLayers *hw_layers) {
+ SCOPE_LOCK(locker_);
+
+ DisplayCompositionContext *display_comp_ctx =
+ reinterpret_cast<DisplayCompositionContext *>(display_ctx);
+ Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx;
+
+ DisplayError error = kErrorUndefined;
+
+ PrepareStrategyConstraints(display_ctx, hw_layers);
+
+ // Select a composition strategy, and try to allocate resources for it.
+ resource_intf_->Start(display_resource_ctx);
+
+ bool exit = false;
+ uint32_t &count = display_comp_ctx->remaining_strategies;
+ for (; !exit && count > 0; count--) {
+ error = display_comp_ctx->strategy->GetNextStrategy(&display_comp_ctx->constraints);
+ if (error != kErrorNone) {
+ // Composition strategies exhausted. Resource Manager could not allocate resources even for
+ // GPU composition. This will never happen.
+ exit = true;
+ }
+
+ if (!exit) {
+ error = resource_intf_->Acquire(display_resource_ctx, hw_layers);
+ // Exit if successfully allocated resource, else try next strategy.
+ exit = (error == kErrorNone);
+ }
+ }
+
+ if (error != kErrorNone) {
+ DLOGE("Composition strategies exhausted for display = %d", display_comp_ctx->display_type);
+ }
+
+ resource_intf_->Stop(display_resource_ctx);
+
+ return error;
+}
+
+DisplayError CompManager::PostPrepare(Handle display_ctx, HWLayers *hw_layers) {
+ SCOPE_LOCK(locker_);
+ DisplayCompositionContext *display_comp_ctx =
+ reinterpret_cast<DisplayCompositionContext *>(display_ctx);
+ Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx;
+
+ DisplayError error = kErrorNone;
+ error = resource_intf_->PostPrepare(display_resource_ctx, hw_layers);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ display_comp_ctx->strategy->Stop();
+
+ return kErrorNone;
+}
+
+DisplayError CompManager::PostCommit(Handle display_ctx, HWLayers *hw_layers) {
+ SCOPE_LOCK(locker_);
+
+ DisplayError error = kErrorNone;
+ DisplayCompositionContext *display_comp_ctx =
+ reinterpret_cast<DisplayCompositionContext *>(display_ctx);
+ SET_BIT(configured_displays_, display_comp_ctx->display_type);
+ if (configured_displays_ == registered_displays_) {
+ safe_mode_ = false;
+ }
+
+ error = resource_intf_->PostCommit(display_comp_ctx->display_resource_ctx, hw_layers);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ display_comp_ctx->idle_fallback = false;
+
+ DLOGV_IF(kTagCompManager, "registered display bit mask 0x%x, configured display bit mask 0x%x, " \
+ "display type %d", registered_displays_, configured_displays_,
+ display_comp_ctx->display_type);
+
+ return kErrorNone;
+}
+
+void CompManager::Purge(Handle display_ctx) {
+ SCOPE_LOCK(locker_);
+
+ DisplayCompositionContext *display_comp_ctx =
+ reinterpret_cast<DisplayCompositionContext *>(display_ctx);
+
+ resource_intf_->Purge(display_comp_ctx->display_resource_ctx);
+}
+
+bool CompManager::ProcessIdleTimeout(Handle display_ctx) {
+ SCOPE_LOCK(locker_);
+
+ DisplayCompositionContext *display_comp_ctx =
+ reinterpret_cast<DisplayCompositionContext *>(display_ctx);
+
+ if (!display_comp_ctx) {
+ return false;
+ }
+
+ // 1. handle_idle_timeout flag is set to true on start of every draw call, if the current
+ // composition is not due to idle fallback.
+ // 2. idle_fallback flag will be set only if handle_idle_timeout flag is true and there is no
+ // update to the screen for specified amount of time.
+ // 3. handle_idle_timeout flag helps us handle the very first idle timeout event and
+ // ignore the next idle timeout event on consecutive two idle timeout events.
+ if (display_comp_ctx->handle_idle_timeout) {
+ display_comp_ctx->idle_fallback = true;
+ display_comp_ctx->handle_idle_timeout = false;
+
+ return true;
+ }
+
+ return false;
+}
+
+void CompManager::ProcessThermalEvent(Handle display_ctx, int64_t thermal_level) {
+ SCOPE_LOCK(locker_);
+
+ DisplayCompositionContext *display_comp_ctx =
+ reinterpret_cast<DisplayCompositionContext *>(display_ctx);
+
+ if (thermal_level >= kMaxThermalLevel) {
+ display_comp_ctx->fallback_ = true;
+ } else {
+ display_comp_ctx->fallback_ = false;
+ }
+}
+
+DisplayError CompManager::SetMaxMixerStages(Handle display_ctx, uint32_t max_mixer_stages) {
+ SCOPE_LOCK(locker_);
+
+ DisplayError error = kErrorNone;
+ DisplayCompositionContext *display_comp_ctx =
+ reinterpret_cast<DisplayCompositionContext *>(display_ctx);
+
+ if (display_comp_ctx) {
+ error = resource_intf_->SetMaxMixerStages(display_comp_ctx->display_resource_ctx,
+ max_mixer_stages);
+ }
+
+ return error;
+}
+
+void CompManager::AppendDump(char *buffer, uint32_t length) {
+ SCOPE_LOCK(locker_);
+}
+
+DisplayError CompManager::ValidateScaling(const LayerRect &crop, const LayerRect &dst,
+ bool rotate90) {
+ return resource_intf_->ValidateScaling(crop, dst, rotate90);
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/core/comp_manager.h b/sdm/libs/core/comp_manager.h
new file mode 100644
index 0000000..f48beed
--- /dev/null
+++ b/sdm/libs/core/comp_manager.h
@@ -0,0 +1,99 @@
+/*
+* 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __COMP_MANAGER_H__
+#define __COMP_MANAGER_H__
+
+#include <core/display_interface.h>
+#include <private/extension_interface.h>
+#include <utils/locker.h>
+
+#include "strategy.h"
+#include "resource_default.h"
+#include "hw_interface.h"
+#include "dump_impl.h"
+
+namespace sdm {
+
+class CompManager : public DumpImpl {
+ public:
+ CompManager();
+ DisplayError Init(const HWResourceInfo &hw_res_info_, ExtensionInterface *extension_intf);
+ DisplayError Deinit();
+ DisplayError RegisterDisplay(DisplayType type, const HWDisplayAttributes &attributes,
+ const HWPanelInfo &hw_panel_info, Handle *res_mgr_hnd);
+ DisplayError UnregisterDisplay(Handle res_mgr_hnd);
+ void ReconfigureDisplay(Handle display_ctx, const HWDisplayAttributes &attributes,
+ const HWPanelInfo &hw_panel_info);
+ void PrePrepare(Handle display_ctx, HWLayers *hw_layers);
+ DisplayError Prepare(Handle display_ctx, HWLayers *hw_layers);
+ DisplayError PostPrepare(Handle display_ctx, HWLayers *hw_layers);
+ DisplayError PostCommit(Handle display_ctx, HWLayers *hw_layers);
+ void Purge(Handle display_ctx);
+ bool ProcessIdleTimeout(Handle display_ctx);
+ void ProcessThermalEvent(Handle display_ctx, int64_t thermal_level);
+ DisplayError SetMaxMixerStages(Handle display_ctx, uint32_t max_mixer_stages);
+ DisplayError ValidateScaling(const LayerRect &crop, const LayerRect &dst, bool rotate90);
+
+ // DumpImpl method
+ virtual void AppendDump(char *buffer, uint32_t length);
+
+ private:
+ static const int kMaxThermalLevel = 3;
+
+ void PrepareStrategyConstraints(Handle display_ctx, HWLayers *hw_layers);
+
+ struct DisplayCompositionContext {
+ Strategy *strategy;
+ StrategyConstraints constraints;
+ Handle display_resource_ctx;
+ DisplayType display_type;
+ uint32_t max_strategies;
+ uint32_t remaining_strategies;
+ bool idle_fallback;
+ bool handle_idle_timeout;
+ bool fallback_;
+
+ DisplayCompositionContext()
+ : display_resource_ctx(NULL), display_type(kPrimary), max_strategies(0),
+ remaining_strategies(0), idle_fallback(false), handle_idle_timeout(true),
+ fallback_(false) { }
+ };
+
+ Locker locker_;
+ ResourceInterface *resource_intf_;
+ ResourceDefault resource_default_;
+ uint64_t registered_displays_; // Stores the bit mask of registered displays
+ uint64_t configured_displays_; // Stores the bit mask of sucessfully configured displays
+ bool safe_mode_; // Flag to notify all displays to be in resource crunch
+ // mode, where strategy manager chooses the best strategy
+ // that uses optimal number of pipes for each display
+ HWResourceInfo hw_res_info_;
+ ExtensionInterface *extension_intf_;
+};
+
+} // namespace sdm
+
+#endif // __COMP_MANAGER_H__
+
diff --git a/sdm/libs/core/core_impl.cpp b/sdm/libs/core/core_impl.cpp
new file mode 100644
index 0000000..f017d8d
--- /dev/null
+++ b/sdm/libs/core/core_impl.cpp
@@ -0,0 +1,208 @@
+/*
+* 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:
+* * 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.
+*/
+
+#include <dlfcn.h>
+#include <utils/locker.h>
+#include <utils/constants.h>
+#include <utils/debug.h>
+
+#include "core_impl.h"
+#include "display_primary.h"
+#include "display_hdmi.h"
+#include "display_virtual.h"
+#include "hw_info_interface.h"
+
+#define __CLASS__ "CoreImpl"
+
+namespace sdm {
+
+CoreImpl::CoreImpl(CoreEventHandler *event_handler, BufferAllocator *buffer_allocator,
+ BufferSyncHandler *buffer_sync_handler)
+ : event_handler_(event_handler), buffer_allocator_(buffer_allocator),
+ buffer_sync_handler_(buffer_sync_handler), hw_resource_(NULL), hw_info_intf_(NULL),
+ rotator_intf_(NULL), extension_lib_(NULL), extension_intf_(NULL),
+ create_extension_intf_(NULL), destroy_extension_intf_(NULL) {
+}
+
+DisplayError CoreImpl::Init() {
+ SCOPE_LOCK(locker_);
+ DisplayError error = kErrorNone;
+
+ // Try to load extension library & get handle to its interface.
+ extension_lib_ = ::dlopen(EXTENSION_LIBRARY_NAME, RTLD_NOW);
+ if (extension_lib_) {
+ void **create_sym = reinterpret_cast<void **>(&create_extension_intf_);
+ void **destroy_sym = reinterpret_cast<void **>(&destroy_extension_intf_);
+
+ *create_sym = ::dlsym(extension_lib_, CREATE_EXTENSION_INTERFACE_NAME);
+ *destroy_sym = ::dlsym(extension_lib_, DESTROY_EXTENSION_INTERFACE_NAME);
+
+ if (!create_extension_intf_ || !destroy_extension_intf_) {
+ DLOGE("Unable to load symbols");
+ ::dlclose(extension_lib_);
+ return kErrorUndefined;
+ }
+
+ error = create_extension_intf_(EXTENSION_VERSION_TAG, &extension_intf_);
+ if(error != kErrorNone) {
+ DLOGE("Unable to create interface");
+ ::dlclose(extension_lib_);
+ return error;
+ }
+ } else {
+ DLOGW("Unable to load = %s", EXTENSION_LIBRARY_NAME);
+ }
+
+ error = HWInfoInterface::Create(&hw_info_intf_);
+ if (error != kErrorNone) {
+ goto CleanupOnError;
+ }
+
+ hw_resource_ = new HWResourceInfo();
+ if (!hw_resource_) {
+ error = kErrorMemory;
+ goto CleanupOnError;
+ }
+
+ error = hw_info_intf_->GetHWResourceInfo(hw_resource_);
+ if (error != kErrorNone) {
+ goto CleanupOnError;
+ }
+
+ error = comp_mgr_.Init(*hw_resource_, extension_intf_);
+ if (error != kErrorNone) {
+ goto CleanupOnError;
+ }
+
+ if (extension_intf_) {
+ error = extension_intf_->CreateRotator(buffer_allocator_, buffer_sync_handler_,
+ &rotator_intf_);
+ if (error != kErrorNone) {
+ comp_mgr_.Deinit();
+ goto CleanupOnError;
+ }
+ }
+
+ return kErrorNone;
+
+CleanupOnError:
+ if (hw_info_intf_) {
+ HWInfoInterface::Destroy(hw_info_intf_);
+ }
+
+ if (hw_resource_) {
+ delete hw_resource_;
+ }
+
+ if (extension_lib_) {
+ destroy_extension_intf_(extension_intf_);
+ ::dlclose(extension_lib_);
+ }
+
+ return error;
+}
+
+DisplayError CoreImpl::Deinit() {
+ SCOPE_LOCK(locker_);
+
+ if (extension_intf_) {
+ extension_intf_->DestroyRotator(rotator_intf_);
+ }
+
+ comp_mgr_.Deinit();
+ HWInfoInterface::Destroy(hw_info_intf_);
+
+ if (hw_resource_) {
+ delete hw_resource_;
+ }
+
+ if (extension_lib_) {
+ destroy_extension_intf_(extension_intf_);
+ ::dlclose(extension_lib_);
+ }
+
+ return kErrorNone;
+}
+
+DisplayError CoreImpl::CreateDisplay(DisplayType type, DisplayEventHandler *event_handler,
+ DisplayInterface **intf) {
+ SCOPE_LOCK(locker_);
+
+ if (!event_handler || !intf) {
+ return kErrorParameters;
+ }
+
+ DisplayBase *display_base = NULL;
+
+ switch (type) {
+ case kPrimary:
+ display_base = new DisplayPrimary(event_handler, hw_info_intf_, buffer_sync_handler_,
+ &comp_mgr_, rotator_intf_);
+ break;
+ case kHDMI:
+ display_base = new DisplayHDMI(event_handler, hw_info_intf_, buffer_sync_handler_,
+ &comp_mgr_, rotator_intf_);
+ break;
+ case kVirtual:
+ display_base = new DisplayVirtual(event_handler, hw_info_intf_, buffer_sync_handler_,
+ &comp_mgr_, rotator_intf_);
+ break;
+ default:
+ DLOGE("Spurious display type %d", type);
+ return kErrorParameters;
+ }
+
+ if (!display_base) {
+ return kErrorMemory;
+ }
+
+ DisplayError error = display_base->Init();
+ if (error != kErrorNone) {
+ display_base->Deinit();
+ delete display_base;
+ display_base = NULL;
+ return error;
+ }
+
+ *intf = display_base;
+ return kErrorNone;
+}
+
+DisplayError CoreImpl::DestroyDisplay(DisplayInterface *intf) {
+ SCOPE_LOCK(locker_);
+
+ if (!intf) {
+ return kErrorParameters;
+ }
+
+ DisplayBase *display_base = static_cast<DisplayBase *>(intf);
+ display_base->Deinit();
+ delete display_base;
+ display_base = NULL;
+
+ return kErrorNone;
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/core/core_impl.h b/sdm/libs/core/core_impl.h
new file mode 100644
index 0000000..bad241c
--- /dev/null
+++ b/sdm/libs/core/core_impl.h
@@ -0,0 +1,80 @@
+/*
+* 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __CORE_IMPL_H__
+#define __CORE_IMPL_H__
+
+#include <core/core_interface.h>
+#include <private/extension_interface.h>
+#include <utils/locker.h>
+
+#include "hw_interface.h"
+#include "comp_manager.h"
+
+#define SET_REVISION(major, minor) ((major << 8) | minor)
+
+namespace sdm {
+
+class HWInfoInterface;
+class RotatorCtrl;
+
+class CoreImpl : public CoreInterface {
+ public:
+ // This class implements display core interface revision 1.0.
+ static const uint16_t kRevision = SET_REVISION(1, 0);
+
+ CoreImpl(CoreEventHandler *event_handler, BufferAllocator *buffer_allocator,
+ BufferSyncHandler *buffer_sync_handler);
+ virtual ~CoreImpl() { }
+
+ // This method returns the interface revision for the current display core object.
+ // Future revisions will override this method and return the appropriate revision upon query.
+ virtual uint16_t GetRevision() { return kRevision; }
+ virtual DisplayError Init();
+ virtual DisplayError Deinit();
+
+ // Methods from core interface
+ virtual DisplayError CreateDisplay(DisplayType type, DisplayEventHandler *event_handler,
+ DisplayInterface **intf);
+ virtual DisplayError DestroyDisplay(DisplayInterface *intf);
+
+ protected:
+ Locker locker_;
+ CoreEventHandler *event_handler_;
+ BufferAllocator *buffer_allocator_;
+ BufferSyncHandler *buffer_sync_handler_;
+ HWResourceInfo *hw_resource_;
+ CompManager comp_mgr_;
+ HWInfoInterface *hw_info_intf_;
+ RotatorInterface *rotator_intf_;
+ void *extension_lib_;
+ ExtensionInterface *extension_intf_;
+ CreateExtensionInterface create_extension_intf_;
+ DestroyExtensionInterface destroy_extension_intf_;
+};
+
+} // namespace sdm
+
+#endif // __CORE_IMPL_H__
+
diff --git a/sdm/libs/core/core_interface.cpp b/sdm/libs/core/core_interface.cpp
new file mode 100644
index 0000000..34eceff
--- /dev/null
+++ b/sdm/libs/core/core_interface.cpp
@@ -0,0 +1,124 @@
+/*
+* 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:
+* * 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.
+*/
+
+#include <utils/locker.h>
+#include <utils/constants.h>
+#include <utils/debug.h>
+#include <core/buffer_sync_handler.h>
+
+#include "core_impl.h"
+
+#define __CLASS__ "CoreInterface"
+
+#define GET_REVISION(version) (version >> 16)
+#define GET_DATA_ALIGNMENT(version) ((version >> 8) & 0xFF)
+#define GET_INSTRUCTION_SET(version) (version & 0xFF)
+
+namespace sdm {
+
+// Currently, we support only one client and one session for display core. So, create a global
+// singleton core object.
+struct CoreSingleton {
+ CoreSingleton() : core_impl(NULL) { }
+
+ CoreImpl *core_impl;
+ Locker locker;
+} g_core;
+
+// TODO(user): Have a single structure handle carries all the interface pointers.
+DisplayError CoreInterface::CreateCore(CoreEventHandler *event_handler, DebugHandler *debug_handler,
+ BufferAllocator *buffer_allocator,
+ BufferSyncHandler *buffer_sync_handler,
+ CoreInterface **interface, uint32_t client_version) {
+ SCOPE_LOCK(g_core.locker);
+
+ if (!event_handler || !debug_handler || !buffer_allocator || !buffer_sync_handler || !interface) {
+ return kErrorParameters;
+ }
+
+ // Check compatibility of client and core.
+ uint32_t lib_version = SDM_VERSION_TAG;
+ if (GET_REVISION(client_version) > GET_REVISION(lib_version)) {
+ return kErrorVersion;
+ } else if (GET_DATA_ALIGNMENT(client_version) != GET_DATA_ALIGNMENT(lib_version)) {
+ return kErrorDataAlignment;
+ } else if (GET_INSTRUCTION_SET(client_version) != GET_INSTRUCTION_SET(lib_version)) {
+ return kErrorInstructionSet;
+ }
+
+ CoreImpl *&core_impl = g_core.core_impl;
+ if (core_impl) {
+ return kErrorUndefined;
+ }
+
+ Debug::SetDebugHandler(debug_handler);
+
+ // Create appropriate CoreImpl object based on client version.
+ if (GET_REVISION(client_version) == CoreImpl::kRevision) {
+ core_impl = new CoreImpl(event_handler, buffer_allocator, buffer_sync_handler);
+ } else {
+ return kErrorNotSupported;
+ }
+
+ if (!core_impl) {
+ return kErrorMemory;
+ }
+
+ DisplayError error = core_impl->Init();
+ if (error != kErrorNone) {
+ delete core_impl;
+ core_impl = NULL;
+ return error;
+ }
+
+ *interface = core_impl;
+ DLOGI("Open interface handle = %p", *interface);
+
+ return kErrorNone;
+}
+
+DisplayError CoreInterface::DestroyCore() {
+ SCOPE_LOCK(g_core.locker);
+
+ DLOGI("Close handle");
+
+ CoreImpl *&core_impl = g_core.core_impl;
+ if (!core_impl) {
+ return kErrorUndefined;
+ }
+
+ core_impl->Deinit();
+ delete core_impl;
+ core_impl = NULL;
+
+ return kErrorNone;
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
new file mode 100644
index 0000000..8dc9b19
--- /dev/null
+++ b/sdm/libs/core/display_base.cpp
@@ -0,0 +1,564 @@
+/*
+* 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:
+* * 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.
+*/
+
+#include <stdio.h>
+#include <utils/constants.h>
+#include <utils/debug.h>
+
+#include "display_base.h"
+
+#define __CLASS__ "DisplayBase"
+
+namespace sdm {
+
+// TODO(user): Have a single structure handle carries all the interface pointers and variables.
+DisplayBase::DisplayBase(DisplayType display_type, DisplayEventHandler *event_handler,
+ HWDeviceType hw_device_type, BufferSyncHandler *buffer_sync_handler,
+ CompManager *comp_manager, RotatorInterface *rotator_intf)
+ : display_type_(display_type), event_handler_(event_handler), hw_device_type_(hw_device_type),
+ buffer_sync_handler_(buffer_sync_handler), comp_manager_(comp_manager),
+ rotator_intf_(rotator_intf), state_(kStateOff), hw_device_(0), display_comp_ctx_(0),
+ display_attributes_(NULL), num_modes_(0), active_mode_index_(0), pending_commit_(false),
+ vsync_enable_(false), underscan_supported_(false) {
+}
+
+DisplayError DisplayBase::Init() {
+ DisplayError error = kErrorNone;
+ hw_panel_info_ = HWPanelInfo();
+ hw_intf_->GetHWPanelInfo(&hw_panel_info_);
+
+ error = hw_intf_->GetNumDisplayAttributes(&num_modes_);
+ if (error != kErrorNone) {
+ goto CleanupOnError;
+ }
+
+ display_attributes_ = new HWDisplayAttributes[num_modes_];
+ if (!display_attributes_) {
+ error = kErrorMemory;
+ goto CleanupOnError;
+ }
+
+ for (uint32_t i = 0; i < num_modes_; i++) {
+ error = hw_intf_->GetDisplayAttributes(&display_attributes_[i], i);
+ if (error != kErrorNone) {
+ goto CleanupOnError;
+ }
+ }
+
+ active_mode_index_ = GetBestConfig();
+
+ error = hw_intf_->SetDisplayAttributes(active_mode_index_);
+ if (error != kErrorNone) {
+ goto CleanupOnError;
+ }
+
+ error = comp_manager_->RegisterDisplay(display_type_, display_attributes_[active_mode_index_],
+ hw_panel_info_, &display_comp_ctx_);
+ if (error != kErrorNone) {
+ goto CleanupOnError;
+ }
+
+ if (rotator_intf_) {
+ error = rotator_intf_->RegisterDisplay(display_type_, &display_rotator_ctx_);
+ if (error != kErrorNone) {
+ goto CleanupOnError;
+ }
+ }
+
+ return kErrorNone;
+
+CleanupOnError:
+ if (display_comp_ctx_) {
+ comp_manager_->UnregisterDisplay(display_comp_ctx_);
+ }
+
+ if (display_attributes_) {
+ delete[] display_attributes_;
+ display_attributes_ = NULL;
+ }
+
+ hw_intf_->Close();
+
+ return error;
+}
+
+DisplayError DisplayBase::Deinit() {
+ if (rotator_intf_) {
+ rotator_intf_->UnregisterDisplay(display_rotator_ctx_);
+ }
+
+ comp_manager_->UnregisterDisplay(display_comp_ctx_);
+
+ if (display_attributes_) {
+ delete[] display_attributes_;
+ display_attributes_ = NULL;
+ }
+
+ hw_intf_->Close();
+
+ return kErrorNone;
+}
+
+DisplayError DisplayBase::Prepare(LayerStack *layer_stack) {
+ DisplayError error = kErrorNone;
+
+ if (!layer_stack) {
+ return kErrorParameters;
+ }
+
+ pending_commit_ = false;
+
+ if (state_ == kStateOn) {
+ // Clean hw layers for reuse.
+ hw_layers_.info = HWLayersInfo();
+ hw_layers_.info.stack = layer_stack;
+ hw_layers_.output_compression = 1.0f;
+
+ comp_manager_->PrePrepare(display_comp_ctx_, &hw_layers_);
+ while (true) {
+ error = comp_manager_->Prepare(display_comp_ctx_, &hw_layers_);
+ if (error != kErrorNone) {
+ break;
+ }
+
+ if (IsRotationRequired(&hw_layers_)) {
+ if (!rotator_intf_) {
+ continue;
+ }
+ error = rotator_intf_->Prepare(display_rotator_ctx_, &hw_layers_);
+ } else {
+ // Release all the previous rotator sessions.
+ if (rotator_intf_) {
+ error = rotator_intf_->Purge(display_rotator_ctx_, &hw_layers_);
+ }
+ }
+
+ if (error == kErrorNone) {
+ error = hw_intf_->Validate(&hw_layers_);
+ if (error == kErrorNone) {
+ // Strategy is successful now, wait for Commit().
+ pending_commit_ = true;
+ break;
+ }
+ }
+ }
+ comp_manager_->PostPrepare(display_comp_ctx_, &hw_layers_);
+ } else {
+ return kErrorNotSupported;
+ }
+
+ return error;
+}
+
+DisplayError DisplayBase::Commit(LayerStack *layer_stack) {
+ DisplayError error = kErrorNone;
+
+ if (!layer_stack) {
+ return kErrorParameters;
+ }
+
+ if (state_ != kStateOn) {
+ return kErrorNotSupported;
+ }
+
+ if (!pending_commit_) {
+ DLOGE("Commit: Corresponding Prepare() is not called for display = %d", display_type_);
+ return kErrorUndefined;
+ }
+
+ pending_commit_ = false;
+
+ if (rotator_intf_ && IsRotationRequired(&hw_layers_)) {
+ error = rotator_intf_->Commit(display_rotator_ctx_, &hw_layers_);
+ if (error != kErrorNone) {
+ return error;
+ }
+ }
+
+ error = hw_intf_->Commit(&hw_layers_);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ if (rotator_intf_ && IsRotationRequired(&hw_layers_)) {
+ error = rotator_intf_->PostCommit(display_rotator_ctx_, &hw_layers_);
+ if (error != kErrorNone) {
+ return error;
+ }
+ }
+
+ error = comp_manager_->PostCommit(display_comp_ctx_, &hw_layers_);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError DisplayBase::Flush() {
+ DisplayError error = kErrorNone;
+
+ if (state_ != kStateOn) {
+ return kErrorNone;
+ }
+
+ hw_layers_.info.count = 0;
+ error = hw_intf_->Flush();
+ if (error == kErrorNone) {
+ comp_manager_->Purge(display_comp_ctx_);
+ pending_commit_ = false;
+ } else {
+ DLOGV("Failed to flush device.");
+ }
+
+ return error;
+}
+
+DisplayError DisplayBase::GetDisplayState(DisplayState *state) {
+ if (!state) {
+ return kErrorParameters;
+ }
+
+ *state = state_;
+ return kErrorNone;
+}
+
+DisplayError DisplayBase::GetNumVariableInfoConfigs(uint32_t *count) {
+ if (!count) {
+ return kErrorParameters;
+ }
+
+ *count = num_modes_;
+
+ return kErrorNone;
+}
+
+DisplayError DisplayBase::GetConfig(DisplayConfigFixedInfo *fixed_info) {
+ if (!fixed_info) {
+ return kErrorParameters;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError DisplayBase::GetConfig(uint32_t index, DisplayConfigVariableInfo *variable_info) {
+ if (!variable_info || index >= num_modes_) {
+ return kErrorParameters;
+ }
+
+ *variable_info = display_attributes_[index];
+
+ return kErrorNone;
+}
+
+DisplayError DisplayBase::GetActiveConfig(uint32_t *index) {
+ if (!index) {
+ return kErrorParameters;
+ }
+
+ *index = active_mode_index_;
+
+ return kErrorNone;
+}
+
+DisplayError DisplayBase::GetVSyncState(bool *enabled) {
+ if (!enabled) {
+ return kErrorParameters;
+ }
+
+ return kErrorNone;
+}
+
+bool DisplayBase::IsUnderscanSupported() {
+ return underscan_supported_;
+}
+
+DisplayError DisplayBase::SetDisplayState(DisplayState state) {
+ DisplayError error = kErrorNone;
+
+ DLOGI("Set state = %d, display %d", state, display_type_);
+
+ if (state == state_) {
+ DLOGI("Same state transition is requested.");
+ return kErrorNone;
+ }
+
+ switch (state) {
+ case kStateOff:
+ hw_layers_.info.count = 0;
+ error = hw_intf_->Flush();
+ if (error == kErrorNone) {
+ comp_manager_->Purge(display_comp_ctx_);
+
+ error = hw_intf_->PowerOff();
+ }
+ break;
+
+ case kStateOn:
+ error = hw_intf_->PowerOn();
+ break;
+
+ case kStateDoze:
+ error = hw_intf_->Doze();
+ break;
+
+ case kStateDozeSuspend:
+ error = hw_intf_->DozeSuspend();
+ break;
+
+ case kStateStandby:
+ error = hw_intf_->Standby();
+ break;
+
+ default:
+ DLOGE("Spurious state = %d transition requested.", state);
+ break;
+ }
+
+ if (error == kErrorNone) {
+ state_ = state;
+ }
+
+ return error;
+}
+
+DisplayError DisplayBase::SetActiveConfig(uint32_t index) {
+ DisplayError error = kErrorNone;
+
+ if (index >= num_modes_) {
+ return kErrorParameters;
+ }
+
+ error = hw_intf_->SetDisplayAttributes(index);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ active_mode_index_ = index;
+
+ if (display_comp_ctx_) {
+ comp_manager_->UnregisterDisplay(display_comp_ctx_);
+ }
+
+ error = comp_manager_->RegisterDisplay(display_type_, display_attributes_[index], hw_panel_info_,
+ &display_comp_ctx_);
+
+ return error;
+}
+
+DisplayError DisplayBase::SetMaxMixerStages(uint32_t max_mixer_stages) {
+ DisplayError error = kErrorNone;
+
+ if (comp_manager_) {
+ error = comp_manager_->SetMaxMixerStages(display_comp_ctx_, max_mixer_stages);
+ }
+
+ return error;
+}
+
+DisplayError DisplayBase::SetDisplayMode(uint32_t mode) {
+ return kErrorNotSupported;
+}
+
+DisplayError DisplayBase::IsScalingValid(const LayerRect &crop, const LayerRect &dst,
+ bool rotate90) {
+ return comp_manager_->ValidateScaling(crop, dst, rotate90);
+}
+
+void DisplayBase::AppendDump(char *buffer, uint32_t length) {
+ DumpImpl::AppendString(buffer, length, "\n-----------------------");
+ DumpImpl::AppendString(buffer, length, "\ndevice type: %u", display_type_);
+ DumpImpl::AppendString(buffer, length, "\nstate: %u, vsync on: %u", state_, INT(vsync_enable_));
+ DumpImpl::AppendString(buffer, length, "\nnum configs: %u, active config index: %u",
+ num_modes_, active_mode_index_);
+
+ DisplayConfigVariableInfo &info = display_attributes_[active_mode_index_];
+ DumpImpl::AppendString(buffer, length, "\nres:%u x %u, dpi:%.2f x %.2f, fps:%.2f,"
+ "vsync period: %u", info.x_pixels, info.y_pixels, info.x_dpi,
+ info.y_dpi, info.fps, info.vsync_period_ns);
+
+ DumpImpl::AppendString(buffer, length, "\n");
+
+ uint32_t num_layers = 0;
+ uint32_t num_hw_layers = 0;
+ if (hw_layers_.info.stack) {
+ num_layers = hw_layers_.info.stack->layer_count;
+ num_hw_layers = hw_layers_.info.count;
+ }
+
+ if (num_hw_layers == 0) {
+ DumpImpl::AppendString(buffer, length, "\nNo hardware layers programmed");
+ return;
+ }
+
+ HWLayersInfo &layer_info = hw_layers_.info;
+ LayerRect &l_roi = layer_info.left_partial_update;
+ LayerRect &r_roi = layer_info.right_partial_update;
+ DumpImpl::AppendString(buffer, length, "\nROI(L T R B) : LEFT(%d %d %d %d), RIGHT(%d %d %d %d)",
+ INT(l_roi.left), INT(l_roi.top), INT(l_roi.right), INT(l_roi.bottom),
+ INT(r_roi.left), INT(r_roi.top), INT(r_roi.right), INT(r_roi.bottom));
+
+ const char *header = "\n| Idx | Comp Type | Split | WB | Pipe | W x H | Format | Src Rect (L T R B) | Dst Rect (L T R B) | Z | Flags | Deci(HxV) |"; //NOLINT
+ const char *newline = "\n|-----|-------------|--------|----|-------|-------------|--------------------|---------------------|---------------------|----|------------|-----------|"; //NOLINT
+ const char *format = "\n| %3s | %11s " "| %6s " "| %2s | 0x%03x | %4d x %4d | %18s " "| %4d %4d %4d %4d " "| %4d %4d %4d %4d " "| %2s | %10s " "| %9s |"; //NOLINT
+
+ DumpImpl::AppendString(buffer, length, "\n");
+ DumpImpl::AppendString(buffer, length, newline);
+ DumpImpl::AppendString(buffer, length, header);
+ DumpImpl::AppendString(buffer, length, newline);
+
+ for (uint32_t i = 0; i < num_hw_layers; i++) {
+ uint32_t layer_index = hw_layers_.info.index[i];
+ Layer &layer = hw_layers_.info.stack->layers[layer_index];
+ LayerBuffer *input_buffer = layer.input_buffer;
+ HWLayerConfig &layer_config = hw_layers_.config[i];
+ HWRotatorSession &hw_rotator_session = layer_config.hw_rotator_session;
+
+ char idx[8] = { 0 };
+ const char *comp_type = GetName(layer.composition);
+ const char *buffer_format = GetName(input_buffer->format);
+ const char *rotate_split[2] = { "Rot-L", "Rot-R" };
+ const char *comp_split[2] = { "Comp-L", "Comp-R" };
+
+ snprintf(idx, sizeof(idx), "%d", layer_index);
+
+ for (uint32_t count = 0; count < hw_rotator_session.hw_block_count; count++) {
+ char writeback_id[8];
+ HWRotateInfo &rotate = hw_rotator_session.hw_rotate_info[count];
+ LayerRect &src_roi = rotate.src_roi;
+ LayerRect &dst_roi = rotate.dst_roi;
+
+ snprintf(writeback_id, sizeof(writeback_id), "%d", rotate.writeback_id);
+
+ DumpImpl::AppendString(buffer, length, format, idx, comp_type, rotate_split[count],
+ writeback_id, rotate.pipe_id, input_buffer->width,
+ input_buffer->height, buffer_format, INT(src_roi.left),
+ INT(src_roi.top), INT(src_roi.right), INT(src_roi.bottom),
+ INT(dst_roi.left), INT(dst_roi.top), INT(dst_roi.right),
+ INT(dst_roi.bottom), "-", "- ", "- ");
+
+ // print the below only once per layer block, fill with spaces for rest.
+ idx[0] = 0;
+ comp_type = "";
+ }
+
+ if (hw_rotator_session.hw_block_count > 0) {
+ input_buffer = &hw_rotator_session.output_buffer;
+ buffer_format = GetName(input_buffer->format);
+ }
+
+ for (uint32_t count = 0; count < 2; count++) {
+ char decimation[16];
+ char flags[16];
+ char z_order[8];
+ HWPipeInfo &pipe = (count == 0) ? layer_config.left_pipe : layer_config.right_pipe;
+
+ if (!pipe.valid) {
+ continue;
+ }
+
+ LayerRect &src_roi = pipe.src_roi;
+ LayerRect &dst_roi = pipe.dst_roi;
+
+ snprintf(z_order, sizeof(z_order), "%d", pipe.z_order);
+ snprintf(flags, sizeof(flags), "0x%08x", layer.flags.flags);
+ snprintf(decimation, sizeof(decimation), "%3d x %3d", pipe.horizontal_decimation,
+ pipe.vertical_decimation);
+
+ DumpImpl::AppendString(buffer, length, format, idx, comp_type, comp_split[count],
+ "-", pipe.pipe_id, input_buffer->width, input_buffer->height,
+ buffer_format, INT(src_roi.left), INT(src_roi.top),
+ INT(src_roi.right), INT(src_roi.bottom), INT(dst_roi.left),
+ INT(dst_roi.top), INT(dst_roi.right), INT(dst_roi.bottom),
+ z_order, flags, decimation);
+
+ // print the below only once per layer block, fill with spaces for rest.
+ idx[0] = 0;
+ comp_type = "";
+ }
+
+ DumpImpl::AppendString(buffer, length, newline);
+ }
+}
+
+int DisplayBase::GetBestConfig() {
+ return (num_modes_ == 1) ? 0 : -1;
+}
+
+bool DisplayBase::IsRotationRequired(HWLayers *hw_layers) {
+ HWLayersInfo &layer_info = hw_layers->info;
+
+ for (uint32_t i = 0; i < layer_info.count; i++) {
+ Layer& layer = layer_info.stack->layers[layer_info.index[i]];
+ HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session;
+
+ if (hw_rotator_session->hw_block_count) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+const char * DisplayBase::GetName(const LayerComposition &composition) {
+ switch (composition) {
+ case kCompositionGPU: return "GPU";
+ case kCompositionSDE: return "SDE";
+ case kCompositionGPUTarget: return "GPU_TARGET";
+ default: return "UNKNOWN";
+ }
+}
+
+const char * DisplayBase::GetName(const LayerBufferFormat &format) {
+ switch (format) {
+ case kFormatARGB8888: return "ARGB_8888";
+ case kFormatRGBA8888: return "RGBA_8888";
+ case kFormatBGRA8888: return "BGRA_8888";
+ case kFormatXRGB8888: return "XRGB_8888";
+ case kFormatRGBX8888: return "RGBX_8888";
+ case kFormatBGRX8888: return "BGRX_8888";
+ case kFormatRGBA5551: return "RGBA_5551";
+ case kFormatRGBA4444: return "RGBA_4444";
+ case kFormatRGB888: return "RGB_888";
+ case kFormatBGR888: return "BGR_888";
+ case kFormatRGB565: return "RGB_565";
+ case kFormatRGBA8888Ubwc: return "RGBA_8888_UBWC";
+ case kFormatRGBX8888Ubwc: return "RGBX_8888_UBWC";
+ case kFormatRGB565Ubwc: return "RGB_565_UBWC";
+ case kFormatYCbCr420Planar: return "Y_CB_CR_420";
+ case kFormatYCrCb420Planar: return "Y_CR_CB_420";
+ case kFormatYCbCr420SemiPlanar: return "Y_CBCR_420";
+ case kFormatYCrCb420SemiPlanar: return "Y_CRCB_420";
+ case kFormatYCbCr420SemiPlanarVenus: return "Y_CBCR_420_VENUS";
+ case kFormatYCbCr422H1V2SemiPlanar: return "Y_CBCR_422_H1V2";
+ case kFormatYCrCb422H1V2SemiPlanar: return "Y_CRCB_422_H1V2";
+ case kFormatYCbCr422H2V1SemiPlanar: return "Y_CBCR_422_H2V1";
+ case kFormatYCrCb422H2V1SemiPlanar: return "Y_CRCB_422_H2V2";
+ case kFormatYCbCr420SPVenusUbwc: return "Y_CBCR_420_VENUS_UBWC";
+ case kFormatYCbCr422H2V1Packed: return "YCBYCR_422_H2V1";
+ default: return "UNKNOWN";
+ }
+}
+
+} // namespace sdm
diff --git a/sdm/libs/core/display_base.h b/sdm/libs/core/display_base.h
new file mode 100644
index 0000000..56e6682
--- /dev/null
+++ b/sdm/libs/core/display_base.h
@@ -0,0 +1,98 @@
+/*
+* 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __DISPLAY_BASE_H__
+#define __DISPLAY_BASE_H__
+
+#include <core/display_interface.h>
+#include <private/strategy_interface.h>
+#include <private/rotator_interface.h>
+#include <utils/locker.h>
+
+#include "hw_interface.h"
+#include "comp_manager.h"
+
+
+namespace sdm {
+
+class RotatorCtrl;
+
+class DisplayBase : public DisplayInterface {
+ public:
+ DisplayBase(DisplayType display_type, DisplayEventHandler *event_handler,
+ HWDeviceType hw_device_type, BufferSyncHandler *buffer_sync_handler,
+ CompManager *comp_manager, RotatorInterface *rotator_intf);
+ virtual ~DisplayBase() { }
+ virtual DisplayError Init();
+ virtual DisplayError Deinit();
+ virtual DisplayError Prepare(LayerStack *layer_stack);
+ virtual DisplayError Commit(LayerStack *layer_stack);
+ virtual DisplayError Flush();
+ virtual DisplayError GetDisplayState(DisplayState *state);
+ virtual DisplayError GetNumVariableInfoConfigs(uint32_t *count);
+ virtual DisplayError GetConfig(DisplayConfigFixedInfo *fixed_info);
+ virtual DisplayError GetConfig(uint32_t index, DisplayConfigVariableInfo *variable_info);
+ virtual DisplayError GetActiveConfig(uint32_t *index);
+ virtual DisplayError GetVSyncState(bool *enabled);
+ virtual DisplayError SetDisplayState(DisplayState state);
+ virtual DisplayError SetActiveConfig(uint32_t index);
+ virtual DisplayError SetMaxMixerStages(uint32_t max_mixer_stages);
+ virtual DisplayError SetDisplayMode(uint32_t mode);
+ virtual DisplayError IsScalingValid(const LayerRect &crop, const LayerRect &dst, bool rotate90);
+ virtual bool IsUnderscanSupported();
+
+ protected:
+ // DumpImpl method
+ void AppendDump(char *buffer, uint32_t length);
+
+ virtual int GetBestConfig();
+ bool IsRotationRequired(HWLayers *hw_layers);
+ const char * GetName(const LayerComposition &composition);
+ const char * GetName(const LayerBufferFormat &format);
+
+ DisplayType display_type_;
+ DisplayEventHandler *event_handler_;
+ HWDeviceType hw_device_type_;
+ HWInterface *hw_intf_;
+ HWPanelInfo hw_panel_info_;
+ BufferSyncHandler *buffer_sync_handler_;
+ CompManager *comp_manager_;
+ RotatorInterface *rotator_intf_;
+ DisplayState state_;
+ Handle hw_device_;
+ Handle display_comp_ctx_;
+ Handle display_rotator_ctx_;
+ HWDisplayAttributes *display_attributes_;
+ uint32_t num_modes_;
+ uint32_t active_mode_index_;
+ HWLayers hw_layers_;
+ bool pending_commit_;
+ bool vsync_enable_;
+ bool underscan_supported_;
+};
+
+} // namespace sdm
+
+#endif // __DISPLAY_BASE_H__
+
diff --git a/sdm/libs/core/display_hdmi.cpp b/sdm/libs/core/display_hdmi.cpp
new file mode 100644
index 0000000..ef25b90
--- /dev/null
+++ b/sdm/libs/core/display_hdmi.cpp
@@ -0,0 +1,251 @@
+/*
+* 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:
+* * 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.
+*/
+
+#include <utils/constants.h>
+#include <utils/debug.h>
+
+#include "display_hdmi.h"
+#include "hw_hdmi_interface.h"
+#include "hw_info_interface.h"
+
+#define __CLASS__ "DisplayHDMI"
+
+namespace sdm {
+
+DisplayHDMI::DisplayHDMI(DisplayEventHandler *event_handler, HWInfoInterface *hw_info_intf,
+ BufferSyncHandler *buffer_sync_handler, CompManager *comp_manager,
+ RotatorInterface *rotator_intf)
+ : DisplayBase(kHDMI, event_handler, kDeviceHDMI, buffer_sync_handler, comp_manager,
+ rotator_intf), hw_info_intf_(hw_info_intf) {
+}
+
+DisplayError DisplayHDMI::Init() {
+ SCOPE_LOCK(locker_);
+
+ DisplayError error = HWHDMIInterface::Create(&hw_hdmi_intf_, hw_info_intf_,
+ DisplayBase::buffer_sync_handler_);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ DisplayBase::hw_intf_ = hw_hdmi_intf_;
+ error = hw_hdmi_intf_->Open(NULL);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ error = DisplayBase::Init();
+ if (error != kErrorNone) {
+ HWHDMIInterface::Destroy(hw_hdmi_intf_);
+ }
+
+ GetScanSupport();
+ underscan_supported_ = (scan_support_ == kScanAlwaysUnderscanned) || (scan_support_ == kScanBoth);
+
+ return error;
+}
+
+DisplayError DisplayHDMI::Deinit() {
+ SCOPE_LOCK(locker_);
+
+ DisplayError error = DisplayBase::Deinit();
+ if (error != kErrorNone) {
+ return error;
+ }
+ HWHDMIInterface::Destroy(hw_hdmi_intf_);
+
+ return error;
+}
+
+DisplayError DisplayHDMI::Prepare(LayerStack *layer_stack) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::Prepare(layer_stack);
+}
+
+DisplayError DisplayHDMI::Commit(LayerStack *layer_stack) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::Commit(layer_stack);
+}
+
+DisplayError DisplayHDMI::Flush() {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::Flush();
+}
+
+DisplayError DisplayHDMI::GetDisplayState(DisplayState *state) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::GetDisplayState(state);
+}
+
+DisplayError DisplayHDMI::GetNumVariableInfoConfigs(uint32_t *count) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::GetNumVariableInfoConfigs(count);
+}
+
+DisplayError DisplayHDMI::GetConfig(DisplayConfigFixedInfo *fixed_info) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::GetConfig(fixed_info);
+}
+
+DisplayError DisplayHDMI::GetConfig(uint32_t index, DisplayConfigVariableInfo *variable_info) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::GetConfig(index, variable_info);
+}
+
+DisplayError DisplayHDMI::GetActiveConfig(uint32_t *index) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::GetActiveConfig(index);
+}
+
+DisplayError DisplayHDMI::GetVSyncState(bool *enabled) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::GetVSyncState(enabled);
+}
+
+DisplayError DisplayHDMI::SetDisplayState(DisplayState state) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::SetDisplayState(state);
+}
+
+DisplayError DisplayHDMI::SetActiveConfig(DisplayConfigVariableInfo *variable_info) {
+ SCOPE_LOCK(locker_);
+ return kErrorNotSupported;
+}
+
+DisplayError DisplayHDMI::SetActiveConfig(uint32_t index) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::SetActiveConfig(index);
+}
+
+DisplayError DisplayHDMI::SetVSyncState(bool enable) {
+ SCOPE_LOCK(locker_);
+ return kErrorNotSupported;
+}
+
+void DisplayHDMI::SetIdleTimeoutMs(uint32_t timeout_ms) { }
+
+DisplayError DisplayHDMI::SetMaxMixerStages(uint32_t max_mixer_stages) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::SetMaxMixerStages(max_mixer_stages);
+}
+
+DisplayError DisplayHDMI::SetDisplayMode(uint32_t mode) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::SetDisplayMode(mode);
+}
+
+DisplayError DisplayHDMI::IsScalingValid(const LayerRect &crop, const LayerRect &dst,
+ bool rotate90) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::IsScalingValid(crop, dst, rotate90);
+}
+
+DisplayError DisplayHDMI::SetRefreshRate(uint32_t refresh_rate) {
+ SCOPE_LOCK(locker_);
+ return kErrorNotSupported;
+}
+
+bool DisplayHDMI::IsUnderscanSupported() {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::IsUnderscanSupported();
+}
+
+int DisplayHDMI::GetBestConfig() {
+ uint32_t best_config_mode = 0;
+ HWDisplayAttributes *best = &display_attributes_[0];
+ if (num_modes_ == 1) {
+ return best_config_mode;
+ }
+
+ // From the available configs, select the best
+ // Ex: 1920x1080@60Hz is better than 1920x1080@30 and 1920x1080@30 is better than 1280x720@60
+ for (uint32_t index = 1; index < num_modes_; index++) {
+ HWDisplayAttributes *current = &display_attributes_[index];
+ // compare the two modes: in the order of Resolution followed by refreshrate
+ if (current->y_pixels > best->y_pixels) {
+ best_config_mode = index;
+ } else if (current->y_pixels == best->y_pixels) {
+ if (current->x_pixels > best->x_pixels) {
+ best_config_mode = index;
+ } else if (current->x_pixels == best->x_pixels) {
+ if (current->vsync_period_ns < best->vsync_period_ns) {
+ best_config_mode = index;
+ }
+ }
+ }
+ if (best_config_mode == index) {
+ best = &display_attributes_[index];
+ }
+ }
+
+ // Used for changing HDMI Resolution - override the best with user set config
+ uint32_t user_config = Debug::GetHDMIResolution();
+ if (user_config) {
+ uint32_t config_index = -1;
+ // For the config, get the corresponding index
+ DisplayError error = hw_intf_->GetConfigIndex(user_config, &config_index);
+ if (error == kErrorNone)
+ return config_index;
+ }
+
+ return best_config_mode;
+}
+
+void DisplayHDMI::GetScanSupport() {
+ DisplayError error = kErrorNone;
+ uint32_t video_format = -1;
+ uint32_t max_cea_format = -1;
+ HWScanInfo scan_info = HWScanInfo();
+ hw_hdmi_intf_->GetHWScanInfo(&scan_info);
+
+ error = hw_hdmi_intf_->GetVideoFormat(active_mode_index_, &video_format);
+ if (error != kErrorNone) {
+ return;
+ }
+
+ error = hw_hdmi_intf_->GetMaxCEAFormat(&max_cea_format);
+ if (error != kErrorNone) {
+ return;
+ }
+
+ // The scan support for a given HDMI TV must be read from scan info corresponding to
+ // Preferred Timing if the preferred timing of the display is currently active, and if it is
+ // valid. In all other cases, we must read the scan support from CEA scan info if
+ // the resolution is a CEA resolution, or from IT scan info for all other resolutions.
+ if (active_mode_index_ == 0 && scan_info.pt_scan_support != kScanNotSupported) {
+ scan_support_ = scan_info.pt_scan_support;
+ } else if (video_format < max_cea_format) {
+ scan_support_ = scan_info.cea_scan_support;
+ } else {
+ scan_support_ = scan_info.it_scan_support;
+ }
+}
+
+void DisplayHDMI::AppendDump(char *buffer, uint32_t length) {
+ SCOPE_LOCK(locker_);
+ DisplayBase::AppendDump(buffer, length);
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/core/display_hdmi.h b/sdm/libs/core/display_hdmi.h
new file mode 100644
index 0000000..96b9eea
--- /dev/null
+++ b/sdm/libs/core/display_hdmi.h
@@ -0,0 +1,77 @@
+/*
+* 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __DISPLAY_HDMI_H__
+#define __DISPLAY_HDMI_H__
+
+#include "display_base.h"
+#include "dump_impl.h"
+
+namespace sdm {
+
+class HWHDMIInterface;
+class HWInfoInterface;
+
+class DisplayHDMI : public DisplayBase, DumpImpl {
+ public:
+ DisplayHDMI(DisplayEventHandler *event_handler, HWInfoInterface *hw_info_intf,
+ BufferSyncHandler *buffer_sync_handler, CompManager *comp_manager,
+ RotatorInterface *rotator_intf);
+ virtual DisplayError Init();
+ virtual DisplayError Deinit();
+ virtual DisplayError Prepare(LayerStack *layer_stack);
+ virtual DisplayError Commit(LayerStack *layer_stack);
+ virtual DisplayError Flush();
+ virtual DisplayError GetDisplayState(DisplayState *state);
+ virtual DisplayError GetNumVariableInfoConfigs(uint32_t *count);
+ virtual DisplayError GetConfig(DisplayConfigFixedInfo *fixed_info);
+ virtual DisplayError GetConfig(uint32_t index, DisplayConfigVariableInfo *variable_info);
+ virtual DisplayError GetActiveConfig(uint32_t *index);
+ virtual DisplayError GetVSyncState(bool *enabled);
+ virtual DisplayError SetDisplayState(DisplayState state);
+ virtual DisplayError SetActiveConfig(DisplayConfigVariableInfo *variable_info);
+ virtual DisplayError SetActiveConfig(uint32_t index);
+ virtual DisplayError SetVSyncState(bool enable);
+ virtual void SetIdleTimeoutMs(uint32_t timeout_ms);
+ virtual DisplayError SetMaxMixerStages(uint32_t max_mixer_stages);
+ virtual DisplayError SetDisplayMode(uint32_t mode);
+ virtual DisplayError IsScalingValid(const LayerRect &crop, const LayerRect &dst, bool rotate90);
+ virtual DisplayError SetRefreshRate(uint32_t refresh_rate);
+ virtual bool IsUnderscanSupported();
+ virtual void AppendDump(char *buffer, uint32_t length);
+
+ private:
+ virtual int GetBestConfig();
+ virtual void GetScanSupport();
+
+ Locker locker_;
+ HWHDMIInterface *hw_hdmi_intf_;
+ HWInfoInterface *hw_info_intf_;
+ HWScanSupport scan_support_;
+};
+
+} // namespace sdm
+
+#endif // __DISPLAY_HDMI_H__
+
diff --git a/sdm/libs/core/display_primary.cpp b/sdm/libs/core/display_primary.cpp
new file mode 100644
index 0000000..63ee78b
--- /dev/null
+++ b/sdm/libs/core/display_primary.cpp
@@ -0,0 +1,292 @@
+/*
+* 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:
+* * 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.
+*/
+
+#include <utils/constants.h>
+#include <utils/debug.h>
+
+#include "display_primary.h"
+#include "hw_primary_interface.h"
+#include "hw_info_interface.h"
+
+#define __CLASS__ "DisplayPrimary"
+
+namespace sdm {
+
+DisplayPrimary::DisplayPrimary(DisplayEventHandler *event_handler, HWInfoInterface *hw_info_intf,
+ BufferSyncHandler *buffer_sync_handler, CompManager *comp_manager,
+ RotatorInterface *rotator_intf)
+ : DisplayBase(kPrimary, event_handler, kDevicePrimary, buffer_sync_handler, comp_manager,
+ rotator_intf), hw_info_intf_(hw_info_intf) {
+}
+
+DisplayError DisplayPrimary::Init() {
+ SCOPE_LOCK(locker_);
+
+ DisplayError error = HWPrimaryInterface::Create(&hw_primary_intf_, hw_info_intf_,
+ DisplayBase::buffer_sync_handler_);
+ if (error != kErrorNone) {
+ return error;
+ }
+ DisplayBase::hw_intf_ = hw_primary_intf_;
+
+ error = hw_primary_intf_->Open(this);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ error = DisplayBase::Init();
+ if (error != kErrorNone) {
+ HWPrimaryInterface::Destroy(hw_primary_intf_);
+ }
+
+ // Idle fallback feature is supported only for video mode panel.
+ if (hw_panel_info_.mode == kModeVideo) {
+ hw_primary_intf_->SetIdleTimeoutMs(Debug::GetIdleTimeoutMs());
+ }
+
+ return error;
+}
+
+DisplayError DisplayPrimary::Deinit() {
+ SCOPE_LOCK(locker_);
+
+ DisplayError error = DisplayBase::Deinit();
+ if (error != kErrorNone) {
+ return error;
+ }
+ HWPrimaryInterface::Destroy(hw_primary_intf_);
+
+ return error;
+}
+
+DisplayError DisplayPrimary::Prepare(LayerStack *layer_stack) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::Prepare(layer_stack);
+}
+
+DisplayError DisplayPrimary::Commit(LayerStack *layer_stack) {
+ SCOPE_LOCK(locker_);
+ DisplayError error = kErrorNone;
+ HWPanelInfo panel_info;
+ HWDisplayAttributes display_attributes;
+
+ error = DisplayBase::Commit(layer_stack);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ hw_primary_intf_->GetHWPanelInfo(&panel_info);
+
+ hw_primary_intf_->GetDisplayAttributes(&display_attributes, active_mode_index_);
+
+ if (panel_info != hw_panel_info_ ||
+ display_attributes != display_attributes_[active_mode_index_]) {
+ comp_manager_->ReconfigureDisplay(display_comp_ctx_, display_attributes, panel_info);
+
+ hw_panel_info_ = panel_info;
+ display_attributes_[active_mode_index_] = display_attributes;
+ }
+
+ return error;
+}
+
+DisplayError DisplayPrimary::Flush() {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::Flush();
+}
+
+DisplayError DisplayPrimary::GetDisplayState(DisplayState *state) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::GetDisplayState(state);
+}
+
+DisplayError DisplayPrimary::GetNumVariableInfoConfigs(uint32_t *count) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::GetNumVariableInfoConfigs(count);
+}
+
+DisplayError DisplayPrimary::GetConfig(DisplayConfigFixedInfo *fixed_info) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::GetConfig(fixed_info);
+}
+
+DisplayError DisplayPrimary::GetConfig(uint32_t index, DisplayConfigVariableInfo *variable_info) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::GetConfig(index, variable_info);
+}
+
+DisplayError DisplayPrimary::GetActiveConfig(uint32_t *index) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::GetActiveConfig(index);
+}
+
+DisplayError DisplayPrimary::GetVSyncState(bool *enabled) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::GetVSyncState(enabled);
+}
+
+bool DisplayPrimary::IsUnderscanSupported() {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::IsUnderscanSupported();
+}
+
+DisplayError DisplayPrimary::SetDisplayState(DisplayState state) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::SetDisplayState(state);
+}
+
+DisplayError DisplayPrimary::SetActiveConfig(DisplayConfigVariableInfo *variable_info) {
+ SCOPE_LOCK(locker_);
+ return kErrorNotSupported;
+}
+
+DisplayError DisplayPrimary::SetActiveConfig(uint32_t index) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::SetActiveConfig(index);
+}
+
+DisplayError DisplayPrimary::SetVSyncState(bool enable) {
+ SCOPE_LOCK(locker_);
+ DisplayError error = kErrorNone;
+ if (vsync_enable_ != enable) {
+ error = hw_primary_intf_->SetVSyncState(enable);
+ if (error == kErrorNone) {
+ vsync_enable_ = enable;
+ }
+ }
+
+ return error;
+}
+
+void DisplayPrimary::SetIdleTimeoutMs(uint32_t timeout_ms) {
+ SCOPE_LOCK(locker_);
+ // Idle fallback feature is supported only for video mode panel.
+ if (hw_panel_info_.mode == kModeVideo) {
+ hw_primary_intf_->SetIdleTimeoutMs(timeout_ms);
+ }
+}
+
+DisplayError DisplayPrimary::SetMaxMixerStages(uint32_t max_mixer_stages) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::SetMaxMixerStages(max_mixer_stages);
+}
+
+DisplayError DisplayPrimary::SetDisplayMode(uint32_t mode) {
+ SCOPE_LOCK(locker_);
+ DisplayError error = kErrorNone;
+ HWDisplayMode hw_display_mode = kModeDefault;
+
+ if (state_ != kStateOn) {
+ DLOGW("Invalid display state (%d). Panel must be on.", state_);
+ return kErrorNotSupported;
+ }
+
+ switch (mode) {
+ case kModeVideo:
+ hw_display_mode = kModeVideo;
+ break;
+ case kModeCommand:
+ hw_display_mode = kModeCommand;
+ break;
+ default:
+ DLOGW("Invalid panel mode parameters. Requested (%d)", mode);
+ return kErrorParameters;
+ }
+
+ if (hw_display_mode == hw_panel_info_.mode) {
+ DLOGW("Same display mode requested. Current (%d) Requested (%d)", hw_panel_info_.mode,
+ hw_display_mode);
+ return kErrorNone;
+ }
+
+ error = hw_primary_intf_->SetDisplayMode(hw_display_mode);
+ if (error != kErrorNone) {
+ DLOGW("Retaining current display mode. Current (%d), Requested (%d)", hw_panel_info_.mode,
+ hw_display_mode);
+ return error;
+ }
+
+ return error;
+}
+
+DisplayError DisplayPrimary::IsScalingValid(const LayerRect &crop, const LayerRect &dst,
+ bool rotate90) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::IsScalingValid(crop, dst, rotate90);
+}
+
+DisplayError DisplayPrimary::SetRefreshRate(uint32_t refresh_rate) {
+ SCOPE_LOCK(locker_);
+
+ DisplayError error = kErrorNone;
+
+ if (!hw_panel_info_.dynamic_fps) {
+ DLOGW("Dynamic fps feature is not supported");
+ return kErrorNotSupported;
+ }
+
+ if (refresh_rate > hw_panel_info_.max_fps) {
+ refresh_rate = hw_panel_info_.max_fps;
+ } else if (refresh_rate < hw_panel_info_.min_fps) {
+ refresh_rate = hw_panel_info_.min_fps;
+ }
+
+ return hw_primary_intf_->SetRefreshRate(refresh_rate);
+}
+
+void DisplayPrimary::AppendDump(char *buffer, uint32_t length) {
+ SCOPE_LOCK(locker_);
+ DisplayBase::AppendDump(buffer, length);
+}
+
+DisplayError DisplayPrimary::VSync(int64_t timestamp) {
+ if (vsync_enable_) {
+ DisplayEventVSync vsync;
+ vsync.timestamp = timestamp;
+ event_handler_->VSync(vsync);
+ }
+
+ return kErrorNone;
+}
+
+DisplayError DisplayPrimary::Blank(bool blank) {
+ SCOPE_LOCK(locker_);
+ return kErrorNone;
+}
+
+void DisplayPrimary::IdleTimeout() {
+ SCOPE_LOCK(locker_);
+ bool need_refresh = comp_manager_->ProcessIdleTimeout(display_comp_ctx_);
+ if (need_refresh) {
+ event_handler_->Refresh();
+ }
+}
+
+void DisplayPrimary::ThermalEvent(int64_t thermal_level) {
+ SCOPE_LOCK(locker_);
+ comp_manager_->ProcessThermalEvent(display_comp_ctx_, thermal_level);
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/core/display_primary.h b/sdm/libs/core/display_primary.h
new file mode 100644
index 0000000..2cbae4b
--- /dev/null
+++ b/sdm/libs/core/display_primary.h
@@ -0,0 +1,79 @@
+/*
+* 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __DISPLAY_PRIMARY_H__
+#define __DISPLAY_PRIMARY_H__
+
+#include "display_base.h"
+#include "dump_impl.h"
+
+namespace sdm {
+
+class HWPrimaryInterface;
+class HWInfoInterface;
+
+class DisplayPrimary : public DisplayBase, DumpImpl, HWEventHandler {
+ public:
+ DisplayPrimary(DisplayEventHandler *event_handler, HWInfoInterface *hw_info_intf,
+ BufferSyncHandler *buffer_sync_handler, CompManager *comp_manager,
+ RotatorInterface *rotator_intf);
+ virtual DisplayError Init();
+ virtual DisplayError Deinit();
+ virtual DisplayError Prepare(LayerStack *layer_stack);
+ virtual DisplayError Commit(LayerStack *layer_stack);
+ virtual DisplayError Flush();
+ virtual DisplayError GetDisplayState(DisplayState *state);
+ virtual DisplayError GetNumVariableInfoConfigs(uint32_t *count);
+ virtual DisplayError GetConfig(DisplayConfigFixedInfo *fixed_info);
+ virtual DisplayError GetConfig(uint32_t index, DisplayConfigVariableInfo *variable_info);
+ virtual DisplayError GetActiveConfig(uint32_t *index);
+ virtual DisplayError GetVSyncState(bool *enabled);
+ virtual DisplayError SetDisplayState(DisplayState state);
+ virtual DisplayError SetActiveConfig(DisplayConfigVariableInfo *variable_info);
+ virtual DisplayError SetActiveConfig(uint32_t index);
+ virtual DisplayError SetVSyncState(bool enable);
+ virtual void SetIdleTimeoutMs(uint32_t timeout_ms);
+ virtual DisplayError SetMaxMixerStages(uint32_t max_mixer_stages);
+ virtual DisplayError SetDisplayMode(uint32_t mode);
+ virtual DisplayError IsScalingValid(const LayerRect &crop, const LayerRect &dst, bool rotate90);
+ virtual DisplayError SetRefreshRate(uint32_t refresh_rate);
+ virtual bool IsUnderscanSupported();
+ virtual void AppendDump(char *buffer, uint32_t length);
+
+ // Implement the HWEventHandlers
+ virtual DisplayError VSync(int64_t timestamp);
+ virtual DisplayError Blank(bool blank);
+ virtual void IdleTimeout();
+ virtual void ThermalEvent(int64_t thermal_level);
+
+ private:
+ Locker locker_;
+ HWPrimaryInterface *hw_primary_intf_;
+ HWInfoInterface *hw_info_intf_;
+};
+
+} // namespace sdm
+
+#endif // __DISPLAY_PRIMARY_H__
+
diff --git a/sdm/libs/core/display_virtual.cpp b/sdm/libs/core/display_virtual.cpp
new file mode 100644
index 0000000..262db7f
--- /dev/null
+++ b/sdm/libs/core/display_virtual.cpp
@@ -0,0 +1,203 @@
+/*
+* 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:
+* * 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.
+*/
+
+#include <utils/constants.h>
+#include <utils/debug.h>
+
+#include "display_virtual.h"
+#include "hw_virtual_interface.h"
+#include "hw_info_interface.h"
+
+#define __CLASS__ "DisplayVirtual"
+
+namespace sdm {
+
+DisplayVirtual::DisplayVirtual(DisplayEventHandler *event_handler, HWInfoInterface *hw_info_intf,
+ BufferSyncHandler *buffer_sync_handler, CompManager *comp_manager,
+ RotatorInterface *rotator_intf)
+ : DisplayBase(kVirtual, event_handler, kDeviceVirtual, buffer_sync_handler, comp_manager,
+ rotator_intf), hw_info_intf_(hw_info_intf) {
+}
+
+DisplayError DisplayVirtual::Init() {
+ SCOPE_LOCK(locker_);
+
+ DisplayError error = HWVirtualInterface::Create(&hw_virtual_intf_, hw_info_intf_,
+ DisplayBase::buffer_sync_handler_);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ DisplayBase::hw_intf_ = hw_virtual_intf_;
+ error = hw_virtual_intf_->Open(NULL);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ error = DisplayBase::Init();
+ if (error != kErrorNone) {
+ HWVirtualInterface::Destroy(hw_virtual_intf_);
+ }
+
+ return error;
+}
+
+DisplayError DisplayVirtual::Deinit() {
+ SCOPE_LOCK(locker_);
+
+ DisplayError error = DisplayBase::Deinit();
+ if (error != kErrorNone) {
+ return error;
+ }
+ HWVirtualInterface::Destroy(hw_virtual_intf_);
+
+ return error;
+}
+
+DisplayError DisplayVirtual::Prepare(LayerStack *layer_stack) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::Prepare(layer_stack);
+}
+
+DisplayError DisplayVirtual::Commit(LayerStack *layer_stack) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::Commit(layer_stack);
+}
+
+DisplayError DisplayVirtual::Flush() {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::Flush();
+}
+
+DisplayError DisplayVirtual::GetDisplayState(DisplayState *state) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::GetDisplayState(state);
+}
+
+DisplayError DisplayVirtual::GetNumVariableInfoConfigs(uint32_t *count) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::GetNumVariableInfoConfigs(count);
+}
+
+DisplayError DisplayVirtual::GetConfig(DisplayConfigFixedInfo *fixed_info) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::GetConfig(fixed_info);
+}
+
+DisplayError DisplayVirtual::GetConfig(uint32_t index, DisplayConfigVariableInfo *variable_info) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::GetConfig(index, variable_info);
+}
+
+DisplayError DisplayVirtual::GetActiveConfig(uint32_t *index) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::GetActiveConfig(index);
+}
+
+DisplayError DisplayVirtual::GetVSyncState(bool *enabled) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::GetVSyncState(enabled);
+}
+
+bool DisplayVirtual::IsUnderscanSupported() {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::IsUnderscanSupported();
+}
+
+DisplayError DisplayVirtual::SetDisplayState(DisplayState state) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::SetDisplayState(state);
+}
+
+DisplayError DisplayVirtual::SetActiveConfig(DisplayConfigVariableInfo *variable_info) {
+ SCOPE_LOCK(locker_);
+ DisplayError error = kErrorNone;
+
+ if (!variable_info) {
+ return kErrorParameters;
+ }
+
+ HWDisplayAttributes display_attributes = display_attributes_[active_mode_index_];
+
+ display_attributes.x_pixels = variable_info->x_pixels;
+ display_attributes.y_pixels = variable_info->y_pixels;
+ display_attributes.fps = variable_info->fps;
+
+ // if display is already connected, unregister display from composition manager and register
+ // the display with new configuration.
+ if (display_comp_ctx_) {
+ comp_manager_->UnregisterDisplay(display_comp_ctx_);
+ }
+
+ error = comp_manager_->RegisterDisplay(display_type_, display_attributes, hw_panel_info_,
+ &display_comp_ctx_);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ display_attributes_[active_mode_index_] = display_attributes;
+
+ return error;
+}
+
+DisplayError DisplayVirtual::SetActiveConfig(uint32_t index) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::SetActiveConfig(index);
+}
+
+DisplayError DisplayVirtual::SetVSyncState(bool enable) {
+ SCOPE_LOCK(locker_);
+ return kErrorNotSupported;
+}
+
+void DisplayVirtual::SetIdleTimeoutMs(uint32_t timeout_ms) { }
+
+DisplayError DisplayVirtual::SetMaxMixerStages(uint32_t max_mixer_stages) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::SetMaxMixerStages(max_mixer_stages);
+}
+
+DisplayError DisplayVirtual::SetDisplayMode(uint32_t mode) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::SetDisplayMode(mode);
+}
+
+DisplayError DisplayVirtual::IsScalingValid(const LayerRect &crop, const LayerRect &dst,
+ bool rotate90) {
+ SCOPE_LOCK(locker_);
+ return DisplayBase::IsScalingValid(crop, dst, rotate90);
+}
+
+DisplayError DisplayVirtual::SetRefreshRate(uint32_t refresh_rate) {
+ SCOPE_LOCK(locker_);
+ return kErrorNotSupported;
+}
+
+void DisplayVirtual::AppendDump(char *buffer, uint32_t length) {
+ SCOPE_LOCK(locker_);
+ DisplayBase::AppendDump(buffer, length);
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/core/display_virtual.h b/sdm/libs/core/display_virtual.h
new file mode 100644
index 0000000..2065534
--- /dev/null
+++ b/sdm/libs/core/display_virtual.h
@@ -0,0 +1,73 @@
+/*
+* 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __DISPLAY_VIRTUAL_H__
+#define __DISPLAY_VIRTUAL_H__
+
+#include "display_base.h"
+#include "dump_impl.h"
+
+namespace sdm {
+
+class HWVirtualInterface;
+class HWInfoInterface;
+
+class DisplayVirtual : public DisplayBase, DumpImpl {
+ public:
+ DisplayVirtual(DisplayEventHandler *event_handler, HWInfoInterface *hw_info_intf,
+ BufferSyncHandler *buffer_sync_handler, CompManager *comp_manager,
+ RotatorInterface *rotator_intf);
+ virtual DisplayError Init();
+ virtual DisplayError Deinit();
+ virtual DisplayError Prepare(LayerStack *layer_stack);
+ virtual DisplayError Commit(LayerStack *layer_stack);
+ virtual DisplayError Flush();
+ virtual DisplayError GetDisplayState(DisplayState *state);
+ virtual DisplayError GetNumVariableInfoConfigs(uint32_t *count);
+ virtual DisplayError GetConfig(DisplayConfigFixedInfo *fixed_info);
+ virtual DisplayError GetConfig(uint32_t index, DisplayConfigVariableInfo *variable_info);
+ virtual DisplayError GetActiveConfig(uint32_t *index);
+ virtual DisplayError GetVSyncState(bool *enabled);
+ virtual DisplayError SetDisplayState(DisplayState state);
+ virtual DisplayError SetActiveConfig(DisplayConfigVariableInfo *variable_info);
+ virtual DisplayError SetActiveConfig(uint32_t index);
+ virtual DisplayError SetVSyncState(bool enable);
+ virtual void SetIdleTimeoutMs(uint32_t timeout_ms);
+ virtual DisplayError SetMaxMixerStages(uint32_t max_mixer_stages);
+ virtual DisplayError SetDisplayMode(uint32_t mode);
+ virtual DisplayError IsScalingValid(const LayerRect &crop, const LayerRect &dst, bool rotate90);
+ virtual DisplayError SetRefreshRate(uint32_t refresh_rate);
+ virtual bool IsUnderscanSupported();
+ virtual void AppendDump(char *buffer, uint32_t length);
+
+ private:
+ Locker locker_;
+ HWVirtualInterface *hw_virtual_intf_;
+ HWInfoInterface *hw_info_intf_;
+};
+
+} // namespace sdm
+
+#endif // __DISPLAY_VIRTUAL_H__
+
diff --git a/sdm/libs/core/dump_impl.cpp b/sdm/libs/core/dump_impl.cpp
new file mode 100644
index 0000000..0d6c9b2
--- /dev/null
+++ b/sdm/libs/core/dump_impl.cpp
@@ -0,0 +1,93 @@
+/*
+* 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.
+*/
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <utils/constants.h>
+
+#include "dump_impl.h"
+
+namespace sdm {
+
+DumpImpl* DumpImpl::dump_list_[] = { 0 };
+uint32_t DumpImpl::dump_count_ = 0;
+
+DisplayError DumpInterface::GetDump(char *buffer, uint32_t length) {
+ if (!buffer || !length) {
+ return kErrorParameters;
+ }
+
+ buffer[0] = '\0';
+ DumpImpl::AppendString(buffer, length, "\n-------- Snapdragon Display Manager --------");
+ for (uint32_t i = 0; i < DumpImpl::dump_count_; i++) {
+ DumpImpl::dump_list_[i]->AppendDump(buffer, length);
+ }
+ DumpImpl::AppendString(buffer, length, "\n\n");
+
+ return kErrorNone;
+}
+
+DumpImpl::DumpImpl() {
+ Register(this);
+}
+
+DumpImpl::~DumpImpl() {
+ Unregister(this);
+}
+
+void DumpImpl::AppendString(char *buffer, uint32_t length, const char *format, ...) {
+ uint32_t filled = UINT32(strlen(buffer));
+ if (filled >= length) {
+ return;
+ }
+ buffer += filled;
+
+ va_list list;
+ va_start(list, format);
+ vsnprintf(buffer, length - filled, format, list);
+}
+
+// Every object is created or destroyed through display core only, which itself protects the
+// the access, so no need to protect registration or de-registration.
+void DumpImpl::Register(DumpImpl *dump_impl) {
+ if (dump_count_ < kMaxDumpObjects) {
+ dump_list_[dump_count_] = dump_impl;
+ dump_count_++;
+ }
+}
+
+void DumpImpl::Unregister(DumpImpl *dump_impl) {
+ for (uint32_t i = 0; i < dump_count_; i++) {
+ if (dump_list_[i] == dump_impl) {
+ dump_count_--;
+ for (; i < dump_count_; i++) {
+ dump_list_[i] = dump_list_[i + 1];
+ }
+ }
+ }
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/core/dump_impl.h b/sdm/libs/core/dump_impl.h
new file mode 100644
index 0000000..123c568
--- /dev/null
+++ b/sdm/libs/core/dump_impl.h
@@ -0,0 +1,58 @@
+/*
+* 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.
+*/
+
+#ifndef __DUMP_IMPL_H__
+#define __DUMP_IMPL_H__
+
+#include <core/dump_interface.h>
+
+namespace sdm {
+
+class DumpImpl {
+ public:
+ // To be implemented in the modules which will add dump information to final dump buffer.
+ // buffer address & length will be already adjusted before calling into these modules.
+ virtual void AppendDump(char *buffer, uint32_t length) = 0;
+ static void AppendString(char *buffer, uint32_t length, const char *format, ...);
+
+ protected:
+ DumpImpl();
+ virtual ~DumpImpl();
+
+ private:
+ static const uint32_t kMaxDumpObjects = 32;
+
+ static void Register(DumpImpl *dump_impl);
+ static void Unregister(DumpImpl *dump_impl);
+
+ static DumpImpl *dump_list_[kMaxDumpObjects];
+ static uint32_t dump_count_;
+
+ friend DumpInterface;
+};
+
+} // namespace sdm
+
+#endif // __DUMP_IMPL_H__
+
diff --git a/sdm/libs/core/fb/hw_device.cpp b/sdm/libs/core/fb/hw_device.cpp
new file mode 100644
index 0000000..b905c31
--- /dev/null
+++ b/sdm/libs/core/fb/hw_device.cpp
@@ -0,0 +1,946 @@
+/*
+* 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:
+* * 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.
+*/
+
+#define __STDC_FORMAT_MACROS
+#include <ctype.h>
+#include <math.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/fb.h>
+#include <utils/constants.h>
+#include <utils/debug.h>
+
+#include "hw_device.h"
+
+#define __CLASS__ "HWDevice"
+
+#ifdef DISPLAY_CORE_VIRTUAL_DRIVER
+extern int virtual_ioctl(int fd, int cmd, ...);
+extern int virtual_open(const char *file_name, int access, ...);
+extern int virtual_close(int fd);
+extern int virtual_poll(struct pollfd *fds, nfds_t num, int timeout);
+extern ssize_t virtual_pread(int fd, void *data, size_t count, off_t offset);
+extern ssize_t virtual_pwrite(int fd, const void *data, size_t count, off_t offset);
+extern FILE* virtual_fopen(const char *fname, const char *mode);
+extern int virtual_fclose(FILE* fileptr);
+extern ssize_t virtual_getline(char **lineptr, size_t *linelen, FILE *stream);
+#endif
+
+namespace sdm {
+
+HWDevice::HWDevice(BufferSyncHandler *buffer_sync_handler)
+ : fb_node_index_(-1), fb_path_("/sys/devices/virtual/graphics/fb"), hotplug_enabled_(false),
+ buffer_sync_handler_(buffer_sync_handler), synchronous_commit_(false) {
+ // Pointer to actual driver interfaces.
+ ioctl_ = ::ioctl;
+ open_ = ::open;
+ close_ = ::close;
+ poll_ = ::poll;
+ pread_ = ::pread;
+ pwrite_ = ::pwrite;
+ fopen_ = ::fopen;
+ fclose_ = ::fclose;
+ getline_ = ::getline;
+
+#ifdef DISPLAY_CORE_VIRTUAL_DRIVER
+ // If debug property to use virtual driver is set, point to virtual driver interfaces.
+ if (Debug::IsVirtualDriver()) {
+ ioctl_ = virtual_ioctl;
+ open_ = virtual_open;
+ close_ = virtual_close;
+ poll_ = virtual_poll;
+ pread_ = virtual_pread;
+ pwrite_ = virtual_pwrite;
+ fopen_ = virtual_fopen;
+ fclose_ = virtual_fclose;
+ getline_ = virtual_getline;
+ }
+#endif
+}
+
+DisplayError HWDevice::Init() {
+ DisplayError error = kErrorNone;
+
+ // Read the fb node index
+ fb_node_index_ = GetFBNodeIndex(device_type_);
+ if (fb_node_index_ == -1) {
+ DLOGE("%s should be present", device_name_);
+ return kErrorHardware;
+ }
+
+ // Populate Panel Info (Used for Partial Update)
+ PopulateHWPanelInfo();
+ // Populate HW Capabilities
+ hw_resource_ = HWResourceInfo();
+ hw_info_intf_->GetHWResourceInfo(&hw_resource_);
+
+ return error;
+}
+
+DisplayError HWDevice::Open(HWEventHandler *eventhandler) {
+ DisplayError error = kErrorNone;
+
+ char device_name[64] = {0};
+
+ // Store EventHandlers for two Physical displays, i.e., Primary and HDMI
+ // TODO(user): Need to revisit for HDMI as Primary usecase
+ event_handler_ = eventhandler;
+ snprintf(device_name, sizeof(device_name), "%s%d", "/dev/graphics/fb", fb_node_index_);
+
+ device_fd_ = open_(device_name, O_RDWR);
+ if (device_fd_ < 0) {
+ DLOGE("open %s failed err = %d errstr = %s", device_name, errno, strerror(errno));
+ return kErrorResources;
+ }
+
+ return error;
+}
+
+DisplayError HWDevice::Close() {
+ if (device_fd_ > 0) {
+ close_(device_fd_);
+ }
+
+ return kErrorNone;
+}
+
+DisplayError HWDevice::GetNumDisplayAttributes(uint32_t *count) {
+ *count = 1;
+ return kErrorNone;
+}
+
+DisplayError HWDevice::GetDisplayAttributes(HWDisplayAttributes *display_attributes,
+ uint32_t index) {
+ return kErrorNone;
+}
+
+DisplayError HWDevice::GetHWPanelInfo(HWPanelInfo *panel_info) {
+ *panel_info = hw_panel_info_;
+ return kErrorNone;
+}
+
+DisplayError HWDevice::SetDisplayAttributes(uint32_t index) {
+ return kErrorNone;
+}
+
+DisplayError HWDevice::GetConfigIndex(uint32_t mode, uint32_t *index) {
+ return kErrorNone;
+}
+
+
+DisplayError HWDevice::PowerOn() {
+ DTRACE_SCOPED();
+
+ if (ioctl_(device_fd_, FBIOBLANK, FB_BLANK_UNBLANK) < 0) {
+ IOCTL_LOGE(FB_BLANK_UNBLANK, device_type_);
+ return kErrorHardware;
+ }
+
+ // Need to turn on HPD
+ if (!hotplug_enabled_) {
+ hotplug_enabled_ = EnableHotPlugDetection(1);
+ }
+
+ return kErrorNone;
+}
+
+DisplayError HWDevice::PowerOff() {
+ return kErrorNone;
+}
+
+DisplayError HWDevice::Doze() {
+ return kErrorNone;
+}
+
+DisplayError HWDevice::DozeSuspend() {
+ return kErrorNone;
+}
+
+DisplayError HWDevice::Standby() {
+ return kErrorNone;
+}
+
+DisplayError HWDevice::Validate(HWLayers *hw_layers) {
+ DTRACE_SCOPED();
+
+ DisplayError error = kErrorNone;
+
+ HWLayersInfo &hw_layer_info = hw_layers->info;
+ LayerStack *stack = hw_layer_info.stack;
+
+ DLOGV_IF(kTagDriverConfig, "************************** %s Validate Input ***********************",
+ device_name_);
+ DLOGV_IF(kTagDriverConfig, "SDE layer count is %d", hw_layer_info.count);
+
+ mdp_layer_commit_v1 &mdp_commit = mdp_disp_commit_.commit_v1;
+ uint32_t &mdp_layer_count = mdp_commit.input_layer_cnt;
+
+ DLOGI_IF(kTagDriverConfig, "left_roi: x = %d, y = %d, w = %d, h = %d", mdp_commit.left_roi.x,
+ mdp_commit.left_roi.y, mdp_commit.left_roi.w, mdp_commit.left_roi.h);
+ DLOGI_IF(kTagDriverConfig, "right_roi: x = %d, y = %d, w = %d, h = %d", mdp_commit.right_roi.x,
+ mdp_commit.right_roi.y, mdp_commit.right_roi.w, mdp_commit.right_roi.h);
+
+ 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_index];
+ LayerBuffer *input_buffer = layer.input_buffer;
+ HWPipeInfo *left_pipe = &hw_layers->config[i].left_pipe;
+ HWPipeInfo *right_pipe = &hw_layers->config[i].right_pipe;
+ HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session;
+ bool is_rotator_used = (hw_rotator_session->hw_block_count != 0);
+ mdp_input_layer mdp_layer;
+
+ for (uint32_t count = 0; count < 2; count++) {
+ HWPipeInfo *pipe_info = (count == 0) ? left_pipe : right_pipe;
+ HWRotateInfo *hw_rotate_info = &hw_rotator_session->hw_rotate_info[count];
+
+ if (hw_rotate_info->valid) {
+ input_buffer = &hw_rotator_session->output_buffer;
+ }
+
+ if (pipe_info->valid) {
+ mdp_input_layer &mdp_layer = mdp_in_layers_[mdp_layer_count];
+ mdp_layer_buffer &mdp_buffer = mdp_layer.buffer;
+
+ mdp_buffer.width = input_buffer->width;
+ mdp_buffer.height = input_buffer->height;
+ mdp_buffer.comp_ratio.denom = 1000;
+ mdp_buffer.comp_ratio.numer = UINT32(hw_layers->config[i].compression * 1000);
+
+ error = SetFormat(input_buffer->format, &mdp_buffer.format);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ mdp_layer.alpha = layer.plane_alpha;
+ mdp_layer.z_order = UINT16(pipe_info->z_order);
+ mdp_layer.transp_mask = 0xffffffff;
+ SetBlending(layer.blending, &mdp_layer.blend_op);
+ mdp_layer.pipe_ndx = pipe_info->pipe_id;
+ mdp_layer.horz_deci = pipe_info->horizontal_decimation;
+ mdp_layer.vert_deci = pipe_info->vertical_decimation;
+
+ SetRect(pipe_info->src_roi, &mdp_layer.src_rect);
+ SetRect(pipe_info->dst_roi, &mdp_layer.dst_rect);
+ SetMDPFlags(layer, is_rotator_used, &mdp_layer.flags);
+
+ if (pipe_info->scale_data.enable_pixel_ext) {
+ if ((mdp_layer.flags & MDP_LAYER_DEINTERLACE) && (layer.transform.rotation == 90.0f)) {
+ mdp_buffer.width = pipe_info->scale_data.src_width;
+ }
+ SetHWScaleData(pipe_info->scale_data, mdp_layer_count);
+ }
+
+ // Send scale data to MDP driver
+ mdp_layer.scale = GetScaleDataRef(mdp_layer_count);
+ mdp_layer_count++;
+
+ DLOGV_IF(kTagDriverConfig, "******************* Layer[%d] %s pipe Input ******************",
+ i, count ? "Right" : "Left");
+ DLOGV_IF(kTagDriverConfig, "in_w %d, in_h %d, in_f %d", mdp_buffer.width, mdp_buffer.height,
+ mdp_buffer.format);
+ DLOGV_IF(kTagDriverConfig, "plane_alpha %d, zorder %d, blending %d, horz_deci %d, "
+ "vert_deci %d, pipe_id = 0x%x, mdp_flags 0x%x", mdp_layer.alpha, mdp_layer.z_order,
+ mdp_layer.blend_op, mdp_layer.horz_deci, mdp_layer.vert_deci, mdp_layer.pipe_ndx,
+ mdp_layer.flags);
+ DLOGV_IF(kTagDriverConfig, "src_rect [%d, %d, %d, %d]", mdp_layer.src_rect.x,
+ mdp_layer.src_rect.y, mdp_layer.src_rect.w, mdp_layer.src_rect.h);
+ DLOGV_IF(kTagDriverConfig, "dst_rect [%d, %d, %d, %d]", mdp_layer.dst_rect.x,
+ mdp_layer.dst_rect.y, mdp_layer.dst_rect.w, mdp_layer.dst_rect.h);
+ for (int j = 0; j < 4; j++) {
+ DLOGV_IF(kTagDriverConfig, "Scale Data[%d]: Phase=[%x %x %x %x] Pixel_Ext=[%d %d %d %d]",
+ j, mdp_layer.scale->init_phase_x[j], mdp_layer.scale->phase_step_x[j],
+ mdp_layer.scale->init_phase_y[j], mdp_layer.scale->phase_step_y[j],
+ mdp_layer.scale->num_ext_pxls_left[j], mdp_layer.scale->num_ext_pxls_top[j],
+ mdp_layer.scale->num_ext_pxls_right[j], mdp_layer.scale->num_ext_pxls_btm[j]);
+ DLOGV_IF(kTagDriverConfig, "Fetch=[%d %d %d %d] Repeat=[%d %d %d %d] roi_width = %d",
+ mdp_layer.scale->left_ftch[j], mdp_layer.scale->top_ftch[j],
+ mdp_layer.scale->right_ftch[j], mdp_layer.scale->btm_ftch[j],
+ mdp_layer.scale->left_rpt[j], mdp_layer.scale->top_rpt[j],
+ mdp_layer.scale->right_rpt[j], mdp_layer.scale->btm_rpt[j],
+ mdp_layer.scale->roi_w[j]);
+ }
+ DLOGV_IF(kTagDriverConfig, "*************************************************************");
+ }
+ }
+ }
+
+ if (device_type_ == kDeviceVirtual) {
+ LayerBuffer *output_buffer = hw_layers->info.stack->output_buffer;
+ // TODO(user): Need to assign the writeback id from the resource manager, since the support
+ // has not been added hard coding it to 2 for now.
+ mdp_out_layer_.writeback_ndx = 2;
+ mdp_out_layer_.buffer.width = output_buffer->width;
+ mdp_out_layer_.buffer.height = output_buffer->height;
+ mdp_out_layer_.buffer.comp_ratio.denom = 1000;
+ mdp_out_layer_.buffer.comp_ratio.numer = UINT32(hw_layers->output_compression * 1000);
+ SetFormat(output_buffer->format, &mdp_out_layer_.buffer.format);
+
+ DLOGI_IF(kTagDriverConfig, "********************* Output buffer Info ************************");
+ DLOGI_IF(kTagDriverConfig, "out_w %d, out_h %d, out_f %d, wb_id %d",
+ mdp_out_layer_.buffer.width, mdp_out_layer_.buffer.height,
+ mdp_out_layer_.buffer.format, mdp_out_layer_.writeback_ndx);
+ DLOGI_IF(kTagDriverConfig, "*****************************************************************");
+ }
+
+ mdp_commit.flags |= MDP_VALIDATE_LAYER;
+ if (ioctl_(device_fd_, MSMFB_ATOMIC_COMMIT, &mdp_disp_commit_) < 0) {
+ IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, device_type_);
+ DumpLayerCommit(mdp_disp_commit_);
+ return kErrorHardware;
+ }
+
+ return kErrorNone;
+}
+
+void HWDevice::DumpLayerCommit(const mdp_layer_commit &layer_commit) {
+ const mdp_layer_commit_v1 &mdp_commit = layer_commit.commit_v1;
+ const mdp_input_layer *mdp_layers = mdp_commit.input_layers;
+
+ DLOGE("mdp_commit: flags = %x, release fence = %x", mdp_commit.flags, mdp_commit.release_fence);
+ DLOGE("left_roi: x = %d, y = %d, w = %d, h = %d", mdp_commit.left_roi.x, mdp_commit.left_roi.y,
+ mdp_commit.left_roi.w, mdp_commit.left_roi.h);
+ DLOGE("right_roi: x = %d, y = %d, w = %d, h = %d", mdp_commit.right_roi.x,
+ mdp_commit.right_roi.y, mdp_commit.right_roi.w, mdp_commit.right_roi.h);
+ for (uint32_t i = 0; i < mdp_commit.input_layer_cnt; i++) {
+ DLOGE("mdp_commit: layer_cnt = %d, pipe_ndx = %x, zorder = %d, flags = %x",
+ i, mdp_layers[i].pipe_ndx, mdp_layers[i].z_order, mdp_layers[i].flags);
+ const mdp_rect &src_rect = mdp_layers[i].src_rect;
+ DLOGE("src rect: x = %d, y = %d, w = %d, h = %d",
+ src_rect.x, src_rect.y, src_rect.w, src_rect.h);
+ const mdp_rect &dst_rect = mdp_layers[i].dst_rect;
+ DLOGE("dst rect: x = %d, y = %d, w = %d, h = %d",
+ dst_rect.x, dst_rect.y, dst_rect.w, dst_rect.h);
+ }
+}
+
+DisplayError HWDevice::Commit(HWLayers *hw_layers) {
+ DTRACE_SCOPED();
+
+ HWLayersInfo &hw_layer_info = hw_layers->info;
+ LayerStack *stack = hw_layer_info.stack;
+
+ DLOGV_IF(kTagDriverConfig, "*************************** %s Commit Input ************************",
+ device_name_);
+ DLOGV_IF(kTagDriverConfig, "SDE layer count is %d", hw_layer_info.count);
+
+ mdp_layer_commit_v1 &mdp_commit = mdp_disp_commit_.commit_v1;
+ uint32_t mdp_layer_index = 0;
+
+ for (uint32_t i = 0; i < hw_layer_info.count; i++) {
+ uint32_t layer_index = hw_layer_info.index[i];
+ LayerBuffer *input_buffer = stack->layers[layer_index].input_buffer;
+ HWPipeInfo *left_pipe = &hw_layers->config[i].left_pipe;
+ HWPipeInfo *right_pipe = &hw_layers->config[i].right_pipe;
+ HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session;
+
+ for (uint32_t count = 0; count < 2; count++) {
+ HWPipeInfo *pipe_info = (count == 0) ? left_pipe : right_pipe;
+ HWRotateInfo *hw_rotate_info = &hw_rotator_session->hw_rotate_info[count];
+
+ if (hw_rotate_info->valid) {
+ input_buffer = &hw_rotator_session->output_buffer;
+ }
+
+ if (pipe_info->valid) {
+ mdp_layer_buffer &mdp_buffer = mdp_in_layers_[mdp_layer_index].buffer;
+ mdp_input_layer &mdp_layer = mdp_in_layers_[mdp_layer_index];
+ if (input_buffer->planes[0].fd >= 0) {
+ mdp_buffer.plane_count = 1;
+ mdp_buffer.planes[0].fd = input_buffer->planes[0].fd;
+ mdp_buffer.planes[0].offset = input_buffer->planes[0].offset;
+ SetStride(device_type_, input_buffer->format, input_buffer->planes[0].stride,
+ &mdp_buffer.planes[0].stride);
+ } else {
+ DLOGW("Invalid buffer fd, setting plane count to 0");
+ mdp_buffer.plane_count = 0;
+ }
+
+ mdp_buffer.fence = input_buffer->acquire_fence_fd;
+ mdp_layer_index++;
+
+ DLOGV_IF(kTagDriverConfig, "****************** Layer[%d] %s pipe Input *******************",
+ i, count ? "Right" : "Left");
+ DLOGI_IF(kTagDriverConfig, "in_w %d, in_h %d, in_f %d, horz_deci %d, vert_deci %d",
+ mdp_buffer.width, mdp_buffer.height, mdp_buffer.format, mdp_layer.horz_deci,
+ mdp_layer.vert_deci);
+ DLOGI_IF(kTagDriverConfig, "in_buf_fd %d, in_buf_offset %d, in_buf_stride %d, " \
+ "in_plane_count %d, in_fence %d, layer count %d", mdp_buffer.planes[0].fd,
+ mdp_buffer.planes[0].offset, mdp_buffer.planes[0].stride, mdp_buffer.plane_count,
+ mdp_buffer.fence, mdp_commit.input_layer_cnt);
+ DLOGV_IF(kTagDriverConfig, "*************************************************************");
+ }
+ }
+ }
+ if (device_type_ == kDeviceVirtual) {
+ LayerBuffer *output_buffer = hw_layers->info.stack->output_buffer;
+
+ if (output_buffer->planes[0].fd >= 0) {
+ mdp_out_layer_.buffer.planes[0].fd = output_buffer->planes[0].fd;
+ mdp_out_layer_.buffer.planes[0].offset = output_buffer->planes[0].offset;
+ SetStride(device_type_, output_buffer->format, output_buffer->planes[0].stride,
+ &mdp_out_layer_.buffer.planes[0].stride);
+ mdp_out_layer_.buffer.plane_count = 1;
+ } else {
+ DLOGW("Invalid output buffer fd, setting plane count to 0");
+ mdp_out_layer_.buffer.plane_count = 0;
+ }
+
+ mdp_out_layer_.buffer.fence = output_buffer->acquire_fence_fd;
+
+ DLOGI_IF(kTagDriverConfig, "********************** Output buffer Info ***********************");
+ DLOGI_IF(kTagDriverConfig, "out_fd %d, out_offset %d, out_stride %d, acquire_fence %d",
+ mdp_out_layer_.buffer.planes[0].fd, mdp_out_layer_.buffer.planes[0].offset,
+ mdp_out_layer_.buffer.planes[0].stride, mdp_out_layer_.buffer.fence);
+ DLOGI_IF(kTagDriverConfig, "*****************************************************************");
+ }
+
+ mdp_commit.release_fence = -1;
+ mdp_commit.flags &= ~MDP_VALIDATE_LAYER;
+ if (synchronous_commit_) {
+ mdp_commit.flags |= MDP_COMMIT_WAIT_FOR_FINISH;
+ }
+ if (ioctl_(device_fd_, MSMFB_ATOMIC_COMMIT, &mdp_disp_commit_) < 0) {
+ IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, device_type_);
+ DumpLayerCommit(mdp_disp_commit_);
+ synchronous_commit_ = false;
+ return kErrorHardware;
+ }
+
+ stack->retire_fence_fd = mdp_commit.retire_fence;
+
+ // MDP returns only one release fence for the entire layer stack. Duplicate this fence into all
+ // layers being composed by MDP.
+ for (uint32_t i = 0; i < hw_layer_info.count; i++) {
+ uint32_t layer_index = hw_layer_info.index[i];
+ LayerBuffer *input_buffer = stack->layers[layer_index].input_buffer;
+ HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session;
+ HWRotateInfo *left_rotate = &hw_rotator_session->hw_rotate_info[0];
+ HWRotateInfo *right_rotate = &hw_rotator_session->hw_rotate_info[1];
+
+ if (!left_rotate->valid && !right_rotate->valid) {
+ input_buffer->release_fence_fd = dup(mdp_commit.release_fence);
+ continue;
+ }
+
+ for (uint32_t count = 0; count < 2; count++) {
+ HWRotateInfo *hw_rotate_info = &hw_rotator_session->hw_rotate_info[count];
+ if (hw_rotate_info->valid) {
+ input_buffer = &hw_rotator_session->output_buffer;
+ input_buffer->release_fence_fd = dup(mdp_commit.release_fence);
+ close_(input_buffer->acquire_fence_fd);
+ input_buffer->acquire_fence_fd = -1;
+ }
+ }
+ }
+ DLOGI_IF(kTagDriverConfig, "*************************** %s Commit Input ************************",
+ device_name_);
+ DLOGI_IF(kTagDriverConfig, "retire_fence_fd %d", stack->retire_fence_fd);
+ DLOGI_IF(kTagDriverConfig, "*******************************************************************");
+
+ close_(mdp_commit.release_fence);
+
+ if (synchronous_commit_) {
+ // A synchronous commit can be requested when changing the display mode so we need to update
+ // panel info.
+ PopulateHWPanelInfo();
+ synchronous_commit_ = false;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError HWDevice::Flush() {
+ ResetDisplayParams();
+ mdp_layer_commit_v1 &mdp_commit = mdp_disp_commit_.commit_v1;
+ mdp_commit.input_layer_cnt = 0;
+ mdp_commit.output_layer = NULL;
+
+ mdp_commit.flags &= ~MDP_VALIDATE_LAYER;
+ if (ioctl_(device_fd_, MSMFB_ATOMIC_COMMIT, &mdp_disp_commit_) < 0) {
+ IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, device_type_);
+ DumpLayerCommit(mdp_disp_commit_);
+ return kErrorHardware;
+ }
+ return kErrorNone;
+}
+
+DisplayError HWDevice::SetFormat(const LayerBufferFormat &source, uint32_t *target) {
+ switch (source) {
+ case kFormatARGB8888: *target = MDP_ARGB_8888; break;
+ case kFormatRGBA8888: *target = MDP_RGBA_8888; break;
+ case kFormatBGRA8888: *target = MDP_BGRA_8888; break;
+ case kFormatRGBX8888: *target = MDP_RGBX_8888; break;
+ case kFormatBGRX8888: *target = MDP_BGRX_8888; break;
+ case kFormatRGBA5551: *target = MDP_RGBA_5551; break;
+ case kFormatRGBA4444: *target = MDP_RGBA_4444; break;
+ case kFormatRGB888: *target = MDP_RGB_888; break;
+ case kFormatBGR888: *target = MDP_BGR_888; break;
+ case kFormatRGB565: *target = MDP_RGB_565; break;
+ case kFormatYCbCr420Planar: *target = MDP_Y_CB_CR_H2V2; break;
+ case kFormatYCrCb420Planar: *target = MDP_Y_CR_CB_H2V2; break;
+ case kFormatYCbCr420SemiPlanar: *target = MDP_Y_CBCR_H2V2; break;
+ case kFormatYCrCb420SemiPlanar: *target = MDP_Y_CRCB_H2V2; break;
+ case kFormatYCbCr422H1V2SemiPlanar: *target = MDP_Y_CBCR_H1V2; break;
+ case kFormatYCrCb422H1V2SemiPlanar: *target = MDP_Y_CRCB_H1V2; break;
+ case kFormatYCbCr422H2V1SemiPlanar: *target = MDP_Y_CBCR_H2V1; break;
+ case kFormatYCrCb422H2V1SemiPlanar: *target = MDP_Y_CRCB_H2V1; break;
+ case kFormatYCbCr422H2V1Packed: *target = MDP_YCBYCR_H2V1; break;
+ case kFormatYCbCr420SemiPlanarVenus: *target = MDP_Y_CBCR_H2V2_VENUS; break;
+ case kFormatRGBA8888Ubwc: *target = MDP_RGBA_8888_UBWC; break;
+ case kFormatRGBX8888Ubwc: *target = MDP_RGBX_8888_UBWC; break;
+ case kFormatRGB565Ubwc: *target = MDP_RGB_565_UBWC; break;
+ case kFormatYCbCr420SPVenusUbwc: *target = MDP_Y_CBCR_H2V2_UBWC; break;
+ default:
+ DLOGE("Unsupported format type %d", source);
+ return kErrorParameters;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError HWDevice::SetStride(HWDeviceType device_type, LayerBufferFormat format,
+ uint32_t width, uint32_t *target) {
+ // TODO(user): This SetStride function is a workaround to satisfy the driver expectation for
+ // rotator and virtual devices. Eventually this will be taken care in the driver.
+ if (device_type != kDeviceRotator && device_type != kDeviceVirtual) {
+ *target = width;
+ return kErrorNone;
+ }
+
+ switch (format) {
+ case kFormatARGB8888:
+ case kFormatRGBA8888:
+ case kFormatBGRA8888:
+ case kFormatRGBX8888:
+ case kFormatBGRX8888:
+ case kFormatRGBA8888Ubwc:
+ case kFormatRGBX8888Ubwc:
+ *target = width * 4;
+ break;
+ case kFormatRGB888:
+ case kFormatBGR888:
+ *target = width * 3;
+ break;
+ case kFormatRGB565:
+ case kFormatRGB565Ubwc:
+ *target = width * 2;
+ break;
+ case kFormatYCbCr420SemiPlanarVenus:
+ case kFormatYCbCr420SPVenusUbwc:
+ case kFormatYCbCr420Planar:
+ case kFormatYCrCb420Planar:
+ case kFormatYCbCr420SemiPlanar:
+ case kFormatYCrCb420SemiPlanar:
+ *target = width;
+ break;
+ case kFormatYCbCr422H2V1Packed:
+ case kFormatYCrCb422H2V1SemiPlanar:
+ case kFormatYCrCb422H1V2SemiPlanar:
+ case kFormatYCbCr422H2V1SemiPlanar:
+ case kFormatYCbCr422H1V2SemiPlanar:
+ case kFormatRGBA5551:
+ case kFormatRGBA4444:
+ *target = width * 2;
+ break;
+ default:
+ DLOGE("Unsupported format type %d", format);
+ return kErrorParameters;
+ }
+
+ return kErrorNone;
+}
+
+void HWDevice::SetBlending(const LayerBlending &source, mdss_mdp_blend_op *target) {
+ switch (source) {
+ case kBlendingPremultiplied: *target = BLEND_OP_PREMULTIPLIED; break;
+ case kBlendingCoverage: *target = BLEND_OP_COVERAGE; break;
+ default: *target = BLEND_OP_NOT_DEFINED; break;
+ }
+}
+
+void HWDevice::SetRect(const LayerRect &source, mdp_rect *target) {
+ target->x = UINT32(source.left);
+ target->y = UINT32(source.top);
+ target->w = UINT32(source.right) - target->x;
+ target->h = UINT32(source.bottom) - target->y;
+}
+
+void HWDevice::SetMDPFlags(const Layer &layer, const bool &is_rotator_used,
+ uint32_t *mdp_flags) {
+ LayerBuffer *input_buffer = layer.input_buffer;
+
+ // Flips will be taken care by rotator, if layer uses rotator for downscale/rotation. So ignore
+ // flip flags for MDP.
+ if (!is_rotator_used) {
+ if (layer.transform.flip_vertical) {
+ *mdp_flags |= MDP_LAYER_FLIP_UD;
+ }
+
+ if (layer.transform.flip_horizontal) {
+ *mdp_flags |= MDP_LAYER_FLIP_LR;
+ }
+ }
+
+ if (input_buffer->flags.interlace) {
+ *mdp_flags |= MDP_LAYER_DEINTERLACE;
+ }
+
+ if (input_buffer->flags.secure) {
+ *mdp_flags |= MDP_LAYER_SECURE_SESSION;
+ }
+
+ if (input_buffer->flags.secure_display) {
+ *mdp_flags |= MDP_SECURE_DISPLAY_OVERLAY_SESSION;
+ }
+}
+
+void HWDevice::SyncMerge(const int &fd1, const int &fd2, int *target) {
+ if (fd1 >= 0 && fd2 >= 0) {
+ buffer_sync_handler_->SyncMerge(fd1, fd2, target);
+ } else if (fd1 >= 0) {
+ *target = fd1;
+ } else if (fd2 >= 0) {
+ *target = fd2;
+ }
+}
+
+int HWDevice::GetFBNodeIndex(HWDeviceType device_type) {
+ int fb_node_index = -1;
+ for (int i = 0; i < kDeviceMax; i++) {
+ HWPanelInfo *panel_info = new HWPanelInfo();
+ GetHWPanelInfoByNode(i, panel_info);
+ switch (device_type) {
+ case kDevicePrimary:
+ if (panel_info->is_primary_panel) {
+ fb_node_index = i;
+ }
+ break;
+ case kDeviceHDMI:
+ if (panel_info->port == kPortDTv) {
+ fb_node_index = i;
+ }
+ break;
+ case kDeviceVirtual:
+ if (panel_info->port == kPortWriteBack) {
+ fb_node_index = i;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return fb_node_index;
+}
+
+void HWDevice::PopulateHWPanelInfo() {
+ hw_panel_info_ = HWPanelInfo();
+ GetHWPanelInfoByNode(fb_node_index_, &hw_panel_info_);
+ DLOGI("Device type = %d, Display Port = %d, Display Mode = %d, Device Node = %d, Is Primary = %d",
+ device_type_, hw_panel_info_.port, hw_panel_info_.mode, fb_node_index_,
+ hw_panel_info_.is_primary_panel);
+ DLOGI("Partial Update = %d, Dynamic FPS = %d",
+ hw_panel_info_.partial_update, hw_panel_info_.dynamic_fps);
+ DLOGI("Align: left = %d, width = %d, top = %d, height = %d",
+ hw_panel_info_.left_align, hw_panel_info_.width_align,
+ hw_panel_info_.top_align, hw_panel_info_.height_align);
+ DLOGI("ROI: min_width = %d, min_height = %d, need_merge = %d",
+ hw_panel_info_.min_roi_width, hw_panel_info_.min_roi_height,
+ hw_panel_info_.needs_roi_merge);
+ DLOGI("FPS: min = %d, max =%d", hw_panel_info_.min_fps, hw_panel_info_.max_fps);
+ DLOGI("Left Split = %d, Right Split = %d", hw_panel_info_.split_info.left_split,
+ hw_panel_info_.split_info.right_split);
+ DLOGI("Source Split Always = %d", hw_panel_info_.split_info.always_src_split);
+}
+
+void HWDevice::GetHWPanelInfoByNode(int device_node, HWPanelInfo *panel_info) {
+ if (!panel_info) {
+ DLOGE("PanelInfo pointer in invalid.");
+ return;
+ }
+ char stringbuffer[kMaxStringLength];
+ FILE *fileptr = NULL;
+ snprintf(stringbuffer, sizeof(stringbuffer), "%s%d/msm_fb_panel_info", fb_path_, device_node);
+ fileptr = fopen(stringbuffer, "r");
+ if (!fileptr) {
+ DLOGW("Failed to open msm_fb_panel_info node device node %d", device_node);
+ return;
+ }
+
+ size_t len = kMaxStringLength;
+ ssize_t read;
+ char *line = NULL;
+ while ((read = getline(&line, &len, fileptr)) != -1) {
+ uint32_t token_count = 0;
+ const uint32_t max_count = 10;
+ char *tokens[max_count] = { NULL };
+ if (!ParseLine(line, tokens, max_count, &token_count)) {
+ if (!strncmp(tokens[0], "pu_en", strlen("pu_en"))) {
+ panel_info->partial_update = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "xstart", strlen("xstart"))) {
+ panel_info->left_align = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "walign", strlen("walign"))) {
+ panel_info->width_align = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "ystart", strlen("ystart"))) {
+ panel_info->top_align = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "halign", strlen("halign"))) {
+ panel_info->height_align = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "min_w", strlen("min_w"))) {
+ panel_info->min_roi_width = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "min_h", strlen("min_h"))) {
+ panel_info->min_roi_height = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "roi_merge", strlen("roi_merge"))) {
+ panel_info->needs_roi_merge = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "dyn_fps_en", strlen("dyn_fps_en"))) {
+ panel_info->dynamic_fps = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "min_fps", strlen("min_fps"))) {
+ panel_info->min_fps = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "max_fps", strlen("max_fps"))) {
+ panel_info->max_fps= atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "primary_panel", strlen("primary_panel"))) {
+ panel_info->is_primary_panel = atoi(tokens[1]);
+ }
+ }
+ }
+ fclose(fileptr);
+ free(line);
+ panel_info->port = GetHWDisplayPort(device_node);
+ panel_info->mode = GetHWDisplayMode(device_node);
+ GetSplitInfo(device_node, panel_info);
+}
+
+HWDisplayPort HWDevice::GetHWDisplayPort(int device_node) {
+ char stringbuffer[kMaxStringLength];
+ DisplayError error = kErrorNone;
+ char *line = NULL;
+ size_t len = kMaxStringLength;
+ ssize_t read;
+ HWDisplayPort port = kPortDefault;
+
+ snprintf(stringbuffer, sizeof(stringbuffer), "%s%d/msm_fb_type", fb_path_, device_node);
+ FILE *fileptr = fopen(stringbuffer, "r");
+ if (!fileptr) {
+ DLOGW("File not found %s", stringbuffer);
+ return port;
+ }
+ read = getline(&line, &len, fileptr);
+ if (read == -1) {
+ fclose(fileptr);
+ return port;
+ }
+ if ((strncmp(line, "mipi dsi cmd panel", strlen("mipi dsi cmd panel")) == 0)) {
+ port = kPortDSI;
+ } else if ((strncmp(line, "mipi dsi video panel", strlen("mipi dsi video panel")) == 0)) {
+ port = kPortDSI;
+ } else if ((strncmp(line, "lvds panel", strlen("lvds panel")) == 0)) {
+ port = kPortLVDS;
+ } else if ((strncmp(line, "edp panel", strlen("edp panel")) == 0)) {
+ port = kPortEDP;
+ } else if ((strncmp(line, "dtv panel", strlen("dtv panel")) == 0)) {
+ port = kPortDTv;
+ } else if ((strncmp(line, "writeback panel", strlen("writeback panel")) == 0)) {
+ port = kPortWriteBack;
+ } else {
+ port = kPortDefault;
+ }
+ fclose(fileptr);
+ free(line);
+ return port;
+}
+
+HWDisplayMode HWDevice::GetHWDisplayMode(int device_node) {
+ char stringbuffer[kMaxStringLength];
+ DisplayError error = kErrorNone;
+ char *line = NULL;
+ size_t len = kMaxStringLength;
+ ssize_t read;
+ HWDisplayMode mode = kModeDefault;
+
+ snprintf(stringbuffer, sizeof(stringbuffer), "%s%d/msm_fb_type", fb_path_, device_node);
+ FILE *fileptr = fopen(stringbuffer, "r");
+ if (!fileptr) {
+ DLOGW("File not found %s", stringbuffer);
+ return mode;
+ }
+ read = getline(&line, &len, fileptr);
+ if (read == -1) {
+ fclose(fileptr);
+ return mode;
+ }
+ if ((strncmp(line, "mipi dsi cmd panel", strlen("mipi dsi cmd panel")) == 0)) {
+ mode = kModeCommand;
+ } else if ((strncmp(line, "mipi dsi video panel", strlen("mipi dsi video panel")) == 0)) {
+ mode = kModeVideo;
+ } else {
+ mode = kModeDefault;
+ }
+ fclose(fileptr);
+ free(line);
+ return mode;
+}
+
+void HWDevice::GetSplitInfo(int device_node, HWPanelInfo *panel_info) {
+ char stringbuffer[kMaxStringLength];
+ FILE *fileptr = NULL;
+ size_t len = kMaxStringLength;
+ ssize_t read;
+ char *line = NULL;
+ uint32_t token_count = 0;
+ const uint32_t max_count = 10;
+ char *tokens[max_count] = { NULL };
+
+ // Split info - for MDSS Version 5 - No need to check version here
+ snprintf(stringbuffer , sizeof(stringbuffer), "%s%d/msm_fb_split", fb_path_, device_node);
+ fileptr = fopen(stringbuffer, "r");
+ if (!fileptr) {
+ DLOGW("File not found %s", stringbuffer);
+ return;
+ }
+
+ // Format "left right" space as delimiter
+ read = getline(&line, &len, fileptr);
+ if (read != -1) {
+ if (!ParseLine(line, tokens, max_count, &token_count)) {
+ panel_info->split_info.left_split = atoi(tokens[0]);
+ panel_info->split_info.right_split = atoi(tokens[1]);
+ }
+ }
+ fclose(fileptr);
+
+ // SourceSplit enabled - Get More information
+ snprintf(stringbuffer , sizeof(stringbuffer), "%s%d/msm_fb_src_split_info", fb_path_,
+ device_node);
+ fileptr = fopen(stringbuffer, "r");
+ if (!fileptr) {
+ DLOGW("File not found %s", stringbuffer);
+ return;
+ }
+
+ read = getline(&line, &len, fileptr);
+ if (read != -1) {
+ if (!strncmp(line, "src_split_always", strlen("src_split_always"))) {
+ panel_info->split_info.always_src_split = true;
+ }
+ }
+ fclose(fileptr);
+ free(line);
+}
+
+int HWDevice::ParseLine(char *input, char *tokens[], const uint32_t max_token, uint32_t *count) {
+ char *tmp_token = NULL;
+ char *temp_ptr;
+ uint32_t index = 0;
+ const char *delim = ", =\n";
+ if (!input) {
+ return -1;
+ }
+ tmp_token = strtok_r(input, delim, &temp_ptr);
+ while (tmp_token && index < max_token) {
+ tokens[index++] = tmp_token;
+ tmp_token = strtok_r(NULL, delim, &temp_ptr);
+ }
+ *count = index;
+
+ return 0;
+}
+
+bool HWDevice::EnableHotPlugDetection(int enable) {
+ bool ret_value = true;
+ char hpdpath[kMaxStringLength];
+ int hdmi_node_index = GetFBNodeIndex(kDeviceHDMI);
+ snprintf(hpdpath , sizeof(hpdpath), "%s%d/hpd", fb_path_, hdmi_node_index);
+ int hpdfd = open_(hpdpath, O_RDWR, 0);
+ if (hpdfd < 0) {
+ DLOGE("Open failed = %s", hpdpath);
+ return kErrorHardware;
+ }
+ char value = enable ? '1' : '0';
+ ssize_t length = pwrite_(hpdfd, &value, 1, 0);
+ if (length <= 0) {
+ DLOGE("Write failed 'hpd' = %d", enable);
+ ret_value = false;
+ }
+ close_(hpdfd);
+
+ return ret_value;
+}
+
+void HWDevice::ResetDisplayParams() {
+ memset(&mdp_disp_commit_, 0, sizeof(mdp_disp_commit_));
+ memset(&mdp_in_layers_, 0, sizeof(mdp_in_layers_));
+ memset(&mdp_out_layer_, 0, sizeof(mdp_out_layer_));
+ memset(&scale_data_, 0, sizeof(scale_data_));
+
+ for (uint32_t i = 0; i < kMaxSDELayers * 2; i++) {
+ mdp_in_layers_[i].buffer.fence = -1;
+ }
+
+ mdp_disp_commit_.version = MDP_COMMIT_VERSION_1_0;
+ mdp_disp_commit_.commit_v1.input_layers = mdp_in_layers_;
+ mdp_disp_commit_.commit_v1.output_layer = &mdp_out_layer_;
+ mdp_disp_commit_.commit_v1.release_fence = -1;
+ mdp_disp_commit_.commit_v1.retire_fence = -1;
+}
+
+void HWDevice::SetHWScaleData(const ScaleData &scale, uint32_t index) {
+ mdp_scale_data *mdp_scale = GetScaleDataRef(index);
+ mdp_scale->enable_pxl_ext = scale.enable_pixel_ext;
+
+ for (int i = 0; i < 4; i++) {
+ const HWPlane &plane = scale.plane[i];
+ mdp_scale->init_phase_x[i] = plane.init_phase_x;
+ mdp_scale->phase_step_x[i] = plane.phase_step_x;
+ mdp_scale->init_phase_y[i] = plane.init_phase_y;
+ mdp_scale->phase_step_y[i] = plane.phase_step_y;
+
+ mdp_scale->num_ext_pxls_left[i] = plane.left.extension;
+ mdp_scale->left_ftch[i] = plane.left.overfetch;
+ mdp_scale->left_rpt[i] = plane.left.repeat;
+
+ mdp_scale->num_ext_pxls_top[i] = plane.top.extension;
+ mdp_scale->top_ftch[i] = plane.top.overfetch;
+ mdp_scale->top_rpt[i] = plane.top.repeat;
+
+ mdp_scale->num_ext_pxls_right[i] = plane.right.extension;
+ mdp_scale->right_ftch[i] = plane.right.overfetch;
+ mdp_scale->right_rpt[i] = plane.right.repeat;
+
+ mdp_scale->num_ext_pxls_btm[i] = plane.bottom.extension;
+ mdp_scale->btm_ftch[i] = plane.bottom.overfetch;
+ mdp_scale->btm_rpt[i] = plane.bottom.repeat;
+
+ mdp_scale->roi_w[i] = plane.roi_width;
+ }
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/core/fb/hw_device.h b/sdm/libs/core/fb/hw_device.h
new file mode 100644
index 0000000..7d617f0
--- /dev/null
+++ b/sdm/libs/core/fb/hw_device.h
@@ -0,0 +1,131 @@
+/*
+* 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __HW_DEVICE_H__
+#define __HW_DEVICE_H__
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <linux/msm_mdp_ext.h>
+#include <linux/mdss_rotator.h>
+#include <poll.h>
+#include <pthread.h>
+
+#include "hw_interface.h"
+#include "hw_info_interface.h"
+
+#define IOCTL_LOGE(ioctl, type) DLOGE("ioctl %s, device = %d errno = %d, desc = %s", #ioctl, \
+ type, errno, strerror(errno))
+
+namespace sdm {
+
+class HWDevice {
+ protected:
+ explicit HWDevice(BufferSyncHandler *buffer_sync_handler);
+ DisplayError Init();
+ DisplayError Open(HWEventHandler *eventhandler);
+ DisplayError Close();
+ DisplayError GetNumDisplayAttributes(uint32_t *count);
+ DisplayError GetDisplayAttributes(HWDisplayAttributes *display_attributes,
+ uint32_t index);
+ DisplayError GetHWPanelInfo(HWPanelInfo *panel_info);
+ DisplayError SetDisplayAttributes(uint32_t index);
+ DisplayError GetConfigIndex(uint32_t mode, uint32_t *index);
+ DisplayError PowerOn();
+ DisplayError PowerOff();
+ DisplayError Doze();
+ DisplayError DozeSuspend();
+ DisplayError Standby();
+ DisplayError Validate(HWLayers *hw_layers);
+ DisplayError Commit(HWLayers *hw_layers);
+ DisplayError Flush();
+
+ enum {
+ kHWEventVSync,
+ kHWEventBlank,
+ };
+
+ static const int kMaxStringLength = 1024;
+ static const int kNumPhysicalDisplays = 2;
+ static const int kNumDisplayEvents = 4;
+
+ void DumpLayerCommit(const mdp_layer_commit &layer_commit);
+ DisplayError SetFormat(const LayerBufferFormat &source, uint32_t *target);
+ DisplayError SetStride(HWDeviceType device_type, LayerBufferFormat format,
+ uint32_t width, uint32_t *target);
+ void SetBlending(const LayerBlending &source, mdss_mdp_blend_op *target);
+ void SetRect(const LayerRect &source, mdp_rect *target);
+ void SetMDPFlags(const Layer &layer, const bool &is_rotator_used, uint32_t *mdp_flags);
+ void SyncMerge(const int &fd1, const int &fd2, int *target);
+
+ // Retrieves HW FrameBuffer Node Index
+ int GetFBNodeIndex(HWDeviceType device_type);
+ // Populates HWPanelInfo based on node index
+ void PopulateHWPanelInfo();
+ void GetHWPanelInfoByNode(int device_node, HWPanelInfo *panel_info);
+ HWDisplayPort GetHWDisplayPort(int device_node);
+ HWDisplayMode GetHWDisplayMode(int device_node);
+ void GetSplitInfo(int device_node, HWPanelInfo *panel_info);
+ int ParseLine(char *input, char *tokens[], const uint32_t max_token, uint32_t *count);
+ mdp_scale_data* GetScaleDataRef(uint32_t index) { return &scale_data_[index]; }
+ void SetHWScaleData(const ScaleData &scale, uint32_t index);
+ void ResetDisplayParams();
+
+ bool EnableHotPlugDetection(int enable);
+
+ // Pointers to system calls which are either mapped to actual system call or virtual driver.
+ int (*ioctl_)(int, int, ...);
+ int (*open_)(const char *, int, ...);
+ int (*close_)(int);
+ int (*poll_)(struct pollfd *, nfds_t, int);
+ ssize_t (*pread_)(int, void *, size_t, off_t);
+ ssize_t (*pwrite_)(int, const void *, size_t, off_t);
+ FILE* (*fopen_)( const char *fname, const char *mode);
+ int (*fclose_)(FILE* fileptr);
+ ssize_t (*getline_)(char **lineptr, size_t *linelen, FILE *stream);
+
+ // Store the Device EventHandler - used for callback
+ HWEventHandler *event_handler_;
+ HWResourceInfo hw_resource_;
+ HWPanelInfo hw_panel_info_;
+ HWInfoInterface *hw_info_intf_;
+ int fb_node_index_;
+ const char *fb_path_;
+ bool hotplug_enabled_;
+ BufferSyncHandler *buffer_sync_handler_;
+ int device_fd_;
+ HWDeviceType device_type_;
+ mdp_layer_commit mdp_disp_commit_;
+ mdp_input_layer mdp_in_layers_[kMaxSDELayers * 2]; // split panel (left + right)
+ mdp_scale_data scale_data_[kMaxSDELayers * 2];
+ mdp_output_layer mdp_out_layer_;
+ const char *device_name_;
+ bool synchronous_commit_;
+};
+
+} // namespace sdm
+
+#endif // __HW_DEVICE_H__
+
diff --git a/sdm/libs/core/fb/hw_hdmi.cpp b/sdm/libs/core/fb/hw_hdmi.cpp
new file mode 100644
index 0000000..1a5c538
--- /dev/null
+++ b/sdm/libs/core/fb/hw_hdmi.cpp
@@ -0,0 +1,421 @@
+/*
+* Copyright (c) 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:
+* * 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.
+*/
+
+#include <sys/ioctl.h>
+#include <ctype.h>
+#include <utils/debug.h>
+#include <fcntl.h>
+#include "hw_hdmi.h"
+
+#define __CLASS__ "HWHDMI"
+
+namespace sdm {
+
+static int ParseLine(char *input, char *tokens[], const uint32_t max_token, uint32_t *count) {
+ char *tmp_token = NULL;
+ char *temp_ptr;
+ uint32_t index = 0;
+ const char *delim = ", =\n";
+ if (!input) {
+ return -1;
+ }
+ tmp_token = strtok_r(input, delim, &temp_ptr);
+ while (tmp_token && index < max_token) {
+ tokens[index++] = tmp_token;
+ tmp_token = strtok_r(NULL, delim, &temp_ptr);
+ }
+ *count = index;
+
+ return 0;
+}
+
+static bool MapHDMIDisplayTiming(const msm_hdmi_mode_timing_info *mode,
+ fb_var_screeninfo *info) {
+ if (!mode || !info) {
+ return false;
+ }
+
+ info->reserved[0] = 0;
+ info->reserved[1] = 0;
+ info->reserved[2] = 0;
+ info->reserved[3] = (info->reserved[3] & 0xFFFF) | (mode->video_format << 16);
+ info->xoffset = 0;
+ info->yoffset = 0;
+ info->xres = mode->active_h;
+ info->yres = mode->active_v;
+ info->pixclock = (mode->pixel_freq) * 1000;
+ info->vmode = mode->interlaced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED;
+ info->right_margin = mode->front_porch_h;
+ info->hsync_len = mode->pulse_width_h;
+ info->left_margin = mode->back_porch_h;
+ info->lower_margin = mode->front_porch_v;
+ info->vsync_len = mode->pulse_width_v;
+ info->upper_margin = mode->back_porch_v;
+
+ return true;
+}
+
+DisplayError HWHDMIInterface::Create(HWHDMIInterface **intf, HWInfoInterface *hw_info_intf,
+ BufferSyncHandler *buffer_sync_handler) {
+ DisplayError error = kErrorNone;
+ HWHDMI *hw_fb_hdmi = NULL;
+
+ hw_fb_hdmi = new HWHDMI(buffer_sync_handler, hw_info_intf);
+ error = hw_fb_hdmi->Init();
+ if (error != kErrorNone) {
+ delete hw_fb_hdmi;
+ } else {
+ *intf = hw_fb_hdmi;
+ }
+ return error;
+}
+
+DisplayError HWHDMIInterface::Destroy(HWHDMIInterface *intf) {
+ HWHDMI *hw_fb_hdmi = static_cast<HWHDMI *>(intf);
+ hw_fb_hdmi->Deinit();
+ delete hw_fb_hdmi;
+
+ return kErrorNone;
+}
+
+HWHDMI::HWHDMI(BufferSyncHandler *buffer_sync_handler, HWInfoInterface *hw_info_intf)
+ : HWDevice(buffer_sync_handler), hw_scan_info_() {
+ HWDevice::device_type_ = kDeviceHDMI;
+ HWDevice::device_name_ = "HDMI Display Device";
+ HWDevice::hw_info_intf_ = hw_info_intf;
+}
+
+DisplayError HWHDMI::Init() {
+ DisplayError error = kErrorNone;
+
+ error = HWDevice::Init();
+ if (error != kErrorNone) {
+ goto CleanupOnError;
+ }
+
+ // Mode look-up table for HDMI
+ supported_video_modes_ = new msm_hdmi_mode_timing_info[HDMI_VFRMT_MAX];
+ if (!supported_video_modes_) {
+ error = kErrorMemory;
+ goto CleanupOnError;
+ }
+ // Populate the mode table for supported modes
+ MSM_HDMI_MODES_INIT_TIMINGS(supported_video_modes_);
+ MSM_HDMI_MODES_SET_SUPP_TIMINGS(supported_video_modes_, MSM_HDMI_MODES_ALL);
+
+ ReadScanInfo();
+ return kErrorNone;
+
+CleanupOnError:
+ if (supported_video_modes_) {
+ delete supported_video_modes_;
+ }
+
+ return error;
+}
+
+DisplayError HWHDMI::Deinit() {
+ hdmi_mode_count_ = 0;
+ if (supported_video_modes_) {
+ delete supported_video_modes_;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError HWHDMI::Open(HWEventHandler *eventhandler) {
+ return HWDevice::Open(eventhandler);
+}
+
+DisplayError HWHDMI::Close() {
+ return HWDevice::Close();
+}
+
+DisplayError HWHDMI::GetNumDisplayAttributes(uint32_t *count) {
+ *count = GetHDMIModeCount();
+ if (*count <= 0) {
+ return kErrorHardware;
+ }
+
+ return kErrorNone;
+}
+
+int HWHDMI::GetHDMIModeCount() {
+ ssize_t length = -1;
+ char edid_str[256] = {'\0'};
+ char edid_path[kMaxStringLength] = {'\0'};
+ snprintf(edid_path, sizeof(edid_path), "%s%d/edid_modes", fb_path_, fb_node_index_);
+ int edid_file = open_(edid_path, O_RDONLY);
+ if (edid_file < 0) {
+ DLOGE("EDID file open failed.");
+ return -1;
+ }
+
+ length = pread_(edid_file, edid_str, sizeof(edid_str)-1, 0);
+ if (length <= 0) {
+ DLOGE("%s: edid_modes file empty");
+ edid_str[0] = '\0';
+ } else {
+ DLOGI("EDID mode string: %s", edid_str);
+ while (length > 1 && isspace(edid_str[length-1])) {
+ --length;
+ }
+ edid_str[length] = '\0';
+ }
+ close_(edid_file);
+
+ if (length > 0) {
+ // Get EDID modes from the EDID string
+ char *ptr = edid_str;
+ const uint32_t edid_count_max = 128;
+ char *tokens[edid_count_max] = { NULL };
+ ParseLine(ptr, tokens, edid_count_max, &hdmi_mode_count_);
+ for (uint32_t i = 0; i < hdmi_mode_count_; i++) {
+ hdmi_modes_[i] = atoi(tokens[i]);
+ }
+ }
+ return (hdmi_mode_count_ > 0) ? hdmi_mode_count_ : 0;
+}
+
+DisplayError HWHDMI::GetDisplayAttributes(HWDisplayAttributes *display_attributes,
+ uint32_t index) {
+ DTRACE_SCOPED();
+
+ // Variable screen info
+ STRUCT_VAR(fb_var_screeninfo, var_screeninfo);
+
+ // Get the resolution info from the look up table
+ msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[0];
+ for (int i = 0; i < HDMI_VFRMT_MAX; i++) {
+ msm_hdmi_mode_timing_info *cur = &supported_video_modes_[i];
+ if (cur->video_format == hdmi_modes_[index]) {
+ timing_mode = cur;
+ break;
+ }
+ }
+ display_attributes->x_pixels = timing_mode->active_h;
+ display_attributes->y_pixels = timing_mode->active_v;
+ display_attributes->v_total = timing_mode->active_v + timing_mode->front_porch_v +
+ timing_mode->back_porch_v + timing_mode->pulse_width_v;
+ uint32_t h_blanking = timing_mode->front_porch_h + timing_mode->back_porch_h +
+ timing_mode->pulse_width_h;
+ display_attributes->h_total = timing_mode->active_h + h_blanking;
+ display_attributes->x_dpi = 0;
+ display_attributes->y_dpi = 0;
+ display_attributes->fps = timing_mode->refresh_rate / 1000;
+ display_attributes->vsync_period_ns = UINT32(1000000000L / display_attributes->fps);
+ display_attributes->split_left = display_attributes->x_pixels;
+ if (display_attributes->x_pixels > hw_resource_.max_mixer_width) {
+ display_attributes->is_device_split = true;
+ display_attributes->split_left = display_attributes->x_pixels / 2;
+ display_attributes->h_total += h_blanking;
+ }
+ return kErrorNone;
+}
+
+DisplayError HWHDMI::SetDisplayAttributes(uint32_t index) {
+ DTRACE_SCOPED();
+
+ DisplayError error = kErrorNone;
+
+ // Variable screen info
+ STRUCT_VAR(fb_var_screeninfo, vscreeninfo);
+ if (ioctl_(device_fd_, FBIOGET_VSCREENINFO, &vscreeninfo) < 0) {
+ IOCTL_LOGE(FBIOGET_VSCREENINFO, device_type_);
+ return kErrorHardware;
+ }
+
+ DLOGI("GetInfo<Mode=%d %dx%d (%d,%d,%d),(%d,%d,%d) %dMHz>", vscreeninfo.reserved[3],
+ vscreeninfo.xres, vscreeninfo.yres, vscreeninfo.right_margin, vscreeninfo.hsync_len,
+ vscreeninfo.left_margin, vscreeninfo.lower_margin, vscreeninfo.vsync_len,
+ vscreeninfo.upper_margin, vscreeninfo.pixclock/1000000);
+
+ msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[0];
+ for (int i = 0; i < HDMI_VFRMT_MAX; i++) {
+ msm_hdmi_mode_timing_info *cur = &supported_video_modes_[i];
+ if (cur->video_format == hdmi_modes_[index]) {
+ timing_mode = cur;
+ break;
+ }
+ }
+
+ if (MapHDMIDisplayTiming(timing_mode, &vscreeninfo) == false) {
+ return kErrorParameters;
+ }
+
+ STRUCT_VAR(msmfb_metadata, metadata);
+ metadata.op = metadata_op_vic;
+ metadata.data.video_info_code = timing_mode->video_format;
+ if (ioctl(device_fd_, MSMFB_METADATA_SET, &metadata) < 0) {
+ IOCTL_LOGE(MSMFB_METADATA_SET, device_type_);
+ return kErrorHardware;
+ }
+
+ DLOGI("SetInfo<Mode=%d %dx%d (%d,%d,%d),(%d,%d,%d) %dMHz>", vscreeninfo.reserved[3] & 0xFF00,
+ vscreeninfo.xres, vscreeninfo.yres, vscreeninfo.right_margin, vscreeninfo.hsync_len,
+ vscreeninfo.left_margin, vscreeninfo.lower_margin, vscreeninfo.vsync_len,
+ vscreeninfo.upper_margin, vscreeninfo.pixclock/1000000);
+
+ vscreeninfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE;
+ if (ioctl_(device_fd_, FBIOPUT_VSCREENINFO, &vscreeninfo) < 0) {
+ IOCTL_LOGE(FBIOGET_VSCREENINFO, device_type_);
+ return kErrorHardware;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError HWHDMI::GetConfigIndex(uint32_t mode, uint32_t *index) {
+ // Check if the mode is valid and return corresponding index
+ for (uint32_t i = 0; i < hdmi_mode_count_; i++) {
+ if (hdmi_modes_[i] == mode) {
+ *index = i;
+ DLOGI("Index = %d for config = %d", *index, mode);
+ return kErrorNone;
+ }
+ }
+
+ DLOGE("Config = %d not supported", mode);
+ return kErrorNotSupported;
+}
+
+DisplayError HWHDMI::PowerOn() {
+ return HWDevice::PowerOn();
+}
+
+DisplayError HWHDMI::PowerOff() {
+ return HWDevice::PowerOff();
+}
+
+DisplayError HWHDMI::Doze() {
+ return HWDevice::Doze();
+}
+
+DisplayError HWHDMI::DozeSuspend() {
+ return HWDevice::DozeSuspend();
+}
+
+DisplayError HWHDMI::Standby() {
+ return HWDevice::Standby();
+}
+
+DisplayError HWHDMI::Validate(HWLayers *hw_layers) {
+ HWDevice::ResetDisplayParams();
+ return HWDevice::Validate(hw_layers);
+}
+
+DisplayError HWHDMI::Commit(HWLayers *hw_layers) {
+ return HWDevice::Commit(hw_layers);
+}
+
+DisplayError HWHDMI::Flush() {
+ return HWDevice::Flush();
+}
+
+DisplayError HWHDMI::GetHWPanelInfo(HWPanelInfo *panel_info) {
+ return HWDevice::GetHWPanelInfo(panel_info);
+}
+
+DisplayError HWHDMI::GetHWScanInfo(HWScanInfo *scan_info) {
+ if (!scan_info) {
+ return kErrorParameters;
+ }
+ *scan_info = hw_scan_info_;
+ return kErrorNone;
+}
+
+DisplayError HWHDMI::GetVideoFormat(uint32_t config_index, uint32_t *video_format) {
+ *video_format = hdmi_modes_[config_index];
+
+ return kErrorNone;
+}
+
+DisplayError HWHDMI::GetMaxCEAFormat(uint32_t *max_cea_format) {
+ *max_cea_format = HDMI_VFRMT_END;
+
+ return kErrorNone;
+}
+
+HWScanSupport HWHDMI::MapHWScanSupport(uint32_t value) {
+ switch (value) {
+ // TODO(user): Read the scan type from driver defined values instead of hardcoding
+ case 0:
+ return kScanNotSupported;
+ case 1:
+ return kScanAlwaysOverscanned;
+ case 2:
+ return kScanAlwaysUnderscanned;
+ case 3:
+ return kScanBoth;
+ default:
+ return kScanNotSupported;
+ break;
+ }
+}
+
+void HWHDMI::ReadScanInfo() {
+ int scan_info_file = -1;
+ ssize_t len = -1;
+ char data[PAGE_SIZE] = {'\0'};
+
+ snprintf(data, sizeof(data), "%s%d/scan_info", fb_path_, fb_node_index_);
+ scan_info_file = open_(data, O_RDONLY);
+ if (scan_info_file < 0) {
+ DLOGW("File '%s' not found.", data);
+ return;
+ }
+
+ memset(&data[0], 0, sizeof(data));
+ len = read(scan_info_file, data, sizeof(data) - 1);
+ if (len <= 0) {
+ close_(scan_info_file);
+ DLOGW("File %s%d/scan_info is empty.", fb_path_, fb_node_index_);
+ return;
+ }
+ data[len] = '\0';
+ close_(scan_info_file);
+
+ const uint32_t scan_info_max_count = 3;
+ uint32_t scan_info_count = 0;
+ char *tokens[scan_info_max_count] = { NULL };
+ ParseLine(data, tokens, scan_info_max_count, &scan_info_count);
+ if (scan_info_count != scan_info_max_count) {
+ DLOGW("Failed to parse scan info string %s", data);
+ return;
+ }
+
+ hw_scan_info_.pt_scan_support = MapHWScanSupport(atoi(tokens[0]));
+ hw_scan_info_.it_scan_support = MapHWScanSupport(atoi(tokens[1]));
+ hw_scan_info_.cea_scan_support = MapHWScanSupport(atoi(tokens[2]));
+ DLOGI("PT %d IT %d CEA %d", hw_scan_info_.pt_scan_support, hw_scan_info_.it_scan_support,
+ hw_scan_info_.cea_scan_support);
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/core/fb/hw_hdmi.h b/sdm/libs/core/fb/hw_hdmi.h
new file mode 100644
index 0000000..8ac491d
--- /dev/null
+++ b/sdm/libs/core/fb/hw_hdmi.h
@@ -0,0 +1,74 @@
+/*
+* Copyright (c) 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __HW_HDMI_H__
+#define __HW_HDMI_H__
+
+#include <video/msm_hdmi_modes.h>
+#include "hw_device.h"
+#include "hw_hdmi_interface.h"
+
+namespace sdm {
+
+class HWHDMI : public HWDevice, public HWHDMIInterface {
+ public:
+ HWHDMI(BufferSyncHandler *buffer_sync_handler, HWInfoInterface *hw_info_intf);
+ virtual DisplayError Init();
+ virtual DisplayError Deinit();
+ virtual DisplayError Open(HWEventHandler *eventhandler);
+ virtual DisplayError Close();
+ virtual DisplayError GetNumDisplayAttributes(uint32_t *count);
+ virtual DisplayError GetDisplayAttributes(HWDisplayAttributes *display_attributes,
+ uint32_t index);
+ virtual DisplayError GetHWPanelInfo(HWPanelInfo *panel_info);
+ virtual DisplayError GetHWScanInfo(HWScanInfo *scan_info);
+ virtual DisplayError GetVideoFormat(uint32_t config_index, uint32_t *video_format);
+ virtual DisplayError GetMaxCEAFormat(uint32_t *max_cea_format);
+ virtual DisplayError SetDisplayAttributes(uint32_t index);
+ virtual DisplayError GetConfigIndex(uint32_t mode, uint32_t *index);
+ virtual DisplayError PowerOn();
+ virtual DisplayError PowerOff();
+ virtual DisplayError Doze();
+ virtual DisplayError DozeSuspend();
+ virtual DisplayError Standby();
+ virtual DisplayError Validate(HWLayers *hw_layers);
+ virtual DisplayError Commit(HWLayers *hw_layers);
+ virtual DisplayError Flush();
+
+ private:
+ int GetHDMIModeCount();
+ void ReadScanInfo();
+ HWScanSupport MapHWScanSupport(uint32_t value);
+
+ uint32_t hdmi_mode_count_;
+ uint32_t hdmi_modes_[256];
+ // Holds the hdmi timing information. Ex: resolution, fps etc.,
+ msm_hdmi_mode_timing_info *supported_video_modes_;
+ HWScanInfo hw_scan_info_;
+};
+
+} // namespace sdm
+
+#endif // __HW_HDMI_H__
+
diff --git a/sdm/libs/core/fb/hw_info.cpp b/sdm/libs/core/fb/hw_info.cpp
new file mode 100644
index 0000000..b998a46
--- /dev/null
+++ b/sdm/libs/core/fb/hw_info.cpp
@@ -0,0 +1,173 @@
+/*
+* Copyright (c) 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:
+* * 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.
+*/
+
+#include "hw_info.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <utils/constants.h>
+#include <utils/debug.h>
+
+#define __CLASS__ "HWInfo"
+
+namespace sdm {
+
+int HWInfo::ParseLine(char *input, char *tokens[], const uint32_t max_token, uint32_t *count) {
+ char *tmp_token = NULL;
+ char *temp_ptr;
+ uint32_t index = 0;
+ const char *delim = ", =\n";
+ if (!input) {
+ return -1;
+ }
+ tmp_token = strtok_r(input, delim, &temp_ptr);
+ while (tmp_token && index < max_token) {
+ tokens[index++] = tmp_token;
+ tmp_token = strtok_r(NULL, delim, &temp_ptr);
+ }
+ *count = index;
+
+ return 0;
+}
+
+DisplayError HWInfoInterface::Create(HWInfoInterface **intf) {
+ DisplayError error = kErrorNone;
+ HWInfo *hw_info = NULL;
+
+ hw_info = new HWInfo();
+ if (!hw_info) {
+ error = kErrorMemory;
+ } else {
+ *intf = hw_info;
+ }
+
+ return error;
+}
+
+DisplayError HWInfoInterface::Destroy(HWInfoInterface *intf) {
+ HWInfo *hw_info = static_cast<HWInfo *>(intf);
+ delete hw_info;
+
+ return kErrorNone;
+}
+
+DisplayError HWInfo::GetHWResourceInfo(HWResourceInfo *hw_resource) {
+ if (!hw_resource) {
+ DLOGE("HWResourceInfo pointer in invalid.");
+ return kErrorParameters;
+ }
+ const char *kHWCapabilitiesPath = "/sys/devices/virtual/graphics/fb";
+ FILE *fileptr = NULL;
+ char stringbuffer[kMaxStringLength];
+ uint32_t token_count = 0;
+ const uint32_t max_count = 10;
+ char *tokens[max_count] = { NULL };
+ snprintf(stringbuffer , sizeof(stringbuffer), "%s%d/mdp/caps",
+ kHWCapabilitiesPath, kHWCapabilitiesNode);
+ fileptr = fopen(stringbuffer, "rb");
+
+ if (!fileptr) {
+ DLOGE("File '%s' not found", stringbuffer);
+ return kErrorHardware;
+ }
+
+ size_t len = kMaxStringLength;
+ ssize_t read;
+ char *line = stringbuffer;
+ hw_resource->hw_version = kHWMdssVersion5;
+ while ((read = getline(&line, &len, fileptr)) != -1) {
+ // parse the line and update information accordingly
+ if (!ParseLine(line, tokens, max_count, &token_count)) {
+ if (!strncmp(tokens[0], "hw_rev", strlen("hw_rev"))) {
+ hw_resource->hw_revision = atoi(tokens[1]); // HW Rev, v1/v2
+ } else if (!strncmp(tokens[0], "rgb_pipes", strlen("rgb_pipes"))) {
+ hw_resource->num_rgb_pipe = UINT8(atoi(tokens[1]));
+ } else if (!strncmp(tokens[0], "vig_pipes", strlen("vig_pipes"))) {
+ hw_resource->num_vig_pipe = UINT8(atoi(tokens[1]));
+ } else if (!strncmp(tokens[0], "dma_pipes", strlen("dma_pipes"))) {
+ hw_resource->num_dma_pipe = UINT8(atoi(tokens[1]));
+ } else if (!strncmp(tokens[0], "cursor_pipes", strlen("cursor_pipes"))) {
+ hw_resource->num_cursor_pipe = UINT8(atoi(tokens[1]));
+ } else if (!strncmp(tokens[0], "blending_stages", strlen("blending_stages"))) {
+ hw_resource->num_blending_stages = UINT8(atoi(tokens[1]));
+ } else if (!strncmp(tokens[0], "max_downscale_ratio", strlen("max_downscale_ratio"))) {
+ hw_resource->max_scale_down = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "max_upscale_ratio", strlen("max_upscale_ratio"))) {
+ hw_resource->max_scale_up = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "max_bandwidth_low", strlen("max_bandwidth_low"))) {
+ hw_resource->max_bandwidth_low = atol(tokens[1]);
+ } else if (!strncmp(tokens[0], "max_bandwidth_high", strlen("max_bandwidth_high"))) {
+ hw_resource->max_bandwidth_high = atol(tokens[1]);
+ } else if (!strncmp(tokens[0], "max_mixer_width", strlen("max_mixer_width"))) {
+ hw_resource->max_mixer_width = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "max_pipe_width", strlen("max_pipe_width"))) {
+ hw_resource->max_pipe_width = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "max_pipe_bw", strlen("max_pipe_bw"))) {
+ hw_resource->max_pipe_bw = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "max_mdp_clk", strlen("max_mdp_clk"))) {
+ hw_resource->max_sde_clk = atoi(tokens[1]);
+ } else if (!strncmp(tokens[0], "clk_fudge_factor", strlen("clk_fudge_factor"))) {
+ hw_resource->clk_fudge_factor = FLOAT(atoi(tokens[1])) / FLOAT(atoi(tokens[2]));
+ } else if (!strncmp(tokens[0], "features", strlen("features"))) {
+ for (uint32_t i = 0; i < token_count; i++) {
+ if (!strncmp(tokens[i], "bwc", strlen("bwc"))) {
+ hw_resource->has_bwc = true;
+ } else if (!strncmp(tokens[i], "decimation", strlen("decimation"))) {
+ hw_resource->has_decimation = true;
+ } else if (!strncmp(tokens[i], "tile_format", strlen("tile_format"))) {
+ hw_resource->has_macrotile = true;
+ } else if (!strncmp(tokens[i], "src_split", strlen("src_split"))) {
+ hw_resource->is_src_split = true;
+ } else if (!strncmp(tokens[i], "non_scalar_rgb", strlen("non_scalar_rgb"))) {
+ hw_resource->has_non_scalar_rgb = true;
+ } else if (!strncmp(tokens[i], "rotator_downscale", strlen("rotator_downscale"))) {
+ hw_resource->has_rotator_downscale = true;
+ }
+ }
+ }
+ }
+ }
+ fclose(fileptr);
+
+ DLOGI("SDE Version = %d, SDE Revision = %x, RGB = %d, VIG = %d, DMA = %d, Cursor = %d",
+ hw_resource->hw_version, hw_resource->hw_revision, hw_resource->num_rgb_pipe,
+ hw_resource->num_vig_pipe, hw_resource->num_dma_pipe, hw_resource->num_cursor_pipe);
+ DLOGI("Upscale Ratio = %d, Downscale Ratio = %d, Blending Stages = %d", hw_resource->max_scale_up,
+ hw_resource->max_scale_down, hw_resource->num_blending_stages);
+ DLOGI("BWC = %d, Decimation = %d, Tile Format = %d, Rotator Downscale = %d", hw_resource->has_bwc,
+ hw_resource->has_decimation, hw_resource->has_macrotile,
+ hw_resource->has_rotator_downscale);
+ DLOGI("SourceSplit = %d", hw_resource->is_src_split);
+ DLOGI("MaxLowBw = %"PRIu64", MaxHighBw = %"PRIu64"", hw_resource->max_bandwidth_low,
+ hw_resource->max_bandwidth_high);
+ DLOGI("MaxPipeBw = %"PRIu64" KBps, MaxSDEClock = %"PRIu64" Hz, ClockFudgeFactor = %f",
+ hw_resource->max_pipe_bw, hw_resource->max_sde_clk, hw_resource->clk_fudge_factor);
+
+ return kErrorNone;
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/core/fb/hw_info.h b/sdm/libs/core/fb/hw_info.h
new file mode 100644
index 0000000..95f669f
--- /dev/null
+++ b/sdm/libs/core/fb/hw_info.h
@@ -0,0 +1,54 @@
+/*
+* Copyright (c) 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __HW_INFO_H__
+#define __HW_INFO_H__
+
+#include <inttypes.h>
+#include <core/sdm_types.h>
+#include <private/hw_info_types.h>
+#include "hw_info_interface.h"
+
+namespace sdm {
+
+class HWInfo: public HWInfoInterface {
+ public:
+ virtual DisplayError GetHWResourceInfo(HWResourceInfo *hw_resource);
+
+ private:
+ // TODO(user): Read Mdss version from the driver
+ static const int kHWMdssVersion5 = 500; // MDSS_V5
+ static const int kMaxStringLength = 1024;
+ // MDP Capabilities are replicated across all frame buffer devices.
+ // However, we rely on reading the capabalities from fbO since this
+ // is guaranteed to be available.
+ static const int kHWCapabilitiesNode = 0;
+
+ static int ParseLine(char *input, char *tokens[], const uint32_t max_token, uint32_t *count);
+};
+
+} // namespace sdm
+
+#endif // __HW_INFO_H__
+
diff --git a/sdm/libs/core/fb/hw_primary.cpp b/sdm/libs/core/fb/hw_primary.cpp
new file mode 100644
index 0000000..cb4d8b2
--- /dev/null
+++ b/sdm/libs/core/fb/hw_primary.cpp
@@ -0,0 +1,498 @@
+/*
+* Copyright (c) 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:
+* * 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.
+*/
+
+#include <sys/prctl.h>
+#include <sys/ioctl.h>
+#include <pthread.h>
+#include <sys/resource.h>
+#include <fcntl.h>
+#include <utils/debug.h>
+#include "hw_primary.h"
+
+#define __CLASS__ "HWPrimary"
+
+namespace sdm {
+
+DisplayError HWPrimaryInterface::Create(HWPrimaryInterface **intf, HWInfoInterface *hw_info_intf,
+ BufferSyncHandler *buffer_sync_handler) {
+ DisplayError error = kErrorNone;
+ HWPrimary *hw_primary = NULL;
+
+ hw_primary = new HWPrimary(buffer_sync_handler, hw_info_intf);
+ error = hw_primary->Init();
+ if (error != kErrorNone) {
+ delete hw_primary;
+ } else {
+ *intf = hw_primary;
+ }
+
+ return error;
+}
+
+DisplayError HWPrimaryInterface::Destroy(HWPrimaryInterface *intf) {
+ HWPrimary *hw_primary = static_cast<HWPrimary *>(intf);
+ hw_primary->Deinit();
+ delete hw_primary;
+
+ return kErrorNone;
+}
+
+HWPrimary::HWPrimary(BufferSyncHandler *buffer_sync_handler, HWInfoInterface *hw_info_intf)
+ : HWDevice(buffer_sync_handler), event_thread_name_("SDM_EventThread"), fake_vsync_(false),
+ exit_threads_(false), config_changed_(true) {
+ HWDevice::device_type_ = kDevicePrimary;
+ HWDevice::device_name_ = "Primary Display Device";
+ HWDevice::hw_info_intf_ = hw_info_intf;
+}
+
+DisplayError HWPrimary::Init() {
+ DisplayError error = kErrorNone;
+ char node_path[kMaxStringLength] = {0};
+ char data[kMaxStringLength] = {0};
+ const char* event_name[kNumDisplayEvents] = {"vsync_event", "show_blank_event", "idle_notify",
+ "msm_fb_thermal_level"};
+
+ error = HWDevice::Init();
+ if (error != kErrorNone) {
+ goto CleanupOnError;
+ }
+
+ // Open nodes for polling
+ for (int event = 0; event < kNumDisplayEvents; event++) {
+ poll_fds_[event].fd = -1;
+ }
+
+ if (!fake_vsync_) {
+ for (int event = 0; event < kNumDisplayEvents; event++) {
+ pollfd &poll_fd = poll_fds_[event];
+
+ if ((hw_panel_info_.mode == kModeCommand) &&
+ (!strncmp(event_name[event], "idle_notify", strlen("idle_notify")))) {
+ continue;
+ }
+
+ snprintf(node_path, sizeof(node_path), "%s%d/%s", fb_path_, fb_node_index_,
+ event_name[event]);
+
+ poll_fd.fd = open_(node_path, O_RDONLY);
+ if (poll_fd.fd < 0) {
+ DLOGE("open failed for event=%d, error=%s", event, strerror(errno));
+ error = kErrorHardware;
+ goto CleanupOnError;
+ }
+
+ // Read once on all fds to clear data on all fds.
+ pread_(poll_fd.fd, data , kMaxStringLength, 0);
+ poll_fd.events = POLLPRI | POLLERR;
+ }
+ }
+
+ // Start the Event thread
+ if (pthread_create(&event_thread_, NULL, &DisplayEventThread, this) < 0) {
+ DLOGE("Failed to start %s, error = %s", event_thread_name_);
+ error = kErrorResources;
+ 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:
+ // Close all poll fds
+ for (int event = 0; event < kNumDisplayEvents; event++) {
+ int &fd = poll_fds_[event].fd;
+ if (fd >= 0) {
+ close_(fd);
+ }
+ }
+
+ return error;
+}
+
+DisplayError HWPrimary::Deinit() {
+ exit_threads_ = true;
+ pthread_join(event_thread_, NULL);
+
+ for (int event = 0; event < kNumDisplayEvents; event++) {
+ close_(poll_fds_[event].fd);
+ }
+
+ return kErrorNone;
+}
+
+DisplayError HWPrimary::Open(HWEventHandler *eventhandler) {
+ return HWDevice::Open(eventhandler);
+}
+
+DisplayError HWPrimary::Close() {
+ return HWDevice::Close();
+}
+
+DisplayError HWPrimary::GetNumDisplayAttributes(uint32_t *count) {
+ return HWDevice::GetNumDisplayAttributes(count);
+}
+
+DisplayError HWPrimary::GetDisplayAttributes(HWDisplayAttributes *display_attributes,
+ uint32_t index) {
+ if (!display_attributes) {
+ return kErrorParameters;
+ }
+
+ if (config_changed_) {
+ PopulateDisplayAttributes();
+ config_changed_ = false;
+ }
+
+ *display_attributes = display_attributes_;
+
+ return kErrorNone;
+}
+
+DisplayError HWPrimary::PopulateDisplayAttributes() {
+ DTRACE_SCOPED();
+
+ // Variable screen info
+ STRUCT_VAR(fb_var_screeninfo, var_screeninfo);
+
+ if (ioctl_(device_fd_, FBIOGET_VSCREENINFO, &var_screeninfo) < 0) {
+ IOCTL_LOGE(FBIOGET_VSCREENINFO, device_type_);
+ return kErrorHardware;
+ }
+
+ // Frame rate
+ STRUCT_VAR(msmfb_metadata, meta_data);
+ meta_data.op = metadata_op_frame_rate;
+ if (ioctl_(device_fd_, MSMFB_METADATA_GET, &meta_data) < 0) {
+ IOCTL_LOGE(MSMFB_METADATA_GET, device_type_);
+ 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);
+ }
+
+ display_attributes_.x_pixels = var_screeninfo.xres;
+ display_attributes_.y_pixels = var_screeninfo.yres;
+ display_attributes_.v_total = var_screeninfo.yres + var_screeninfo.lower_margin +
+ var_screeninfo.upper_margin + var_screeninfo.vsync_len;
+ uint32_t h_blanking = var_screeninfo.right_margin + var_screeninfo.left_margin +
+ var_screeninfo.hsync_len;
+ display_attributes_.h_total = var_screeninfo.xres + var_screeninfo.right_margin +
+ var_screeninfo.left_margin + var_screeninfo.hsync_len;
+ display_attributes_.x_dpi =
+ (FLOAT(var_screeninfo.xres) * 25.4f) / FLOAT(var_screeninfo.width);
+ display_attributes_.y_dpi =
+ (FLOAT(var_screeninfo.yres) * 25.4f) / FLOAT(var_screeninfo.height);
+ display_attributes_.fps = meta_data.data.panel_frame_rate;
+ display_attributes_.vsync_period_ns = UINT32(1000000000L / display_attributes_.fps);
+ display_attributes_.is_device_split = (hw_panel_info_.split_info.left_split ||
+ (var_screeninfo.xres > hw_resource_.max_mixer_width)) ? true : false;
+ display_attributes_.split_left = hw_panel_info_.split_info.left_split ?
+ hw_panel_info_.split_info.left_split : display_attributes_.x_pixels / 2;
+ display_attributes_.always_src_split = hw_panel_info_.split_info.always_src_split;
+ display_attributes_.h_total += display_attributes_.is_device_split ? h_blanking : 0;
+
+ return kErrorNone;
+}
+
+DisplayError HWPrimary::SetDisplayAttributes(uint32_t index) {
+ return HWDevice::SetDisplayAttributes(index);
+}
+
+DisplayError HWPrimary::SetRefreshRate(uint32_t refresh_rate) {
+ char node_path[kMaxStringLength] = {0};
+
+ DLOGI("Setting refresh rate to = %d fps", refresh_rate);
+
+ snprintf(node_path, sizeof(node_path), "%s%d/dynamic_fps", fb_path_, fb_node_index_);
+
+ int fd = open_(node_path, O_WRONLY);
+ if (fd < 0) {
+ DLOGE("Failed to open %s with error %s", node_path, strerror(errno));
+ return kErrorFileDescriptor;
+ }
+
+ char refresh_rate_string[kMaxStringLength];
+ snprintf(refresh_rate_string, sizeof(refresh_rate_string), "%d", refresh_rate);
+ ssize_t len = pwrite_(fd, refresh_rate_string, strlen(refresh_rate_string), 0);
+ if (len < 0) {
+ DLOGE("Failed to write %d with error %s", refresh_rate, strerror(errno));
+ close_(fd);
+ return kErrorUndefined;
+ }
+ close_(fd);
+
+ config_changed_ = true;
+ synchronous_commit_ = true;
+
+ return kErrorNone;
+}
+
+DisplayError HWPrimary::GetConfigIndex(uint32_t mode, uint32_t *index) {
+ return HWDevice::GetConfigIndex(mode, index);
+}
+
+DisplayError HWPrimary::PowerOn() {
+ return HWDevice::PowerOn();
+}
+
+DisplayError HWPrimary::PowerOff() {
+ if (ioctl_(device_fd_, FBIOBLANK, FB_BLANK_POWERDOWN) < 0) {
+ IOCTL_LOGE(FB_BLANK_POWERDOWN, device_type_);
+ return kErrorHardware;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError HWPrimary::Doze() {
+ if (ioctl_(device_fd_, FBIOBLANK, FB_BLANK_NORMAL) < 0) {
+ IOCTL_LOGE(FB_BLANK_NORMAL, device_type_);
+ return kErrorHardware;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError HWPrimary::DozeSuspend() {
+ if (ioctl_(device_fd_, FBIOBLANK, FB_BLANK_VSYNC_SUSPEND) < 0) {
+ IOCTL_LOGE(FB_BLANK_VSYNC_SUSPEND, device_type_);
+ return kErrorHardware;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError HWPrimary::Standby() {
+ return HWDevice::Standby();
+}
+
+DisplayError HWPrimary::Validate(HWLayers *hw_layers) {
+ HWDevice::ResetDisplayParams();
+
+ mdp_layer_commit_v1 &mdp_commit = mdp_disp_commit_.commit_v1;
+
+ LayerRect left_roi = hw_layers->info.left_partial_update;
+ LayerRect right_roi = hw_layers->info.right_partial_update;
+ mdp_commit.left_roi.x = INT(left_roi.left);
+ mdp_commit.left_roi.y = INT(left_roi.top);
+ mdp_commit.left_roi.w = INT(left_roi.right - left_roi.left);
+ mdp_commit.left_roi.h = INT(left_roi.bottom - left_roi.top);
+
+ // SDM treats ROI as one full coordinate system.
+ // In case source split is disabled, However, Driver assumes Mixer to operate in
+ // different co-ordinate system.
+ if (!hw_resource_.is_src_split) {
+ mdp_commit.right_roi.x = INT(right_roi.left) - hw_panel_info_.split_info.left_split;
+ mdp_commit.right_roi.y = INT(right_roi.top);
+ mdp_commit.right_roi.w = INT(right_roi.right - right_roi.left);
+ mdp_commit.right_roi.h = INT(right_roi.bottom - right_roi.top);
+ }
+
+ return HWDevice::Validate(hw_layers);
+}
+
+DisplayError HWPrimary::Commit(HWLayers *hw_layers) {
+ return HWDevice::Commit(hw_layers);
+}
+
+DisplayError HWPrimary::Flush() {
+ return HWDevice::Flush();
+}
+
+DisplayError HWPrimary::GetHWPanelInfo(HWPanelInfo *panel_info) {
+ return HWDevice::GetHWPanelInfo(panel_info);
+}
+
+void* HWPrimary::DisplayEventThread(void *context) {
+ if (context) {
+ return reinterpret_cast<HWPrimary *>(context)->DisplayEventThreadHandler();
+ }
+
+ return NULL;
+}
+
+void* HWPrimary::DisplayEventThreadHandler() {
+ char data[kMaxStringLength] = {0};
+
+ prctl(PR_SET_NAME, event_thread_name_, 0, 0, 0);
+ setpriority(PRIO_PROCESS, 0, kThreadPriorityUrgent);
+
+ if (fake_vsync_) {
+ while (!exit_threads_) {
+ // Fake vsync is used only when set explicitly through a property(todo) or when
+ // the vsync timestamp node cannot be opened at bootup. There is no
+ // fallback to fake vsync from the true vsync loop, ever, as the
+ // condition can easily escape detection.
+ // Also, fake vsync is delivered only for the primary display.
+ usleep(16666);
+ STRUCT_VAR(timeval, time_now);
+ gettimeofday(&time_now, NULL);
+ uint64_t ts = uint64_t(time_now.tv_sec)*1000000000LL +uint64_t(time_now.tv_usec)*1000LL;
+
+ // Send Vsync event for primary display(0)
+ event_handler_->VSync(ts);
+ }
+
+ pthread_exit(0);
+ }
+
+ typedef void (HWPrimary::*EventHandler)(char*);
+ EventHandler event_handler[kNumDisplayEvents] = { &HWPrimary::HandleVSync,
+ &HWPrimary::HandleBlank,
+ &HWPrimary::HandleIdleTimeout,
+ &HWPrimary::HandleThermal };
+
+ while (!exit_threads_) {
+ int error = poll_(poll_fds_, kNumDisplayEvents, -1);
+ if (error < 0) {
+ DLOGW("poll failed. error = %s", strerror(errno));
+ continue;
+ }
+ for (int event = 0; event < kNumDisplayEvents; event++) {
+ pollfd &poll_fd = poll_fds_[event];
+
+ if (poll_fd.revents & POLLPRI) {
+ ssize_t length = pread_(poll_fd.fd, data, kMaxStringLength, 0);
+ if (length < 0) {
+ // If the read was interrupted - it is not a fatal error, just continue.
+ DLOGW("pread failed. event = %d, error = %s", event, strerror(errno));
+ continue;
+ }
+
+ (this->*event_handler[event])(data);
+ }
+ }
+ }
+
+ pthread_exit(0);
+
+ return NULL;
+}
+
+void HWPrimary::HandleVSync(char *data) {
+ int64_t timestamp = 0;
+ if (!strncmp(data, "VSYNC=", strlen("VSYNC="))) {
+ timestamp = strtoull(data + strlen("VSYNC="), NULL, 0);
+ }
+ event_handler_->VSync(timestamp);
+}
+
+void HWPrimary::HandleBlank(char *data) {
+ // TODO(user): Need to send blank Event
+}
+
+void HWPrimary::HandleIdleTimeout(char *data) {
+ event_handler_->IdleTimeout();
+}
+
+void HWPrimary::HandleThermal(char *data) {
+ int64_t thermal_level = 0;
+ if (!strncmp(data, "thermal_level=", strlen("thermal_level="))) {
+ thermal_level = strtoull(data + strlen("thermal_level="), NULL, 0);
+ }
+
+ DLOGI("Received thermal notification with thermal level = %d", thermal_level);
+
+ event_handler_->ThermalEvent(thermal_level);
+}
+
+void HWPrimary::SetIdleTimeoutMs(uint32_t timeout_ms) {
+ char node_path[kMaxStringLength] = {0};
+
+ DLOGI("Setting idle timeout to = %d ms", timeout_ms);
+
+ snprintf(node_path, sizeof(node_path), "%s%d/idle_time", fb_path_, fb_node_index_);
+
+ // Open a sysfs node to send the timeout value to driver.
+ int fd = open_(node_path, O_WRONLY);
+ if (fd < 0) {
+ DLOGE("Unable to open %s, node %s", node_path, strerror(errno));
+ return;
+ }
+
+ char timeout_string[64];
+ snprintf(timeout_string, sizeof(timeout_string), "%d", timeout_ms);
+
+ // Notify driver about the timeout value
+ ssize_t length = pwrite_(fd, timeout_string, strlen(timeout_string), 0);
+ if (length < -1) {
+ DLOGE("Unable to write into %s, node %s", node_path, strerror(errno));
+ }
+
+ close_(fd);
+}
+
+DisplayError HWPrimary::SetVSyncState(bool enable) {
+ DTRACE_SCOPED();
+
+ int vsync_on = enable ? 1 : 0;
+ if (ioctl_(device_fd_, MSMFB_OVERLAY_VSYNC_CTRL, &vsync_on) < 0) {
+ IOCTL_LOGE(MSMFB_OVERLAY_VSYNC_CTRL, device_type_);
+ return kErrorHardware;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError HWPrimary::SetDisplayMode(const HWDisplayMode hw_display_mode) {
+ DisplayError error = kErrorNone;
+ uint32_t mode = -1;
+
+ switch (hw_display_mode) {
+ case kModeVideo:
+ mode = kModeLPMVideo;
+ break;
+ case kModeCommand:
+ mode = kModeLPMCommand;
+ break;
+ default:
+ DLOGW("Failed to translate SDE display mode %d to a MSMFB_LPM_ENABLE mode",
+ hw_display_mode);
+ return kErrorParameters;
+ }
+
+ if (ioctl_(device_fd_, MSMFB_LPM_ENABLE, &mode) < 0) {
+ IOCTL_LOGE(MSMFB_LPM_ENABLE, device_type_);
+ return kErrorHardware;
+ }
+
+ DLOGI("Triggering display mode change to %d on next commit.", hw_display_mode);
+ synchronous_commit_ = true;
+
+ return kErrorNone;
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/core/fb/hw_primary.h b/sdm/libs/core/fb/hw_primary.h
new file mode 100644
index 0000000..f7ccef2
--- /dev/null
+++ b/sdm/libs/core/fb/hw_primary.h
@@ -0,0 +1,88 @@
+/*
+* Copyright (c) 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __HW_PRIMARY_H__
+#define __HW_PRIMARY_H__
+
+#include "hw_device.h"
+#include "hw_primary_interface.h"
+
+namespace sdm {
+
+class HWPrimary : public HWDevice, public HWPrimaryInterface {
+ public:
+ HWPrimary(BufferSyncHandler *buffer_sync_handler, HWInfoInterface *hw_info_intf);
+ virtual DisplayError Init();
+ virtual DisplayError Deinit();
+ virtual DisplayError Open(HWEventHandler *eventhandler);
+ virtual DisplayError Close();
+ virtual DisplayError GetNumDisplayAttributes(uint32_t *count);
+ virtual DisplayError GetDisplayAttributes(HWDisplayAttributes *display_attributes,
+ uint32_t index);
+ virtual DisplayError GetHWPanelInfo(HWPanelInfo *panel_info);
+ virtual DisplayError SetDisplayAttributes(uint32_t index);
+ virtual DisplayError GetConfigIndex(uint32_t mode, uint32_t *index);
+ virtual DisplayError PowerOn();
+ virtual DisplayError PowerOff();
+ virtual DisplayError Doze();
+ virtual DisplayError DozeSuspend();
+ virtual DisplayError Standby();
+ virtual DisplayError Validate(HWLayers *hw_layers);
+ virtual DisplayError Commit(HWLayers *hw_layers);
+ virtual DisplayError Flush();
+ virtual void SetIdleTimeoutMs(uint32_t timeout_ms);
+ virtual DisplayError SetVSyncState(bool enable);
+ virtual DisplayError SetDisplayMode(const HWDisplayMode hw_display_mode);
+ virtual DisplayError SetRefreshRate(uint32_t refresh_rate);
+
+ private:
+ // Panel modes for the MSMFB_LPM_ENABLE ioctl
+ enum {
+ kModeLPMVideo,
+ kModeLPMCommand,
+ };
+
+ // Event Thread to receive vsync/blank events
+ static void* DisplayEventThread(void *context);
+ void* DisplayEventThreadHandler();
+
+ void HandleVSync(char *data);
+ void HandleBlank(char *data);
+ void HandleIdleTimeout(char *data);
+ void HandleThermal(char *data);
+ DisplayError PopulateDisplayAttributes();
+
+ pollfd poll_fds_[kNumDisplayEvents];
+ pthread_t event_thread_;
+ const char *event_thread_name_;
+ bool fake_vsync_;
+ bool exit_threads_;
+ HWDisplayAttributes display_attributes_;
+ bool config_changed_;
+};
+
+} // namespace sdm
+
+#endif // __HW_PRIMARY_H__
+
diff --git a/sdm/libs/core/fb/hw_virtual.cpp b/sdm/libs/core/fb/hw_virtual.cpp
new file mode 100644
index 0000000..79c9537
--- /dev/null
+++ b/sdm/libs/core/fb/hw_virtual.cpp
@@ -0,0 +1,139 @@
+/*
+* Copyright (c) 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:
+* * 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.
+*/
+
+#include <utils/debug.h>
+#include "hw_virtual.h"
+
+#define __CLASS__ "HWVirtual"
+
+namespace sdm {
+
+DisplayError HWVirtualInterface::Create(HWVirtualInterface **intf, HWInfoInterface *hw_info_intf,
+ BufferSyncHandler *buffer_sync_handler) {
+ DisplayError error = kErrorNone;
+ HWVirtual *hw_virtual = NULL;
+
+ hw_virtual = new HWVirtual(buffer_sync_handler, hw_info_intf);
+ error = hw_virtual->Init();
+ if (error != kErrorNone) {
+ delete hw_virtual;
+ } else {
+ *intf = hw_virtual;
+ }
+
+ return error;
+}
+
+DisplayError HWVirtualInterface::Destroy(HWVirtualInterface *intf) {
+ HWVirtual *hw_virtual = static_cast<HWVirtual *>(intf);
+ hw_virtual->Deinit();
+ delete hw_virtual;
+
+ return kErrorNone;
+}
+
+HWVirtual::HWVirtual(BufferSyncHandler *buffer_sync_handler, HWInfoInterface *hw_info_intf)
+ : HWDevice(buffer_sync_handler) {
+ HWDevice::device_type_ = kDeviceVirtual;
+ HWDevice::device_name_ = "Virtual Display Device";
+ HWDevice::hw_info_intf_ = hw_info_intf;
+}
+
+DisplayError HWVirtual::Init() {
+ return HWDevice::Init();
+}
+
+DisplayError HWVirtual::Deinit() {
+ return kErrorNone;
+}
+
+DisplayError HWVirtual::Open(HWEventHandler *eventhandler) {
+ return HWDevice::Open(eventhandler);
+}
+
+DisplayError HWVirtual::Close() {
+ return HWDevice::Close();
+}
+
+DisplayError HWVirtual::GetNumDisplayAttributes(uint32_t *count) {
+ return HWDevice::GetNumDisplayAttributes(count);
+}
+
+DisplayError HWVirtual::GetDisplayAttributes(HWDisplayAttributes *display_attributes,
+ uint32_t index) {
+ return HWDevice::GetDisplayAttributes(display_attributes, index);
+}
+
+DisplayError HWVirtual::SetDisplayAttributes(uint32_t index) {
+ return HWDevice::SetDisplayAttributes(index);
+}
+
+DisplayError HWVirtual::GetConfigIndex(uint32_t mode, uint32_t *index) {
+ return HWDevice::GetConfigIndex(mode, index);
+}
+
+DisplayError HWVirtual::PowerOn() {
+ return HWDevice::PowerOn();
+}
+
+DisplayError HWVirtual::PowerOff() {
+ return HWDevice::PowerOff();
+}
+
+DisplayError HWVirtual::Doze() {
+ return HWDevice::Doze();
+}
+
+DisplayError HWVirtual::DozeSuspend() {
+ return HWDevice::DozeSuspend();
+}
+
+DisplayError HWVirtual::Standby() {
+ return HWDevice::Standby();
+}
+
+DisplayError HWVirtual::Validate(HWLayers *hw_layers) {
+ HWDevice::ResetDisplayParams();
+ return HWDevice::Validate(hw_layers);
+}
+
+DisplayError HWVirtual::Commit(HWLayers *hw_layers) {
+ return HWDevice::Commit(hw_layers);
+}
+
+DisplayError HWVirtual::Flush() {
+ return HWDevice::Flush();
+}
+
+DisplayError HWVirtual::GetHWPanelInfo(HWPanelInfo *panel_info) {
+ return HWDevice::GetHWPanelInfo(panel_info);
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/core/fb/hw_virtual.h b/sdm/libs/core/fb/hw_virtual.h
new file mode 100644
index 0000000..507de88
--- /dev/null
+++ b/sdm/libs/core/fb/hw_virtual.h
@@ -0,0 +1,59 @@
+/*
+* Copyright (c) 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __HW_VIRTUAL_H__
+#define __HW_VIRTUAL_H__
+
+#include "hw_device.h"
+#include "hw_virtual_interface.h"
+
+namespace sdm {
+
+class HWVirtual : public HWDevice, public HWVirtualInterface {
+ public:
+ HWVirtual(BufferSyncHandler *buffer_sync_handler, HWInfoInterface *hw_info_intf);
+ virtual DisplayError Init();
+ virtual DisplayError Deinit();
+ virtual DisplayError Open(HWEventHandler *eventhandler);
+ virtual DisplayError Close();
+ virtual DisplayError GetNumDisplayAttributes(uint32_t *count);
+ virtual DisplayError GetDisplayAttributes(HWDisplayAttributes *display_attributes,
+ uint32_t index);
+ virtual DisplayError GetHWPanelInfo(HWPanelInfo *panel_info);
+ virtual DisplayError SetDisplayAttributes(uint32_t index);
+ virtual DisplayError GetConfigIndex(uint32_t mode, uint32_t *index);
+ virtual DisplayError PowerOn();
+ virtual DisplayError PowerOff();
+ virtual DisplayError Doze();
+ virtual DisplayError DozeSuspend();
+ virtual DisplayError Standby();
+ virtual DisplayError Validate(HWLayers *hw_layers);
+ virtual DisplayError Commit(HWLayers *hw_layers);
+ virtual DisplayError Flush();
+};
+
+} // namespace sdm
+
+#endif // __HW_VIRTUAL_H__
+
diff --git a/sdm/libs/core/hw_hdmi_interface.h b/sdm/libs/core/hw_hdmi_interface.h
new file mode 100644
index 0000000..0d3d800
--- /dev/null
+++ b/sdm/libs/core/hw_hdmi_interface.h
@@ -0,0 +1,50 @@
+/*
+* Copyright (c) 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __HW_HDMI_INTERFACE_H__
+#define __HW_HDMI_INTERFACE_H__
+
+#include "hw_interface.h"
+
+namespace sdm {
+
+class HWInfoInterface;
+
+class HWHDMIInterface: virtual public HWInterface {
+ public:
+ static DisplayError Create(HWHDMIInterface **intf, HWInfoInterface *hw_info_intf,
+ BufferSyncHandler *buffer_sync_handler);
+ static DisplayError Destroy(HWHDMIInterface *intf);
+ virtual DisplayError GetHWScanInfo(HWScanInfo *scan_info) = 0;
+ virtual DisplayError GetVideoFormat(uint32_t config_index, uint32_t *video_format) = 0;
+ virtual DisplayError GetMaxCEAFormat(uint32_t *max_cea_format) = 0;
+
+ protected:
+ virtual ~HWHDMIInterface() { }
+};
+
+} // namespace sdm
+
+#endif // __HW_HDMI_INTERFACE_H__
+
diff --git a/sdm/libs/core/hw_info_interface.h b/sdm/libs/core/hw_info_interface.h
new file mode 100644
index 0000000..014ab0d
--- /dev/null
+++ b/sdm/libs/core/hw_info_interface.h
@@ -0,0 +1,46 @@
+/*
+* 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __HW_INFO_INTERFACE_H__
+#define __HW_INFO_INTERFACE_H__
+
+#include <inttypes.h>
+#include <private/hw_info_types.h>
+
+namespace sdm {
+
+class HWInfoInterface {
+ public:
+ static DisplayError Create(HWInfoInterface **intf);
+ static DisplayError Destroy(HWInfoInterface *intf);
+ virtual DisplayError GetHWResourceInfo(HWResourceInfo *hw_resource) = 0;
+
+ protected:
+ virtual ~HWInfoInterface() { }
+};
+
+} // namespace sdm
+
+#endif // __HW_INFO_INTERFACE_H__
+
diff --git a/sdm/libs/core/hw_interface.h b/sdm/libs/core/hw_interface.h
new file mode 100644
index 0000000..317e087
--- /dev/null
+++ b/sdm/libs/core/hw_interface.h
@@ -0,0 +1,90 @@
+/*
+* 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __HW_INTERFACE_H__
+#define __HW_INTERFACE_H__
+
+#include <core/display_interface.h>
+#include <private/strategy_interface.h>
+#include <private/hw_info_types.h>
+#include <utils/constants.h>
+#include <core/buffer_allocator.h>
+#include <core/buffer_sync_handler.h>
+
+namespace sdm {
+
+enum HWScanSupport {
+ kScanNotSupported,
+ kScanAlwaysOverscanned,
+ kScanAlwaysUnderscanned,
+ kScanBoth,
+};
+
+struct HWScanInfo {
+ HWScanSupport pt_scan_support; // Scan support for preferred timing
+ HWScanSupport it_scan_support; // Scan support for digital monitor or industry timings
+ HWScanSupport cea_scan_support; // Scan support for CEA resolution timings
+
+ HWScanInfo() : pt_scan_support(kScanNotSupported), it_scan_support(kScanNotSupported),
+ cea_scan_support(kScanNotSupported) { }
+};
+
+// HWEventHandler - Implemented in DisplayBase and HWInterface implementation
+class HWEventHandler {
+ public:
+ virtual DisplayError VSync(int64_t timestamp) = 0;
+ virtual DisplayError Blank(bool blank) = 0;
+ virtual void IdleTimeout() = 0;
+ virtual void ThermalEvent(int64_t thermal_level) = 0;
+ protected:
+ virtual ~HWEventHandler() { }
+};
+
+class HWInterface {
+ public:
+ virtual DisplayError Open(HWEventHandler *eventhandler) = 0;
+ virtual DisplayError Close() = 0;
+ virtual DisplayError GetNumDisplayAttributes(uint32_t *count) = 0;
+ virtual DisplayError GetDisplayAttributes(HWDisplayAttributes *display_attributes,
+ uint32_t index) = 0;
+ virtual DisplayError GetHWPanelInfo(HWPanelInfo *panel_info) = 0;
+ virtual DisplayError SetDisplayAttributes(uint32_t index) = 0;
+ virtual DisplayError GetConfigIndex(uint32_t mode, uint32_t *index) = 0;
+ virtual DisplayError PowerOn() = 0;
+ virtual DisplayError PowerOff() = 0;
+ virtual DisplayError Doze() = 0;
+ virtual DisplayError DozeSuspend() = 0;
+ virtual DisplayError Standby() = 0;
+ virtual DisplayError Validate(HWLayers *hw_layers) = 0;
+ virtual DisplayError Commit(HWLayers *hw_layers) = 0;
+ virtual DisplayError Flush() = 0;
+
+ protected:
+ virtual ~HWInterface() { }
+};
+
+} // namespace sdm
+
+#endif // __HW_INTERFACE_H__
+
diff --git a/sdm/libs/core/hw_primary_interface.h b/sdm/libs/core/hw_primary_interface.h
new file mode 100644
index 0000000..9faa6e5
--- /dev/null
+++ b/sdm/libs/core/hw_primary_interface.h
@@ -0,0 +1,50 @@
+/*
+* Copyright (c) 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __HW_PRIMARY_INTERFACE_H__
+#define __HW_PRIMARY_INTERFACE_H__
+
+namespace sdm {
+
+class BufferSyncHandler;
+class HWInfoInterface;
+
+class HWPrimaryInterface: virtual public HWInterface {
+ public:
+ static DisplayError Create(HWPrimaryInterface **intf, HWInfoInterface *hw_info_intf,
+ BufferSyncHandler *buffer_sync_handler);
+ static DisplayError Destroy(HWPrimaryInterface *intf);
+ virtual DisplayError SetVSyncState(bool enable) = 0;
+ virtual void SetIdleTimeoutMs(uint32_t timeout_ms) = 0;
+ virtual DisplayError SetDisplayMode(const HWDisplayMode hw_display_mode) = 0;
+ virtual DisplayError SetRefreshRate(uint32_t refresh_rate) = 0;
+
+ protected:
+ virtual ~HWPrimaryInterface() { }
+};
+
+} // namespace sdm
+
+#endif // __HW_PRIMARY_INTERFACE_H__
+
diff --git a/sdm/libs/core/hw_virtual_interface.h b/sdm/libs/core/hw_virtual_interface.h
new file mode 100644
index 0000000..ba14ae6
--- /dev/null
+++ b/sdm/libs/core/hw_virtual_interface.h
@@ -0,0 +1,47 @@
+/*
+* Copyright (c) 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __HW_VIRTUAL_INTERFACE_H__
+#define __HW_VIRTUAL_INTERFACE_H__
+
+#include "hw_interface.h"
+
+namespace sdm {
+
+class HWInfoInterface;
+
+class HWVirtualInterface: virtual public HWInterface {
+ public:
+ static DisplayError Create(HWVirtualInterface **intf, HWInfoInterface *hw_info_intf,
+ BufferSyncHandler *buffer_sync_handler);
+ static DisplayError Destroy(HWVirtualInterface *intf);
+
+ protected:
+ virtual ~HWVirtualInterface() { }
+};
+
+} // namespace sdm
+
+#endif // __HW_VIRTUAL_INTERFACE_H__
+
diff --git a/sdm/libs/core/resource_default.cpp b/sdm/libs/core/resource_default.cpp
new file mode 100644
index 0000000..783b621
--- /dev/null
+++ b/sdm/libs/core/resource_default.cpp
@@ -0,0 +1,912 @@
+/*
+* 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:
+* * 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.
+*/
+
+#include <math.h>
+#include <utils/constants.h>
+#include <utils/debug.h>
+#include <utils/rect.h>
+#include <dlfcn.h>
+
+#include "resource_default.h"
+
+#define __CLASS__ "ResourceDefault"
+
+namespace sdm {
+
+ResourceDefault::ResourceDefault()
+ : num_pipe_(0), vig_pipes_(NULL), rgb_pipes_(NULL), dma_pipes_(NULL) {
+}
+
+DisplayError ResourceDefault::Init(const HWResourceInfo &hw_res_info) {
+ DisplayError error = kErrorNone;
+ uint32_t num_pipe = 0;
+
+ num_pipe = hw_res_info.num_vig_pipe + hw_res_info.num_rgb_pipe + hw_res_info.num_dma_pipe;
+
+ if (num_pipe > kPipeIdMax) {
+ DLOGE("Number of pipe is over the limit! %d", num_pipe);
+ return kErrorParameters;
+ }
+
+ num_pipe_ = num_pipe;
+ hw_res_info_ = hw_res_info;
+ // 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);
+
+ if (hw_res_info_.max_scale_down < 1 || hw_res_info_.max_scale_up < 1) {
+ DLOGE("Max scaling setting is invalid! max_scale_down = %d, max_scale_up = %d",
+ hw_res_info_.max_scale_down, hw_res_info_.max_scale_up);
+ hw_res_info_.max_scale_down = 1;
+ hw_res_info_.max_scale_up = 1;
+ }
+
+ rgb_pipes_[0].owner = kPipeOwnerKernelMode;
+ rgb_pipes_[1].owner = kPipeOwnerKernelMode;
+
+ return error;
+}
+
+DisplayError ResourceDefault::Deinit() {
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::RegisterDisplay(DisplayType type,
+ const HWDisplayAttributes &attributes,
+ const HWPanelInfo &hw_panel_info,
+ Handle *display_ctx) {
+ DisplayError error = kErrorNone;
+
+ HWBlockType hw_block_id = kHWBlockMax;
+ switch (type) {
+ case kPrimary:
+ if (!hw_block_ctx_[kHWPrimary].is_in_use) {
+ hw_block_id = kHWPrimary;
+ }
+ break;
+
+ case kHDMI:
+ if (!hw_block_ctx_[kHWHDMI].is_in_use) {
+ hw_block_id = kHWHDMI;
+ }
+ break;
+
+ default:
+ DLOGW("RegisterDisplay, invalid type %d", type);
+ return kErrorParameters;
+ }
+
+ if (hw_block_id == kHWBlockMax) {
+ return kErrorResources;
+ }
+
+ DisplayResourceContext *display_resource_ctx = new DisplayResourceContext();
+ if (!display_resource_ctx) {
+ return kErrorMemory;
+ }
+
+ hw_block_ctx_[hw_block_id].is_in_use = true;
+
+ display_resource_ctx->display_attributes = attributes;
+ display_resource_ctx->hw_block_id = hw_block_id;
+
+ if (!display_resource_ctx->display_attributes.is_device_split) {
+ display_resource_ctx->display_attributes.split_left = attributes.x_pixels;
+ }
+
+ *display_ctx = display_resource_ctx;
+ return error;
+}
+
+DisplayError ResourceDefault::UnregisterDisplay(Handle display_ctx) {
+ DisplayResourceContext *display_resource_ctx =
+ reinterpret_cast<DisplayResourceContext *>(display_ctx);
+ Purge(display_ctx);
+
+ hw_block_ctx_[display_resource_ctx->hw_block_id].is_in_use = false;
+
+ delete display_resource_ctx;
+
+ return kErrorNone;
+}
+
+void ResourceDefault::ReconfigureDisplay(Handle display_ctx, const HWDisplayAttributes &attributes,
+ const HWPanelInfo &hw_panel_info) {
+ SCOPE_LOCK(locker_);
+
+ DisplayResourceContext *display_resource_ctx =
+ reinterpret_cast<DisplayResourceContext *>(display_ctx);
+
+ display_resource_ctx->display_attributes = attributes;
+}
+
+DisplayError ResourceDefault::Start(Handle display_ctx) {
+ locker_.Lock();
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::Stop(Handle display_ctx) {
+ locker_.Unlock();
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::Acquire(Handle display_ctx, HWLayers *hw_layers) {
+ DisplayResourceContext *display_resource_ctx =
+ reinterpret_cast<DisplayResourceContext *>(display_ctx);
+
+ DisplayError error = kErrorNone;
+ const struct HWLayersInfo &layer_info = hw_layers->info;
+ HWBlockType hw_block_id = display_resource_ctx->hw_block_id;
+
+ DLOGV_IF(kTagResources, "==== Resource reserving start: hw_block = %d ====", hw_block_id);
+
+ if (layer_info.count > 1) {
+ DLOGV_IF(kTagResources, "More than one FB layers");
+ return kErrorResources;
+ }
+
+ Layer &layer = layer_info.stack->layers[layer_info.index[0]];
+
+ if (layer.composition != kCompositionGPUTarget) {
+ DLOGV_IF(kTagResources, "Not an FB layer");
+ return kErrorParameters;
+ }
+
+ error = Config(display_resource_ctx, hw_layers);
+ if (error != kErrorNone) {
+ DLOGV_IF(kTagResources, "Resource config failed");
+ return error;
+ }
+
+ for (uint32_t i = 0; i < num_pipe_; i++) {
+ if (src_pipes_[i].hw_block_id == hw_block_id && src_pipes_[i].owner == kPipeOwnerUserMode) {
+ src_pipes_[i].ResetState();
+ }
+ }
+
+ uint32_t left_index = kPipeIdMax;
+ uint32_t right_index = kPipeIdMax;
+ bool need_scale = false;
+
+ struct HWLayerConfig &layer_config = hw_layers->config[0];
+
+ HWPipeInfo *left_pipe = &layer_config.left_pipe;
+ HWPipeInfo *right_pipe = &layer_config.right_pipe;
+
+ // left pipe is needed
+ if (left_pipe->valid) {
+ need_scale = IsScalingNeeded(left_pipe);
+ left_index = GetPipe(hw_block_id, need_scale);
+ if (left_index >= num_pipe_) {
+ DLOGV_IF(kTagResources, "Get left pipe failed: hw_block_id = %d, need_scale = %d",
+ hw_block_id, need_scale);
+ ResourceStateLog();
+ goto CleanupOnError;
+ }
+ }
+
+ error = SetDecimationFactor(left_pipe);
+ if (error != kErrorNone) {
+ goto CleanupOnError;
+ }
+
+ if (!right_pipe->valid) {
+ // assign single pipe
+ if (left_index < num_pipe_) {
+ left_pipe->pipe_id = src_pipes_[left_index].mdss_pipe_id;
+ }
+ DLOGV_IF(kTagResources, "1 pipe acquired for FB layer, left_pipe = %x", left_pipe->pipe_id);
+ return kErrorNone;
+ }
+
+ need_scale = IsScalingNeeded(right_pipe);
+
+ right_index = GetPipe(hw_block_id, need_scale);
+ if (right_index >= num_pipe_) {
+ DLOGV_IF(kTagResources, "Get right pipe failed: hw_block_id = %d, need_scale = %d", hw_block_id,
+ need_scale);
+ ResourceStateLog();
+ goto CleanupOnError;
+ }
+
+ if (src_pipes_[right_index].priority < src_pipes_[left_index].priority) {
+ // Swap pipe based on priority
+ Swap(left_index, right_index);
+ }
+
+ // assign dual pipes
+ left_pipe->pipe_id = src_pipes_[left_index].mdss_pipe_id;
+ right_pipe->pipe_id = src_pipes_[right_index].mdss_pipe_id;
+
+ error = SetDecimationFactor(right_pipe);
+ if (error != kErrorNone) {
+ goto CleanupOnError;
+ }
+
+ DLOGV_IF(kTagResources, "2 pipes acquired for FB layer, left_pipe = %x, right_pipe = %x",
+ left_pipe->pipe_id, right_pipe->pipe_id);
+
+ return kErrorNone;
+
+CleanupOnError:
+ DLOGV_IF(kTagResources, "Resource reserving failed! hw_block = %d", hw_block_id);
+
+ return kErrorResources;
+}
+
+DisplayError ResourceDefault::PostPrepare(Handle display_ctx, HWLayers *hw_layers) {
+ SCOPE_LOCK(locker_);
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::PostCommit(Handle display_ctx, HWLayers *hw_layers) {
+ SCOPE_LOCK(locker_);
+ DisplayResourceContext *display_resource_ctx =
+ reinterpret_cast<DisplayResourceContext *>(display_ctx);
+ HWBlockType hw_block_id = display_resource_ctx->hw_block_id;
+ uint64_t frame_count = display_resource_ctx->frame_count;
+ DisplayError error = kErrorNone;
+
+ DLOGV_IF(kTagResources, "Resource for hw_block = %d, frame_count = %d", hw_block_id, frame_count);
+
+ // handoff pipes which are used by splash screen
+ if ((frame_count == 0) && (hw_block_id == kHWPrimary)) {
+ for (uint32_t i = 0; i < num_pipe_; i++) {
+ if (src_pipes_[i].hw_block_id == hw_block_id && src_pipes_[i].owner == kPipeOwnerKernelMode) {
+ src_pipes_[i].owner = kPipeOwnerUserMode;
+ }
+ }
+ }
+
+ display_resource_ctx->frame_count++;
+
+ return kErrorNone;
+}
+
+void ResourceDefault::Purge(Handle display_ctx) {
+ SCOPE_LOCK(locker_);
+
+ DisplayResourceContext *display_resource_ctx =
+ reinterpret_cast<DisplayResourceContext *>(display_ctx);
+ HWBlockType hw_block_id = display_resource_ctx->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].owner == kPipeOwnerUserMode) {
+ src_pipes_[i].ResetState();
+ }
+ }
+ DLOGV_IF(kTagResources, "display id = %d", display_resource_ctx->hw_block_id);
+}
+
+DisplayError ResourceDefault::SetMaxMixerStages(Handle display_ctx, uint32_t max_mixer_stages) {
+ SCOPE_LOCK(locker_);
+
+ return kErrorNone;
+}
+
+uint32_t ResourceDefault::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 ResourceDefault::SearchPipe(HWBlockType hw_block_id, SourcePipe *src_pipes,
+ uint32_t num_pipe) {
+ uint32_t index = kPipeIdMax;
+ SourcePipe *src_pipe;
+
+ // search the pipe being used
+ for (uint32_t i = 0; i < num_pipe; i++) {
+ src_pipe = &src_pipes[i];
+ if (src_pipe->owner == kPipeOwnerUserMode && src_pipe->hw_block_id == kHWBlockMax) {
+ index = src_pipe->index;
+ src_pipe->hw_block_id = hw_block_id;
+ break;
+ }
+ }
+
+ return index;
+}
+
+uint32_t ResourceDefault::NextPipe(PipeType type, HWBlockType hw_block_id) {
+ uint32_t num_pipe = 0;
+ SourcePipe *src_pipes = NULL;
+
+ switch (type) {
+ case kPipeTypeVIG:
+ src_pipes = vig_pipes_;
+ num_pipe = hw_res_info_.num_vig_pipe;
+ break;
+ case kPipeTypeRGB:
+ src_pipes = rgb_pipes_;
+ num_pipe = hw_res_info_.num_rgb_pipe;
+ break;
+ case kPipeTypeDMA:
+ default:
+ src_pipes = dma_pipes_;
+ num_pipe = hw_res_info_.num_dma_pipe;
+ break;
+ }
+
+ return SearchPipe(hw_block_id, src_pipes, num_pipe);
+}
+
+uint32_t ResourceDefault::GetPipe(HWBlockType hw_block_id, bool need_scale) {
+ uint32_t index = kPipeIdMax;
+
+ // The default behavior is to assume RGB and VG pipes have scalars
+ if (!need_scale) {
+ index = NextPipe(kPipeTypeDMA, hw_block_id);
+ }
+
+ if ((index >= num_pipe_) && (!need_scale || !hw_res_info_.has_non_scalar_rgb)) {
+ index = NextPipe(kPipeTypeRGB, hw_block_id);
+ }
+
+ if (index >= num_pipe_) {
+ index = NextPipe(kPipeTypeVIG, hw_block_id);
+ }
+
+ return index;
+}
+
+bool ResourceDefault::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));
+}
+
+void ResourceDefault::ResourceStateLog() {
+ DLOGV_IF(kTagResources, "==== resource manager pipe state ====");
+ uint32_t i;
+ for (i = 0; i < num_pipe_; i++) {
+ SourcePipe *src_pipe = &src_pipes_[i];
+ DLOGV_IF(kTagResources, "index = %d, id = %x, hw_block = %d, owner = %s",
+ src_pipe->index, src_pipe->mdss_pipe_id, src_pipe->hw_block_id,
+ (src_pipe->owner == kPipeOwnerUserMode) ? "user mode" : "kernel mode");
+ }
+}
+
+DisplayError ResourceDefault::SrcSplitConfig(DisplayResourceContext *display_resource_ctx,
+ const LayerRect &src_rect, const LayerRect &dst_rect,
+ HWLayerConfig *layer_config) {
+ HWDisplayAttributes &display_attributes = display_resource_ctx->display_attributes;
+ HWPipeInfo *left_pipe = &layer_config->left_pipe;
+ HWPipeInfo *right_pipe = &layer_config->right_pipe;
+ float src_width = src_rect.right - src_rect.left;
+ float dst_width = dst_rect.right - dst_rect.left;
+ float src_height = src_rect.bottom - src_rect.top;
+ float dst_height = dst_rect.bottom - dst_rect.top;
+ float left_mixer_width = FLOAT(display_attributes.split_left);
+
+ // Layer cannot qualify for SrcSplit if source or destination width exceeds max pipe width.
+ // For perf/power optimization, even if "always_src_split" is enabled, use 2 pipes only if:
+ // Source width is greater than split_left (left_mixer_width)
+ if ((src_width > hw_res_info_.max_pipe_width) || (dst_width > hw_res_info_.max_pipe_width) ||
+ (display_resource_ctx->display_attributes.always_src_split && src_width > left_mixer_width)) {
+ SplitRect(src_rect, dst_rect, &left_pipe->src_roi, &left_pipe->dst_roi, &right_pipe->src_roi,
+ &right_pipe->dst_roi);
+ left_pipe->valid = true;
+ right_pipe->valid = true;
+ } else {
+ left_pipe->src_roi = src_rect;
+ left_pipe->dst_roi = dst_rect;
+ left_pipe->valid = true;
+ right_pipe->Reset();
+ }
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::DisplaySplitConfig(DisplayResourceContext *display_resource_ctx,
+ const LayerRect &src_rect, const LayerRect &dst_rect,
+ HWLayerConfig *layer_config) {
+ HWDisplayAttributes &display_attributes = display_resource_ctx->display_attributes;
+
+ // for display split case
+ HWPipeInfo *left_pipe = &layer_config->left_pipe;
+ HWPipeInfo *right_pipe = &layer_config->right_pipe;
+ LayerRect scissor_left, scissor_right, dst_left, crop_left, crop_right, dst_right;
+
+ scissor_left.right = FLOAT(display_attributes.split_left);
+ scissor_left.bottom = FLOAT(display_attributes.y_pixels);
+
+ scissor_right.left = FLOAT(display_attributes.split_left);
+ scissor_right.top = 0.0f;
+ scissor_right.right = FLOAT(display_attributes.x_pixels);
+ scissor_right.bottom = FLOAT(display_attributes.y_pixels);
+
+ crop_left = src_rect;
+ dst_left = dst_rect;
+ crop_right = crop_left;
+ dst_right = dst_left;
+
+ bool crop_left_valid = CalculateCropRects(scissor_left, &crop_left, &dst_left);
+ bool crop_right_valid = false;
+
+ if (IsValid(scissor_right)) {
+ crop_right_valid = CalculateCropRects(scissor_right, &crop_right, &dst_right);
+ }
+
+ // Reset left_pipe and right_pipe to invalid by default
+ left_pipe->Reset();
+ right_pipe->Reset();
+
+ if (crop_left_valid) {
+ // assign left pipe
+ left_pipe->src_roi = crop_left;
+ left_pipe->dst_roi = dst_left;
+ left_pipe->valid = true;
+ }
+
+ // assign right pipe if needed
+ if (crop_right_valid) {
+ right_pipe->src_roi = crop_right;
+ right_pipe->dst_roi = dst_right;
+ right_pipe->valid = true;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::Config(DisplayResourceContext *display_resource_ctx,
+ HWLayers *hw_layers) {
+ HWDisplayAttributes &display_attributes = display_resource_ctx->display_attributes;
+ HWLayersInfo &layer_info = hw_layers->info;
+ DisplayError error = kErrorNone;
+ uint32_t z_order = 0;
+
+ Layer& layer = layer_info.stack->layers[layer_info.index[0]];
+
+ error = ValidateLayerDimensions(layer);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ struct HWLayerConfig *layer_config = &hw_layers->config[0];
+ HWPipeInfo &left_pipe = layer_config->left_pipe;
+ HWPipeInfo &right_pipe = layer_config->right_pipe;
+
+ LayerRect src_rect = layer.src_rect;
+ LayerRect dst_rect = layer.dst_rect;
+
+ error = ValidateDimensions(src_rect, dst_rect);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ error = ValidateScaling(src_rect, dst_rect, false);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ if (hw_res_info_.is_src_split) {
+ error = SrcSplitConfig(display_resource_ctx, src_rect, dst_rect, layer_config);
+ } else {
+ error = DisplaySplitConfig(display_resource_ctx, src_rect, dst_rect, layer_config);
+ }
+
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ error = AlignPipeConfig(layer, &left_pipe, &right_pipe);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ // set z_order, left_pipe should always be valid
+ left_pipe.z_order = 0;
+
+ DLOGV_IF(kTagResources, "==== FB layer Config ====");
+ Log(kTagResources, "input layer src_rect", layer.src_rect);
+ Log(kTagResources, "input layer dst_rect", layer.dst_rect);
+ Log(kTagResources, "cropped src_rect", src_rect);
+ Log(kTagResources, "cropped dst_rect", dst_rect);
+ Log(kTagResources, "left pipe src", layer_config->left_pipe.src_roi);
+ Log(kTagResources, "left pipe dst", layer_config->left_pipe.dst_roi);
+ if (right_pipe.valid) {
+ right_pipe.z_order = 0;
+ Log(kTagResources, "right pipe src", layer_config->right_pipe.src_roi);
+ Log(kTagResources, "right pipe dst", layer_config->right_pipe.dst_roi);
+ }
+
+ return error;
+}
+
+bool ResourceDefault::CalculateCropRects(const LayerRect &scissor, LayerRect *crop,
+ LayerRect *dst) {
+ float &crop_left = crop->left;
+ float &crop_top = crop->top;
+ float &crop_right = crop->right;
+ float &crop_bottom = crop->bottom;
+ float crop_width = crop->right - crop->left;
+ float crop_height = crop->bottom - crop->top;
+
+ float &dst_left = dst->left;
+ float &dst_top = dst->top;
+ float &dst_right = dst->right;
+ float &dst_bottom = dst->bottom;
+ float dst_width = dst->right - dst->left;
+ float dst_height = dst->bottom - dst->top;
+
+ const float &sci_left = scissor.left;
+ const float &sci_top = scissor.top;
+ const float &sci_right = scissor.right;
+ const float &sci_bottom = scissor.bottom;
+
+ float left_cut_ratio = 0.0, right_cut_ratio = 0.0, top_cut_ratio = 0.0, bottom_cut_ratio = 0.0;
+ bool need_cut = false;
+
+ if (dst_left < sci_left) {
+ left_cut_ratio = (sci_left - dst_left) / dst_width;
+ dst_left = sci_left;
+ need_cut = true;
+ }
+
+ if (dst_right > sci_right) {
+ right_cut_ratio = (dst_right - sci_right) / dst_width;
+ dst_right = sci_right;
+ need_cut = true;
+ }
+
+ if (dst_top < sci_top) {
+ top_cut_ratio = (sci_top - dst_top) / (dst_height);
+ dst_top = sci_top;
+ need_cut = true;
+ }
+
+ if (dst_bottom > sci_bottom) {
+ bottom_cut_ratio = (dst_bottom - sci_bottom) / (dst_height);
+ dst_bottom = sci_bottom;
+ need_cut = true;
+ }
+
+ if (!need_cut)
+ return true;
+
+ crop_left += crop_width * left_cut_ratio;
+ crop_top += crop_height * top_cut_ratio;
+ crop_right -= crop_width * right_cut_ratio;
+ crop_bottom -= crop_height * bottom_cut_ratio;
+ Normalize(1, 1, crop);
+ Normalize(1, 1, dst);
+ if (IsValid(*crop) && IsValid(*dst))
+ return true;
+ else
+ return false;
+}
+
+DisplayError ResourceDefault::ValidateLayerDimensions(const Layer &layer) {
+ const LayerRect &src = layer.src_rect;
+ const LayerRect &dst = layer.dst_rect;
+ LayerBuffer *input_buffer = layer.input_buffer;
+
+ if (!IsValid(src) || !IsValid(dst)) {
+ Log(kTagResources, "input layer src_rect", src);
+ Log(kTagResources, "input layer dst_rect", dst);
+ return kErrorNotSupported;
+ }
+
+ // Make sure source in integral only if it is a non secure layer.
+ if (!input_buffer->flags.secure && (src.left - roundf(src.left) || src.top - roundf(src.top) ||
+ src.right - roundf(src.right) || src.bottom - roundf(src.bottom))) {
+ DLOGV_IF(kTagResources, "Input ROI is not integral");
+ return kErrorNotSupported;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::ValidateDimensions(const LayerRect &crop, const LayerRect &dst) {
+ if (!IsValid(crop)) {
+ Log(kTagResources, "Invalid crop rect", crop);
+ return kErrorNotSupported;
+ }
+
+ if (!IsValid(dst)) {
+ Log(kTagResources, "Invalid dst rect", dst);
+ return kErrorNotSupported;
+ }
+
+ float crop_width = crop.right - crop.left;
+ float crop_height = crop.bottom - crop.top;
+ float dst_width = dst.right - dst.left;
+ float dst_height = dst.bottom - dst.top;
+
+ if ((UINT32(crop_width - dst_width) == 1) || (UINT32(crop_height - dst_height) == 1)) {
+ DLOGV_IF(kTagResources, "One pixel downscaling detected crop_w = %.0f, dst_w = %.0f, " \
+ "crop_h = %.0f, dst_h = %.0f", crop_width, dst_width, crop_height, dst_height);
+ return kErrorNotSupported;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::ValidatePipeParams(HWPipeInfo *pipe_info) {
+ DisplayError error = kErrorNone;
+
+ const LayerRect &src_rect = pipe_info->src_roi;
+ const LayerRect &dst_rect = pipe_info->dst_roi;
+
+ error = ValidateDimensions(src_rect, dst_rect);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ error = ValidateScaling(src_rect, dst_rect, false);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::ValidateScaling(const LayerRect &crop, const LayerRect &dst,
+ bool rotate90) {
+ DisplayError error = kErrorNone;
+
+ float scale_x = 1.0f;
+ float scale_y = 1.0f;
+
+ error = GetScaleFactor(crop, dst, &scale_x, &scale_y);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ error = ValidateDownScaling(scale_x, scale_y);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ error = ValidateUpScaling(scale_x, scale_y);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::ValidateDownScaling(float scale_x, float scale_y) {
+ if ((UINT32(scale_x) > 1) || (UINT32(scale_y) > 1)) {
+ float max_scale_down = FLOAT(hw_res_info_.max_scale_down);
+
+ if (hw_res_info_.has_decimation) {
+ max_scale_down *= FLOAT(kMaxDecimationDownScaleRatio);
+ }
+
+ if (scale_x > max_scale_down || scale_y > max_scale_down) {
+ DLOGV_IF(kTagResources,
+ "Scaling down is over the limit: scale_x = %.0f, scale_y = %.0f, " \
+ "has_deci = %d", scale_x, scale_y, hw_res_info_.has_decimation);
+ return kErrorNotSupported;
+ }
+ }
+
+ DLOGV_IF(kTagResources, "scale_x = %.4f, scale_y = %.4f", scale_x, scale_y);
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::ValidateUpScaling(float scale_x, float scale_y) {
+ float max_scale_up = FLOAT(hw_res_info_.max_scale_up);
+
+ if (UINT32(scale_x) < 1 && scale_x > 0.0f) {
+ if ((1.0f / scale_x) > max_scale_up) {
+ DLOGV_IF(kTagResources, "Scaling up is over limit scale_x = %f", 1.0f / scale_x);
+ return kErrorNotSupported;
+ }
+ }
+
+ if (UINT32(scale_y) < 1 && scale_y > 0.0f) {
+ if ((1.0f / scale_y) > max_scale_up) {
+ DLOGV_IF(kTagResources, "Scaling up is over limit scale_y = %f", 1.0f / scale_y);
+ return kErrorNotSupported;
+ }
+ }
+
+ DLOGV_IF(kTagResources, "scale_x = %.4f, scale_y = %.4f", scale_x, scale_y);
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::GetScaleFactor(const LayerRect &crop, const LayerRect &dst,
+ float *scale_x, float *scale_y) {
+ float crop_width = crop.right - crop.left;
+ float crop_height = crop.bottom - crop.top;
+ float dst_width = dst.right - dst.left;
+ float dst_height = dst.bottom - dst.top;
+
+ *scale_x = crop_width / dst_width;
+ *scale_y = crop_height / dst_height;
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::SetDecimationFactor(HWPipeInfo *pipe) {
+ float src_h = pipe->src_roi.bottom - pipe->src_roi.top;
+ float dst_h = pipe->dst_roi.bottom - pipe->dst_roi.top;
+ float down_scale_h = src_h / dst_h;
+
+ float src_w = pipe->src_roi.right - pipe->src_roi.left;
+ float dst_w = pipe->dst_roi.right - pipe->dst_roi.left;
+ float down_scale_w = src_w / dst_w;
+
+ pipe->horizontal_decimation = 0;
+ pipe->vertical_decimation = 0;
+
+ if (CalculateDecimation(down_scale_w, &pipe->horizontal_decimation) != kErrorNone) {
+ return kErrorNotSupported;
+ }
+
+ if (CalculateDecimation(down_scale_h, &pipe->vertical_decimation) != kErrorNone) {
+ return kErrorNotSupported;
+ }
+
+ DLOGI_IF(kTagResources, "horizontal_decimation %d, vertical_decimation %d",
+ pipe->horizontal_decimation, pipe->vertical_decimation);
+
+ return kErrorNone;
+}
+
+void ResourceDefault::SplitRect(const LayerRect &src_rect, const LayerRect &dst_rect,
+ LayerRect *src_left, LayerRect *dst_left, LayerRect *src_right,
+ LayerRect *dst_right) {
+ // Split rectangle horizontally and evenly into two.
+ float src_width = src_rect.right - src_rect.left;
+ float dst_width = dst_rect.right - dst_rect.left;
+ float src_width_ori = src_width;
+ src_width = ROUND_UP_ALIGN_DOWN(src_width / 2, 1);
+ dst_width = ROUND_UP_ALIGN_DOWN(dst_width * src_width / src_width_ori, 1);
+
+ src_left->left = src_rect.left;
+ src_left->right = src_rect.left + src_width;
+ src_right->left = src_left->right;
+ src_right->right = src_rect.right;
+
+ src_left->top = src_rect.top;
+ src_left->bottom = src_rect.bottom;
+ src_right->top = src_rect.top;
+ src_right->bottom = src_rect.bottom;
+
+ dst_left->top = dst_rect.top;
+ dst_left->bottom = dst_rect.bottom;
+ dst_right->top = dst_rect.top;
+ dst_right->bottom = dst_rect.bottom;
+
+ dst_left->left = dst_rect.left;
+ dst_left->right = dst_rect.left + dst_width;
+ dst_right->left = dst_left->right;
+ dst_right->right = dst_rect.right;
+}
+
+DisplayError ResourceDefault::AlignPipeConfig(const Layer &layer, HWPipeInfo *left_pipe,
+ HWPipeInfo *right_pipe) {
+ DisplayError error = kErrorNone;
+ if (!left_pipe->valid) {
+ DLOGE_IF(kTagResources, "left_pipe should not be invalid");
+ return kErrorNotSupported;
+ }
+
+ error = ValidatePipeParams(left_pipe);
+ if (error != kErrorNone) {
+ goto PipeConfigExit;
+ }
+
+ if (right_pipe->valid) {
+ // Make sure the left and right ROI are conjunct
+ right_pipe->src_roi.left = left_pipe->src_roi.right;
+ right_pipe->dst_roi.left = left_pipe->dst_roi.right;
+ error = ValidatePipeParams(right_pipe);
+ }
+
+PipeConfigExit:
+ if (error != kErrorNone) {
+ DLOGV_IF(kTagResources, "AlignPipeConfig failed");
+ }
+ return error;
+}
+
+DisplayError ResourceDefault::CalculateDecimation(float downscale, uint8_t *decimation) {
+ float max_down_scale = FLOAT(hw_res_info_.max_scale_down);
+
+ if (downscale <= max_down_scale) {
+ *decimation = 0;
+ return kErrorNone;
+ } else if (!hw_res_info_.has_decimation) {
+ DLOGE("Downscaling exceeds the maximum MDP downscale limit but decimation not enabled");
+ return kErrorNotSupported;
+ }
+
+ // Decimation is the remaining downscale factor after doing max SDE downscale.
+ // In SDE, decimation is supported in powers of 2.
+ // For ex: If a pipe needs downscale of 8 but max_down_scale is 4
+ // So decimation = powf(2.0, ceilf(log2f(8 / 4))) = powf(2.0, 1.0) = 2
+ *decimation = UINT8(ceilf(log2f(downscale / max_down_scale)));
+ return kErrorNone;
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/core/resource_default.h b/sdm/libs/core/resource_default.h
new file mode 100644
index 0000000..14174d1
--- /dev/null
+++ b/sdm/libs/core/resource_default.h
@@ -0,0 +1,156 @@
+/*
+* 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __RESOURCE_DEFAULT_H__
+#define __RESOURCE_DEFAULT_H__
+
+#include <core/display_interface.h>
+#include <private/resource_interface.h>
+#include <utils/locker.h>
+
+#include "hw_interface.h"
+
+namespace sdm {
+
+class ResourceDefault : public ResourceInterface {
+ public:
+ ResourceDefault();
+ DisplayError Init(const HWResourceInfo &hw_resource_info);
+ DisplayError Deinit();
+ virtual DisplayError RegisterDisplay(DisplayType type, const HWDisplayAttributes &attributes,
+ const HWPanelInfo &hw_panel_info, Handle *display_ctx);
+ virtual DisplayError UnregisterDisplay(Handle display_ctx);
+ virtual void ReconfigureDisplay(Handle display_ctx, const HWDisplayAttributes &attributes,
+ const HWPanelInfo &hw_panel_info);
+ virtual DisplayError Start(Handle display_ctx);
+ virtual DisplayError Stop(Handle display_ctx);
+ virtual DisplayError Acquire(Handle display_ctx, HWLayers *hw_layers);
+ virtual DisplayError PostPrepare(Handle display_ctx, HWLayers *hw_layers);
+ virtual DisplayError PostCommit(Handle display_ctx, HWLayers *hw_layers);
+ virtual void Purge(Handle display_ctx);
+ virtual DisplayError SetMaxMixerStages(Handle display_ctx, uint32_t max_mixer_stages);
+ virtual DisplayError ValidateScaling(const LayerRect &crop, const LayerRect &dst,
+ bool rotate90);
+
+ private:
+ enum PipeId {
+ kPipeIdVIG0,
+ kPipeIdVIG1,
+ kPipeIdVIG2,
+ kPipeIdRGB0,
+ kPipeIdRGB1,
+ kPipeIdRGB2,
+ kPipeIdDMA0,
+ kPipeIdDMA1,
+ kPipeIdVIG3,
+ kPipeIdRGB3,
+ kPipeIdMax,
+ };
+
+ enum PipeType {
+ kPipeTypeUnused,
+ kPipeTypeVIG,
+ kPipeTypeRGB,
+ kPipeTypeDMA,
+ kPipeTypeMax,
+ };
+
+ enum PipeOwner {
+ kPipeOwnerUserMode, // Pipe state when it is available for reservation
+ kPipeOwnerKernelMode, // Pipe state when pipe is owned by kernel
+ };
+
+ // todo: retrieve all these from kernel
+ enum {
+ kMaxDecimationDownScaleRatio = 8,
+ };
+
+ struct SourcePipe {
+ PipeType type;
+ PipeOwner owner;
+ uint32_t mdss_pipe_id;
+ uint32_t index;
+ HWBlockType hw_block_id;
+ int priority;
+
+ SourcePipe() : type(kPipeTypeUnused), owner(kPipeOwnerUserMode), mdss_pipe_id(kPipeIdMax),
+ index(0), hw_block_id(kHWBlockMax), priority(0) { }
+
+ inline void ResetState() { hw_block_id = kHWBlockMax;}
+ };
+
+ struct DisplayResourceContext {
+ HWDisplayAttributes display_attributes;
+ HWBlockType hw_block_id;
+ uint64_t frame_count;
+
+ DisplayResourceContext() : hw_block_id(kHWBlockMax), frame_count(0) { }
+ };
+
+ 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);
+ uint32_t SearchPipe(HWBlockType hw_block_id, SourcePipe *src_pipes, uint32_t num_pipe);
+ uint32_t GetPipe(HWBlockType hw_block_id, bool need_scale);
+ bool IsScalingNeeded(const HWPipeInfo *pipe_info);
+ DisplayError Config(DisplayResourceContext *display_resource_ctx, HWLayers *hw_layers);
+ DisplayError DisplaySplitConfig(DisplayResourceContext *display_resource_ctx,
+ const LayerRect &src_rect, const LayerRect &dst_rect,
+ HWLayerConfig *layer_config);
+ DisplayError SrcSplitConfig(DisplayResourceContext *display_resource_ctx,
+ const LayerRect &src_rect, const LayerRect &dst_rect,
+ HWLayerConfig *layer_config);
+ bool CalculateCropRects(const LayerRect &scissor, LayerRect *crop, LayerRect *dst);
+ DisplayError ValidateLayerDimensions(const Layer &layer);
+ DisplayError ValidateDimensions(const LayerRect &crop, const LayerRect &dst);
+ DisplayError ValidatePipeParams(HWPipeInfo *pipe_info);
+ DisplayError ValidateDownScaling(float scale_x, float scale_y);
+ DisplayError ValidateUpScaling(float scale_x, float scale_y);
+ DisplayError GetScaleFactor(const LayerRect &crop, const LayerRect &dst, float *scale_x,
+ float *scale_y);
+ DisplayError SetDecimationFactor(HWPipeInfo *pipe);
+ void SplitRect(const LayerRect &src_rect, const LayerRect &dst_rect, LayerRect *src_left,
+ LayerRect *dst_left, LayerRect *src_right, LayerRect *dst_right);
+ DisplayError AlignPipeConfig(const Layer &layer, HWPipeInfo *left_pipe, HWPipeInfo *right_pipe);
+ void ResourceStateLog(void);
+ DisplayError CalculateDecimation(float downscale, uint8_t *decimation);
+
+ 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_;
+};
+
+} // namespace sdm
+
+#endif // __RESOURCE_DEFAULT_H__
+
diff --git a/sdm/libs/core/strategy.cpp b/sdm/libs/core/strategy.cpp
new file mode 100644
index 0000000..16e3f63
--- /dev/null
+++ b/sdm/libs/core/strategy.cpp
@@ -0,0 +1,185 @@
+/*
+* 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:
+* * 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.
+*/
+
+#include <utils/constants.h>
+#include <utils/debug.h>
+
+#include "strategy.h"
+
+#define __CLASS__ "Strategy"
+
+namespace sdm {
+
+Strategy::Strategy(ExtensionInterface *extension_intf, DisplayType type,
+ const HWResourceInfo &hw_resource_info, const HWPanelInfo &hw_panel_info)
+ : extension_intf_(extension_intf), strategy_intf_(NULL), partial_update_intf_(NULL),
+ display_type_(type),hw_resource_info_(hw_resource_info), hw_panel_info_(hw_panel_info),
+ hw_layers_info_(NULL), fb_layer_index_(0), extn_start_success_(false), tried_default_(false) {
+}
+
+DisplayError Strategy::Init() {
+ DisplayError error = kErrorNone;
+
+ if (extension_intf_) {
+ error = extension_intf_->CreateStrategyExtn(display_type_, &strategy_intf_);
+ if (error != kErrorNone) {
+ DLOGE("Failed to create strategy");
+ return error;
+ }
+
+ error = extension_intf_->CreatePartialUpdate(display_type_, hw_resource_info_,
+ hw_panel_info_, &partial_update_intf_);
+ if (error != kErrorNone) {
+ DLOGW("Partial Update creation failed, Continue without partial update.");
+ }
+ }
+
+ return kErrorNone;
+}
+
+DisplayError Strategy::Deinit() {
+ if (strategy_intf_) {
+ if (partial_update_intf_) {
+ extension_intf_->DestroyPartialUpdate(partial_update_intf_);
+ }
+
+ extension_intf_->DestroyStrategyExtn(strategy_intf_);
+ }
+
+ return kErrorNone;
+}
+
+DisplayError Strategy::Start(HWLayersInfo *hw_layers_info, uint32_t *max_attempts) {
+ DisplayError error = kErrorNone;
+
+ hw_layers_info_ = hw_layers_info;
+ extn_start_success_ = false;
+ tried_default_ = false;
+
+ uint32_t i = 0;
+ LayerStack *layer_stack = hw_layers_info_->stack;
+ for (; i < layer_stack->layer_count; i++) {
+ if (layer_stack->layers[i].composition == kCompositionGPUTarget) {
+ fb_layer_index_ = i;
+ break;
+ }
+ }
+
+ if (i == layer_stack->layer_count) {
+ return kErrorUndefined;
+ }
+
+ GenerateROI();
+
+ if (strategy_intf_) {
+ error = strategy_intf_->Start(hw_layers_info_, max_attempts);
+ if (error == kErrorNone) {
+ extn_start_success_ = true;
+ return kErrorNone;
+ }
+ }
+
+ *max_attempts = 1;
+
+ return kErrorNone;
+}
+
+DisplayError Strategy::Stop() {
+ if (extn_start_success_) {
+ return strategy_intf_->Stop();
+ }
+
+ return kErrorNone;
+}
+
+DisplayError Strategy::GetNextStrategy(StrategyConstraints *constraints) {
+ DisplayError error = kErrorNone;
+
+ if (extn_start_success_) {
+ error = strategy_intf_->GetNextStrategy(constraints);
+ if (error == kErrorNone) {
+ return kErrorNone;
+ }
+ }
+
+ // Default composition is already tried.
+ if (tried_default_) {
+ return kErrorUndefined;
+ }
+
+ // Mark all layers for GPU composition. Find GPU target buffer and store its index for
+ // programming the hardware.
+ LayerStack *layer_stack = hw_layers_info_->stack;
+ uint32_t &hw_layer_count = hw_layers_info_->count;
+ hw_layer_count = 0;
+ for (uint32_t i = 0; i < layer_stack->layer_count; i++) {
+ LayerComposition &composition = layer_stack->layers[i].composition;
+ if (composition == kCompositionGPUTarget) {
+ hw_layers_info_->index[hw_layer_count++] = i;
+ } else {
+ composition = kCompositionGPU;
+ }
+ }
+
+ tried_default_ = true;
+
+ // There can be one and only one GPU target buffer.
+ if (hw_layer_count != 1) {
+ return kErrorParameters;
+ }
+
+ return kErrorNone;
+}
+
+void Strategy::GenerateROI() {
+ bool split_display = false;
+
+ if (partial_update_intf_ && partial_update_intf_->GenerateROI(hw_layers_info_) == kErrorNone) {
+ return;
+ }
+
+ LayerStack *layer_stack = hw_layers_info_->stack;
+ LayerRect &src_rect = layer_stack->layers[fb_layer_index_].src_rect;
+ // TODO(user): read panels x_pixels and y_pixels instead of fb_x_res and fb_y_res
+ float fb_x_res = src_rect.right - src_rect.left;
+ float fb_y_res = src_rect.bottom - src_rect.top;
+
+ if (!hw_resource_info_.is_src_split &&
+ ((fb_x_res > hw_resource_info_.max_mixer_width) ||
+ ((display_type_ == kPrimary) && hw_panel_info_.split_info.right_split))) {
+ split_display = true;
+ }
+
+ if (split_display) {
+ float left_split = FLOAT(hw_panel_info_.split_info.left_split);
+ hw_layers_info_->left_partial_update = (LayerRect) {0.0f, 0.0f, left_split, fb_y_res};
+ hw_layers_info_->right_partial_update = (LayerRect) {left_split, 0.0f, fb_x_res, fb_y_res};
+ } else {
+ hw_layers_info_->left_partial_update = (LayerRect) {0.0f, 0.0f, fb_x_res, fb_y_res};
+ hw_layers_info_->right_partial_update = (LayerRect) {0.0f, 0.0f, 0.0f, 0.0f};
+ }
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/core/strategy.h b/sdm/libs/core/strategy.h
new file mode 100644
index 0000000..c7a67d9
--- /dev/null
+++ b/sdm/libs/core/strategy.h
@@ -0,0 +1,63 @@
+/*
+* 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __STRATEGY_H__
+#define __STRATEGY_H__
+
+#include <core/display_interface.h>
+#include <private/extension_interface.h>
+
+namespace sdm {
+
+class Strategy {
+ public:
+ Strategy(ExtensionInterface *extension_intf, DisplayType type,
+ const HWResourceInfo &hw_resource_info, const HWPanelInfo &hw_panel_info);
+
+ DisplayError Init();
+ DisplayError Deinit();
+
+ DisplayError Start(HWLayersInfo *hw_layers_info, uint32_t *max_attempts);
+ DisplayError GetNextStrategy(StrategyConstraints *constraints);
+ DisplayError Stop();
+
+ private:
+ void GenerateROI();
+
+ ExtensionInterface *extension_intf_;
+ StrategyInterface *strategy_intf_;
+ PartialUpdateInterface *partial_update_intf_;
+ DisplayType display_type_;
+ HWResourceInfo hw_resource_info_;
+ HWPanelInfo hw_panel_info_;
+ HWLayersInfo *hw_layers_info_;
+ uint32_t fb_layer_index_;
+ bool extn_start_success_;
+ bool tried_default_;
+};
+
+} // namespace sdm
+
+#endif // __STRATEGY_H__
+
diff --git a/sdm/libs/hwc/Android.mk b/sdm/libs/hwc/Android.mk
new file mode 100644
index 0000000..f233557
--- /dev/null
+++ b/sdm/libs/hwc/Android.mk
@@ -0,0 +1,31 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := hwcomposer.$(TARGET_BOARD_PLATFORM)
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := hardware/qcom/display/sdm/include/ \
+ hardware/qcom/display/libgralloc/ \
+ hardware/qcom/display/libqservice/ \
+ hardware/qcom/display/libqdutils/
+LOCAL_CFLAGS := -Wno-missing-field-initializers -Wno-unused-parameter \
+ -Wconversion -Wall -Werror \
+ -DLOG_TAG=\"SDM\"
+
+# TODO: Move this to the common makefile
+ifeq ($(call is-board-platform-in-list, $(MASTER_SIDE_CP_TARGET_LIST)), true)
+ LOCAL_CFLAGS += -DMASTER_SIDE_CP
+endif
+
+LOCAL_SHARED_LIBRARIES := libsdmcore libqservice libbinder libhardware libhardware_legacy \
+ libutils libcutils libsync libmemalloc libqdutils
+LOCAL_SRC_FILES := hwc_session.cpp \
+ hwc_display.cpp \
+ hwc_display_primary.cpp \
+ hwc_display_external.cpp \
+ hwc_display_virtual.cpp \
+ hwc_debugger.cpp \
+ hwc_buffer_allocator.cpp \
+ hwc_buffer_sync_handler.cpp
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/sdm/libs/hwc/hwc_buffer_allocator.cpp b/sdm/libs/hwc/hwc_buffer_allocator.cpp
new file mode 100644
index 0000000..2d79f0d
--- /dev/null
+++ b/sdm/libs/hwc/hwc_buffer_allocator.cpp
@@ -0,0 +1,187 @@
+/*
+* Copyright (c) 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:
+* * 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.
+*/
+
+#include <gralloc_priv.h>
+#include <memalloc.h>
+#include <gr.h>
+#include <alloc_controller.h>
+#include <utils/constants.h>
+#include <core/buffer_allocator.h>
+
+#include "hwc_debugger.h"
+#include "hwc_buffer_allocator.h"
+
+#define __CLASS__ "HWCBufferAllocator"
+
+namespace sdm {
+
+HWCBufferAllocator::HWCBufferAllocator() {
+ alloc_controller_ = gralloc::IAllocController::getInstance();
+}
+
+DisplayError HWCBufferAllocator::AllocateBuffer(BufferInfo *buffer_info) {
+ gralloc::alloc_data data;
+
+ const BufferConfig &buffer_config = buffer_info->buffer_config;
+ AllocatedBufferInfo *alloc_buffer_info = &buffer_info->alloc_buffer_info;
+ MetaBufferInfo *meta_buffer_info = new MetaBufferInfo();
+
+ if (!meta_buffer_info) {
+ return kErrorMemory;
+ }
+
+ int alloc_flags = GRALLOC_USAGE_PRIVATE_IOMMU_HEAP;
+ int error = 0;
+
+ int width = INT(buffer_config.width);
+ int height = INT(buffer_config.height);
+ int format;
+
+ if (buffer_config.secure) {
+ alloc_flags = GRALLOC_USAGE_PRIVATE_MM_HEAP;
+ alloc_flags |= GRALLOC_USAGE_PROTECTED;
+ data.align = SECURE_ALIGN;
+ } else {
+ data.align = getpagesize();
+ }
+
+ if (buffer_config.cache == false) {
+ // Allocate uncached buffers
+ alloc_flags |= GRALLOC_USAGE_PRIVATE_UNCACHED;
+ }
+
+ error = SetBufferInfo(buffer_config.format, &format, &alloc_flags);
+ if (error != 0) {
+ return kErrorParameters;
+ }
+
+ int aligned_width = 0, aligned_height = 0;
+ uint32_t buffer_size = getBufferSizeAndDimensions(width, height, format, alloc_flags,
+ aligned_width, aligned_height);
+
+ buffer_size = ROUND_UP(buffer_size, data.align) * buffer_config.buffer_count;
+
+ data.base = 0;
+ data.fd = -1;
+ data.offset = 0;
+ data.size = buffer_size;
+ data.uncached = !buffer_config.cache;
+
+ error = alloc_controller_->allocate(data, alloc_flags);
+ if (error != 0) {
+ DLOGE("Error allocating memory size %d uncached %d", data.size, data.uncached);
+ return kErrorMemory;
+ }
+
+ alloc_buffer_info->fd = data.fd;
+ alloc_buffer_info->stride = aligned_width;
+ alloc_buffer_info->size = buffer_size;
+
+ meta_buffer_info->base_addr = data.base;
+ meta_buffer_info->alloc_type = data.allocType;
+
+ buffer_info->private_data = meta_buffer_info;
+
+ return kErrorNone;
+}
+
+DisplayError HWCBufferAllocator::FreeBuffer(BufferInfo *buffer_info) {
+ int ret = 0;
+
+ AllocatedBufferInfo *alloc_buffer_info = &buffer_info->alloc_buffer_info;
+ MetaBufferInfo *meta_buffer_info = static_cast<MetaBufferInfo *> (buffer_info->private_data);
+ if (alloc_buffer_info->fd < 0) {
+ DLOGE("Invalid parameters: fd %d", alloc_buffer_info->fd);
+ return kErrorParameters;
+ }
+
+ gralloc::IMemAlloc *memalloc = alloc_controller_->getAllocator(meta_buffer_info->alloc_type);
+ if (memalloc == NULL) {
+ DLOGE("Memalloc handle is NULL, alloc type %d", meta_buffer_info->alloc_type);
+ return kErrorResources;
+ }
+
+ ret = memalloc->free_buffer(meta_buffer_info->base_addr, alloc_buffer_info->size, 0,
+ alloc_buffer_info->fd);
+ if (ret != 0) {
+ DLOGE("Error freeing buffer base_addr %p size %d fd %d", meta_buffer_info->base_addr,
+ alloc_buffer_info->size, alloc_buffer_info->fd);
+ return kErrorMemory;
+ }
+
+ alloc_buffer_info->fd = -1;
+ alloc_buffer_info->stride = 0;
+ alloc_buffer_info->size = 0;
+
+ meta_buffer_info->base_addr = NULL;
+ meta_buffer_info->alloc_type = 0;
+
+ delete meta_buffer_info;
+ meta_buffer_info = NULL;
+
+ return kErrorNone;
+}
+
+int HWCBufferAllocator::SetBufferInfo(LayerBufferFormat format, int *target, int *flags) {
+ switch (format) {
+ case kFormatRGBA8888: *target = HAL_PIXEL_FORMAT_RGBA_8888; break;
+ case kFormatRGBX8888: *target = HAL_PIXEL_FORMAT_RGBX_8888; break;
+ case kFormatRGB888: *target = HAL_PIXEL_FORMAT_RGB_888; break;
+ case kFormatRGB565: *target = HAL_PIXEL_FORMAT_RGB_565; break;
+ case kFormatBGRA8888: *target = HAL_PIXEL_FORMAT_BGRA_8888; break;
+ case kFormatYCrCb420Planar: *target = HAL_PIXEL_FORMAT_YV12; break;
+ case kFormatYCrCb420SemiPlanar: *target = HAL_PIXEL_FORMAT_YCrCb_420_SP; break;
+ case kFormatYCbCr420SemiPlanar: *target = HAL_PIXEL_FORMAT_YCbCr_420_SP; break;
+ case kFormatYCbCr422H2V1Packed: *target = HAL_PIXEL_FORMAT_YCbCr_422_I; break;
+ case kFormatYCbCr422H2V1SemiPlanar: *target = HAL_PIXEL_FORMAT_YCbCr_422_SP; break;
+ case kFormatYCbCr420SemiPlanarVenus: *target = HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS; break;
+ case kFormatYCbCr420SPVenusUbwc: *target = HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC; break;
+ case kFormatRGBA5551: *target = HAL_PIXEL_FORMAT_RGBA_5551; break;
+ case kFormatRGBA4444: *target = HAL_PIXEL_FORMAT_RGBA_4444; break;
+ case kFormatRGBA8888Ubwc:
+ *target = HAL_PIXEL_FORMAT_RGBA_8888;
+ *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC;
+ break;
+ case kFormatRGBX8888Ubwc:
+ *target = HAL_PIXEL_FORMAT_RGBX_8888;
+ *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC;
+ break;
+ case kFormatRGB565Ubwc:
+ *target = HAL_PIXEL_FORMAT_RGB_565;
+ *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC;
+ break;
+ default:
+ DLOGE("Unsupported format = 0x%x", format);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+} // namespace sdm
diff --git a/sdm/libs/hwc/hwc_buffer_allocator.h b/sdm/libs/hwc/hwc_buffer_allocator.h
new file mode 100644
index 0000000..b3f8add
--- /dev/null
+++ b/sdm/libs/hwc/hwc_buffer_allocator.h
@@ -0,0 +1,65 @@
+/*
+* Copyright (c) 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:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __HWC_BUFFER_ALLOCATOR_H__
+#define __HWC_BUFFER_ALLOCATOR_H__
+
+#include <sys/mman.h>
+#include <fcntl.h>
+
+namespace gralloc {
+
+class IAllocController;
+
+} // namespace gralloc
+
+namespace sdm {
+
+class HWCBufferAllocator : public BufferAllocator {
+ public:
+ HWCBufferAllocator();
+
+ DisplayError AllocateBuffer(BufferInfo *buffer_info);
+ DisplayError FreeBuffer(BufferInfo *buffer_info);
+
+ private:
+ struct MetaBufferInfo {
+ int alloc_type; //!< Specifies allocation type set by the buffer allocator.
+ void *base_addr; //!< Specifies the base address of the allocated output buffer.
+ };
+
+ int SetBufferInfo(LayerBufferFormat format, int *target, int *flags);
+
+ gralloc::IAllocController *alloc_controller_;
+};
+
+} // namespace sdm
+#endif // __HWC_BUFFER_ALLOCATOR_H__
+
diff --git a/sdm/libs/hwc/hwc_buffer_sync_handler.cpp b/sdm/libs/hwc/hwc_buffer_sync_handler.cpp
new file mode 100644
index 0000000..9bc4ec9
--- /dev/null
+++ b/sdm/libs/hwc/hwc_buffer_sync_handler.cpp
@@ -0,0 +1,71 @@
+/*
+* Copyright (c) 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:
+* * 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.
+*/
+
+#include <sync/sync.h>
+#include <utils/constants.h>
+
+#include "hwc_debugger.h"
+#include "hwc_buffer_sync_handler.h"
+
+#define __CLASS__ "HWCBufferSyncHandler"
+
+namespace sdm {
+
+DisplayError HWCBufferSyncHandler::SyncWait(int fd) {
+ int error = 0;
+
+ if (fd >= 0) {
+ error = sync_wait(fd, 1000);
+ if (error < 0) {
+ DLOGE("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
+ close(fd);
+ return kErrorTimeOut;
+ }
+ close(fd);
+ }
+
+ return kErrorNone;
+}
+
+DisplayError HWCBufferSyncHandler::SyncMerge(int fd1, int fd2, int *merged_fd) {
+ DisplayError error = kErrorNone;
+
+ *merged_fd = sync_merge("SyncMerge", fd1, fd2);
+ if (*merged_fd == -1) {
+ DLOGE(" Sync merge error! fd1 %d fd2 %d", fd1, fd2);
+ error = kErrorFileDescriptor;
+ }
+ close(fd1);
+ close(fd2);
+
+ return error;
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/hwc/hwc_buffer_sync_handler.h b/sdm/libs/hwc/hwc_buffer_sync_handler.h
new file mode 100644
index 0000000..da94650
--- /dev/null
+++ b/sdm/libs/hwc/hwc_buffer_sync_handler.h
@@ -0,0 +1,52 @@
+/*
+* Copyright (c) 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:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __HWC_BUFFER_SYNC_HANDLER_H__
+#define __HWC_BUFFER_SYNC_HANDLER_H__
+
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <core/sdm_types.h>
+#include <core/buffer_sync_handler.h>
+
+namespace sdm {
+
+class HWCBufferSyncHandler : public BufferSyncHandler {
+ public:
+ HWCBufferSyncHandler() { }
+
+ virtual DisplayError SyncWait(int fd);
+ virtual DisplayError SyncMerge(int fd1, int fd2, int *merged_fd);
+};
+
+} // namespace sdm
+#endif // __HWC_BUFFER_SYNC_HANDLER_H__
+
+
diff --git a/sdm/libs/hwc/hwc_debugger.cpp b/sdm/libs/hwc/hwc_debugger.cpp
new file mode 100644
index 0000000..ab9309e
--- /dev/null
+++ b/sdm/libs/hwc/hwc_debugger.cpp
@@ -0,0 +1,127 @@
+/*
+* 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:
+* * 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.
+*/
+
+#include <utils/constants.h>
+
+#include "hwc_debugger.h"
+
+namespace sdm {
+
+HWCDebugHandler HWCDebugHandler::debug_handler_;
+uint32_t HWCDebugHandler::debug_flags_ = 0x1;
+
+void HWCDebugHandler::DebugAll(bool enable) {
+ if (enable) {
+ debug_flags_ = 0xFFFFFFFF;
+ } else {
+ debug_flags_ = 0x1; // kTagNone should always be printed.
+ }
+}
+
+void HWCDebugHandler::DebugResources(bool enable) {
+ if (enable) {
+ SET_BIT(debug_flags_, kTagResources);
+ } else {
+ CLEAR_BIT(debug_flags_, kTagResources);
+ }
+}
+
+void HWCDebugHandler::DebugStrategy(bool enable) {
+ if (enable) {
+ SET_BIT(debug_flags_, kTagStrategy);
+ } else {
+ CLEAR_BIT(debug_flags_, kTagStrategy);
+ }
+}
+
+void HWCDebugHandler::DebugCompManager(bool enable) {
+ if (enable) {
+ SET_BIT(debug_flags_, kTagCompManager);
+ } else {
+ CLEAR_BIT(debug_flags_, kTagCompManager);
+ }
+}
+
+void HWCDebugHandler::DebugDriverConfig(bool enable) {
+ if (enable) {
+ SET_BIT(debug_flags_, kTagDriverConfig);
+ } else {
+ CLEAR_BIT(debug_flags_, kTagDriverConfig);
+ }
+}
+
+void HWCDebugHandler::DebugRotator(bool enable) {
+ if (enable) {
+ SET_BIT(debug_flags_, kTagRotator);
+ } else {
+ CLEAR_BIT(debug_flags_, kTagRotator);
+ }
+}
+
+void HWCDebugHandler::Error(DebugTag /*tag*/, const char *format, ...) {
+ va_list list;
+ va_start(list, format);
+ __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, list);
+}
+
+void HWCDebugHandler::Warning(DebugTag /*tag*/, const char *format, ...) {
+ va_list list;
+ va_start(list, format);
+ __android_log_vprint(ANDROID_LOG_WARN, LOG_TAG, format, list);
+}
+
+void HWCDebugHandler::Info(DebugTag tag, const char *format, ...) {
+ if (IS_BIT_SET(debug_flags_, tag)) {
+ va_list list;
+ va_start(list, format);
+ __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, list);
+ }
+}
+
+void HWCDebugHandler::Verbose(DebugTag tag, const char *format, ...) {
+ if (IS_BIT_SET(debug_flags_, tag)) {
+ va_list list;
+ va_start(list, format);
+ __android_log_vprint(ANDROID_LOG_VERBOSE, LOG_TAG, format, list);
+ }
+}
+
+void HWCDebugHandler::BeginTrace(const char *class_name, const char *function_name,
+ const char *custom_string) {
+ char name[PATH_MAX] = {0};
+ snprintf(name, sizeof(name), "%s::%s::%s", class_name, function_name, custom_string);
+ atrace_begin(ATRACE_TAG, name);
+}
+
+void HWCDebugHandler::EndTrace() {
+ atrace_end(ATRACE_TAG);
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/hwc/hwc_debugger.h b/sdm/libs/hwc/hwc_debugger.h
new file mode 100644
index 0000000..61a1b6f
--- /dev/null
+++ b/sdm/libs/hwc/hwc_debugger.h
@@ -0,0 +1,80 @@
+/*
+* 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:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __HWC_DEBUGGER_H__
+#define __HWC_DEBUGGER_H__
+
+#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
+
+#include <core/sdm_types.h>
+#include <core/debug_interface.h>
+#include <cutils/log.h>
+#include <utils/Trace.h>
+
+#define DLOG(Macro, format, ...) Macro(__CLASS__ "::%s: " format, __FUNCTION__, ##__VA_ARGS__)
+
+#define DLOGE(format, ...) DLOG(ALOGE, format, ##__VA_ARGS__)
+#define DLOGW(format, ...) DLOG(ALOGW, format, ##__VA_ARGS__)
+#define DLOGI(format, ...) DLOG(ALOGI, format, ##__VA_ARGS__)
+#define DLOGV(format, ...) DLOG(ALOGV, format, ##__VA_ARGS__)
+
+#define DTRACE_BEGIN(custom_string) HWCDebugHandler::Get()->BeginTrace(__CLASS__, __FUNCTION__, \
+ custom_string)
+#define DTRACE_END() HWCDebugHandler::Get()->EndTrace()
+#define DTRACE_SCOPED() ScopeTracer<HWCDebugHandler> scope_tracer(__CLASS__, __FUNCTION__)
+
+namespace sdm {
+
+class HWCDebugHandler : public DebugHandler {
+ public:
+ static inline DebugHandler* Get() { return &debug_handler_; }
+ static void DebugAll(bool enable);
+ static void DebugResources(bool enable);
+ static void DebugStrategy(bool enable);
+ static void DebugCompManager(bool enable);
+ static void DebugDriverConfig(bool enable);
+ static void DebugRotator(bool enable);
+
+ virtual void Error(DebugTag tag, const char *format, ...);
+ virtual void Warning(DebugTag tag, const char *format, ...);
+ virtual void Info(DebugTag tag, const char *format, ...);
+ virtual void Verbose(DebugTag tag, const char *format, ...);
+ virtual void BeginTrace(const char *class_name, const char *function_name,
+ const char *custom_string);
+ virtual void EndTrace();
+
+ private:
+ static HWCDebugHandler debug_handler_;
+ static uint32_t debug_flags_;
+};
+
+} // namespace sdm
+
+#endif // __HWC_DEBUGGER_H__
+
diff --git a/sdm/libs/hwc/hwc_display.cpp b/sdm/libs/hwc/hwc_display.cpp
new file mode 100644
index 0000000..0278c90
--- /dev/null
+++ b/sdm/libs/hwc/hwc_display.cpp
@@ -0,0 +1,1008 @@
+/*
+* 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:
+* * 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.
+*/
+
+#include <math.h>
+#include <errno.h>
+#include <gralloc_priv.h>
+#include <utils/constants.h>
+#include <qdMetaData.h>
+#include <sync/sync.h>
+#include <cutils/properties.h>
+
+#include "hwc_display.h"
+#include "hwc_debugger.h"
+
+#define __CLASS__ "HWCDisplay"
+
+namespace sdm {
+
+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), dump_frame_count_(0), dump_frame_index_(0),
+ dump_input_layers_(false), swap_interval_zero_(false), framebuffer_config_(NULL),
+ display_paused_(false), use_metadata_refresh_rate_(false), metadata_refresh_rate_(0) {
+}
+
+int HWCDisplay::Init() {
+ DisplayError error = core_intf_->CreateDisplay(type_, this, &display_intf_);
+ if (error != kErrorNone) {
+ DLOGE("Display create failed. Error = %d display_type %d event_handler %p disp_intf %p",
+ error, type_, this, &display_intf_);
+ return -EINVAL;
+ }
+
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get("debug.egl.swapinterval", property, "1") > 0) {
+ if (atoi(property) == 0) {
+ swap_interval_zero_ = true;
+ }
+ }
+
+ framebuffer_config_ = new DisplayConfigVariableInfo();
+ if (!framebuffer_config_) {
+ DLOGV("Failed to allocate memory for custom framebuffer config.");
+ core_intf_->DestroyDisplay(display_intf_);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int HWCDisplay::Deinit() {
+ DisplayError error = core_intf_->DestroyDisplay(display_intf_);
+ if (error != kErrorNone) {
+ DLOGE("Display destroy failed. Error = %d", error);
+ return -EINVAL;
+ }
+
+ if (layer_stack_memory_.raw) {
+ delete[] layer_stack_memory_.raw;
+ layer_stack_memory_.raw = NULL;
+ }
+
+ delete framebuffer_config_;
+
+ return 0;
+}
+
+int HWCDisplay::EventControl(int event, int enable) {
+ DisplayError error = kErrorNone;
+
+ switch (event) {
+ case HWC_EVENT_VSYNC:
+ error = display_intf_->SetVSyncState(enable);
+ break;
+ case HWC_EVENT_ORIENTATION:
+ // TODO(user): Need to handle this case
+ break;
+ default:
+ DLOGW("Unsupported event = %d", event);
+ }
+
+ if (error != kErrorNone) {
+ DLOGE("Failed. event = %d, enable = %d, error = %d", event, enable, error);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int HWCDisplay::SetPowerMode(int mode) {
+ DLOGI("display = %d, mode = %d", id_, mode);
+ DisplayState state = kStateOff;
+
+ switch (mode) {
+ case HWC_POWER_MODE_OFF:
+ state = kStateOff;
+ break;
+ case HWC_POWER_MODE_NORMAL:
+ state = kStateOn;
+ last_power_mode_ = HWC_POWER_MODE_NORMAL;
+ break;
+ case HWC_POWER_MODE_DOZE:
+ state = kStateDoze;
+ last_power_mode_ = HWC_POWER_MODE_DOZE;
+ break;
+ case HWC_POWER_MODE_DOZE_SUSPEND:
+ state = kStateDozeSuspend;
+ last_power_mode_ = HWC_POWER_MODE_DOZE_SUSPEND;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ DisplayError error = display_intf_->SetDisplayState(state);
+ if (error != kErrorNone) {
+ DLOGE("Set state failed. Error = %d", error);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int HWCDisplay::GetDisplayConfigs(uint32_t *configs, size_t *num_configs) {
+ if (*num_configs > 0) {
+ configs[0] = 0;
+ *num_configs = 1;
+ }
+
+ return 0;
+}
+
+int HWCDisplay::GetDisplayAttributes(uint32_t config, const uint32_t *attributes, int32_t *values) {
+ DisplayError error = kErrorNone;
+
+ DisplayConfigVariableInfo variable_config;
+ uint32_t active_config = UINT32(GetActiveConfig());
+ if (IsFrameBufferScaled() && config == active_config) {
+ variable_config = *framebuffer_config_;
+ } else {
+ error = display_intf_->GetConfig(config, &variable_config);
+ if (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;
+ case HWC_DISPLAY_SECURE:
+ values[i] = INT32(true); // For backward compatibility. All Physical displays are secure
+ break;
+ default:
+ DLOGW("Spurious attribute type = %d", attributes[i]);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+int HWCDisplay::GetActiveConfig() {
+ DisplayError error = kErrorNone;
+ uint32_t index = 0;
+
+ error = display_intf_->GetActiveConfig(&index);
+ if (error != kErrorNone) {
+ DLOGE("GetActiveConfig failed. Error = %d", error);
+ return -1;
+ }
+
+ return index;
+}
+
+int HWCDisplay::SetActiveConfig(hwc_display_contents_1_t *content_list) {
+ return 0;
+}
+
+int HWCDisplay::SetActiveConfig(int index) {
+ DisplayError error = kErrorNone;
+
+ error = display_intf_->SetActiveConfig(index);
+ if (error != kErrorNone) {
+ DLOGE("SetActiveConfig failed. Error = %d", error);
+ return -1;
+ }
+
+ 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_);
+}
+
+uint32_t HWCDisplay::GetLastPowerMode() {
+ return last_power_mode_;
+}
+
+DisplayError HWCDisplay::VSync(const DisplayEventVSync &vsync) {
+ if (*hwc_procs_) {
+ (*hwc_procs_)->vsync(*hwc_procs_, id_, vsync.timestamp);
+ }
+
+ return kErrorNone;
+}
+
+DisplayError HWCDisplay::Refresh() {
+ if (*hwc_procs_) {
+ (*hwc_procs_)->invalidate(*hwc_procs_);
+ }
+
+ return kErrorNone;
+}
+
+int HWCDisplay::AllocateLayerStack(hwc_display_contents_1_t *content_list) {
+ if (!content_list || !content_list->numHwLayers) {
+ DLOGW("Invalid content list");
+ return -EINVAL;
+ }
+
+ 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 (layer_stack_memory_.size < required_size) {
+ if (layer_stack_memory_.raw) {
+ delete[] layer_stack_memory_.raw;
+ layer_stack_memory_.size = 0;
+ }
+
+ // Allocate in multiple of kSizeSteps.
+ required_size = ROUND_UP(required_size, layer_stack_memory_.kSizeSteps);
+
+ layer_stack_memory_.raw = new uint8_t[required_size];
+ if (!layer_stack_memory_.raw) {
+ return -ENOMEM;
+ }
+
+ layer_stack_memory_.size = required_size;
+ }
+
+ // Assign memory addresses now.
+ uint8_t *current_address = layer_stack_memory_.raw;
+
+ // Layer array address
+ layer_stack_ = LayerStack();
+ layer_stack_.layers = reinterpret_cast<Layer *>(current_address);
+ layer_stack_.layer_count = static_cast<uint32_t>(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[i];
+ layer = Layer();
+
+ // Layer buffer handle address
+ layer.input_buffer = reinterpret_cast<LayerBuffer *>(current_address);
+ *layer.input_buffer = LayerBuffer();
+ current_address += sizeof(LayerBuffer);
+
+ // Visible rectangle address
+ layer.visible_regions.rect = reinterpret_cast<LayerRect *>(current_address);
+ layer.visible_regions.count = static_cast<uint32_t>(hwc_layer.visibleRegionScreen.numRects);
+ for (size_t i = 0; i < layer.visible_regions.count; i++) {
+ *layer.visible_regions.rect = LayerRect();
+ }
+ 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;
+ *layer.dirty_regions.rect = LayerRect();
+ current_address += sizeof(LayerRect);
+ }
+
+ return 0;
+}
+
+int HWCDisplay::PrepareLayerStack(hwc_display_contents_1_t *content_list) {
+ if (!content_list || !content_list->numHwLayers) {
+ DLOGW("Invalid content list");
+ return -EINVAL;
+ }
+
+ size_t num_hw_layers = content_list->numHwLayers;
+ if (num_hw_layers <= 1) {
+ flush_ = true;
+ return 0;
+ }
+
+ DisplayConfigVariableInfo active_config;
+ uint32_t active_config_index = 0;
+ display_intf_->GetActiveConfig(&active_config_index);
+
+ display_intf_->GetConfig(active_config_index, &active_config);
+
+ // 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[i];
+ LayerBuffer *layer_buffer = layer.input_buffer;
+
+ if (pvt_handle) {
+ layer_buffer->format = GetSDMFormat(pvt_handle->format, pvt_handle->flags);
+ if (layer_buffer->format == kFormatInvalid) {
+ return -EINVAL;
+ }
+
+ layer_buffer->width = pvt_handle->width;
+ layer_buffer->height = pvt_handle->height;
+ if (pvt_handle->bufferType == BUFFER_TYPE_VIDEO) {
+ layer_stack_.flags.video_present = true;
+ layer_buffer->flags.video = true;
+ }
+ if (pvt_handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
+ layer_stack_.flags.secure_present = true;
+ layer_buffer->flags.secure = true;
+ }
+
+ layer.frame_rate = UINT32(active_config.fps);
+ MetaData_t *meta_data = reinterpret_cast<MetaData_t *>(pvt_handle->base_metadata);
+ if (meta_data && meta_data->operation & UPDATE_REFRESH_RATE) {
+ layer.frame_rate = RoundToStandardFPS(meta_data->refreshrate);
+ }
+
+ if (meta_data && meta_data->operation == PP_PARAM_INTERLACED && meta_data->interlaced) {
+ layer_buffer->flags.interlace = true;
+ }
+
+ if (pvt_handle->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY) {
+ layer_buffer->flags.secure_display = true;
+ }
+ }
+
+ hwc_rect_t scaled_display_frame = hwc_layer.displayFrame;
+ ScaleDisplayFrame(&scaled_display_frame);
+ ApplyScanAdjustment(&scaled_display_frame);
+
+ SetRect(scaled_display_frame, &layer.dst_rect);
+ SetRect(hwc_layer.sourceCropf, &layer.src_rect);
+ for (size_t j = 0; j < hwc_layer.visibleRegionScreen.numRects; j++) {
+ SetRect(hwc_layer.visibleRegionScreen.rects[j], &layer.visible_regions.rect[j]);
+ }
+ SetRect(hwc_layer.dirtyRect, &layer.dirty_regions.rect[0]);
+ SetComposition(hwc_layer.compositionType, &layer.composition);
+ SetBlending(hwc_layer.blending, &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);
+ layer.flags.updating = (layer_stack_cache_.layer_cache[i].handle != hwc_layer.handle);
+
+ if (hwc_layer.flags & HWC_SCREENSHOT_ANIMATOR_LAYER) {
+ layer_stack_.flags.animating = true;
+ }
+
+ if (layer.flags.skip) {
+ layer_stack_.flags.skip_present = true;
+ }
+ }
+
+ // Configure layer stack
+ layer_stack_.flags.geometry_changed = ((content_list->flags & HWC_GEOMETRY_CHANGED) > 0);
+
+ DisplayError error = display_intf_->Prepare(&layer_stack_);
+ if (error != kErrorNone) {
+ DLOGE("Prepare failed. Error = %d", error);
+
+ // To prevent surfaceflinger infinite wait, flush the previous frame during Commit() so that
+ // previous buffer and fences are released, and override the error.
+ flush_ = true;
+
+ return 0;
+ }
+
+ bool needs_fb_refresh = NeedsFrameBufferRefresh(content_list);
+
+ metadata_refresh_rate_ = 0;
+
+ 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[i];
+ LayerComposition composition = layer.composition;
+
+ if (composition == kCompositionSDE) {
+ hwc_layer.hints |= HWC_HINT_CLEAR_FB;
+
+ if (use_metadata_refresh_rate_ && layer.frame_rate > metadata_refresh_rate_) {
+ metadata_refresh_rate_ = layer.frame_rate;
+ }
+ }
+
+ // If current layer does not need frame buffer redraw, then mark it as HWC_OVERLAY
+ if (!needs_fb_refresh && (composition != kCompositionGPUTarget)) {
+ composition = kCompositionSDE;
+ }
+
+ SetComposition(composition, &hwc_layer.compositionType);
+ }
+
+ // Cache the current layer stack information like layer_count, composition type and layer handle
+ // for the future.
+ CacheLayerStackInfo(content_list);
+
+ return 0;
+}
+
+int HWCDisplay::CommitLayerStack(hwc_display_contents_1_t *content_list) {
+ if (!content_list || !content_list->numHwLayers) {
+ DLOGW("Invalid content list");
+ return -EINVAL;
+ }
+
+ int status = 0;
+
+ 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];
+ const private_handle_t *pvt_handle = static_cast<const private_handle_t *>(hwc_layer.handle);
+ LayerBuffer *layer_buffer = layer_stack_.layers[i].input_buffer;
+
+ if (pvt_handle) {
+ layer_buffer->planes[0].fd = pvt_handle->fd;
+ layer_buffer->planes[0].offset = pvt_handle->offset;
+ layer_buffer->planes[0].stride = pvt_handle->width;
+ }
+
+ // if swapinterval property is set to 0 then close and reset the acquireFd
+ if (swap_interval_zero_ && hwc_layer.acquireFenceFd >= 0) {
+ close(hwc_layer.acquireFenceFd);
+ hwc_layer.acquireFenceFd = -1;
+ }
+ layer_buffer->acquire_fence_fd = hwc_layer.acquireFenceFd;
+ }
+
+ DisplayError error = display_intf_->Commit(&layer_stack_);
+ if (error != kErrorNone) {
+ DLOGE("Commit failed. Error = %d", error);
+
+ // To prevent surfaceflinger infinite wait, flush the previous frame during Commit() so that
+ // previous buffer and fences are released, and override the error.
+ flush_ = true;
+ }
+ }
+
+ 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);
+ }
+ }
+
+ 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[i];
+ LayerBuffer *layer_buffer = layer_stack_.layers[i].input_buffer;
+
+ if (!flush_) {
+ // if swapinterval property is set to 0 then do not update f/w release fences with driver
+ // values
+ if (swap_interval_zero_) {
+ hwc_layer.releaseFenceFd = -1;
+ close(layer_buffer->release_fence_fd);
+ layer_buffer->release_fence_fd = -1;
+ }
+
+ if (layer.composition != kCompositionGPU) {
+ hwc_layer.releaseFenceFd = layer_buffer->release_fence_fd;
+ }
+
+ // During animation on external/virtual display, SDM will use the cached
+ // framebuffer layer throughout animation and do not allow framework to do eglswapbuffer on
+ // framebuffer target. So graphics doesn't close the release fence fd of framebuffer target,
+ // Hence close the release fencefd of framebuffer target here.
+ if (layer.composition == kCompositionGPUTarget && layer_stack_cache_.animating) {
+ close(hwc_layer.releaseFenceFd);
+ hwc_layer.releaseFenceFd = -1;
+ }
+ }
+
+ if (hwc_layer.acquireFenceFd >= 0) {
+ close(hwc_layer.acquireFenceFd);
+ hwc_layer.acquireFenceFd = -1;
+ }
+ }
+
+
+ if (!flush_) {
+ layer_stack_cache_.animating = layer_stack_.flags.animating;
+
+ // if swapinterval property is set to 0 then close and reset the list retire fence
+ if (swap_interval_zero_) {
+ close(layer_stack_.retire_fence_fd);
+ layer_stack_.retire_fence_fd = -1;
+ }
+ 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;
+
+ // Frame buffer needs to be refreshed for the following reasons:
+ // 1. Any layer is marked skip in the current layer stack.
+ // 2. Any layer is added/removed/layer properties changes in the current layer stack.
+ // 3. Any layer handle is changed and it is marked for GPU composition
+ // 4. Any layer's current composition is different from previous composition.
+ if (((layer_stack_cache_.layer_count != layer_count) || layer_stack_.flags.skip_present ||
+ layer_stack_.flags.geometry_changed) && !layer_stack_cache_.animating) {
+ return true;
+ }
+
+ for (uint32_t i = 0; i < layer_count; i++) {
+ hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
+ Layer &layer = layer_stack_.layers[i];
+ LayerCache &layer_cache = layer_stack_cache_.layer_cache[i];
+
+ if (layer.composition == kCompositionGPUTarget) {
+ continue;
+ }
+
+ if (layer_cache.composition != layer.composition) {
+ return true;
+ }
+
+ if ((layer.composition == kCompositionGPU) && (layer_cache.handle != hwc_layer.handle) &&
+ !layer_stack_cache_.animating) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void HWCDisplay::CacheLayerStackInfo(hwc_display_contents_1_t *content_list) {
+ uint32_t layer_count = layer_stack_.layer_count;
+
+ for (uint32_t i = 0; i < layer_count; i++) {
+ Layer &layer = layer_stack_.layers[i];
+
+ if (layer.composition == kCompositionGPUTarget) {
+ continue;
+ }
+
+ layer_stack_cache_.layer_cache[i].handle = content_list->hwLayers[i].handle;
+ layer_stack_cache_.layer_cache[i].composition = layer.composition;
+ }
+
+ layer_stack_cache_.layer_count = layer_count;
+}
+
+void HWCDisplay::SetRect(const hwc_rect_t &source, LayerRect *target) {
+ target->left = FLOAT(source.left);
+ target->top = FLOAT(source.top);
+ target->right = FLOAT(source.right);
+ target->bottom = FLOAT(source.bottom);
+}
+
+void HWCDisplay::SetRect(const hwc_frect_t &source, LayerRect *target) {
+ target->left = floorf(source.left);
+ target->top = floorf(source.top);
+ target->right = ceilf(source.right);
+ target->bottom = ceilf(source.bottom);
+}
+
+void HWCDisplay::SetComposition(const int32_t &source, LayerComposition *target) {
+ switch (source) {
+ case HWC_FRAMEBUFFER_TARGET: *target = kCompositionGPUTarget; break;
+ default: *target = kCompositionSDE; break;
+ }
+}
+
+void HWCDisplay::SetComposition(const int32_t &source, int32_t *target) {
+ switch (source) {
+ case kCompositionGPUTarget: *target = HWC_FRAMEBUFFER_TARGET; break;
+ case kCompositionSDE: *target = HWC_OVERLAY; break;
+ default: *target = HWC_FRAMEBUFFER; break;
+ }
+}
+
+void HWCDisplay::SetBlending(const int32_t &source, LayerBlending *target) {
+ switch (source) {
+ case HWC_BLENDING_PREMULT: *target = kBlendingPremultiplied; break;
+ case HWC_BLENDING_COVERAGE: *target = kBlendingCoverage; break;
+ default: *target = kBlendingOpaque; break;
+ }
+}
+
+void HWCDisplay::SetIdleTimeoutMs(uint32_t timeout_ms) {
+ if (display_intf_) {
+ display_intf_->SetIdleTimeoutMs(timeout_ms);
+ }
+}
+
+DisplayError HWCDisplay::SetMaxMixerStages(uint32_t max_mixer_stages) {
+ DisplayError error = kErrorNone;
+
+ if (display_intf_) {
+ error = display_intf_->SetMaxMixerStages(max_mixer_stages);
+ }
+
+ return error;
+}
+
+LayerBufferFormat HWCDisplay::GetSDMFormat(const int32_t &source, const int flags) {
+ LayerBufferFormat format = kFormatInvalid;
+ if (flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) {
+ switch (source) {
+ case HAL_PIXEL_FORMAT_RGBA_8888: format = kFormatRGBA8888Ubwc; break;
+ case HAL_PIXEL_FORMAT_RGBX_8888: format = kFormatRGBX8888Ubwc; break;
+ case HAL_PIXEL_FORMAT_RGB_565: format = kFormatRGB565Ubwc; break;
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC:
+ case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: format = kFormatYCbCr420SPVenusUbwc; break;
+ default:
+ DLOGE("Unsupported format type for UBWC %d", source);
+ return kFormatInvalid;
+ }
+ return format;
+ }
+
+ switch (source) {
+ case HAL_PIXEL_FORMAT_RGBA_8888: format = kFormatRGBA8888; break;
+ case HAL_PIXEL_FORMAT_RGBA_5551: format = kFormatRGBA5551; break;
+ case HAL_PIXEL_FORMAT_RGBA_4444: format = kFormatRGBA4444; break;
+ case HAL_PIXEL_FORMAT_BGRA_8888: format = kFormatBGRA8888; break;
+ case HAL_PIXEL_FORMAT_RGBX_8888: format = kFormatRGBX8888; break;
+ case HAL_PIXEL_FORMAT_BGRX_8888: format = kFormatBGRX8888; break;
+ case HAL_PIXEL_FORMAT_RGB_888: format = kFormatRGB888; break;
+ case HAL_PIXEL_FORMAT_RGB_565: format = kFormatRGB565; break;
+ case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: format = kFormatYCbCr420SemiPlanarVenus; break;
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC: format = kFormatYCbCr420SPVenusUbwc; break;
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP: format = kFormatYCrCb420SemiPlanar; break;
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP: format = kFormatYCbCr422H2V1SemiPlanar; break;
+ case HAL_PIXEL_FORMAT_YCbCr_422_I: format = kFormatYCbCr422H2V1Packed; break;
+ default:
+ DLOGW("Unsupported format type = %d", source);
+ return kFormatInvalid;
+ }
+
+ 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";
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC:
+ return "YCbCr_420_SP_VENUS_UBWC";
+ 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";
+ }
+}
+
+int HWCDisplay::SetFrameBufferResolution(uint32_t x_pixels, uint32_t y_pixels) {
+ if (x_pixels <= 0 || y_pixels <= 0) {
+ DLOGV("Unsupported config: x_pixels=%d, y_pixels=%d", x_pixels, y_pixels);
+ return -EINVAL;
+ }
+
+ if (framebuffer_config_->x_pixels == x_pixels && framebuffer_config_->y_pixels == y_pixels) {
+ return 0;
+ }
+
+ DisplayConfigVariableInfo active_config;
+ int active_config_index = GetActiveConfig();
+ DisplayError error = display_intf_->GetConfig(active_config_index, &active_config);
+ if (error != kErrorNone) {
+ DLOGV("GetConfig variable info failed. Error = %d", error);
+ return -EINVAL;
+ }
+
+ if (active_config.x_pixels <= 0 || active_config.y_pixels <= 0) {
+ DLOGV("Invalid panel resolution (%dx%d)", active_config.x_pixels, active_config.y_pixels);
+ return -EINVAL;
+ }
+
+ // Create rects to represent the new source and destination crops
+ LayerRect crop = LayerRect(0, 0, FLOAT(x_pixels), FLOAT(y_pixels));
+ LayerRect dst = LayerRect(0, 0, FLOAT(active_config.x_pixels), FLOAT(active_config.y_pixels));
+ // Set rotate90 to false since this is taken care of during regular composition.
+ bool rotate90 = false;
+ error = display_intf_->IsScalingValid(crop, dst, rotate90);
+ if (error != kErrorNone) {
+ DLOGV("Unsupported resolution: (%dx%d)", x_pixels, y_pixels);
+ return -EINVAL;
+ }
+
+ uint32_t panel_width =
+ UINT32((FLOAT(active_config.x_pixels) * 25.4f) / FLOAT(active_config.x_dpi));
+ uint32_t panel_height =
+ UINT32((FLOAT(active_config.y_pixels) * 25.4f) / FLOAT(active_config.y_dpi));
+ framebuffer_config_->x_pixels = x_pixels;
+ framebuffer_config_->y_pixels = y_pixels;
+ framebuffer_config_->vsync_period_ns = active_config.vsync_period_ns;
+ framebuffer_config_->x_dpi =
+ (FLOAT(framebuffer_config_->x_pixels) * 25.4f) / FLOAT(panel_width);
+ framebuffer_config_->y_dpi =
+ (FLOAT(framebuffer_config_->y_pixels) * 25.4f) / FLOAT(panel_height);
+
+ DLOGI("New framebuffer resolution (%dx%d)", framebuffer_config_->x_pixels,
+ framebuffer_config_->y_pixels);
+
+ return 0;
+}
+
+void HWCDisplay::GetFrameBufferResolution(uint32_t *x_pixels, uint32_t *y_pixels) {
+ *x_pixels = framebuffer_config_->x_pixels;
+ *y_pixels = framebuffer_config_->y_pixels;
+}
+
+void HWCDisplay::ScaleDisplayFrame(hwc_rect_t *display_frame) {
+ if (!IsFrameBufferScaled()) {
+ return;
+ }
+
+ int active_config_index = GetActiveConfig();
+ DisplayConfigVariableInfo active_config;
+ DisplayError error = display_intf_->GetConfig(active_config_index, &active_config);
+ if (error != kErrorNone) {
+ DLOGE("GetConfig variable info failed. Error = %d", error);
+ return;
+ }
+
+ float custom_x_pixels = FLOAT(framebuffer_config_->x_pixels);
+ float custom_y_pixels = FLOAT(framebuffer_config_->y_pixels);
+ float active_x_pixels = FLOAT(active_config.x_pixels);
+ float active_y_pixels = FLOAT(active_config.y_pixels);
+ float x_pixels_ratio = active_x_pixels / custom_x_pixels;
+ float y_pixels_ratio = active_y_pixels / custom_y_pixels;
+ float layer_width = FLOAT(display_frame->right - display_frame->left);
+ float layer_height = FLOAT(display_frame->bottom - display_frame->top);
+
+ display_frame->left = INT(x_pixels_ratio * FLOAT(display_frame->left));
+ display_frame->top = INT(y_pixels_ratio * FLOAT(display_frame->top));
+ display_frame->right = INT(FLOAT(display_frame->left) + layer_width * x_pixels_ratio);
+ display_frame->bottom = INT(FLOAT(display_frame->top) + layer_height * y_pixels_ratio);
+}
+
+bool HWCDisplay::IsFrameBufferScaled() {
+ if (framebuffer_config_->x_pixels == 0 || framebuffer_config_->y_pixels == 0) {
+ return false;
+ }
+ uint32_t panel_x_pixels = 0;
+ uint32_t panel_y_pixels = 0;
+ GetPanelResolution(&panel_x_pixels, &panel_y_pixels);
+ return (framebuffer_config_->x_pixels != panel_x_pixels) ||
+ (framebuffer_config_->y_pixels != panel_y_pixels);
+}
+
+void HWCDisplay::GetPanelResolution(uint32_t *x_pixels, uint32_t *y_pixels) {
+ DisplayConfigVariableInfo active_config;
+ int active_config_index = GetActiveConfig();
+ DisplayError error = display_intf_->GetConfig(active_config_index, &active_config);
+ if (error != kErrorNone) {
+ DLOGE("GetConfig variable info failed. Error = %d", error);
+ return;
+ }
+ *x_pixels = active_config.x_pixels;
+ *y_pixels = active_config.y_pixels;
+}
+
+int HWCDisplay::SetDisplayStatus(uint32_t display_status) {
+ int status = 0;
+
+ switch (display_status) {
+ case kDisplayStatusResume:
+ display_paused_ = false;
+ case kDisplayStatusOnline:
+ status = SetPowerMode(HWC_POWER_MODE_NORMAL);
+ break;
+ case kDisplayStatusPause:
+ display_paused_ = true;
+ case kDisplayStatusOffline:
+ status = SetPowerMode(HWC_POWER_MODE_OFF);
+ break;
+ default:
+ DLOGW("Invalid display status %d", display_status);
+ return -EINVAL;
+ }
+
+ return status;
+}
+
+void HWCDisplay::MarkLayersForGPUBypass(hwc_display_contents_1_t *content_list) {
+ for (size_t i = 0 ; i < (content_list->numHwLayers - 1); i++) {
+ hwc_layer_1_t *layer = &content_list->hwLayers[i];
+ layer->compositionType = HWC_OVERLAY;
+ }
+}
+
+void HWCDisplay::CloseAcquireFences(hwc_display_contents_1_t *content_list) {
+ for (size_t i = 0; i < content_list->numHwLayers; i++) {
+ if (content_list->hwLayers[i].acquireFenceFd >= 0) {
+ close(content_list->hwLayers[i].acquireFenceFd);
+ content_list->hwLayers[i].acquireFenceFd = -1;
+ }
+ }
+}
+
+uint32_t HWCDisplay::RoundToStandardFPS(uint32_t fps) {
+ static const uint32_t standard_fps[4] = {30, 24, 48, 60};
+
+ int count = INT(sizeof(standard_fps) / sizeof(standard_fps[0]));
+ for (int i = 0; i < count; i++) {
+ if (abs(standard_fps[i] - fps) < 2) {
+ // Most likely used for video, the fps can fluctuate
+ // Ex: b/w 29 and 30 for 30 fps clip
+ return standard_fps[i];
+ }
+ }
+
+ return fps;
+}
+
+void HWCDisplay::ApplyScanAdjustment(hwc_rect_t *display_frame) {
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/hwc/hwc_display.h b/sdm/libs/hwc/hwc_display.h
new file mode 100644
index 0000000..2df0928
--- /dev/null
+++ b/sdm/libs/hwc/hwc_display.h
@@ -0,0 +1,149 @@
+/*
+* 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __HWC_DISPLAY_H__
+#define __HWC_DISPLAY_H__
+
+#include <hardware/hwcomposer.h>
+#include <core/core_interface.h>
+
+namespace sdm {
+
+class HWCDisplay : public DisplayEventHandler {
+ public:
+ virtual int Init();
+ 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 SetPowerMode(int mode);
+ virtual int GetDisplayConfigs(uint32_t *configs, size_t *num_configs);
+ virtual int GetDisplayAttributes(uint32_t config, const uint32_t *attributes, int32_t *values);
+ virtual int GetActiveConfig();
+ virtual int SetActiveConfig(int index);
+ virtual int SetActiveConfig(hwc_display_contents_1_t *content_list);
+ virtual void SetIdleTimeoutMs(uint32_t timeout_ms);
+ virtual void SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type);
+ virtual DisplayError SetMaxMixerStages(uint32_t max_mixer_stages);
+ virtual uint32_t GetLastPowerMode();
+ virtual int SetFrameBufferResolution(uint32_t x_pixels, uint32_t y_pixels);
+ virtual void GetFrameBufferResolution(uint32_t *x_pixels, uint32_t *y_pixels);
+ virtual void GetPanelResolution(uint32_t *x_pixels, uint32_t *y_pixels);
+ virtual int SetDisplayStatus(uint32_t display_status);
+
+ protected:
+ enum DisplayStatus {
+ kDisplayStatusOffline = 0,
+ kDisplayStatusOnline,
+ kDisplayStatusPause,
+ kDisplayStatusResume,
+ };
+
+ // Maximum number of layers supported by display manager.
+ static const uint32_t kMaxLayerCount = 32;
+
+ // Structure to track memory allocation for layer stack (layers, rectangles) object.
+ struct LayerStackMemory {
+ static const size_t kSizeSteps = 1024; // Default memory allocation.
+ uint8_t *raw; // Pointer to byte array.
+ size_t size; // Current number of allocated bytes.
+
+ LayerStackMemory() : raw(NULL), size(0) { }
+ };
+
+ struct LayerCache {
+ buffer_handle_t handle;
+ LayerComposition composition;
+
+ LayerCache() : handle(NULL), composition(kCompositionGPU) { }
+ };
+
+ struct LayerStackCache {
+ LayerCache layer_cache[kMaxLayerCount];
+ uint32_t layer_count;
+ bool animating;
+
+ LayerStackCache() : layer_count(0), animating(false) { }
+ };
+
+ HWCDisplay(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, DisplayType type, int id);
+ virtual ~HWCDisplay() { }
+
+ // DisplayEventHandler methods
+ virtual DisplayError VSync(const DisplayEventVSync &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);
+ 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);
+ inline void SetRect(const hwc_frect_t &source, LayerRect *target);
+ inline void SetComposition(const int32_t &source, LayerComposition *target);
+ inline void SetComposition(const int32_t &source, int32_t *target);
+ inline void SetBlending(const int32_t &source, LayerBlending *target);
+ int SetFormat(const int32_t &source, const int flags, LayerBufferFormat *target);
+ LayerBufferFormat GetSDMFormat(const int32_t &source, const int flags);
+ void DumpInputBuffers(hwc_display_contents_1_t *content_list);
+ const char *GetHALPixelFormatString(int format);
+ const char *GetDisplayString();
+ void ScaleDisplayFrame(hwc_rect_t *display_frame);
+ bool IsFrameBufferScaled();
+ void MarkLayersForGPUBypass(hwc_display_contents_1_t *content_list);
+ void CloseAcquireFences(hwc_display_contents_1_t *content_list);
+ uint32_t RoundToStandardFPS(uint32_t fps);
+ virtual void ApplyScanAdjustment(hwc_rect_t *display_frame);
+
+ enum {
+ INPUT_LAYER_DUMP,
+ OUTPUT_LAYER_DUMP,
+ };
+
+ CoreInterface *core_intf_;
+ hwc_procs_t const **hwc_procs_;
+ DisplayType type_;
+ int id_;
+ DisplayInterface *display_intf_;
+ LayerStackMemory layer_stack_memory_;
+ LayerStack layer_stack_;
+ LayerStackCache layer_stack_cache_;
+ bool flush_;
+ LayerBuffer *output_buffer_;
+ uint32_t dump_frame_count_;
+ uint32_t dump_frame_index_;
+ bool dump_input_layers_;
+ uint32_t last_power_mode_;
+ bool swap_interval_zero_;
+ DisplayConfigVariableInfo *framebuffer_config_;
+ bool display_paused_;
+ bool use_metadata_refresh_rate_;
+ uint32_t metadata_refresh_rate_;
+};
+
+} // namespace sdm
+
+#endif // __HWC_DISPLAY_H__
+
diff --git a/sdm/libs/hwc/hwc_display_external.cpp b/sdm/libs/hwc/hwc_display_external.cpp
new file mode 100644
index 0000000..52c64d1
--- /dev/null
+++ b/sdm/libs/hwc/hwc_display_external.cpp
@@ -0,0 +1,141 @@
+/*
+* 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:
+* * 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.
+*/
+
+#include <cutils/properties.h>
+#include <utils/constants.h>
+
+#include "hwc_display_external.h"
+#include "hwc_debugger.h"
+
+#define __CLASS__ "HWCDisplayExternal"
+
+namespace sdm {
+
+HWCDisplayExternal::HWCDisplayExternal(CoreInterface *core_intf, hwc_procs_t const **hwc_procs)
+ : HWCDisplay(core_intf, hwc_procs, kHDMI, HWC_DISPLAY_EXTERNAL) {
+}
+
+int HWCDisplayExternal::Init() {
+ int status = 0;
+
+ status = HWCDisplay::Init();
+ if (status != 0) {
+ return status;
+ }
+
+ return status;
+}
+
+int HWCDisplayExternal::Prepare(hwc_display_contents_1_t *content_list) {
+ int status = 0;
+
+ status = AllocateLayerStack(content_list);
+ if (status) {
+ return status;
+ }
+
+ status = PrepareLayerStack(content_list);
+ if (status) {
+ return status;
+ }
+
+ return 0;
+}
+
+int HWCDisplayExternal::Commit(hwc_display_contents_1_t *content_list) {
+ int status = 0;
+
+ status = HWCDisplay::CommitLayerStack(content_list);
+ if (status) {
+ return status;
+ }
+
+ status = HWCDisplay::PostCommitLayerStack(content_list);
+ if (status) {
+ return status;
+ }
+
+ return 0;
+}
+
+int HWCDisplayExternal::GetDisplayConfigs(uint32_t *configs, size_t *num_configs) {
+ uint32_t config_count = 0;
+ if (*num_configs <= 0) {
+ return -EINVAL;
+ }
+
+ display_intf_->GetNumVariableInfoConfigs(&config_count);
+ *num_configs = static_cast<size_t>(config_count);
+ if (*num_configs <= 0) {
+ return -EINVAL;
+ }
+
+ for (uint32_t i = 0; i < config_count; i++) {
+ configs[i] = i;
+ }
+
+ return 0;
+}
+
+void HWCDisplayExternal::ApplyScanAdjustment(hwc_rect_t *display_frame) {
+ if (display_intf_->IsUnderscanSupported()) {
+ return;
+ }
+
+ // Read user defined width and height ratio
+ char property[PROPERTY_VALUE_MAX];
+ property_get("persist.sys.actionsafe.width", property, "0");
+ float width_ratio = FLOAT(atoi(property)) / 100.0f;
+ property_get("persist.sys.actionsafe.height", property, "0");
+ float height_ratio = FLOAT(atoi(property)) / 100.0f;
+
+ if (width_ratio == 0.0f || height_ratio == 0.0f) {
+ return;
+ }
+
+ uint32_t panel_width = 0;
+ uint32_t panel_height = 0;
+ GetPanelResolution(&panel_width, &panel_height);
+
+ if (panel_width == 0 || panel_height == 0) {
+ DLOGV("Invalid panel dimensions (%d, %d)", panel_width, panel_height);
+ return;
+ }
+
+ int x_offset = INT((FLOAT(panel_width) * width_ratio) / 2.0f);
+ int y_offset = INT((FLOAT(panel_height) * height_ratio) / 2.0f);
+
+ display_frame->left = display_frame->left + x_offset;
+ display_frame->top = display_frame->top + y_offset;
+ display_frame->right = display_frame->right - x_offset;
+ display_frame->bottom = display_frame->bottom - y_offset;
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/hwc/hwc_display_external.h b/sdm/libs/hwc/hwc_display_external.h
new file mode 100644
index 0000000..6d3e229
--- /dev/null
+++ b/sdm/libs/hwc/hwc_display_external.h
@@ -0,0 +1,46 @@
+/*
+* 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.
+*/
+
+#ifndef __HWC_DISPLAY_EXTERNAL_H__
+#define __HWC_DISPLAY_EXTERNAL_H__
+
+#include "hwc_display.h"
+
+namespace sdm {
+
+class HWCDisplayExternal : public HWCDisplay {
+ public:
+ explicit HWCDisplayExternal(CoreInterface *core_intf, hwc_procs_t const **hwc_procs);
+ virtual int Init();
+ virtual int Prepare(hwc_display_contents_1_t *content_list);
+ virtual int Commit(hwc_display_contents_1_t *content_list);
+ virtual int GetDisplayConfigs(uint32_t *configs, size_t *num_configs);
+ private:
+ virtual void ApplyScanAdjustment(hwc_rect_t *display_frame);
+};
+
+} // namespace sdm
+
+#endif // __HWC_DISPLAY_EXTERNAL_H__
+
diff --git a/sdm/libs/hwc/hwc_display_primary.cpp b/sdm/libs/hwc/hwc_display_primary.cpp
new file mode 100644
index 0000000..53110ca
--- /dev/null
+++ b/sdm/libs/hwc/hwc_display_primary.cpp
@@ -0,0 +1,114 @@
+/*
+* 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:
+* * 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.
+*/
+
+#include <utils/constants.h>
+
+#include "hwc_display_primary.h"
+#include "hwc_debugger.h"
+
+#define __CLASS__ "HWCDisplayPrimary"
+
+namespace sdm {
+
+HWCDisplayPrimary::HWCDisplayPrimary(CoreInterface *core_intf, hwc_procs_t const **hwc_procs)
+ : HWCDisplay(core_intf, hwc_procs, kPrimary, HWC_DISPLAY_PRIMARY) {
+}
+
+int HWCDisplayPrimary::Prepare(hwc_display_contents_1_t *content_list) {
+ int status = 0;
+
+ status = AllocateLayerStack(content_list);
+ if (status) {
+ return status;
+ }
+
+ status = PrepareLayerStack(content_list);
+ if (status) {
+ return status;
+ }
+
+ if (use_metadata_refresh_rate_) {
+ SetRefreshRate(metadata_refresh_rate_);
+ }
+
+ return 0;
+}
+
+int HWCDisplayPrimary::Commit(hwc_display_contents_1_t *content_list) {
+ int status = 0;
+
+ status = HWCDisplay::CommitLayerStack(content_list);
+ if (status) {
+ return status;
+ }
+
+ status = HWCDisplay::PostCommitLayerStack(content_list);
+ if (status) {
+ return status;
+ }
+
+ return 0;
+}
+
+DisplayError HWCDisplayPrimary::SetDisplayMode(uint32_t mode) {
+ DisplayError error = kErrorNone;
+
+ if (display_intf_) {
+ error = display_intf_->SetDisplayMode(mode);
+ }
+
+ return error;
+}
+
+int HWCDisplayPrimary::SetActiveConfig(uint32_t index) {
+ DisplayError error = kErrorNone;
+
+ if (display_intf_) {
+ error = display_intf_->SetActiveConfig(index);
+ }
+
+ return error;
+}
+
+int HWCDisplayPrimary::SetRefreshRate(uint32_t refresh_rate) {
+ DisplayError error = kErrorNone;
+
+ if (display_intf_) {
+ error = display_intf_->SetRefreshRate(refresh_rate);
+ }
+
+ return error;
+}
+
+void HWCDisplayPrimary::SetMetaDataRefreshRateFlag(bool enable) {
+ use_metadata_refresh_rate_ = enable;
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/hwc/hwc_display_primary.h b/sdm/libs/hwc/hwc_display_primary.h
new file mode 100644
index 0000000..e862508
--- /dev/null
+++ b/sdm/libs/hwc/hwc_display_primary.h
@@ -0,0 +1,46 @@
+/*
+* 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.
+*/
+
+#ifndef __HWC_DISPLAY_PRIMARY_H__
+#define __HWC_DISPLAY_PRIMARY_H__
+
+#include "hwc_display.h"
+
+namespace sdm {
+
+class HWCDisplayPrimary : public HWCDisplay {
+ public:
+ explicit HWCDisplayPrimary(CoreInterface *core_intf, hwc_procs_t const **hwc_procs);
+ virtual int Prepare(hwc_display_contents_1_t *content_list);
+ virtual int Commit(hwc_display_contents_1_t *content_list);
+ virtual DisplayError SetDisplayMode(uint32_t mode);
+ virtual int SetActiveConfig(uint32_t index);
+ virtual int SetRefreshRate(uint32_t refresh_rate);
+ virtual void SetMetaDataRefreshRateFlag(bool enable);
+};
+
+} // namespace sdm
+
+#endif // __HWC_DISPLAY_PRIMARY_H__
+
diff --git a/sdm/libs/hwc/hwc_display_virtual.cpp b/sdm/libs/hwc/hwc_display_virtual.cpp
new file mode 100644
index 0000000..d36a171
--- /dev/null
+++ b/sdm/libs/hwc/hwc_display_virtual.cpp
@@ -0,0 +1,278 @@
+/*
+* 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:
+* * 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.
+*/
+
+#include <utils/constants.h>
+#include <sync/sync.h>
+
+#include "hwc_display_virtual.h"
+#include "hwc_debugger.h"
+
+#define __CLASS__ "HWCDisplayVirtual"
+
+namespace sdm {
+
+HWCDisplayVirtual::HWCDisplayVirtual(CoreInterface *core_intf, hwc_procs_t const **hwc_procs)
+ : HWCDisplay(core_intf, hwc_procs, kVirtual, HWC_DISPLAY_VIRTUAL),
+ dump_output_layer_(false) {
+}
+
+int HWCDisplayVirtual::Init() {
+ int status = 0;
+
+ output_buffer_ = new LayerBuffer();
+ if (!output_buffer_) {
+ return -ENOMEM;
+ }
+
+ return HWCDisplay::Init();
+}
+
+int HWCDisplayVirtual::Deinit() {
+ int status = 0;
+
+ status = HWCDisplay::Deinit();
+ if (status) {
+ return status;
+ }
+
+ if (output_buffer_) {
+ delete output_buffer_;
+ }
+
+ return status;
+}
+
+int HWCDisplayVirtual::Prepare(hwc_display_contents_1_t *content_list) {
+ int status = 0;
+ if (display_paused_) {
+ MarkLayersForGPUBypass(content_list);
+ return status;
+ }
+
+ status = AllocateLayerStack(content_list);
+ if (status) {
+ return status;
+ }
+
+ status = SetOutputBuffer(content_list);
+ if (status) {
+ return status;
+ }
+
+ status = PrepareLayerStack(content_list);
+ if (status) {
+ return status;
+ }
+
+ return 0;
+}
+
+int HWCDisplayVirtual::Commit(hwc_display_contents_1_t *content_list) {
+ int status = 0;
+ if (display_paused_) {
+ if (content_list->outbufAcquireFenceFd >= 0) {
+ // If we do not handle the frame set retireFenceFd to outbufAcquireFenceFd,
+ // which will make sure the framework waits on it and closes it.
+ content_list->retireFenceFd = dup(content_list->outbufAcquireFenceFd);
+ close(content_list->outbufAcquireFenceFd);
+ content_list->outbufAcquireFenceFd = -1;
+ }
+ CloseAcquireFences(content_list);
+
+ DisplayError error = display_intf_->Flush();
+ if (error != kErrorNone) {
+ DLOGE("Flush failed. Error = %d", error);
+ }
+ return status;
+ }
+
+ status = HWCDisplay::CommitLayerStack(content_list);
+ if (status) {
+ 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;
+ }
+
+ return 0;
+}
+
+int HWCDisplayVirtual::SetActiveConfig(hwc_display_contents_1_t *content_list) {
+ const private_handle_t *output_handle =
+ static_cast<const private_handle_t *>(content_list->outbuf);
+ DisplayError error = kErrorNone;
+ int status = 0;
+
+ if (output_handle) {
+ LayerBufferFormat format = GetSDMFormat(output_handle->format, output_handle->flags);
+ if (format == kFormatInvalid) {
+ return -EINVAL;
+ }
+
+ int active_width = GetWidth(output_handle);
+ int active_height = GetHeight(output_handle);
+
+ if ((active_width != INT(output_buffer_->width)) ||
+ (active_height!= INT(output_buffer_->height)) ||
+ (format != output_buffer_->format)) {
+ DisplayConfigVariableInfo variable_info;
+ variable_info.x_pixels = active_width;
+ variable_info.y_pixels = active_height;
+ // TODO(user): Need to get the framerate of primary display and update it.
+ variable_info.fps = 60;
+
+ error = display_intf_->SetActiveConfig(&variable_info);
+ if (error != kErrorNone) {
+ return -EINVAL;
+ }
+
+ status = SetOutputBuffer(content_list);
+ if (status) {
+ return status;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int HWCDisplayVirtual::SetOutputBuffer(hwc_display_contents_1_t *content_list) {
+ int status = 0;
+
+ const private_handle_t *output_handle =
+ static_cast<const private_handle_t *>(content_list->outbuf);
+
+ // Fill output buffer parameters (width, height, format, plane information, fence)
+ output_buffer_->acquire_fence_fd = content_list->outbufAcquireFenceFd;
+
+ if (output_handle) {
+ output_buffer_->format = GetSDMFormat(output_handle->format, output_handle->flags);
+ if (output_buffer_->format == kFormatInvalid) {
+ return -EINVAL;
+ }
+
+ output_buffer_->width = GetWidth(output_handle);
+ output_buffer_->height = GetHeight(output_handle);
+ output_buffer_->flags.secure = 0;
+ output_buffer_->flags.video = 0;
+
+ // ToDo: Need to extend for non-RGB formats
+ output_buffer_->planes[0].fd = output_handle->fd;
+ output_buffer_->planes[0].offset = output_handle->offset;
+ output_buffer_->planes[0].stride = output_handle->width;
+ }
+
+ layer_stack_.output_buffer = output_buffer_;
+
+ 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_);
+}
+
+int HWCDisplayVirtual::GetWidth(const private_handle_t* handle) {
+ MetaData_t *metadata = reinterpret_cast<MetaData_t *>(handle->base_metadata);
+ if (metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) {
+ return metadata->bufferDim.sliceWidth;
+ }
+
+ return handle->width;
+}
+
+int HWCDisplayVirtual::GetHeight(const private_handle_t* handle) {
+ MetaData_t *metadata = reinterpret_cast<MetaData_t *>(handle->base_metadata);
+ if (metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) {
+ return metadata->bufferDim.sliceHeight;
+ }
+
+ return handle->height;
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/hwc/hwc_display_virtual.h b/sdm/libs/hwc/hwc_display_virtual.h
new file mode 100644
index 0000000..74285d7
--- /dev/null
+++ b/sdm/libs/hwc/hwc_display_virtual.h
@@ -0,0 +1,56 @@
+/*
+* 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.
+*/
+
+#ifndef __HWC_DISPLAY_VIRTUAL_H__
+#define __HWC_DISPLAY_VIRTUAL_H__
+
+#include <qdMetaData.h>
+#include <gralloc_priv.h>
+#include "hwc_display.h"
+
+namespace sdm {
+
+class HWCDisplayVirtual : public HWCDisplay {
+ public:
+ explicit HWCDisplayVirtual(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);
+ 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);
+ int GetWidth(const private_handle_t* handle);
+ int GetHeight(const private_handle_t* handle);
+
+ bool dump_output_layer_;
+};
+
+} // namespace sdm
+
+#endif // __HWC_DISPLAY_VIRTUAL_H__
+
diff --git a/sdm/libs/hwc/hwc_session.cpp b/sdm/libs/hwc/hwc_session.cpp
new file mode 100644
index 0000000..e5ffda9
--- /dev/null
+++ b/sdm/libs/hwc/hwc_session.cpp
@@ -0,0 +1,1004 @@
+/*
+* 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:
+* * 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.
+*/
+
+#include <core/dump_interface.h>
+#include <core/buffer_allocator.h>
+#include <utils/constants.h>
+#include <utils/String16.h>
+#include <cutils/properties.h>
+#include <hardware_legacy/uevent.h>
+#include <sys/resource.h>
+#include <sys/prctl.h>
+#include <binder/Parcel.h>
+#include <QService.h>
+#include <gr.h>
+#include <gralloc_priv.h>
+#include <display_config.h>
+
+#include "hwc_buffer_allocator.h"
+#include "hwc_buffer_sync_handler.h"
+#include "hwc_session.h"
+#include "hwc_debugger.h"
+
+#define __CLASS__ "HWCSession"
+
+#define HWC_UEVENT_SWITCH_HDMI "change@/devices/virtual/switch/hdmi"
+#define HWC_UEVENT_GRAPHICS_FB0 "change@/devices/virtual/graphics/fb0"
+
+static sdm::HWCSession::HWCModuleMethods g_hwc_module_methods;
+
+hwc_module_t HAL_MODULE_INFO_SYM = {
+ common: {
+ tag: HARDWARE_MODULE_TAG,
+ version_major: 2,
+ version_minor: 0,
+ id: HWC_HARDWARE_MODULE_ID,
+ name: "QTI Hardware Composer Module",
+ author: "CodeAurora Forum",
+ methods: &g_hwc_module_methods,
+ dso: 0,
+ reserved: {0},
+ }
+};
+
+namespace sdm {
+
+Locker HWCSession::locker_;
+bool HWCSession::reset_panel_ = false;
+
+HWCSession::HWCSession(const hw_module_t *module) : core_intf_(NULL), hwc_procs_(NULL),
+ display_primary_(NULL), display_external_(NULL), display_virtual_(NULL),
+ uevent_thread_exit_(false), uevent_thread_name_("HWC_UeventThread") {
+ hwc_composer_device_1_t::common.tag = HARDWARE_DEVICE_TAG;
+ hwc_composer_device_1_t::common.version = HWC_DEVICE_API_VERSION_1_4;
+ hwc_composer_device_1_t::common.module = const_cast<hw_module_t*>(module);
+ hwc_composer_device_1_t::common.close = Close;
+ hwc_composer_device_1_t::prepare = Prepare;
+ hwc_composer_device_1_t::set = Set;
+ hwc_composer_device_1_t::eventControl = EventControl;
+ hwc_composer_device_1_t::setPowerMode = SetPowerMode;
+ hwc_composer_device_1_t::query = Query;
+ hwc_composer_device_1_t::registerProcs = RegisterProcs;
+ hwc_composer_device_1_t::dump = Dump;
+ hwc_composer_device_1_t::getDisplayConfigs = GetDisplayConfigs;
+ hwc_composer_device_1_t::getDisplayAttributes = GetDisplayAttributes;
+ hwc_composer_device_1_t::getActiveConfig = GetActiveConfig;
+ hwc_composer_device_1_t::setActiveConfig = SetActiveConfig;
+}
+
+int HWCSession::Init() {
+ int status = -EINVAL;
+ const char *qservice_name = "display.qservice";
+
+ // Start QService and connect to it.
+ qService::QService::init();
+ android::sp<qService::IQService> qservice = android::interface_cast<qService::IQService>(
+ android::defaultServiceManager()->getService(android::String16(qservice_name)));
+
+ if (qservice.get()) {
+ qservice->connect(android::sp<qClient::IQClient>(this));
+ } else {
+ DLOGE("Failed to acquire %s", qservice_name);
+ return -EINVAL;
+ }
+
+ buffer_allocator_ = new HWCBufferAllocator();
+ if (buffer_allocator_ == NULL) {
+ DLOGE("Display core initialization failed due to no memory");
+ return -ENOMEM;
+ }
+
+ buffer_sync_handler_ = new HWCBufferSyncHandler();
+ if (buffer_sync_handler_ == NULL) {
+ DLOGE("Display core initialization failed due to no memory");
+ return -ENOMEM;
+ }
+
+ DisplayError error = CoreInterface::CreateCore(this, HWCDebugHandler::Get(), buffer_allocator_,
+ buffer_sync_handler_, &core_intf_);
+ if (error != kErrorNone) {
+ DLOGE("Display core initialization failed. Error = %d", error);
+ return -EINVAL;
+ }
+
+ // Create and power on primary display
+ display_primary_ = new HWCDisplayPrimary(core_intf_, &hwc_procs_);
+ if (!display_primary_) {
+ CoreInterface::DestroyCore();
+ return -ENOMEM;
+ }
+
+ status = display_primary_->Init();
+ if (status) {
+ CoreInterface::DestroyCore();
+ delete display_primary_;
+ return status;
+ }
+
+ status = display_primary_->SetPowerMode(HWC_POWER_MODE_NORMAL);
+ if (status) {
+ display_primary_->Deinit();
+ delete display_primary_;
+ CoreInterface::DestroyCore();
+ return status;
+ }
+
+ if (pthread_create(&uevent_thread_, NULL, &HWCUeventThread, this) < 0) {
+ DLOGE("Failed to start = %s, error = %s", uevent_thread_name_);
+ display_primary_->Deinit();
+ delete display_primary_;
+ CoreInterface::DestroyCore();
+ return -errno;
+ }
+
+ SetFrameBufferResolution(HWC_DISPLAY_PRIMARY, NULL);
+
+ return 0;
+}
+
+int HWCSession::Deinit() {
+ display_primary_->SetPowerMode(HWC_POWER_MODE_OFF);
+ display_primary_->Deinit();
+ delete display_primary_;
+ uevent_thread_exit_ = true;
+ pthread_join(uevent_thread_, NULL);
+
+ 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 (!module || !name || !device) {
+ DLOGE("Invalid parameters.");
+ return -EINVAL;
+ }
+
+ if (!strcmp(name, HWC_HARDWARE_COMPOSER)) {
+ HWCSession *hwc_session = new HWCSession(module);
+ if (!hwc_session) {
+ return -ENOMEM;
+ }
+
+ int status = hwc_session->Init();
+ if (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 (!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) {
+ DTRACE_SCOPED();
+
+ SEQUENCE_ENTRY_SCOPE_LOCK(locker_);
+
+ if (!device || !displays) {
+ return -EINVAL;
+ }
+
+ HWCSession *hwc_session = static_cast<HWCSession *>(device);
+
+ if (reset_panel_) {
+ DLOGW("panel is in bad state, resetting the panel");
+ hwc_session->ResetPanel();
+ }
+
+ for (ssize_t i = (num_displays-1); i >= 0; i--) {
+ hwc_display_contents_1_t *content_list = displays[i];
+
+ switch (i) {
+ case HWC_DISPLAY_PRIMARY:
+ hwc_session->display_primary_->Prepare(content_list);
+ break;
+ case HWC_DISPLAY_EXTERNAL:
+ if (hwc_session->display_external_) {
+ hwc_session->display_external_->Prepare(content_list);
+ }
+ break;
+ case HWC_DISPLAY_VIRTUAL:
+ if (hwc_session->display_external_) {
+ break;
+ }
+ if (hwc_session->ValidateContentList(content_list)) {
+ hwc_session->CreateVirtualDisplay(content_list);
+ } else {
+ hwc_session->DestroyVirtualDisplay();
+ }
+
+ if (hwc_session->display_virtual_) {
+ hwc_session->display_virtual_->Prepare(content_list);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Return 0, else client will go into bad state
+ return 0;
+}
+
+int HWCSession::Set(hwc_composer_device_1 *device, size_t num_displays,
+ hwc_display_contents_1_t **displays) {
+ DTRACE_SCOPED();
+
+ SEQUENCE_EXIT_SCOPE_LOCK(locker_);
+
+ if (!device || !displays) {
+ return -EINVAL;
+ }
+
+ HWCSession *hwc_session = static_cast<HWCSession *>(device);
+
+ for (size_t i = 0; i < num_displays; i++) {
+ hwc_display_contents_1_t *content_list = displays[i];
+
+ switch (i) {
+ case HWC_DISPLAY_PRIMARY:
+ hwc_session->display_primary_->Commit(content_list);
+ break;
+ case HWC_DISPLAY_EXTERNAL:
+ if (hwc_session->display_external_) {
+ hwc_session->display_external_->Commit(content_list);
+ }
+ break;
+ case HWC_DISPLAY_VIRTUAL:
+ if (hwc_session->display_external_) {
+ if (content_list) {
+ for (size_t i = 0; i < content_list->numHwLayers; i++) {
+ if (content_list->hwLayers[i].acquireFenceFd >= 0) {
+ close(content_list->hwLayers[i].acquireFenceFd);
+ content_list->hwLayers[i].acquireFenceFd = -1;
+ }
+ }
+ if (content_list->outbufAcquireFenceFd >= 0) {
+ close(content_list->outbufAcquireFenceFd);
+ content_list->outbufAcquireFenceFd = -1;
+ }
+ content_list->retireFenceFd = -1;
+ }
+ }
+ if (hwc_session->display_virtual_) {
+ hwc_session->display_virtual_->Commit(content_list);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Return 0, else client will go into bad state
+ return 0;
+}
+
+int HWCSession::EventControl(hwc_composer_device_1 *device, int disp, int event, int enable) {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+ if (!device) {
+ return -EINVAL;
+ }
+
+ HWCSession *hwc_session = static_cast<HWCSession *>(device);
+ int status = -EINVAL;
+
+ switch (disp) {
+ case HWC_DISPLAY_PRIMARY:
+ status = hwc_session->display_primary_->EventControl(event, enable);
+ break;
+ case HWC_DISPLAY_EXTERNAL:
+ if (hwc_session->display_external_) {
+ status = hwc_session->display_external_->EventControl(event, enable);
+ }
+ break;
+ case HWC_DISPLAY_VIRTUAL:
+ break;
+ default:
+ status = -EINVAL;
+ }
+
+ return status;
+}
+
+int HWCSession::SetPowerMode(hwc_composer_device_1 *device, int disp, int mode) {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+ if (!device) {
+ return -EINVAL;
+ }
+
+ HWCSession *hwc_session = static_cast<HWCSession *>(device);
+ int status = -EINVAL;
+
+ switch (disp) {
+ case HWC_DISPLAY_PRIMARY:
+ status = hwc_session->display_primary_->SetPowerMode(mode);
+ // Set the power mode for virtual display while setting power mode for primary, as surfaceflinger
+ // does not invoke SetPowerMode() for virtual display.
+ case HWC_DISPLAY_VIRTUAL:
+ if (hwc_session->display_virtual_) {
+ status = hwc_session->display_virtual_->SetPowerMode(mode);
+ }
+ break;
+ case HWC_DISPLAY_EXTERNAL:
+ if (hwc_session->display_external_) {
+ status = hwc_session->display_external_->SetPowerMode(mode);
+ }
+ break;
+ default:
+ status = -EINVAL;
+ }
+
+ return status;
+}
+
+int HWCSession::Query(hwc_composer_device_1 *device, int param, int *value) {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+ if (!device || !value) {
+ return -EINVAL;
+ }
+
+ return -EINVAL;
+}
+
+void HWCSession::RegisterProcs(hwc_composer_device_1 *device, hwc_procs_t const *procs) {
+ if (!device || !procs) {
+ return;
+ }
+
+ HWCSession *hwc_session = static_cast<HWCSession *>(device);
+ hwc_session->hwc_procs_ = procs;
+}
+
+void HWCSession::Dump(hwc_composer_device_1 *device, char *buffer, int length) {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+ if (!device || !buffer || !length) {
+ return;
+ }
+
+ DumpInterface::GetDump(buffer, length);
+}
+
+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;
+ }
+
+ HWCSession *hwc_session = static_cast<HWCSession *>(device);
+ int status = -EINVAL;
+
+ switch (disp) {
+ case HWC_DISPLAY_PRIMARY:
+ status = hwc_session->display_primary_->GetDisplayConfigs(configs, num_configs);
+ break;
+ case HWC_DISPLAY_EXTERNAL:
+ if (hwc_session->display_external_) {
+ status = hwc_session->display_external_->GetDisplayConfigs(configs, num_configs);
+ }
+ break;
+ case HWC_DISPLAY_VIRTUAL:
+ if (hwc_session->display_virtual_) {
+ status = hwc_session->display_virtual_->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) {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+ if (!device || !attributes || !values) {
+ return -EINVAL;
+ }
+
+ HWCSession *hwc_session = static_cast<HWCSession *>(device);
+ int status = -EINVAL;
+
+ switch (disp) {
+ case HWC_DISPLAY_PRIMARY:
+ status = hwc_session->display_primary_->GetDisplayAttributes(config, attributes, values);
+ break;
+ case HWC_DISPLAY_EXTERNAL:
+ if (hwc_session->display_external_) {
+ status = hwc_session->display_external_->GetDisplayAttributes(config, attributes, values);
+ }
+ break;
+ case HWC_DISPLAY_VIRTUAL:
+ if (hwc_session->display_virtual_) {
+ status = hwc_session->display_virtual_->GetDisplayAttributes(config, attributes, values);
+ }
+ break;
+ default:
+ status = -EINVAL;
+ }
+
+ return status;
+}
+
+int HWCSession::GetActiveConfig(hwc_composer_device_1 *device, int disp) {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+ if (!device) {
+ return -1;
+ }
+
+ HWCSession *hwc_session = static_cast<HWCSession *>(device);
+ int active_config = -1;
+
+ switch (disp) {
+ case HWC_DISPLAY_PRIMARY:
+ active_config = hwc_session->display_primary_->GetActiveConfig();
+ break;
+ case HWC_DISPLAY_EXTERNAL:
+ if (hwc_session->display_external_) {
+ active_config = hwc_session->display_external_->GetActiveConfig();
+ }
+ break;
+ case HWC_DISPLAY_VIRTUAL:
+ if (hwc_session->display_virtual_) {
+ active_config = hwc_session->display_virtual_->GetActiveConfig();
+ }
+ break;
+ default:
+ active_config = -1;
+ }
+
+ return active_config;
+}
+
+int HWCSession::SetActiveConfig(hwc_composer_device_1 *device, int disp, int index) {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+ if (!device) {
+ return -EINVAL;
+ }
+
+ HWCSession *hwc_session = static_cast<HWCSession *>(device);
+ int status = -EINVAL;
+
+ switch (disp) {
+ case HWC_DISPLAY_PRIMARY:
+ status = hwc_session->display_primary_->SetActiveConfig(index);
+ break;
+ case HWC_DISPLAY_EXTERNAL:
+ if (hwc_session->display_external_) {
+ // TODO(user): Uncomment it. HDMI does not support resolution change currently.
+ status = 0; // hwc_session->display_external_->SetActiveConfig(index);
+ }
+ break;
+ case HWC_DISPLAY_VIRTUAL:
+ break;
+ default:
+ status = -EINVAL;
+ }
+
+ return status;
+}
+
+bool HWCSession::ValidateContentList(hwc_display_contents_1_t *content_list) {
+ return (content_list && content_list->numHwLayers > 0 && content_list->outbuf);
+}
+
+int HWCSession::CreateVirtualDisplay(hwc_display_contents_1_t *content_list) {
+ int status = 0;
+
+ if (!display_virtual_) {
+ // Create virtual display device
+ display_virtual_ = new HWCDisplayVirtual(core_intf_, &hwc_procs_);
+ if (!display_virtual_) {
+ // This is not catastrophic. Leave a warning message for now.
+ DLOGW("Virtual Display creation failed");
+ return -ENOMEM;
+ }
+
+ status = display_virtual_->Init();
+ if (status) {
+ goto CleanupOnError;
+ }
+
+ status = display_virtual_->SetPowerMode(HWC_POWER_MODE_NORMAL);
+ if (status) {
+ goto CleanupOnError;
+ }
+ }
+
+ if (display_virtual_) {
+ SetFrameBufferResolution(HWC_DISPLAY_VIRTUAL, content_list);
+ status = display_virtual_->SetActiveConfig(content_list);
+ }
+
+ return status;
+
+CleanupOnError:
+ return DestroyVirtualDisplay();
+}
+
+int HWCSession::DestroyVirtualDisplay() {
+ int status = 0;
+
+ if (display_virtual_) {
+ status = display_virtual_->Deinit();
+ if (!status) {
+ delete display_virtual_;
+ display_virtual_ = NULL;
+ // Signal the HotPlug thread to continue with the external display connection
+ locker_.Signal();
+ }
+ }
+
+ return status;
+}
+
+DisplayError HWCSession::Hotplug(const CoreEventHotplug &hotplug) {
+ return kErrorNone;
+}
+
+android::status_t HWCSession::notifyCallback(uint32_t command, const android::Parcel *input_parcel,
+ android::Parcel */*output_parcel*/) {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+ android::status_t status = 0;
+
+ switch (command) {
+ case qService::IQService::DYNAMIC_DEBUG:
+ DynamicDebug(input_parcel);
+ break;
+
+ case qService::IQService::SCREEN_REFRESH:
+ hwc_procs_->invalidate(hwc_procs_);
+ break;
+
+ case qService::IQService::SET_IDLE_TIMEOUT:
+ if (display_primary_) {
+ uint32_t timeout = UINT32(input_parcel->readInt32());
+ display_primary_->SetIdleTimeoutMs(timeout);
+ }
+ break;
+
+ case qService::IQService::SET_FRAME_DUMP_CONFIG:
+ SetFrameDumpConfig(input_parcel);
+ break;
+
+ case qService::IQService::SET_MAX_PIPES_PER_MIXER:
+ status = SetMaxMixerStages(input_parcel);
+ break;
+
+ case qService::IQService::SET_DISPLAY_MODE:
+ status = SetDisplayMode(input_parcel);
+ break;
+ case qService::IQService::SET_SECONDARY_DISPLAY_STATUS:
+ status = SetSecondaryDisplayStatus(input_parcel);
+ break;
+
+ case qService::IQService::CONFIGURE_DYN_REFRESH_RATE:
+ status = ConfigureRefreshRate(input_parcel);
+ break;
+
+ default:
+ DLOGW("QService command = %d is not supported", command);
+ return -EINVAL;
+ }
+
+ return status;
+}
+
+android::status_t HWCSession::SetSecondaryDisplayStatus(const android::Parcel *input_parcel) {
+ uint32_t display_id = UINT32(input_parcel->readInt32());
+ uint32_t display_status = UINT32(input_parcel->readInt32());
+ HWCDisplay *display = NULL;
+
+ DLOGI("Display %d Status %d", display_id, display_status);
+ switch (display_id) {
+ case HWC_DISPLAY_EXTERNAL:
+ display = display_external_;
+ break;
+ case HWC_DISPLAY_VIRTUAL:
+ display = display_virtual_;
+ break;
+ default:
+ DLOGW("Not supported for display %d", display_id);
+ return -EINVAL;
+ }
+
+ return display->SetDisplayStatus(display_status);
+}
+
+android::status_t HWCSession::ConfigureRefreshRate(const android::Parcel *input_parcel) {
+ uint32_t operation = UINT32(input_parcel->readInt32());
+
+ switch (operation) {
+ case qdutils::DISABLE_METADATA_DYN_REFRESH_RATE:
+ display_primary_->SetMetaDataRefreshRateFlag(false);
+ break;
+
+ case qdutils::ENABLE_METADATA_DYN_REFRESH_RATE:
+ display_primary_->SetMetaDataRefreshRateFlag(true);
+ break;
+
+ case qdutils::SET_BINDER_DYN_REFRESH_RATE:
+ {
+ uint32_t refresh_rate = UINT32(input_parcel->readInt32());
+
+ display_primary_->SetRefreshRate(refresh_rate);
+ break;
+ }
+
+ default:
+ DLOGW("Invalid operation %d", operation);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+android::status_t HWCSession::SetDisplayMode(const android::Parcel *input_parcel) {
+ DisplayError error = kErrorNone;
+ uint32_t mode = UINT32(input_parcel->readInt32());
+
+ error = display_primary_->SetDisplayMode(mode);
+ if (error != kErrorNone) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+android::status_t HWCSession::SetMaxMixerStages(const android::Parcel *input_parcel) {
+ DisplayError error = kErrorNone;
+ uint32_t bit_mask_display_type = UINT32(input_parcel->readInt32());
+ uint32_t max_mixer_stages = UINT32(input_parcel->readInt32());
+
+ if (IS_BIT_SET(bit_mask_display_type, HWC_DISPLAY_PRIMARY)) {
+ if (display_primary_) {
+ error = display_primary_->SetMaxMixerStages(max_mixer_stages);
+ if (error != kErrorNone) {
+ return -EINVAL;
+ }
+ }
+ }
+
+ if (IS_BIT_SET(bit_mask_display_type, HWC_DISPLAY_EXTERNAL)) {
+ if (display_external_) {
+ error = display_external_->SetMaxMixerStages(max_mixer_stages);
+ if (error != kErrorNone) {
+ return -EINVAL;
+ }
+ }
+ }
+
+ if (IS_BIT_SET(bit_mask_display_type, HWC_DISPLAY_VIRTUAL)) {
+ if (display_virtual_) {
+ error = display_virtual_->SetMaxMixerStages(max_mixer_stages);
+ if (error != kErrorNone) {
+ return -EINVAL;
+ }
+ }
+ }
+
+ 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 (IS_BIT_SET(bit_mask_display_type, HWC_DISPLAY_PRIMARY)) {
+ if (display_primary_) {
+ display_primary_->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
+ }
+ }
+
+ if (IS_BIT_SET(bit_mask_display_type, HWC_DISPLAY_EXTERNAL)) {
+ if (display_external_) {
+ display_external_->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
+ }
+ }
+
+ if (IS_BIT_SET(bit_mask_display_type, HWC_DISPLAY_VIRTUAL)) {
+ 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);
+ DLOGI("type = %d enable = %d", type, enable);
+
+ switch (type) {
+ case qService::IQService::DEBUG_ALL:
+ HWCDebugHandler::DebugAll(enable);
+ break;
+
+ case qService::IQService::DEBUG_MDPCOMP:
+ HWCDebugHandler::DebugStrategy(enable);
+ HWCDebugHandler::DebugCompManager(enable);
+ break;
+
+ case qService::IQService::DEBUG_PIPE_LIFECYCLE:
+ HWCDebugHandler::DebugResources(enable);
+ break;
+
+ case qService::IQService::DEBUG_DRIVER_CONFIG:
+ HWCDebugHandler::DebugDriverConfig(enable);
+ break;
+
+ case qService::IQService::DEBUG_ROTATOR:
+ HWCDebugHandler::DebugResources(enable);
+ HWCDebugHandler::DebugDriverConfig(enable);
+ HWCDebugHandler::DebugRotator(enable);
+ break;
+
+ default:
+ DLOGW("type = %d is not supported", type);
+ }
+}
+
+void* HWCSession::HWCUeventThread(void *context) {
+ if (context) {
+ return reinterpret_cast<HWCSession *>(context)->HWCUeventThreadHandler();
+ }
+
+ return NULL;
+}
+
+void* HWCSession::HWCUeventThreadHandler() {
+ static char uevent_data[PAGE_SIZE];
+ int length = 0;
+ prctl(PR_SET_NAME, uevent_thread_name_, 0, 0, 0);
+ setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
+ if (!uevent_init()) {
+ DLOGE("Failed to init uevent");
+ pthread_exit(0);
+ return NULL;
+ }
+
+ while (!uevent_thread_exit_) {
+ // keep last 2 zeroes to ensure double 0 termination
+ length = uevent_next_event(uevent_data, INT32(sizeof(uevent_data)) - 2);
+
+ if (strcasestr(HWC_UEVENT_SWITCH_HDMI, uevent_data)) {
+ DLOGI("Uevent HDMI = %s", uevent_data);
+ int connected = GetEventValue(uevent_data, length, "SWITCH_STATE=");
+ if (connected >= 0) {
+ DLOGI("HDMI = %s", connected ? "connected" : "disconnected");
+ if (HotPlugHandler(connected) == -1) {
+ DLOGE("Failed handling Hotplug = %s", connected ? "connected" : "disconnected");
+ }
+ }
+ } else if (strcasestr(HWC_UEVENT_GRAPHICS_FB0, uevent_data)) {
+ DLOGI("Uevent FB0 = %s", uevent_data);
+ int panel_reset = GetEventValue(uevent_data, length, "PANEL_ALIVE=");
+ if (panel_reset == 0) {
+ if (hwc_procs_) {
+ reset_panel_ = true;
+ hwc_procs_->invalidate(hwc_procs_);
+ } else {
+ DLOGW("Ignore resetpanel - hwc_proc not registered");
+ }
+ }
+ }
+ }
+ pthread_exit(0);
+
+ return NULL;
+}
+
+int HWCSession::GetEventValue(const char *uevent_data, int length, const char *event_info) {
+ const char *iterator_str = uevent_data;
+ while (((iterator_str - uevent_data) <= length) && (*iterator_str)) {
+ char *pstr = strstr(iterator_str, event_info);
+ if (pstr != NULL) {
+ return (atoi(iterator_str + strlen(event_info)));
+ }
+ iterator_str += strlen(iterator_str) + 1;
+ }
+
+ return -1;
+}
+
+void HWCSession::ResetPanel() {
+ int status = -EINVAL;
+
+ DLOGI("Powering off primary");
+ status = display_primary_->SetPowerMode(HWC_POWER_MODE_OFF);
+ if (status) {
+ DLOGE("power-off on primary failed with error = %d", status);
+ }
+
+ DLOGI("Restoring power mode on primary");
+ uint32_t mode = display_primary_->GetLastPowerMode();
+ status = display_primary_->SetPowerMode(mode);
+ if (status) {
+ DLOGE("Setting power mode = %d on primary failed with error = %d", mode, status);
+ }
+
+ status = display_primary_->EventControl(HWC_EVENT_VSYNC, 1);
+ if (status) {
+ DLOGE("enabling vsync failed for primary with error = %d", status);
+ }
+
+ reset_panel_ = false;
+}
+
+int HWCSession::HotPlugHandler(bool connected) {
+ if (!hwc_procs_) {
+ DLOGW("Ignore hotplug - hwc_proc not registered");
+ return -1;
+ }
+
+ if (connected) {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+ if (display_virtual_) {
+ // Wait for the virtual display to tear down
+ int status = locker_.WaitFinite(kExternalConnectionTimeoutMs);
+ if (status != 0) {
+ DLOGE("Timed out while waiting for virtual display to tear down.");
+ return -1;
+ }
+ }
+ if (display_external_) {
+ DLOGE("HDMI already connected");
+ return -1;
+ }
+ // Create hdmi display
+ display_external_ = new HWCDisplayExternal(core_intf_, &hwc_procs_);
+ if (!display_external_) {
+ return -1;
+ }
+ int status = display_external_->Init();
+ if (status) {
+ delete display_external_;
+ display_external_ = NULL;
+ return -1;
+ }
+ SetFrameBufferResolution(HWC_DISPLAY_EXTERNAL, NULL);
+ } else {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+ if (!display_external_) {
+ DLOGE("HDMI not connected");
+ return -1;
+ }
+ display_external_->SetPowerMode(HWC_POWER_MODE_OFF);
+ display_external_->Deinit();
+ delete display_external_;
+ display_external_ = NULL;
+ }
+
+ // notify client and trigger a screen refresh
+ hwc_procs_->hotplug(hwc_procs_, HWC_DISPLAY_EXTERNAL, connected);
+ hwc_procs_->invalidate(hwc_procs_);
+
+ return 0;
+}
+
+void HWCSession::SetFrameBufferResolution(int disp, hwc_display_contents_1_t *content_list) {
+ char property[PROPERTY_VALUE_MAX];
+ uint32_t primary_width = 0;
+ uint32_t primary_height = 0;
+
+ switch (disp) {
+ case HWC_DISPLAY_PRIMARY:
+ {
+ display_primary_->GetPanelResolution(&primary_width, &primary_height);
+ if (property_get("debug.hwc.fbsize", property, NULL) > 0) {
+ char *yptr = strcasestr(property, "x");
+ primary_width = atoi(property);
+ primary_height = atoi(yptr + 1);
+ }
+ display_primary_->SetFrameBufferResolution(primary_width, primary_height);
+ break;
+ }
+
+ case HWC_DISPLAY_EXTERNAL:
+ {
+ uint32_t external_width = 0;
+ uint32_t external_height = 0;
+ display_external_->GetPanelResolution(&external_width, &external_height);
+
+ if (property_get("sys.hwc.mdp_downscale_enabled", property, "false") &&
+ !strcmp(property, "true")) {
+ display_primary_->GetFrameBufferResolution(&primary_width, &primary_height);
+ uint32_t primary_area = primary_width * primary_height;
+ uint32_t external_area = external_width * external_height;
+
+ if (primary_area > external_area) {
+ if (primary_height > primary_width) {
+ Swap(primary_height, primary_width);
+ }
+ AdjustSourceResolution(primary_width, primary_height,
+ &external_width, &external_height);
+ }
+ }
+ display_external_->SetFrameBufferResolution(external_width, external_height);
+ break;
+ }
+
+ case HWC_DISPLAY_VIRTUAL:
+ {
+ if (ValidateContentList(content_list)) {
+ const private_handle_t *output_handle =
+ static_cast<const private_handle_t *>(content_list->outbuf);
+ int virtual_width = 0;
+ int virtual_height = 0;
+ getBufferSizeAndDimensions(output_handle->width, output_handle->height, output_handle->format,
+ virtual_width, virtual_height);
+ display_virtual_->SetFrameBufferResolution(virtual_width, virtual_height);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+void HWCSession::AdjustSourceResolution(uint32_t dst_width, uint32_t dst_height,
+ uint32_t *src_width, uint32_t *src_height) {
+ *src_height = (dst_width * (*src_height)) / (*src_width);
+ *src_width = dst_width;
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/hwc/hwc_session.h b/sdm/libs/hwc/hwc_session.h
new file mode 100644
index 0000000..15b762c
--- /dev/null
+++ b/sdm/libs/hwc/hwc_session.h
@@ -0,0 +1,116 @@
+/*
+* 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __HWC_SESSION_H__
+#define __HWC_SESSION_H__
+
+#include <hardware/hwcomposer.h>
+#include <core/core_interface.h>
+#include <utils/locker.h>
+#include <IQClient.h>
+
+#include "hwc_display_primary.h"
+#include "hwc_display_external.h"
+#include "hwc_display_virtual.h"
+
+namespace sdm {
+
+class HWCSession : hwc_composer_device_1_t, CoreEventHandler, public qClient::BnQClient {
+ public:
+ struct HWCModuleMethods : public hw_module_methods_t {
+ HWCModuleMethods() {
+ hw_module_methods_t::open = HWCSession::Open;
+ }
+ };
+
+ explicit HWCSession(const hw_module_t *module);
+ int Init();
+ int Deinit();
+
+ private:
+ static const int kExternalConnectionTimeoutMs = 500;
+
+ // hwc methods
+ static int Open(const hw_module_t *module, const char* name, hw_device_t **device);
+ static int Close(hw_device_t *device);
+ static int Prepare(hwc_composer_device_1 *device, size_t num_displays,
+ hwc_display_contents_1_t **displays);
+ static int Set(hwc_composer_device_1 *device, size_t num_displays,
+ hwc_display_contents_1_t **displays);
+ static int EventControl(hwc_composer_device_1 *device, int disp, int event, int enable);
+ static int SetPowerMode(hwc_composer_device_1 *device, int disp, int mode);
+ static int Query(hwc_composer_device_1 *device, int param, int *value);
+ static void RegisterProcs(hwc_composer_device_1 *device, hwc_procs_t const *procs);
+ static void Dump(hwc_composer_device_1 *device, char *buffer, int length);
+ static int GetDisplayConfigs(hwc_composer_device_1 *device, int disp, uint32_t *configs,
+ size_t *numConfigs);
+ static int GetDisplayAttributes(hwc_composer_device_1 *device, int disp, uint32_t config,
+ const uint32_t *attributes, int32_t *values);
+ static int GetActiveConfig(hwc_composer_device_1 *device, int disp);
+ static int SetActiveConfig(hwc_composer_device_1 *device, int disp, int index);
+
+ // Uevent thread
+ static void* HWCUeventThread(void *context);
+ void* HWCUeventThreadHandler();
+ int GetEventValue(const char *uevent_data, int length, const char *event_info);
+ int HotPlugHandler(bool connected);
+ void ResetPanel();
+ bool ValidateContentList(hwc_display_contents_1_t *content_list);
+ int CreateVirtualDisplay(hwc_display_contents_1_t *content_list);
+ int DestroyVirtualDisplay();
+
+ // CoreEventHandler methods
+ virtual DisplayError Hotplug(const CoreEventHotplug &hotplug);
+
+ // QClient methods
+ 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);
+ android::status_t SetMaxMixerStages(const android::Parcel *input_parcel);
+ android::status_t SetDisplayMode(const android::Parcel *input_parcel);
+ android::status_t SetSecondaryDisplayStatus(const android::Parcel *input_parcel);
+ void SetFrameBufferResolution(int disp, hwc_display_contents_1_t *content_list);
+ void AdjustSourceResolution(uint32_t dst_width, uint32_t dst_height,
+ uint32_t *src_width, uint32_t *src_height);
+ android::status_t ConfigureRefreshRate(const android::Parcel *input_parcel);
+
+ static Locker locker_;
+ CoreInterface *core_intf_;
+ hwc_procs_t const *hwc_procs_;
+ HWCDisplayPrimary *display_primary_;
+ HWCDisplayExternal *display_external_;
+ HWCDisplayVirtual *display_virtual_;
+ pthread_t uevent_thread_;
+ bool uevent_thread_exit_;
+ static bool reset_panel_;
+ const char *uevent_thread_name_;
+ HWCBufferAllocator *buffer_allocator_;
+ HWCBufferSyncHandler *buffer_sync_handler_;
+};
+
+} // namespace sdm
+
+#endif // __HWC_SESSION_H__
+
diff --git a/sdm/libs/utils/Android.mk b/sdm/libs/utils/Android.mk
new file mode 100644
index 0000000..57c2088
--- /dev/null
+++ b/sdm/libs/utils/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libsdmutils
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := hardware/qcom/display/sdm/include/
+LOCAL_CFLAGS := -Wno-missing-field-initializers -Wno-unused-parameter \
+ -Wconversion -Wall -Werror \
+ -DLOG_TAG=\"SDM\"
+LOCAL_SHARED_LIBRARIES := libcutils
+LOCAL_SRC_FILES := debug_android.cpp rect.cpp
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/sdm/libs/utils/debug_android.cpp b/sdm/libs/utils/debug_android.cpp
new file mode 100644
index 0000000..f57d04d
--- /dev/null
+++ b/sdm/libs/utils/debug_android.cpp
@@ -0,0 +1,103 @@
+/*
+* 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:
+* * 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.
+*/
+
+#include <stdlib.h>
+#include <utils/debug.h>
+#include <utils/constants.h>
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+namespace sdm {
+
+Debug Debug::debug_;
+
+Debug::Debug() : debug_handler_(&default_debug_handler_), virtual_driver_(false) {
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get("displaycore.virtualdriver", property, NULL) > 0) {
+ virtual_driver_ = (atoi(property) == 1);
+ }
+}
+
+uint32_t Debug::GetSimulationFlag() {
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get("debug.hwc.simulate", property, NULL) > 0) {
+ return atoi(property);
+ }
+
+ return 0;
+}
+
+uint32_t Debug::GetHDMIResolution() {
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get("hw.hdmi.resolution", property, NULL) > 0) {
+ return atoi(property);
+ }
+
+ return 0;
+}
+
+uint32_t Debug::GetIdleTimeoutMs() {
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get("debug.mdpcomp.idletime", property, NULL) > 0) {
+ return atoi(property);
+ }
+
+ return IDLE_TIMEOUT_DEFAULT_MS;
+}
+
+bool Debug::IsRotatorDownScaleDisabled() {
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get("sdm.disable_rotator_downscaling", property, NULL) > 0) {
+ return (atoi(property) ? 0 : false, true);
+ }
+
+ return false;
+}
+
+bool Debug::IsDecimationDisabled() {
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get("sdm.disable_decimation", property, NULL) > 0) {
+ return (atoi(property) ? 0 : false, true);
+ }
+
+ return false;
+}
+
+// This property serves to disable/enable partial update
+bool Debug::IsPartialUpdateEnabled() {
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get("sdm.hwc.partial_update", property, NULL) > 0) {
+ return (atoi(property) ? 1 : true, false);
+ }
+
+ return false;
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/utils/rect.cpp b/sdm/libs/utils/rect.cpp
new file mode 100644
index 0000000..9edc4f4
--- /dev/null
+++ b/sdm/libs/utils/rect.cpp
@@ -0,0 +1,142 @@
+/*
+* Copyright (c) 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:
+* * 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.
+*/
+
+#include <math.h>
+#include <utils/rect.h>
+#include <utils/constants.h>
+
+#define __CLASS__ "RectUtils"
+
+namespace sdm {
+
+bool IsValid(const LayerRect &rect) {
+ return ((rect.bottom > rect.top) && (rect.right > rect.left));
+}
+
+bool IsCongruent(const LayerRect &rect1, const LayerRect &rect2) {
+ return ((rect1.left == rect2.left) &&
+ (rect1.top == rect2.top) &&
+ (rect1.right == rect2.right) &&
+ (rect1.bottom == rect2.bottom));
+}
+
+void Log(DebugTag debug_tag, const char *prefix, const LayerRect &roi) {
+ DLOGV_IF(debug_tag, "%s: left = %.0f, top = %.0f, right = %.0f, bottom = %.0f",
+ prefix, roi.left, roi.top, roi.right, roi.bottom);
+}
+
+void Normalize(const uint32_t &align_x, const uint32_t &align_y, LayerRect *rect) {
+ rect->left = ROUND_UP_ALIGN_UP(rect->left, align_x);
+ rect->right = ROUND_UP_ALIGN_DOWN(rect->right, align_x);
+ rect->top = ROUND_UP_ALIGN_UP(rect->top, align_y);
+ rect->bottom = ROUND_UP_ALIGN_DOWN(rect->bottom, align_y);
+}
+
+LayerRect Intersection(const LayerRect &rect1, const LayerRect &rect2) {
+ LayerRect res;
+
+ if (!IsValid(rect1) || !IsValid(rect2)) {
+ return LayerRect();
+ }
+
+ res.left = MAX(rect1.left, rect2.left);
+ res.top = MAX(rect1.top, rect2.top);
+ res.right = MIN(rect1.right, rect2.right);
+ res.bottom = MIN(rect1.bottom, rect2.bottom);
+
+ if (!IsValid(res)) {
+ return LayerRect();
+ }
+
+ return res;
+}
+
+LayerRect Reposition(const LayerRect &rect, const int &x_offset, const int &y_offset) {
+ LayerRect res;
+
+ if (!IsValid(rect)) {
+ return LayerRect();
+ }
+
+ res.left = rect.left + FLOAT(x_offset);
+ res.top = rect.top + FLOAT(y_offset);
+ res.right = rect.right + FLOAT(x_offset);
+ res.bottom = rect.bottom + FLOAT(y_offset);
+
+ return res;
+}
+
+// Not a geometrical rect deduction. Deducts rect2 from rect1 only if it results a single rect
+LayerRect Subtract(const LayerRect &rect1, const LayerRect &rect2) {
+ LayerRect res;
+
+ res = rect1;
+
+ if ((rect1.left == rect2.left) && (rect1.right == rect2.right)) {
+ if ((rect1.top == rect2.top) && (rect2.bottom <= rect1.bottom)) {
+ res.top = rect2.bottom;
+ } else if ((rect1.bottom == rect2.bottom) && (rect2.top >= rect1.top)) {
+ res.bottom = rect2.top;
+ }
+ } else if ((rect1.top == rect2.top) && (rect1.bottom == rect2.bottom)) {
+ if ((rect1.left == rect2.left) && (rect2.right <= rect1.right)) {
+ res.left = rect2.right;
+ } else if ((rect1.right == rect2.right) && (rect2.left >= rect1.left)) {
+ res.right = rect2.left;
+ }
+ }
+
+ return res;
+}
+
+LayerRect Union(const LayerRect &rect1, const LayerRect &rect2) {
+ LayerRect res;
+
+ if (!IsValid(rect1) && !IsValid(rect2)) {
+ return LayerRect();
+ }
+
+ if (!IsValid(rect1)) {
+ return rect2;
+ }
+
+ if (!IsValid(rect2)) {
+ return rect1;
+ }
+
+ res.left = MIN(rect1.left, rect2.left);
+ res.top = MIN(rect1.top, rect2.top);
+ res.right = MAX(rect1.right, rect2.right);
+ res.bottom = MAX(rect1.bottom, rect2.bottom);
+
+ return res;
+}
+
+} // namespace sdm
+