hwc: HWC 2.0 implementation
Add HWCLayer, HWCCallbacks and implement HWC2 layer functionality. Change-Id: Ic7764e72f4cae534e68764df4cf80eb3db982071
This commit is contained in:
parent
c14b2088b0
commit
b92e73fc10
|
@ -0,0 +1,4 @@
|
|||
CMakeLists.txt
|
||||
.idea/
|
||||
.editorconfig
|
||||
.clang-complete
|
|
@ -2,7 +2,7 @@ display-hals := libgralloc libcopybit liblight libmemtrack libqservice libqdutil
|
|||
display-hals += hdmi_cec
|
||||
|
||||
sdm-libs := sdm/libs
|
||||
display-hals += $(sdm-libs)/utils $(sdm-libs)/core $(sdm-libs)/hwc
|
||||
display-hals += $(sdm-libs)/utils $(sdm-libs)/core $(sdm-libs)/hwc $(sdm-libs)/hwc2
|
||||
|
||||
ifeq ($(call is-vendor-board-platform,QCOM),true)
|
||||
include $(call all-named-subdir-makefiles,$(display-hals))
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#Common headers
|
||||
display_top := $(call my-dir)
|
||||
|
||||
use_hwc2 := false
|
||||
|
||||
common_includes := $(display_top)/libqdutils
|
||||
common_includes += $(display_top)/libqservice
|
||||
common_includes += $(display_top)/libcopybit
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
ColumnLimit: 100
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Right
|
||||
#ReflowComments: false
|
|
@ -45,6 +45,7 @@
|
|||
#define DLOGV_IF(tag, format, ...) DLOG(tag, Verbose, format, ##__VA_ARGS__)
|
||||
|
||||
#define DLOGE(format, ...) DLOGE_IF(kTagNone, format, ##__VA_ARGS__)
|
||||
#define DLOGD(format, ...) DLOGD_IF(kTagNone, format, ##__VA_ARGS__)
|
||||
#define DLOGW(format, ...) DLOGW_IF(kTagNone, format, ##__VA_ARGS__)
|
||||
#define DLOGI(format, ...) DLOGI_IF(kTagNone, format, ##__VA_ARGS__)
|
||||
#define DLOGV(format, ...) DLOGV_IF(kTagNone, format, ##__VA_ARGS__)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
include $(LOCAL_PATH)/../../../common.mk
|
||||
ifeq ($(use_hwc2),false)
|
||||
|
||||
LOCAL_MODULE := hwcomposer.$(TARGET_BOARD_PLATFORM)
|
||||
LOCAL_MODULE_RELATIVE_PATH := hw
|
||||
|
@ -30,3 +31,4 @@ LOCAL_SRC_FILES := hwc_session.cpp \
|
|||
cpuhint.cpp
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
include $(LOCAL_PATH)/../../../common.mk
|
||||
|
||||
ifeq ($(use_hwc2),true)
|
||||
|
||||
LOCAL_MODULE := hwcomposer.$(TARGET_BOARD_PLATFORM)
|
||||
LOCAL_MODULE_RELATIVE_PATH := hw
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := $(common_includes)
|
||||
|
||||
LOCAL_CFLAGS := -Wno-missing-field-initializers -Wno-unused-parameter \
|
||||
-std=c++11 -fcolor-diagnostics\
|
||||
-DLOG_TAG=\"SDM\" $(common_flags) \
|
||||
-I $(display_top)/sdm/libs/hwc
|
||||
LOCAL_CLANG := true
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := libsdmcore libqservice libbinder libhardware libhardware_legacy \
|
||||
libutils libcutils libsync libmemalloc libqdutils libdl \
|
||||
libpowermanager libsdmutils libc++
|
||||
|
||||
LOCAL_SRC_FILES := hwc_session.cpp \
|
||||
hwc_display.cpp \
|
||||
hwc_display_primary.cpp \
|
||||
hwc_display_external.cpp \
|
||||
hwc_display_virtual.cpp \
|
||||
../hwc/hwc_debugger.cpp \
|
||||
../hwc/hwc_buffer_allocator.cpp \
|
||||
../hwc/hwc_buffer_sync_handler.cpp \
|
||||
hwc_color_manager.cpp \
|
||||
hwc_layers.cpp \
|
||||
hwc_callbacks.cpp \
|
||||
../hwc/blit_engine_c2d.cpp \
|
||||
../hwc/cpuhint.cpp
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
endif
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 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 "hwc_callbacks.h"
|
||||
|
||||
#define __CLASS__ "HWCCallbacks"
|
||||
|
||||
namespace sdm {
|
||||
|
||||
void HWCCallbacks::Hotplug(hwc2_display_t display, HWC2::Connection state) {
|
||||
if (hotplug_) {
|
||||
hotplug_(hotplug_data_, display, INT32(state));
|
||||
}
|
||||
}
|
||||
|
||||
void HWCCallbacks::Refresh(hwc2_display_t display) {
|
||||
if (refresh_) {
|
||||
refresh_(refresh_data_, display);
|
||||
}
|
||||
}
|
||||
|
||||
void HWCCallbacks::Vsync(hwc2_display_t display, int64_t timestamp) {
|
||||
if (vsync_) {
|
||||
vsync_(vsync_data_, display, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
HWC2::Error HWCCallbacks::Register(HWC2::Callback descriptor, hwc2_callback_data_t callback_data,
|
||||
hwc2_function_pointer_t pointer) {
|
||||
switch (descriptor) {
|
||||
case HWC2::Callback::Hotplug:
|
||||
hotplug_data_ = callback_data;
|
||||
hotplug_ = reinterpret_cast<HWC2_PFN_HOTPLUG>(pointer);
|
||||
break;
|
||||
case HWC2::Callback::Refresh:
|
||||
refresh_data_ = callback_data;
|
||||
refresh_ = reinterpret_cast<HWC2_PFN_REFRESH>(pointer);
|
||||
break;
|
||||
case HWC2::Callback::Vsync:
|
||||
vsync_data_ = callback_data;
|
||||
vsync_ = reinterpret_cast<HWC2_PFN_VSYNC>(pointer);
|
||||
break;
|
||||
default:
|
||||
return HWC2::Error::BadParameter;
|
||||
}
|
||||
return HWC2::Error::None;
|
||||
}
|
||||
|
||||
} // namespace sdm
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 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_CALLBACKS_H__
|
||||
#define __HWC_CALLBACKS_H__
|
||||
|
||||
#define HWC2_INCLUDE_STRINGIFICATION
|
||||
#define HWC2_USE_CPP11
|
||||
#include <hardware/hwcomposer2.h>
|
||||
#undef HWC2_INCLUDE_STRINGIFICATION
|
||||
#undef HWC2_USE_CPP11
|
||||
|
||||
namespace sdm {
|
||||
|
||||
class HWCCallbacks {
|
||||
public:
|
||||
void Hotplug(hwc2_display_t display, HWC2::Connection state);
|
||||
void Refresh(hwc2_display_t display);
|
||||
void Vsync(hwc2_display_t display, int64_t timestamp);
|
||||
HWC2::Error Register(HWC2::Callback, hwc2_callback_data_t callback_data,
|
||||
hwc2_function_pointer_t pointer);
|
||||
|
||||
private:
|
||||
hwc2_callback_data_t hotplug_data_ = nullptr;
|
||||
hwc2_callback_data_t refresh_data_ = nullptr;
|
||||
hwc2_callback_data_t vsync_data_ = nullptr;
|
||||
|
||||
HWC2_PFN_HOTPLUG hotplug_ = nullptr;
|
||||
HWC2_PFN_REFRESH refresh_ = nullptr;
|
||||
HWC2_PFN_VSYNC vsync_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace sdm
|
||||
|
||||
#endif // __HWC_CALLBACKS_H__
|
|
@ -0,0 +1,564 @@
|
|||
/*
|
||||
* Copyright (c) 2015 - 2016, 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 <powermanager/IPowerManager.h>
|
||||
#include <cutils/sockets.h>
|
||||
#include <cutils/native_handle.h>
|
||||
#include <utils/String16.h>
|
||||
#include <binder/Parcel.h>
|
||||
#include <gralloc_priv.h>
|
||||
#include <hardware/hwcomposer.h>
|
||||
#include <hardware/hwcomposer_defs.h>
|
||||
#include <QService.h>
|
||||
|
||||
#include <core/dump_interface.h>
|
||||
#include <utils/constants.h>
|
||||
#include <utils/debug.h>
|
||||
#include <core/buffer_allocator.h>
|
||||
#include <private/color_params.h>
|
||||
#include "hwc_buffer_allocator.h"
|
||||
#include "hwc_buffer_sync_handler.h"
|
||||
#include "hwc_session.h"
|
||||
#include "hwc_debugger.h"
|
||||
|
||||
#define __CLASS__ "HWCColorManager"
|
||||
|
||||
namespace sdm {
|
||||
|
||||
uint32_t HWCColorManager::Get8BitsARGBColorValue(const PPColorFillParams ¶ms) {
|
||||
uint32_t argb_color = ((params.color.r << 16) & 0xff0000) | ((params.color.g) & 0xff) |
|
||||
((params.color.b << 8) & 0xff00);
|
||||
return argb_color;
|
||||
}
|
||||
|
||||
int HWCColorManager::CreatePayloadFromParcel(const android::Parcel &in, uint32_t *disp_id,
|
||||
PPDisplayAPIPayload *sink) {
|
||||
int ret = 0;
|
||||
uint32_t id(0);
|
||||
uint32_t size(0);
|
||||
|
||||
id = UINT32(in.readInt32());
|
||||
size = UINT32(in.readInt32());
|
||||
if (size > 0 && size == in.dataAvail()) {
|
||||
const void *data = in.readInplace(size);
|
||||
const uint8_t *temp = reinterpret_cast<const uint8_t *>(data);
|
||||
|
||||
sink->size = size;
|
||||
sink->payload = const_cast<uint8_t *>(temp);
|
||||
*disp_id = id;
|
||||
} else {
|
||||
DLOGW("Failing size checking, size = %d", size);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void HWCColorManager::MarshallStructIntoParcel(const PPDisplayAPIPayload &data,
|
||||
android::Parcel *out_parcel) {
|
||||
out_parcel->writeInt32(INT32(data.size));
|
||||
if (data.payload)
|
||||
out_parcel->write(data.payload, data.size);
|
||||
}
|
||||
|
||||
HWCColorManager *HWCColorManager::CreateColorManager() {
|
||||
HWCColorManager *color_mgr = new HWCColorManager();
|
||||
|
||||
if (color_mgr) {
|
||||
void *&color_lib = color_mgr->color_apis_lib_;
|
||||
// Load display API interface library. And retrieve color API function tables.
|
||||
color_lib = ::dlopen(DISPLAY_API_INTERFACE_LIBRARY_NAME, RTLD_NOW);
|
||||
if (color_lib) {
|
||||
color_mgr->color_apis_ = ::dlsym(color_lib, DISPLAY_API_FUNC_TABLES);
|
||||
if (!color_mgr->color_apis_) {
|
||||
DLOGE("Fail to retrieve = %s from %s", DISPLAY_API_FUNC_TABLES,
|
||||
DISPLAY_API_INTERFACE_LIBRARY_NAME);
|
||||
::dlclose(color_lib);
|
||||
delete color_mgr;
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
DLOGW("Unable to load = %s", DISPLAY_API_INTERFACE_LIBRARY_NAME);
|
||||
delete color_mgr;
|
||||
return NULL;
|
||||
}
|
||||
DLOGI("Successfully loaded %s", DISPLAY_API_INTERFACE_LIBRARY_NAME);
|
||||
|
||||
// Load diagclient library and invokes its entry point to pass in display APIs.
|
||||
void *&diag_lib = color_mgr->diag_client_lib_;
|
||||
diag_lib = ::dlopen(QDCM_DIAG_CLIENT_LIBRARY_NAME, RTLD_NOW);
|
||||
if (diag_lib) {
|
||||
*(reinterpret_cast<void **>(&color_mgr->qdcm_diag_init_)) =
|
||||
::dlsym(diag_lib, INIT_QDCM_DIAG_CLIENT_NAME);
|
||||
*(reinterpret_cast<void **>(&color_mgr->qdcm_diag_deinit_)) =
|
||||
::dlsym(diag_lib, DEINIT_QDCM_DIAG_CLIENT_NAME);
|
||||
|
||||
if (!color_mgr->qdcm_diag_init_ || !color_mgr->qdcm_diag_deinit_) {
|
||||
DLOGE("Fail to retrieve = %s from %s", INIT_QDCM_DIAG_CLIENT_NAME,
|
||||
QDCM_DIAG_CLIENT_LIBRARY_NAME);
|
||||
::dlclose(diag_lib);
|
||||
} else {
|
||||
// invoke Diag Client entry point to initialize.
|
||||
color_mgr->qdcm_diag_init_(color_mgr->color_apis_);
|
||||
DLOGI("Successfully loaded %s and %s and diag_init'ed", DISPLAY_API_INTERFACE_LIBRARY_NAME,
|
||||
QDCM_DIAG_CLIENT_LIBRARY_NAME);
|
||||
}
|
||||
} else {
|
||||
DLOGW("Unable to load = %s", QDCM_DIAG_CLIENT_LIBRARY_NAME);
|
||||
// only QDCM Diag client failed to be loaded and system still should function.
|
||||
}
|
||||
} else {
|
||||
DLOGE("Unable to create HWCColorManager");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return color_mgr;
|
||||
}
|
||||
|
||||
HWCColorManager::~HWCColorManager() {
|
||||
}
|
||||
|
||||
void HWCColorManager::DestroyColorManager() {
|
||||
if (qdcm_mode_mgr_) {
|
||||
delete qdcm_mode_mgr_;
|
||||
}
|
||||
if (qdcm_diag_deinit_) {
|
||||
qdcm_diag_deinit_();
|
||||
}
|
||||
if (diag_client_lib_) {
|
||||
::dlclose(diag_client_lib_);
|
||||
}
|
||||
if (color_apis_lib_) {
|
||||
::dlclose(color_apis_lib_);
|
||||
}
|
||||
delete this;
|
||||
}
|
||||
|
||||
int HWCColorManager::EnableQDCMMode(bool enable, HWCDisplay *hwc_display) {
|
||||
int ret = 0;
|
||||
|
||||
if (!qdcm_mode_mgr_) {
|
||||
qdcm_mode_mgr_ = HWCQDCMModeManager::CreateQDCMModeMgr();
|
||||
if (!qdcm_mode_mgr_) {
|
||||
DLOGE("Unable to create QDCM operating mode manager.");
|
||||
ret = -EFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
if (qdcm_mode_mgr_) {
|
||||
ret = qdcm_mode_mgr_->EnableQDCMMode(enable, hwc_display);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool HWCColorManager::SolidFillLayersPrepare(hwc_display_contents_1_t **displays,
|
||||
HWCDisplay *hwc_display) {
|
||||
SCOPE_LOCK(locker_);
|
||||
|
||||
// Query HWCColorManager if QDCM tool requesting SOLID_FILL mode.
|
||||
uint32_t solid_fill_color = Get8BitsARGBColorValue(solid_fill_params_);
|
||||
hwc_display_contents_1_t *layer_list = displays[HWC_DISPLAY_PRIMARY];
|
||||
|
||||
if (solid_fill_enable_ && solid_fill_layers_ && layer_list) {
|
||||
// 1. shallow copy HWC_FRAMEBUFFER_TARGET layer info solid fill layer list.
|
||||
solid_fill_layers_->hwLayers[1] = layer_list->hwLayers[layer_list->numHwLayers - 1];
|
||||
|
||||
// 2. continue the prepare<> on solid_fill_layers.
|
||||
hwc_display->Perform(HWCDisplayPrimary::SET_QDCM_SOLID_FILL_INFO, solid_fill_color);
|
||||
// TODO(user): Remove the display_contents generated here and
|
||||
// use the solid fill layer support in HWC2 to set this up
|
||||
// hwc_display->Prepare(solid_fill_layers_); // RECT info included.
|
||||
|
||||
// 3. Set HWC_OVERLAY to all SF layers before returning to framework.
|
||||
for (size_t i = 0; i < (layer_list->numHwLayers - 1); i++) {
|
||||
hwc_layer_1_t *layer = &layer_list->hwLayers[i];
|
||||
layer->compositionType = HWC_OVERLAY;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else if (!solid_fill_enable_) {
|
||||
hwc_display->Perform(HWCDisplayPrimary::UNSET_QDCM_SOLID_FILL_INFO, 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HWCColorManager::SolidFillLayersSet(hwc_display_contents_1_t **displays,
|
||||
HWCDisplay *hwc_display) {
|
||||
// Query HWCColorManager if QDCM tool requesting SOLID_FILL mode.
|
||||
SCOPE_LOCK(locker_);
|
||||
hwc_display_contents_1_t *layer_list = displays[HWC_DISPLAY_PRIMARY];
|
||||
if (solid_fill_enable_ && solid_fill_layers_ && layer_list) {
|
||||
// TODO(user): Present solid fill
|
||||
// hwc_display->Commit(solid_fill_layers_);
|
||||
|
||||
// SurfaceFlinger layer stack is dropped in solid fill case and replaced with local layer stack
|
||||
// Close acquire fence fds associated with SF layer stack
|
||||
// Close release/retire fence fds returned along with local layer stack
|
||||
for (size_t i = 0; i < (layer_list->numHwLayers - 1); i++) {
|
||||
int &fence_fd = layer_list->hwLayers[i].acquireFenceFd;
|
||||
if (fence_fd >= 0) {
|
||||
close(fence_fd);
|
||||
fence_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < (solid_fill_layers_->numHwLayers - 1); i++) {
|
||||
int &fence_fd = solid_fill_layers_->hwLayers[i].releaseFenceFd;
|
||||
if (fence_fd >= 0) {
|
||||
close(fence_fd);
|
||||
fence_fd = -1;
|
||||
}
|
||||
}
|
||||
if (solid_fill_layers_->retireFenceFd >= 0) {
|
||||
close(solid_fill_layers_->retireFenceFd);
|
||||
solid_fill_layers_->retireFenceFd = -1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int HWCColorManager::CreateSolidFillLayers(HWCDisplay *hwc_display) {
|
||||
int ret = 0;
|
||||
|
||||
if (!solid_fill_layers_) {
|
||||
uint32_t size = sizeof(hwc_display_contents_1) + kNumSolidFillLayers * sizeof(hwc_layer_1_t);
|
||||
uint32_t primary_width = 0;
|
||||
uint32_t primary_height = 0;
|
||||
|
||||
hwc_display->GetPanelResolution(&primary_width, &primary_height);
|
||||
uint8_t *buf = new uint8_t[size]();
|
||||
// handle for solid fill layer with fd = -1.
|
||||
private_handle_t *handle = new private_handle_t(-1, 0, private_handle_t::PRIV_FLAGS_FRAMEBUFFER,
|
||||
BUFFER_TYPE_UI, HAL_PIXEL_FORMAT_RGBA_8888,
|
||||
INT32(primary_width), INT32(primary_height));
|
||||
|
||||
if (!buf || !handle) {
|
||||
DLOGE("Failed to allocate memory.");
|
||||
if (buf)
|
||||
delete[] buf;
|
||||
if (handle)
|
||||
delete handle;
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
solid_fill_layers_ = reinterpret_cast<hwc_display_contents_1 *>(buf);
|
||||
hwc_layer_1_t &layer = solid_fill_layers_->hwLayers[0];
|
||||
layer.handle = handle;
|
||||
}
|
||||
|
||||
solid_fill_layers_->flags = HWC_GEOMETRY_CHANGED;
|
||||
solid_fill_layers_->numHwLayers = kNumSolidFillLayers;
|
||||
solid_fill_layers_->retireFenceFd = -1;
|
||||
solid_fill_layers_->outbuf = NULL;
|
||||
solid_fill_layers_->outbufAcquireFenceFd = -1;
|
||||
|
||||
hwc_layer_1_t &layer = solid_fill_layers_->hwLayers[0];
|
||||
hwc_rect_t solid_fill_rect = {
|
||||
INT(solid_fill_params_.rect.x), INT(solid_fill_params_.rect.y),
|
||||
solid_fill_params_.rect.x + INT(solid_fill_params_.rect.width),
|
||||
solid_fill_params_.rect.y + INT(solid_fill_params_.rect.height),
|
||||
};
|
||||
|
||||
layer.compositionType = HWC_FRAMEBUFFER;
|
||||
layer.blending = HWC_BLENDING_PREMULT;
|
||||
layer.sourceCropf.left = solid_fill_params_.rect.x;
|
||||
layer.sourceCropf.top = solid_fill_params_.rect.y;
|
||||
layer.sourceCropf.right = UINT32(solid_fill_params_.rect.x) + solid_fill_params_.rect.width;
|
||||
layer.sourceCropf.bottom = UINT32(solid_fill_params_.rect.y) + solid_fill_params_.rect.height;
|
||||
layer.acquireFenceFd = -1;
|
||||
layer.releaseFenceFd = -1;
|
||||
layer.flags = 0;
|
||||
layer.transform = 0;
|
||||
layer.hints = 0;
|
||||
layer.planeAlpha = 0xff;
|
||||
layer.displayFrame = solid_fill_rect;
|
||||
layer.visibleRegionScreen.numRects = 1;
|
||||
layer.visibleRegionScreen.rects = &layer.displayFrame;
|
||||
layer.surfaceDamage.numRects = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void HWCColorManager::DestroySolidFillLayers() {
|
||||
if (solid_fill_layers_) {
|
||||
hwc_layer_1_t &layer = solid_fill_layers_->hwLayers[0];
|
||||
uint8_t *buf = reinterpret_cast<uint8_t *>(solid_fill_layers_);
|
||||
private_handle_t const *hnd = reinterpret_cast<private_handle_t const *>(layer.handle);
|
||||
|
||||
if (hnd)
|
||||
delete hnd;
|
||||
|
||||
if (buf)
|
||||
delete[] buf;
|
||||
|
||||
solid_fill_layers_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int HWCColorManager::SetSolidFill(const void *params, bool enable, HWCDisplay *hwc_display) {
|
||||
SCOPE_LOCK(locker_);
|
||||
int ret = 0;
|
||||
|
||||
if (params) {
|
||||
solid_fill_params_ = *reinterpret_cast<const PPColorFillParams *>(params);
|
||||
} else {
|
||||
solid_fill_params_ = PPColorFillParams();
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
// will create solid fill layers for rendering if not present.
|
||||
ret = CreateSolidFillLayers(hwc_display);
|
||||
} else {
|
||||
DestroySolidFillLayers();
|
||||
}
|
||||
solid_fill_enable_ = enable;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int HWCColorManager::SetFrameCapture(void *params, bool enable, HWCDisplay *hwc_display) {
|
||||
SCOPE_LOCK(locker_);
|
||||
int ret = 0;
|
||||
|
||||
PPFrameCaptureData *frame_capture_data = reinterpret_cast<PPFrameCaptureData *>(params);
|
||||
|
||||
if (enable) {
|
||||
std::memset(&buffer_info, 0x00, sizeof(buffer_info));
|
||||
hwc_display->GetFrameBufferResolution(&buffer_info.buffer_config.width,
|
||||
&buffer_info.buffer_config.height);
|
||||
if (frame_capture_data->input_params.out_pix_format == PP_PIXEL_FORMAT_RGB_888) {
|
||||
buffer_info.buffer_config.format = kFormatRGB888;
|
||||
} else if (frame_capture_data->input_params.out_pix_format == PP_PIXEL_FORMAT_RGB_2101010) {
|
||||
// TODO(user): Complete the implementation
|
||||
DLOGE("RGB 10-bit format NOT supported");
|
||||
return -EFAULT;
|
||||
} else {
|
||||
DLOGE("Pixel-format: %d NOT support.", frame_capture_data->input_params.out_pix_format);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
buffer_info.buffer_config.buffer_count = 1;
|
||||
buffer_info.alloc_buffer_info.fd = -1;
|
||||
buffer_info.alloc_buffer_info.stride = 0;
|
||||
buffer_info.alloc_buffer_info.size = 0;
|
||||
|
||||
buffer_allocator_ = new HWCBufferAllocator();
|
||||
if (buffer_allocator_ == NULL) {
|
||||
DLOGE("Memory allocation for buffer_allocator_ FAILED");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = buffer_allocator_->AllocateBuffer(&buffer_info);
|
||||
if (ret != 0) {
|
||||
DLOGE("Buffer allocation failed. ret: %d", ret);
|
||||
delete[] buffer_allocator_;
|
||||
buffer_allocator_ = NULL;
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
void *buffer = mmap(NULL, buffer_info.alloc_buffer_info.size, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, buffer_info.alloc_buffer_info.fd, 0);
|
||||
|
||||
if (buffer == MAP_FAILED) {
|
||||
DLOGE("mmap failed. err = %d", errno);
|
||||
frame_capture_data->buffer = NULL;
|
||||
ret = buffer_allocator_->FreeBuffer(&buffer_info);
|
||||
delete[] buffer_allocator_;
|
||||
buffer_allocator_ = NULL;
|
||||
return -EFAULT;
|
||||
} else {
|
||||
frame_capture_data->buffer = reinterpret_cast<uint8_t *>(buffer);
|
||||
frame_capture_data->buffer_stride = buffer_info.alloc_buffer_info.stride;
|
||||
frame_capture_data->buffer_size = buffer_info.alloc_buffer_info.size;
|
||||
}
|
||||
// TODO(user): Call HWC interface to provide the buffer and rectangle information
|
||||
}
|
||||
} else {
|
||||
if (frame_capture_data->buffer != NULL) {
|
||||
if (munmap(frame_capture_data->buffer, buffer_info.alloc_buffer_info.size) != 0) {
|
||||
DLOGE("munmap failed. err = %d", errno);
|
||||
}
|
||||
}
|
||||
if (buffer_allocator_ != NULL) {
|
||||
std::memset(frame_capture_data, 0x00, sizeof(PPFrameCaptureData));
|
||||
ret = buffer_allocator_->FreeBuffer(&buffer_info);
|
||||
if (ret != 0) {
|
||||
DLOGE("FreeBuffer failed. ret = %d", ret);
|
||||
}
|
||||
delete[] buffer_allocator_;
|
||||
buffer_allocator_ = NULL;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
const HWCQDCMModeManager::ActiveFeatureCMD HWCQDCMModeManager::kActiveFeatureCMD[] = {
|
||||
HWCQDCMModeManager::ActiveFeatureCMD("cabl:on", "cabl:off", "cabl:status", "running"),
|
||||
HWCQDCMModeManager::ActiveFeatureCMD("ad:on", "ad:off", "ad:query:status", "running"),
|
||||
HWCQDCMModeManager::ActiveFeatureCMD("svi:on", "svi:off", "svi:status", "running"),
|
||||
};
|
||||
|
||||
const char *const HWCQDCMModeManager::kSocketName = "pps";
|
||||
const char *const HWCQDCMModeManager::kTagName = "surfaceflinger";
|
||||
const char *const HWCQDCMModeManager::kPackageName = "colormanager";
|
||||
|
||||
HWCQDCMModeManager *HWCQDCMModeManager::CreateQDCMModeMgr() {
|
||||
HWCQDCMModeManager *mode_mgr = new HWCQDCMModeManager();
|
||||
|
||||
if (!mode_mgr) {
|
||||
DLOGW("No memory to create HWCQDCMModeManager.");
|
||||
return NULL;
|
||||
} else {
|
||||
mode_mgr->socket_fd_ =
|
||||
::socket_local_client(kSocketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
|
||||
if (mode_mgr->socket_fd_ < 0) {
|
||||
// it should not be disastrous and we still can grab wakelock in QDCM mode.
|
||||
DLOGW("Unable to connect to dpps socket!");
|
||||
}
|
||||
|
||||
// retrieve system GPU idle timeout value for later to recover.
|
||||
mode_mgr->entry_timeout_ = UINT32(HWCDebugHandler::GetIdleTimeoutMs());
|
||||
|
||||
// acquire the binder handle to Android system PowerManager for later use.
|
||||
android::sp<android::IBinder> binder =
|
||||
android::defaultServiceManager()->checkService(android::String16("power"));
|
||||
if (binder == NULL) {
|
||||
DLOGW("Application can't connect to power manager service");
|
||||
delete mode_mgr;
|
||||
mode_mgr = NULL;
|
||||
} else {
|
||||
mode_mgr->power_mgr_ = android::interface_cast<android::IPowerManager>(binder);
|
||||
}
|
||||
}
|
||||
|
||||
return mode_mgr;
|
||||
}
|
||||
|
||||
HWCQDCMModeManager::~HWCQDCMModeManager() {
|
||||
if (socket_fd_ >= 0)
|
||||
::close(socket_fd_);
|
||||
}
|
||||
|
||||
int HWCQDCMModeManager::AcquireAndroidWakeLock(bool enable) {
|
||||
int ret = 0;
|
||||
|
||||
if (enable) {
|
||||
if (wakelock_token_ == NULL) {
|
||||
android::sp<android::IBinder> binder = new android::BBinder();
|
||||
android::status_t status = power_mgr_->acquireWakeLock(
|
||||
(kFullWakeLock | kAcquireCauseWakeup | kONAfterRelease), binder,
|
||||
android::String16(kTagName), android::String16(kPackageName));
|
||||
if (status == android::NO_ERROR) {
|
||||
wakelock_token_ = binder;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (wakelock_token_ != NULL && power_mgr_ != NULL) {
|
||||
power_mgr_->releaseWakeLock(wakelock_token_, 0);
|
||||
wakelock_token_.clear();
|
||||
wakelock_token_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int HWCQDCMModeManager::EnableActiveFeatures(bool enable,
|
||||
const HWCQDCMModeManager::ActiveFeatureCMD &cmds,
|
||||
bool *was_running) {
|
||||
int ret = 0;
|
||||
ssize_t size = 0;
|
||||
char response[kSocketCMDMaxLength] = {
|
||||
0,
|
||||
};
|
||||
|
||||
if (socket_fd_ < 0) {
|
||||
DLOGW("No socket connection available!");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (!enable) { // if client requesting to disable it.
|
||||
// query CABL status, if off, no action. keep the status.
|
||||
size = ::write(socket_fd_, cmds.cmd_query_status, strlen(cmds.cmd_query_status));
|
||||
if (size < 0) {
|
||||
DLOGW("Unable to send data over socket %s", ::strerror(errno));
|
||||
ret = -EFAULT;
|
||||
} else {
|
||||
size = ::read(socket_fd_, response, kSocketCMDMaxLength);
|
||||
if (size < 0) {
|
||||
DLOGW("Unable to read data over socket %s", ::strerror(errno));
|
||||
ret = -EFAULT;
|
||||
} else if (!strncmp(response, cmds.running, strlen(cmds.running))) {
|
||||
*was_running = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (*was_running) { // if was running, it's requested to disable it.
|
||||
size = ::write(socket_fd_, cmds.cmd_off, strlen(cmds.cmd_off));
|
||||
if (size < 0) {
|
||||
DLOGW("Unable to send data over socket %s", ::strerror(errno));
|
||||
ret = -EFAULT;
|
||||
}
|
||||
}
|
||||
} else { // if was running, need enable it back.
|
||||
if (*was_running) {
|
||||
size = ::write(socket_fd_, cmds.cmd_on, strlen(cmds.cmd_on));
|
||||
if (size < 0) {
|
||||
DLOGW("Unable to send data over socket %s", ::strerror(errno));
|
||||
ret = -EFAULT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int HWCQDCMModeManager::EnableQDCMMode(bool enable, HWCDisplay *hwc_display) {
|
||||
int ret = 0;
|
||||
|
||||
ret = EnableActiveFeatures((enable ? false : true), kActiveFeatureCMD[kCABLFeature],
|
||||
&cabl_was_running_);
|
||||
ret = AcquireAndroidWakeLock(enable);
|
||||
|
||||
// if enter QDCM mode, disable GPU fallback idle timeout.
|
||||
if (hwc_display) {
|
||||
uint32_t timeout = enable ? 0 : entry_timeout_;
|
||||
hwc_display->SetIdleTimeoutMs(timeout);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace sdm
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
|
||||
* Not a Contribution.
|
||||
*
|
||||
* Copyright 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __HWC_DISPLAY_H__
|
||||
#define __HWC_DISPLAY_H__
|
||||
|
||||
#include <hardware/hwcomposer.h>
|
||||
#include <core/core_interface.h>
|
||||
#include <qdMetaData.h>
|
||||
#include <QService.h>
|
||||
#include <private/color_params.h>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
#include "hwc_callbacks.h"
|
||||
#include "hwc_layers.h"
|
||||
|
||||
namespace sdm {
|
||||
|
||||
class BlitEngine;
|
||||
|
||||
// Subclasses set this to their type. This has to be different from DisplayType.
|
||||
// This is to avoid RTTI and dynamic_cast
|
||||
enum DisplayClass {
|
||||
DISPLAY_CLASS_PRIMARY,
|
||||
DISPLAY_CLASS_EXTERNAL,
|
||||
DISPLAY_CLASS_VIRTUAL,
|
||||
DISPLAY_CLASS_NULL
|
||||
};
|
||||
|
||||
class HWCDisplay : public DisplayEventHandler {
|
||||
public:
|
||||
virtual ~HWCDisplay() {}
|
||||
virtual int Init();
|
||||
virtual int Deinit();
|
||||
|
||||
// Framebuffer configurations
|
||||
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 DisplayError ControlPartialUpdate(bool enable, uint32_t *pending);
|
||||
virtual HWC2::PowerMode 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);
|
||||
virtual int OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level);
|
||||
virtual int Perform(uint32_t operation, ...);
|
||||
virtual void SetSecureDisplay(bool secure_display_active);
|
||||
|
||||
// Captures frame output in the buffer specified by output_buffer_info. The API is
|
||||
// non-blocking and the client is expected to check operation status later on.
|
||||
// Returns -1 if the input is invalid.
|
||||
virtual int FrameCaptureAsync(const BufferInfo &output_buffer_info, bool post_processed) {
|
||||
return -1;
|
||||
}
|
||||
// Returns the status of frame capture operation requested with FrameCaptureAsync().
|
||||
// -EAGAIN : No status obtain yet, call API again after another frame.
|
||||
// < 0 : Operation happened but failed.
|
||||
// 0 : Success.
|
||||
virtual int GetFrameCaptureStatus() { return -EAGAIN; }
|
||||
|
||||
// Display Configurations
|
||||
virtual int SetActiveDisplayConfig(int config);
|
||||
virtual int GetActiveDisplayConfig(uint32_t *config);
|
||||
virtual int GetDisplayConfigCount(uint32_t *count);
|
||||
virtual int GetDisplayAttributesForConfig(int config, DisplayConfigVariableInfo *attributes);
|
||||
|
||||
int SetPanelBrightness(int level);
|
||||
int GetPanelBrightness(int *level);
|
||||
int ToggleScreenUpdates(bool enable);
|
||||
int ColorSVCRequestRoute(const PPDisplayAPIPayload &in_payload, PPDisplayAPIPayload *out_payload,
|
||||
PPPendingParams *pending_action);
|
||||
DisplayClass GetDisplayClass();
|
||||
int GetVisibleDisplayRect(hwc_rect_t *rect);
|
||||
void BuildLayerStack(void);
|
||||
HWCLayer *GetHWCLayer(hwc2_layer_t layer);
|
||||
|
||||
// HWC2 APIs
|
||||
virtual HWC2::Error AcceptDisplayChanges(void);
|
||||
virtual HWC2::Error GetActiveConfig(hwc2_config_t *out_config);
|
||||
virtual HWC2::Error SetActiveConfig(hwc2_config_t config);
|
||||
virtual HWC2::Error SetClientTarget(buffer_handle_t target, int32_t acquire_fence,
|
||||
int32_t dataspace);
|
||||
virtual HWC2::Error GetDisplayConfigs(uint32_t *out_num_configs, hwc2_config_t *out_configs);
|
||||
virtual HWC2::Error GetDisplayAttribute(hwc2_config_t config, HWC2::Attribute attribute,
|
||||
int32_t *out_value);
|
||||
virtual HWC2::Error GetClientTargetSupport(uint32_t width, uint32_t height, int32_t format,
|
||||
int32_t dataspace);
|
||||
virtual HWC2::Error GetChangedCompositionTypes(uint32_t *out_num_elements,
|
||||
hwc2_layer_t *out_layers, int32_t *out_types);
|
||||
virtual HWC2::Error GetDisplayRequests(int32_t *out_display_requests, uint32_t *out_num_elements,
|
||||
hwc2_layer_t *out_layers, int32_t *out_layer_requests);
|
||||
virtual HWC2::Error GetDisplayName(uint32_t *out_size, char *out_name);
|
||||
virtual HWC2::Error GetDisplayType(int32_t *out_type);
|
||||
virtual HWC2::Error SetCursorPosition(hwc2_layer_t layer, int x, int y);
|
||||
virtual HWC2::Error SetVsyncEnabled(HWC2::Vsync enabled);
|
||||
virtual HWC2::Error SetPowerMode(HWC2::PowerMode mode);
|
||||
virtual HWC2::Error CreateLayer(hwc2_layer_t *out_layer_id);
|
||||
virtual HWC2::Error DestroyLayer(hwc2_layer_t layer_id);
|
||||
virtual HWC2::Error SetLayerZOrder(hwc2_layer_t layer_id, uint32_t z);
|
||||
virtual HWC2::Error Validate(uint32_t *out_num_types, uint32_t *out_num_requests) = 0;
|
||||
virtual HWC2::Error GetReleaseFences(uint32_t *out_num_elements, hwc2_layer_t *out_layers,
|
||||
int32_t *out_fences);
|
||||
virtual HWC2::Error Present(int32_t *out_retire_fence) = 0;
|
||||
|
||||
protected:
|
||||
enum DisplayStatus {
|
||||
kDisplayStatusOffline = 0,
|
||||
kDisplayStatusOnline,
|
||||
kDisplayStatusPause,
|
||||
kDisplayStatusResume,
|
||||
};
|
||||
|
||||
// Maximum number of layers supported by display manager.
|
||||
static const uint32_t kMaxLayerCount = 32;
|
||||
|
||||
HWCDisplay(CoreInterface *core_intf, HWCCallbacks *callbacks, DisplayType type, hwc2_display_t id,
|
||||
bool needs_blit, qService::QService *qservice, DisplayClass display_class);
|
||||
|
||||
// DisplayEventHandler methods
|
||||
virtual DisplayError VSync(const DisplayEventVSync &vsync);
|
||||
virtual DisplayError Refresh();
|
||||
virtual DisplayError CECMessage(char *message);
|
||||
virtual void DumpOutputBuffer(const BufferInfo &buffer_info, void *base, int fence);
|
||||
virtual HWC2::Error PrepareLayerStack(uint32_t *out_num_types, uint32_t *out_num_requests);
|
||||
virtual HWC2::Error CommitLayerStack(void);
|
||||
virtual HWC2::Error PostCommitLayerStack(int32_t *out_retire_fence);
|
||||
LayerBufferFormat GetSDMFormat(const int32_t &source, const int flags);
|
||||
const char *GetHALPixelFormatString(int format);
|
||||
const char *GetDisplayString();
|
||||
void ScaleDisplayFrame(hwc_rect_t *display_frame);
|
||||
void MarkLayersForGPUBypass(void);
|
||||
virtual void ApplyScanAdjustment(hwc_rect_t *display_frame);
|
||||
bool NeedsFrameBufferRefresh(void);
|
||||
bool SingleLayerUpdating(void);
|
||||
uint32_t SanitizeRefreshRate(uint32_t req_refresh_rate);
|
||||
virtual void CloseAcquireFds();
|
||||
|
||||
enum {
|
||||
INPUT_LAYER_DUMP,
|
||||
OUTPUT_LAYER_DUMP,
|
||||
};
|
||||
|
||||
CoreInterface *core_intf_;
|
||||
HWCCallbacks *callbacks_;
|
||||
DisplayType type_;
|
||||
hwc2_display_t id_;
|
||||
bool needs_blit_ = false;
|
||||
DisplayInterface *display_intf_ = NULL;
|
||||
LayerStack layer_stack_;
|
||||
HWCLayer *client_target_; // Also known as framebuffer target
|
||||
std::map<hwc2_layer_t, HWCLayer *> layer_map_; // Look up by Id - TODO
|
||||
std::multiset<HWCLayer *, SortLayersByZ> layer_set_; // Maintain a set sorted by Z
|
||||
std::map<hwc2_layer_t, HWC2::Composition> layer_changes_;
|
||||
std::map<hwc2_layer_t, HWC2::LayerRequest> layer_requests_;
|
||||
bool flush_on_error_ = false;
|
||||
bool flush_ = false;
|
||||
uint32_t dump_frame_count_ = 0;
|
||||
uint32_t dump_frame_index_ = 0;
|
||||
bool dump_input_layers_ = false;
|
||||
HWC2::PowerMode last_power_mode_;
|
||||
bool swap_interval_zero_ = false;
|
||||
DisplayConfigVariableInfo *framebuffer_config_ = NULL;
|
||||
bool display_paused_ = false;
|
||||
uint32_t min_refresh_rate_ = 0;
|
||||
uint32_t max_refresh_rate_ = 0;
|
||||
uint32_t current_refresh_rate_ = 0;
|
||||
bool use_metadata_refresh_rate_ = false;
|
||||
uint32_t metadata_refresh_rate_ = 0;
|
||||
uint32_t force_refresh_rate_ = 0;
|
||||
bool boot_animation_completed_ = false;
|
||||
bool shutdown_pending_ = false;
|
||||
bool use_blit_comp_ = false;
|
||||
bool secure_display_active_ = false;
|
||||
bool skip_prepare_ = false;
|
||||
bool solid_fill_enable_ = false;
|
||||
uint32_t solid_fill_color_ = 0;
|
||||
LayerRect display_rect_;
|
||||
bool validated_ = false;
|
||||
|
||||
private:
|
||||
bool IsFrameBufferScaled();
|
||||
void DumpInputBuffers(void);
|
||||
BlitEngine *blit_engine_ = NULL;
|
||||
qService::QService *qservice_ = NULL;
|
||||
DisplayClass display_class_;
|
||||
int32_t stored_retire_fence_;
|
||||
uint32_t geometry_changes_ = GeometryChanges::kNone;
|
||||
};
|
||||
|
||||
inline int HWCDisplay::Perform(uint32_t operation, ...) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace sdm
|
||||
|
||||
#endif // __HWC_DISPLAY_H__
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* Copyright (c) 2014 - 2016, 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 <utils/debug.h>
|
||||
|
||||
#include "hwc_display_external.h"
|
||||
#include "hwc_debugger.h"
|
||||
|
||||
#define __CLASS__ "HWCDisplayExternal"
|
||||
|
||||
namespace sdm {
|
||||
|
||||
int HWCDisplayExternal::Create(CoreInterface *core_intf, HWCCallbacks *callbacks,
|
||||
qService::QService *qservice, HWCDisplay **hwc_display) {
|
||||
return Create(core_intf, callbacks, 0, 0, qservice, false, hwc_display);
|
||||
}
|
||||
|
||||
int HWCDisplayExternal::Create(CoreInterface *core_intf, HWCCallbacks *callbacks,
|
||||
uint32_t primary_width, uint32_t primary_height,
|
||||
qService::QService *qservice, bool use_primary_res,
|
||||
HWCDisplay **hwc_display) {
|
||||
uint32_t external_width = 0;
|
||||
uint32_t external_height = 0;
|
||||
|
||||
HWCDisplay *hwc_display_external = new HWCDisplayExternal(core_intf, callbacks, qservice);
|
||||
int status = hwc_display_external->Init();
|
||||
if (status) {
|
||||
delete hwc_display_external;
|
||||
return status;
|
||||
}
|
||||
|
||||
hwc_display_external->GetPanelResolution(&external_width, &external_height);
|
||||
|
||||
if (primary_width && primary_height) {
|
||||
// use_primary_res means HWCDisplayExternal should directly set framebuffer resolution to the
|
||||
// provided primary_width and primary_height
|
||||
if (use_primary_res) {
|
||||
external_width = primary_width;
|
||||
external_height = primary_height;
|
||||
} else {
|
||||
int downscale_enabled = 0;
|
||||
HWCDebugHandler::Get()->GetProperty("sdm.debug.downscale_external", &downscale_enabled);
|
||||
if (downscale_enabled) {
|
||||
GetDownscaleResolution(primary_width, primary_height, &external_width, &external_height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
status = hwc_display_external->SetFrameBufferResolution(external_width, external_height);
|
||||
if (status) {
|
||||
Destroy(hwc_display_external);
|
||||
return status;
|
||||
}
|
||||
|
||||
*hwc_display = hwc_display_external;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void HWCDisplayExternal::Destroy(HWCDisplay *hwc_display) {
|
||||
hwc_display->Deinit();
|
||||
delete hwc_display;
|
||||
}
|
||||
|
||||
HWCDisplayExternal::HWCDisplayExternal(CoreInterface *core_intf, HWCCallbacks *callbacks,
|
||||
qService::QService *qservice)
|
||||
: HWCDisplay(core_intf, callbacks, kHDMI, HWC_DISPLAY_EXTERNAL, false, qservice,
|
||||
DISPLAY_CLASS_EXTERNAL) {
|
||||
}
|
||||
|
||||
HWC2::Error HWCDisplayExternal::Validate(uint32_t *out_num_types, uint32_t *out_num_requests) {
|
||||
auto status = HWC2::Error::None;
|
||||
|
||||
if (secure_display_active_) {
|
||||
MarkLayersForGPUBypass();
|
||||
return status;
|
||||
}
|
||||
|
||||
BuildLayerStack();
|
||||
|
||||
if (layer_set_.empty()) {
|
||||
flush_ = true;
|
||||
return status;
|
||||
}
|
||||
|
||||
status = PrepareLayerStack(out_num_types, out_num_requests);
|
||||
return status;
|
||||
}
|
||||
|
||||
HWC2::Error HWCDisplayExternal::Present(int32_t *out_retire_fence) {
|
||||
auto status = HWC2::Error::None;
|
||||
|
||||
if (!secure_display_active_) {
|
||||
status = HWCDisplay::CommitLayerStack();
|
||||
if (status == HWC2::Error::None) {
|
||||
status = HWCDisplay::PostCommitLayerStack(out_retire_fence);
|
||||
}
|
||||
}
|
||||
CloseAcquireFds();
|
||||
return status;
|
||||
}
|
||||
|
||||
void HWCDisplayExternal::ApplyScanAdjustment(hwc_rect_t *display_frame) {
|
||||
if (display_intf_->IsUnderscanSupported()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Read user defined width and height ratio
|
||||
int width = 0, height = 0;
|
||||
HWCDebugHandler::Get()->GetProperty("sdm.external_action_safe_width", &width);
|
||||
float width_ratio = FLOAT(width) / 100.0f;
|
||||
HWCDebugHandler::Get()->GetProperty("sdm.external_action_safe_height", &height);
|
||||
float height_ratio = FLOAT(height) / 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;
|
||||
}
|
||||
|
||||
uint32_t new_panel_width = UINT32(panel_width * FLOAT(1.0f - width_ratio));
|
||||
uint32_t new_panel_height = UINT32(panel_height * FLOAT(1.0f - height_ratio));
|
||||
|
||||
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 * INT32(new_panel_width) / INT32(panel_width)) + x_offset;
|
||||
display_frame->top =
|
||||
(display_frame->top * INT32(new_panel_height) / INT32(panel_height)) + y_offset;
|
||||
display_frame->right =
|
||||
((display_frame->right * INT32(new_panel_width)) / INT32(panel_width)) + x_offset;
|
||||
display_frame->bottom =
|
||||
((display_frame->bottom * INT32(new_panel_height)) / INT32(panel_height)) + y_offset;
|
||||
}
|
||||
|
||||
void HWCDisplayExternal::SetSecureDisplay(bool secure_display_active) {
|
||||
if (secure_display_active_ != secure_display_active) {
|
||||
secure_display_active_ = secure_display_active;
|
||||
|
||||
if (secure_display_active_) {
|
||||
DisplayError error = display_intf_->Flush();
|
||||
if (error != kErrorNone) {
|
||||
DLOGE("Flush failed. Error = %d", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void 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;
|
||||
}
|
||||
|
||||
void HWCDisplayExternal::GetDownscaleResolution(uint32_t primary_width, uint32_t primary_height,
|
||||
uint32_t *non_primary_width,
|
||||
uint32_t *non_primary_height) {
|
||||
uint32_t primary_area = primary_width * primary_height;
|
||||
uint32_t non_primary_area = (*non_primary_width) * (*non_primary_height);
|
||||
|
||||
if (primary_area > non_primary_area) {
|
||||
if (primary_height > primary_width) {
|
||||
Swap(primary_height, primary_width);
|
||||
}
|
||||
AdjustSourceResolution(primary_width, primary_height, non_primary_width, non_primary_height);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sdm
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2016, 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:
|
||||
static int Create(CoreInterface *core_intf, HWCCallbacks *callbacks, uint32_t primary_width,
|
||||
uint32_t primary_height, qService::QService *qservice, bool use_primary_res,
|
||||
HWCDisplay **hwc_display);
|
||||
static int Create(CoreInterface *core_intf, HWCCallbacks *callbacks, qService::QService *qservice,
|
||||
HWCDisplay **hwc_display);
|
||||
static void Destroy(HWCDisplay *hwc_display);
|
||||
virtual HWC2::Error Validate(uint32_t *out_num_types, uint32_t *out_num_requests);
|
||||
virtual HWC2::Error Present(int32_t *out_retire_fence);
|
||||
virtual void SetSecureDisplay(bool secure_display_active);
|
||||
|
||||
private:
|
||||
HWCDisplayExternal(CoreInterface *core_intf, HWCCallbacks *callbacks,
|
||||
qService::QService *qservice);
|
||||
void ApplyScanAdjustment(hwc_rect_t *display_frame);
|
||||
static void GetDownscaleResolution(uint32_t primary_width, uint32_t primary_height,
|
||||
uint32_t *virtual_width, uint32_t *virtual_height);
|
||||
};
|
||||
|
||||
} // namespace sdm
|
||||
|
||||
#endif // __HWC_DISPLAY_EXTERNAL_H__
|
|
@ -0,0 +1,471 @@
|
|||
/*
|
||||
* Copyright (c) 2014 - 2016, 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 <sync/sync.h>
|
||||
#include <utils/constants.h>
|
||||
#include <utils/debug.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "hwc_display_primary.h"
|
||||
#include "hwc_debugger.h"
|
||||
|
||||
#define __CLASS__ "HWCDisplayPrimary"
|
||||
|
||||
namespace sdm {
|
||||
|
||||
int HWCDisplayPrimary::Create(CoreInterface *core_intf, BufferAllocator *buffer_allocator,
|
||||
HWCCallbacks *callbacks, qService::QService *qservice,
|
||||
HWCDisplay **hwc_display) {
|
||||
int status = 0;
|
||||
uint32_t primary_width = 0;
|
||||
uint32_t primary_height = 0;
|
||||
|
||||
HWCDisplay *hwc_display_primary =
|
||||
new HWCDisplayPrimary(core_intf, buffer_allocator, callbacks, qservice);
|
||||
status = hwc_display_primary->Init();
|
||||
if (status) {
|
||||
delete hwc_display_primary;
|
||||
return status;
|
||||
}
|
||||
|
||||
hwc_display_primary->GetPanelResolution(&primary_width, &primary_height);
|
||||
int width = 0, height = 0;
|
||||
HWCDebugHandler::Get()->GetProperty("sdm.fb_size_width", &width);
|
||||
HWCDebugHandler::Get()->GetProperty("sdm.fb_size_height", &height);
|
||||
if (width > 0 && height > 0) {
|
||||
primary_width = UINT32(width);
|
||||
primary_height = UINT32(height);
|
||||
}
|
||||
|
||||
status = hwc_display_primary->SetFrameBufferResolution(primary_width, primary_height);
|
||||
if (status) {
|
||||
Destroy(hwc_display_primary);
|
||||
return status;
|
||||
}
|
||||
|
||||
*hwc_display = hwc_display_primary;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void HWCDisplayPrimary::Destroy(HWCDisplay *hwc_display) {
|
||||
hwc_display->Deinit();
|
||||
delete hwc_display;
|
||||
}
|
||||
|
||||
HWCDisplayPrimary::HWCDisplayPrimary(CoreInterface *core_intf, BufferAllocator *buffer_allocator,
|
||||
HWCCallbacks *callbacks, qService::QService *qservice)
|
||||
: HWCDisplay(core_intf, callbacks, kPrimary, HWC_DISPLAY_PRIMARY, true, qservice,
|
||||
DISPLAY_CLASS_PRIMARY),
|
||||
buffer_allocator_(buffer_allocator),
|
||||
cpu_hint_(NULL) {
|
||||
}
|
||||
|
||||
int HWCDisplayPrimary::Init() {
|
||||
cpu_hint_ = new CPUHint();
|
||||
if (cpu_hint_->Init(static_cast<HWCDebugHandler *>(HWCDebugHandler::Get())) != kErrorNone) {
|
||||
delete cpu_hint_;
|
||||
cpu_hint_ = NULL;
|
||||
}
|
||||
|
||||
use_metadata_refresh_rate_ = true;
|
||||
int disable_metadata_dynfps = 0;
|
||||
HWCDebugHandler::Get()->GetProperty("persist.metadata_dynfps.disable", &disable_metadata_dynfps);
|
||||
if (disable_metadata_dynfps) {
|
||||
use_metadata_refresh_rate_ = false;
|
||||
}
|
||||
|
||||
return HWCDisplay::Init();
|
||||
}
|
||||
|
||||
void HWCDisplayPrimary::ProcessBootAnimCompleted() {
|
||||
uint32_t numBootUpLayers = 0;
|
||||
// TODO(user): Remove this hack
|
||||
|
||||
numBootUpLayers = static_cast<uint32_t>(Debug::GetBootAnimLayerCount());
|
||||
|
||||
if (numBootUpLayers == 0) {
|
||||
numBootUpLayers = 2;
|
||||
}
|
||||
/* All other checks namely "init.svc.bootanim" or
|
||||
* HWC_GEOMETRY_CHANGED fail in correctly identifying the
|
||||
* exact bootup transition to homescreen
|
||||
*/
|
||||
char cryptoState[PROPERTY_VALUE_MAX];
|
||||
char voldDecryptState[PROPERTY_VALUE_MAX];
|
||||
bool isEncrypted = false;
|
||||
bool main_class_services_started = false;
|
||||
if (property_get("ro.crypto.state", cryptoState, "unencrypted")) {
|
||||
if (!strcmp(cryptoState, "encrypted")) {
|
||||
isEncrypted = true;
|
||||
if (property_get("vold.decrypt", voldDecryptState, "") &&
|
||||
!strcmp(voldDecryptState, "trigger_restart_framework"))
|
||||
main_class_services_started = true;
|
||||
}
|
||||
}
|
||||
if ((!isEncrypted || (isEncrypted && main_class_services_started)) &&
|
||||
(layer_set_.size() > numBootUpLayers)) {
|
||||
boot_animation_completed_ = true;
|
||||
// Applying default mode after bootanimation is finished And
|
||||
// If Data is Encrypted, it is ready for access.
|
||||
if (display_intf_)
|
||||
display_intf_->ApplyDefaultDisplayMode();
|
||||
}
|
||||
}
|
||||
|
||||
HWC2::Error HWCDisplayPrimary::Validate(uint32_t *out_num_types, uint32_t *out_num_requests) {
|
||||
auto status = HWC2::Error::None;
|
||||
DisplayError error = kErrorNone;
|
||||
|
||||
if (!boot_animation_completed_)
|
||||
ProcessBootAnimCompleted();
|
||||
|
||||
if (display_paused_) {
|
||||
MarkLayersForGPUBypass();
|
||||
return status;
|
||||
}
|
||||
|
||||
// Fill in the remaining blanks in the layers and add them to the SDM layerstack
|
||||
BuildLayerStack();
|
||||
|
||||
bool pending_output_dump = dump_frame_count_ && dump_output_to_file_;
|
||||
|
||||
if (frame_capture_buffer_queued_ || pending_output_dump) {
|
||||
// RHS values were set in FrameCaptureAsync() called from a binder thread. They are picked up
|
||||
// here in a subsequent draw round.
|
||||
layer_stack_.output_buffer = &output_buffer_;
|
||||
layer_stack_.flags.post_processed_output = post_processed_output_;
|
||||
}
|
||||
|
||||
bool one_updating_layer = SingleLayerUpdating();
|
||||
ToggleCPUHint(one_updating_layer);
|
||||
|
||||
uint32_t refresh_rate = GetOptimalRefreshRate(one_updating_layer);
|
||||
if (current_refresh_rate_ != refresh_rate) {
|
||||
error = display_intf_->SetRefreshRate(refresh_rate);
|
||||
}
|
||||
|
||||
if (error == kErrorNone) {
|
||||
// On success, set current refresh rate to new refresh rate
|
||||
current_refresh_rate_ = refresh_rate;
|
||||
}
|
||||
|
||||
if (handle_idle_timeout_) {
|
||||
handle_idle_timeout_ = false;
|
||||
}
|
||||
|
||||
// TODO(user): Validate this
|
||||
if (layer_set_.empty()) {
|
||||
flush_ = true;
|
||||
return status;
|
||||
}
|
||||
|
||||
status = PrepareLayerStack(out_num_types, out_num_requests);
|
||||
return status;
|
||||
}
|
||||
|
||||
HWC2::Error HWCDisplayPrimary::Present(int32_t *out_retire_fence) {
|
||||
auto status = HWC2::Error::None;
|
||||
if (display_paused_) {
|
||||
// TODO(user): From old HWC implementation
|
||||
// If we do not handle the frame set retireFenceFd to outbufAcquireFenceFd
|
||||
// Revisit this when validating display_paused
|
||||
DisplayError error = display_intf_->Flush();
|
||||
if (error != kErrorNone) {
|
||||
DLOGE("Flush failed. Error = %d", error);
|
||||
}
|
||||
} else {
|
||||
status = HWCDisplay::CommitLayerStack();
|
||||
if (status == HWC2::Error::None) {
|
||||
HandleFrameOutput();
|
||||
status = HWCDisplay::PostCommitLayerStack(out_retire_fence);
|
||||
}
|
||||
}
|
||||
CloseAcquireFds();
|
||||
return status;
|
||||
}
|
||||
|
||||
int HWCDisplayPrimary::Perform(uint32_t operation, ...) {
|
||||
va_list args;
|
||||
va_start(args, operation);
|
||||
int val = va_arg(args, int32_t);
|
||||
va_end(args);
|
||||
switch (operation) {
|
||||
case SET_METADATA_DYN_REFRESH_RATE:
|
||||
SetMetaDataRefreshRateFlag(val);
|
||||
break;
|
||||
case SET_BINDER_DYN_REFRESH_RATE:
|
||||
ForceRefreshRate(UINT32(val));
|
||||
break;
|
||||
case SET_DISPLAY_MODE:
|
||||
SetDisplayMode(UINT32(val));
|
||||
break;
|
||||
case SET_QDCM_SOLID_FILL_INFO:
|
||||
SetQDCMSolidFillInfo(true, UINT32(val));
|
||||
break;
|
||||
case UNSET_QDCM_SOLID_FILL_INFO:
|
||||
SetQDCMSolidFillInfo(false, UINT32(val));
|
||||
break;
|
||||
default:
|
||||
DLOGW("Invalid operation %d", operation);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DisplayError HWCDisplayPrimary::SetDisplayMode(uint32_t mode) {
|
||||
DisplayError error = kErrorNone;
|
||||
|
||||
if (display_intf_) {
|
||||
error = display_intf_->SetDisplayMode(mode);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void HWCDisplayPrimary::SetMetaDataRefreshRateFlag(bool enable) {
|
||||
int disable_metadata_dynfps = 0;
|
||||
|
||||
HWCDebugHandler::Get()->GetProperty("persist.metadata_dynfps.disable", &disable_metadata_dynfps);
|
||||
if (disable_metadata_dynfps) {
|
||||
return;
|
||||
}
|
||||
use_metadata_refresh_rate_ = enable;
|
||||
}
|
||||
|
||||
void HWCDisplayPrimary::SetQDCMSolidFillInfo(bool enable, uint32_t color) {
|
||||
solid_fill_enable_ = enable;
|
||||
solid_fill_color_ = color;
|
||||
}
|
||||
|
||||
void HWCDisplayPrimary::ToggleCPUHint(bool set) {
|
||||
if (!cpu_hint_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (set) {
|
||||
cpu_hint_->Set();
|
||||
} else {
|
||||
cpu_hint_->Reset();
|
||||
}
|
||||
}
|
||||
|
||||
void HWCDisplayPrimary::SetSecureDisplay(bool secure_display_active) {
|
||||
if (secure_display_active_ != secure_display_active) {
|
||||
// Skip Prepare and call Flush for null commit
|
||||
DLOGI("SecureDisplay state changed from %d to %d Needs Flush!!", secure_display_active_,
|
||||
secure_display_active);
|
||||
secure_display_active_ = secure_display_active;
|
||||
skip_prepare_ = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void HWCDisplayPrimary::ForceRefreshRate(uint32_t refresh_rate) {
|
||||
if ((refresh_rate && (refresh_rate < min_refresh_rate_ || refresh_rate > max_refresh_rate_)) ||
|
||||
force_refresh_rate_ == refresh_rate) {
|
||||
// Cannot honor force refresh rate, as its beyond the range or new request is same
|
||||
return;
|
||||
}
|
||||
|
||||
force_refresh_rate_ = refresh_rate;
|
||||
|
||||
callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t HWCDisplayPrimary::GetOptimalRefreshRate(bool one_updating_layer) {
|
||||
if (force_refresh_rate_) {
|
||||
return force_refresh_rate_;
|
||||
} else if (handle_idle_timeout_) {
|
||||
return min_refresh_rate_;
|
||||
} else if (use_metadata_refresh_rate_ && one_updating_layer && metadata_refresh_rate_) {
|
||||
return metadata_refresh_rate_;
|
||||
}
|
||||
|
||||
return max_refresh_rate_;
|
||||
}
|
||||
|
||||
DisplayError HWCDisplayPrimary::Refresh() {
|
||||
DisplayError error = kErrorNone;
|
||||
|
||||
callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
|
||||
handle_idle_timeout_ = true;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void HWCDisplayPrimary::SetIdleTimeoutMs(uint32_t timeout_ms) {
|
||||
display_intf_->SetIdleTimeoutMs(timeout_ms);
|
||||
}
|
||||
|
||||
static void SetLayerBuffer(const BufferInfo &output_buffer_info, LayerBuffer *output_buffer) {
|
||||
output_buffer->width = output_buffer_info.buffer_config.width;
|
||||
output_buffer->height = output_buffer_info.buffer_config.height;
|
||||
output_buffer->format = output_buffer_info.buffer_config.format;
|
||||
output_buffer->planes[0].fd = output_buffer_info.alloc_buffer_info.fd;
|
||||
output_buffer->planes[0].stride = output_buffer_info.alloc_buffer_info.stride;
|
||||
}
|
||||
|
||||
void HWCDisplayPrimary::HandleFrameOutput() {
|
||||
if (frame_capture_buffer_queued_) {
|
||||
HandleFrameCapture();
|
||||
} else if (dump_output_to_file_) {
|
||||
HandleFrameDump();
|
||||
}
|
||||
}
|
||||
|
||||
void HWCDisplayPrimary::HandleFrameCapture() {
|
||||
if (output_buffer_.release_fence_fd >= 0) {
|
||||
frame_capture_status_ = sync_wait(output_buffer_.release_fence_fd, 1000);
|
||||
::close(output_buffer_.release_fence_fd);
|
||||
output_buffer_.release_fence_fd = -1;
|
||||
}
|
||||
|
||||
frame_capture_buffer_queued_ = false;
|
||||
post_processed_output_ = false;
|
||||
output_buffer_ = {};
|
||||
|
||||
uint32_t pending = 0; // Just a temporary to satisfy the API
|
||||
ControlPartialUpdate(true /* enable */, &pending);
|
||||
}
|
||||
|
||||
void HWCDisplayPrimary::HandleFrameDump() {
|
||||
if (dump_frame_count_ && output_buffer_.release_fence_fd >= 0) {
|
||||
int ret = sync_wait(output_buffer_.release_fence_fd, 1000);
|
||||
::close(output_buffer_.release_fence_fd);
|
||||
output_buffer_.release_fence_fd = -1;
|
||||
if (ret < 0) {
|
||||
DLOGE("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
|
||||
} else {
|
||||
DumpOutputBuffer(output_buffer_info_, output_buffer_base_, layer_stack_.retire_fence_fd);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == dump_frame_count_) {
|
||||
dump_output_to_file_ = false;
|
||||
// Unmap and Free buffer
|
||||
if (munmap(output_buffer_base_, output_buffer_info_.alloc_buffer_info.size) != 0) {
|
||||
DLOGE("unmap failed with err %d", errno);
|
||||
}
|
||||
if (buffer_allocator_->FreeBuffer(&output_buffer_info_) != 0) {
|
||||
DLOGE("FreeBuffer failed");
|
||||
}
|
||||
|
||||
post_processed_output_ = false;
|
||||
output_buffer_ = {};
|
||||
output_buffer_info_ = {};
|
||||
output_buffer_base_ = nullptr;
|
||||
|
||||
uint32_t pending = 0; // Just a temporary to satisfy the API
|
||||
ControlPartialUpdate(true /* enable */, &pending);
|
||||
}
|
||||
}
|
||||
|
||||
void HWCDisplayPrimary::SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type) {
|
||||
HWCDisplay::SetFrameDumpConfig(count, bit_mask_layer_type);
|
||||
dump_output_to_file_ = bit_mask_layer_type & (1 << OUTPUT_LAYER_DUMP);
|
||||
DLOGI("output_layer_dump_enable %d", dump_output_to_file_);
|
||||
|
||||
if (!count || !dump_output_to_file_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Allocate and map output buffer
|
||||
output_buffer_info_ = {};
|
||||
// Since we dump DSPP output use Panel resolution.
|
||||
GetPanelResolution(&output_buffer_info_.buffer_config.width,
|
||||
&output_buffer_info_.buffer_config.height);
|
||||
output_buffer_info_.buffer_config.format = kFormatRGB888;
|
||||
output_buffer_info_.buffer_config.buffer_count = 1;
|
||||
if (buffer_allocator_->AllocateBuffer(&output_buffer_info_) != 0) {
|
||||
DLOGE("Buffer allocation failed");
|
||||
output_buffer_info_ = {};
|
||||
return;
|
||||
}
|
||||
|
||||
void *buffer = mmap(NULL, output_buffer_info_.alloc_buffer_info.size, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, output_buffer_info_.alloc_buffer_info.fd, 0);
|
||||
|
||||
if (buffer == MAP_FAILED) {
|
||||
DLOGE("mmap failed with err %d", errno);
|
||||
buffer_allocator_->FreeBuffer(&output_buffer_info_);
|
||||
output_buffer_info_ = {};
|
||||
return;
|
||||
}
|
||||
|
||||
output_buffer_base_ = buffer;
|
||||
post_processed_output_ = true;
|
||||
uint32_t pending = 0; // Just a temporary to satisfy the API
|
||||
ControlPartialUpdate(false /* enable */, &pending);
|
||||
}
|
||||
|
||||
int HWCDisplayPrimary::FrameCaptureAsync(const BufferInfo &output_buffer_info,
|
||||
bool post_processed_output) {
|
||||
// Note: This function is called in context of a binder thread and a lock is already held
|
||||
if (output_buffer_info.alloc_buffer_info.fd < 0) {
|
||||
DLOGE("Invalid fd %d", output_buffer_info.alloc_buffer_info.fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto panel_width = 0u;
|
||||
auto panel_height = 0u;
|
||||
auto fb_width = 0u;
|
||||
auto fb_height = 0u;
|
||||
|
||||
GetPanelResolution(&panel_width, &panel_height);
|
||||
GetFrameBufferResolution(&fb_width, &fb_height);
|
||||
|
||||
if (post_processed_output && (output_buffer_info_.buffer_config.width < panel_width ||
|
||||
output_buffer_info_.buffer_config.height < panel_height)) {
|
||||
DLOGE("Buffer dimensions should not be less than panel resolution");
|
||||
return -1;
|
||||
} else if (!post_processed_output && (output_buffer_info_.buffer_config.width < fb_width ||
|
||||
output_buffer_info_.buffer_config.height < fb_height)) {
|
||||
DLOGE("Buffer dimensions should not be less than FB resolution");
|
||||
return -1;
|
||||
}
|
||||
|
||||
SetLayerBuffer(output_buffer_info, &output_buffer_);
|
||||
post_processed_output_ = post_processed_output;
|
||||
frame_capture_buffer_queued_ = true;
|
||||
// Status is only cleared on a new call to dump and remains valid otherwise
|
||||
frame_capture_status_ = -EAGAIN;
|
||||
|
||||
uint32_t pending = 0; // Just a temporary to satisfy the API
|
||||
ControlPartialUpdate(false /* enable */, &pending);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace sdm
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2016, 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 "cpuhint.h"
|
||||
#include "hwc_display.h"
|
||||
|
||||
namespace sdm {
|
||||
|
||||
class HWCDisplayPrimary : public HWCDisplay {
|
||||
public:
|
||||
enum {
|
||||
SET_METADATA_DYN_REFRESH_RATE,
|
||||
SET_BINDER_DYN_REFRESH_RATE,
|
||||
SET_DISPLAY_MODE,
|
||||
SET_QDCM_SOLID_FILL_INFO,
|
||||
UNSET_QDCM_SOLID_FILL_INFO,
|
||||
};
|
||||
|
||||
static int Create(CoreInterface *core_intf, BufferAllocator *buffer_allocator,
|
||||
HWCCallbacks *callbacks, qService::QService *qservice,
|
||||
HWCDisplay **hwc_display);
|
||||
static void Destroy(HWCDisplay *hwc_display);
|
||||
virtual int Init();
|
||||
virtual HWC2::Error Validate(uint32_t *out_num_types, uint32_t *out_num_requests);
|
||||
virtual HWC2::Error Present(int32_t *out_retire_fence);
|
||||
virtual int Perform(uint32_t operation, ...);
|
||||
virtual void SetSecureDisplay(bool secure_display_active);
|
||||
virtual DisplayError Refresh();
|
||||
virtual void SetIdleTimeoutMs(uint32_t timeout_ms);
|
||||
virtual void SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type);
|
||||
virtual int FrameCaptureAsync(const BufferInfo &output_buffer_info, bool post_processed);
|
||||
virtual int GetFrameCaptureStatus() { return frame_capture_status_; }
|
||||
|
||||
private:
|
||||
HWCDisplayPrimary(CoreInterface *core_intf, BufferAllocator *buffer_allocator,
|
||||
HWCCallbacks *callbacks, qService::QService *qservice);
|
||||
void SetMetaDataRefreshRateFlag(bool enable);
|
||||
virtual DisplayError SetDisplayMode(uint32_t mode);
|
||||
void ProcessBootAnimCompleted(void);
|
||||
void SetQDCMSolidFillInfo(bool enable, uint32_t color);
|
||||
void ToggleCPUHint(bool set);
|
||||
void ForceRefreshRate(uint32_t refresh_rate);
|
||||
uint32_t GetOptimalRefreshRate(bool one_updating_layer);
|
||||
void HandleFrameOutput();
|
||||
void HandleFrameCapture();
|
||||
void HandleFrameDump();
|
||||
|
||||
BufferAllocator *buffer_allocator_ = nullptr;
|
||||
CPUHint *cpu_hint_ = nullptr;
|
||||
bool handle_idle_timeout_ = false;
|
||||
|
||||
// Primary output buffer configuration
|
||||
LayerBuffer output_buffer_ = {};
|
||||
bool post_processed_output_ = false;
|
||||
|
||||
// Members for 1 frame capture in a client provided buffer
|
||||
bool frame_capture_buffer_queued_ = false;
|
||||
int frame_capture_status_ = -EAGAIN;
|
||||
|
||||
// Members for N frame output dump to file
|
||||
bool dump_output_to_file_ = false;
|
||||
BufferInfo output_buffer_info_ = {};
|
||||
void *output_buffer_base_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace sdm
|
||||
|
||||
#endif // __HWC_DISPLAY_PRIMARY_H__
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* Copyright (c) 2014 - 2016, 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 <sync/sync.h>
|
||||
#include <stdarg.h>
|
||||
#include <gr.h>
|
||||
|
||||
#include "hwc_display_virtual.h"
|
||||
#include "hwc_debugger.h"
|
||||
|
||||
#define __CLASS__ "HWCDisplayVirtual"
|
||||
|
||||
namespace sdm {
|
||||
|
||||
int HWCDisplayVirtual::Create(CoreInterface *core_intf, HWCCallbacks *callbacks, uint32_t width,
|
||||
uint32_t height, HWCDisplay **hwc_display) {
|
||||
int status = 0;
|
||||
HWCDisplayVirtual *hwc_display_virtual = new HWCDisplayVirtual(core_intf, callbacks);
|
||||
uint32_t virtual_width = 0, virtual_height = 0;
|
||||
|
||||
status = hwc_display_virtual->Init();
|
||||
if (status) {
|
||||
delete hwc_display_virtual;
|
||||
return status;
|
||||
}
|
||||
|
||||
status = INT32(hwc_display_virtual->SetPowerMode(HWC2::PowerMode::On));
|
||||
if (status) {
|
||||
Destroy(hwc_display_virtual);
|
||||
return status;
|
||||
}
|
||||
|
||||
hwc_display_virtual->GetPanelResolution(&virtual_width, &virtual_height);
|
||||
|
||||
status = hwc_display_virtual->SetFrameBufferResolution(width, height);
|
||||
|
||||
if (status) {
|
||||
Destroy(hwc_display_virtual);
|
||||
return status;
|
||||
}
|
||||
|
||||
*hwc_display = static_cast<HWCDisplay *>(hwc_display_virtual);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void HWCDisplayVirtual::Destroy(HWCDisplay *hwc_display) {
|
||||
hwc_display->Deinit();
|
||||
delete hwc_display;
|
||||
}
|
||||
|
||||
HWCDisplayVirtual::HWCDisplayVirtual(CoreInterface *core_intf, HWCCallbacks *callbacks)
|
||||
: HWCDisplay(core_intf, callbacks, kVirtual, HWC_DISPLAY_VIRTUAL, false, NULL,
|
||||
DISPLAY_CLASS_VIRTUAL) {
|
||||
}
|
||||
|
||||
int HWCDisplayVirtual::Init() {
|
||||
return HWCDisplay::Init();
|
||||
}
|
||||
|
||||
int HWCDisplayVirtual::Deinit() {
|
||||
int status = 0;
|
||||
|
||||
status = HWCDisplay::Deinit();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
HWC2::Error HWCDisplayVirtual::Validate(uint32_t *out_num_types, uint32_t *out_num_requests) {
|
||||
auto status = HWC2::Error::None;
|
||||
|
||||
if (display_paused_) {
|
||||
MarkLayersForGPUBypass();
|
||||
return status;
|
||||
}
|
||||
|
||||
BuildLayerStack();
|
||||
status = PrepareLayerStack(out_num_types, out_num_requests);
|
||||
return status;
|
||||
}
|
||||
|
||||
HWC2::Error HWCDisplayVirtual::Present(int32_t *out_retire_fence) {
|
||||
auto status = HWC2::Error::None;
|
||||
if (display_paused_) {
|
||||
DisplayError error = display_intf_->Flush();
|
||||
if (error != kErrorNone) {
|
||||
DLOGE("Flush failed. Error = %d", error);
|
||||
}
|
||||
} else {
|
||||
status = HWCDisplay::CommitLayerStack();
|
||||
if (status == HWC2::Error::None) {
|
||||
if (dump_frame_count_ && !flush_ && dump_output_layer_) {
|
||||
if (output_handle_ && output_handle_->base) {
|
||||
BufferInfo buffer_info;
|
||||
const private_handle_t *output_handle =
|
||||
reinterpret_cast<const private_handle_t *>(output_buffer_->buffer_id);
|
||||
buffer_info.buffer_config.width = static_cast<uint32_t>(output_handle->width);
|
||||
buffer_info.buffer_config.height = static_cast<uint32_t>(output_handle->height);
|
||||
buffer_info.buffer_config.format =
|
||||
GetSDMFormat(output_handle->format, output_handle->flags);
|
||||
buffer_info.alloc_buffer_info.size = static_cast<uint32_t>(output_handle->size);
|
||||
DumpOutputBuffer(buffer_info, reinterpret_cast<void *>(output_handle->base),
|
||||
layer_stack_.retire_fence_fd);
|
||||
}
|
||||
}
|
||||
|
||||
status = HWCDisplay::PostCommitLayerStack(out_retire_fence);
|
||||
}
|
||||
}
|
||||
CloseAcquireFds();
|
||||
return status;
|
||||
}
|
||||
|
||||
HWC2::Error HWCDisplayVirtual::SetOutputBuffer(buffer_handle_t buf, int32_t release_fence) {
|
||||
const private_handle_t *output_handle = static_cast<const private_handle_t *>(buf);
|
||||
|
||||
// Fill output buffer parameters (width, height, format, plane information, fence)
|
||||
output_buffer_->acquire_fence_fd = dup(release_fence);
|
||||
|
||||
if (output_handle) {
|
||||
output_buffer_->buffer_id = reinterpret_cast<uint64_t>(output_handle);
|
||||
int output_handle_format = output_handle->format;
|
||||
|
||||
if (output_handle_format == HAL_PIXEL_FORMAT_RGBA_8888) {
|
||||
output_handle_format = HAL_PIXEL_FORMAT_RGBX_8888;
|
||||
}
|
||||
|
||||
output_buffer_->format = GetSDMFormat(output_handle_format, output_handle->flags);
|
||||
|
||||
if (output_buffer_->format == kFormatInvalid) {
|
||||
return HWC2::Error::BadParameter;
|
||||
}
|
||||
|
||||
int output_buffer_width, output_buffer_height;
|
||||
AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(output_handle, output_buffer_width,
|
||||
output_buffer_height);
|
||||
|
||||
output_buffer_->width = UINT32(output_buffer_width);
|
||||
output_buffer_->height = UINT32(output_buffer_height);
|
||||
// TODO(mkavm): Handle DRC and metadata changes
|
||||
output_buffer_->flags.secure = 0;
|
||||
output_buffer_->flags.video = 0;
|
||||
|
||||
// TZ Protected Buffer - L1
|
||||
if (output_handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
|
||||
output_buffer_->flags.secure = 1;
|
||||
}
|
||||
|
||||
// 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 = UINT32(output_handle->width);
|
||||
}
|
||||
|
||||
layer_stack_.output_buffer = output_buffer_;
|
||||
return HWC2::Error::None;
|
||||
}
|
||||
|
||||
void HWCDisplayVirtual::SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type) {
|
||||
HWCDisplay::SetFrameDumpConfig(count, bit_mask_layer_type);
|
||||
dump_output_layer_ = ((bit_mask_layer_type & (1 << OUTPUT_LAYER_DUMP)) != 0);
|
||||
|
||||
DLOGI("output_layer_dump_enable %d", dump_output_layer_);
|
||||
}
|
||||
|
||||
} // namespace sdm
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2016, 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:
|
||||
static int Create(CoreInterface *core_intf, HWCCallbacks *callbacks, uint32_t primary_width,
|
||||
uint32_t primary_height, HWCDisplay **hwc_display);
|
||||
static void Destroy(HWCDisplay *hwc_display);
|
||||
virtual int Init();
|
||||
virtual int Deinit();
|
||||
virtual HWC2::Error Validate(uint32_t *out_num_types, uint32_t *out_num_requests);
|
||||
virtual HWC2::Error Present(int32_t *out_retire_fence);
|
||||
virtual void SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type);
|
||||
HWC2::Error SetOutputBuffer(buffer_handle_t buf, int32_t release_fence);
|
||||
|
||||
private:
|
||||
HWCDisplayVirtual(CoreInterface *core_intf, HWCCallbacks *callbacks);
|
||||
|
||||
bool dump_output_layer_ = false;
|
||||
LayerBuffer *output_buffer_ = NULL;
|
||||
const private_handle_t *output_handle_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace sdm
|
||||
|
||||
#endif // __HWC_DISPLAY_VIRTUAL_H__
|
|
@ -0,0 +1,500 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
|
||||
* Not a Contribution.
|
||||
*
|
||||
* Copyright 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "hwc_layers.h"
|
||||
#include <gr.h>
|
||||
#include <utils/debug.h>
|
||||
#include <cmath>
|
||||
|
||||
#define __CLASS__ "HWCLayer"
|
||||
|
||||
namespace sdm {
|
||||
|
||||
bool SortLayersByZ::operator()(const HWCLayer *lhs, const HWCLayer *rhs) {
|
||||
return lhs->GetZ() < rhs->GetZ();
|
||||
}
|
||||
|
||||
std::atomic<hwc2_layer_t> HWCLayer::next_id_(1);
|
||||
|
||||
// Layer operations
|
||||
HWCLayer::HWCLayer(hwc2_display_t display_id) : id_(next_id_++), display_id_(display_id) {
|
||||
layer_ = new Layer();
|
||||
layer_->input_buffer = new LayerBuffer();
|
||||
// Fences are deferred, so the first time this layer is presented, return -1
|
||||
// TODO(user): Verify that fences are properly obtained on suspend/resume
|
||||
release_fences_.push(-1);
|
||||
}
|
||||
|
||||
HWCLayer::~HWCLayer() {
|
||||
// Close any fences left for this layer
|
||||
while (!release_fences_.empty()) {
|
||||
close(release_fences_.front());
|
||||
release_fences_.pop();
|
||||
}
|
||||
|
||||
if (layer_) {
|
||||
if (layer_->input_buffer) {
|
||||
delete (layer_->input_buffer);
|
||||
}
|
||||
delete layer_;
|
||||
}
|
||||
}
|
||||
|
||||
HWC2::Error HWCLayer::SetLayerBuffer(buffer_handle_t buffer, int32_t acquire_fence) {
|
||||
if (!buffer) {
|
||||
DLOGE("Invalid buffer handle: %p on layer: %d", buffer, id_);
|
||||
return HWC2::Error::BadParameter;
|
||||
}
|
||||
|
||||
const private_handle_t *handle = static_cast<const private_handle_t *>(buffer);
|
||||
LayerBuffer *layer_buffer = layer_->input_buffer;
|
||||
layer_buffer->width = UINT32(handle->width);
|
||||
layer_buffer->height = UINT32(handle->height);
|
||||
layer_buffer->format = GetSDMFormat(handle->format, handle->flags);
|
||||
if (SetMetaData(handle, layer_) != kErrorNone) {
|
||||
return HWC2::Error::BadLayer;
|
||||
}
|
||||
|
||||
if (handle->bufferType == BUFFER_TYPE_VIDEO) {
|
||||
layer_buffer->flags.video = true;
|
||||
}
|
||||
// TZ Protected Buffer - L1
|
||||
if (handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
|
||||
layer_buffer->flags.secure = true;
|
||||
}
|
||||
if (handle->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY) {
|
||||
layer_buffer->flags.secure_display = true;
|
||||
}
|
||||
|
||||
layer_buffer->planes[0].fd = handle->fd;
|
||||
layer_buffer->planes[0].offset = handle->offset;
|
||||
layer_buffer->planes[0].stride = UINT32(handle->width);
|
||||
layer_buffer->acquire_fence_fd = acquire_fence;
|
||||
layer_buffer->buffer_id = reinterpret_cast<uint64_t>(handle);
|
||||
|
||||
return HWC2::Error::None;
|
||||
}
|
||||
|
||||
HWC2::Error HWCLayer::SetLayerSurfaceDamage(hwc_region_t damage) {
|
||||
auto num_dirty_rects = damage.numRects;
|
||||
if (num_dirty_rects > 0) {
|
||||
for (uint32_t i = 0; i <= damage.numRects; i++) {
|
||||
LayerRect rect;
|
||||
SetRect(damage.rects[i], &rect);
|
||||
layer_->dirty_regions.push_back(rect);
|
||||
}
|
||||
}
|
||||
return HWC2::Error::None;
|
||||
}
|
||||
|
||||
HWC2::Error HWCLayer::SetLayerBlendMode(HWC2::BlendMode mode) {
|
||||
switch (mode) {
|
||||
case HWC2::BlendMode::Coverage:
|
||||
layer_->blending = kBlendingCoverage;
|
||||
break;
|
||||
case HWC2::BlendMode::Premultiplied:
|
||||
layer_->blending = kBlendingPremultiplied;
|
||||
break;
|
||||
case HWC2::BlendMode::None:
|
||||
layer_->blending = kBlendingOpaque;
|
||||
break;
|
||||
default:
|
||||
return HWC2::Error::BadParameter;
|
||||
}
|
||||
geometry_changes_ |= kBlendMode;
|
||||
return HWC2::Error::None;
|
||||
}
|
||||
|
||||
HWC2::Error HWCLayer::SetLayerColor(hwc_color_t color) {
|
||||
layer_->solid_fill_color = GetUint32Color(color);
|
||||
layer_->input_buffer->format = kFormatARGB8888;
|
||||
DLOGD("Layer color set to: %u", layer_->solid_fill_color);
|
||||
DLOGD("[%" PRIu64 "][%" PRIu64 "] Layer color set to %u %" PRIu64, display_id_, id_,
|
||||
layer_->solid_fill_color);
|
||||
return HWC2::Error::None;
|
||||
}
|
||||
|
||||
HWC2::Error HWCLayer::SetLayerCompositionType(HWC2::Composition type) {
|
||||
layer_->flags = {}; // Reset earlier flags
|
||||
composition_ = type; // Used to compute changes
|
||||
switch (type) {
|
||||
case HWC2::Composition::Client:
|
||||
layer_->flags.skip = true;
|
||||
break;
|
||||
case HWC2::Composition::Device:
|
||||
// We try and default to this in SDM
|
||||
break;
|
||||
case HWC2::Composition::SolidColor:
|
||||
layer_->flags.solid_fill = true;
|
||||
break;
|
||||
case HWC2::Composition::Cursor:
|
||||
layer_->flags.cursor = true;
|
||||
break;
|
||||
case HWC2::Composition::Invalid:
|
||||
return HWC2::Error::BadParameter;
|
||||
default:
|
||||
return HWC2::Error::Unsupported;
|
||||
}
|
||||
// TODO(user): Check if this should be set here or somewhere else
|
||||
layer_->flags.updating = true;
|
||||
return HWC2::Error::None;
|
||||
}
|
||||
|
||||
HWC2::Error HWCLayer::SetLayerDataspace(int32_t dataspace) {
|
||||
// TODO(user): Implement later
|
||||
geometry_changes_ |= kDataspace;
|
||||
return HWC2::Error::None;
|
||||
}
|
||||
|
||||
HWC2::Error HWCLayer::SetLayerDisplayFrame(hwc_rect_t frame) {
|
||||
SetRect(frame, &layer_->dst_rect);
|
||||
geometry_changes_ |= kDisplayFrame;
|
||||
return HWC2::Error::None;
|
||||
}
|
||||
|
||||
HWC2::Error HWCLayer::SetLayerPlaneAlpha(float alpha) {
|
||||
// Conversion of float alpha in range 0.0 to 1.0 similar to the HWC Adapter
|
||||
layer_->plane_alpha = static_cast<uint8_t>(255.0f * alpha + 0.5f);
|
||||
geometry_changes_ |= kPlaneAlpha;
|
||||
return HWC2::Error::None;
|
||||
}
|
||||
|
||||
HWC2::Error HWCLayer::SetLayerSourceCrop(hwc_frect_t crop) {
|
||||
SetRect(crop, &layer_->src_rect);
|
||||
geometry_changes_ |= kSourceCrop;
|
||||
return HWC2::Error::None;
|
||||
}
|
||||
|
||||
HWC2::Error HWCLayer::SetLayerTransform(HWC2::Transform transform) {
|
||||
switch (transform) {
|
||||
case HWC2::Transform::FlipH:
|
||||
layer_->transform.flip_horizontal = true;
|
||||
break;
|
||||
case HWC2::Transform::FlipV:
|
||||
layer_->transform.flip_vertical = true;
|
||||
break;
|
||||
case HWC2::Transform::Rotate90:
|
||||
layer_->transform.rotation = 90.0f;
|
||||
break;
|
||||
case HWC2::Transform::Rotate180:
|
||||
layer_->transform.rotation = 180.0f;
|
||||
break;
|
||||
case HWC2::Transform::Rotate270:
|
||||
layer_->transform.rotation = 270.0f;
|
||||
break;
|
||||
case HWC2::Transform::FlipHRotate90:
|
||||
layer_->transform.rotation = 90.0f;
|
||||
layer_->transform.flip_horizontal = true;
|
||||
break;
|
||||
case HWC2::Transform::FlipVRotate90:
|
||||
layer_->transform.rotation = 90.0f;
|
||||
layer_->transform.flip_vertical = true;
|
||||
break;
|
||||
default:
|
||||
layer_->transform.rotation = 0.0f;
|
||||
layer_->transform.flip_horizontal = false;
|
||||
layer_->transform.flip_vertical = false;
|
||||
}
|
||||
geometry_changes_ |= kTransform;
|
||||
return HWC2::Error::None;
|
||||
}
|
||||
|
||||
HWC2::Error HWCLayer::SetLayerVisibleRegion(hwc_region_t visible) {
|
||||
auto num_dirty_rects = visible.numRects;
|
||||
if (num_dirty_rects > 0) {
|
||||
for (uint32_t i = 0; i <= visible.numRects; i++) {
|
||||
LayerRect rect;
|
||||
SetRect(visible.rects[i], &rect);
|
||||
layer_->visible_regions.push_back(rect);
|
||||
}
|
||||
}
|
||||
|
||||
return HWC2::Error::None;
|
||||
}
|
||||
|
||||
HWC2::Error HWCLayer::SetLayerZOrder(uint32_t z) {
|
||||
z_ = z;
|
||||
geometry_changes_ |= kZOrder;
|
||||
return HWC2::Error::None;
|
||||
}
|
||||
|
||||
void HWCLayer::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 HWCLayer::SetRect(const hwc_frect_t &source, LayerRect *target) {
|
||||
// Recommended way of rounding as in hwcomposer2.h - SetLayerSourceCrop
|
||||
target->left = std::ceil(source.left);
|
||||
target->top = std::ceil(source.top);
|
||||
target->right = std::floor(source.right);
|
||||
target->bottom = std::floor(source.bottom);
|
||||
}
|
||||
|
||||
uint32_t HWCLayer::GetUint32Color(const hwc_color_t &source) {
|
||||
// Returns 32 bit ARGB
|
||||
uint32_t a = UINT32(source.a) << 24;
|
||||
uint32_t r = UINT32(source.r) << 16;
|
||||
uint32_t g = UINT32(source.g) << 8;
|
||||
uint32_t b = UINT32(source.b);
|
||||
uint32_t color = a & r & g & b;
|
||||
return color;
|
||||
}
|
||||
|
||||
LayerBufferFormat HWCLayer::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_BGR_565:
|
||||
format = kFormatBGR565Ubwc;
|
||||
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_BGR_565:
|
||||
format = kFormatBGR565;
|
||||
break;
|
||||
case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
|
||||
case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
|
||||
format = kFormatYCbCr420SemiPlanarVenus;
|
||||
break;
|
||||
case HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS:
|
||||
format = kFormatYCrCb420SemiPlanarVenus;
|
||||
break;
|
||||
case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC:
|
||||
format = kFormatYCbCr420SPVenusUbwc;
|
||||
break;
|
||||
case HAL_PIXEL_FORMAT_YV12:
|
||||
format = kFormatYCrCb420PlanarStride16;
|
||||
break;
|
||||
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
|
||||
format = kFormatYCrCb420SemiPlanar;
|
||||
break;
|
||||
case HAL_PIXEL_FORMAT_YCbCr_420_SP:
|
||||
format = kFormatYCbCr420SemiPlanar;
|
||||
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;
|
||||
}
|
||||
|
||||
LayerBufferS3DFormat HWCLayer::GetS3DFormat(uint32_t s3d_format) {
|
||||
LayerBufferS3DFormat sdm_s3d_format = kS3dFormatNone;
|
||||
switch (s3d_format) {
|
||||
case HAL_NO_3D:
|
||||
sdm_s3d_format = kS3dFormatNone;
|
||||
break;
|
||||
case HAL_3D_SIDE_BY_SIDE_L_R:
|
||||
sdm_s3d_format = kS3dFormatLeftRight;
|
||||
break;
|
||||
case HAL_3D_SIDE_BY_SIDE_R_L:
|
||||
sdm_s3d_format = kS3dFormatRightLeft;
|
||||
break;
|
||||
case HAL_3D_TOP_BOTTOM:
|
||||
sdm_s3d_format = kS3dFormatTopBottom;
|
||||
break;
|
||||
default:
|
||||
DLOGW("Invalid S3D format %d", s3d_format);
|
||||
}
|
||||
return sdm_s3d_format;
|
||||
}
|
||||
|
||||
DisplayError HWCLayer::SetMetaData(const private_handle_t *pvt_handle, Layer *layer) {
|
||||
const MetaData_t *meta_data = reinterpret_cast<MetaData_t *>(pvt_handle->base_metadata);
|
||||
LayerBuffer *layer_buffer = layer->input_buffer;
|
||||
|
||||
if (!meta_data) {
|
||||
return kErrorNone;
|
||||
}
|
||||
|
||||
if (meta_data->operation & UPDATE_COLOR_SPACE) {
|
||||
if (SetCSC(meta_data->colorSpace, &layer->csc) != kErrorNone) {
|
||||
return kErrorNotSupported;
|
||||
}
|
||||
}
|
||||
|
||||
if (meta_data->operation & SET_IGC) {
|
||||
if (SetIGC(meta_data->igc, &layer->igc) != kErrorNone) {
|
||||
return kErrorNotSupported;
|
||||
}
|
||||
}
|
||||
|
||||
if (meta_data->operation & UPDATE_REFRESH_RATE) {
|
||||
layer->frame_rate = RoundToStandardFPS(meta_data->refreshrate);
|
||||
}
|
||||
|
||||
if ((meta_data->operation & PP_PARAM_INTERLACED) && meta_data->interlaced) {
|
||||
layer_buffer->flags.interlace = true;
|
||||
}
|
||||
|
||||
if (meta_data->operation & LINEAR_FORMAT) {
|
||||
layer_buffer->format = GetSDMFormat(INT32(meta_data->linearFormat), 0);
|
||||
}
|
||||
|
||||
if (meta_data->operation & UPDATE_BUFFER_GEOMETRY) {
|
||||
int actual_width = pvt_handle->width;
|
||||
int actual_height = pvt_handle->height;
|
||||
AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(pvt_handle, actual_width, actual_height);
|
||||
layer_buffer->width = UINT32(actual_width);
|
||||
layer_buffer->height = UINT32(actual_height);
|
||||
}
|
||||
|
||||
if (meta_data->operation & S3D_FORMAT) {
|
||||
layer_buffer->s3d_format = GetS3DFormat(meta_data->s3dFormat);
|
||||
}
|
||||
|
||||
return kErrorNone;
|
||||
}
|
||||
|
||||
DisplayError HWCLayer::SetCSC(ColorSpace_t source, LayerCSC *target) {
|
||||
switch (source) {
|
||||
case ITU_R_601:
|
||||
*target = kCSCLimitedRange601;
|
||||
break;
|
||||
case ITU_R_601_FR:
|
||||
*target = kCSCFullRange601;
|
||||
break;
|
||||
case ITU_R_709:
|
||||
*target = kCSCLimitedRange709;
|
||||
break;
|
||||
default:
|
||||
DLOGE("Unsupported CSC: %d", source);
|
||||
return kErrorNotSupported;
|
||||
}
|
||||
|
||||
return kErrorNone;
|
||||
}
|
||||
|
||||
DisplayError HWCLayer::SetIGC(IGC_t source, LayerIGC *target) {
|
||||
switch (source) {
|
||||
case IGC_NotSpecified:
|
||||
*target = kIGCNotSpecified;
|
||||
break;
|
||||
case IGC_sRGB:
|
||||
*target = kIGCsRGB;
|
||||
break;
|
||||
default:
|
||||
DLOGE("Unsupported IGC: %d", source);
|
||||
return kErrorNotSupported;
|
||||
}
|
||||
|
||||
return kErrorNone;
|
||||
}
|
||||
|
||||
uint32_t HWCLayer::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 ((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 HWCLayer::SetComposition(const LayerComposition &source) {
|
||||
auto composition = HWC2::Composition::Invalid;
|
||||
switch (source) {
|
||||
case kCompositionGPU:
|
||||
composition = HWC2::Composition::Client;
|
||||
break;
|
||||
case kCompositionHWCursor:
|
||||
composition = HWC2::Composition::Cursor;
|
||||
break;
|
||||
default:
|
||||
composition = HWC2::Composition::Device;
|
||||
break;
|
||||
}
|
||||
// Update solid fill composition
|
||||
if (layer_->composition == kCompositionSDE && layer_->flags.solid_fill != 0) {
|
||||
composition = HWC2::Composition::SolidColor;
|
||||
}
|
||||
if (composition != composition_) {
|
||||
// Composition changed for this layer
|
||||
composition_changed_ = true;
|
||||
composition_ = composition;
|
||||
}
|
||||
}
|
||||
void HWCLayer::PushReleaseFence(int32_t fence) {
|
||||
release_fences_.push(fence);
|
||||
}
|
||||
int32_t HWCLayer::PopReleaseFence(void) {
|
||||
if (release_fences_.empty())
|
||||
return -1;
|
||||
auto fence = release_fences_.front();
|
||||
release_fences_.pop();
|
||||
return fence;
|
||||
}
|
||||
|
||||
} // namespace sdm
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
|
||||
* Not a Contribution.
|
||||
*
|
||||
* Copyright 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __HWC_LAYERS_H__
|
||||
#define __HWC_LAYERS_H__
|
||||
|
||||
/* This class translates HWC2 Layer functions to the SDM LayerStack
|
||||
*/
|
||||
|
||||
#include <gralloc_priv.h>
|
||||
#include <qdMetaData.h>
|
||||
#include <core/layer_stack.h>
|
||||
#define HWC2_INCLUDE_STRINGIFICATION
|
||||
#define HWC2_USE_CPP11
|
||||
#include <hardware/hwcomposer2.h>
|
||||
#undef HWC2_INCLUDE_STRINGIFICATION
|
||||
#undef HWC2_USE_CPP11
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
|
||||
namespace sdm {
|
||||
|
||||
enum GeometryChanges {
|
||||
kNone = 0x00,
|
||||
kBlendMode = 0x01,
|
||||
kDataspace = 0x02,
|
||||
kDisplayFrame = 0x04,
|
||||
kPlaneAlpha = 0x08,
|
||||
kSourceCrop = 0x0A,
|
||||
kTransform = 0x10,
|
||||
kZOrder = 0x12,
|
||||
kAdded = 0x14,
|
||||
kRemoved = 0x18,
|
||||
};
|
||||
|
||||
class HWCLayer {
|
||||
public:
|
||||
explicit HWCLayer(hwc2_display_t display_id);
|
||||
~HWCLayer();
|
||||
uint32_t GetZ() const { return z_; }
|
||||
hwc2_layer_t GetId() const { return id_; }
|
||||
Layer *GetSDMLayer() { return layer_; }
|
||||
|
||||
HWC2::Error SetLayerBlendMode(HWC2::BlendMode mode);
|
||||
HWC2::Error SetLayerBuffer(buffer_handle_t buffer, int32_t acquire_fence);
|
||||
HWC2::Error SetLayerColor(hwc_color_t color);
|
||||
HWC2::Error SetLayerCompositionType(HWC2::Composition type);
|
||||
HWC2::Error SetLayerDataspace(int32_t dataspace);
|
||||
HWC2::Error SetLayerDisplayFrame(hwc_rect_t frame);
|
||||
HWC2::Error SetLayerPlaneAlpha(float alpha);
|
||||
HWC2::Error SetLayerSourceCrop(hwc_frect_t crop);
|
||||
HWC2::Error SetLayerSurfaceDamage(hwc_region_t damage);
|
||||
HWC2::Error SetLayerTransform(HWC2::Transform transform);
|
||||
HWC2::Error SetLayerVisibleRegion(hwc_region_t visible);
|
||||
HWC2::Error SetLayerZOrder(uint32_t z);
|
||||
void SetComposition(const LayerComposition &source);
|
||||
bool CompositionChanged(void) { return composition_changed_; }
|
||||
HWC2::Composition GetCompositionType() { return composition_; }
|
||||
uint32_t GetGeometryChanges() { return geometry_changes_; }
|
||||
void ResetGeometryChanges() { geometry_changes_ = GeometryChanges::kNone; }
|
||||
void PushReleaseFence(int32_t fence);
|
||||
int32_t PopReleaseFence(void);
|
||||
|
||||
private:
|
||||
Layer *layer_ = nullptr;
|
||||
uint32_t z_ = 0;
|
||||
const hwc2_layer_t id_;
|
||||
const hwc2_display_t display_id_;
|
||||
static std::atomic<hwc2_layer_t> next_id_;
|
||||
std::queue<int32_t> release_fences_;
|
||||
|
||||
HWC2::Composition composition_ = HWC2::Composition::Device;
|
||||
bool composition_changed_ = false;
|
||||
uint32_t geometry_changes_ = GeometryChanges::kNone;
|
||||
|
||||
void SetRect(const hwc_rect_t &source, LayerRect *target);
|
||||
void SetRect(const hwc_frect_t &source, LayerRect *target);
|
||||
uint32_t GetUint32Color(const hwc_color_t &source);
|
||||
LayerBufferFormat GetSDMFormat(const int32_t &source, const int flags);
|
||||
LayerBufferS3DFormat GetS3DFormat(uint32_t s3d_format);
|
||||
DisplayError SetMetaData(const private_handle_t *pvt_handle, Layer *layer);
|
||||
DisplayError SetCSC(ColorSpace_t source, LayerCSC *target);
|
||||
DisplayError SetIGC(IGC_t source, LayerIGC *target);
|
||||
uint32_t RoundToStandardFPS(uint32_t fps);
|
||||
};
|
||||
|
||||
struct SortLayersByZ {
|
||||
bool operator()(const HWCLayer *lhs, const HWCLayer *rhs);
|
||||
};
|
||||
|
||||
} // namespace sdm
|
||||
#endif // __HWC_LAYERS_H__
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
|
||||
* Not a Contribution.
|
||||
*
|
||||
* Copyright 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __HWC_SESSION_H__
|
||||
#define __HWC_SESSION_H__
|
||||
|
||||
#include <core/core_interface.h>
|
||||
#include <utils/locker.h>
|
||||
|
||||
#include "hwc_callbacks.h"
|
||||
#include "hwc_layers.h"
|
||||
#include "hwc_display.h"
|
||||
#include "hwc_display_primary.h"
|
||||
#include "hwc_display_external.h"
|
||||
#include "hwc_display_virtual.h"
|
||||
#include "hwc_color_manager.h"
|
||||
|
||||
namespace sdm {
|
||||
|
||||
class HWCSession : hwc2_device_t, 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();
|
||||
HWC2::Error CreateVirtualDisplayObject(uint32_t width, uint32_t height);
|
||||
|
||||
template <typename... Args>
|
||||
static int32_t CallDisplayFunction(hwc2_device_t *device, hwc2_display_t display,
|
||||
HWC2::Error (HWCDisplay::*member)(Args...), Args... args) {
|
||||
if (!device) {
|
||||
return HWC2_ERROR_BAD_DISPLAY;
|
||||
}
|
||||
|
||||
HWCSession *hwc_session = static_cast<HWCSession *>(device);
|
||||
auto status = HWC2::Error::BadDisplay;
|
||||
if (hwc_session->hwc_display_[display]) {
|
||||
auto hwc_display = hwc_session->hwc_display_[display];
|
||||
status = (hwc_display->*member)(std::forward<Args>(args)...);
|
||||
}
|
||||
return INT32(status);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static int32_t CallLayerFunction(hwc2_device_t *device, hwc2_display_t display,
|
||||
hwc2_layer_t layer, HWC2::Error (HWCLayer::*member)(Args...),
|
||||
Args... args) {
|
||||
if (!device) {
|
||||
return HWC2_ERROR_BAD_DISPLAY;
|
||||
}
|
||||
|
||||
HWCSession *hwc_session = static_cast<HWCSession *>(device);
|
||||
auto status = HWC2::Error::BadDisplay;
|
||||
if (hwc_session->hwc_display_[display]) {
|
||||
status = HWC2::Error::BadLayer;
|
||||
auto hwc_layer = hwc_session->hwc_display_[display]->GetHWCLayer(layer);
|
||||
if (hwc_layer != nullptr) {
|
||||
status = (hwc_layer->*member)(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
return INT32(status);
|
||||
}
|
||||
|
||||
// HWC2 Functions that require a concrete implementation in hwc session
|
||||
// and hence need to be member functions
|
||||
static int32_t CreateVirtualDisplay(hwc2_device_t *device, uint32_t width, uint32_t height,
|
||||
hwc2_display_t *out_display_id);
|
||||
static int32_t DestroyVirtualDisplay(hwc2_device_t *device, hwc2_display_t display);
|
||||
static int32_t PresentDisplay(hwc2_device_t *device, hwc2_display_t display,
|
||||
int32_t *out_retire_fence);
|
||||
static int32_t RegisterCallback(hwc2_device_t *device, int32_t descriptor,
|
||||
hwc2_callback_data_t callback_data,
|
||||
hwc2_function_pointer_t pointer);
|
||||
static int32_t SetOutputBuffer(hwc2_device_t *device, hwc2_display_t display,
|
||||
buffer_handle_t buffer, int32_t releaseFence);
|
||||
static int32_t ValidateDisplay(hwc2_device_t *device, hwc2_display_t display,
|
||||
uint32_t *out_num_types, uint32_t *out_num_requests);
|
||||
|
||||
private:
|
||||
static const int kExternalConnectionTimeoutMs = 500;
|
||||
static const int kPartialUpdateControlTimeoutMs = 100;
|
||||
|
||||
// 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 void GetCapabilities(struct hwc2_device *device, uint32_t *outCount,
|
||||
int32_t *outCapabilities);
|
||||
static hwc2_function_pointer_t GetFunction(struct hwc2_device *device, int32_t descriptor);
|
||||
|
||||
// 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();
|
||||
int32_t ConnectDisplay(int disp);
|
||||
int DisconnectDisplay(int disp);
|
||||
int GetVsyncPeriod(int disp);
|
||||
|
||||
// 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,
|
||||
android::Parcel *output_parcel);
|
||||
android::status_t ToggleScreenUpdates(const android::Parcel *input_parcel,
|
||||
android::Parcel *output_parcel);
|
||||
android::status_t ConfigureRefreshRate(const android::Parcel *input_parcel);
|
||||
android::status_t QdcmCMDHandler(const android::Parcel *input_parcel,
|
||||
android::Parcel *output_parcel);
|
||||
android::status_t ControlPartialUpdate(const android::Parcel *input_parcel, android::Parcel *out);
|
||||
android::status_t OnMinHdcpEncryptionLevelChange(const android::Parcel *input_parcel,
|
||||
android::Parcel *output_parcel);
|
||||
android::status_t SetPanelBrightness(const android::Parcel *input_parcel,
|
||||
android::Parcel *output_parcel);
|
||||
android::status_t GetPanelBrightness(const android::Parcel *input_parcel,
|
||||
android::Parcel *output_parcel);
|
||||
// These functions return the actual display config info as opposed to FB
|
||||
android::status_t HandleSetActiveDisplayConfig(const android::Parcel *input_parcel,
|
||||
android::Parcel *output_parcel);
|
||||
android::status_t HandleGetActiveDisplayConfig(const android::Parcel *input_parcel,
|
||||
android::Parcel *output_parcel);
|
||||
android::status_t HandleGetDisplayConfigCount(const android::Parcel *input_parcel,
|
||||
android::Parcel *output_parcel);
|
||||
android::status_t HandleGetDisplayAttributesForConfig(const android::Parcel *input_parcel,
|
||||
android::Parcel *output_parcel);
|
||||
android::status_t GetVisibleDisplayRect(const android::Parcel *input_parcel,
|
||||
android::Parcel *output_parcel);
|
||||
|
||||
android::status_t SetDynamicBWForCamera(const android::Parcel *input_parcel,
|
||||
android::Parcel *output_parcel);
|
||||
android::status_t GetBWTransactionStatus(const android::Parcel *input_parcel,
|
||||
android::Parcel *output_parcel);
|
||||
static Locker locker_;
|
||||
CoreInterface *core_intf_ = NULL;
|
||||
HWCDisplay *hwc_display_[HWC_NUM_DISPLAY_TYPES] = {NULL};
|
||||
HWCCallbacks callbacks_;
|
||||
pthread_t uevent_thread_;
|
||||
bool uevent_thread_exit_ = false;
|
||||
const char *uevent_thread_name_ = "HWC_UeventThread";
|
||||
HWCBufferAllocator *buffer_allocator_ = NULL;
|
||||
HWCBufferSyncHandler *buffer_sync_handler_ = NULL;
|
||||
HWCColorManager *color_mgr_ = NULL;
|
||||
bool reset_panel_ = false;
|
||||
bool secure_display_active_ = false;
|
||||
bool external_pending_connect_ = false;
|
||||
bool new_bw_mode_ = false;
|
||||
bool need_invalidate_ = false;
|
||||
int bw_mode_release_fd_ = -1;
|
||||
qService::QService *qservice_ = NULL;
|
||||
};
|
||||
|
||||
} // namespace sdm
|
||||
|
||||
#endif // __HWC_SESSION_H__
|
Loading…
Reference in New Issue