author | baocheng sun <baocheng.sun@amlogic.com> | 2020-05-28 09:48:49 (GMT) |
---|---|---|
committer | baocheng sun <baocheng.sun@amlogic.com> | 2020-05-29 09:39:14 (GMT) |
commit | 26d4b3ab2aa2310c0eb48ded1686c66cc9168553 (patch) | |
tree | b3c825c7d732b7e59e43fb614afb2611797ec018 | |
parent | f34c749ec03c46df0271a0b30278e27906a13ef6 (diff) | |
download | hwcomposer-26d4b3ab2aa2310c0eb48ded1686c66cc9168553.zip hwcomposer-26d4b3ab2aa2310c0eb48ded1686c66cc9168553.tar.gz hwcomposer-26d4b3ab2aa2310c0eb48ded1686c66cc9168553.tar.bz2 |
meson-display: add meson_display sdk on R [1/5]
PD#SWPL-14827
Problem:
enable meson_display sdk on android
Solution:
Add a vendor hw binder service and implement a IPC api
to handle display mode and screencap
Verify:
newton
Change-Id: I8a36666e7e2ce85a4b81ca5c92283f9451d750f5
Signed-off-by: baocheng sun <baocheng.sun@amlogic.com>
28 files changed, 2343 insertions, 0 deletions
diff --git a/mesondisplay/Android.bp b/mesondisplay/Android.bp new file mode 100644 index 0000000..0153800 --- a/dev/null +++ b/mesondisplay/Android.bp @@ -0,0 +1,86 @@ +// Copyright (C) 2008 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. + +cc_library_static { + name: "libmeson_display_adapter_local_static", + vendor_available: true, + recovery_available: true, + + cflags: [ + "-DRECOVERY_MODE", + ], + srcs: [ + "adapter/DisplayAdapterRecovery.cpp", + "adapter/DisplayAdapterCommon.cpp", + ], + + local_include_dirs: [ + "include", + "adapter", + ], + + static_libs: [ + "libjsoncpp", + ], + + shared_libs: [ + "liblog", + "libcutils", + ], + + export_include_dirs: [ + "include", + "adapter", + ], +} + +cc_library_shared { + name: "libmeson_display_adapter_remote@1", + + cflags: [ + "-Werror", + "-Wall", + ], + + srcs: [ + "adapter/DisplayAdapterRemote.cpp", + "adapter/DisplayAdapterCommon.cpp", + "adapter/DisplayClient.cpp", + ], + + local_include_dirs: [ + "include", + "adapter", + ], + + shared_libs: [ + "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", + "vendor.amlogic.display.meson_display_ipc@1.0", + "liblog", + "libcutils", + "libutils", + "libhidlbase", + ], + + static_libs: [ + "libjsoncpp", + ], + + export_include_dirs: [ + "include", + "adapter", + ], +} diff --git a/mesondisplay/Android.mk b/mesondisplay/Android.mk new file mode 100644 index 0000000..e1e613e --- a/dev/null +++ b/mesondisplay/Android.mk @@ -0,0 +1,271 @@ +# Copyright (C) 2008 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. + +LOCAL_PATH:= $(call my-dir) + + +HIDL_DEP_SHARED_LIBRARIES := \ + libhidlbase \ + libhidltransport \ + libhwbinder \ + vendor.amlogic.display.meson_display_ipc@1.0 \ + libui \ + liblog \ + libutils \ + libcutils + +#################################################### +####### shared :libmeson_display_service ############ +#################################################### + +include $(CLEAR_VARS) +LOCAL_MODULE := libmeson_display_service + +LOCAL_SRC_FILES := \ + service/DisplayService.cpp + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/service + +LOCAL_SHARED_LIBRARIES := \ + libamgralloc_ext \ + $(HIDL_DEP_SHARED_LIBRARIES) + +LOCAL_STATIC_LIBRARIES += \ + libmeson_display_adapter_common \ + hwc.utils_static \ + libjsoncpp + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_C_INCLUDES) + +LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := \ + $(LOCAL_STATIC_LIBRARIES) + +LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \ + $(LOCAL_SHARED_LIBRARIES) + +ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 28 && echo OK),OK) +LOCAL_PROPRIETARY_MODULE := true +endif +include $(BUILD_SHARED_LIBRARY) + +########################################################### +####### shared :libmeson_display_adapter_common ########## +########################################################### +include $(CLEAR_VARS) +LOCAL_MODULE := libmeson_display_adapter_common +LOCAL_CFLAGS := + +LOCAL_SRC_FILES := \ + adapter/DisplayAdapterCommon.cpp + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/adapter \ + $(LOCAL_PATH)/include + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_C_INCLUDES) + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libcutils + +LOCAL_WHOLE_STATIC_LIBRARIES := \ + libjsoncpp + +ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 28 && echo OK),OK) +LOCAL_PROPRIETARY_MODULE := true +endif +include $(BUILD_STATIC_LIBRARY) + +########################################################### +####### static :libmeson_display_adapter_local ############ +########################################################### +include $(CLEAR_VARS) +# need distinct with static lib "libmeson_display_adapter_local" for recovery on Android.bp +LOCAL_MODULE := libmeson_display_adapter_local +LOCAL_CFLAGS := + +LOCAL_SRC_FILES := \ + adapter/DisplayAdapterLocal.cpp + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/adapter + +#copy frme hwc. because hwc.display_static depend it. +LOCAL_HWC_SHARED_LIBS := \ + libamgralloc_ext \ + libcutils \ + liblog \ + libdl \ + libhardware \ + libutils \ + libsync \ + libion \ + libge2d \ + libui \ + vendor.amlogic.hardware.systemcontrol@1.0 \ + vendor.amlogic.hardware.systemcontrol@1.1 \ + libbase \ + libhidlbase \ + libbinder \ + libhidltransport + +LOCAL_SHARED_LIBRARIES := \ + $(LOCAL_HWC_SHARED_LIBS) \ + liblog + +LOCAL_STATIC_LIBRARIES += \ + libmeson_display_adapter_common \ + hwc.common_static \ + hwc.composition_static \ + hwc.postprocessor_static \ + hwc.display_static \ + hwc.utils_static \ + hwc.base_static \ + hwc.debug_static \ + hwc.composer_static \ + libomxutil + +LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \ + $(LOCAL_SHARED_LIBRARIES) + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_C_INCLUDES) + +ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 28 && echo OK),OK) +LOCAL_PROPRIETARY_MODULE := true +endif +include $(BUILD_STATIC_LIBRARY) + +#################################################### +####### shared :libmeson_display_adapter_remote #### +#################################################### +include $(CLEAR_VARS) + +LOCAL_MODULE:= libmeson_display_adapter_remote + +LOCAL_SRC_FILES:= \ + adapter/DisplayAdapterRemote.cpp \ + adapter/DisplayClient.cpp + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/adapter + +LOCAL_EXPORT_C_INCLUDE_DIRS := \ + $(LOCAL_PATH)/include + +LOCAL_SHARED_LIBRARIES := \ + $(HIDL_DEP_SHARED_LIBRARIES) \ + android.hardware.graphics.mapper@2.0 \ + android.hardware.graphics.mapper@3.0 \ + android.hardware.graphics.mapper@4.0 + +LOCAL_STATIC_LIBRARIES := \ + libmeson_display_adapter_common \ + libjsoncpp + +LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \ + $(LOCAL_SHARED_LIBRARIES) + +LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := \ + $(LOCAL_STATIC_LIBRARIES) + +LOCAL_MODULE_TAGS := optional + +ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26 && echo OK),OK) +LOCAL_PROPRIETARY_MODULE := true +endif + +include $(BUILD_SHARED_LIBRARY) + +####################################### +####### exec :meson_display_client #### +####################################### +include $(CLEAR_VARS) + +LOCAL_MODULE:= meson_display_client + +LOCAL_SRC_FILES:= \ + test/display_client.cpp + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libmeson_display_adapter_remote + + +LOCAL_MODULE_TAGS := optional + +ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26 && echo OK),OK) +LOCAL_PROPRIETARY_MODULE := true +endif + +include $(BUILD_EXECUTABLE) + + +#################################### +####### exec :test_ipc ########## +#################################### +include $(CLEAR_VARS) + +LOCAL_MODULE:= test_ipc + +LOCAL_SRC_FILES := \ + test/ipc_test.cpp + +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + $(HIDL_DEP_SHARED_LIBRARIES) \ + libmeson_display_adapter_remote \ + libmeson_display_service + +LOCAL_STATIC_LIBRARIES := \ + libmeson_display_adapter_common \ + libjsoncpp + +LOCAL_MODULE_TAGS := optional + +ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26 && echo OK),OK) +LOCAL_PROPRIETARY_MODULE := true +endif +include $(BUILD_EXECUTABLE) + + +####################################### +####### exec :test_display_recovery #### +####################################### +include $(CLEAR_VARS) + +LOCAL_MODULE:= test_display_recovery + +LOCAL_CFLAGS += -DRECOVERY_MODE + +LOCAL_SRC_FILES := \ + test/display_recovery_test.cpp + +LOCAL_SHARED_LIBRARIES := \ + $(HIDL_DEP_SHARED_LIBRARIES) + +LOCAL_STATIC_LIBRARIES := \ + libmeson_display_adapter_local_static + +LOCAL_MODULE_TAGS := optional + +ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26 && echo OK),OK) +LOCAL_PROPRIETARY_MODULE := true +endif +include $(BUILD_EXECUTABLE) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/mesondisplay/README.md b/mesondisplay/README.md new file mode 100644 index 0000000..3f58f68 --- a/dev/null +++ b/mesondisplay/README.md @@ -0,0 +1,15 @@ +# introduc +the hwc used api implement on display_adapter_local, systemcontrol and other process use a +display client which under display_adapter_remote +architecture like below: +## Android mode: + HWC--->DisplayServer--->DisplayAdapterLocal(shared library) + || + ||(HDIL Binder) + || + DisplayClient <-----| +systemcontrol--> DisplayAdapterRemot-->| + +## Android Recovery mode: +systemcontrol--> DisplayAdapterLocal(static library). + diff --git a/mesondisplay/adapter/DisplayAdapterCommon.cpp b/mesondisplay/adapter/DisplayAdapterCommon.cpp new file mode 100644 index 0000000..45c9bae --- a/dev/null +++ b/mesondisplay/adapter/DisplayAdapterCommon.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019 Amlogic, Inc. All rights reserved. + * + * This source code is subject to the terms and conditions defined in the + * file 'LICENSE' which is part of this source code package. + * + * Description: + */ + +#include "DisplayAdapter.h" +#include <json/json.h> +namespace meson{ + +bool Json2DisplayMode(const Json::Value& json, DisplayModeInfo& mode) { + if (json.isMember("name") && json.isMember("dpiX") && + json.isMember("dpiY") && json.isMember("pixelW") && + json.isMember("pixelH") && json.isMember("refreshRate")) { + if (!json["name"].isString()) { + return false; + } + mode.name = json["name"].asString(); + mode.dpiX = json["dpiX"].asUInt(); + mode.dpiY = json["dpiY"].asUInt(); + mode.pixelW = json["pixelW"].asUInt(); + mode.pixelH = json["pixelH"].asUInt(); + mode.refreshRate = json["refreshRate"].asFloat(); + return true; + } + return false; +}; + +bool DisplayMode2Json(const DisplayModeInfo& mode, Json::Value& json) { + json["name"] = mode.name; + json["dpiX"] = mode.dpiX; + json["dpiY"] = mode.dpiY; + json["pixelW"] = mode.pixelW; + json["pixelH"] = mode.pixelH; + json["refreshRate"] = mode.refreshRate; + return true; +}; + +}; //namespace meson diff --git a/mesondisplay/adapter/DisplayAdapterLocal.cpp b/mesondisplay/adapter/DisplayAdapterLocal.cpp new file mode 100644 index 0000000..9485c90 --- a/dev/null +++ b/mesondisplay/adapter/DisplayAdapterLocal.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2019 Amlogic, Inc. All rights reserved. + * + * This source code is subject to the terms and conditions defined in the + * file 'LICENSE' which is part of this source code package. + * + * Description: + */ + +#include "HwDisplayManager.h" +#include "HwDisplayConnector.h" +#include "HwDisplayCrtc.h" +#include "DisplayAdapterLocal.h" + +#include "misc.h" +#include "MesonHwc2.h" +#include "HwcConfig.h" +#include "MesonLog.h" + +namespace meson{ + +using namespace std; +using ConnectorType = DisplayAdapter::ConnectorType; +using BackendType = DisplayAdapter::BackendType; + +void DisplayTypeConv(drm_connector_type_t& type, ConnectorType displayType) { + switch (displayType) { + case DisplayAdapter::CONN_TYPE_HDMI: + type = DRM_MODE_CONNECTOR_HDMI; + break; + case DisplayAdapter::CONN_TYPE_PANEL: + type = DRM_MODE_CONNECTOR_PANEL; + break; + case DisplayAdapter::CONN_TYPE_DUMMY: + type = DRM_MODE_CONNECTOR_DUMMY; + break; + } +} + +void DisplayModeConv(DisplayModeInfo& mode, drm_mode_info_t& mode_in) { + mode.name = mode_in.name; + mode.dpiX = mode_in.dpiX; + mode.dpiY = mode_in.dpiY; + mode.pixelW = mode_in.pixelW; + mode.pixelH = mode_in.pixelH; + mode.refreshRate = mode_in.refreshRate; +} + + +DisplayAdapterLocal::DisplayAdapterLocal() { +} + +DisplayAdapter::BackendType DisplayAdapterLocal::displayType() { + return DISPLAY_TYPE_FBDEV; +} + +bool DisplayAdapterLocal::getSupportDisplayModes(vector<DisplayModeInfo>& displayModeList, ConnectorType displayType) { + drm_connector_type_t type; + std::shared_ptr<HwDisplayConnector> connector; + map<uint32_t, drm_mode_info_t> modes; + DisplayTypeConv(type, displayType); + HwDisplayManager::getInstance().getConnector(connector, type); + if (connector) { + connector->getModes(modes); + displayModeList.clear(); + DisplayModeInfo mode; + for (auto it : modes) { + DisplayModeConv(mode, it.second); + displayModeList.push_back(mode); + } + } + return true;; +}; + +bool DisplayAdapterLocal::getDisplayMode(string& mode, ConnectorType displayType) { + drm_connector_type_t type; + std::shared_ptr<HwDisplayConnector> connector; + drm_mode_info_t mode_in; + + DisplayTypeConv(type, displayType); + HwDisplayManager::getInstance().getConnector(connector, type); + if (connector && connector->mCrtc) { + connector->mCrtc->getMode(mode_in); + mode = mode_in.name; + } + DEBUG_INFO("GetDisplayMode:%s", mode.c_str()); + return true; +} + +bool DisplayAdapterLocal::setDisplayMode(const string& mode, ConnectorType displayType) { + drm_connector_type_t type; + std::shared_ptr<HwDisplayConnector> connector; + drm_mode_info_t mock; + strncpy(mock.name, mode.c_str(), DRM_DISPLAY_MODE_LEN); + DisplayTypeConv(type, displayType); + + DEBUG_INFO("SetDisplay[%s] Mode to \"%s\"", type == DRM_MODE_CONNECTOR_HDMI ? "HDMI" : + (type == DRM_MODE_CONNECTOR_PANEL ? "panel":"dummy"), mode.c_str()); + + HwDisplayManager::getInstance().getConnector(connector, type); + if (connector && connector->mCrtc) { + connector->mCrtc->setMode(mock); + } + DEBUG_INFO("SetDisplayMode done"); + return true; +}; + +bool DisplayAdapterLocal::captureDisplayScreen(const native_handle_t **outBufferHandle) { + // get framebuffer width and height + uint32_t fbW = 1290; + uint32_t fbH = 1080; + HwcConfig::getFramebufferSize(0, fbW, fbH); + + if (sys_get_bool_prop("vendor.hwc.3dmode", false)) { + fbW = 960; + fbH = 540; + } + + // format is always HAL_PIXEL_FORMAT_RGB_888 + native_handle_t* hnd = gralloc_alloc_dma_buf(fbW, fbH, HAL_PIXEL_FORMAT_RGB_888, true, false); + if (hnd == nullptr || am_gralloc_get_buffer_fd(hnd) < 0) { + MESON_LOGE("DisplayAdapterLocal::captureDisplayScreen alloc buffer error"); + return false; + } + + int32_t ret = MesonHwc2::getInstance().captureDisplayScreen(hnd); + *outBufferHandle = hnd; + + if (ret != 1) { + gralloc_unref_dma_buf(hnd); + gralloc_free_dma_buf(hnd); + } + + return ret == 1 ? true : false; +} + +std::unique_ptr<DisplayAdapter> DisplayAdapterLocal::create(DisplayAdapter::BackendType type) { + switch (type) { + case BackendType::DISPLAY_TYPE_DRM: + return {nullptr}; + case BackendType::DISPLAY_TYPE_FBDEV: + return static_cast<std::unique_ptr<DisplayAdapter>>(std::make_unique<DisplayAdapterLocal>()); + default: + return static_cast<std::unique_ptr<DisplayAdapter>>(std::make_unique<DisplayAdapterLocal>()); + } +} + +std::unique_ptr<DisplayAdapter> DisplayAdapterCreateLocal(DisplayAdapter::BackendType type) { + return DisplayAdapterLocal::create(type); +}; + + +}; //namespace meson diff --git a/mesondisplay/adapter/DisplayAdapterLocal.h b/mesondisplay/adapter/DisplayAdapterLocal.h new file mode 100644 index 0000000..6460749 --- a/dev/null +++ b/mesondisplay/adapter/DisplayAdapterLocal.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2019 Amlogic, Inc. All rights reserved. + * + * This source code is subject to the terms and conditions defined in the + * file 'LICENSE' which is part of this source code package. + * + * Description: + */ + +#pragma once +#include "DisplayAdapter.h" +#include "utile.h" + +namespace meson{ + +class DisplayAdapterLocal: public DisplayAdapter { +public: + AdapterType type() override { return ADAPTER_TYPE_LOCAL; } + BackendType displayType() override; + + bool getSupportDisplayModes(vector<DisplayModeInfo>& displayModeList, ConnectorType displayType) override; + bool getDisplayMode(string& mode, ConnectorType displayType) override; + bool setDisplayMode(const string& mode, ConnectorType displayType) override; + //bool setPrefDisplayMode(const string& mode, ConnectorType displayType) override; + bool captureDisplayScreen(const native_handle_t **outBufferHandle) override; + static std::unique_ptr<DisplayAdapter> create(DisplayAdapter::BackendType type); + + DisplayAdapterLocal(); + ~DisplayAdapterLocal() = default; +private: + + DISALLOW_COPY_AND_ASSIGN(DisplayAdapterLocal); +}; + +}; //namespace meson diff --git a/mesondisplay/adapter/DisplayAdapterRecovery.cpp b/mesondisplay/adapter/DisplayAdapterRecovery.cpp new file mode 100644 index 0000000..1776c74 --- a/dev/null +++ b/mesondisplay/adapter/DisplayAdapterRecovery.cpp @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2019 Amlogic, Inc. All rights reserved. + * + * This source code is subject to the terms and conditions defined in the + * file 'LICENSE' which is part of this source code package. + * + * Description: + */ + +#include <stdio.h> +#include <errno.h> +#include "utile.h" +#include <unistd.h> +#include "DisplayAdapterLocal.h" +#include <fcntl.h> +namespace meson{ +//For recovery mode for temporary. +#define SYSFS_DISPLAY_MODE "/sys/class/display/mode" +#define SYSFS_DISPLAY_MODE2 "/sys/class/display2/mode" +#define MAX_BUFFER_LEN_EDID 4096 +#define READ_BUFFER_LEN 64 +#define FORMAT_DISPLAY_HDMI_EDID "/sys/class/amhdmitx/amhdmitx0/disp_cap"//RX support display mode + +#define FS_READ(path, buffer, len) \ +do { \ + int fd;\ + if ((fd = open(path, O_RDONLY)) < 0) { \ + perror(path);\ + DEBUG_INFO("open file %s error!", path);\ + goto error_handle; \ + } \ + if (read(fd, buffer, len) == -1) { \ + perror(path); \ + DEBUG_INFO("Read file %s error!", path); \ + close(fd); \ + goto error_handle; \ + } \ + close(fd); \ +} while (0) + +#define FS_WRITE(path, buffer, len) \ +do { \ + int fd;\ + if ((fd = open(path, O_RDWR)) < 0) { \ + perror(path);\ + DEBUG_INFO("open file %s error!", path);\ + goto error_handle; \ + } \ + if (write(fd, buffer, len) == -1) { \ + perror(path); \ + DEBUG_INFO("Read file %s error!", path); \ + close(fd); \ + goto error_handle; \ + } \ + close(fd); \ +} while (0) + + + +#define CONNECT_HDMI_INDEX CONN1; +#define CONNECT_PANEL_INDEX CONN2; +#define CONNECT_DUMMY_INDEX CONN3; + +using namespace std; +using ConnectorType = DisplayAdapter::ConnectorType; +typedef enum { + CONN1 = 0, + CONN2 = 1, + CONN3 = 2, +} connector_index; + +void DisplayTypeConvToIndex(ConnectorType displayType, connector_index& type) { + switch (displayType) { + case DisplayAdapter::CONN_TYPE_HDMI: + type = CONNECT_HDMI_INDEX; + break; + case DisplayAdapter::CONN_TYPE_PANEL: + type = CONNECT_PANEL_INDEX; + break; + case DisplayAdapter::CONN_TYPE_DUMMY: + type = CONNECT_DUMMY_INDEX; + break; + } +} + +DisplayAdapterLocal::DisplayAdapterLocal() { +} + +DisplayAdapter::BackendType DisplayAdapterLocal::displayType() { + return DISPLAY_TYPE_FBDEV; +} + +bool GetHDMIEDID(char* buffer, int len) { + FS_READ(FORMAT_DISPLAY_HDMI_EDID, buffer, len); + return true; +error_handle: + DEBUG_INFO("Get EDID error:%s", strerror(errno)); + return false; +} + +bool DisplayAdapterLocal::getSupportDisplayModes(vector<DisplayModeInfo>& displayModeList, ConnectorType displayType) { + DisplayModeInfo mode; + if (displayType == DisplayAdapter::CONN_TYPE_HDMI) { + displayModeList.clear(); + char edid_buf[MAX_BUFFER_LEN_EDID]; + const char *delim = "\n"; + char *ptr = NULL; + if (false == GetHDMIEDID(edid_buf, MAX_BUFFER_LEN_EDID)) { + return false; + } + ptr = strtok(edid_buf, delim); + while (ptr != NULL) { + int len = strlen(ptr); + if (ptr[len - 1] == '*') + ptr[len - 1] = '\0'; + + mode.name = ptr; + //TODO: Add other info + displayModeList.push_back(mode); + ptr = strtok(NULL, delim); + }; + } else { + //TODO: now just show the current mode beside HDMI + displayModeList.clear(); + getDisplayMode(mode.name, displayType); + displayModeList.push_back(mode); + } + + return true; +}; + +bool DisplayAdapterLocal::getDisplayMode(string& mode, ConnectorType displayType) { + connector_index conn; + char buf[READ_BUFFER_LEN] = {0}; + const char* path = NULL; + + DisplayTypeConvToIndex(displayType, conn); + if (conn == CONN1) { + path = SYSFS_DISPLAY_MODE; + } else if (conn == CONN2) { + path = SYSFS_DISPLAY_MODE2; + } else { + DEBUG_INFO("No such device"); + assert(0); + return false; + } + + FS_READ(path, buf, READ_BUFFER_LEN); + mode = buf; + return true; +error_handle: + return false; +} + +bool DisplayAdapterLocal::setDisplayMode(const string& mode, ConnectorType displayType) { + connector_index conn ; + DisplayTypeConvToIndex(displayType, conn); + const char* path = NULL; + + if (conn == CONN1) { + path = SYSFS_DISPLAY_MODE; + } else if (conn == CONN2) { + path = SYSFS_DISPLAY_MODE2; + } else { + DEBUG_INFO("No such device"); + assert(0); + return false; + } + + FS_WRITE(path, mode.c_str(), mode.length()); + + return true; +error_handle: + return false; +}; + +bool DisplayAdapterLocal::captureDisplayScreen(const native_handle_t **outBufferHandle) { + *outBufferHandle = nullptr; + return true; +} + +std::unique_ptr<DisplayAdapter> DisplayAdapterLocal::create(DisplayAdapter::BackendType type) { + switch (type) { + case BackendType::DISPLAY_TYPE_DRM: + return {nullptr}; + case BackendType::DISPLAY_TYPE_FBDEV: + return static_cast<std::unique_ptr<DisplayAdapter>>(std::make_unique<DisplayAdapterLocal>()); + default: + return static_cast<std::unique_ptr<DisplayAdapter>>(std::make_unique<DisplayAdapterLocal>()); + } +} + +std::unique_ptr<DisplayAdapter> DisplayAdapterCreateLocal(DisplayAdapter::BackendType type) { + return DisplayAdapterLocal::create(type); +}; + +}; //namespace meson diff --git a/mesondisplay/adapter/DisplayAdapterRemote.cpp b/mesondisplay/adapter/DisplayAdapterRemote.cpp new file mode 100644 index 0000000..64df199 --- a/dev/null +++ b/mesondisplay/adapter/DisplayAdapterRemote.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2019 Amlogic, Inc. All rights reserved. + * + * This source code is subject to the terms and conditions defined in the + * file 'LICENSE' which is part of this source code package. + * + * Description: + */ + +#include "DisplayAdapter.h" +#include "DisplayClient.h" +#include "DisplayAdapterRemote.h" + +#define IF_SERVER_NOT_READY_RETURN(ret) \ + if (!connectServerIfNeed()) { \ + DEBUG_INFO("Can't connect with server!"); \ + return ret; \ + } + +namespace meson{ +using namespace std; +using ConnectorType = DisplayAdapter::ConnectorType; +using BackendType = DisplayAdapter::BackendType; + +DisplayAdapter::BackendType DisplayAdapterRemote::displayType() { + Json::Value cmd, ret; + IF_SERVER_NOT_READY_RETURN(DisplayAdapter::DISPLAY_TYPE_MAX); + cmd["cmd"] = "displayType"; + ipc->send_request_wait_reply(cmd, ret); + if (ret.isMember("ret")) { + DEBUG_INFO("Server reply error!"); + return (DisplayAdapter::BackendType)ret["ret"].asUInt(); + } else { + return DisplayAdapter::DISPLAY_TYPE_MAX; + } +}; + +bool DisplayAdapterRemote::getSupportDisplayModes(vector<DisplayModeInfo>& displayModeList, ConnectorType displayType) { + Json::Value cmd, ret; + Json::FastWriter write; + IF_SERVER_NOT_READY_RETURN(false); + cmd["cmd"] = "getSupportDisplayModes"; + cmd["p_displayType"] = displayType; + ipc->send_request_wait_reply(cmd, ret); + if (ret.isMember("ret") && ret["ret"].isMember("displayModeList")) { + Json::Value& list = ret["ret"]["displayModeList"]; + displayModeList.clear(); + for (unsigned int i = 0; i < list.size(); i++) { + Json::Value& mode_in = list[i]; + DisplayModeInfo mode; + if (true == Json2DisplayMode(mode_in, mode)) { + displayModeList.push_back(mode); + } else { + DEBUG_INFO("Get Wrong DisplayMode info"); + return false; + } + } + return true; + } else { + return false; + } +}; +bool DisplayAdapterRemote::getDisplayMode(string& mode, ConnectorType displayType) { + Json::Value cmd, ret; + Json::FastWriter write; + IF_SERVER_NOT_READY_RETURN(false); + cmd["cmd"] = "getDisplayMode"; + cmd["p_displayType"] = displayType; + ipc->send_request_wait_reply(cmd, ret); + if (ret.isMember("ret") && ret["ret"]["mode"].isString()) { + mode = ret["ret"]["mode"].asString(); + return true; + } else + return false; +}; +bool DisplayAdapterRemote::setDisplayMode(const string& mode, ConnectorType displayType) { + Json::Value cmd; + IF_SERVER_NOT_READY_RETURN(false); + cmd["cmd"] = "setDisplayMode"; + cmd["p_mode"] = mode; + cmd["p_displayType"] = displayType; + ipc->send_request(cmd); + return true; +}; +bool DisplayAdapterRemote::setPrefDisplayMode(const string& mode, ConnectorType displayType) { + Json::Value cmd; + IF_SERVER_NOT_READY_RETURN(false); + cmd["cmd"] = "setPrefDisplayMode"; + cmd["p_mode"] = mode; + cmd["p_displayType"] = displayType; + ipc->send_request(cmd); + return true; +}; + +bool DisplayAdapterRemote::captureDisplayScreen(const native_handle_t **outBufferHandle) { + IF_SERVER_NOT_READY_RETURN(false); + return ipc->captureDisplayScreen(outBufferHandle); +} + +DisplayAdapterRemote::DisplayAdapterRemote() { + ipc = DisplayClient::create("DisplayAdapterRemote"); + if (!ipc) + DEBUG_INFO("Error when connect with Server"); +} + +std::unique_ptr<DisplayAdapter> DisplayAdapterRemote::create() { + return static_cast<std::unique_ptr<DisplayAdapter>>(std::make_unique<DisplayAdapterRemote>()); +} + +bool DisplayAdapterRemote::connectServerIfNeed() { + return ipc->tryGetService(); +}; + +std::unique_ptr<DisplayAdapter> DisplayAdapterCreateRemote() { + return DisplayAdapterRemote::create(); +}; + +} //namespace android diff --git a/mesondisplay/adapter/DisplayAdapterRemote.h b/mesondisplay/adapter/DisplayAdapterRemote.h new file mode 100644 index 0000000..89c9f42 --- a/dev/null +++ b/mesondisplay/adapter/DisplayAdapterRemote.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019 Amlogic, Inc. All rights reserved. + * + * This source code is subject to the terms and conditions defined in the + * file 'LICENSE' which is part of this source code package. + * + * Description: + */ + +#pragma once +#include <stdbool.h> +#include "utile.h" +#include "DisplayAdapter.h" +#include "DisplayClient.h" + +namespace meson{ +using namespace std; + +class DisplayAdapterRemote: public DisplayAdapter { +public: + AdapterType type() override { return ADAPTER_TYPE_REMOTE; } + BackendType displayType() override; + + bool getSupportDisplayModes(vector<DisplayModeInfo>& displayModeList, ConnectorType displayType) override; + bool getDisplayMode(string& mode, ConnectorType displayType) override; + bool setDisplayMode(const string& mode, ConnectorType displayType) override; + bool setPrefDisplayMode(const string& mode, ConnectorType displayType) override; + bool captureDisplayScreen(const native_handle_t **outBufferHandle) override; + + static std::unique_ptr<DisplayAdapter> create(); + DisplayAdapterRemote(); + ~DisplayAdapterRemote() = default; +private: + + // For later start server. + bool connectServerIfNeed(); + std::unique_ptr<DisplayClient> ipc; + DISALLOW_COPY_AND_ASSIGN(DisplayAdapterRemote); +}; + +} //namespace android diff --git a/mesondisplay/adapter/DisplayClient.cpp b/mesondisplay/adapter/DisplayClient.cpp new file mode 100644 index 0000000..51a6fce --- a/dev/null +++ b/mesondisplay/adapter/DisplayClient.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2020 Amlogic, Inc. All rights reserved. + * + * This source code is subject to the terms and conditions defined in the + * file 'LICENSE' which is part of this source code package. + * + * Description: + */ + +#include "DisplayClient.h" +#include "MesonLog.h" + +namespace meson{ +using namespace std; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_handle; +using ::android::hardware::hidl_vec; +using ::android::hardware::graphics::mapper::V3_0::IMapper; +using ::vendor::amlogic::display::meson_display_ipc::V1_0::IMesonDisplayIPC; +using ::vendor::amlogic::display::meson_display_ipc::V1_0::Error; + +static const int MAX_GET_SERVICE_COUNT = 5; + +DisplayClient::DisplayClient(std::string str) + : name(str) { + meson_ipc_client = NULL; + is_ready = false; + //Note: you need call tryGetService befor other api called. + //tryGetService(); +} + +bool DisplayClient::tryGetService() { + if (is_ready == true) + return true; + + int count = 0; + while (meson_ipc_client == NULL && count <= MAX_GET_SERVICE_COUNT) { + DEBUG_INFO("Try get meson_ipc service(%d)", count); + meson_ipc_client = IMesonDisplayIPC::tryGetService(); + count++; + } + + mMapper = IMapper::getService(); + + if (meson_ipc_client && mMapper) + is_ready = true; + else + is_ready = false; + + return is_ready; +} + +std::unique_ptr<DisplayClient> DisplayClient::create(std::string name) { + return std::unique_ptr<DisplayClient>(new DisplayClient(name)); +} + +int32_t DisplayClient::send_request_wait_reply(Json::Value& data, Json::Value& out) { + Json::FastWriter write; + bool ret = false; + const hidl_string str = write.write(data); + if (is_ready) { + DEBUG_INFO("Client SendSync :%s", str.c_str()); + meson_ipc_client->send_msg_wait_reply(str, [&out, &ret](const hidl_string& in) { + Json::Reader reader; + const std::string tmp = in.c_str(); + ret = reader.parse(tmp, out); + }); + } + if (ret == false) { + DEBUG_INFO("Server reply format error !"); + } + return 0; +} + +int32_t DisplayClient::send_request(Json::Value& data) { + Json::FastWriter write; + const hidl_string str = write.write(data); + if (is_ready) { + DEBUG_INFO("Client Send :%s", str.c_str()); + meson_ipc_client->send_msg(str); + } + return 0; +} + +bool DisplayClient::captureDisplayScreen(const native_handle_t** outBufferHandle) { + MESON_LOGD("Client captureDisplayScreen"); + if (!is_ready) { + MESON_LOGE("captureDisplayScreen Server not ready"); + return false; + } + + Error error; + hidl_vec<hidl_handle> dataHandles; + const native_handle_t *bufferHandle = nullptr; + + meson_ipc_client->captureDisplayScreen(0 /*displayId reserved*/, 0 /*layerId reserved*/, + [&] (const auto& tmpError, const auto& tmpOutHandles){ + error = tmpError; + dataHandles.setToExternal(const_cast<hidl_handle*>(tmpOutHandles.data()), + tmpOutHandles.size()); + }); + if (error != Error::NONE) { + MESON_LOGE("captureDislayScreen failed"); + return false; + } + + // only import the first buffer handle. + // We assumed there is only one native handle currently + if (dataHandles.size() > 0) { + mMapper->importBuffer(dataHandles[0], + [&](const auto& tmpError, const auto& tmpBufferHandle) { + if (tmpError != android::hardware::graphics::mapper::V3_0::Error::NONE) { + MESON_LOGE("captureDisplayScreen mapper import buffer error:%d", tmpError); + return; + } + bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle); + }); + } + + *outBufferHandle = bufferHandle; + + return true; +} + +} // meson diff --git a/mesondisplay/adapter/DisplayClient.h b/mesondisplay/adapter/DisplayClient.h new file mode 100644 index 0000000..8eb91af --- a/dev/null +++ b/mesondisplay/adapter/DisplayClient.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020 Amlogic, Inc. All rights reserved. + * + * This source code is subject to the terms and conditions defined in the + * file 'LICENSE' which is part of this source code package. + * + * Description: + */ + +#pragma once + +#include <json/json.h> +#include <stdbool.h> +#include <string> + +#include <utils/StrongPointer.h> +#include <cutils/native_handle.h> + +#include <android/hardware/graphics/mapper/2.0/IMapper.h> +#include <android/hardware/graphics/mapper/3.0/IMapper.h> +#include <android/hardware/graphics/mapper/4.0/IMapper.h> +#include <vendor/amlogic/display/meson_display_ipc/1.0/IMesonDisplayIPC.h> + +#include "utile.h" + +namespace meson { +using namespace std; +using ::android::sp; +using ::vendor::amlogic::display::meson_display_ipc::V1_0::IMesonDisplayIPC; +//using ::android::hardware::graphics::mapper; +using ::android::hardware::graphics::mapper::V3_0::IMapper; + +class DisplayClient { +public: + DisplayClient(std::string name); + ~DisplayClient() = default; + bool tryGetService(); + int32_t send_request_wait_reply(Json::Value& data, Json::Value& out); + int32_t send_request(Json::Value& data); + static std::unique_ptr<DisplayClient> create(std::string name); + bool captureDisplayScreen(const native_handle_t** outBufferHandle); + +protected: + std::string name; + sp<IMesonDisplayIPC> meson_ipc_client; + //sp<android::hardware::graphics::mapper::V2_0::IMapper> mMapper; +// sp<mapper::V2_0::IMapper> mMapper2; +// sp<mapper::V3_0::IMapper> mMapper3; +// sp<mapper::V4_0::IMapper> mMapper4; + sp<IMapper> mMapper; + + //std::unique_ptr<GrallocMapper> mMapper; + bool is_ready; +private: + DISALLOW_COPY_AND_ASSIGN(DisplayClient); +}; + +} //namespace meson diff --git a/mesondisplay/include/DisplayAdapter.h b/mesondisplay/include/DisplayAdapter.h new file mode 100644 index 0000000..13c5b6c --- a/dev/null +++ b/mesondisplay/include/DisplayAdapter.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2019 Amlogic, Inc. All rights reserved. + * + * This source code is subject to the terms and conditions defined in the + * file 'LICENSE' which is part of this source code package. + * + * Description: + */ +#pragma once +#include <stdbool.h> +#include <string> +#include <memory> +#include <vector> +#include <cutils/native_handle.h> +#include "utile.h" + +namespace Json { + class Value; +} + +namespace meson{ +using namespace std; + +typedef struct { + string name; + uint32_t dpiX, dpiY; + uint32_t pixelW, pixelH; + float refreshRate; +} DisplayModeInfo; + + +class DisplayAdapter { +public: + typedef enum { + ADAPTER_TYPE_REMOTE = 0, + ADAPTER_TYPE_LOCAL = 1, + } AdapterType; + typedef enum { + DISPLAY_TYPE_DRM = 0, + DISPLAY_TYPE_FBDEV = 1, + DISPLAY_TYPE_MAX, + } BackendType; + typedef enum { + CONN_TYPE_DUMMY = 0, + CONN_TYPE_HDMI = 1, + CONN_TYPE_PANEL = 2, + } ConnectorType; + virtual AdapterType type() = 0; + virtual BackendType displayType() = 0; + virtual bool getSupportDisplayModes(vector<DisplayModeInfo>& displayModeList, ConnectorType displayType) { + UNUSED(displayModeList); + UNUSED(displayType); + NOTIMPLEMENTED; + return false; + }; + virtual bool getDisplayMode(string& mode, ConnectorType displayType) { + UNUSED(mode); + UNUSED(displayType); + NOTIMPLEMENTED; + return false; + }; + virtual bool setDisplayMode(const string& mode, ConnectorType displayType) { + UNUSED(mode); + UNUSED(displayType); + NOTIMPLEMENTED; + return false; + }; + virtual bool setPrefDisplayMode(const string& mode, ConnectorType displayType) { + UNUSED(mode); + UNUSED(displayType); + NOTIMPLEMENTED; + return false; + }; + + virtual bool captureDisplayScreen(const native_handle_t **outBufferHandle) = 0; + + virtual ~DisplayAdapter() = default; + DisplayAdapter() = default; +private: + DisplayAdapter(const DisplayAdapter&) = delete; + void operator=(const DisplayAdapter&) = delete; +}; + + +bool Json2DisplayMode(const Json::Value& json, DisplayModeInfo& mode); + +bool DisplayMode2Json(const DisplayModeInfo& mode, Json::Value& json); + +std::unique_ptr<DisplayAdapter> DisplayAdapterCreateLocal(DisplayAdapter::BackendType type); +std::unique_ptr<DisplayAdapter> DisplayAdapterCreateRemote(); + + +}; + diff --git a/mesondisplay/include/MesonLog.h b/mesondisplay/include/MesonLog.h new file mode 100644 index 0000000..212a39a --- a/dev/null +++ b/mesondisplay/include/MesonLog.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017 Amlogic, Inc. All rights reserved. + * + * This source code is subject to the terms and conditions defined in the + * file 'LICENSE' which is part of this source code package. + * + * Description: + */ + +#ifndef MESON_LOG_H +#define MESON_LOG_H + +#ifndef LOG_TAG +#define LOG_TAG "MesonDisplay" +#endif + +#define LOG_NDEBUG 0 +#include <log/log.h> +#include <stdlib.h> + +#ifdef HWC_RELEASE +#define MESON_DEBUG_LEVEL 0 +#else +#define MESON_DEBUG_LEVEL 1 +#endif + +#if MESON_DEBUG_LEVEL > 0 +#define MESON_LOGV(fmt,...) ALOGV(fmt, ##__VA_ARGS__) +#define MESON_LOGD(fmt,...) ALOGD(fmt, ##__VA_ARGS__) +#define MESON_LOGI(fmt,...) ALOGI(fmt, ##__VA_ARGS__) +#define MESON_LOGW(fmt,...) ALOGW(fmt, ##__VA_ARGS__) +#else +#define MESON_LOGV(fmt,...) ((void)0) +#define MESON_LOGD(fmt,...) ((void)0) +#define MESON_LOGI(fmt,...) ((void)0) +#define MESON_LOGW(fmt,...) ((void)0) +#endif +#define MESON_LOGE(fmt,...) ALOGE(fmt, ##__VA_ARGS__) + +#if MESON_DEBUG_LEVEL > 0 +#define MESON_ASSERT(condition,fmt,...) \ + if (!(condition)) { \ + ALOGE(fmt, ##__VA_ARGS__); \ + abort(); \ + } +#else +#define MESON_ASSERT(condition,fmt,...) \ + if (!(condition)) { \ + ALOGE(fmt, ##__VA_ARGS__); \ + } +#endif + +#if MESON_DEBUG_LEVEL > 2 +#define MESON_LOG_FUN_ENTER() ALOGV("Enter %s", __func__) +#define MESON_LOG_FUN_LEAVE() ALOGV("Leave %s", __func__) +#else +#define MESON_LOG_FUN_ENTER() ((void)0) +#define MESON_LOG_FUN_LEAVE() ((void)0) +#endif + +#define MESON_LOG_EMPTY_FUN() \ + ALOGD("ERR: PLEASE FIX NON-IMPLEMENT FUN(%s).", __func__); + +#endif/*MESON_LOG_H*/ diff --git a/mesondisplay/include/utile.h b/mesondisplay/include/utile.h new file mode 100644 index 0000000..d7014f5 --- a/dev/null +++ b/mesondisplay/include/utile.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019 Amlogic, Inc. All rights reserved. + * + * This source code is subject to the terms and conditions defined in the + * file 'LICENSE' which is part of this source code package. + * + * Description: + */ + +#ifndef MESON_DISPLAY_UTIL_H +#define MESON_DISPLAY_UTIL_H +#define DEBUG +#ifdef DEBUG +#include <unistd.h> +#include <time.h> +#define COLOR_F (getpid()%6)+1 +#define COLOR_B 8 +#ifndef RECOVERY_MODE +#include <android/log.h> +#define DEBUG_INFO(fmt, arg...) do { __android_log_print(ANDROID_LOG_INFO, "MesonDisplay", fmt " [in %s:%d]\n", ##arg, __func__, __LINE__);}while(0) +#else +#define DEBUG_INFO(fmt, arg...) do { fprintf(stderr, "[meson_display: Debug:PID[%5d]:%8ld]\033[3%d;4%dm " fmt "\033[0m [in %s:%d]\n",getpid(), time(NULL), COLOR_F, COLOR_B, ##arg, __func__, __LINE__);}while(0) +#endif +#else +#define DEBUG_INFO(fmt, arg...) +#endif //DEBUG + +#define DEBUG_INFO_ONCE(...) do { \ + static int a = 1; \ + if (a == 1) { \ + a = 0; \ + DEBUG_INFO(__VA_ARGS__); \ + };} while(0) + + +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&) = delete; \ + void operator=(const TypeName&) = delete + +#ifndef UNUSED +#define UNUSED(s) (void)s +#endif +#ifndef NOTIMPLEMENTED +#define NOTIMPLEMENTED DEBUG_INFO("Function:%s not implemented", __PRETTY_FUNCTION__); +#endif +#endif //MESON_DISPLAY_UTIL_H diff --git a/mesondisplay/service/Android.mk b/mesondisplay/service/Android.mk new file mode 100644 index 0000000..cfd03be --- a/dev/null +++ b/mesondisplay/service/Android.mk @@ -0,0 +1,2 @@ +LOCAL_PATH:= $(call my-dir) +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/mesondisplay/service/DisplayService.cpp b/mesondisplay/service/DisplayService.cpp new file mode 100644 index 0000000..03085d8 --- a/dev/null +++ b/mesondisplay/service/DisplayService.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2020 Amlogic, Inc. All rights reserved. + * + * This source code is subject to the terms and conditions defined in the + * file 'LICENSE' which is part of this source code package. + * + * Description: + * Meson display server side implement + */ + +#include "DisplayService.h" +#include "MesonLog.h" +#include "misc.h" + +namespace meson{ +using namespace std; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_handle; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::vendor::amlogic::display::meson_display_ipc::V1_0::Error; +using ConnectorType = DisplayAdapter::ConnectorType; + +MesonIpcServer::MesonIpcServer() { +} + +bool MesonIpcServer::check_recursion_record_and_push(const std::string& str) { + if (recursion_record.size() >= RECURSION_LIMIT) { + DEBUG_INFO("Service reach recursion limited(%d), show stack below", RECURSION_LIMIT); + //show the first str on top + DEBUG_INFO("%s", str.c_str()); + while (!recursion_record.empty()) { + std::string stack; + recursion_record.top(stack); + DEBUG_INFO("%s", stack.c_str()); + recursion_record.pop(); + } + return false; + } + recursion_record.push(str); + return true; +}; + +Return<void> MesonIpcServer::send_msg_wait_reply(const hidl_string& msg_in, send_msg_wait_reply_cb _hidl_cb) { + bool ret; + Json::Reader reader; + Json::Value value, reply; + Json::FastWriter write; + hidl_string out_str; + const std::string tmp = msg_in.c_str(); + DEBUG_INFO("Server(s):<<:%s:", msg_in.c_str()); + + if (!check_recursion_record_and_push(tmp)) { + _hidl_cb(""); + return Void(); + } + + ret = reader.parse(tmp, value); + if (!ret) { + DEBUG_INFO("Server message decode error!"); + _hidl_cb(""); + } else { + message_handle(value, reply); + out_str = write.write(reply); + DEBUG_INFO("Server:>>:%s:", out_str.c_str()); + _hidl_cb(out_str); + } + recursion_record.pop(); + return Void(); +} + +Return<void> MesonIpcServer::send_msg(const hidl_string& msg_in) { + bool ret; + Json::Reader reader; + Json::Value value, reply; + const std::string tmp = msg_in.c_str(); + DEBUG_INFO("Server:<<:%s:", msg_in.c_str()); + + if (!check_recursion_record_and_push(tmp)) { + return Void(); + } + + ret = reader.parse(tmp, value); + if (!ret) { + DEBUG_INFO("Server message decode error!"); + } else { + message_handle(value, reply); + } + recursion_record.pop(); + return Void(); +} + +void MesonIpcServer::message_handle(Json::Value& in, Json::Value& out) { + UNUSED(in); + UNUSED(out); + NOTIMPLEMENTED; +} + +Return<void> MesonIpcServer::captureDisplayScreen(const int32_t displayId, const int32_t layerId, + captureDisplayScreen_cb hidl_cb) { + UNUSED(displayId); + UNUSED(layerId); + UNUSED(hidl_cb); + NOTIMPLEMENTED; + return Void(); +} + +DisplayServer::DisplayServer(std::unique_ptr<DisplayAdapter>& adapter) { + if (!adapter) { + DEBUG_INFO("Server create with null adapter!"); + } + this->adapter = std::move(adapter); +#if 1 + if (registerAsService() != android::OK) { + DEBUG_INFO("Server RegisterAsServer failed(%d)!", registerAsService()); + } else { + DEBUG_INFO("register success"); + } +#endif +} + +void DisplayServer::message_handle(Json::Value& in, Json::Value& out) { + std::string cmd,tmp1; + Json::Value ret; + if (!adapter || !in.isMember("cmd")) { + DEBUG_INFO("Server: Display Adapter not ready or cmd formate issue!"); + return; + } + cmd = in["cmd"].asString(); + DEBUG_INFO("Server Handle[%s]", cmd.c_str()); + if (cmd == "displayType") { + ret = adapter->displayType(); + } else if (cmd == "getSupportDisplayModes") { + vector<DisplayModeInfo> displayModeList; + Json::Value list; + if (!in.isMember("p_displayType")) + goto OUT; + adapter->getSupportDisplayModes(displayModeList, (ConnectorType)in["p_displayType"].asUInt()); + int index = 0; + for (auto i : displayModeList) { + Json::Value mode; + if (true == DisplayMode2Json(i, mode)) { + list[index++] = mode; + } + } + ret["displayModeList"] = list; + } else if (cmd == "getDisplayMode") { + std::string mode; + if (!in.isMember("p_displayType")) + goto OUT; + adapter->getDisplayMode(mode, (ConnectorType)in["p_displayType"].asUInt()); + ret["mode"] = mode; + } else if (cmd == "setDisplayMode") { + if (!in.isMember("p_displayType") || !in.isMember("p_mode")) + goto OUT; + adapter->setDisplayMode(in["p_mode"].asString(), (ConnectorType)in["p_displayType"].asUInt()); + } else if (cmd == "setPrefDisplayMode") { + if (!in.isMember("p_displayType") || !in.isMember("p_mode")) + goto OUT; + adapter->setPrefDisplayMode(in["p_mode"].asString(), (ConnectorType)in["p_displayType"].asUInt()); + } else { + DEBUG_INFO("CMD not implement!"); + } +OUT: + out["ret"] = ret; +} + +Return<void> DisplayServer::captureDisplayScreen(const int32_t displayId, const int32_t layerId, + captureDisplayScreen_cb hidl_cb) { + UNUSED(displayId); + UNUSED(layerId); + + MESON_LOGD("DisplayServer captureDisplayScreen"); + hidl_vec<hidl_handle> outHandles; + + if (!adapter) { + MESON_LOGD("DisplayServer display Adatprer not ready"); + outHandles.setToExternal(nullptr, 0); + hidl_cb(Error::NO_RESOURCES, outHandles); + return Void(); + } + + const native_handle_t* bufferHandle = nullptr; + bool ret = adapter->captureDisplayScreen(&bufferHandle); + if (!ret) { + outHandles.setToExternal(nullptr, 0); + hidl_cb(Error::NO_RESOURCES, outHandles); + return Void(); + } + + std::vector<hidl_handle> handles; + handles.push_back(bufferHandle); + + outHandles.setToExternal(const_cast<hidl_handle*>(handles.data()), handles.size()); + hidl_cb(Error::NONE, outHandles); + + // release native handle + if (bufferHandle) { + gralloc_unref_dma_buf(const_cast<native_handle_t*> (bufferHandle)); + gralloc_free_dma_buf(const_cast<native_handle_t*> (bufferHandle)); + } + return Void(); +} + +} //namespace android diff --git a/mesondisplay/service/DisplayService.h b/mesondisplay/service/DisplayService.h new file mode 100644 index 0000000..1b8f1f7 --- a/dev/null +++ b/mesondisplay/service/DisplayService.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2019 Amlogic, Inc. All rights reserved. + * + * This source code is subject to the terms and conditions defined in the + * file 'LICENSE' which is part of this source code package. + * + * Description: + */ + +#pragma once + +#include "DisplayAdapter.h" +#include <json/json.h> +#include <vendor/amlogic/display/meson_display_ipc/1.0/IMesonDisplayIPC.h> +#include <stdbool.h> +#include <pthread.h> +#include "utile.h" +#include <stack> + +//Limite the server recursion. +const int RECURSION_LIMIT = 10; + +namespace meson { +using ::android::hardware::hidl_string; +using ::android::hardware::Return; +using ::vendor::amlogic::display::meson_display_ipc::V1_0::IMesonDisplayIPC; +using ::android::hardware::hidl_string; +using ::android::hardware::Return; +using namespace std; + +template <typename T> +class SafeStack { +public: + SafeStack() { + int ret = pthread_mutex_init(&mutex, NULL); + if (ret) + DEBUG_INFO("mutex init with error!"); + }; + ~SafeStack() { + pthread_mutex_destroy(&mutex); + }; + void push(const T e) { + pthread_mutex_lock(&mutex); + m_stack.push(e); + pthread_mutex_unlock(&mutex); + }; + void pop() { + pthread_mutex_lock(&mutex); + if (!m_stack.empty()) + m_stack.pop(); + pthread_mutex_unlock(&mutex); + }; + size_t size() { + size_t size; + pthread_mutex_lock(&mutex); + size = m_stack.size(); + pthread_mutex_unlock(&mutex); + return size; + }; + bool empty() { + bool ret; + pthread_mutex_lock(&mutex); + ret = m_stack.empty(); + pthread_mutex_unlock(&mutex); + return ret; + }; + void top(T& t) { + pthread_mutex_lock(&mutex); + t = m_stack.top(); + pthread_mutex_unlock(&mutex); + }; +private: + pthread_mutex_t mutex; + std::stack<T> m_stack; +}; + +class MesonIpcServer : public IMesonDisplayIPC{ +public: + MesonIpcServer(); + virtual ~MesonIpcServer() = default; + // Methods from ::vendor::amlogic::display::meson_display_ipc::V1_0::IMesonDisplayIPC follow. + Return<void> send_msg_wait_reply(const hidl_string& msg_in, send_msg_wait_reply_cb _hidl_cb) override; + Return<void> send_msg(const hidl_string& msg_in) override; + virtual void message_handle(Json::Value& in, Json::Value& out); + virtual Return<void> captureDisplayScreen(const int32_t displayId, + const int32_t layerId, captureDisplayScreen_cb hidl_cb) override; + +private: + bool check_recursion_record_and_push(const std::string& str); + SafeStack<std::string> recursion_record; + DISALLOW_COPY_AND_ASSIGN(MesonIpcServer); +}; + + +class DisplayServer: public MesonIpcServer { +public: + void message_handle(Json::Value& in, Json::Value& out) override; + DisplayServer(std::unique_ptr<DisplayAdapter>& adapter); + DisplayServer() = default; + Return<void> captureDisplayScreen(const int32_t displayId, + const int32_t layerId, captureDisplayScreen_cb hidl_cb) override; + +private: + std::unique_ptr<DisplayAdapter> adapter; + DISALLOW_COPY_AND_ASSIGN(DisplayServer); +}; + +} //namespace meson diff --git a/mesondisplay/service/current.txt b/mesondisplay/service/current.txt new file mode 100644 index 0000000..41146ed --- a/dev/null +++ b/mesondisplay/service/current.txt @@ -0,0 +1 @@ +7e7bd3f6059a5419909d27c29c33c6a51e8362ee475fa884ca383d62d61b1b8a vendor.amlogic.display.meson_display_ipc@1.0::IMesonDisplayIPC diff --git a/mesondisplay/service/interfaces/Android.bp b/mesondisplay/service/interfaces/Android.bp new file mode 100644 index 0000000..3068f8c --- a/dev/null +++ b/mesondisplay/service/interfaces/Android.bp @@ -0,0 +1,18 @@ +// Copyright (C) 2008 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. + +hidl_package_root { + name: "vendor.amlogic.display", + path: "hardware/amlogic/hwcomposer/mesondisplay/service/interfaces", +} diff --git a/mesondisplay/service/interfaces/meson_display_ipc/1.0/Android.bp b/mesondisplay/service/interfaces/meson_display_ipc/1.0/Android.bp new file mode 100644 index 0000000..e43c4b4 --- a/dev/null +++ b/mesondisplay/service/interfaces/meson_display_ipc/1.0/Android.bp @@ -0,0 +1,18 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "vendor.amlogic.display.meson_display_ipc@1.0", + root: "vendor.amlogic.display", + srcs: [ + "types.hal", + "IMesonDisplayIPC.hal", + ], + interfaces: [ + "android.hidl.base@1.0", + ], + types: [ + "Error", + ], + gen_java: false, +} + diff --git a/mesondisplay/service/interfaces/meson_display_ipc/1.0/IMesonDisplayIPC.hal b/mesondisplay/service/interfaces/meson_display_ipc/1.0/IMesonDisplayIPC.hal new file mode 100644 index 0000000..440a31f --- a/dev/null +++ b/mesondisplay/service/interfaces/meson_display_ipc/1.0/IMesonDisplayIPC.hal @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2020 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. + */ + +package vendor.amlogic.display.meson_display_ipc@1.0; + +interface IMesonDisplayIPC{ + send_msg_wait_reply(string msg_in) + generates (string msg_out); + send_msg(string msg_in); + + /** + * Capture screen of specific layer. + * @param displayId is the hwc display id which now is reserved. + * only supoort the primary Display + * @param layerId is the hwc layer id which now is reserved + * @return error is NONE upon sucess. otherwise + * BAD_VALUE when the id is invalid (reserved) + * NO_RESOURCE when capture failed + * @return buffer is the return buffer handle and has the type + * buffer_handle_t + */ + captureDisplayScreen(int32_t displayId, int32_t layerId) + generates (Error error, + vec<handle> outHandles); +}; diff --git a/mesondisplay/service/interfaces/meson_display_ipc/1.0/types.hal b/mesondisplay/service/interfaces/meson_display_ipc/1.0/types.hal new file mode 100644 index 0000000..746e68c --- a/dev/null +++ b/mesondisplay/service/interfaces/meson_display_ipc/1.0/types.hal @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2020 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. + */ + +package vendor.amlogic.display.meson_display_ipc@1.0; + +/** Return codes from all functions. */ +enum Error : int32_t { + NONE = 0, /* no error */ + BAD_PARAMETER = 1, /* invalid id, etc. */ + NO_RESOURCES = 2, /* temporary failure due to resource contention */ +}; + diff --git a/mesondisplay/test/Android.bp b/mesondisplay/test/Android.bp new file mode 100644 index 0000000..ab3f438 --- a/dev/null +++ b/mesondisplay/test/Android.bp @@ -0,0 +1,27 @@ +cc_binary { + name: "meson_display_screencap", + +// cflags: [ +// "-Wall", +// "-Werror", +// ], + + srcs: [ + "display_screencap.cpp", + ], + + shared_libs: [ + "liblog", + "libui", + "libcutils", + "libgui", + "libhwui", + "libamgralloc_ext@2", + "libmeson_display_adapter_remote@1", + "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", + ], + + clang: true, +} diff --git a/mesondisplay/test/display_client.cpp b/mesondisplay/test/display_client.cpp new file mode 100644 index 0000000..72183df --- a/dev/null +++ b/mesondisplay/test/display_client.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2019 Amlogic, Inc. All rights reserved. + * + * This source code is subject to the terms and conditions defined in the + * file 'LICENSE' which is part of this source code package. + * + * Description: + */ + +#include <pthread.h> +#include <sys/time.h> +#include <stdio.h> +#include <sys/wait.h> +#include <stdio.h> +#include <getopt.h> +#include <string.h> + +#include "DisplayAdapter.h" + +using meson::DisplayAdapter; +using std::unique_ptr; + +static const char* short_option = ""; +static const struct option long_option[] = { + {"list-modes", no_argument, 0, 'l'}, + {"chang-mode", required_argument, 0, 'c'}, + {"get-property", required_argument, 0, 'g'}, + {"set-property", required_argument, 0, 's'}, + {"raw-cmd", required_argument, 0, 'r'}, + {"G", required_argument, 0, 'G'}, + {"S", required_argument, 0, 'S'}, + {0, 0, 0, 0} +}; + +static void print_usage(const char* name) { + printf("Usage: %s [-lcrgs]\n" + "Get or change the mode setting of the weston drm output.\n" + "Options:\n" + " -l,--list-modes \tlist connector support modes\n" + " -c,--change-mode MODE \tchange connector current mode, MODE format like:%%dx%%d@%%d width,height,refresh\n" + " -g,--get-connector-property \"PROPERTY\"\tget connector property\n" + " -s,--set-connector-property \"PROPERTY\"=value\tset connector property\n" + " -G \"[ui-rect|display-mode]\"\tget [logic ui rect|display mode]\n" + " -S \"[ui-rect]\"\tset [logic ui rect]\n" + " \t eg: \"Content Protection\"=1\n" + " -r,--raw-cmd \tsend raw cmd\n", name); +} + + +int main(int argc, char* argv[]) { + std::vector<meson::DisplayModeInfo> displayModeList; + if (argc == 1) { + print_usage(argv[0]); + return 0; + } + unique_ptr<DisplayAdapter> client = meson::DisplayAdapterCreateRemote(); + DisplayAdapter::ConnectorType type = DisplayAdapter::CONN_TYPE_HDMI; + DEBUG_INFO("Start client"); + + int opt; + while ((opt = getopt_long_only(argc, argv, short_option, long_option, NULL)) != -1) { + switch (opt) { + case 'l': + if (client->getSupportDisplayModes(displayModeList, type)) { + for (auto mode : displayModeList) { + printf("%s %u %u %u %u %f \n", mode.name.c_str(), mode.dpiX, mode.dpiY, mode.pixelW, mode.pixelH, mode.refreshRate); + } + } + break; + case 'c': + client->setDisplayMode(optarg, type); + break; + case 'g': + NOTIMPLEMENTED; + break; + case 's': + NOTIMPLEMENTED; + break; + case 'G': + if (optarg == NULL) + break; + if (0 == memcmp("display-mode", optarg, sizeof("display-mode"))) { + std::string mode; + client->getDisplayMode(mode, type); + printf("%s\n", mode.c_str()); + } else { + NOTIMPLEMENTED; + } + break; + case 'S': + if (optarg == NULL) + break; + { + if (0 == memcmp("display-mode", optarg, sizeof("display-mode"))) { + if (optind + 1 > argc) { + DEBUG_INFO("miss parameter"); + break; + } + client->setDisplayMode(argv[optind], type); + optind++; + } else { + NOTIMPLEMENTED; + } + } + break; + case 'r': + NOTIMPLEMENTED; + break; + default: + print_usage(argv[0]); + } + }; + + DEBUG_INFO("Exit client"); + return 0; +} diff --git a/mesondisplay/test/display_recovery_test.cpp b/mesondisplay/test/display_recovery_test.cpp new file mode 100644 index 0000000..6effc5e --- a/dev/null +++ b/mesondisplay/test/display_recovery_test.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2019 Amlogic, Inc. All rights reserved. + * + * This source code is subject to the terms and conditions defined in the + * file 'LICENSE' which is part of this source code package. + * + * Description: + */ + +#include <pthread.h> +#include <sys/time.h> +#include <stdio.h> +#include <sys/wait.h> +#include <stdio.h> +#include <getopt.h> +#include <string.h> + +#include "DisplayAdapter.h" + +using meson::DisplayAdapter; +using std::unique_ptr; + +static const char* short_option = ""; +static const struct option long_option[] = { + {"list-modes", no_argument, 0, 'l'}, + {"chang-mode", required_argument, 0, 'c'}, + {"get-property", required_argument, 0, 'g'}, + {"set-property", required_argument, 0, 's'}, + {"raw-cmd", required_argument, 0, 'r'}, + {"G", required_argument, 0, 'G'}, + {"S", required_argument, 0, 'S'}, + {0, 0, 0, 0} +}; + +static void print_usage(const char* name) { + printf("Usage: %s [-lcrgs]\n" + "Get or change the mode setting of the weston drm output.\n" + "Options:\n" + " -l,--list-modes \tlist connector support modes\n" + " -c,--change-mode MODE \tchange connector current mode, MODE format like:%%dx%%d@%%d width,height,refresh\n" + " -g,--get-connector-property \"PROPERTY\"\tget connector property\n" + " -s,--set-connector-property \"PROPERTY\"=value\tset connector property\n" + " -G \"[ui-rect|display-mode]\"\tget [logic ui rect|display mode]\n" + " -S \"[ui-rect]\"\tset [logic ui rect]\n" + " \t eg: \"Content Protection\"=1\n" + " -r,--raw-cmd \tsend raw cmd\n", name); +} + + +int main(int argc, char* argv[]) { + std::vector<meson::DisplayModeInfo> displayModeList; + if (argc == 1) { + print_usage(argv[0]); + return 0; + } + unique_ptr<DisplayAdapter> client = meson::DisplayAdapterCreateLocal(meson::DisplayAdapter::BackendType::DISPLAY_TYPE_FBDEV); + DisplayAdapter::ConnectorType type = DisplayAdapter::CONN_TYPE_HDMI; + DEBUG_INFO("Start client"); + + int opt; + while ((opt = getopt_long_only(argc, argv, short_option, long_option, NULL)) != -1) { + switch (opt) { + case 'l': + client->getSupportDisplayModes(displayModeList, type); + for (auto mode : displayModeList) { + printf("%s %u %u %u %u %f \n", mode.name.c_str(), mode.dpiX, mode.dpiY, mode.pixelW, mode.pixelH, mode.refreshRate); + } + break; + case 'c': + client->setDisplayMode(optarg, type); + break; + case 'g': + NOTIMPLEMENTED; + break; + case 's': + NOTIMPLEMENTED; + break; + case 'G': + if (optarg == NULL) + break; + if (0 == memcmp("display-mode", optarg, sizeof("display-mode"))) { + std::string mode; + client->getDisplayMode(mode, type); + printf("%s\n", mode.c_str()); + } else { + NOTIMPLEMENTED; + } + break; + case 'S': + if (optarg == NULL) + break; + { + if (0 == memcmp("display-mode", optarg, sizeof("display-mode"))) { + if (optind + 1 > argc) { + DEBUG_INFO("miss parameter"); + break; + } + client->setDisplayMode(argv[optind], type); + optind++; + } else { + NOTIMPLEMENTED; + } + } + break; + case 'r': + NOTIMPLEMENTED; + break; + default: + print_usage(argv[0]); + } + }; + + DEBUG_INFO("Exit client"); + return 0; +} diff --git a/mesondisplay/test/display_screencap.cpp b/mesondisplay/test/display_screencap.cpp new file mode 100644 index 0000000..0c7dfaa --- a/dev/null +++ b/mesondisplay/test/display_screencap.cpp @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2020 Amlogic, Inc. All rights reserved. + * + * This source code is subject to the terms and conditions defined in the + * file 'LICENSE' which is part of this source code package. + * + * Description: + * Display screen test + */ + +#include <errno.h> +#include <unistd.h> +#include <stdio.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> + +#include <linux/fb.h> +#include <sys/mman.h> + +#include <ui/Rect.h> +#include <ui/GraphicTypes.h> +#include <ui/PixelFormat.h> +#include <ui/GraphicBufferMapper.h> +#include <ui/GraphicBufferAllocator.h> + +#include <cutils/properties.h> + +#include <system/graphics.h> + +#include "DisplayAdapter.h" +#include "am_gralloc_ext.h" +//#include "misc.h" + +// TODO: Fix Skia. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#include <SkImageEncoder.h> +#include <SkData.h> +#include <SkColorSpace.h> +#pragma GCC diagnostic pop + +using namespace android; + +static void usage(const char* pname) { + fprintf(stderr, + "usage: %s [-h] [-r] [-l layer-id] [FILENAME]\n" + " -h: print this message\n" + " -r: save as raw data or not.\n" + " -l: specify the hwc layer id to capture(not implement now)\n" + " see \"dumpsys SurfaceFlinger\" for valid layer IDS.\n" + "if FILENAME not given, the results will be printed to sdtout.\n", + pname); +} + +static SkColorType flinger2skia(PixelFormat f) { + switch (f) { + case PIXEL_FORMAT_RGB_565: + return kRGB_565_SkColorType; + default: + return kN32_SkColorType; + } +} + +static int32_t gralloc_unref_dma_buf(native_handle_t * hnd) { + static GraphicBufferMapper & maper = GraphicBufferMapper::get(); + + bool bfreed = false; + if (am_gralloc_is_valid_graphic_buffer(hnd)) { + if (NO_ERROR == maper.freeBuffer(hnd)) { + bfreed = true; + } + } + + if (bfreed == false) { + /*may be we got handle not alloc by gralloc*/ + native_handle_close(hnd); + native_handle_delete(hnd); + } + + return 0; +} + +static int32_t gralloc_lock_dma_buf( + native_handle_t * handle, void** vaddr) { + static GraphicBufferMapper & maper = GraphicBufferMapper::get(); + uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN; + int w = am_gralloc_get_width(handle); + int h = am_gralloc_get_height(handle); + + Rect r(w, h); + if (NO_ERROR == maper.lock(handle, usage, r, vaddr)) + return 0; + + fprintf(stderr, "lock buffer failed\n"); + return -EINVAL; +} + +static int32_t gralloc_unlock_dma_buf(native_handle_t * handle) { + static GraphicBufferMapper & maper = GraphicBufferMapper::get(); + if (NO_ERROR == maper.unlock(handle)) + return 0; + return -EINVAL; +} + +int main(int argc, char **argv) { + const char* pname = argv[0]; + int layerId = -1; + int c; + bool rawData = false; + + while ((c = getopt(argc, argv, "rhl:")) != -1) { + switch (c) { + case 'l': + layerId = atoi(optarg); + break; + case 'r': + rawData = true; + break; + case '?': + case 'h': + usage(pname); + return 1; + } + } + + argc -= optind; + argv += optind; + + int fd = -1; + const char* fn = NULL; + if (argc == 0) { + fd = dup(STDOUT_FILENO); + } else if (argc == 1) { + fn = argv[0]; + fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664); + if (fd == -1) { + fprintf(stderr, "Error opening file: %s (%s)\n", fn, strerror(errno)); + return 1; + } + } + + if (fd == -1) { + usage(pname); + return 1; + } + + const native_handle_t *outBufferHandle = nullptr; + std::unique_ptr<meson::DisplayAdapter> displayAdapter = meson::DisplayAdapterCreateRemote(); + + if (!displayAdapter) { + fprintf(stderr, "DisplayAdapter init failed\n"); + return 1; + } + displayAdapter->captureDisplayScreen(&outBufferHandle); + + if (outBufferHandle == nullptr) { + fprintf(stderr, "capture display screen got a null buffhandle\n"); + close(fd); + return 1; + } + + fprintf(stderr, "\npassh handle nubFds %d, numInts %d\n", + outBufferHandle->numFds, outBufferHandle->numInts); + + for (int i = 0; i < outBufferHandle->numFds; i++) { + fprintf(stderr, "Get naitve handle fd[%d]= %d\n", i, outBufferHandle->data[i]); + } + + native_handle_t *bufferHandle = const_cast<native_handle_t*> (outBufferHandle); + + int width = am_gralloc_get_width(bufferHandle); + int height = am_gralloc_get_height(bufferHandle); + int stride = am_gralloc_get_stride_in_pixel(bufferHandle); + int format = am_gralloc_get_format(bufferHandle); + + size_t size = stride * height * bytesPerPixel(format); + + fprintf(stderr, "format %d, (%d, %d) stride %d\n", + format, width, height, stride); + void* mapBase = nullptr; + + if (gralloc_lock_dma_buf(bufferHandle, &mapBase) != 0) { + fprintf(stderr, "lock dma buff failed\n"); + close(fd); + return 1; + } + + if (property_get_bool("vendor.meson.display.debug", false)) { + sleep(30); + } + fprintf(stderr, "start screencap size=%u\n", size); + + if (rawData == false) { + const SkImageInfo info = + SkImageInfo::Make(width, height, flinger2skia(format), kPremul_SkAlphaType, nullptr); + + SkPixmap pixmap(info, mapBase, stride * bytesPerPixel(format)); + struct FDWStream final : public SkWStream { + size_t fBytesWritten = 0; + int fFd; + FDWStream(int f) : fFd(f) {} + size_t bytesWritten() const override { + return fBytesWritten; + } + bool write(const void* buffer, size_t size) override { + fBytesWritten += size; + return size == 0 || ::write(fFd, buffer, size) > 0; + } + } fdStream(fd); + (void)SkEncodeImage(&fdStream, pixmap, SkEncodedImageFormat::kPNG, 100); + } else { + size_t Bpp = bytesPerPixel(format); + for (size_t y = 0 ; y < height ; y++) { + write(fd, mapBase, width*Bpp); + mapBase = (void *)((char *)mapBase + stride*Bpp); + } + } + + close(fd); + // after use, need unlock and free native handle + gralloc_unlock_dma_buf(bufferHandle); + gralloc_unref_dma_buf(bufferHandle); + + fprintf(stderr, "display screen cap finish!\n"); + + if (property_get_bool("vendor.meson.display.debug", false)) { + sleep(30); + } + + return 0; +} diff --git a/mesondisplay/test/ipc_test.cpp b/mesondisplay/test/ipc_test.cpp new file mode 100644 index 0000000..9407b69 --- a/dev/null +++ b/mesondisplay/test/ipc_test.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2019 Amlogic, Inc. All rights reserved. + * + * This source code is subject to the terms and conditions defined in the + * file 'LICENSE' which is part of this source code package. + * + * Description: + */ + +#include "DisplayService.h" +#include "DisplayClient.h" +#include <sys/wait.h> +#include <unistd.h> +#include <hidl/HidlTransportSupport.h> +#include <binder/ProcessState.h> +#include <binder/IPCThreadState.h> +#include <utils/RefBase.h> +#include <binder/IServiceManager.h> +#include <utils/String16.h> + +class ipcserver: public meson::MesonIpcServer { + public: + void message_handle(Json::Value& in, Json::Value& out) { + Json::FastWriter write; + UNUSED(in); + UNUSED(out); + DEBUG_INFO("Get message:%s", write.write(in).c_str()); + }; + ipcserver() { + DEBUG_INFO("ipcserver created"); + if (registerAsService() != android::OK) { + DEBUG_INFO("RegisterAsServer failed(%d)!", registerAsService()); + } + }; + virtual ~ipcserver() = default; +}; + +void print_help(const char* cmd) { + printf("Useage:\n %s server : start a ipc server \n%s : start a ipc client test.", cmd, cmd); +}; + +int main(int argc, char* argv[]) { + UNUSED(argv); + print_help(argv[0]); + if (argc == 1) { + //IPC client + Json::Value a = "test"; + Json::Reader reader; + Json::FastWriter writer; + bool ok = reader.parse("{ \"property\" : \"value\" }", a); + if (!ok) { + DEBUG_INFO("format error!"); + } + + auto client = meson::DisplayClient::create("meson_dispaly"); + while (true) { + DEBUG_INFO("begin"); + DEBUG_INFO("Send=>%s", writer.write(a).c_str()); + sleep(3); + client->send_request(a); + sleep(3); + } + } else { + //IPC Server + android::ProcessState::initWithDriver("/dev/vndbinder"); + android::hardware::configureRpcThreadpool(16, false); + + static ipcserver* m_server = new ipcserver(); + UNUSED(m_server); + android::IPCThreadState::self()->joinThreadPool(); + } + return 0; +}; diff --git a/mesondisplay/test/test.sh b/mesondisplay/test/test.sh new file mode 100644 index 0000000..dbee2e3 --- a/dev/null +++ b/mesondisplay/test/test.sh @@ -0,0 +1,19 @@ +# 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. + +cycle=0 +while true;do + list=`meson_display_client -l|cut -d' ' -f1`; + let cycle++; + + for mode in $list;do + echo -en "\rchange mode[$cycle] $(meson_display_client -G display-mode) =>$mode"; + meson_display_client -c $mode; + sleep 2; + done +done |