diff options
author | Ben Fennema <fennema@google.com> | 2018-05-08 13:50:32 -0700 |
---|---|---|
committer | Ben Fennema <fennema@google.com> | 2018-05-08 14:36:40 -0700 |
commit | d39a514dd0540cf47e121775a77e9ac1b578bdb1 (patch) | |
tree | 77c1c6c4ab08abbdcc067f2f05cf8a7cb50696a1 | |
parent | 3a26d0f124f7d89c4e01078dd44e6ed656e5ccaf (diff) | |
download | display-d39a514dd0540cf47e121775a77e9ac1b578bdb1.tar.gz |
display: msm8909w caf release LW.BR.4.0-00800-8x09w.0 for SD2100.
MSM8909W display HAL code copied from CAF release LW.BR.4.0-00800-8x09w.0.
Bug: 79356346
Test: build
Change-Id: Ie801976595c8ed9164b0d91737f5daf40764d8a6
Signed-off-by: Ben Fennema <fennema@google.com>
295 files changed, 50516 insertions, 21464 deletions
diff --git a/msm8909/.clang-format b/msm8909/.clang-format new file mode 100644 index 00000000..9082c400 --- /dev/null +++ b/msm8909/.clang-format @@ -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 diff --git a/msm8909/.gitignore b/msm8909/.gitignore new file mode 100644 index 00000000..ad71dd6c --- /dev/null +++ b/msm8909/.gitignore @@ -0,0 +1,4 @@ +CMakeLists.txt +.idea/ +.editorconfig +.clang-complete diff --git a/msm8909/Android.bp b/msm8909/Android.bp new file mode 100644 index 00000000..ea40594f --- /dev/null +++ b/msm8909/Android.bp @@ -0,0 +1,42 @@ +soong_namespace { +} + +cc_defaults { + name: "display_defaults", + cflags: [ + "-Wno-missing-field-initializers", + "-Wconversion", + "-Wall", + "-Werror", + "-std=c++14", + ], + shared_libs: [ + "liblog", + "libcutils", + "libutils", + ], + header_libs: ["display_headers"], + clang: true, +} + +cc_library_headers { + name: "display_headers", + vendor_available: true, + export_include_dirs: [ + "include", + "libcopybit", + "libdrmutils", + "libqdutils", + "libqservice", + "gpu_tonemapper", + "sdm/include", + "gralloc", + ], + header_libs: ["libhardware_headers"], + export_header_lib_headers: ["libhardware_headers"], +} + +subdirs = [ + "libqservice", + "libqdutils", +] diff --git a/msm8909/Android.mk b/msm8909/Android.mk index d8b168d2..f354caf5 100644 --- a/msm8909/Android.mk +++ b/msm8909/Android.mk @@ -1,6 +1,13 @@ -display-hals := libgralloc libgenlock libcopybit liblight -display-hals += libhwcomposer liboverlay libqdutils libhdmi libqservice -display-hals += libmemtrack +sdm-libs := sdm/libs +display-hals := include $(sdm-libs)/utils $(sdm-libs)/core + +ifneq ($(TARGET_IS_HEADLESS), true) + display-hals += libcopybit liblight libmemtrack hdmi_cec \ + $(sdm-libs)/hwc $(sdm-libs)/hwc2 gpu_tonemapper libdrmutils libdisplayconfig +endif + +display-hals += gralloc + ifeq ($(call is-vendor-board-platform,QCOM),true) include $(call all-named-subdir-makefiles,$(display-hals)) else diff --git a/msm8909/common.mk b/msm8909/common.mk index 2465cc86..f8fe936e 100644 --- a/msm8909/common.mk +++ b/msm8909/common.mk @@ -1,69 +1,81 @@ #Common headers -common_includes := $(LOCAL_PATH)/../libgralloc -common_includes += $(LOCAL_PATH)/../liboverlay -common_includes += $(LOCAL_PATH)/../libcopybit -common_includes += $(LOCAL_PATH)/../libqdutils -common_includes += $(LOCAL_PATH)/../libhwcomposer -common_includes += $(LOCAL_PATH)/../libhdmi -common_includes += $(LOCAL_PATH)/../libqservice +display_top := $(call my-dir) +display_config_version := $(shell \ + if [ -d "$(TOP)/vendor/qcom/codeaurora/interfaces/vendor/display/config/1.1" ];\ + then echo DISPLAY_CONFIG_1_1; fi) -ifeq ($(TARGET_USES_POST_PROCESSING),true) - common_flags += -DUSES_POST_PROCESSING - common_includes += $(TARGET_OUT_HEADERS)/pp/inc +#Common C flags +common_flags := -DDEBUG_CALC_FPS -Wno-missing-field-initializers +common_flags += -Wconversion -Wall -Werror -std=c++14 +ifeq ($(TARGET_IS_HEADLESS), true) + common_flags += -DTARGET_HEADLESS + LOCAL_CLANG := false endif -common_header_export_path := qcom/display +ifeq ($(display_config_version), DISPLAY_CONFIG_1_1) + common_flags += -DDISPLAY_CONFIG_1_1 +endif -#Common libraries external to display HAL -common_libs := liblog libutils libcutils libhardware +ifeq ($(TARGET_USES_COLOR_METADATA), true) + common_flags += -DUSE_COLOR_METADATA +endif -#Common C flags -common_flags := -DDEBUG_CALC_FPS -Wno-missing-field-initializers -common_flags += -Wconversion -Wall -Werror -Wno-sign-conversion +ifeq ($(TARGET_USES_QCOM_BSP),true) + common_flags += -DQTI_BSP +endif ifeq ($(ARCH_ARM_HAVE_NEON),true) common_flags += -D__ARM_HAVE_NEON endif -ifeq ($(call is-board-platform-in-list, $(MSM_VIDC_TARGET_LIST)), true) - common_flags += -DVENUS_COLOR_FORMAT +ifeq ($(call is-board-platform-in-list, $(MASTER_SIDE_CP_TARGET_LIST)), true) + common_flags += -DMASTER_SIDE_CP endif -ifeq ($(call is-board-platform-in-list, msm8974 msm8226 msm8610 apq8084 \ - mpq8092 msm_bronze msm8916 msm8994), true) - common_flags += -DMDSS_TARGET +use_hwc2 := false +ifeq ($(TARGET_USES_HWC2), true) + use_hwc2 := true + common_flags += -DVIDEO_MODE_DEFER_RETIRE_FENCE endif -ifeq ($(call is-board-platform-in-list, msm8909), true) - common_flags += -DVENUS_COLOR_FORMAT - common_flags += -DMDSS_TARGET + +ifeq ($(TARGET_USES_GRALLOC1), true) + common_flags += -DUSE_GRALLOC1 endif -ifeq ($(DISPLAY_DEBUG_SWAPINTERVAL),true) - common_flags += -DDEBUG_SWAPINTERVAL +common_includes := system/core/base/include +CHECK_VERSION_LE = $(shell if [ $(1) -le $(2) ] ; then echo true ; else echo false ; fi) +PLATFORM_SDK_NOUGAT = 25 +ifeq "REL" "$(PLATFORM_VERSION_CODENAME)" +ifeq ($(call CHECK_VERSION_LE, $(PLATFORM_SDK_VERSION), $(PLATFORM_SDK_NOUGAT)), true) +version_flag := -D__NOUGAT__ + +# These include paths are deprecated post N +common_includes += $(display_top)/libqdutils +common_includes += $(display_top)/libqservice +common_includes += $(display_top)/gpu_tonemapper +ifneq ($(TARGET_IS_HEADLESS), true) + common_includes += $(display_top)/libcopybit +endif + +common_includes += $(display_top)/include +common_includes += $(display_top)/sdm/include +common_flags += -isystem $(TARGET_OUT_HEADERS)/qcom/display +endif endif -common_flags += -D__STDC_FORMAT_MACROS +common_header_export_path := qcom/display +#Common libraries external to display HAL +common_libs := liblog libutils libcutils libhardware common_deps := kernel_includes := -# Executed only on QCOM BSPs -ifeq ($(TARGET_USES_QCOM_BSP),true) -# Enable QCOM Display features - common_flags += -DQTI_BSP - common_includes += $(BOARD_OPENSOURCE_DIR)/display-frameworks/include -endif -ifneq ($(call is-platform-sdk-version-at-least,18),true) - common_flags += -DANDROID_JELLYBEAN_MR1=1 -endif -ifeq ($(call is-vendor-board-platform,QCOM),true) +ifeq ($(TARGET_COMPILE_WITH_MSM_KERNEL),true) # This check is to pick the kernel headers from the right location. # If the macro above is defined, we make the assumption that we have the kernel # available in the build tree. # If the macro is not present, the headers are picked from hardware/qcom/msmXXXX # failing which, they are picked from bionic. - common_deps += $(BOARD_KERNEL_HEADER_DEPENDENCIES) - kernel_includes += $(BOARD_KERNEL_HEADER_DIR) + common_deps += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr + kernel_includes += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include endif - -common_clang_flags := true diff --git a/msm8909/gpu_tonemapper/Android.mk b/msm8909/gpu_tonemapper/Android.mk new file mode 100644 index 00000000..77ecc4a3 --- /dev/null +++ b/msm8909/gpu_tonemapper/Android.mk @@ -0,0 +1,27 @@ +LOCAL_PATH := $(call my-dir) +include $(LOCAL_PATH)/../common.mk + +include $(CLEAR_VARS) +LOCAL_COPY_HEADERS_TO := $(common_header_export_path) +LOCAL_COPY_HEADERS := TonemapFactory.h Tonemapper.h +include $(BUILD_COPY_HEADERS) + +include $(CLEAR_VARS) +LOCAL_MODULE := libgpu_tonemapper +LOCAL_VENDOR_MODULE := true +LOCAL_MODULE_TAGS := optional +LOCAL_C_INCLUDES := $(TARGET_OUT_HEADERS)/qcom/display/ +LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_SHARED_LIBRARIES := libEGL libGLESv2 libGLESv3 libui libutils liblog +LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps) + +LOCAL_CFLAGS := $(version_flag) -Wno-missing-field-initializers -Wall \ + -Wno-unused-parameter -std=c++11 -DLOG_TAG=\"GPU_TONEMAPPER\" + +LOCAL_SRC_FILES := TonemapFactory.cpp \ + glengine.cpp \ + EGLImageBuffer.cpp \ + EGLImageWrapper.cpp \ + Tonemapper.cpp + +include $(BUILD_SHARED_LIBRARY) diff --git a/msm8909/gpu_tonemapper/EGLImageBuffer.cpp b/msm8909/gpu_tonemapper/EGLImageBuffer.cpp new file mode 100644 index 00000000..eeb02733 --- /dev/null +++ b/msm8909/gpu_tonemapper/EGLImageBuffer.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2016-2017, 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 "EGLImageBuffer.h" +#include <cutils/native_handle.h> +#include <gralloc_priv.h> +#include <ui/GraphicBuffer.h> +#include <map> +#include "EGLImageWrapper.h" +#include "glengine.h" + +//----------------------------------------------------------------------------- +EGLImageKHR create_eglImage(android::sp<android::GraphicBuffer> graphicBuffer) +//----------------------------------------------------------------------------- +{ + bool isProtected = (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED); + EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, + isProtected ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE, + isProtected ? EGL_TRUE : EGL_NONE, EGL_NONE}; + + EGLImageKHR eglImage = eglCreateImageKHR( + eglGetCurrentDisplay(), (EGLContext)EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, + (EGLClientBuffer)(graphicBuffer->getNativeBuffer()), attrs); + + return eglImage; +} + +//----------------------------------------------------------------------------- +EGLImageBuffer::EGLImageBuffer(android::sp<android::GraphicBuffer> graphicBuffer) +//----------------------------------------------------------------------------- +{ + // this->graphicBuffer = graphicBuffer; + this->eglImageID = create_eglImage(graphicBuffer); + this->width = graphicBuffer->getWidth(); + this->height = graphicBuffer->getHeight(); + + textureID = 0; + renderbufferID = 0; + framebufferID = 0; +} + +//----------------------------------------------------------------------------- +EGLImageBuffer::~EGLImageBuffer() +//----------------------------------------------------------------------------- +{ + if (textureID != 0) { + GL(glDeleteTextures(1, &textureID)); + textureID = 0; + } + + if (renderbufferID != 0) { + GL(glDeleteRenderbuffers(1, &renderbufferID)); + renderbufferID = 0; + } + + if (framebufferID != 0) { + GL(glDeleteFramebuffers(1, &framebufferID)); + framebufferID = 0; + } + + // Delete the eglImage + if (eglImageID != 0) + { + eglDestroyImageKHR(eglGetCurrentDisplay(), eglImageID); + eglImageID = 0; + } +} + +//----------------------------------------------------------------------------- +int EGLImageBuffer::getWidth() +//----------------------------------------------------------------------------- +{ + return width; +} + +//----------------------------------------------------------------------------- +int EGLImageBuffer::getHeight() +//----------------------------------------------------------------------------- +{ + return height; +} + +//----------------------------------------------------------------------------- +unsigned int EGLImageBuffer::getTexture() +//----------------------------------------------------------------------------- +{ + if (textureID == 0) { + bindAsTexture(); + } + + return textureID; +} + +//----------------------------------------------------------------------------- +unsigned int EGLImageBuffer::getFramebuffer() +//----------------------------------------------------------------------------- +{ + if (framebufferID == 0) { + bindAsFramebuffer(); + } + + return framebufferID; +} + +//----------------------------------------------------------------------------- +void EGLImageBuffer::bindAsTexture() +//----------------------------------------------------------------------------- +{ + if (textureID == 0) { + GL(glGenTextures(1, &textureID)); + int target = 0x8D65; + GL(glBindTexture(target, textureID)); + GL(glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + GL(glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + GL(glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GL(glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + + GL(glEGLImageTargetTexture2DOES(0x8D65, eglImageID)); + } + + GL(glBindTexture(0x8D65, textureID)); +} + +//----------------------------------------------------------------------------- +void EGLImageBuffer::bindAsFramebuffer() +//----------------------------------------------------------------------------- +{ + if (renderbufferID == 0) { + GL(glGenFramebuffers(1, &framebufferID)); + GL(glGenRenderbuffers(1, &renderbufferID)); + + GL(glBindRenderbuffer(GL_RENDERBUFFER, renderbufferID)); + GL(glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, eglImageID)); + + GL(glBindFramebuffer(GL_FRAMEBUFFER, framebufferID)); + GL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, + renderbufferID)); + GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (result != GL_FRAMEBUFFER_COMPLETE) { + ALOGI("%s Framebuffer Invalid***************", __FUNCTION__); + } + } + + GL(glBindFramebuffer(GL_FRAMEBUFFER, framebufferID)); +} diff --git a/msm8909/gpu_tonemapper/EGLImageBuffer.h b/msm8909/gpu_tonemapper/EGLImageBuffer.h new file mode 100644 index 00000000..23af5732 --- /dev/null +++ b/msm8909/gpu_tonemapper/EGLImageBuffer.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 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 __EGLIMAGE_BUFFER_H__ +#define __EGLIMAGE_BUFFER_H__ + +#include <cutils/native_handle.h> +#include <gralloc_priv.h> +#include <ui/GraphicBuffer.h> +#include "engine.h" + +class EGLImageBuffer { + // android::sp<android::GraphicBuffer> graphicBuffer; + void *eglImageID; + int width; + int height; + uint textureID; + uint renderbufferID; + uint framebufferID; + + public: + int getWidth(); + int getHeight(); + EGLImageBuffer(android::sp<android::GraphicBuffer>); + unsigned int getTexture(); + unsigned int getFramebuffer(); + void bindAsTexture(); + void bindAsFramebuffer(); + ~EGLImageBuffer(); + static EGLImageBuffer *from(const private_handle_t *src); + static void clear(); +}; + +#endif //__EGLIMAGE_BUFFER_H__
\ No newline at end of file diff --git a/msm8909/gpu_tonemapper/EGLImageWrapper.cpp b/msm8909/gpu_tonemapper/EGLImageWrapper.cpp new file mode 100644 index 00000000..dfc16d84 --- /dev/null +++ b/msm8909/gpu_tonemapper/EGLImageWrapper.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2016-2017, 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 "EGLImageWrapper.h" +#include <cutils/native_handle.h> +#include <gralloc_priv.h> +#include <ui/GraphicBuffer.h> +#include <fcntl.h> +#include <linux/msm_ion.h> + +//----------------------------------------------------------------------------- +void free_ion_cookie(int ion_fd, int cookie) +//----------------------------------------------------------------------------- +{ + if (ion_fd && !ioctl(ion_fd, ION_IOC_FREE, &cookie)) { + } else { + ALOGE("ION_IOC_FREE failed: ion_fd = %d, cookie = %d", ion_fd, cookie); + } +} + +//----------------------------------------------------------------------------- +int get_ion_cookie(int ion_fd, int fd) +//----------------------------------------------------------------------------- +{ + int cookie = fd; + + struct ion_fd_data fdData; + memset(&fdData, 0, sizeof(fdData)); + fdData.fd = fd; + + if (ion_fd && !ioctl(ion_fd, ION_IOC_IMPORT, &fdData)) { + cookie = fdData.handle; + } else { + ALOGE("ION_IOC_IMPORT failed: ion_fd = %d, fd = %d", ion_fd, fd); + } + + return cookie; +} + +//----------------------------------------------------------------------------- +EGLImageWrapper::DeleteEGLImageCallback::DeleteEGLImageCallback(int fd) +//----------------------------------------------------------------------------- +{ + ion_fd = fd; +} + +//----------------------------------------------------------------------------- +void EGLImageWrapper::DeleteEGLImageCallback::operator()(int& k, EGLImageBuffer*& eglImage) +//----------------------------------------------------------------------------- +{ + free_ion_cookie(ion_fd, k); + if( eglImage != 0 ) + { + delete eglImage; + } +} + +//----------------------------------------------------------------------------- +EGLImageWrapper::EGLImageWrapper() +//----------------------------------------------------------------------------- +{ + eglImageBufferMap = new android::LruCache<int, EGLImageBuffer*>(32); + ion_fd = open("/dev/ion", O_RDONLY); + callback = new DeleteEGLImageCallback(ion_fd); + eglImageBufferMap->setOnEntryRemovedListener(callback); +} + +//----------------------------------------------------------------------------- +EGLImageWrapper::~EGLImageWrapper() +//----------------------------------------------------------------------------- +{ + if( eglImageBufferMap != 0 ) + { + eglImageBufferMap->clear(); + delete eglImageBufferMap; + eglImageBufferMap = 0; + } + + if( callback != 0 ) + { + delete callback; + callback = 0; + } + + if( ion_fd > 0 ) + { + close(ion_fd); + } + ion_fd = -1; +} +//----------------------------------------------------------------------------- +static EGLImageBuffer* L_wrap(const private_handle_t *src) +//----------------------------------------------------------------------------- +{ + EGLImageBuffer* result = 0; + + native_handle_t *native_handle = const_cast<private_handle_t *>(src); + + int flags = android::GraphicBuffer::USAGE_HW_TEXTURE | + android::GraphicBuffer::USAGE_SW_READ_NEVER | + android::GraphicBuffer::USAGE_SW_WRITE_NEVER; + + if (src->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) { + flags |= android::GraphicBuffer::USAGE_PROTECTED; + } + + android::sp<android::GraphicBuffer> graphicBuffer = + new android::GraphicBuffer(src->unaligned_width, src->unaligned_height, src->format, +#ifndef __NOUGAT__ + 1, // Layer count +#endif + flags, src->width /*src->stride*/, + native_handle, false); + + result = new EGLImageBuffer(graphicBuffer); + + return result; +} + +//----------------------------------------------------------------------------- +EGLImageBuffer *EGLImageWrapper::wrap(const void *pvt_handle) +//----------------------------------------------------------------------------- +{ + const private_handle_t *src = static_cast<const private_handle_t *>(pvt_handle); + + int ion_cookie = get_ion_cookie(ion_fd, src->fd); + EGLImageBuffer* eglImage = eglImageBufferMap->get(ion_cookie); + if( eglImage == 0 ) + { + eglImage = L_wrap(src); + eglImageBufferMap->put(ion_cookie, eglImage); + } + else { + free_ion_cookie(ion_fd, ion_cookie); + } + + return eglImage; +} diff --git a/msm8909/gpu_tonemapper/EGLImageWrapper.h b/msm8909/gpu_tonemapper/EGLImageWrapper.h new file mode 100644 index 00000000..e9a4d68f --- /dev/null +++ b/msm8909/gpu_tonemapper/EGLImageWrapper.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016-2017, 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 __TONEMAPPER_EGLIMAGEWRAPPER_H__ +#define __TONEMAPPER_EGLIMAGEWRAPPER_H__ + +#include <utils/LruCache.h> +#include "EGLImageBuffer.h" + +class EGLImageWrapper { + private: + class DeleteEGLImageCallback : public android::OnEntryRemoved<int, EGLImageBuffer*> + { + private: + int ion_fd; + public: + DeleteEGLImageCallback(int ion_fd); + void operator()(int& ion_cookie, EGLImageBuffer*& eglImage); + }; + + android::LruCache<int, EGLImageBuffer *>* eglImageBufferMap; + DeleteEGLImageCallback* callback; + int ion_fd; + + public: + EGLImageWrapper(); + ~EGLImageWrapper(); + EGLImageBuffer* wrap(const void *pvt_handle); +}; + +#endif //__TONEMAPPER_EGLIMAGEWRAPPER_H__ diff --git a/msm8909/gpu_tonemapper/TonemapFactory.cpp b/msm8909/gpu_tonemapper/TonemapFactory.cpp new file mode 100644 index 00000000..db4b8be6 --- /dev/null +++ b/msm8909/gpu_tonemapper/TonemapFactory.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016-2017, 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 "TonemapFactory.h" +#include <log/log.h> +#include "Tonemapper.h" +#include "engine.h" + +//---------------------------------------------------------------------------------------------------------------------------------------------------------- +Tonemapper *TonemapperFactory_GetInstance(int type, void *colorMap, int colorMapSize, + void *lutXform, int lutXformSize, bool isSecure) +//---------------------------------------------------------------------------------------------------------------------------------------------------------- +{ + // build the tonemapper + Tonemapper *tonemapper = Tonemapper::build(type, colorMap, colorMapSize, lutXform, lutXformSize, isSecure); + + return tonemapper; +} diff --git a/msm8909/gpu_tonemapper/TonemapFactory.h b/msm8909/gpu_tonemapper/TonemapFactory.h new file mode 100644 index 00000000..17cad400 --- /dev/null +++ b/msm8909/gpu_tonemapper/TonemapFactory.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 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 __TONEMAPPER_TONEMAPPERFACTORY_H__ +#define __TONEMAPPER_TONEMAPPERFACTORY_H__ + +#include "Tonemapper.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// returns an instance of Tonemapper +Tonemapper *TonemapperFactory_GetInstance(int type, void *colorMap, int colorMapSize, + void *lutXform, int lutXformSize, bool isSecure); + +#ifdef __cplusplus +} +#endif + +#endif //__TONEMAPPER_TONEMAPPERFACTORY_H__ diff --git a/msm8909/gpu_tonemapper/Tonemapper.cpp b/msm8909/gpu_tonemapper/Tonemapper.cpp new file mode 100644 index 00000000..811e091a --- /dev/null +++ b/msm8909/gpu_tonemapper/Tonemapper.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2016-2017, 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 <utils/Log.h> + +#include "EGLImageWrapper.h" +#include "Tonemapper.h" +#include "engine.h" +#include "forward_tonemap.inl" +#include "fullscreen_vertex_shader.inl" +#include "rgba_inverse_tonemap.inl" + +//----------------------------------------------------------------------------- +Tonemapper::Tonemapper() +//----------------------------------------------------------------------------- +{ + tonemapTexture = 0; + lutXformTexture = 0; + programID = 0; + eglImageWrapper = new EGLImageWrapper(); + + lutXformScaleOffset[0] = 1.0f; + lutXformScaleOffset[1] = 0.0f; + + tonemapScaleOffset[0] = 1.0f; + tonemapScaleOffset[1] = 0.0f; +} + +//----------------------------------------------------------------------------- +Tonemapper::~Tonemapper() +//----------------------------------------------------------------------------- +{ + engine_bind(engineContext); + engine_deleteInputBuffer(tonemapTexture); + engine_deleteInputBuffer(lutXformTexture); + engine_deleteProgram(programID); + + // clear EGLImage mappings + if (eglImageWrapper != 0) { + delete eglImageWrapper; + eglImageWrapper = 0; + } + + engine_shutdown(engineContext); +} + +//----------------------------------------------------------------------------- +Tonemapper *Tonemapper::build(int type, void *colorMap, int colorMapSize, void *lutXform, + int lutXformSize, bool isSecure) +//----------------------------------------------------------------------------- +{ + if (colorMapSize <= 0) { + ALOGE("Invalid Color Map size = %d", colorMapSize); + return NULL; + } + + // build new tonemapper + Tonemapper *tonemapper = new Tonemapper(); + + tonemapper->engineContext = engine_initialize(isSecure); + + engine_bind(tonemapper->engineContext); + + // load the 3d lut + tonemapper->tonemapTexture = engine_load3DTexture(colorMap, colorMapSize, 0); + tonemapper->tonemapScaleOffset[0] = ((float)(colorMapSize-1))/((float)(colorMapSize)); + tonemapper->tonemapScaleOffset[1] = 1.0f/(2.0f*colorMapSize); + + // load the non-uniform xform + tonemapper->lutXformTexture = engine_load1DTexture(lutXform, lutXformSize, 0); + bool bUseXform = (tonemapper->lutXformTexture != 0) && (lutXformSize != 0); + if( bUseXform ) + { + tonemapper->lutXformScaleOffset[0] = ((float)(lutXformSize-1))/((float)(lutXformSize)); + tonemapper->lutXformScaleOffset[1] = 1.0f/(2.0f*lutXformSize); + } + + // create the program + const char *fragmentShaders[3]; + int fragmentShaderCount = 0; + const char *version = "#version 300 es\n"; + const char *define = "#define USE_NONUNIFORM_SAMPLING\n"; + + fragmentShaders[fragmentShaderCount++] = version; + + // non-uniform sampling + if (bUseXform) { + fragmentShaders[fragmentShaderCount++] = define; + } + + if (type == TONEMAP_INVERSE) { // inverse tonemapping + fragmentShaders[fragmentShaderCount++] = rgba_inverse_tonemap_shader; + } else { // forward tonemapping + fragmentShaders[fragmentShaderCount++] = forward_tonemap_shader; + } + + tonemapper->programID = + engine_loadProgram(1, &fullscreen_vertex_shader, fragmentShaderCount, fragmentShaders); + + return tonemapper; +} + +//----------------------------------------------------------------------------- +int Tonemapper::blit(const void *dst, const void *src, int srcFenceFd) +//----------------------------------------------------------------------------- +{ + // make current + engine_bind(engineContext); + + // create eglimages if required + EGLImageBuffer *dst_buffer = eglImageWrapper->wrap(dst); + EGLImageBuffer *src_buffer = eglImageWrapper->wrap(src); + + // bind the program + engine_setProgram(programID); + + engine_setData2f(3, tonemapScaleOffset); + bool bUseXform = (lutXformTexture != 0); + if( bUseXform ) + { + engine_setData2f(4, lutXformScaleOffset); + } + + // set destination + engine_setDestination(dst_buffer->getFramebuffer(), 0, 0, dst_buffer->getWidth(), + dst_buffer->getHeight()); + // set source + engine_setExternalInputBuffer(0, src_buffer->getTexture()); + // set 3d lut + engine_set3DInputBuffer(1, tonemapTexture); + // set non-uniform xform + engine_set2DInputBuffer(2, lutXformTexture); + + // perform + int fenceFD = engine_blit(srcFenceFd); + + return fenceFD; +} diff --git a/msm8909/gpu_tonemapper/Tonemapper.h b/msm8909/gpu_tonemapper/Tonemapper.h new file mode 100644 index 00000000..707cdfe6 --- /dev/null +++ b/msm8909/gpu_tonemapper/Tonemapper.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016-2017, 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 __TONEMAPPER_TONEMAP_H__ +#define __TONEMAPPER_TONEMAP_H__ + +#define TONEMAP_FORWARD 0 +#define TONEMAP_INVERSE 1 + +#include "EGLImageWrapper.h" +#include "engine.h" + +class Tonemapper { + private: + void* engineContext; + unsigned int tonemapTexture; + unsigned int lutXformTexture; + unsigned int programID; + float lutXformScaleOffset[2]; + float tonemapScaleOffset[2]; + EGLImageWrapper* eglImageWrapper; + Tonemapper(); + + public: + ~Tonemapper(); + static Tonemapper *build(int type, void *colorMap, int colorMapSize, void *lutXform, + int lutXformSize, bool isSecure); + int blit(const void *dst, const void *src, int srcFenceFd); +}; + +#endif //__TONEMAPPER_TONEMAP_H__ diff --git a/msm8909/gpu_tonemapper/engine.h b/msm8909/gpu_tonemapper/engine.h new file mode 100644 index 00000000..8fb9452f --- /dev/null +++ b/msm8909/gpu_tonemapper/engine.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016-2017, 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 __TONEMAPPER_ENGINE_H__ +#define __TONEMAPPER_ENGINE_H__ + +void* engine_initialize(bool isSecure); +void engine_bind(void*); +void engine_shutdown(void*); + +unsigned int engine_loadProgram(int, const char **, int, const char **); +void engine_setProgram(int); +void engine_deleteProgram(unsigned int); + +unsigned int engine_load3DTexture(void *data, int sz, int format); +unsigned int engine_load1DTexture(void *xform, int xformSize, int format); +void engine_deleteInputBuffer(unsigned int); + +void engine_set2DInputBuffer(int binding, unsigned int textureID); +void engine_set3DInputBuffer(int binding, unsigned int textureID); +void engine_setExternalInputBuffer(int binding, unsigned int textureID); +void engine_setDestination(int id, int x, int y, int w, int h); +void engine_setData2f(int loc, float* data); + +int engine_blit(int); + +#endif //__TONEMAPPER_ENGINE_H__ diff --git a/msm8909/gpu_tonemapper/forward_tonemap.inl b/msm8909/gpu_tonemapper/forward_tonemap.inl new file mode 100644 index 00000000..0d89a9ea --- /dev/null +++ b/msm8909/gpu_tonemapper/forward_tonemap.inl @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016-2017, 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. + */ + +const char* forward_tonemap_shader = "" + "#extension GL_OES_EGL_image_external_essl3 : require \n" + "precision highp float; \n" + "precision highp sampler2D; \n" + "layout(binding = 0) uniform samplerExternalOES externalTexture; \n" + "layout(binding = 1) uniform sampler3D tonemapper; \n" + "layout(binding = 2) uniform sampler2D xform; \n" + "layout(location = 3) uniform vec2 tSO; \n" + "#ifdef USE_NONUNIFORM_SAMPLING \n" + "layout(location = 4) uniform vec2 xSO; \n" + "#endif \n" + "in vec2 uv; \n" + "out vec4 fs_color; \n" + " \n" + "vec3 ScaleOffset(in vec3 samplePt, in vec2 so) \n" + "{ \n" + " vec3 adjPt = so.x * samplePt + so.y; \n" + " return adjPt; \n" + "} \n" + " \n" + "void main() \n" + "{ \n" + "vec2 flipped = vec2(uv.x, 1.0f - uv.y); \n" + "vec4 rgb = texture(externalTexture, flipped); \n" + "#ifdef USE_NONUNIFORM_SAMPLING \n" + "vec3 adj = ScaleOffset(rgb.xyz, xSO); \n" + "float r = texture(xform, vec2(adj.r, 0.5f)).r; \n" + "float g = texture(xform, vec2(adj.g, 0.5f)).g; \n" + "float b = texture(xform, vec2(adj.b, 0.5f)).b; \n" + "#else \n" + "float r = rgb.r; \n" + "float g = rgb.g; \n" + "float b = rgb.b; \n" + "#endif \n" + "fs_color.rgb = texture(tonemapper, ScaleOffset(vec3(r, g, b), tSO)).rgb; \n" + "} \n"; diff --git a/msm8909/gpu_tonemapper/fullscreen_vertex_shader.inl b/msm8909/gpu_tonemapper/fullscreen_vertex_shader.inl new file mode 100644 index 00000000..9a70c2b3 --- /dev/null +++ b/msm8909/gpu_tonemapper/fullscreen_vertex_shader.inl @@ -0,0 +1,37 @@ +/* + * Copyright (c) 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. + */ + +const char* fullscreen_vertex_shader = " " +"#version 300 es \n" +"precision highp float; \n" +"layout(location = 0) in vec2 iUV; \n" +"out vec2 uv; \n" +"void main() \n" +"{ \n" +" vec2 positions[3]; \n" +" positions[0] = vec2(-1.0f, 3.0f); \n" +" positions[1] = vec2(-1.0f, -1.0f); \n" +" positions[2] = vec2(3.0f, -1.0f); \n" +" vec2 uvs[3]; \n" +" uvs[0] = vec2(0.0f, -1.0f); \n" +" uvs[1] = vec2(0.0f, 1.0f); \n" +" uvs[2] = vec2(2.0f, 1.0f); \n" +" gl_Position = vec4(positions[gl_VertexID], -1.0f, 1.0f); \n" +" uv = uvs[gl_VertexID]; \n" +"} \n"; diff --git a/msm8909/gpu_tonemapper/glengine.cpp b/msm8909/gpu_tonemapper/glengine.cpp new file mode 100644 index 00000000..35e1932c --- /dev/null +++ b/msm8909/gpu_tonemapper/glengine.cpp @@ -0,0 +1,415 @@ +/* + * Copyright (c) 2016-2017, 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 "glengine.h" +#include <log/log.h> +#include "engine.h" + +void checkGlError(const char *, int); +void checkEglError(const char *, int); + +class EngineContext { + public: + EGLDisplay eglDisplay; + EGLContext eglContext; + EGLSurface eglSurface; + EngineContext() + { + eglDisplay = EGL_NO_DISPLAY; + eglContext = EGL_NO_CONTEXT; + eglSurface = EGL_NO_SURFACE; + } +}; + +//----------------------------------------------------------------------------- +// Make Current +void engine_bind(void* context) +//----------------------------------------------------------------------------- +{ + EngineContext* engineContext = (EngineContext*)(context); + EGL(eglMakeCurrent(engineContext->eglDisplay, engineContext->eglSurface, engineContext->eglSurface, engineContext->eglContext)); +} + +//----------------------------------------------------------------------------- +// initialize GL +// +void* engine_initialize(bool isSecure) +//----------------------------------------------------------------------------- +{ + EngineContext* engineContext = new EngineContext(); + + // display + engineContext->eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + EGL(eglBindAPI(EGL_OPENGL_ES_API)); + + // initialize + EGL(eglInitialize(engineContext->eglDisplay, 0, 0)); + + // config + EGLConfig eglConfig; + EGLint eglConfigAttribList[] = {EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_NONE}; + int numConfig = 0; + EGL(eglChooseConfig(engineContext->eglDisplay, eglConfigAttribList, &eglConfig, 1, &numConfig)); + + // context + EGLint eglContextAttribList[] = {EGL_CONTEXT_CLIENT_VERSION, 3, + isSecure ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE, + isSecure ? EGL_TRUE : EGL_NONE, + EGL_NONE}; + engineContext->eglContext = eglCreateContext(engineContext->eglDisplay, eglConfig, NULL, eglContextAttribList); + + // surface + EGLint eglSurfaceAttribList[] = {EGL_WIDTH, 1, + EGL_HEIGHT, 1, + isSecure ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE, + isSecure ? EGL_TRUE : EGL_NONE, + EGL_NONE}; + engineContext->eglSurface = eglCreatePbufferSurface(engineContext->eglDisplay, eglConfig, eglSurfaceAttribList); + + eglMakeCurrent(engineContext->eglDisplay, engineContext->eglSurface, engineContext->eglSurface, engineContext->eglContext); + + ALOGI("In %s context = %p", __FUNCTION__, (void *)(engineContext->eglContext)); + + return (void*)(engineContext); +} + +//----------------------------------------------------------------------------- +// Shutdown. +void engine_shutdown(void* context) +//----------------------------------------------------------------------------- +{ + EngineContext* engineContext = (EngineContext*)context; + EGL(eglMakeCurrent(engineContext->eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); + EGL(eglDestroySurface(engineContext->eglDisplay, engineContext->eglSurface)); + EGL(eglDestroyContext(engineContext->eglDisplay, engineContext->eglContext)); + EGL(eglTerminate(engineContext->eglDisplay)); + engineContext->eglDisplay = EGL_NO_DISPLAY; + engineContext->eglContext = EGL_NO_CONTEXT; + engineContext->eglSurface = EGL_NO_SURFACE; +} + +//----------------------------------------------------------------------------- +void engine_deleteInputBuffer(unsigned int id) +//----------------------------------------------------------------------------- +{ + if (id != 0) { + GL(glDeleteTextures(1, &id)); + } +} + +//----------------------------------------------------------------------------- +void engine_deleteProgram(unsigned int id) +//----------------------------------------------------------------------------- +{ + if (id != 0) { + GL(glDeleteProgram(id)); + } +} + +//----------------------------------------------------------------------------- +void engine_setData2f(int location, float* data) +//----------------------------------------------------------------------------- +{ + GL(glUniform2f(location, data[0], data[1])); +} + +//----------------------------------------------------------------------------- +unsigned int engine_load3DTexture(void *colorMapData, int sz, int format) +//----------------------------------------------------------------------------- +{ + GLuint texture = 0; + GL(glGenTextures(1, &texture)); + GL(glBindTexture(GL_TEXTURE_3D, texture)); + GL(glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GL(glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + GL(glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE)); + GL(glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + GL(glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + + GL(glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB10_A2, sz, sz, sz, 0, GL_RGBA, + GL_UNSIGNED_INT_2_10_10_10_REV, colorMapData)); + + return texture; +} +//----------------------------------------------------------------------------- +unsigned int engine_load1DTexture(void *data, int sz, int format) +//----------------------------------------------------------------------------- +{ + GLuint texture = 0; + if ((data != 0) && (sz != 0)) { + GL(glGenTextures(1, &texture)); + GL(glBindTexture(GL_TEXTURE_2D, texture)); + GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + + GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB10_A2, sz, 1, 0, GL_RGBA, + GL_UNSIGNED_INT_2_10_10_10_REV, data)); + } + return texture; +} + +//----------------------------------------------------------------------------- +void dumpShaderLog(int shader) +//----------------------------------------------------------------------------- +{ + int success = 0; + GLchar infoLog[512]; + GL(glGetShaderiv(shader, GL_COMPILE_STATUS, &success)); + if (!success) { + glGetShaderInfoLog(shader, 512, NULL, infoLog); + ALOGI("Shader Failed to compile: %s\n", infoLog); + } +} + +//----------------------------------------------------------------------------- +GLuint engine_loadProgram(int vertexEntries, const char **vertex, int fragmentEntries, + const char **fragment) +//----------------------------------------------------------------------------- +{ + GLuint progId = glCreateProgram(); + + int vertId = glCreateShader(GL_VERTEX_SHADER); + int fragId = glCreateShader(GL_FRAGMENT_SHADER); + + GL(glShaderSource(vertId, vertexEntries, vertex, 0)); + GL(glCompileShader(vertId)); + dumpShaderLog(vertId); + + GL(glShaderSource(fragId, fragmentEntries, fragment, 0)); + GL(glCompileShader(fragId)); + dumpShaderLog(fragId); + + GL(glAttachShader(progId, vertId)); + GL(glAttachShader(progId, fragId)); + + GL(glLinkProgram(progId)); + + GL(glDetachShader(progId, vertId)); + GL(glDetachShader(progId, fragId)); + + GL(glDeleteShader(vertId)); + GL(glDeleteShader(fragId)); + + return progId; +} + +//----------------------------------------------------------------------------- +void WaitOnNativeFence(int fd) +//----------------------------------------------------------------------------- +{ + if (fd != -1) { + EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fd, EGL_NONE}; + + EGLSyncKHR sync = eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); + + if (sync == EGL_NO_SYNC_KHR) { + ALOGE("%s - Failed to Create sync from source fd", __FUNCTION__); + } else { + // the gpu will wait for this sync - not this cpu thread. + EGL(eglWaitSyncKHR(eglGetCurrentDisplay(), sync, 0)); + EGL(eglDestroySyncKHR(eglGetCurrentDisplay(), sync)); + } + } +} + +//----------------------------------------------------------------------------- +int CreateNativeFence() +//----------------------------------------------------------------------------- +{ + int fd = -1; + + EGLSyncKHR sync = eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); + GL(glFlush()); + if (sync == EGL_NO_SYNC_KHR) { + ALOGE("%s - Failed to Create Native Fence sync", __FUNCTION__); + } else { + fd = eglDupNativeFenceFDANDROID(eglGetCurrentDisplay(), sync); + if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { + ALOGE("%s - Failed to dup sync", __FUNCTION__); + } + EGL(eglDestroySyncKHR(eglGetCurrentDisplay(), sync)); + } + + return fd; +} + +//----------------------------------------------------------------------------- +void engine_setDestination(int id, int x, int y, int w, int h) +//----------------------------------------------------------------------------- +{ + GL(glBindFramebuffer(GL_FRAMEBUFFER, id)); + GL(glViewport(x, y, w, h)); +} + +//----------------------------------------------------------------------------- +void engine_setProgram(int id) +//----------------------------------------------------------------------------- +{ + GL(glUseProgram(id)); +} + +//----------------------------------------------------------------------------- +void engine_set2DInputBuffer(int binding, unsigned int id) +//----------------------------------------------------------------------------- +{ + GL(glActiveTexture(GL_TEXTURE0 + binding)); + GL(glBindTexture(GL_TEXTURE_2D, id)); +} + +//----------------------------------------------------------------------------- +void engine_set3DInputBuffer(int binding, unsigned int id) +//----------------------------------------------------------------------------- +{ + GL(glActiveTexture(GL_TEXTURE0 + binding)); + GL(glBindTexture(GL_TEXTURE_3D, id)); +} + +//----------------------------------------------------------------------------- +void engine_setExternalInputBuffer(int binding, unsigned int id) +//----------------------------------------------------------------------------- +{ + GL(glActiveTexture(GL_TEXTURE0 + binding)); + GL(glBindTexture(0x8D65, id)); +} + +//----------------------------------------------------------------------------- +int engine_blit(int srcFenceFd) +//----------------------------------------------------------------------------- +{ + int fd = -1; + WaitOnNativeFence(srcFenceFd); + float fullscreen_vertices[]{0.0f, 2.0f, 0.0f, 0.0f, 2.0f, 0.0f}; + GL(glEnableVertexAttribArray(0)); + GL(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, fullscreen_vertices)); + GL(glDrawArrays(GL_TRIANGLES, 0, 3)); + fd = CreateNativeFence(); + GL(glFlush()); + return fd; +} + +//----------------------------------------------------------------------------- +void checkGlError(const char *file, int line) +//----------------------------------------------------------------------------- +{ + for (GLint error = glGetError(); error; error = glGetError()) { + char *pError; + switch (error) { + case GL_NO_ERROR: + pError = (char *)"GL_NO_ERROR"; + break; + case GL_INVALID_ENUM: + pError = (char *)"GL_INVALID_ENUM"; + break; + case GL_INVALID_VALUE: + pError = (char *)"GL_INVALID_VALUE"; + break; + case GL_INVALID_OPERATION: + pError = (char *)"GL_INVALID_OPERATION"; + break; + case GL_OUT_OF_MEMORY: + pError = (char *)"GL_OUT_OF_MEMORY"; + break; + case GL_INVALID_FRAMEBUFFER_OPERATION: + pError = (char *)"GL_INVALID_FRAMEBUFFER_OPERATION"; + break; + + default: + ALOGE("glError (0x%x) %s:%d\n", error, file, line); + return; + } + + ALOGE("glError (%s) %s:%d\n", pError, file, line); + return; + } + return; +} + +//----------------------------------------------------------------------------- +void checkEglError(const char *file, int line) +//----------------------------------------------------------------------------- +{ + for (int i = 0; i < 5; i++) { + const EGLint error = eglGetError(); + if (error == EGL_SUCCESS) { + break; + } + + char *pError; + switch (error) { + case EGL_SUCCESS: + pError = (char *)"EGL_SUCCESS"; + break; + case EGL_NOT_INITIALIZED: + pError = (char *)"EGL_NOT_INITIALIZED"; + break; + case EGL_BAD_ACCESS: + pError = (char *)"EGL_BAD_ACCESS"; + break; + case EGL_BAD_ALLOC: + pError = (char *)"EGL_BAD_ALLOC"; + break; + case EGL_BAD_ATTRIBUTE: + pError = (char *)"EGL_BAD_ATTRIBUTE"; + break; + case EGL_BAD_CONTEXT: + pError = (char *)"EGL_BAD_CONTEXT"; + break; + case EGL_BAD_CONFIG: + pError = (char *)"EGL_BAD_CONFIG"; + break; + case EGL_BAD_CURRENT_SURFACE: + pError = (char *)"EGL_BAD_CURRENT_SURFACE"; + break; + case EGL_BAD_DISPLAY: + pError = (char *)"EGL_BAD_DISPLAY"; + break; + case EGL_BAD_SURFACE: + pError = (char *)"EGL_BAD_SURFACE"; + break; + case EGL_BAD_MATCH: + pError = (char *)"EGL_BAD_MATCH"; + break; + case EGL_BAD_PARAMETER: + pError = (char *)"EGL_BAD_PARAMETER"; + break; + case EGL_BAD_NATIVE_PIXMAP: + pError = (char *)"EGL_BAD_NATIVE_PIXMAP"; + break; + case EGL_BAD_NATIVE_WINDOW: + pError = (char *)"EGL_BAD_NATIVE_WINDOW"; + break; + case EGL_CONTEXT_LOST: + pError = (char *)"EGL_CONTEXT_LOST"; + break; + default: + ALOGE("eglError (0x%x) %s:%d\n", error, file, line); + return; + } + ALOGE("eglError (%s) %s:%d\n", pError, file, line); + return; + } + return; +} diff --git a/msm8909/gpu_tonemapper/glengine.h b/msm8909/gpu_tonemapper/glengine.h new file mode 100644 index 00000000..f6aeec84 --- /dev/null +++ b/msm8909/gpu_tonemapper/glengine.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 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 __TONEMAPPER_GLENGINE_H__ +#define __TONEMAPPER_GLENGINE_H__ +#include <EGL/egl.h> +#define EGL_EGLEXT_PROTOTYPES +#include <EGL/eglext.h> +#include <GLES3/gl31.h> +#define GL_GLEXT_PROTOTYPES +#include <GLES2/gl2ext.h> +#include <GLES3/gl3ext.h> + +#if defined(CHECK_GL_ERRORS) +#define GL(func) func; +#define EGL(func) func; +#else +#define GL(func) \ + func; \ + checkGlError(__FILE__, __LINE__); +#define EGL(func) \ + func; \ + checkEglError(__FILE__, __LINE__); +#endif + +#define EGL_PROTECTED_CONTENT_EXT 0x32C0 + +void checkGlError(const char *file, int line); +void checkEglError(const char *file, int line); + +#endif //__TONEMAPPER_GLENGINE_H__ diff --git a/msm8909/gpu_tonemapper/rgba_inverse_tonemap.inl b/msm8909/gpu_tonemapper/rgba_inverse_tonemap.inl new file mode 100644 index 00000000..2865fbe0 --- /dev/null +++ b/msm8909/gpu_tonemapper/rgba_inverse_tonemap.inl @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016-2017, 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. + */ + +const char* rgba_inverse_tonemap_shader = "" + "#extension GL_OES_EGL_image_external_essl3 : require \n" + "precision highp float; \n" + "precision highp sampler2D; \n" + "layout(binding = 0) uniform samplerExternalOES externalTexture; \n" + "layout(binding = 1) uniform sampler3D tonemapper; \n" + "layout(binding = 2) uniform sampler2D xform; \n" + "layout(location = 3) uniform vec2 tSO; \n" + "#if defined(USE_NONUNIFORM_SAMPLING) \n" + "layout(location = 4) uniform vec2 xSO; \n" + "#endif \n" + "in vec2 uv; \n" + "out vec4 fs_color; \n" + " \n" + "vec3 ScaleOffset(in vec3 samplePt, in vec2 so) \n" + "{ \n" + " vec3 adjPt = so.x * samplePt + so.y; \n" + " return adjPt; \n" + "} \n" + " \n" + "void main() \n" + "{ \n" + "vec2 flipped = vec2(uv.x, 1.0f - uv.y); \n" + "vec4 rgb_premulalpha = texture(externalTexture, flipped); \n" + "fs_color = rgb_premulalpha; \n" + "if( rgb_premulalpha.a > 0.0 ) { \n" + "vec3 rgb = rgb_premulalpha.rgb/rgb_premulalpha.a; \n" + "#if defined(USE_NONUNIFORM_SAMPLING) \n" + "vec3 adj = ScaleOffset(rgb.xyz, xSO); \n" + "float r = texture(xform, vec2(adj.r, 0.5f)).r; \n" + "float g = texture(xform, vec2(adj.g, 0.5f)).g; \n" + "float b = texture(xform, vec2(adj.b, 0.5f)).b; \n" + "#else \n" + "float r = rgb.r; \n" + "float g = rgb.g; \n" + "float b = rgb.b; \n" + "#endif \n" + "fs_color.rgb = texture(tonemapper, ScaleOffset(vec3(r, g, b), tSO)).rgb * rgb_premulalpha.a; \n" + "fs_color.a = rgb_premulalpha.a; \n" + "} \n" + "} \n"; diff --git a/msm8909/gralloc/Android.mk b/msm8909/gralloc/Android.mk new file mode 100644 index 00000000..cdb651cf --- /dev/null +++ b/msm8909/gralloc/Android.mk @@ -0,0 +1,38 @@ +# Gralloc module +LOCAL_PATH := $(call my-dir) +include $(LOCAL_PATH)/../common.mk +include $(CLEAR_VARS) + +LOCAL_MODULE := gralloc.$(TARGET_BOARD_PLATFORM) +LOCAL_VENDOR_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_MODULE_TAGS := optional +LOCAL_C_INCLUDES := $(common_includes) \ + external/libcxx/include/ + +LOCAL_HEADER_LIBRARIES := display_headers +LOCAL_SHARED_LIBRARIES := $(common_libs) libqdMetaData libsync libgrallocutils +LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdgralloc\" -Wall -std=c++11 -Werror +LOCAL_CFLAGS += -isystem $(kernel_includes) +LOCAL_CLANG := true +LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps) +LOCAL_SRC_FILES := gr_ion_alloc.cpp \ + gr_allocator.cpp \ + gr_buf_mgr.cpp \ + gr_device_impl.cpp +LOCAL_COPY_HEADERS_TO := $(common_header_export_path) +LOCAL_COPY_HEADERS := gr_device_impl.h gralloc_priv.h gr_priv_handle.h +include $(BUILD_SHARED_LIBRARY) + +#libgrallocutils +include $(CLEAR_VARS) +LOCAL_MODULE := libgrallocutils +LOCAL_VENDOR_MODULE := true +LOCAL_MODULE_TAGS := optional +LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes) +LOCAL_HEADER_LIBRARIES := display_headers +LOCAL_SHARED_LIBRARIES := $(common_libs) libqdMetaData libdl +LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"grallocutils\" -Wno-sign-conversion +LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps) +LOCAL_SRC_FILES := gr_utils.cpp gr_adreno_info.cpp +include $(BUILD_SHARED_LIBRARY) diff --git a/msm8909/gralloc/gr_adreno_info.cpp b/msm8909/gralloc/gr_adreno_info.cpp new file mode 100644 index 00000000..c681daaf --- /dev/null +++ b/msm8909/gralloc/gr_adreno_info.cpp @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2011-2018, 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 <log/log.h> +#include <cutils/properties.h> +#include <dlfcn.h> +#include <mutex> + +#include "gralloc_priv.h" +#include "gr_adreno_info.h" +#include "gr_utils.h" + +using std::lock_guard; +using std::mutex; + +namespace gralloc1 { + +AdrenoMemInfo *AdrenoMemInfo::s_instance = nullptr; + +AdrenoMemInfo *AdrenoMemInfo::GetInstance() { + static mutex s_lock; + lock_guard<mutex> obj(s_lock); + if (!s_instance) { + s_instance = new AdrenoMemInfo(); + } + + return s_instance; +} + +AdrenoMemInfo::AdrenoMemInfo() { + libadreno_utils_ = ::dlopen("libadreno_utils.so", RTLD_NOW); + if (libadreno_utils_) { + *reinterpret_cast<void **>(&LINK_adreno_compute_aligned_width_and_height) = + ::dlsym(libadreno_utils_, "compute_aligned_width_and_height"); + *reinterpret_cast<void **>(&LINK_adreno_compute_padding) = + ::dlsym(libadreno_utils_, "compute_surface_padding"); + *reinterpret_cast<void **>(&LINK_adreno_compute_compressedfmt_aligned_width_and_height) = + ::dlsym(libadreno_utils_, "compute_compressedfmt_aligned_width_and_height"); + *reinterpret_cast<void **>(&LINK_adreno_isUBWCSupportedByGpu) = + ::dlsym(libadreno_utils_, "isUBWCSupportedByGpu"); + *reinterpret_cast<void **>(&LINK_adreno_get_gpu_pixel_alignment) = + ::dlsym(libadreno_utils_, "get_gpu_pixel_alignment"); + } else { + ALOGE(" Failed to load libadreno_utils.so"); + } + + // Check if the overriding property debug.gralloc.gfx_ubwc_disable + // that disables UBWC allocations for the graphics stack is set + char property[PROPERTY_VALUE_MAX]; + property_get(DISABLE_UBWC_PROP, property, "0"); + if (!(strncmp(property, "1", PROPERTY_VALUE_MAX)) || + !(strncmp(property, "true", PROPERTY_VALUE_MAX))) { + gfx_ubwc_disable_ = true; + } + + if ((property_get(MAP_FB_MEMORY_PROP, property, NULL) > 0) && + (!strncmp(property, "1", PROPERTY_VALUE_MAX) || + (!strncasecmp(property, "true", PROPERTY_VALUE_MAX)))) { + map_fb_ = true; + } +} + +AdrenoMemInfo::~AdrenoMemInfo() { + if (libadreno_utils_) { + ::dlclose(libadreno_utils_); + } +} + +void AdrenoMemInfo::AlignUnCompressedRGB(int width, int height, int format, int tile_enabled, + unsigned int *aligned_w, unsigned int *aligned_h) { + *aligned_w = (unsigned int)ALIGN(width, 32); + *aligned_h = (unsigned int)ALIGN(height, 32); + + // Don't add any additional padding if debug.gralloc.map_fb_memory + // is enabled + if (map_fb_) { + return; + } + + int bpp = 4; + switch (format) { + case HAL_PIXEL_FORMAT_RGB_888: + case HAL_PIXEL_FORMAT_BGR_888: + bpp = 3; + break; + case HAL_PIXEL_FORMAT_RGB_565: + case HAL_PIXEL_FORMAT_BGR_565: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: + bpp = 2; + break; + default: + break; + } + + int raster_mode = 0; // Adreno unknown raster mode. + int padding_threshold = 512; // Threshold for padding surfaces. + // the function below computes aligned width and aligned height + // based on linear or macro tile mode selected. + if (LINK_adreno_compute_aligned_width_and_height) { + LINK_adreno_compute_aligned_width_and_height( + width, height, bpp, tile_enabled, raster_mode, padding_threshold, + reinterpret_cast<int *>(aligned_w), reinterpret_cast<int *>(aligned_h)); + } else if (LINK_adreno_compute_padding) { + int surface_tile_height = 1; // Linear surface + *aligned_w = UINT(LINK_adreno_compute_padding(width, bpp, surface_tile_height, raster_mode, + padding_threshold)); + ALOGW("%s: Warning!! Old GFX API is used to calculate stride", __FUNCTION__); + } else { + ALOGW( + "%s: Warning!! Symbols compute_surface_padding and " + "compute_aligned_width_and_height not found", + __FUNCTION__); + } +} + +void AdrenoMemInfo::AlignCompressedRGB(int width, int height, int format, unsigned int *aligned_w, + unsigned int *aligned_h) { + if (LINK_adreno_compute_compressedfmt_aligned_width_and_height) { + int bytesPerPixel = 0; + int raster_mode = 0; // Adreno unknown raster mode. + int padding_threshold = 512; // Threshold for padding + // surfaces. + + LINK_adreno_compute_compressedfmt_aligned_width_and_height( + width, height, format, 0, raster_mode, padding_threshold, + reinterpret_cast<int *>(aligned_w), reinterpret_cast<int *>(aligned_h), &bytesPerPixel); + } else { + *aligned_w = (unsigned int)ALIGN(width, 32); + *aligned_h = (unsigned int)ALIGN(height, 32); + ALOGW("%s: Warning!! compute_compressedfmt_aligned_width_and_height not found", __FUNCTION__); + } +} + +bool AdrenoMemInfo::IsUBWCSupportedByGPU(int format) { + if (!gfx_ubwc_disable_ && LINK_adreno_isUBWCSupportedByGpu) { + ADRENOPIXELFORMAT gpu_format = GetGpuPixelFormat(format); + return LINK_adreno_isUBWCSupportedByGpu(gpu_format); + } + + return false; +} + +uint32_t AdrenoMemInfo::GetGpuPixelAlignment() { + if (LINK_adreno_get_gpu_pixel_alignment) { + return LINK_adreno_get_gpu_pixel_alignment(); + } + + return 1; +} + +ADRENOPIXELFORMAT AdrenoMemInfo::GetGpuPixelFormat(int hal_format) { + switch (hal_format) { + case HAL_PIXEL_FORMAT_RGBA_8888: + return ADRENO_PIXELFORMAT_R8G8B8A8; + case HAL_PIXEL_FORMAT_RGBX_8888: + return ADRENO_PIXELFORMAT_R8G8B8X8; + case HAL_PIXEL_FORMAT_RGB_565: + return ADRENO_PIXELFORMAT_B5G6R5; + case HAL_PIXEL_FORMAT_BGR_565: + return ADRENO_PIXELFORMAT_R5G6B5; + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + return ADRENO_PIXELFORMAT_NV12; + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC: + return ADRENO_PIXELFORMAT_NV12_EXT; + case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC: + return ADRENO_PIXELFORMAT_TP10; + case HAL_PIXEL_FORMAT_YCbCr_420_P010: + case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC: + return ADRENO_PIXELFORMAT_P010; + case HAL_PIXEL_FORMAT_RGBA_1010102: + return ADRENO_PIXELFORMAT_R10G10B10A2_UNORM; + case HAL_PIXEL_FORMAT_RGBX_1010102: + return ADRENO_PIXELFORMAT_R10G10B10X2_UNORM; + case HAL_PIXEL_FORMAT_ABGR_2101010: + return ADRENO_PIXELFORMAT_A2B10G10R10_UNORM; + case HAL_PIXEL_FORMAT_RGB_888: + return ADRENO_PIXELFORMAT_R8G8B8; + default: + ALOGE("%s: No map for format: 0x%x", __FUNCTION__, hal_format); + break; + } + + return ADRENO_PIXELFORMAT_UNKNOWN; +} + +} // namespace gralloc1 diff --git a/msm8909/gralloc/gr_adreno_info.h b/msm8909/gralloc/gr_adreno_info.h new file mode 100644 index 00000000..478b5270 --- /dev/null +++ b/msm8909/gralloc/gr_adreno_info.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2011-2017, 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 __GR_ADRENO_INFO_H__ +#define __GR_ADRENO_INFO_H__ + +#include <media/msm_media_info.h> + +namespace gralloc1 { + +// Adreno Pixel Formats +typedef enum { + ADRENO_PIXELFORMAT_UNKNOWN = 0, + ADRENO_PIXELFORMAT_R10G10B10A2_UNORM = 24, // Vertex, Normalized GL_UNSIGNED_INT_10_10_10_2_OES + ADRENO_PIXELFORMAT_R8G8B8A8 = 28, + ADRENO_PIXELFORMAT_R8G8B8A8_SRGB = 29, + ADRENO_PIXELFORMAT_B5G6R5 = 85, + ADRENO_PIXELFORMAT_B5G5R5A1 = 86, + ADRENO_PIXELFORMAT_B8G8R8A8 = 90, + ADRENO_PIXELFORMAT_B8G8R8A8_SRGB = 91, + ADRENO_PIXELFORMAT_B8G8R8X8_SRGB = 93, + ADRENO_PIXELFORMAT_NV12 = 103, + ADRENO_PIXELFORMAT_P010 = 104, + ADRENO_PIXELFORMAT_YUY2 = 107, + ADRENO_PIXELFORMAT_B4G4R4A4 = 115, + ADRENO_PIXELFORMAT_NV12_EXT = 506, // NV12 with non-std alignment and offsets + ADRENO_PIXELFORMAT_R8G8B8X8 = 507, // GL_RGB8 (Internal) + ADRENO_PIXELFORMAT_R8G8B8 = 508, // GL_RGB8 + ADRENO_PIXELFORMAT_A1B5G5R5 = 519, // GL_RGB5_A1 + ADRENO_PIXELFORMAT_R8G8B8X8_SRGB = 520, // GL_SRGB8 + ADRENO_PIXELFORMAT_R8G8B8_SRGB = 521, // GL_SRGB8 + ADRENO_PIXELFORMAT_A2B10G10R10_UNORM = 532, + // Vertex, Normalized GL_UNSIGNED_INT_10_10_10_2_OES + ADRENO_PIXELFORMAT_R10G10B10X2_UNORM = 537, + // Vertex, Normalized GL_UNSIGNED_INT_10_10_10_2_OES + ADRENO_PIXELFORMAT_R5G6B5 = 610, // RGBA version of B5G6R5 + ADRENO_PIXELFORMAT_R5G5B5A1 = 611, // RGBA version of B5G5R5A1 + ADRENO_PIXELFORMAT_R4G4B4A4 = 612, // RGBA version of B4G4R4A4 + ADRENO_PIXELFORMAT_UYVY = 614, // YUV 4:2:2 packed progressive (1 plane) + ADRENO_PIXELFORMAT_NV21 = 619, + ADRENO_PIXELFORMAT_Y8U8V8A8 = 620, // YUV 4:4:4 packed (1 plane) + ADRENO_PIXELFORMAT_Y8 = 625, // Single 8-bit luma only channel YUV format + ADRENO_PIXELFORMAT_TP10 = 648, // YUV 4:2:0 planar 10 bits/comp (2 planes) +} ADRENOPIXELFORMAT; + +class AdrenoMemInfo { + public: + /* + * Function to compute aligned width and aligned height based on + * width, height, format and usage flags. + * + * @return aligned width, aligned height + */ + void GetAlignedWidthAndHeight(int width, int height, int format, int usage, + unsigned int *aligned_w, unsigned int *aligned_h, bool ubwc_enabled, + bool tile_enabled); + + /* + * Function to compute the adreno aligned width and aligned height + * based on the width and format. + * + * @return aligned width, aligned height + */ + void AlignUnCompressedRGB(int width, int height, int format, int tileEnabled, + unsigned int *aligned_w, unsigned int *aligned_h); + + /* + * Function to compute the adreno aligned width and aligned height + * based on the width and format. + * + * @return aligned width, aligned height + */ + void AlignCompressedRGB(int width, int height, int format, unsigned int *aligned_w, + unsigned int *aligned_h); + + /* + * Function to compute the pixel alignment requirement. + * + * @return alignment + */ + uint32_t GetGpuPixelAlignment(); + + /* + * Function to query whether GPU supports UBWC for given HAL format + * @return > 0 : supported + * 0 : not supported + */ + bool IsUBWCSupportedByGPU(int format); + + /* + * Function to get the corresponding Adreno format for given HAL format + */ + ADRENOPIXELFORMAT GetGpuPixelFormat(int hal_format); + + static AdrenoMemInfo *GetInstance(); + + private: + AdrenoMemInfo(); + ~AdrenoMemInfo(); + // link(s)to adreno surface padding library. + int (*LINK_adreno_compute_padding)(int width, int bpp, int surface_tile_height, + int screen_tile_height, int padding_threshold) = NULL; + void (*LINK_adreno_compute_aligned_width_and_height)(int width, int height, int bpp, + int tile_mode, int raster_mode, + int padding_threshold, int *aligned_w, + int *aligned_h) = NULL; + void (*LINK_adreno_compute_compressedfmt_aligned_width_and_height)( + int width, int height, int format, int tile_mode, int raster_mode, int padding_threshold, + int *aligned_w, int *aligned_h, int *bpp) = NULL; + int (*LINK_adreno_isUBWCSupportedByGpu)(ADRENOPIXELFORMAT format) = NULL; + unsigned int (*LINK_adreno_get_gpu_pixel_alignment)() = NULL; + + bool gfx_ubwc_disable_ = false; + bool map_fb_ = false; + void *libadreno_utils_ = NULL; + + static AdrenoMemInfo *s_instance; +}; + +} // namespace gralloc1 + +#endif // __GR_ADRENO_INFO_H__ diff --git a/msm8909/gralloc/gr_allocator.cpp b/msm8909/gralloc/gr_allocator.cpp new file mode 100644 index 00000000..330da182 --- /dev/null +++ b/msm8909/gralloc/gr_allocator.cpp @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2011-2017, 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 <log/log.h> +#include <algorithm> +#include <vector> + +#include "gr_utils.h" +#include "gr_allocator.h" +#include "gralloc_priv.h" + +#include "qd_utils.h" + +#ifndef ION_FLAG_CP_PIXEL +#define ION_FLAG_CP_PIXEL 0 +#endif + +#ifndef ION_FLAG_ALLOW_NON_CONTIG +#define ION_FLAG_ALLOW_NON_CONTIG 0 +#endif + +#ifndef ION_FLAG_CP_CAMERA_PREVIEW +#define ION_FLAG_CP_CAMERA_PREVIEW 0 +#endif + +#ifdef MASTER_SIDE_CP +#define CP_HEAP_ID ION_SECURE_HEAP_ID +#define SD_HEAP_ID ION_SECURE_DISPLAY_HEAP_ID +#define ION_CP_FLAGS (ION_SECURE | ION_FLAG_CP_PIXEL) +#define ION_SD_FLAGS (ION_SECURE | ION_FLAG_CP_SEC_DISPLAY) +#define ION_SC_FLAGS (ION_SECURE | ION_FLAG_CP_CAMERA) +#define ION_SC_PREVIEW_FLAGS (ION_SECURE | ION_FLAG_CP_CAMERA_PREVIEW) +#else // SLAVE_SIDE_CP +#define CP_HEAP_ID ION_CP_MM_HEAP_ID +#define SD_HEAP_ID CP_HEAP_ID +#define ION_CP_FLAGS (ION_SECURE | ION_FLAG_ALLOW_NON_CONTIG) +#define ION_SD_FLAGS ION_SECURE +#define ION_SC_FLAGS ION_SECURE +#define ION_SC_PREVIEW_FLAGS ION_SECURE +#endif + +using std::vector; +using std::shared_ptr; + +namespace gralloc1 { + +static BufferInfo GetBufferInfo(const BufferDescriptor &descriptor) { + return BufferInfo(descriptor.GetWidth(), descriptor.GetHeight(), descriptor.GetFormat(), + descriptor.GetProducerUsage(), descriptor.GetConsumerUsage()); +} + +Allocator::Allocator() : ion_allocator_(NULL) { +} + +bool Allocator::Init() { + ion_allocator_ = new IonAlloc(); + if (!ion_allocator_->Init()) { + return false; + } + + return true; +} + +Allocator::~Allocator() { + if (ion_allocator_) { + delete ion_allocator_; + } +} + +int Allocator::AllocateMem(AllocData *alloc_data, gralloc1_producer_usage_t prod_usage, + gralloc1_consumer_usage_t cons_usage) { + int ret; + alloc_data->uncached = UseUncached(prod_usage, cons_usage); + + // After this point we should have the right heap set, there is no fallback + GetIonHeapInfo(prod_usage, cons_usage, &alloc_data->heap_id, &alloc_data->alloc_type, + &alloc_data->flags); + + ret = ion_allocator_->AllocBuffer(alloc_data); + if (ret >= 0) { + alloc_data->alloc_type |= private_handle_t::PRIV_FLAGS_USES_ION; + } else { + ALOGE("%s: Failed to allocate buffer - heap: 0x%x flags: 0x%x", __FUNCTION__, + alloc_data->heap_id, alloc_data->flags); + } + + return ret; +} + +int Allocator::MapBuffer(void **base, unsigned int size, unsigned int offset, int fd) { + if (ion_allocator_) { + return ion_allocator_->MapBuffer(base, size, offset, fd); + } + + return -EINVAL; +} + +int Allocator::ImportBuffer(int fd) { + if (ion_allocator_) { + return ion_allocator_->ImportBuffer(fd); + } + return -EINVAL; +} + +int Allocator::FreeBuffer(void *base, unsigned int size, unsigned int offset, int fd, + int handle) { + if (ion_allocator_) { + return ion_allocator_->FreeBuffer(base, size, offset, fd, handle); + } + + return -EINVAL; +} + +int Allocator::CleanBuffer(void *base, unsigned int size, unsigned int offset, int handle, int op) { + if (ion_allocator_) { + return ion_allocator_->CleanBuffer(base, size, offset, handle, op); + } + + return -EINVAL; +} + +bool Allocator::CheckForBufferSharing(uint32_t num_descriptors, + const vector<shared_ptr<BufferDescriptor>>& descriptors, + ssize_t *max_index) { + unsigned int cur_heap_id = 0, prev_heap_id = 0; + unsigned int cur_alloc_type = 0, prev_alloc_type = 0; + unsigned int cur_ion_flags = 0, prev_ion_flags = 0; + bool cur_uncached = false, prev_uncached = false; + unsigned int alignedw, alignedh; + unsigned int max_size = 0; + + *max_index = -1; + for (uint32_t i = 0; i < num_descriptors; i++) { + // Check Cached vs non-cached and all the ION flags + cur_uncached = UseUncached(descriptors[i]->GetProducerUsage(), + descriptors[i]->GetConsumerUsage()); + GetIonHeapInfo(descriptors[i]->GetProducerUsage(), descriptors[i]->GetConsumerUsage(), + &cur_heap_id, &cur_alloc_type, &cur_ion_flags); + + if (i > 0 && (cur_heap_id != prev_heap_id || cur_alloc_type != prev_alloc_type || + cur_ion_flags != prev_ion_flags)) { + return false; + } + + // For same format type, find the descriptor with bigger size + GetAlignedWidthAndHeight(GetBufferInfo(*descriptors[i]), &alignedw, &alignedh); + unsigned int size = GetSize(GetBufferInfo(*descriptors[i]), alignedw, alignedh); + if (max_size < size) { + *max_index = INT(i); + max_size = size; + } + + prev_heap_id = cur_heap_id; + prev_uncached = cur_uncached; + prev_ion_flags = cur_ion_flags; + prev_alloc_type = cur_alloc_type; + } + + return true; +} + +int Allocator::GetImplDefinedFormat(gralloc1_producer_usage_t prod_usage, + gralloc1_consumer_usage_t cons_usage, int format) { + int gr_format = format; + + // If input format is HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED then based on + // the usage bits, gralloc assigns a format. + if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED || + format == HAL_PIXEL_FORMAT_YCbCr_420_888) { + if (prod_usage & GRALLOC1_PRODUCER_USAGE_PRIVATE_ALLOC_UBWC) { + gr_format = HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC; + } else if (cons_usage & GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER) { + gr_format = HAL_PIXEL_FORMAT_NV12_ENCODEABLE; // NV12 + } else if (cons_usage & GRALLOC1_CONSUMER_USAGE_CAMERA) { + if (prod_usage & GRALLOC1_PRODUCER_USAGE_CAMERA) { + // Assumed ZSL if both producer and consumer camera flags set + gr_format = HAL_PIXEL_FORMAT_NV21_ZSL; // NV21 + } else { + gr_format = HAL_PIXEL_FORMAT_YCrCb_420_SP; // NV21 + } + } else if (prod_usage & GRALLOC1_PRODUCER_USAGE_CAMERA) { + if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) { + gr_format = HAL_PIXEL_FORMAT_NV21_ZSL; // NV21 + } else { + gr_format = HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS; // NV12 preview + } + } else if (cons_usage & GRALLOC1_CONSUMER_USAGE_HWCOMPOSER) { + // XXX: If we still haven't set a format, default to RGBA8888 + gr_format = HAL_PIXEL_FORMAT_RGBA_8888; + } else if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) { + // If no other usage flags are detected, default the + // flexible YUV format to NV21_ZSL + gr_format = HAL_PIXEL_FORMAT_NV21_ZSL; + } + } + + return gr_format; +} + +/* The default policy is to return cached buffers unless the client explicity + * sets the PRIVATE_UNCACHED flag or indicates that the buffer will be rarely + * read or written in software. */ +bool Allocator::UseUncached(gralloc1_producer_usage_t prod_usage, + gralloc1_consumer_usage_t cons_usage) { + if ((prod_usage & GRALLOC1_PRODUCER_USAGE_PRIVATE_UNCACHED) || + (prod_usage & GRALLOC1_PRODUCER_USAGE_PROTECTED)) { + return true; + } + + // CPU read rarely + if ((prod_usage & GRALLOC1_PRODUCER_USAGE_CPU_READ) && + !(prod_usage & GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN)) { + return true; + } + + // CPU write rarely + if ((prod_usage & GRALLOC1_PRODUCER_USAGE_CPU_WRITE) && + !(prod_usage & GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN)) { + return true; + } + + if ((prod_usage & GRALLOC1_PRODUCER_USAGE_SENSOR_DIRECT_DATA) || + (cons_usage & GRALLOC1_CONSUMER_USAGE_GPU_DATA_BUFFER)) { + return true; + } + + return false; +} + +void Allocator::GetIonHeapInfo(gralloc1_producer_usage_t prod_usage, + gralloc1_consumer_usage_t cons_usage, unsigned int *ion_heap_id, + unsigned int *alloc_type, unsigned int *ion_flags) { + unsigned int heap_id = 0; + unsigned int type = 0; + uint32_t flags = 0; + if (prod_usage & GRALLOC1_PRODUCER_USAGE_PROTECTED) { + if (cons_usage & GRALLOC1_CONSUMER_USAGE_PRIVATE_SECURE_DISPLAY) { + heap_id = ION_HEAP(SD_HEAP_ID); + /* + * There is currently no flag in ION for Secure Display + * VM. Please add it to the define once available. + */ + flags |= UINT(ION_SD_FLAGS); + } else if (prod_usage & GRALLOC1_PRODUCER_USAGE_CAMERA) { + heap_id = ION_HEAP(SD_HEAP_ID); + if (cons_usage & GRALLOC1_CONSUMER_USAGE_HWCOMPOSER) { + flags |= UINT(ION_SC_PREVIEW_FLAGS); + } else { + flags |= UINT(ION_SC_FLAGS); + } + } else { + heap_id = ION_HEAP(CP_HEAP_ID); + flags |= UINT(ION_CP_FLAGS); + } + } else if (prod_usage & GRALLOC1_PRODUCER_USAGE_PRIVATE_MM_HEAP) { + // MM Heap is exclusively a secure heap. + // If it is used for non secure cases, fallback to IOMMU heap + ALOGW("MM_HEAP cannot be used as an insecure heap. Using system heap instead!!"); + heap_id |= ION_HEAP(ION_SYSTEM_HEAP_ID); + } + + if (prod_usage & GRALLOC1_PRODUCER_USAGE_PRIVATE_CAMERA_HEAP) { + heap_id |= ION_HEAP(ION_CAMERA_HEAP_ID); + } + + if (prod_usage & GRALLOC1_PRODUCER_USAGE_PRIVATE_ADSP_HEAP || + prod_usage & GRALLOC1_PRODUCER_USAGE_SENSOR_DIRECT_DATA) { + heap_id |= ION_HEAP(ION_ADSP_HEAP_ID); + } + + if (flags & UINT(ION_SECURE)) { + type |= private_handle_t::PRIV_FLAGS_SECURE_BUFFER; + } + + // if no ion heap flags are set, default to system heap + if (!heap_id) { + heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID); + } + + *alloc_type = type; + *ion_flags = flags; + *ion_heap_id = heap_id; + + return; +} +} // namespace gralloc1 diff --git a/msm8909/gralloc/gr_allocator.h b/msm8909/gralloc/gr_allocator.h new file mode 100644 index 00000000..d57f50e6 --- /dev/null +++ b/msm8909/gralloc/gr_allocator.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2011-2017, 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 __GR_ALLOCATOR_H__ +#define __GR_ALLOCATOR_H__ + +#ifdef MASTER_SIDE_CP +#define SECURE_ALIGN SZ_4K +#else +#define SECURE_ALIGN SZ_1M +#endif + +#include <vector> + +#include "gralloc_priv.h" +#include "gr_buf_descriptor.h" +#include "gr_ion_alloc.h" + +namespace gralloc1 { + +class Allocator { + public: + Allocator(); + ~Allocator(); + bool Init(); + int MapBuffer(void **base, unsigned int size, unsigned int offset, int fd); + int ImportBuffer(int fd); + int FreeBuffer(void *base, unsigned int size, unsigned int offset, int fd, int handle); + int CleanBuffer(void *base, unsigned int size, unsigned int offset, int handle, int op); + int AllocateMem(AllocData *data, gralloc1_producer_usage_t prod_usage, + gralloc1_consumer_usage_t cons_usage); + // @return : index of the descriptor with maximum buffer size req + bool CheckForBufferSharing(uint32_t num_descriptors, + const std::vector<std::shared_ptr<BufferDescriptor>>& descriptors, + ssize_t *max_index); + int GetImplDefinedFormat(gralloc1_producer_usage_t prod_usage, + gralloc1_consumer_usage_t cons_usage, int format); + bool UseUncached(gralloc1_producer_usage_t prod_usage, gralloc1_consumer_usage_t cons_usage); + + private: + void GetIonHeapInfo(gralloc1_producer_usage_t prod_usage, gralloc1_consumer_usage_t cons_usage, + unsigned int *ion_heap_id, unsigned int *alloc_type, unsigned int *ion_flags); + + IonAlloc *ion_allocator_ = NULL; +}; + +} // namespace gralloc1 + +#endif // __GR_ALLOCATOR_H__ diff --git a/msm8909/gralloc/gr_buf_descriptor.h b/msm8909/gralloc/gr_buf_descriptor.h new file mode 100644 index 00000000..c909fa46 --- /dev/null +++ b/msm8909/gralloc/gr_buf_descriptor.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016-2017, 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 __GR_BUF_DESCRIPTOR_H__ +#define __GR_BUF_DESCRIPTOR_H__ + +#include <hardware/gralloc1.h> +#include <atomic> + +namespace gralloc1 { +class BufferDescriptor { + public: + BufferDescriptor() : id_(next_id_++) {} + + BufferDescriptor(int w, int h, int f) + : width_(w), + height_(h), + format_(f), + producer_usage_(GRALLOC1_PRODUCER_USAGE_NONE), + consumer_usage_(GRALLOC1_CONSUMER_USAGE_NONE), + id_(next_id_++) {} + + BufferDescriptor(int w, int h, int f, gralloc1_producer_usage_t prod_usage, + gralloc1_consumer_usage_t cons_usage) + : width_(w), + height_(h), + format_(f), + producer_usage_(prod_usage), + consumer_usage_(cons_usage), + id_(next_id_++) {} + + void SetConsumerUsage(gralloc1_consumer_usage_t usage) { consumer_usage_ = usage; } + + void SetProducerUsage(gralloc1_producer_usage_t usage) { producer_usage_ = usage; } + + void SetDimensions(int w, int h) { + width_ = w; + height_ = h; + } + + void SetColorFormat(int format) { format_ = format; } + + void SetLayerCount(uint32_t layer_count) { layer_count_ = layer_count; } + + gralloc1_consumer_usage_t GetConsumerUsage() const { return consumer_usage_; } + + gralloc1_producer_usage_t GetProducerUsage() const { return producer_usage_; } + + int GetWidth() const { return width_; } + + int GetHeight() const { return height_; } + + int GetFormat() const { return format_; } + + uint32_t GetLayerCount() const { return layer_count_; } + + gralloc1_buffer_descriptor_t GetId() const { return id_; } + + private: + int width_ = -1; + int height_ = -1; + int format_ = -1; + uint32_t layer_count_ = 1; + gralloc1_producer_usage_t producer_usage_ = GRALLOC1_PRODUCER_USAGE_NONE; + gralloc1_consumer_usage_t consumer_usage_ = GRALLOC1_CONSUMER_USAGE_NONE; + const gralloc1_buffer_descriptor_t id_; + static std::atomic<gralloc1_buffer_descriptor_t> next_id_; +}; +}; // namespace gralloc1 +#endif // __GR_BUF_DESCRIPTOR_H__ diff --git a/msm8909/gralloc/gr_buf_mgr.cpp b/msm8909/gralloc/gr_buf_mgr.cpp new file mode 100644 index 00000000..23bed236 --- /dev/null +++ b/msm8909/gralloc/gr_buf_mgr.cpp @@ -0,0 +1,929 @@ +/* + * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved. + * Not a Contribution + * + * Copyright (C) 2010 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. + */ + +#define DEBUG 0 + +#include <iomanip> +#include <utility> +#include <vector> +#include <sstream> + +#include "qd_utils.h" +#include "gr_priv_handle.h" +#include "gr_buf_descriptor.h" +#include "gr_utils.h" +#include "gr_buf_mgr.h" +#include "qdMetaData.h" + +namespace gralloc1 { +std::atomic<gralloc1_buffer_descriptor_t> BufferDescriptor::next_id_(1); + +static BufferInfo GetBufferInfo(const BufferDescriptor &descriptor) { + return BufferInfo(descriptor.GetWidth(), descriptor.GetHeight(), descriptor.GetFormat(), + descriptor.GetProducerUsage(), descriptor.GetConsumerUsage()); +} + +BufferManager::BufferManager() : next_id_(0) { + char property[PROPERTY_VALUE_MAX]; + + // Map framebuffer memory + if ((property_get(MAP_FB_MEMORY_PROP, property, NULL) > 0) && + (!strncmp(property, "1", PROPERTY_VALUE_MAX) || + (!strncasecmp(property, "true", PROPERTY_VALUE_MAX)))) { + map_fb_mem_ = true; + } + + handles_map_.clear(); + allocator_ = new Allocator(); + allocator_->Init(); +} + + +gralloc1_error_t BufferManager::CreateBufferDescriptor( + gralloc1_buffer_descriptor_t *descriptor_id) { + std::lock_guard<std::mutex> lock(descriptor_lock_); + auto descriptor = std::make_shared<BufferDescriptor>(); + descriptors_map_.emplace(descriptor->GetId(), descriptor); + *descriptor_id = descriptor->GetId(); + return GRALLOC1_ERROR_NONE; +} + +gralloc1_error_t BufferManager::DestroyBufferDescriptor( + gralloc1_buffer_descriptor_t descriptor_id) { + std::lock_guard<std::mutex> lock(descriptor_lock_); + const auto descriptor = descriptors_map_.find(descriptor_id); + if (descriptor == descriptors_map_.end()) { + return GRALLOC1_ERROR_BAD_DESCRIPTOR; + } + descriptors_map_.erase(descriptor); + return GRALLOC1_ERROR_NONE; +} + +BufferManager::~BufferManager() { + if (allocator_) { + delete allocator_; + } +} + +gralloc1_error_t BufferManager::AllocateBuffers(uint32_t num_descriptors, + const gralloc1_buffer_descriptor_t *descriptor_ids, + buffer_handle_t *out_buffers) { + bool shared = true; + gralloc1_error_t status = GRALLOC1_ERROR_NONE; + + // since GRALLOC1_CAPABILITY_TEST_ALLOCATE capability is supported + // client can ask to test the allocation by passing NULL out_buffers + bool test_allocate = !out_buffers; + + // Validate descriptors + std::lock_guard<std::mutex> descriptor_lock(descriptor_lock_); + std::vector<std::shared_ptr<BufferDescriptor>> descriptors; + for (uint32_t i = 0; i < num_descriptors; i++) { + const auto map_descriptor = descriptors_map_.find(descriptor_ids[i]); + if (map_descriptor == descriptors_map_.end()) { + return GRALLOC1_ERROR_BAD_DESCRIPTOR; + } else { + descriptors.push_back(map_descriptor->second); + } + } + + // Resolve implementation defined formats + for (auto &descriptor : descriptors) { + descriptor->SetColorFormat(allocator_->GetImplDefinedFormat(descriptor->GetProducerUsage(), + descriptor->GetConsumerUsage(), + descriptor->GetFormat())); + } + + // Check if input descriptors can be supported AND + // Find out if a single buffer can be shared for all the given input descriptors + uint32_t i = 0; + ssize_t max_buf_index = -1; + shared = allocator_->CheckForBufferSharing(num_descriptors, descriptors, &max_buf_index); + + if (test_allocate) { + status = shared ? GRALLOC1_ERROR_NOT_SHARED : status; + return status; + } + + std::lock_guard<std::mutex> buffer_lock(buffer_lock_); + if (shared && (max_buf_index >= 0)) { + // Allocate one and duplicate/copy the handles for each descriptor + if (AllocateBuffer(*descriptors[UINT(max_buf_index)], &out_buffers[max_buf_index])) { + return GRALLOC1_ERROR_NO_RESOURCES; + } + + for (i = 0; i < num_descriptors; i++) { + // Create new handle for a given descriptor. + // Current assumption is even MetaData memory would be same + // Need to revisit if there is a need for own metadata memory + if (i != UINT(max_buf_index)) { + CreateSharedHandle(out_buffers[max_buf_index], *descriptors[i], &out_buffers[i]); + } + } + } else { + // Buffer sharing is not feasible. + // Allocate separate buffer for each descriptor + for (i = 0; i < num_descriptors; i++) { + if (AllocateBuffer(*descriptors[i], &out_buffers[i])) { + return GRALLOC1_ERROR_NO_RESOURCES; + } + } + } + + // Allocation is successful. If backstore is not shared inform the client. + if (!shared) { + return GRALLOC1_ERROR_NOT_SHARED; + } + + return status; +} + +void BufferManager::CreateSharedHandle(buffer_handle_t inbuffer, const BufferDescriptor &descriptor, + buffer_handle_t *outbuffer) { + // TODO(user): This path is not verified + private_handle_t const *input = reinterpret_cast<private_handle_t const *>(inbuffer); + + // Get Buffer attributes or dimension + unsigned int alignedw = 0, alignedh = 0; + BufferInfo info = GetBufferInfo(descriptor); + + GetAlignedWidthAndHeight(info, &alignedw, &alignedh); + + // create new handle from input reference handle and given descriptor + int flags = GetHandleFlags(descriptor.GetFormat(), descriptor.GetProducerUsage(), + descriptor.GetConsumerUsage()); + int buffer_type = GetBufferType(descriptor.GetFormat()); + + // Duplicate the fds + // TODO(user): Not sure what to do for fb_id. Use duped fd and new dimensions? + private_handle_t *out_hnd = new private_handle_t(dup(input->fd), + dup(input->fd_metadata), + flags, + INT(alignedw), + INT(alignedh), + descriptor.GetWidth(), + descriptor.GetHeight(), + descriptor.GetFormat(), + buffer_type, + input->size, + descriptor.GetProducerUsage(), + descriptor.GetConsumerUsage()); + out_hnd->id = ++next_id_; + // TODO(user): Base address of shared handle and ion handles + RegisterHandleLocked(out_hnd, -1, -1); + *outbuffer = out_hnd; +} + +gralloc1_error_t BufferManager::FreeBuffer(std::shared_ptr<Buffer> buf) { + auto hnd = buf->handle; + ALOGD_IF(DEBUG, "FreeBuffer handle:%p", hnd); + + if (private_handle_t::validate(hnd) != 0) { + ALOGE("FreeBuffer: Invalid handle: %p", hnd); + return GRALLOC1_ERROR_BAD_HANDLE; + } + + if (allocator_->FreeBuffer(reinterpret_cast<void *>(hnd->base), hnd->size, hnd->offset, + hnd->fd, buf->ion_handle_main) != 0) { + return GRALLOC1_ERROR_BAD_HANDLE; + } + + unsigned int meta_size = ALIGN((unsigned int)sizeof(MetaData_t), PAGE_SIZE); + if (allocator_->FreeBuffer(reinterpret_cast<void *>(hnd->base_metadata), meta_size, + hnd->offset_metadata, hnd->fd_metadata, buf->ion_handle_meta) != 0) { + return GRALLOC1_ERROR_BAD_HANDLE; + } + + private_handle_t * handle = const_cast<private_handle_t *>(hnd); + handle->fd = -1; + handle->fd_metadata = -1; + if (!(handle->flags & private_handle_t::PRIV_FLAGS_CLIENT_ALLOCATED)) { + delete handle; + } + return GRALLOC1_ERROR_NONE; +} + +void BufferManager::RegisterHandleLocked(const private_handle_t *hnd, + int ion_handle, + int ion_handle_meta) { + auto buffer = std::make_shared<Buffer>(hnd, ion_handle, ion_handle_meta); + handles_map_.emplace(std::make_pair(hnd, buffer)); +} + +gralloc1_error_t BufferManager::ImportHandleLocked(private_handle_t *hnd) { + ALOGD_IF(DEBUG, "Importing handle:%p id: %" PRIu64, hnd, hnd->id); + int ion_handle = allocator_->ImportBuffer(hnd->fd); + if (ion_handle < 0) { + ALOGE("Failed to import ion buffer: hnd: %p, fd:%d, id:%" PRIu64, hnd, hnd->fd, hnd->id); + return GRALLOC1_ERROR_BAD_HANDLE; + } + int ion_handle_meta = allocator_->ImportBuffer(hnd->fd_metadata); + if (ion_handle_meta < 0) { + ALOGE("Failed to import ion metadata buffer: hnd: %p, fd:%d, id:%" PRIu64, hnd, + hnd->fd, hnd->id); + return GRALLOC1_ERROR_BAD_HANDLE; + } + // Set base pointers to NULL since the data here was received over binder + hnd->base = 0; + hnd->base_metadata = 0; + RegisterHandleLocked(hnd, ion_handle, ion_handle_meta); + return GRALLOC1_ERROR_NONE; +} + +std::shared_ptr<BufferManager::Buffer> +BufferManager::GetBufferFromHandleLocked(const private_handle_t *hnd) { + auto it = handles_map_.find(hnd); + if (it != handles_map_.end()) { + return it->second; + } else { + return nullptr; + } +} + +gralloc1_error_t BufferManager::MapBuffer(private_handle_t const *handle) { + private_handle_t *hnd = const_cast<private_handle_t *>(handle); + ALOGD_IF(DEBUG, "Map buffer handle:%p id: %" PRIu64, hnd, hnd->id); + + hnd->base = 0; + if (allocator_->MapBuffer(reinterpret_cast<void **>(&hnd->base), hnd->size, hnd->offset, + hnd->fd) != 0) { + return GRALLOC1_ERROR_BAD_HANDLE; + } + return GRALLOC1_ERROR_NONE; +} + +gralloc1_error_t BufferManager::RetainBuffer(private_handle_t const *hnd) { + ALOGD_IF(DEBUG, "Retain buffer handle:%p id: %" PRIu64, hnd, hnd->id); + gralloc1_error_t err = GRALLOC1_ERROR_NONE; + std::lock_guard<std::mutex> lock(buffer_lock_); + auto buf = GetBufferFromHandleLocked(hnd); + if (buf != nullptr) { + buf->IncRef(); + } else { + private_handle_t *handle = const_cast<private_handle_t *>(hnd); + err = ImportHandleLocked(handle); + } + return err; +} + +gralloc1_error_t BufferManager::ReleaseBuffer(private_handle_t const *hnd) { + ALOGD_IF(DEBUG, "Release buffer handle:%p", hnd); + std::lock_guard<std::mutex> lock(buffer_lock_); + auto buf = GetBufferFromHandleLocked(hnd); + if (buf == nullptr) { + ALOGE("Could not find handle: %p id: %" PRIu64, hnd, hnd->id); + return GRALLOC1_ERROR_BAD_HANDLE; + } else { + if (buf->DecRef()) { + handles_map_.erase(hnd); + // Unmap, close ion handle and close fd + FreeBuffer(buf); + } + } + return GRALLOC1_ERROR_NONE; +} + +gralloc1_error_t BufferManager::LockBuffer(const private_handle_t *hnd, + gralloc1_producer_usage_t prod_usage, + gralloc1_consumer_usage_t cons_usage) { + std::lock_guard<std::mutex> lock(buffer_lock_); + gralloc1_error_t err = GRALLOC1_ERROR_NONE; + ALOGD_IF(DEBUG, "LockBuffer buffer handle:%p id: %" PRIu64, hnd, hnd->id); + + // If buffer is not meant for CPU return err + if (!CpuCanAccess(prod_usage, cons_usage)) { + return GRALLOC1_ERROR_BAD_VALUE; + } + + auto buf = GetBufferFromHandleLocked(hnd); + if (buf == nullptr) { + return GRALLOC1_ERROR_BAD_HANDLE; + } + + if (hnd->base == 0) { + // we need to map for real + err = MapBuffer(hnd); + } + + // todo use handle here + if (!err && (hnd->flags & private_handle_t::PRIV_FLAGS_USES_ION) && + (hnd->flags & private_handle_t::PRIV_FLAGS_CACHED)) { + + // Invalidate if CPU reads in software and there are non-CPU + // writers. No need to do this for the metadata buffer as it is + // only read/written in software. + if ((cons_usage & (GRALLOC1_CONSUMER_USAGE_CPU_READ | GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN)) + && (hnd->flags & private_handle_t::PRIV_FLAGS_NON_CPU_WRITER)) { + if (allocator_->CleanBuffer(reinterpret_cast<void *>(hnd->base), hnd->size, hnd->offset, + buf->ion_handle_main, CACHE_INVALIDATE)) { + + return GRALLOC1_ERROR_BAD_HANDLE; + } + } + } + + // Mark the buffer to be flushed after CPU write. + if (!err && CpuCanWrite(prod_usage)) { + private_handle_t *handle = const_cast<private_handle_t *>(hnd); + handle->flags |= private_handle_t::PRIV_FLAGS_NEEDS_FLUSH; + } + + return err; +} + +gralloc1_error_t BufferManager::UnlockBuffer(const private_handle_t *handle) { + std::lock_guard<std::mutex> lock(buffer_lock_); + gralloc1_error_t status = GRALLOC1_ERROR_NONE; + + private_handle_t *hnd = const_cast<private_handle_t *>(handle); + auto buf = GetBufferFromHandleLocked(hnd); + if (buf == nullptr) { + return GRALLOC1_ERROR_BAD_HANDLE; + } + + if (hnd->flags & private_handle_t::PRIV_FLAGS_NEEDS_FLUSH) { + if (allocator_->CleanBuffer(reinterpret_cast<void *>(hnd->base), hnd->size, hnd->offset, + buf->ion_handle_main, CACHE_CLEAN) != 0) { + status = GRALLOC1_ERROR_BAD_HANDLE; + } + hnd->flags &= ~private_handle_t::PRIV_FLAGS_NEEDS_FLUSH; + } + + return status; +} + +uint32_t BufferManager::GetDataAlignment(int format, gralloc1_producer_usage_t prod_usage, + gralloc1_consumer_usage_t cons_usage) { + uint32_t align = UINT(getpagesize()); + if (format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED) { + align = 8192; + } + + if (prod_usage & GRALLOC1_PRODUCER_USAGE_PROTECTED) { + if ((prod_usage & GRALLOC1_PRODUCER_USAGE_CAMERA) || + (cons_usage & GRALLOC1_CONSUMER_USAGE_PRIVATE_SECURE_DISPLAY)) { + // The alignment here reflects qsee mmu V7L/V8L requirement + align = SZ_2M; + } else { + align = SECURE_ALIGN; + } + } + + return align; +} + +int BufferManager::GetHandleFlags(int format, gralloc1_producer_usage_t prod_usage, + gralloc1_consumer_usage_t cons_usage) { + int flags = 0; + if (cons_usage & GRALLOC1_CONSUMER_USAGE_PRIVATE_EXTERNAL_ONLY) { + flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY; + } + + if (cons_usage & GRALLOC1_CONSUMER_USAGE_PRIVATE_INTERNAL_ONLY) { + flags |= private_handle_t::PRIV_FLAGS_INTERNAL_ONLY; + } + + if (cons_usage & GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER) { + flags |= private_handle_t::PRIV_FLAGS_VIDEO_ENCODER; + } + + if (prod_usage & GRALLOC1_PRODUCER_USAGE_CAMERA) { + flags |= private_handle_t::PRIV_FLAGS_CAMERA_WRITE; + } + + if (prod_usage & GRALLOC1_CONSUMER_USAGE_CAMERA) { + flags |= private_handle_t::PRIV_FLAGS_CAMERA_READ; + } + + if (cons_usage & GRALLOC1_CONSUMER_USAGE_HWCOMPOSER) { + flags |= private_handle_t::PRIV_FLAGS_HW_COMPOSER; + } + + if (prod_usage & GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE) { + flags |= private_handle_t::PRIV_FLAGS_HW_TEXTURE; + } + + if (cons_usage & GRALLOC1_CONSUMER_USAGE_PRIVATE_SECURE_DISPLAY) { + flags |= private_handle_t::PRIV_FLAGS_SECURE_DISPLAY; + } + + if (IsUBwcEnabled(format, prod_usage, cons_usage)) { + flags |= private_handle_t::PRIV_FLAGS_UBWC_ALIGNED; + } + + if (prod_usage & (GRALLOC1_PRODUCER_USAGE_CPU_READ | GRALLOC1_PRODUCER_USAGE_CPU_WRITE)) { + flags |= private_handle_t::PRIV_FLAGS_CPU_RENDERED; + } + + // TODO(user): is this correct??? + if ((cons_usage & + (GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER | GRALLOC1_CONSUMER_USAGE_CLIENT_TARGET)) || + (prod_usage & (GRALLOC1_PRODUCER_USAGE_CAMERA | GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET))) { + flags |= private_handle_t::PRIV_FLAGS_NON_CPU_WRITER; + } + + if (cons_usage & GRALLOC1_CONSUMER_USAGE_HWCOMPOSER) { + flags |= private_handle_t::PRIV_FLAGS_DISP_CONSUMER; + } + + if (!allocator_->UseUncached(prod_usage, cons_usage)) { + flags |= private_handle_t::PRIV_FLAGS_CACHED; + } + + return flags; +} + +int BufferManager::GetBufferType(int inputFormat) { + int buffer_type = BUFFER_TYPE_VIDEO; + if (IsUncompressedRGBFormat(inputFormat)) { + // RGB formats + buffer_type = BUFFER_TYPE_UI; + } + + return buffer_type; +} + +int BufferManager::AllocateBuffer(const BufferDescriptor &descriptor, buffer_handle_t *handle, + unsigned int bufferSize) { + if (!handle) + return -EINVAL; + + int format = descriptor.GetFormat(); + gralloc1_producer_usage_t prod_usage = descriptor.GetProducerUsage(); + gralloc1_consumer_usage_t cons_usage = descriptor.GetConsumerUsage(); + uint32_t layer_count = descriptor.GetLayerCount(); + + // Get implementation defined format + int gralloc_format = allocator_->GetImplDefinedFormat(prod_usage, cons_usage, format); + + unsigned int size; + unsigned int alignedw, alignedh; + int buffer_type = GetBufferType(gralloc_format); + BufferInfo info = GetBufferInfo(descriptor); + GetBufferSizeAndDimensions(info, &size, &alignedw, &alignedh); + size = (bufferSize >= size) ? bufferSize : size; + + int err = 0; + int flags = 0; + auto page_size = UINT(getpagesize()); + AllocData data; + data.align = GetDataAlignment(format, prod_usage, cons_usage); + size = ALIGN(size, data.align) * layer_count; + data.size = size; + data.handle = (uintptr_t) handle; + data.uncached = allocator_->UseUncached(prod_usage, cons_usage); + + // Allocate buffer memory + err = allocator_->AllocateMem(&data, prod_usage, cons_usage); + if (err) { + ALOGE("gralloc failed to allocate err=%s", strerror(-err)); + return err; + } + + // Allocate memory for MetaData + AllocData e_data; + e_data.size = ALIGN(UINT(sizeof(MetaData_t)), page_size); + e_data.handle = data.handle; + e_data.align = page_size; + + err = + allocator_->AllocateMem(&e_data, GRALLOC1_PRODUCER_USAGE_NONE, GRALLOC1_CONSUMER_USAGE_NONE); + if (err) { + ALOGE("gralloc failed to allocate metadata error=%s", strerror(-err)); + return err; + } + + flags = GetHandleFlags(format, prod_usage, cons_usage); + flags |= data.alloc_type; + + // Create handle + private_handle_t *hnd = new private_handle_t(data.fd, + e_data.fd, + flags, + INT(alignedw), + INT(alignedh), + descriptor.GetWidth(), + descriptor.GetHeight(), + format, + buffer_type, + data.size, + prod_usage, + cons_usage); + + hnd->id = ++next_id_; + hnd->base = 0; + hnd->base_metadata = 0; + hnd->layer_count = layer_count; + + ColorSpace_t colorSpace = ITU_R_601; + setMetaData(hnd, UPDATE_COLOR_SPACE, reinterpret_cast<void *>(&colorSpace)); + *handle = hnd; + RegisterHandleLocked(hnd, data.ion_handle, e_data.ion_handle); + ALOGD_IF(DEBUG, "Allocated buffer handle: %p id: %" PRIu64, hnd, hnd->id); + if (DEBUG) { + private_handle_t::Dump(hnd); + } + return err; +} + +gralloc1_error_t BufferManager::Perform(int operation, va_list args) { + switch (operation) { + case GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER: { + int fd = va_arg(args, int); + unsigned int size = va_arg(args, unsigned int); + unsigned int offset = va_arg(args, unsigned int); + void *base = va_arg(args, void *); + int width = va_arg(args, int); + int height = va_arg(args, int); + int format = va_arg(args, int); + + native_handle_t **handle = va_arg(args, native_handle_t **); + if (!handle) { + return GRALLOC1_ERROR_BAD_HANDLE; + } + + private_handle_t *hnd = reinterpret_cast<private_handle_t *>( + native_handle_create(private_handle_t::kNumFds, private_handle_t::NumInts())); + if (hnd) { + unsigned int alignedw = 0, alignedh = 0; + hnd->magic = private_handle_t::kMagic; + hnd->fd = fd; + hnd->flags = private_handle_t::PRIV_FLAGS_USES_ION; + hnd->size = size; + hnd->offset = offset; + hnd->base = uint64_t(base); + hnd->gpuaddr = 0; + BufferInfo info(width, height, format); + GetAlignedWidthAndHeight(info, &alignedw, &alignedh); + hnd->unaligned_width = width; + hnd->unaligned_height = height; + hnd->width = INT(alignedw); + hnd->height = INT(alignedh); + hnd->format = format; + *handle = reinterpret_cast<native_handle_t *>(hnd); + } + } break; + + case GRALLOC_MODULE_PERFORM_GET_STRIDE: { + int width = va_arg(args, int); + int format = va_arg(args, int); + int *stride = va_arg(args, int *); + unsigned int alignedw = 0, alignedh = 0; + + if (!stride) { + return GRALLOC1_ERROR_BAD_VALUE; + } + + BufferInfo info(width, width, format); + GetAlignedWidthAndHeight(info, &alignedw, &alignedh); + *stride = INT(alignedw); + } break; + + case GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_FROM_HANDLE: { + private_handle_t *hnd = va_arg(args, private_handle_t *); + int *stride = va_arg(args, int *); + if (private_handle_t::validate(hnd) != 0) { + return GRALLOC1_ERROR_BAD_HANDLE; + } + + if (!stride) { + return GRALLOC1_ERROR_BAD_VALUE; + } + + BufferDim_t buffer_dim; + if (getMetaData(hnd, GET_BUFFER_GEOMETRY, &buffer_dim) == 0) { + *stride = buffer_dim.sliceWidth; + } else { + *stride = hnd->width; + } + } break; + + // TODO(user) : this alone should be sufficient, ask gfx to get rid of above + case GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_AND_HEIGHT_FROM_HANDLE: { + private_handle_t *hnd = va_arg(args, private_handle_t *); + int *stride = va_arg(args, int *); + int *height = va_arg(args, int *); + if (private_handle_t::validate(hnd) != 0) { + return GRALLOC1_ERROR_BAD_HANDLE; + } + + if (!stride || !height) { + return GRALLOC1_ERROR_BAD_VALUE; + } + + BufferDim_t buffer_dim; + if (getMetaData(hnd, GET_BUFFER_GEOMETRY, &buffer_dim) == 0) { + *stride = buffer_dim.sliceWidth; + *height = buffer_dim.sliceHeight; + } else { + *stride = hnd->width; + *height = hnd->height; + } + } break; + + case GRALLOC_MODULE_PERFORM_GET_ATTRIBUTES: { + // TODO(user): Usage is split now. take care of it from Gfx client. + // see if we can directly expect descriptor from gfx client. + int width = va_arg(args, int); + int height = va_arg(args, int); + int format = va_arg(args, int); + uint64_t producer_usage = va_arg(args, uint64_t); + uint64_t consumer_usage = va_arg(args, uint64_t); + gralloc1_producer_usage_t prod_usage = static_cast<gralloc1_producer_usage_t>(producer_usage); + gralloc1_consumer_usage_t cons_usage = static_cast<gralloc1_consumer_usage_t>(consumer_usage); + + int *aligned_width = va_arg(args, int *); + int *aligned_height = va_arg(args, int *); + int *tile_enabled = va_arg(args, int *); + if (!aligned_width || !aligned_height || !tile_enabled) { + return GRALLOC1_ERROR_BAD_VALUE; + } + + unsigned int alignedw, alignedh; + BufferInfo info(width, height, format, prod_usage, cons_usage); + *tile_enabled = IsUBwcEnabled(format, prod_usage, cons_usage); + GetAlignedWidthAndHeight(info, &alignedw, &alignedh); + *aligned_width = INT(alignedw); + *aligned_height = INT(alignedh); + } break; + + case GRALLOC_MODULE_PERFORM_GET_COLOR_SPACE_FROM_HANDLE: { + private_handle_t *hnd = va_arg(args, private_handle_t *); + int *color_space = va_arg(args, int *); + + if (private_handle_t::validate(hnd) != 0) { + return GRALLOC1_ERROR_BAD_HANDLE; + } + + if (!color_space) { + return GRALLOC1_ERROR_BAD_VALUE; + } + + *color_space = 0; + ColorMetaData color_metadata; + if (getMetaData(hnd, GET_COLOR_METADATA, &color_metadata) == 0) { + switch (color_metadata.colorPrimaries) { + case ColorPrimaries_BT709_5: + *color_space = HAL_CSC_ITU_R_709; + break; + case ColorPrimaries_BT601_6_525: + *color_space = ((color_metadata.range) ? HAL_CSC_ITU_R_601_FR : HAL_CSC_ITU_R_601); + break; + case ColorPrimaries_BT2020: + *color_space = (color_metadata.range) ? HAL_CSC_ITU_R_2020_FR : HAL_CSC_ITU_R_2020; + break; + default: + ALOGE("Unknown Color Space = %d", color_metadata.colorPrimaries); + break; + } + break; + } else if (getMetaData(hnd, GET_COLOR_SPACE, color_space) != 0) { + *color_space = 0; + } + } break; + case GRALLOC_MODULE_PERFORM_GET_YUV_PLANE_INFO: { + private_handle_t *hnd = va_arg(args, private_handle_t *); + android_ycbcr *ycbcr = va_arg(args, struct android_ycbcr *); + if (private_handle_t::validate(hnd) != 0) { + return GRALLOC1_ERROR_BAD_HANDLE; + } + + if (!ycbcr) { + return GRALLOC1_ERROR_BAD_VALUE; + } + + if (GetYUVPlaneInfo(hnd, ycbcr)) { + return GRALLOC1_ERROR_UNDEFINED; + } + } break; + + case GRALLOC_MODULE_PERFORM_GET_MAP_SECURE_BUFFER_INFO: { + private_handle_t *hnd = va_arg(args, private_handle_t *); + int *map_secure_buffer = va_arg(args, int *); + + if (private_handle_t::validate(hnd) != 0) { + return GRALLOC1_ERROR_BAD_HANDLE; + } + + if (!map_secure_buffer) { + return GRALLOC1_ERROR_BAD_VALUE; + } + + if (getMetaData(hnd, GET_MAP_SECURE_BUFFER, map_secure_buffer) == 0) { + *map_secure_buffer = 0; + } + } break; + + case GRALLOC_MODULE_PERFORM_GET_UBWC_FLAG: { + private_handle_t *hnd = va_arg(args, private_handle_t *); + int *flag = va_arg(args, int *); + + if (private_handle_t::validate(hnd) != 0) { + return GRALLOC1_ERROR_BAD_HANDLE; + } + + if (!flag) { + return GRALLOC1_ERROR_BAD_VALUE; + } + + *flag = hnd->flags &private_handle_t::PRIV_FLAGS_UBWC_ALIGNED; + int linear_format = 0; + if (getMetaData(hnd, GET_LINEAR_FORMAT, &linear_format) == 0) { + if (linear_format) { + *flag = 0; + } + } + } break; + + case GRALLOC_MODULE_PERFORM_GET_RGB_DATA_ADDRESS: { + private_handle_t *hnd = va_arg(args, private_handle_t *); + void **rgb_data = va_arg(args, void **); + + if (private_handle_t::validate(hnd) != 0) { + return GRALLOC1_ERROR_BAD_HANDLE; + } + + if (!rgb_data) { + return GRALLOC1_ERROR_BAD_VALUE; + } + + if (GetRgbDataAddress(hnd, rgb_data)) { + return GRALLOC1_ERROR_UNDEFINED; + } + } break; + + case GRALLOC1_MODULE_PERFORM_GET_BUFFER_SIZE_AND_DIMENSIONS: { + int width = va_arg(args, int); + int height = va_arg(args, int); + int format = va_arg(args, int); + uint64_t p_usage = va_arg(args, uint64_t); + uint64_t c_usage = va_arg(args, uint64_t); + gralloc1_producer_usage_t producer_usage = static_cast<gralloc1_producer_usage_t>(p_usage); + gralloc1_consumer_usage_t consumer_usage = static_cast<gralloc1_consumer_usage_t>(c_usage); + uint32_t *aligned_width = va_arg(args, uint32_t *); + uint32_t *aligned_height = va_arg(args, uint32_t *); + uint32_t *size = va_arg(args, uint32_t *); + + if (!aligned_width || !aligned_height || !size) { + return GRALLOC1_ERROR_BAD_VALUE; + } + + auto info = BufferInfo(width, height, format, producer_usage, consumer_usage); + GetBufferSizeAndDimensions(info, size, aligned_width, aligned_height); + // Align size + auto align = GetDataAlignment(format, producer_usage, consumer_usage); + *size = ALIGN(*size, align); + } break; + + case GRALLOC1_MODULE_PERFORM_ALLOCATE_BUFFER: { + std::lock_guard<std::mutex> lock(buffer_lock_); + int width = va_arg(args, int); + int height = va_arg(args, int); + int format = va_arg(args, int); + uint64_t p_usage = va_arg(args, uint64_t); + uint64_t c_usage = va_arg(args, uint64_t); + buffer_handle_t *hnd = va_arg(args, buffer_handle_t*); + gralloc1_producer_usage_t producer_usage = static_cast<gralloc1_producer_usage_t>(p_usage); + gralloc1_consumer_usage_t consumer_usage = static_cast<gralloc1_consumer_usage_t>(c_usage); + BufferDescriptor descriptor(width, height, format, producer_usage, consumer_usage); + unsigned int size; + unsigned int alignedw, alignedh; + GetBufferSizeAndDimensions(GetBufferInfo(descriptor), &size, &alignedw, &alignedh); + AllocateBuffer(descriptor, hnd, size); + } break; + + case GRALLOC1_MODULE_PERFORM_GET_INTERLACE_FLAG: { + private_handle_t *hnd = va_arg(args, private_handle_t *); + int *flag = va_arg(args, int *); + + if (private_handle_t::validate(hnd) != 0) { + return GRALLOC1_ERROR_BAD_HANDLE; + } + + if (!flag) { + return GRALLOC1_ERROR_BAD_VALUE; + } + + if (getMetaData(hnd, GET_PP_PARAM_INTERLACED, flag) != 0) { + *flag = 0; + } + } break; + + default: + break; + } + return GRALLOC1_ERROR_NONE; +} + +static bool IsYuvFormat(const private_handle_t *hnd) { + switch (hnd->format) { + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: // Same as YCbCr_420_SP_VENUS + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + case HAL_PIXEL_FORMAT_YCrCb_422_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: + case HAL_PIXEL_FORMAT_NV21_ZSL: + case HAL_PIXEL_FORMAT_RAW16: + case HAL_PIXEL_FORMAT_Y16: + case HAL_PIXEL_FORMAT_RAW12: + case HAL_PIXEL_FORMAT_RAW10: + case HAL_PIXEL_FORMAT_YV12: + case HAL_PIXEL_FORMAT_Y8: + return true; + default: + return false; + } +} + +gralloc1_error_t BufferManager::GetNumFlexPlanes(const private_handle_t *hnd, + uint32_t *out_num_planes) { + if (!IsYuvFormat(hnd)) { + return GRALLOC1_ERROR_UNSUPPORTED; + } else { + *out_num_planes = 3; + } + return GRALLOC1_ERROR_NONE; +} + +gralloc1_error_t BufferManager::GetFlexLayout(const private_handle_t *hnd, + struct android_flex_layout *layout) { + if (!IsYuvFormat(hnd)) { + return GRALLOC1_ERROR_UNSUPPORTED; + } + + android_ycbcr ycbcr; + int err = GetYUVPlaneInfo(hnd, &ycbcr); + + if (err != 0) { + return GRALLOC1_ERROR_BAD_HANDLE; + } + + layout->format = FLEX_FORMAT_YCbCr; + layout->num_planes = 3; + + for (uint32_t i = 0; i < layout->num_planes; i++) { + layout->planes[i].bits_per_component = 8; + layout->planes[i].bits_used = 8; + layout->planes[i].h_increment = 1; + layout->planes[i].v_increment = 1; + layout->planes[i].h_subsampling = 2; + layout->planes[i].v_subsampling = 2; + } + + layout->planes[0].top_left = static_cast<uint8_t *>(ycbcr.y); + layout->planes[0].component = FLEX_COMPONENT_Y; + layout->planes[0].v_increment = static_cast<int32_t>(ycbcr.ystride); + + layout->planes[1].top_left = static_cast<uint8_t *>(ycbcr.cb); + layout->planes[1].component = FLEX_COMPONENT_Cb; + layout->planes[1].h_increment = static_cast<int32_t>(ycbcr.chroma_step); + layout->planes[1].v_increment = static_cast<int32_t>(ycbcr.cstride); + + layout->planes[2].top_left = static_cast<uint8_t *>(ycbcr.cr); + layout->planes[2].component = FLEX_COMPONENT_Cr; + layout->planes[2].h_increment = static_cast<int32_t>(ycbcr.chroma_step); + layout->planes[2].v_increment = static_cast<int32_t>(ycbcr.cstride); + return GRALLOC1_ERROR_NONE; +} + +gralloc1_error_t BufferManager::Dump(std::ostringstream *os) { + for (auto it : handles_map_) { + auto buf = it.second; + auto hnd = buf->handle; + *os << "handle id: " << std::setw(4) << hnd->id; + *os << " fd: " << std::setw(3) << hnd->fd; + *os << " fd_meta: " << std::setw(3) << hnd->fd_metadata; + *os << " wxh: " << std::setw(4) << hnd->width <<" x " << std::setw(4) << hnd->height; + *os << " uwxuh: " << std::setw(4) << hnd->unaligned_width << " x "; + *os << std::setw(4) << hnd->unaligned_height; + *os << " size: " << std::setw(9) << hnd->size; + *os << std::hex << std::setfill('0'); + *os << " priv_flags: " << "0x" << std::setw(8) << hnd->flags; + *os << " prod_usage: " << "0x" << std::setw(8) << hnd->producer_usage; + *os << " cons_usage: " << "0x" << std::setw(8) << hnd->consumer_usage; + // TODO(user): get format string from qdutils + *os << " format: " << "0x" << std::setw(8) << hnd->format; + *os << std::dec << std::setfill(' ') << std::endl; + } + return GRALLOC1_ERROR_NONE; +} +} // namespace gralloc1 diff --git a/msm8909/gralloc/gr_buf_mgr.h b/msm8909/gralloc/gr_buf_mgr.h new file mode 100644 index 00000000..861a7a7b --- /dev/null +++ b/msm8909/gralloc/gr_buf_mgr.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. + * Not a Contribution + * + * 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. + */ + +#ifndef __GR_BUF_MGR_H__ +#define __GR_BUF_MGR_H__ + +#include <pthread.h> +#include <unordered_map> +#include <unordered_set> +#include <utility> +#include <mutex> + +#include "gralloc_priv.h" +#include "gr_allocator.h" +#include "gr_buf_descriptor.h" + +namespace gralloc1 { + +class BufferManager { + public: + ~BufferManager(); + gralloc1_error_t CreateBufferDescriptor(gralloc1_buffer_descriptor_t *descriptor_id); + gralloc1_error_t DestroyBufferDescriptor(gralloc1_buffer_descriptor_t descriptor_id); + gralloc1_error_t AllocateBuffers(uint32_t num_descriptors, + const gralloc1_buffer_descriptor_t *descriptor_ids, + buffer_handle_t *out_buffers); + gralloc1_error_t RetainBuffer(private_handle_t const *hnd); + gralloc1_error_t ReleaseBuffer(private_handle_t const *hnd); + gralloc1_error_t LockBuffer(const private_handle_t *hnd, gralloc1_producer_usage_t prod_usage, + gralloc1_consumer_usage_t cons_usage); + gralloc1_error_t UnlockBuffer(const private_handle_t *hnd); + gralloc1_error_t Perform(int operation, va_list args); + gralloc1_error_t GetFlexLayout(const private_handle_t *hnd, struct android_flex_layout *layout); + gralloc1_error_t GetNumFlexPlanes(const private_handle_t *hnd, uint32_t *out_num_planes); + gralloc1_error_t Dump(std::ostringstream *os); + + template <typename... Args> + gralloc1_error_t CallBufferDescriptorFunction(gralloc1_buffer_descriptor_t descriptor_id, + void (BufferDescriptor::*member)(Args...), + Args... args) { + std::lock_guard<std::mutex> lock(descriptor_lock_); + const auto map_descriptor = descriptors_map_.find(descriptor_id); + if (map_descriptor == descriptors_map_.end()) { + return GRALLOC1_ERROR_BAD_DESCRIPTOR; + } + const auto descriptor = map_descriptor->second; + (descriptor.get()->*member)(std::forward<Args>(args)...); + return GRALLOC1_ERROR_NONE; + } + + static BufferManager* GetInstance() { + static BufferManager *instance = new BufferManager(); + return instance; + } + + private: + BufferManager(); + gralloc1_error_t MapBuffer(private_handle_t const *hnd); + int GetBufferType(int format); + int AllocateBuffer(const BufferDescriptor &descriptor, buffer_handle_t *handle, + unsigned int bufferSize = 0); + uint32_t GetDataAlignment(int format, gralloc1_producer_usage_t prod_usage, + gralloc1_consumer_usage_t cons_usage); + int GetHandleFlags(int format, gralloc1_producer_usage_t prod_usage, + gralloc1_consumer_usage_t cons_usage); + void CreateSharedHandle(buffer_handle_t inbuffer, const BufferDescriptor &descriptor, + buffer_handle_t *out_buffer); + + // Imports the ion fds into the current process. Returns an error for invalid handles + gralloc1_error_t ImportHandleLocked(private_handle_t *hnd); + + // Creates a Buffer from the valid private handle and adds it to the map + void RegisterHandleLocked(const private_handle_t *hnd, int ion_handle, int ion_handle_meta); + + // Wrapper structure over private handle + // Values associated with the private handle + // that do not need to go over IPC can be placed here + // This structure is also not expected to be ABI stable + // unlike private_handle_t + struct Buffer { + const private_handle_t *handle = nullptr; + int ref_count = 1; + // Hold the main and metadata ion handles + // Freed from the allocator process + // and unused in the mapping process + int ion_handle_main = -1; + int ion_handle_meta = -1; + + Buffer() = delete; + explicit Buffer(const private_handle_t* h, int ih_main = -1, int ih_meta = -1): + handle(h), + ion_handle_main(ih_main), + ion_handle_meta(ih_meta) { + } + void IncRef() { ++ref_count; } + bool DecRef() { return --ref_count == 0; } + }; + + gralloc1_error_t FreeBuffer(std::shared_ptr<Buffer> buf); + + // Get the wrapper Buffer object from the handle, returns nullptr if handle is not found + std::shared_ptr<Buffer> GetBufferFromHandleLocked(const private_handle_t *hnd); + + bool map_fb_mem_ = false; + Allocator *allocator_ = NULL; + std::mutex buffer_lock_; + std::mutex descriptor_lock_; + // TODO(user): The private_handle_t is used as a key because the unique ID generated + // from next_id_ is not unique across processes. The correct way to resolve this would + // be to use the allocator over hwbinder + std::unordered_map<const private_handle_t*, std::shared_ptr<Buffer>> handles_map_ = {}; + std::unordered_map<gralloc1_buffer_descriptor_t, + std::shared_ptr<BufferDescriptor>> descriptors_map_ = {}; + std::atomic<uint64_t> next_id_; +}; + +} // namespace gralloc1 + +#endif // __GR_BUF_MGR_H__ diff --git a/msm8909/gralloc/gr_device_impl.cpp b/msm8909/gralloc/gr_device_impl.cpp new file mode 100644 index 00000000..7a3c16db --- /dev/null +++ b/msm8909/gralloc/gr_device_impl.cpp @@ -0,0 +1,530 @@ +/* + * Copyright (c) 2016-2017, 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 <log/log.h> +#include <sync/sync.h> +#include <algorithm> +#include <sstream> +#include <string> + +#include "gr_device_impl.h" +#include "gr_buf_descriptor.h" +#include "gralloc_priv.h" +#include "qd_utils.h" +#include "qdMetaData.h" +#include "gr_utils.h" + +int gralloc_device_open(const struct hw_module_t *module, const char *name, hw_device_t **device); + +int gralloc_device_close(struct hw_device_t *device); + +static struct hw_module_methods_t gralloc_module_methods = {.open = gralloc_device_open}; + +struct gralloc_module_t HAL_MODULE_INFO_SYM = { + .common = { + .tag = HARDWARE_MODULE_TAG, + .module_api_version = GRALLOC_MODULE_API_VERSION_1_0, + .hal_api_version = HARDWARE_HAL_API_VERSION, + .id = GRALLOC_HARDWARE_MODULE_ID, + .name = "Graphics Memory Module", + .author = "Code Aurora Forum", + .methods = &gralloc_module_methods, + .dso = 0, + .reserved = {0}, + }, +}; + +int gralloc_device_open(const struct hw_module_t *module, const char *name, hw_device_t **device) { + int status = -EINVAL; + if (!strcmp(name, GRALLOC_HARDWARE_MODULE_ID)) { + gralloc1::GrallocImpl * /*gralloc1_device_t*/ dev = gralloc1::GrallocImpl::GetInstance(module); + *device = reinterpret_cast<hw_device_t *>(dev); + if (dev) { + status = 0; + } else { + ALOGE("Fatal error opening gralloc1 device"); + } + } + return status; +} + +namespace gralloc1 { + +GrallocImpl::GrallocImpl(const hw_module_t *module) { + common.tag = HARDWARE_DEVICE_TAG; + common.version = GRALLOC_MODULE_API_VERSION_1_0; + common.module = const_cast<hw_module_t *>(module); + common.close = CloseDevice; + getFunction = GetFunction; + getCapabilities = GetCapabilities; + + initalized_ = Init(); +} + +bool GrallocImpl::Init() { + buf_mgr_ = BufferManager::GetInstance(); + return buf_mgr_ != nullptr; +} + +GrallocImpl::~GrallocImpl() { +} + +int GrallocImpl::CloseDevice(hw_device_t *device __unused) { + // No-op since the gralloc device is a singleton + return 0; +} + +void GrallocImpl::GetCapabilities(struct gralloc1_device *device, uint32_t *out_count, + int32_t /*gralloc1_capability_t*/ *out_capabilities) { + if (device != nullptr) { + if (out_capabilities != nullptr && *out_count >= 3) { + out_capabilities[0] = GRALLOC1_CAPABILITY_TEST_ALLOCATE; + out_capabilities[1] = GRALLOC1_CAPABILITY_LAYERED_BUFFERS; + out_capabilities[2] = GRALLOC1_CAPABILITY_RELEASE_IMPLY_DELETE; + } + *out_count = 3; + } + return; +} + +gralloc1_function_pointer_t GrallocImpl::GetFunction(gralloc1_device_t *device, int32_t function) { + if (!device) { + return NULL; + } + + switch (function) { + case GRALLOC1_FUNCTION_DUMP: + return reinterpret_cast<gralloc1_function_pointer_t>(Dump); + case GRALLOC1_FUNCTION_CREATE_DESCRIPTOR: + return reinterpret_cast<gralloc1_function_pointer_t>(CreateBufferDescriptor); + case GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR: + return reinterpret_cast<gralloc1_function_pointer_t>(DestroyBufferDescriptor); + case GRALLOC1_FUNCTION_SET_CONSUMER_USAGE: + return reinterpret_cast<gralloc1_function_pointer_t>(SetConsumerUsage); + case GRALLOC1_FUNCTION_SET_DIMENSIONS: + return reinterpret_cast<gralloc1_function_pointer_t>(SetBufferDimensions); + case GRALLOC1_FUNCTION_SET_FORMAT: + return reinterpret_cast<gralloc1_function_pointer_t>(SetColorFormat); + case GRALLOC1_FUNCTION_SET_LAYER_COUNT: + return reinterpret_cast<gralloc1_function_pointer_t>(SetLayerCount); + case GRALLOC1_FUNCTION_SET_PRODUCER_USAGE: + return reinterpret_cast<gralloc1_function_pointer_t>(SetProducerUsage); + case GRALLOC1_FUNCTION_GET_BACKING_STORE: + return reinterpret_cast<gralloc1_function_pointer_t>(GetBackingStore); + case GRALLOC1_FUNCTION_GET_CONSUMER_USAGE: + return reinterpret_cast<gralloc1_function_pointer_t>(GetConsumerUsage); + case GRALLOC1_FUNCTION_GET_DIMENSIONS: + return reinterpret_cast<gralloc1_function_pointer_t>(GetBufferDimensions); + case GRALLOC1_FUNCTION_GET_FORMAT: + return reinterpret_cast<gralloc1_function_pointer_t>(GetColorFormat); + case GRALLOC1_FUNCTION_GET_LAYER_COUNT: + return reinterpret_cast<gralloc1_function_pointer_t>(GetLayerCount); + case GRALLOC1_FUNCTION_GET_PRODUCER_USAGE: + return reinterpret_cast<gralloc1_function_pointer_t>(GetProducerUsage); + case GRALLOC1_FUNCTION_GET_STRIDE: + return reinterpret_cast<gralloc1_function_pointer_t>(GetBufferStride); + case GRALLOC1_FUNCTION_ALLOCATE: + return reinterpret_cast<gralloc1_function_pointer_t>(AllocateBuffers); + case GRALLOC1_FUNCTION_RETAIN: + return reinterpret_cast<gralloc1_function_pointer_t>(RetainBuffer); + case GRALLOC1_FUNCTION_RELEASE: + return reinterpret_cast<gralloc1_function_pointer_t>(ReleaseBuffer); + case GRALLOC1_FUNCTION_GET_NUM_FLEX_PLANES: + return reinterpret_cast<gralloc1_function_pointer_t>(GetNumFlexPlanes); + case GRALLOC1_FUNCTION_LOCK: + return reinterpret_cast<gralloc1_function_pointer_t>(LockBuffer); + case GRALLOC1_FUNCTION_LOCK_FLEX: + return reinterpret_cast<gralloc1_function_pointer_t>(LockFlex); + case GRALLOC1_FUNCTION_UNLOCK: + return reinterpret_cast<gralloc1_function_pointer_t>(UnlockBuffer); + case GRALLOC1_FUNCTION_PERFORM: + return reinterpret_cast<gralloc1_function_pointer_t>(Gralloc1Perform); + default: + ALOGE("%s:Gralloc Error. Client Requested for unsupported function", __FUNCTION__); + return NULL; + } + + return NULL; +} + +gralloc1_error_t GrallocImpl::Dump(gralloc1_device_t *device, uint32_t *out_size, + char *out_buffer) { + if (!device) { + ALOGE("Gralloc Error : device=%p", (void *)device); + return GRALLOC1_ERROR_BAD_DESCRIPTOR; + } + const size_t max_dump_size = 8192; + if (out_buffer == nullptr) { + *out_size = max_dump_size; + } else { + std::ostringstream os; + os << "-------------------------------" << std::endl; + os << "QTI gralloc dump:" << std::endl; + os << "-------------------------------" << std::endl; + GrallocImpl const *dev = GRALLOC_IMPL(device); + dev->buf_mgr_->Dump(&os); + os << "-------------------------------" << std::endl; + auto copied = os.str().copy(out_buffer, std::min(os.str().size(), max_dump_size), 0); + *out_size = UINT(copied); + } + + return GRALLOC1_ERROR_NONE; +} + +gralloc1_error_t GrallocImpl::CheckDeviceAndHandle(gralloc1_device_t *device, + buffer_handle_t buffer) { + const private_handle_t *hnd = PRIV_HANDLE_CONST(buffer); + if (!device || (private_handle_t::validate(hnd) != 0)) { + ALOGE("Gralloc Error : device= %p, buffer-handle=%p", (void *)device, (void *)buffer); + return GRALLOC1_ERROR_BAD_HANDLE; + } + + return GRALLOC1_ERROR_NONE; +} + +gralloc1_error_t GrallocImpl::CreateBufferDescriptor(gralloc1_device_t *device, + gralloc1_buffer_descriptor_t *out_descriptor) { + if (!device) { + return GRALLOC1_ERROR_BAD_DESCRIPTOR; + } + GrallocImpl const *dev = GRALLOC_IMPL(device); + return dev->buf_mgr_->CreateBufferDescriptor(out_descriptor); +} + +gralloc1_error_t GrallocImpl::DestroyBufferDescriptor(gralloc1_device_t *device, + gralloc1_buffer_descriptor_t descriptor) { + if (!device) { + return GRALLOC1_ERROR_BAD_DESCRIPTOR; + } + GrallocImpl const *dev = GRALLOC_IMPL(device); + return dev->buf_mgr_->DestroyBufferDescriptor(descriptor); +} + +gralloc1_error_t GrallocImpl::SetConsumerUsage(gralloc1_device_t *device, + gralloc1_buffer_descriptor_t descriptor, + gralloc1_consumer_usage_t usage) { + if (!device) { + return GRALLOC1_ERROR_BAD_DESCRIPTOR; + } else { + GrallocImpl const *dev = GRALLOC_IMPL(device); + return dev->buf_mgr_->CallBufferDescriptorFunction(descriptor, + &BufferDescriptor::SetConsumerUsage, usage); + } +} + +gralloc1_error_t GrallocImpl::SetBufferDimensions(gralloc1_device_t *device, + gralloc1_buffer_descriptor_t descriptor, + uint32_t width, uint32_t height) { + if (!device) { + return GRALLOC1_ERROR_BAD_DESCRIPTOR; + } else { + GrallocImpl const *dev = GRALLOC_IMPL(device); + return dev->buf_mgr_->CallBufferDescriptorFunction(descriptor, + &BufferDescriptor::SetDimensions, + INT(width), INT(height)); + } +} + +gralloc1_error_t GrallocImpl::SetColorFormat(gralloc1_device_t *device, + gralloc1_buffer_descriptor_t descriptor, + int32_t format) { + if (!device) { + return GRALLOC1_ERROR_BAD_DESCRIPTOR; + } else { + GrallocImpl const *dev = GRALLOC_IMPL(device); + return dev->buf_mgr_->CallBufferDescriptorFunction(descriptor, + &BufferDescriptor::SetColorFormat, format); + } +} + +gralloc1_error_t GrallocImpl::SetLayerCount(gralloc1_device_t *device, + gralloc1_buffer_descriptor_t descriptor, + uint32_t layer_count) { + if (!device) { + return GRALLOC1_ERROR_BAD_DESCRIPTOR; + } else { + GrallocImpl const *dev = GRALLOC_IMPL(device); + return dev->buf_mgr_->CallBufferDescriptorFunction(descriptor, + &BufferDescriptor::SetLayerCount, + layer_count); + } +} + +gralloc1_error_t GrallocImpl::SetProducerUsage(gralloc1_device_t *device, + gralloc1_buffer_descriptor_t descriptor, + gralloc1_producer_usage_t usage) { + if (!device) { + return GRALLOC1_ERROR_BAD_DESCRIPTOR; + } else { + GrallocImpl const *dev = GRALLOC_IMPL(device); + return dev->buf_mgr_->CallBufferDescriptorFunction(descriptor, + &BufferDescriptor::SetProducerUsage, usage); + } +} + +gralloc1_error_t GrallocImpl::GetBackingStore(gralloc1_device_t *device, buffer_handle_t buffer, + gralloc1_backing_store_t *out_backstore) { + if (!device || !buffer) { + return GRALLOC1_ERROR_BAD_HANDLE; + } + + *out_backstore = + static_cast<gralloc1_backing_store_t>(PRIV_HANDLE_CONST(buffer)->GetBackingstore()); + + return GRALLOC1_ERROR_NONE; +} + +gralloc1_error_t GrallocImpl::GetConsumerUsage(gralloc1_device_t *device, buffer_handle_t buffer, + gralloc1_consumer_usage_t *outUsage) { + gralloc1_error_t status = CheckDeviceAndHandle(device, buffer); + if (status == GRALLOC1_ERROR_NONE) { + *outUsage = PRIV_HANDLE_CONST(buffer)->GetConsumerUsage(); + } + + return status; +} + +gralloc1_error_t GrallocImpl::GetBufferDimensions(gralloc1_device_t *device, buffer_handle_t buffer, + uint32_t *outWidth, uint32_t *outHeight) { + gralloc1_error_t status = CheckDeviceAndHandle(device, buffer); + if (status == GRALLOC1_ERROR_NONE) { + const private_handle_t *hnd = PRIV_HANDLE_CONST(buffer); + *outWidth = UINT(hnd->GetUnalignedWidth()); + *outHeight = UINT(hnd->GetUnalignedHeight()); + } + + return status; +} + +gralloc1_error_t GrallocImpl::GetColorFormat(gralloc1_device_t *device, buffer_handle_t buffer, + int32_t *outFormat) { + gralloc1_error_t status = CheckDeviceAndHandle(device, buffer); + if (status == GRALLOC1_ERROR_NONE) { + *outFormat = PRIV_HANDLE_CONST(buffer)->GetColorFormat(); + } + + return status; +} + +gralloc1_error_t GrallocImpl::GetLayerCount(gralloc1_device_t *device, buffer_handle_t buffer, + uint32_t *outLayerCount) { + gralloc1_error_t status = CheckDeviceAndHandle(device, buffer); + if (status == GRALLOC1_ERROR_NONE) { + *outLayerCount = PRIV_HANDLE_CONST(buffer)->GetLayerCount(); + } + + return status; +} + +gralloc1_error_t GrallocImpl::GetProducerUsage(gralloc1_device_t *device, buffer_handle_t buffer, + gralloc1_producer_usage_t *outUsage) { + if (!outUsage) { + return GRALLOC1_ERROR_BAD_VALUE; + } + + gralloc1_error_t status = CheckDeviceAndHandle(device, buffer); + if (status == GRALLOC1_ERROR_NONE) { + const private_handle_t *hnd = PRIV_HANDLE_CONST(buffer); + *outUsage = hnd->GetProducerUsage(); + } + + return status; +} + +gralloc1_error_t GrallocImpl::GetBufferStride(gralloc1_device_t *device, buffer_handle_t buffer, + uint32_t *outStride) { + if (!outStride) { + return GRALLOC1_ERROR_BAD_VALUE; + } + + gralloc1_error_t status = CheckDeviceAndHandle(device, buffer); + if (status == GRALLOC1_ERROR_NONE) { + *outStride = UINT(PRIV_HANDLE_CONST(buffer)->GetStride()); + } + + return status; +} + +gralloc1_error_t GrallocImpl::AllocateBuffers(gralloc1_device_t *device, uint32_t num_descriptors, + const gralloc1_buffer_descriptor_t *descriptors, + buffer_handle_t *out_buffers) { + if (!num_descriptors || !descriptors) { + return GRALLOC1_ERROR_BAD_DESCRIPTOR; + } + + if (!device) { + return GRALLOC1_ERROR_BAD_VALUE; + } + + GrallocImpl const *dev = GRALLOC_IMPL(device); + gralloc1_error_t status = dev->buf_mgr_->AllocateBuffers(num_descriptors, descriptors, + out_buffers); + + return status; +} + +gralloc1_error_t GrallocImpl::RetainBuffer(gralloc1_device_t *device, buffer_handle_t buffer) { + gralloc1_error_t status = CheckDeviceAndHandle(device, buffer); + if (status == GRALLOC1_ERROR_NONE) { + const private_handle_t *hnd = PRIV_HANDLE_CONST(buffer); + GrallocImpl const *dev = GRALLOC_IMPL(device); + status = dev->buf_mgr_->RetainBuffer(hnd); + } + + return status; +} + +gralloc1_error_t GrallocImpl::ReleaseBuffer(gralloc1_device_t *device, buffer_handle_t buffer) { + if (!device || !buffer) { + return GRALLOC1_ERROR_BAD_DESCRIPTOR; + } + + const private_handle_t *hnd = PRIV_HANDLE_CONST(buffer); + GrallocImpl const *dev = GRALLOC_IMPL(device); + return dev->buf_mgr_->ReleaseBuffer(hnd); +} + +gralloc1_error_t GrallocImpl::GetNumFlexPlanes(gralloc1_device_t *device, buffer_handle_t buffer, + uint32_t *out_num_planes) { + if (!out_num_planes) { + return GRALLOC1_ERROR_BAD_VALUE; + } + + gralloc1_error_t status = CheckDeviceAndHandle(device, buffer); + if (status == GRALLOC1_ERROR_NONE) { + GrallocImpl const *dev = GRALLOC_IMPL(device); + const private_handle_t *hnd = PRIV_HANDLE_CONST(buffer); + status = dev->buf_mgr_->GetNumFlexPlanes(hnd, out_num_planes); + } + return status; +} + +static inline void CloseFdIfValid(int fd) { + if (fd > 0) { + close(fd); + } +} + +gralloc1_error_t GrallocImpl::LockBuffer(gralloc1_device_t *device, buffer_handle_t buffer, + gralloc1_producer_usage_t prod_usage, + gralloc1_consumer_usage_t cons_usage, + const gralloc1_rect_t *region, void **out_data, + int32_t acquire_fence) { + gralloc1_error_t status = CheckDeviceAndHandle(device, buffer); + if (status != GRALLOC1_ERROR_NONE || !out_data || + !region) { // currently we ignore the region/rect client wants to lock + CloseFdIfValid(acquire_fence); + return status; + } + + if (acquire_fence > 0) { + int error = sync_wait(acquire_fence, 1000); + CloseFdIfValid(acquire_fence); + if (error < 0) { + ALOGE("%s: sync_wait timedout! error = %s", __FUNCTION__, strerror(errno)); + return GRALLOC1_ERROR_UNDEFINED; + } + } + + const private_handle_t *hnd = PRIV_HANDLE_CONST(buffer); + GrallocImpl const *dev = GRALLOC_IMPL(device); + + // Either producer usage or consumer usage must be *_USAGE_NONE + if ((prod_usage != GRALLOC1_PRODUCER_USAGE_NONE) && + (cons_usage != GRALLOC1_CONSUMER_USAGE_NONE)) { + // Current gralloc1 clients do not satisfy this restriction. + // See b/33588773 for details + // return GRALLOC1_ERROR_BAD_VALUE; + } + + // TODO(user): Need to check if buffer was allocated with the same flags + status = dev->buf_mgr_->LockBuffer(hnd, prod_usage, cons_usage); + *out_data = reinterpret_cast<void *>(hnd->base); + + return status; +} + +gralloc1_error_t GrallocImpl::LockFlex(gralloc1_device_t *device, buffer_handle_t buffer, + gralloc1_producer_usage_t prod_usage, + gralloc1_consumer_usage_t cons_usage, + const gralloc1_rect_t *region, + struct android_flex_layout *out_flex_layout, + int32_t acquire_fence) { + if (!out_flex_layout) { + CloseFdIfValid(acquire_fence); + return GRALLOC1_ERROR_BAD_VALUE; + } + + void *out_data {}; + gralloc1_error_t status = GrallocImpl::LockBuffer(device, buffer, prod_usage, cons_usage, region, + &out_data, acquire_fence); + if (status != GRALLOC1_ERROR_NONE) { + return status; + } + + GrallocImpl const *dev = GRALLOC_IMPL(device); + const private_handle_t *hnd = PRIV_HANDLE_CONST(buffer); + dev->buf_mgr_->GetFlexLayout(hnd, out_flex_layout); + return status; +} + +gralloc1_error_t GrallocImpl::UnlockBuffer(gralloc1_device_t *device, buffer_handle_t buffer, + int32_t *release_fence) { + gralloc1_error_t status = CheckDeviceAndHandle(device, buffer); + if (status != GRALLOC1_ERROR_NONE) { + return status; + } + + if (!release_fence) { + return GRALLOC1_ERROR_BAD_VALUE; + } + + const private_handle_t *hnd = PRIV_HANDLE_CONST(buffer); + GrallocImpl const *dev = GRALLOC_IMPL(device); + + *release_fence = -1; + + return dev->buf_mgr_->UnlockBuffer(hnd); +} + +gralloc1_error_t GrallocImpl::Gralloc1Perform(gralloc1_device_t *device, int operation, ...) { + if (!device) { + return GRALLOC1_ERROR_BAD_VALUE; + } + + va_list args; + va_start(args, operation); + GrallocImpl const *dev = GRALLOC_IMPL(device); + gralloc1_error_t err = dev->buf_mgr_->Perform(operation, args); + va_end(args); + + return err; +} + +} // namespace gralloc1 diff --git a/msm8909/gralloc/gr_device_impl.h b/msm8909/gralloc/gr_device_impl.h new file mode 100644 index 00000000..55ce44b3 --- /dev/null +++ b/msm8909/gralloc/gr_device_impl.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2016-2017, 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 __GR_DEVICE_IMPL_H__ +#define __GR_DEVICE_IMPL_H__ + +#include <hardware/hardware.h> +#include <hardware/gralloc1.h> +#include "gr_buf_mgr.h" + +struct private_module_t { + hw_module_t base; +}; + +#define GRALLOC_IMPL(exp) reinterpret_cast<GrallocImpl const *>(exp) + +namespace gralloc1 { + +class GrallocImpl : public gralloc1_device_t { + public: + static int CloseDevice(hw_device_t *device); + static void GetCapabilities(struct gralloc1_device *device, uint32_t *out_count, + int32_t * /*gralloc1_capability_t*/ out_capabilities); + static gralloc1_function_pointer_t GetFunction( + struct gralloc1_device *device, int32_t /*gralloc1_function_descriptor_t*/ descriptor); + + static GrallocImpl* GetInstance(const struct hw_module_t *module) { + static GrallocImpl *instance = new GrallocImpl(module); + if (instance->IsInitialized()) { + return instance; + } else { + return nullptr; + } + } + + private: + static inline gralloc1_error_t Dump(gralloc1_device_t *device, uint32_t *out_size, + char *out_buffer); + static inline gralloc1_error_t CheckDeviceAndHandle(gralloc1_device_t *device, + buffer_handle_t buffer); + static gralloc1_error_t CreateBufferDescriptor(gralloc1_device_t *device, + gralloc1_buffer_descriptor_t *out_descriptor); + static gralloc1_error_t DestroyBufferDescriptor(gralloc1_device_t *device, + gralloc1_buffer_descriptor_t descriptor); + static gralloc1_error_t SetConsumerUsage(gralloc1_device_t *device, + gralloc1_buffer_descriptor_t descriptor, + gralloc1_consumer_usage_t usage); + static gralloc1_error_t SetBufferDimensions(gralloc1_device_t *device, + gralloc1_buffer_descriptor_t descriptor, + uint32_t width, uint32_t height); + static gralloc1_error_t SetColorFormat(gralloc1_device_t *device, + gralloc1_buffer_descriptor_t descriptor, int32_t format); + static gralloc1_error_t SetLayerCount(gralloc1_device_t *device, + gralloc1_buffer_descriptor_t descriptor, + uint32_t layer_count); + static gralloc1_error_t SetProducerUsage(gralloc1_device_t *device, + gralloc1_buffer_descriptor_t descriptor, + gralloc1_producer_usage_t usage); + static gralloc1_error_t GetBackingStore(gralloc1_device_t *device, buffer_handle_t buffer, + gralloc1_backing_store_t *out_store); + static gralloc1_error_t GetConsumerUsage(gralloc1_device_t *device, buffer_handle_t buffer, + gralloc1_consumer_usage_t *out_usage); + static gralloc1_error_t GetBufferDimensions(gralloc1_device_t *device, buffer_handle_t buffer, + uint32_t *out_width, uint32_t *out_height); + static gralloc1_error_t GetColorFormat(gralloc1_device_t *device, buffer_handle_t descriptor, + int32_t *outFormat); + static gralloc1_error_t GetLayerCount(gralloc1_device_t *device, buffer_handle_t buffer, + uint32_t *out_layer_count); + static gralloc1_error_t GetProducerUsage(gralloc1_device_t *device, buffer_handle_t buffer, + gralloc1_producer_usage_t *out_usage); + static gralloc1_error_t GetBufferStride(gralloc1_device_t *device, buffer_handle_t buffer, + uint32_t *out_stride); + static gralloc1_error_t AllocateBuffers(gralloc1_device_t *device, uint32_t num_dptors, + const gralloc1_buffer_descriptor_t *descriptors, + buffer_handle_t *out_buffers); + static gralloc1_error_t RetainBuffer(gralloc1_device_t *device, buffer_handle_t buffer); + static gralloc1_error_t ReleaseBuffer(gralloc1_device_t *device, buffer_handle_t buffer); + static gralloc1_error_t GetNumFlexPlanes(gralloc1_device_t *device, buffer_handle_t buffer, + uint32_t *out_num_planes); + static gralloc1_error_t LockBuffer(gralloc1_device_t *device, buffer_handle_t buffer, + gralloc1_producer_usage_t prod_usage, + gralloc1_consumer_usage_t cons_usage, + const gralloc1_rect_t *region, void **out_data, + int32_t acquire_fence); + static gralloc1_error_t LockFlex(gralloc1_device_t *device, buffer_handle_t buffer, + gralloc1_producer_usage_t prod_usage, + gralloc1_consumer_usage_t cons_usage, + const gralloc1_rect_t *region, + struct android_flex_layout *out_flex_layout, + int32_t acquire_fence); + + static gralloc1_error_t UnlockBuffer(gralloc1_device_t *device, buffer_handle_t buffer, + int32_t *release_fence); + static gralloc1_error_t Gralloc1Perform(gralloc1_device_t *device, int operation, ...); + + explicit GrallocImpl(const hw_module_t *module); + ~GrallocImpl(); + bool Init(); + bool IsInitialized() const { return initalized_; } + + BufferManager *buf_mgr_ = NULL; + bool initalized_ = false; +}; + +} // namespace gralloc1 + +#endif // __GR_DEVICE_IMPL_H__ diff --git a/msm8909/gralloc/gr_ion_alloc.cpp b/msm8909/gralloc/gr_ion_alloc.cpp new file mode 100644 index 00000000..680a516a --- /dev/null +++ b/msm8909/gralloc/gr_ion_alloc.cpp @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define DEBUG 0 +#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL) +#include <string.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <stdlib.h> +#include <fcntl.h> +#include <log/log.h> +#include <errno.h> +#include <utils/Trace.h> + +#include "gralloc_priv.h" +#include "gr_utils.h" +#include "gr_ion_alloc.h" + +namespace gralloc1 { + +bool IonAlloc::Init() { + if (ion_dev_fd_ == FD_INIT) { + ion_dev_fd_ = open(kIonDevice, O_RDONLY); + } + + if (ion_dev_fd_ < 0) { + ALOGE("%s: Failed to open ion device - %s", __FUNCTION__, strerror(errno)); + ion_dev_fd_ = FD_INIT; + return false; + } + + return true; +} + +void IonAlloc::CloseIonDevice() { + if (ion_dev_fd_ > FD_INIT) { + close(ion_dev_fd_); + } + + ion_dev_fd_ = FD_INIT; +} + +int IonAlloc::AllocBuffer(AllocData *data) { + ATRACE_CALL(); + int err = 0; + struct ion_handle_data handle_data; + struct ion_fd_data fd_data; + struct ion_allocation_data ion_alloc_data; + + ion_alloc_data.len = data->size; + ion_alloc_data.align = data->align; + ion_alloc_data.heap_id_mask = data->heap_id; + ion_alloc_data.flags = data->flags; + ion_alloc_data.flags |= data->uncached ? 0 : ION_FLAG_CACHED; + + if (ioctl(ion_dev_fd_, INT(ION_IOC_ALLOC), &ion_alloc_data)) { + err = -errno; + ALOGE("ION_IOC_ALLOC failed with error - %s", strerror(errno)); + return err; + } + + fd_data.handle = ion_alloc_data.handle; + handle_data.handle = ion_alloc_data.handle; + if (ioctl(ion_dev_fd_, INT(ION_IOC_MAP), &fd_data)) { + err = -errno; + ALOGE("%s: ION_IOC_MAP failed with error - %s", __FUNCTION__, strerror(errno)); + ioctl(ion_dev_fd_, INT(ION_IOC_FREE), &handle_data); + return err; + } + + data->fd = fd_data.fd; + data->ion_handle = handle_data.handle; + ALOGD_IF(DEBUG, "ion: Allocated buffer size:%zu fd:%d handle:0x%x", + ion_alloc_data.len, data->fd, data->ion_handle); + + return 0; +} + +int IonAlloc::FreeBuffer(void *base, unsigned int size, unsigned int offset, int fd, + int ion_handle) { + ATRACE_CALL(); + int err = 0; + ALOGD_IF(DEBUG, "ion: Freeing buffer base:%p size:%u fd:%d handle:0x%x", base, size, fd, + ion_handle); + + if (base) { + err = UnmapBuffer(base, size, offset); + } + + if (ion_handle > 0) { + struct ion_handle_data handle_data; + handle_data.handle = ion_handle; + ioctl(ion_dev_fd_, INT(ION_IOC_FREE), &handle_data); + } + close(fd); + return err; +} + +int IonAlloc::MapBuffer(void **base, unsigned int size, unsigned int offset, int fd) { + ATRACE_CALL(); + int err = 0; + void *addr = 0; + + // It is a (quirky) requirement of ION to have opened the + // ion fd in the process that is doing the mapping + addr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + *base = addr; + if (addr == MAP_FAILED) { + err = -errno; + ALOGE("ion: Failed to map memory in the client: %s", strerror(errno)); + } else { + ALOGD_IF(DEBUG, "ion: Mapped buffer base:%p size:%u offset:%u fd:%d", addr, size, offset, fd); + } + + return err; +} + +int IonAlloc::ImportBuffer(int fd) { + struct ion_fd_data fd_data; + int err = 0; + fd_data.fd = fd; + if (ioctl(ion_dev_fd_, INT(ION_IOC_IMPORT), &fd_data)) { + err = -errno; + ALOGE("%s: ION_IOC_IMPORT failed with error - %s", __FUNCTION__, strerror(errno)); + return err; + } + return fd_data.handle; +} + +int IonAlloc::UnmapBuffer(void *base, unsigned int size, unsigned int /*offset*/) { + ATRACE_CALL(); + ALOGD_IF(DEBUG, "ion: Unmapping buffer base:%p size:%u", base, size); + + int err = 0; + if (munmap(base, size)) { + err = -errno; + ALOGE("ion: Failed to unmap memory at %p : %s", base, strerror(errno)); + } + + return err; +} + +int IonAlloc::CleanBuffer(void *base, unsigned int size, unsigned int offset, int handle, int op) { + ATRACE_CALL(); + ATRACE_INT("operation id", op); + struct ion_flush_data flush_data; + int err = 0; + + flush_data.handle = handle; + flush_data.vaddr = base; + // offset and length are unsigned int + flush_data.offset = offset; + flush_data.length = size; + + struct ion_custom_data d; + switch (op) { + case CACHE_CLEAN: + d.cmd = ION_IOC_CLEAN_CACHES; + break; + case CACHE_INVALIDATE: + d.cmd = ION_IOC_INV_CACHES; + break; + case CACHE_CLEAN_AND_INVALIDATE: + default: + d.cmd = ION_IOC_CLEAN_INV_CACHES; + } + + d.arg = (unsigned long)(&flush_data); // NOLINT + if (ioctl(ion_dev_fd_, INT(ION_IOC_CUSTOM), &d)) { + err = -errno; + ALOGE("%s: ION_IOC_CLEAN_INV_CACHES failed with error - %s", __FUNCTION__, strerror(errno)); + return err; + } + + return 0; +} + +} // namespace gralloc1 diff --git a/msm8909/libhdmi/hdmi_stub.cpp b/msm8909/gralloc/gr_ion_alloc.h index 9ba9b602..b25f509b 100644 --- a/msm8909/libhdmi/hdmi_stub.cpp +++ b/msm8909/gralloc/gr_ion_alloc.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. - * + * Copyright (c) 2011-2017, 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: @@ -27,59 +27,58 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "hwc_utils.h" -#include "hdmi.h" +#ifndef __GR_ION_ALLOC_H__ +#define __GR_ION_ALLOC_H__ -namespace qhwc { +#include <linux/msm_ion.h> -HDMIDisplay::HDMIDisplay() : mFd(-1), mCurrentMode(-1), mModeCount(0), - mPrimaryWidth(0), mPrimaryHeight(0), mUnderscanSupported(false) { - ALOGV("%s stub", __FUNCTION__); -} +#define FD_INIT -1 -HDMIDisplay::~HDMIDisplay() { - ALOGV("%s stub", __FUNCTION__); -} +namespace gralloc1 { -void HDMIDisplay::setHPD(uint32_t value) { - ALOGV("%s stub", __FUNCTION__); - (void) value; -} - -bool HDMIDisplay::isHDMIPrimaryDisplay() { - ALOGV("%s stub", __FUNCTION__); - return false; -} +enum { + CACHE_CLEAN = 0x1, + CACHE_INVALIDATE, + CACHE_CLEAN_AND_INVALIDATE, +}; -int HDMIDisplay::getConnectedState() { - ALOGV("%s stub", __FUNCTION__); - return -1; -} +struct AllocData { + void *base = NULL; + int fd = -1; + int ion_handle = -1; + unsigned int offset = 0; + unsigned int size = 0; + unsigned int align = 1; + uintptr_t handle = 0; + bool uncached = false; + unsigned int flags = 0x0; + unsigned int heap_id = 0x0; + unsigned int alloc_type = 0x0; +}; -void HDMIDisplay::activateDisplay() { - ALOGV("%s stub", __FUNCTION__); -} +class IonAlloc { + public: + IonAlloc() { ion_dev_fd_ = FD_INIT; } -void HDMIDisplay::getAttributes(uint32_t& width, uint32_t& height) { - ALOGV("%s stub", __FUNCTION__); - width = height = 0; -} + ~IonAlloc() { CloseIonDevice(); } -int HDMIDisplay::configure() { - ALOGV("%s stub", __FUNCTION__); - return -1; -} + bool Init(); + int AllocBuffer(AllocData *data); + int FreeBuffer(void *base, unsigned int size, unsigned int offset, int fd, int ion_handle); + int MapBuffer(void **base, unsigned int size, unsigned int offset, int fd); + int ImportBuffer(int fd); + int UnmapBuffer(void *base, unsigned int size, unsigned int offset); + int CleanBuffer(void *base, unsigned int size, unsigned int offset, int handle, int op); -int HDMIDisplay::teardown() { - ALOGV("%s stub", __FUNCTION__); - return 0; -} + private: + const char *kIonDevice = "/dev/ion"; -void HDMIDisplay::setPrimaryAttributes(uint32_t primaryWidth, - uint32_t primaryHeight) { - ALOGV("%s stub", __FUNCTION__); - (void) primaryWidth; - (void) primaryHeight; -} + int OpenIonDevice(); + void CloseIonDevice(); + int ion_dev_fd_; }; + +} // namespace gralloc1 + +#endif // __GR_ION_ALLOC_H__ diff --git a/msm8909/gralloc/gr_priv_handle.h b/msm8909/gralloc/gr_priv_handle.h new file mode 100644 index 00000000..8c4797a1 --- /dev/null +++ b/msm8909/gralloc/gr_priv_handle.h @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. + * Not a Contribution + * + * 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. + */ + +#ifndef __GR_PRIV_HANDLE_H__ +#define __GR_PRIV_HANDLE_H__ + +#include <errno.h> +#include <log/log.h> +#include <hardware/gralloc1.h> +#include <hardware/gralloc.h> +#ifdef __cplusplus +#include <cinttypes> +#endif + +#define GRALLOC1_FUNCTION_PERFORM 0x00001000 + +#define DBG_HANDLE false + +typedef gralloc1_error_t (*GRALLOC1_PFN_PERFORM)(gralloc1_device_t *device, int operation, ...); + +#define PRIV_HANDLE_CONST(exp) static_cast<const private_handle_t *>(exp) + +#ifdef __cplusplus +struct private_handle_t : public native_handle_t { +#else +struct private_handle_t { + native_handle_t nativeHandle; +#endif + enum { + PRIV_FLAGS_FRAMEBUFFER = 0x00000001, + PRIV_FLAGS_USES_ION = 0x00000008, + PRIV_FLAGS_NEEDS_FLUSH = 0x00000020, + PRIV_FLAGS_INTERNAL_ONLY = 0x00000040, + PRIV_FLAGS_NON_CPU_WRITER = 0x00000080, + PRIV_FLAGS_CACHED = 0x00000200, + PRIV_FLAGS_SECURE_BUFFER = 0x00000400, + PRIV_FLAGS_EXTERNAL_ONLY = 0x00002000, + PRIV_FLAGS_PROTECTED_BUFFER = 0x00004000, + PRIV_FLAGS_VIDEO_ENCODER = 0x00010000, + PRIV_FLAGS_CAMERA_WRITE = 0x00020000, + PRIV_FLAGS_CAMERA_READ = 0x00040000, + PRIV_FLAGS_HW_COMPOSER = 0x00080000, + PRIV_FLAGS_HW_TEXTURE = 0x00100000, + PRIV_FLAGS_ITU_R_601 = 0x00200000, // Unused from display + PRIV_FLAGS_ITU_R_601_FR = 0x00400000, // Unused from display + PRIV_FLAGS_ITU_R_709 = 0x00800000, // Unused from display + PRIV_FLAGS_SECURE_DISPLAY = 0x01000000, + PRIV_FLAGS_TILE_RENDERED = 0x02000000, + PRIV_FLAGS_CPU_RENDERED = 0x04000000, + PRIV_FLAGS_UBWC_ALIGNED = 0x08000000, + PRIV_FLAGS_DISP_CONSUMER = 0x10000000, + PRIV_FLAGS_CLIENT_ALLOCATED = 0x20000000, // Ion buffer allocated outside of gralloc + }; + + // file-descriptors dup'd over IPC + int fd; + int fd_metadata; + + // values sent over IPC + int magic; + int flags; + int width; // holds width of the actual buffer allocated + int height; // holds height of the actual buffer allocated + int unaligned_width; // holds width client asked to allocate + int unaligned_height; // holds height client asked to allocate + int format; + int buffer_type; + unsigned int size; + unsigned int offset; + unsigned int offset_metadata; + uint64_t base __attribute__((aligned(8))); + uint64_t base_metadata __attribute__((aligned(8))); + uint64_t gpuaddr __attribute__((aligned(8))); + uint64_t id __attribute__((aligned(8))); + gralloc1_producer_usage_t producer_usage __attribute__((aligned(8))); + gralloc1_consumer_usage_t consumer_usage __attribute__((aligned(8))); + unsigned int layer_count; +#ifdef __cplusplus + static const int kNumFds = 2; + static const int kMagic = 'gmsm'; + + static inline int NumInts() { + return ((sizeof(private_handle_t) - sizeof(native_handle_t)) / sizeof(int)) + - kNumFds; + } + + private_handle_t(int fd, + int meta_fd, + int flags, + int width, + int height, + int uw, + int uh, + int format, + int buf_type, + unsigned int size, + gralloc1_producer_usage_t prod_usage = GRALLOC1_PRODUCER_USAGE_NONE, + gralloc1_consumer_usage_t cons_usage = GRALLOC1_CONSUMER_USAGE_NONE) + : fd(fd), + fd_metadata(meta_fd), + magic(kMagic), + flags(flags), + width(width), + height(height), + unaligned_width(uw), + unaligned_height(uh), + format(format), + buffer_type(buf_type), + size(size), + offset(0), + offset_metadata(0), + base(0), + base_metadata(0), + gpuaddr(0), + id(0), + producer_usage(prod_usage), + consumer_usage(cons_usage), + layer_count(1) { + version = static_cast<int>(sizeof(native_handle)); + numInts = NumInts(); + numFds = kNumFds; + } + +// Legacy constructor used by some clients + private_handle_t(int fd, unsigned int size, int usage, int buf_type, int format, int w, int h) + : private_handle_t(fd, -1, PRIV_FLAGS_CLIENT_ALLOCATED, w, h, 0, 0, format, buf_type, size, + static_cast<gralloc1_producer_usage_t>(usage), + static_cast<gralloc1_consumer_usage_t>(usage)) { + } + + ~private_handle_t() { + magic = 0; + ALOGE_IF(DBG_HANDLE, "Deleting buffer handle %p", this); + } + + static int validate(const native_handle *h) { + const private_handle_t *hnd = (const private_handle_t *)h; + if (!h || h->version != sizeof(native_handle) || h->numInts != NumInts() || + h->numFds != kNumFds || hnd->magic != kMagic) { + ALOGE( + "Invalid gralloc handle (at %p): ver(%d/%zu) ints(%d/%d) fds(%d/%d) " + "magic(%c%c%c%c/%c%c%c%c)", + h, h ? h->version : -1, sizeof(native_handle), h ? h->numInts : -1, NumInts(), + h ? h->numFds : -1, kNumFds, + hnd ? (((hnd->magic >> 24) & 0xFF) ? ((hnd->magic >> 24) & 0xFF) : '-') : '?', + hnd ? (((hnd->magic >> 16) & 0xFF) ? ((hnd->magic >> 16) & 0xFF) : '-') : '?', + hnd ? (((hnd->magic >> 8) & 0xFF) ? ((hnd->magic >> 8) & 0xFF) : '-') : '?', + hnd ? (((hnd->magic >> 0) & 0xFF) ? ((hnd->magic >> 0) & 0xFF) : '-') : '?', + (kMagic >> 24) & 0xFF, (kMagic >> 16) & 0xFF, (kMagic >> 8) & 0xFF, (kMagic >> 0) & 0xFF); + return -EINVAL; + } + + return 0; + } + static void Dump(const private_handle_t *hnd) { + ALOGD("handle id:%" PRIu64 " wxh:%dx%d uwxuh:%dx%d size: %d fd:%d fd_meta:%d flags:0x%x " + "prod_usage:0x%" PRIx64" cons_usage:0x%" PRIx64 " format:0x%x layer_count: %d", + hnd->id, hnd->width, hnd->height, hnd->unaligned_width, hnd->unaligned_height, hnd->size, + hnd->fd, hnd->fd_metadata, hnd->flags, hnd->producer_usage, hnd->consumer_usage, + hnd->format, hnd->layer_count); + } + + int GetUnalignedWidth() const { return unaligned_width; } + + int GetUnalignedHeight() const { return unaligned_height; } + + int GetColorFormat() const { return format; } + + unsigned int GetLayerCount() const { return layer_count; } + + int GetStride() const { + // In handle we currently store aligned width after allocation. + return width; + } + + gralloc1_consumer_usage_t GetConsumerUsage() const { return consumer_usage; } + + gralloc1_producer_usage_t GetProducerUsage() const { return producer_usage; } + + uint64_t GetBackingstore() const { return id; } +#endif +}; + +#endif // __GR_PRIV_HANDLE_H__ diff --git a/msm8909/gralloc/gr_utils.cpp b/msm8909/gralloc/gr_utils.cpp new file mode 100644 index 00000000..d89b8fe1 --- /dev/null +++ b/msm8909/gralloc/gr_utils.cpp @@ -0,0 +1,854 @@ +/* + * Copyright (c) 2011-2017, 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 <media/msm_media_info.h> +#include <algorithm> + +#include "gr_utils.h" +#include "gr_adreno_info.h" +#include "qdMetaData.h" + +#define ASTC_BLOCK_SIZE 16 + +#ifndef COLOR_FMT_P010_UBWC +#define COLOR_FMT_P010_UBWC 9 +#endif + +namespace gralloc1 { + +bool IsUncompressedRGBFormat(int format) { + switch (format) { + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_RGB_888: + case HAL_PIXEL_FORMAT_RGB_565: + case HAL_PIXEL_FORMAT_BGR_565: + case HAL_PIXEL_FORMAT_BGRA_8888: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: + case HAL_PIXEL_FORMAT_R_8: + case HAL_PIXEL_FORMAT_RG_88: + case HAL_PIXEL_FORMAT_BGRX_8888: + case HAL_PIXEL_FORMAT_RGBA_1010102: + case HAL_PIXEL_FORMAT_ARGB_2101010: + case HAL_PIXEL_FORMAT_RGBX_1010102: + case HAL_PIXEL_FORMAT_XRGB_2101010: + case HAL_PIXEL_FORMAT_BGRA_1010102: + case HAL_PIXEL_FORMAT_ABGR_2101010: + case HAL_PIXEL_FORMAT_BGRX_1010102: + case HAL_PIXEL_FORMAT_XBGR_2101010: + case HAL_PIXEL_FORMAT_RGBA_FP16: + case HAL_PIXEL_FORMAT_BGR_888: + return true; + default: + break; + } + + return false; +} + +bool IsCompressedRGBFormat(int format) { + switch (format) { + case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_4x4_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_5x4_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_5x5_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_6x5_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_6x6_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x5_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x6_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x8_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x5_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x6_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x8_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x10_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_12x10_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_12x12_KHR: + case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: + return true; + default: + break; + } + + return false; +} + +uint32_t GetBppForUncompressedRGB(int format) { + uint32_t bpp = 0; + switch (format) { + case HAL_PIXEL_FORMAT_RGBA_FP16: + bpp = 8; + break; + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_BGRA_8888: + case HAL_PIXEL_FORMAT_BGRX_8888: + case HAL_PIXEL_FORMAT_RGBA_1010102: + case HAL_PIXEL_FORMAT_ARGB_2101010: + case HAL_PIXEL_FORMAT_RGBX_1010102: + case HAL_PIXEL_FORMAT_XRGB_2101010: + case HAL_PIXEL_FORMAT_BGRA_1010102: + case HAL_PIXEL_FORMAT_ABGR_2101010: + case HAL_PIXEL_FORMAT_BGRX_1010102: + case HAL_PIXEL_FORMAT_XBGR_2101010: + bpp = 4; + break; + case HAL_PIXEL_FORMAT_RGB_888: + case HAL_PIXEL_FORMAT_BGR_888: + bpp = 3; + break; + case HAL_PIXEL_FORMAT_RGB_565: + case HAL_PIXEL_FORMAT_BGR_565: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: + bpp = 2; + break; + default: + ALOGE("Error : %s New format request = 0x%x", __FUNCTION__, format); + break; + } + + return bpp; +} + +bool CpuCanAccess(gralloc1_producer_usage_t prod_usage, gralloc1_consumer_usage_t cons_usage) { + return CpuCanRead(prod_usage, cons_usage) || CpuCanWrite(prod_usage); +} + +bool CpuCanRead(gralloc1_producer_usage_t prod_usage, gralloc1_consumer_usage_t cons_usage) { + if (prod_usage & GRALLOC1_PRODUCER_USAGE_CPU_READ) { + return true; + } + + if (cons_usage & GRALLOC1_CONSUMER_USAGE_CPU_READ) { + return true; + } + + return false; +} + +bool CpuCanWrite(gralloc1_producer_usage_t prod_usage) { + if (prod_usage & GRALLOC1_PRODUCER_USAGE_CPU_WRITE) { + // Application intends to use CPU for rendering + return true; + } + + return false; +} + +unsigned int GetSize(const BufferInfo &info, unsigned int alignedw, + unsigned int alignedh) { + unsigned int size = 0; + int format = info.format; + int width = info.width; + int height = info.height; + gralloc1_producer_usage_t prod_usage = info.prod_usage; + gralloc1_consumer_usage_t cons_usage = info.cons_usage; + + if (IsUBwcEnabled(format, prod_usage, cons_usage)) { + return GetUBwcSize(width, height, format, alignedw, alignedh); + } + + if (IsUncompressedRGBFormat(format)) { + uint32_t bpp = GetBppForUncompressedRGB(format); + size = alignedw * alignedh * bpp; + return size; + } + + if (IsCompressedRGBFormat(format)) { + size = alignedw * alignedh * ASTC_BLOCK_SIZE; + return size; + } + + // Below switch should be for only YUV/custom formats + switch (format) { + case HAL_PIXEL_FORMAT_RAW16: + case HAL_PIXEL_FORMAT_Y16: + size = alignedw * alignedh * 2; + break; + case HAL_PIXEL_FORMAT_RAW10: + case HAL_PIXEL_FORMAT_RAW12: + size = ALIGN(alignedw * alignedh, SIZE_4K); + break; + case HAL_PIXEL_FORMAT_RAW8: + case HAL_PIXEL_FORMAT_Y8: + size = alignedw * alignedh * 1; + break; + + // adreno formats + case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: // NV21 + size = ALIGN(alignedw * alignedh, SIZE_4K); + size += (unsigned int)ALIGN(2 * ALIGN(width / 2, 32) * ALIGN(height / 2, 32), SIZE_4K); + break; + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: // NV12 + // The chroma plane is subsampled, + // but the pitch in bytes is unchanged + // The GPU needs 4K alignment, but the video decoder needs 8K + size = ALIGN(alignedw * alignedh, SIZE_8K); + size += ALIGN(alignedw * (unsigned int)ALIGN(height / 2, 32), SIZE_8K); + break; + case HAL_PIXEL_FORMAT_YV12: + if ((format == HAL_PIXEL_FORMAT_YV12) && ((width & 1) || (height & 1))) { + ALOGE("w or h is odd for the YV12 format"); + return 0; + } + size = alignedw * alignedh + (ALIGN(alignedw / 2, 16) * (alignedh / 2)) * 2; + size = ALIGN(size, (unsigned int)SIZE_4K); + break; + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + size = ALIGN((alignedw * alignedh) + (alignedw * alignedh) / 2 + 1, SIZE_4K); + break; + case HAL_PIXEL_FORMAT_YCbCr_420_P010: + size = ALIGN((alignedw * alignedh * 2) + (alignedw * alignedh) + 1, SIZE_4K); + break; + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + case HAL_PIXEL_FORMAT_YCrCb_422_SP: + case HAL_PIXEL_FORMAT_YCbCr_422_I: + case HAL_PIXEL_FORMAT_YCrCb_422_I: + case HAL_PIXEL_FORMAT_CbYCrY_422_I: + if (width & 1) { + ALOGE("width is odd for the YUV422_SP format"); + return 0; + } + size = ALIGN(alignedw * alignedh * 2, SIZE_4K); + break; + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + size = VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height); + break; + case HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS: + size = VENUS_BUFFER_SIZE(COLOR_FMT_NV21, width, height); + break; + case HAL_PIXEL_FORMAT_BLOB: + case HAL_PIXEL_FORMAT_RAW_OPAQUE: + if (height != 1) { + ALOGE("%s: Buffers with HAL_PIXEL_FORMAT_BLOB must have height 1 ", __FUNCTION__); + return 0; + } + size = (unsigned int)width; + break; + case HAL_PIXEL_FORMAT_NV21_ZSL: + size = ALIGN((alignedw * alignedh) + (alignedw * alignedh) / 2, SIZE_4K); + break; + default: + ALOGE("%s: Unrecognized pixel format: 0x%x", __FUNCTION__, format); + return 0; + } + + return size; +} + +void GetBufferSizeAndDimensions(const BufferInfo &info, unsigned int *size, + unsigned int *alignedw, unsigned int *alignedh) { + GetAlignedWidthAndHeight(info, alignedw, alignedh); + *size = GetSize(info, *alignedw, *alignedh); +} + +void GetYuvUbwcSPPlaneInfo(uint64_t base, uint32_t width, uint32_t height, + int color_format, struct android_ycbcr *ycbcr) { + // UBWC buffer has these 4 planes in the following sequence: + // Y_Meta_Plane, Y_Plane, UV_Meta_Plane, UV_Plane + unsigned int y_meta_stride, y_meta_height, y_meta_size; + unsigned int y_stride, y_height, y_size; + unsigned int c_meta_stride, c_meta_height, c_meta_size; + unsigned int alignment = 4096; + + y_meta_stride = VENUS_Y_META_STRIDE(color_format, INT(width)); + y_meta_height = VENUS_Y_META_SCANLINES(color_format, INT(height)); + y_meta_size = ALIGN((y_meta_stride * y_meta_height), alignment); + + y_stride = VENUS_Y_STRIDE(color_format, INT(width)); + y_height = VENUS_Y_SCANLINES(color_format, INT(height)); + y_size = ALIGN((y_stride * y_height), alignment); + + c_meta_stride = VENUS_UV_META_STRIDE(color_format, INT(width)); + c_meta_height = VENUS_UV_META_SCANLINES(color_format, INT(height)); + c_meta_size = ALIGN((c_meta_stride * c_meta_height), alignment); + + ycbcr->y = reinterpret_cast<void *>(base + y_meta_size); + ycbcr->cb = reinterpret_cast<void *>(base + y_meta_size + y_size + c_meta_size); + ycbcr->cr = reinterpret_cast<void *>(base + y_meta_size + y_size + c_meta_size + 1); + ycbcr->ystride = y_stride; + ycbcr->cstride = VENUS_UV_STRIDE(color_format, INT(width)); +} + +void GetYuvUbwcInterlacedSPPlaneInfo(uint64_t base, uint32_t width, uint32_t height, + int color_format, struct android_ycbcr *ycbcr) { + unsigned int uv_stride, uv_height, uv_size; + unsigned int alignment = 4096; + uint64_t field_base; + + // UBWC interlaced has top-bottom field layout with each field as + // 4-plane NV12_UBWC with width = image_width & height = image_height / 2. + // Client passed ycbcr argument is ptr to struct android_ycbcr[2]. + // Plane info to be filled for each field separately. + height = (height + 1) >> 1; + uv_stride = VENUS_UV_STRIDE(color_format, INT(width)); + uv_height = VENUS_UV_SCANLINES(color_format, INT(height)); + uv_size = ALIGN((uv_stride * uv_height), alignment); + + field_base = base; + GetYuvUbwcSPPlaneInfo(field_base, width, height, COLOR_FMT_NV12_UBWC, &ycbcr[0]); + + field_base = reinterpret_cast<uint64_t>(ycbcr[0].cb) + uv_size; + GetYuvUbwcSPPlaneInfo(field_base, width, height, COLOR_FMT_NV12_UBWC, &ycbcr[1]); +} + +void GetYuvSPPlaneInfo(uint64_t base, uint32_t width, uint32_t height, uint32_t bpp, + struct android_ycbcr *ycbcr) { + unsigned int ystride, cstride; + + ystride = cstride = UINT(width) * bpp; + ycbcr->y = reinterpret_cast<void *>(base); + ycbcr->cb = reinterpret_cast<void *>(base + ystride * UINT(height)); + ycbcr->cr = reinterpret_cast<void *>(base + ystride * UINT(height) + 1); + ycbcr->ystride = ystride; + ycbcr->cstride = cstride; + ycbcr->chroma_step = 2 * bpp; +} + +int GetYUVPlaneInfo(const private_handle_t *hnd, struct android_ycbcr *ycbcr) { + int err = 0; + uint32_t width = UINT(hnd->width); + uint32_t height = UINT(hnd->height); + int format = hnd->format; + gralloc1_producer_usage_t prod_usage = hnd->GetProducerUsage(); + gralloc1_consumer_usage_t cons_usage = hnd->GetConsumerUsage(); + unsigned int ystride, cstride; + bool interlaced = false; + + memset(ycbcr->reserved, 0, sizeof(ycbcr->reserved)); + + // Check if UBWC buffer has been rendered in linear format. + int linear_format = 0; + if (getMetaData(const_cast<private_handle_t *>(hnd), + GET_LINEAR_FORMAT, &linear_format) == 0) { + format = INT(linear_format); + } + + // Check metadata if the geometry has been updated. + BufferDim_t buffer_dim; + if (getMetaData(const_cast<private_handle_t *>(hnd), + GET_BUFFER_GEOMETRY, &buffer_dim) == 0) { + int usage = 0; + if (hnd->flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) { + usage = GRALLOC1_PRODUCER_USAGE_PRIVATE_ALLOC_UBWC; + } + + BufferInfo info(buffer_dim.sliceWidth, buffer_dim.sliceHeight, format, + prod_usage, cons_usage); + GetAlignedWidthAndHeight(info, &width, &height); + } + + // Check metadata for interlaced content. + int interlace_flag = 0; + if (getMetaData(const_cast<private_handle_t *>(hnd), + GET_PP_PARAM_INTERLACED, &interlace_flag) != 0) { + interlaced = interlace_flag; + } + + // Get the chroma offsets from the handle width/height. We take advantage + // of the fact the width _is_ the stride + switch (format) { + // Semiplanar + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + // Same as YCbCr_420_SP_VENUS + GetYuvSPPlaneInfo(hnd->base, width, height, 1, ycbcr); + break; + + case HAL_PIXEL_FORMAT_YCbCr_420_P010: + GetYuvSPPlaneInfo(hnd->base, width, height, 2, ycbcr); + break; + + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC: + if (!interlaced) { + GetYuvUbwcSPPlaneInfo(hnd->base, width, height, COLOR_FMT_NV12_UBWC, ycbcr); + } else { + GetYuvUbwcInterlacedSPPlaneInfo(hnd->base, width, height, COLOR_FMT_NV12_UBWC, ycbcr); + } + ycbcr->chroma_step = 2; + break; + + case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC: + GetYuvUbwcSPPlaneInfo(hnd->base, width, height, COLOR_FMT_NV12_BPP10_UBWC, ycbcr); + ycbcr->chroma_step = 3; + break; + + case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC: + GetYuvUbwcSPPlaneInfo(hnd->base, width, height, COLOR_FMT_P010_UBWC, ycbcr); + ycbcr->chroma_step = 4; + break; + + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + case HAL_PIXEL_FORMAT_YCrCb_422_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: + case HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS: + case HAL_PIXEL_FORMAT_NV21_ZSL: + case HAL_PIXEL_FORMAT_RAW16: + case HAL_PIXEL_FORMAT_Y16: + case HAL_PIXEL_FORMAT_RAW10: + case HAL_PIXEL_FORMAT_RAW8: + case HAL_PIXEL_FORMAT_Y8: + GetYuvSPPlaneInfo(hnd->base, width, height, 1, ycbcr); + std::swap(ycbcr->cb, ycbcr->cr); + break; + + // Planar + case HAL_PIXEL_FORMAT_YV12: + ystride = width; + cstride = ALIGN(width / 2, 16); + ycbcr->y = reinterpret_cast<void *>(hnd->base); + ycbcr->cr = reinterpret_cast<void *>(hnd->base + ystride * height); + ycbcr->cb = reinterpret_cast<void *>(hnd->base + ystride * height + cstride * height / 2); + ycbcr->ystride = ystride; + ycbcr->cstride = cstride; + ycbcr->chroma_step = 1; + break; + case HAL_PIXEL_FORMAT_CbYCrY_422_I: + ystride = width * 2; + cstride = 0; + ycbcr->y = reinterpret_cast<void *>(hnd->base); + ycbcr->cr = NULL; + ycbcr->cb = NULL; + ycbcr->ystride = ystride; + ycbcr->cstride = 0; + ycbcr->chroma_step = 0; + break; + // Unsupported formats + case HAL_PIXEL_FORMAT_YCbCr_422_I: + case HAL_PIXEL_FORMAT_YCrCb_422_I: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: + default: + ALOGD("%s: Invalid format passed: 0x%x", __FUNCTION__, format); + err = -EINVAL; + } + + return err; +} + +// Explicitly defined UBWC formats +bool IsUBwcFormat(int format) { + switch (format) { + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC: + case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC: + case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC: + return true; + default: + return false; + } +} + +bool IsUBwcSupported(int format) { + // Existing HAL formats with UBWC support + switch (format) { + case HAL_PIXEL_FORMAT_BGR_565: + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: + case HAL_PIXEL_FORMAT_RGBA_1010102: + case HAL_PIXEL_FORMAT_RGBX_1010102: + return true; + default: + break; + } + + return false; +} + +bool IsUBwcEnabled(int format, gralloc1_producer_usage_t prod_usage, + gralloc1_consumer_usage_t cons_usage) { + // Allow UBWC, if client is using an explicitly defined UBWC pixel format. + if (IsUBwcFormat(format)) { + return true; + } + + // Allow UBWC, if an OpenGL client sets UBWC usage flag and GPU plus MDP + // support the format. OR if a non-OpenGL client like Rotator, sets UBWC + // usage flag and MDP supports the format. + if ((prod_usage & GRALLOC1_PRODUCER_USAGE_PRIVATE_ALLOC_UBWC) && IsUBwcSupported(format)) { + bool enable = true; + // Query GPU for UBWC only if buffer is intended to be used by GPU. + if ((cons_usage & GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE) || + (prod_usage & GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET)) { + if (AdrenoMemInfo::GetInstance()) { + enable = AdrenoMemInfo::GetInstance()->IsUBWCSupportedByGPU(format); + } + } + + // Allow UBWC, only if CPU usage flags are not set + if (enable && !(CpuCanAccess(prod_usage, cons_usage))) { + return true; + } + } + + return false; +} + +void GetYuvUBwcWidthAndHeight(int width, int height, int format, unsigned int *aligned_w, + unsigned int *aligned_h) { + switch (format) { + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC: + *aligned_w = VENUS_Y_STRIDE(COLOR_FMT_NV12_UBWC, width); + *aligned_h = VENUS_Y_SCANLINES(COLOR_FMT_NV12_UBWC, height); + break; + case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC: + // The macro returns the stride which is 4/3 times the width, hence * 3/4 + *aligned_w = (VENUS_Y_STRIDE(COLOR_FMT_NV12_BPP10_UBWC, width) * 3) / 4; + *aligned_h = VENUS_Y_SCANLINES(COLOR_FMT_NV12_BPP10_UBWC, height); + break; + case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC: + // The macro returns the stride which is 2 times the width, hence / 2 + *aligned_w = (VENUS_Y_STRIDE(COLOR_FMT_P010_UBWC, width) / 2); + *aligned_h = VENUS_Y_SCANLINES(COLOR_FMT_P010_UBWC, height); + break; + default: + ALOGE("%s: Unsupported pixel format: 0x%x", __FUNCTION__, format); + *aligned_w = 0; + *aligned_h = 0; + break; + } +} + +void GetRgbUBwcBlockSize(uint32_t bpp, int *block_width, int *block_height) { + *block_width = 0; + *block_height = 0; + + switch (bpp) { + case 2: + case 4: + *block_width = 16; + *block_height = 4; + break; + case 8: + *block_width = 8; + *block_height = 4; + break; + case 16: + *block_width = 4; + *block_height = 4; + break; + default: + ALOGE("%s: Unsupported bpp: %d", __FUNCTION__, bpp); + break; + } +} + +unsigned int GetRgbUBwcMetaBufferSize(int width, int height, uint32_t bpp) { + unsigned int size = 0; + int meta_width, meta_height; + int block_width, block_height; + + GetRgbUBwcBlockSize(bpp, &block_width, &block_height); + if (!block_width || !block_height) { + ALOGE("%s: Unsupported bpp: %d", __FUNCTION__, bpp); + return size; + } + + // Align meta buffer height to 16 blocks + meta_height = ALIGN(((height + block_height - 1) / block_height), 16); + + // Align meta buffer width to 64 blocks + meta_width = ALIGN(((width + block_width - 1) / block_width), 64); + + // Align meta buffer size to 4K + size = (unsigned int)ALIGN((meta_width * meta_height), 4096); + + return size; +} + +unsigned int GetUBwcSize(int width, int height, int format, unsigned int alignedw, + unsigned int alignedh) { + unsigned int size = 0; + uint32_t bpp = 0; + switch (format) { + case HAL_PIXEL_FORMAT_BGR_565: + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_RGBA_1010102: + case HAL_PIXEL_FORMAT_RGBX_1010102: + bpp = GetBppForUncompressedRGB(format); + size = alignedw * alignedh * bpp; + size += GetRgbUBwcMetaBufferSize(width, height, bpp); + break; + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC: + size = VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC, width, height); + break; + case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC: + size = VENUS_BUFFER_SIZE(COLOR_FMT_NV12_BPP10_UBWC, width, height); + break; + case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC: + size = VENUS_BUFFER_SIZE(COLOR_FMT_P010_UBWC, width, height); + break; + default: + ALOGE("%s: Unsupported pixel format: 0x%x", __FUNCTION__, format); + break; + } + + return size; +} + +int GetRgbDataAddress(private_handle_t *hnd, void **rgb_data) { + int err = 0; + + // This api is for RGB* formats + if (!gralloc1::IsUncompressedRGBFormat(hnd->format)) { + return -EINVAL; + } + + // linear buffer, nothing to do further + if (!(hnd->flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED)) { + *rgb_data = reinterpret_cast<void *>(hnd->base); + return err; + } + + unsigned int meta_size = 0; + uint32_t bpp = GetBppForUncompressedRGB(hnd->format); + switch (hnd->format) { + case HAL_PIXEL_FORMAT_BGR_565: + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_RGBA_1010102: + case HAL_PIXEL_FORMAT_RGBX_1010102: + meta_size = GetRgbUBwcMetaBufferSize(hnd->width, hnd->height, bpp); + break; + default: + ALOGE("%s:Unsupported RGB format: 0x%x", __FUNCTION__, hnd->format); + err = -EINVAL; + break; + } + *rgb_data = reinterpret_cast<void *>(hnd->base + meta_size); + + return err; +} + +void GetAlignedWidthAndHeight(const BufferInfo &info, unsigned int *alignedw, + unsigned int *alignedh) { + int width = info.width; + int height = info.height; + int format = info.format; + gralloc1_producer_usage_t prod_usage = info.prod_usage; + gralloc1_consumer_usage_t cons_usage = info.cons_usage; + + // Currently surface padding is only computed for RGB* surfaces. + bool ubwc_enabled = IsUBwcEnabled(format, prod_usage, cons_usage); + int tile = ubwc_enabled; + + if (IsUncompressedRGBFormat(format)) { + if (AdrenoMemInfo::GetInstance()) { + AdrenoMemInfo::GetInstance()->AlignUnCompressedRGB(width, height, format, tile, alignedw, + alignedh); + } + return; + } + + if (ubwc_enabled) { + GetYuvUBwcWidthAndHeight(width, height, format, alignedw, alignedh); + return; + } + + if (IsCompressedRGBFormat(format)) { + if (AdrenoMemInfo::GetInstance()) { + AdrenoMemInfo::GetInstance()->AlignCompressedRGB(width, height, format, alignedw, alignedh); + } + return; + } + + int aligned_w = width; + int aligned_h = height; + unsigned int alignment = 32; + + // Below should be only YUV family + switch (format) { + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + if (AdrenoMemInfo::GetInstance() == nullptr) { + return; + } + alignment = AdrenoMemInfo::GetInstance()->GetGpuPixelAlignment(); + aligned_w = ALIGN(width, alignment); + break; + case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: + aligned_w = ALIGN(width, alignment); + break; + case HAL_PIXEL_FORMAT_RAW16: + case HAL_PIXEL_FORMAT_Y16: + case HAL_PIXEL_FORMAT_Y8: + aligned_w = ALIGN(width, 16); + break; + case HAL_PIXEL_FORMAT_RAW12: + aligned_w = ALIGN(width * 12 / 8, 8); + break; + case HAL_PIXEL_FORMAT_RAW10: + aligned_w = ALIGN(width * 10 / 8, 8); + break; + case HAL_PIXEL_FORMAT_RAW8: + aligned_w = ALIGN(width, 8); + break; + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: + aligned_w = ALIGN(width, 128); + break; + case HAL_PIXEL_FORMAT_YV12: + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + case HAL_PIXEL_FORMAT_YCrCb_422_SP: + case HAL_PIXEL_FORMAT_YCbCr_422_I: + case HAL_PIXEL_FORMAT_YCrCb_422_I: + case HAL_PIXEL_FORMAT_YCbCr_420_P010: + aligned_w = ALIGN(width, 16); + break; + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + aligned_w = INT(VENUS_Y_STRIDE(COLOR_FMT_NV12, width)); + aligned_h = INT(VENUS_Y_SCANLINES(COLOR_FMT_NV12, height)); + break; + case HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS: + aligned_w = INT(VENUS_Y_STRIDE(COLOR_FMT_NV21, width)); + aligned_h = INT(VENUS_Y_SCANLINES(COLOR_FMT_NV21, height)); + break; + case HAL_PIXEL_FORMAT_BLOB: + case HAL_PIXEL_FORMAT_RAW_OPAQUE: + break; + case HAL_PIXEL_FORMAT_NV21_ZSL: + aligned_w = ALIGN(width, 64); + aligned_h = ALIGN(height, 64); + break; + default: + break; + } + + *alignedw = (unsigned int)aligned_w; + *alignedh = (unsigned int)aligned_h; +} + +int GetBufferLayout(private_handle_t *hnd, uint32_t stride[4], + uint32_t offset[4], uint32_t *num_planes) { + if (!hnd || !stride || !offset || !num_planes) { + return -EINVAL; + } + + struct android_ycbcr yuvInfo = {}; + *num_planes = 1; + stride[0] = 0; + + switch (hnd->format) { + case HAL_PIXEL_FORMAT_RGB_565: + case HAL_PIXEL_FORMAT_BGR_565: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: + stride[0] = static_cast<uint32_t>(hnd->width * 2); + break; + case HAL_PIXEL_FORMAT_RGB_888: + stride[0] = static_cast<uint32_t>(hnd->width * 3); + break; + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_BGRA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_BGRX_8888: + case HAL_PIXEL_FORMAT_RGBA_1010102: + case HAL_PIXEL_FORMAT_ARGB_2101010: + case HAL_PIXEL_FORMAT_RGBX_1010102: + case HAL_PIXEL_FORMAT_XRGB_2101010: + case HAL_PIXEL_FORMAT_BGRA_1010102: + case HAL_PIXEL_FORMAT_ABGR_2101010: + case HAL_PIXEL_FORMAT_BGRX_1010102: + case HAL_PIXEL_FORMAT_XBGR_2101010: + stride[0] = static_cast<uint32_t>(hnd->width * 4); + break; + } + + // Format is RGB + if (stride[0]) { + return 0; + } + + (*num_planes)++; + int ret = GetYUVPlaneInfo(hnd, &yuvInfo); + if (ret < 0) { + ALOGE("%s failed", __FUNCTION__); + return ret; + } + + stride[0] = static_cast<uint32_t>(yuvInfo.ystride); + offset[0] = static_cast<uint32_t>(reinterpret_cast<uint64_t>(yuvInfo.y) - hnd->base); + stride[1] = static_cast<uint32_t>(yuvInfo.cstride); + switch (hnd->format) { + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC: + case HAL_PIXEL_FORMAT_YCbCr_420_P010: + case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC: + case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC: + offset[1] = static_cast<uint32_t>(reinterpret_cast<uint64_t>(yuvInfo.cb) - hnd->base); + break; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS: + case HAL_PIXEL_FORMAT_YCrCb_422_SP: + offset[1] = static_cast<uint32_t>(reinterpret_cast<uint64_t>(yuvInfo.cr) - hnd->base); + break; + case HAL_PIXEL_FORMAT_YV12: + offset[1] = static_cast<uint32_t>(reinterpret_cast<uint64_t>(yuvInfo.cr) - hnd->base); + stride[2] = static_cast<uint32_t>(yuvInfo.cstride); + offset[2] = static_cast<uint32_t>(reinterpret_cast<uint64_t>(yuvInfo.cb) - hnd->base); + (*num_planes)++; + break; + default: + ALOGW("%s: Unsupported format", __FUNCTION__); + ret = -EINVAL; + } + + if (hnd->flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) { + std::fill(offset, offset + 4, 0); + } + + return 0; +} + +} // namespace gralloc1 diff --git a/msm8909/gralloc/gr_utils.h b/msm8909/gralloc/gr_utils.h new file mode 100644 index 00000000..2a085392 --- /dev/null +++ b/msm8909/gralloc/gr_utils.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2011-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 __GR_UTILS_H__ +#define __GR_UTILS_H__ + +#include "gralloc_priv.h" + +#define SZ_2M 0x200000 +#define SZ_1M 0x100000 +#define SZ_4K 0x1000 + +#define SIZE_4K 4096 +#define SIZE_8K 4096 + +#define INT(exp) static_cast<int>(exp) +#define UINT(exp) static_cast<unsigned int>(exp) + +namespace gralloc1 { + +struct BufferInfo { + BufferInfo(int w, int h, int f, gralloc1_producer_usage_t prod = GRALLOC1_PRODUCER_USAGE_NONE, + gralloc1_consumer_usage_t cons = GRALLOC1_CONSUMER_USAGE_NONE) : width(w), height(h), + format(f), prod_usage(prod), cons_usage(cons) {} + int width; + int height; + int format; + gralloc1_producer_usage_t prod_usage; + gralloc1_consumer_usage_t cons_usage; +}; + +template <class Type1, class Type2> +inline Type1 ALIGN(Type1 x, Type2 align) { + return (Type1)((x + (Type1)align - 1) & ~((Type1)align - 1)); +} + +bool IsCompressedRGBFormat(int format); +bool IsUncompressedRGBFormat(int format); +uint32_t GetBppForUncompressedRGB(int format); +bool CpuCanAccess(gralloc1_producer_usage_t prod_usage, gralloc1_consumer_usage_t cons_usage); +bool CpuCanRead(gralloc1_producer_usage_t prod_usage, gralloc1_consumer_usage_t cons_usage); +bool CpuCanWrite(gralloc1_producer_usage_t prod_usage); +unsigned int GetSize(const BufferInfo &d, unsigned int alignedw, unsigned int alignedh); +void GetBufferSizeAndDimensions(const BufferInfo &d, unsigned int *size, + unsigned int *alignedw, unsigned int *alignedh); +void GetAlignedWidthAndHeight(const BufferInfo &d, unsigned int *aligned_w, + unsigned int *aligned_h); +int GetYUVPlaneInfo(const private_handle_t *hnd, struct android_ycbcr *ycbcr); +int GetRgbDataAddress(private_handle_t *hnd, void **rgb_data); +bool IsUBwcFormat(int format); +bool IsUBwcSupported(int format); +bool IsUBwcEnabled(int format, gralloc1_producer_usage_t prod_usage, + gralloc1_consumer_usage_t cons_usage); +void GetYuvUBwcWidthAndHeight(int width, int height, int format, unsigned int *aligned_w, + unsigned int *aligned_h); +void GetYuvSPPlaneInfo(uint64_t base, uint32_t width, uint32_t height, uint32_t bpp, + struct android_ycbcr *ycbcr); +void GetYuvUbwcSPPlaneInfo(uint64_t base, uint32_t width, uint32_t height, int color_format, + struct android_ycbcr *ycbcr); +void GetYuvUbwcInterlacedSPPlaneInfo(uint64_t base, uint32_t width, uint32_t height, + int color_format, struct android_ycbcr *ycbcr); +void GetRgbUBwcBlockSize(uint32_t bpp, int *block_width, int *block_height); +unsigned int GetRgbUBwcMetaBufferSize(int width, int height, uint32_t bpp); +unsigned int GetUBwcSize(int width, int height, int format, unsigned int alignedw, + unsigned int alignedh); +int GetBufferLayout(private_handle_t *hnd, uint32_t stride[4], + uint32_t offset[4], uint32_t *num_planes); +} // namespace gralloc1 + +#endif // __GR_UTILS_H__ diff --git a/msm8909/gralloc/gralloc_priv.h b/msm8909/gralloc/gralloc_priv.h new file mode 100644 index 00000000..5e619eb0 --- /dev/null +++ b/msm8909/gralloc/gralloc_priv.h @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. + * Not a Contribution + * + * 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. + */ + +#ifndef __GRALLOC_PRIV_H__ +#define __GRALLOC_PRIV_H__ + +#include <unistd.h> +#include "gr_priv_handle.h" + +#define GRALLOC_PROP_PREFIX "vendor.gralloc." +#define GRALLOC_PROP(prop_name) GRALLOC_PROP_PREFIX prop_name + +#define DISABLE_UBWC_PROP GRALLOC_PROP("disable_ubwc") +#define ENABLE_FB_UBWC_PROP GRALLOC_PROP("enable_fb_ubwc") +#define MAP_FB_MEMORY_PROP GRALLOC_PROP("map_fb_memory") + +#define ROUND_UP_PAGESIZE(x) roundUpToPageSize(x) +inline int roundUpToPageSize(int x) { + return (x + (getpagesize()-1)) & ~(getpagesize()-1); +} + +/* Gralloc usage bits indicating the type of allocation that should be used */ +/* Refer gralloc1_producer_usage_t & gralloc1_consumer_usage-t in gralloc1.h */ + +/* Producer flags */ +/* Non linear, Universal Bandwidth Compression */ +#define GRALLOC1_PRODUCER_USAGE_PRIVATE_ALLOC_UBWC GRALLOC1_PRODUCER_USAGE_PRIVATE_0 + +/* Set this for allocating uncached memory (using O_DSYNC), + * cannot be used with noncontiguous heaps */ +#define GRALLOC1_PRODUCER_USAGE_PRIVATE_UNCACHED GRALLOC1_PRODUCER_USAGE_PRIVATE_1 + +/* CAMERA heap is a carveout heap for camera, is not secured */ +#define GRALLOC1_PRODUCER_USAGE_PRIVATE_CAMERA_HEAP GRALLOC1_PRODUCER_USAGE_PRIVATE_2 + +/* ADSP heap is a carveout heap, is not secured */ +#define GRALLOC1_PRODUCER_USAGE_PRIVATE_ADSP_HEAP GRALLOC1_PRODUCER_USAGE_PRIVATE_3 + +/* IOMMU heap comes from manually allocated pages, can be cached/uncached, is not secured */ +#define GRALLOC1_PRODUCER_USAGE_PRIVATE_IOMMU_HEAP GRALLOC1_PRODUCER_USAGE_PRIVATE_4 + +/* MM heap is a carveout heap for video, can be secured */ +#define GRALLOC1_PRODUCER_USAGE_PRIVATE_MM_HEAP GRALLOC1_PRODUCER_USAGE_PRIVATE_5 + +/* Use legacy ZSL definition until we know the correct usage on gralloc1 */ +#define GRALLOC1_PRODUCER_USAGE_PRIVATE_CAMERA_ZSL GRALLOC_USAGE_HW_CAMERA_ZSL + + +/* Consumer flags */ +/* TODO(user): Fix when producer and consumer flags are actually separated */ +/* This flag is set for WFD usecase */ +#define GRALLOC1_CONSUMER_USAGE_PRIVATE_WFD 0x00200000 + +/* This flag is used for SECURE display usecase */ +#define GRALLOC1_CONSUMER_USAGE_PRIVATE_SECURE_DISPLAY 0x02000000 + +/* Buffer content should be displayed on a primary display only */ +#define GRALLOC1_CONSUMER_USAGE_PRIVATE_INTERNAL_ONLY 0x04000000 + +/* Buffer content should be displayed on an external display only */ +#define GRALLOC1_CONSUMER_USAGE_PRIVATE_EXTERNAL_ONLY 0x08000000 + + +/* Legacy gralloc0.x definitions */ +/* Some clients may still be using the old flags */ +#define GRALLOC_USAGE_PRIVATE_ALLOC_UBWC GRALLOC1_PRODUCER_USAGE_PRIVATE_ALLOC_UBWC +#define GRALLOC_USAGE_PRIVATE_UNCACHED GRALLOC1_PRODUCER_USAGE_PRIVATE_UNCACHED +#define GRALLOC_USAGE_PRIVATE_IOMMU_HEAP GRALLOC1_PRODUCER_USAGE_PRIVATE_IOMMU_HEAP +#define GRALLOC_USAGE_PRIVATE_WFD GRALLOC1_CONSUMER_USAGE_PRIVATE_WFD +#define GRALLOC_USAGE_PRIVATE_CAMERA_HEAP GRALLOC1_PRODUCER_USAGE_PRIVATE_CAMERA_HEAP +#define GRALLOC_USAGE_PRIVATE_SECURE_DISPLAY GRALLOC1_CONSUMER_USAGE_PRIVATE_SECURE_DISPLAY +#define GRALLOC_USAGE_PRIVATE_MM_HEAP 0x0 + + + +// for PERFORM API : +#define GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER 1 +#define GRALLOC_MODULE_PERFORM_GET_STRIDE 2 +#define GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_FROM_HANDLE 3 +#define GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_AND_HEIGHT_FROM_HANDLE 4 +#define GRALLOC_MODULE_PERFORM_GET_ATTRIBUTES 5 +#define GRALLOC_MODULE_PERFORM_GET_COLOR_SPACE_FROM_HANDLE 6 +#define GRALLOC_MODULE_PERFORM_GET_YUV_PLANE_INFO 7 +#define GRALLOC_MODULE_PERFORM_GET_MAP_SECURE_BUFFER_INFO 8 +#define GRALLOC_MODULE_PERFORM_GET_UBWC_FLAG 9 +#define GRALLOC_MODULE_PERFORM_GET_RGB_DATA_ADDRESS 10 +#define GRALLOC_MODULE_PERFORM_GET_IGC 11 +#define GRALLOC_MODULE_PERFORM_SET_IGC 12 +#define GRALLOC_MODULE_PERFORM_SET_SINGLE_BUFFER_MODE 13 +#define GRALLOC1_MODULE_PERFORM_GET_BUFFER_SIZE_AND_DIMENSIONS 14 +#define GRALLOC1_MODULE_PERFORM_ALLOCATE_BUFFER 15 +#define GRALLOC1_MODULE_PERFORM_GET_INTERLACE_FLAG 16 + +// OEM specific HAL formats +#define HAL_PIXEL_FORMAT_RGBA_5551 6 +#define HAL_PIXEL_FORMAT_RGBA_4444 7 +#define HAL_PIXEL_FORMAT_NV12_ENCODEABLE 0x102 +#define HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS 0x7FA30C04 +#define HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED 0x7FA30C03 +#define HAL_PIXEL_FORMAT_YCbCr_420_SP 0x109 +#define HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO 0x7FA30C01 +#define HAL_PIXEL_FORMAT_YCrCb_422_SP 0x10B +#define HAL_PIXEL_FORMAT_R_8 0x10D +#define HAL_PIXEL_FORMAT_RG_88 0x10E +#define HAL_PIXEL_FORMAT_YCbCr_444_SP 0x10F +#define HAL_PIXEL_FORMAT_YCrCb_444_SP 0x110 +#define HAL_PIXEL_FORMAT_YCrCb_422_I 0x111 +#define HAL_PIXEL_FORMAT_BGRX_8888 0x112 +#define HAL_PIXEL_FORMAT_NV21_ZSL 0x113 +#define HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS 0x114 +#define HAL_PIXEL_FORMAT_BGR_565 0x115 +#define HAL_PIXEL_FORMAT_RAW8 0x123 + +// 10 bit +#define HAL_PIXEL_FORMAT_ARGB_2101010 0x117 +#define HAL_PIXEL_FORMAT_RGBX_1010102 0x118 +#define HAL_PIXEL_FORMAT_XRGB_2101010 0x119 +#define HAL_PIXEL_FORMAT_BGRA_1010102 0x11A +#define HAL_PIXEL_FORMAT_ABGR_2101010 0x11B +#define HAL_PIXEL_FORMAT_BGRX_1010102 0x11C +#define HAL_PIXEL_FORMAT_XBGR_2101010 0x11D +#define HAL_PIXEL_FORMAT_YCbCr_420_P010 0x11F +#define HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC 0x124 + +#define HAL_PIXEL_FORMAT_CbYCrY_422_I 0x120 +#define HAL_PIXEL_FORMAT_BGR_888 0x121 + +#define HAL_PIXEL_FORMAT_INTERLACE 0x180 + +// v4l2_fourcc('Y', 'U', 'Y', 'L'). 24 bpp YUYV 4:2:2 10 bit per component +#define HAL_PIXEL_FORMAT_YCbCr_422_I_10BIT 0x4C595559 + +// v4l2_fourcc('Y', 'B', 'W', 'C'). 10 bit per component. This compressed +// format reduces the memory access bandwidth +#define HAL_PIXEL_FORMAT_YCbCr_422_I_10BIT_COMPRESSED 0x43574259 + +// UBWC aligned Venus format +#define HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC 0x7FA30C06 +#define HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC 0x7FA30C09 + +// Khronos ASTC formats +#define HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 +#define HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1 +#define HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2 +#define HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3 +#define HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4 +#define HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5 +#define HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6 +#define HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7 +#define HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8 +#define HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9 +#define HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA +#define HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB +#define HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC +#define HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD +#define HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0 +#define HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1 +#define HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2 +#define HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3 +#define HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4 +#define HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5 +#define HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6 +#define HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7 +#define HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8 +#define HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9 +#define HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA +#define HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB +#define HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC +#define HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD + +/* possible values for inverse gamma correction */ +#define HAL_IGC_NOT_SPECIFIED 0 +#define HAL_IGC_s_RGB 1 + +/* Color Space: Values maps to ColorSpace_t in qdMetadata.h */ +#define HAL_CSC_ITU_R_601 0 +#define HAL_CSC_ITU_R_601_FR 1 +#define HAL_CSC_ITU_R_709 2 +#define HAL_CSC_ITU_R_2020 3 +#define HAL_CSC_ITU_R_2020_FR 4 + +/* possible formats for 3D content*/ +enum { + HAL_NO_3D = 0x0, + HAL_3D_SIDE_BY_SIDE_L_R = 0x1, + HAL_3D_SIDE_BY_SIDE_R_L = 0x2, + HAL_3D_TOP_BOTTOM = 0x4, + HAL_3D_IN_SIDE_BY_SIDE_L_R = 0x10000, // unused legacy format +}; + +enum { BUFFER_TYPE_UI = 0, BUFFER_TYPE_VIDEO }; + +#endif // __GRALLOC_PRIV_H__ diff --git a/msm8909/hdmi_cec/Android.mk b/msm8909/hdmi_cec/Android.mk new file mode 100644 index 00000000..4fed1f03 --- /dev/null +++ b/msm8909/hdmi_cec/Android.mk @@ -0,0 +1,18 @@ +LOCAL_PATH := $(call my-dir) +include $(LOCAL_PATH)/../common.mk +include $(CLEAR_VARS) + +LOCAL_MODULE := hdmi_cec.$(TARGET_BOARD_PLATFORM) +LOCAL_VENDOR_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_MODULE_TAGS := optional +LOCAL_C_INCLUDES := $(common_includes) +LOCAL_HEADER_LIBRARIES := display_headers +LOCAL_SHARED_LIBRARIES := $(common_libs) + +LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdhdmi_cec\" -Wno-sign-conversion +LOCAL_CLANG := true +LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) +LOCAL_SRC_FILES := qhdmi_cec.cpp + +include $(BUILD_SHARED_LIBRARY) diff --git a/msm8909/hdmi_cec/qhdmi_cec.cpp b/msm8909/hdmi_cec/qhdmi_cec.cpp new file mode 100644 index 00000000..be3ff992 --- /dev/null +++ b/msm8909/hdmi_cec/qhdmi_cec.cpp @@ -0,0 +1,721 @@ +/* +* Copyright (c) 2014, 2016-2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation. nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define DEBUG 0 +#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL) +#include <log/log.h> +#include <errno.h> +#include <hardware/hdmi_cec.h> +#include <utils/Trace.h> +#include <utils/debug.h> +#include <utils/sys.h> +#include <vector> +#include "qhdmi_cec.h" + +namespace qhdmicec { + +const int NUM_HDMI_PORTS = 1; +const int MAX_SYSFS_DATA = 128; +const int MAX_CEC_FRAME_SIZE = 20; +const int MAX_SEND_MESSAGE_RETRIES = 1; + +const char* SYSFS_BASE = "/sys/devices/virtual/graphics/fb"; +const char* UEVENT_SWITCH_HDMI = "change@/devices/virtual/switch/hdmi"; +const char* FB_PATH = "/sys/devices/virtual/graphics/fb"; + +enum { + LOGICAL_ADDRESS_SET = 1, + LOGICAL_ADDRESS_UNSET = -1, +}; + +// Offsets of members of struct hdmi_cec_msg +// drivers/video/msm/mdss/mdss_hdmi_cec.c +// XXX: Get this from a driver header +enum { + CEC_OFFSET_SENDER_ID, + CEC_OFFSET_RECEIVER_ID, + CEC_OFFSET_OPCODE, + CEC_OFFSET_OPERAND, + CEC_OFFSET_FRAME_LENGTH = 17, + CEC_OFFSET_RETRANSMIT, +}; + +//Forward declarations +static void cec_close_context(cec_context_t* ctx __unused); +static int cec_enable(cec_context_t *ctx, int enable); +static int cec_is_connected(const struct hdmi_cec_device* dev, int port_id); +static void cec_monitor_deinit(cec_context_t* ctx); +static void handle_cec_msg_event(cec_context_t* ctx, uint32_t node_event); + +void event_monitor(cec_context_t* ctx); // hdmi event monitor function +static int get_event_value(const char *uevent_data, int length, const char *event_info); +static int uevent_init(int *uevent_fd); +static void handle_hdmihotplug_event(cec_context_t* ctx, uint32_t node_event); + +static int populate_event_data(cec_context_t* ctx, std::vector<eventData> *event_data_list); +static int set_event_params(cec_context_t* ctx, uint32_t node_event, eventData *event_data); +static void handle_exit_event(cec_context_t* ctx, uint32_t node_event); + +static ssize_t read_node(const char *path, char *data) +{ + ssize_t err = 0; + FILE *fp = NULL; + err = access(path, R_OK); + if (!err) { + fp = fopen(path, "r"); + if (fp) { + err = fread(data, sizeof(char), MAX_SYSFS_DATA ,fp); + fclose(fp); + } + } + return err; +} + +static ssize_t write_node(const char *path, const char *data, size_t len) +{ + ssize_t err = 0; + int fd = -1; + err = access(path, W_OK); + if (!err) { + fd = open(path, O_WRONLY); + errno = 0; + err = write(fd, data, len); + if (err < 0) { + err = -errno; + } + close(fd); + } else { + ALOGE("%s: Failed to access path: %s error: %s", + __FUNCTION__, path, strerror(errno)); + err = -errno; + } + return err; +} + +// Helper function to write integer values to the full sysfs path +static ssize_t write_int_to_node(cec_context_t *ctx, + const char *path_postfix, + const int value) +{ + std::string sysfs_full_path; + char sysfs_data[MAX_SYSFS_DATA]; + snprintf(sysfs_data, sizeof(sysfs_data), "%d",value); + sysfs_full_path = ctx->fb_sysfs_path + "/"; + sysfs_full_path.append(path_postfix); + ssize_t err = write_node(sysfs_full_path.c_str(), sysfs_data, strlen(sysfs_data)); + return err; +} + +static void hex_to_string(const char *msg, ssize_t len, char *str) +{ + //Functions assumes sufficient memory in str + char *ptr = str; + for(int i=0; i < len ; i++) { + ptr += snprintf(ptr, 3, "%02X", msg[i]); + // Overwrite null termination of snprintf in all except the last byte + if (i < len - 1) + *ptr = ':'; + ptr++; + } +} + +static ssize_t cec_get_fb_node_number(cec_context_t *ctx) +{ + //XXX: Do this from a common utility library across the display HALs + const int MAX_FB_DEVICES = 2; + ssize_t len = 0; + std::string fb_type_path; + char fb_type[MAX_SYSFS_DATA]; + const char *dtv_panel_str = "dtv panel"; + + for(int num = 0; num < MAX_FB_DEVICES; num++) { + fb_type_path = SYSFS_BASE + std::to_string(ctx->fb_num) + "/msm_fb_type"; + len = read_node(fb_type_path.c_str(), fb_type); + ALOGD_IF(DEBUG, "%s: fb_type:%s", __FUNCTION__, fb_type); + if(len > 0 && (strncmp(fb_type, dtv_panel_str, strlen(dtv_panel_str)) == 0)){ + ALOGD_IF(DEBUG, "%s: Found DTV panel at fb%d", __FUNCTION__, num); + ctx->fb_num = num; + ctx->fb_sysfs_path = SYSFS_BASE + std::to_string(ctx->fb_num); + break; + } + } + if (len < 0) + return len; + else + return 0; +} + +static int cec_add_logical_address(const struct hdmi_cec_device* dev, + cec_logical_address_t addr) +{ + if (addr < CEC_ADDR_TV || addr > CEC_ADDR_BROADCAST) { + ALOGE("%s: Received invalid address: %d ", __FUNCTION__, addr); + return -EINVAL; + } + cec_context_t* ctx = (cec_context_t*)(dev); + ctx->logical_address[addr] = LOGICAL_ADDRESS_SET; + + //XXX: We can get multiple logical addresses here but we can only send one + //to the driver. Store locally for now + ssize_t err = write_int_to_node(ctx, "cec/logical_addr", addr); + ALOGI("%s: Allocated logical address: %d ", __FUNCTION__, addr); + return (int) err; +} + +static void cec_clear_logical_address(const struct hdmi_cec_device* dev) +{ + cec_context_t* ctx = (cec_context_t*)(dev); + memset(ctx->logical_address, LOGICAL_ADDRESS_UNSET, + sizeof(ctx->logical_address)); + //XXX: Find logical_addr that needs to be reset + write_int_to_node(ctx, "cec/logical_addr", 15); + ALOGD_IF(DEBUG, "%s: Cleared logical addresses", __FUNCTION__); +} + +static int cec_get_physical_address(const struct hdmi_cec_device* dev, + uint16_t* addr) +{ + cec_context_t* ctx = (cec_context_t*)(dev); + std::string pa_path; + char pa_data[MAX_SYSFS_DATA]; + pa_path = ctx->fb_sysfs_path; + pa_path.append("/pa"); + int err = (int) read_node(pa_path.c_str(), pa_data); + *addr = (uint16_t) atoi(pa_data); + ALOGD_IF(DEBUG, "%s: Physical Address: 0x%x", __FUNCTION__, *addr); + if (err < 0) + return err; + else + return 0; +} + +static int cec_send_message(const struct hdmi_cec_device* dev, + const cec_message_t* msg) +{ + ATRACE_CALL(); + if(cec_is_connected(dev, 0) <= 0) + return HDMI_RESULT_FAIL; + + cec_context_t* ctx = (cec_context_t*)(dev); + ALOGD_IF(DEBUG, "%s: initiator: %d destination: %d length: %u", + __FUNCTION__, msg->initiator, msg->destination, + (uint32_t) msg->length); + + // Dump message received from framework + char dump[128]; + if(msg->length > 0) { + hex_to_string((char*)msg->body, msg->length, dump); + ALOGD_IF(DEBUG, "%s: message from framework: %s", __FUNCTION__, dump); + } + + std::string write_msg_path; + char write_msg[MAX_CEC_FRAME_SIZE]; + memset(write_msg, 0, sizeof(write_msg)); + // See definition of struct hdmi_cec_msg in driver code + // drivers/video/msm/mdss/mdss_hdmi_cec.c + // Write header block + // XXX: Include this from header in kernel + write_msg[CEC_OFFSET_SENDER_ID] = msg->initiator; + write_msg[CEC_OFFSET_RECEIVER_ID] = msg->destination; + //Kernel splits opcode/operand, but Android sends it in one byte array + write_msg[CEC_OFFSET_OPCODE] = msg->body[0]; + if(msg->length > 1) { + memcpy(&write_msg[CEC_OFFSET_OPERAND], &msg->body[1], + sizeof(char)*(msg->length - 1)); + } + //msg length + initiator + destination + write_msg[CEC_OFFSET_FRAME_LENGTH] = (unsigned char) (msg->length + 1); + hex_to_string(write_msg, sizeof(write_msg), dump); + write_msg_path = ctx->fb_sysfs_path; + write_msg_path.append("/cec/wr_msg"); + int retry_count = 0; + ssize_t err = 0; + //HAL spec requires us to retry at least once. + while (true) { + err = write_node(write_msg_path.c_str(), write_msg, sizeof(write_msg)); + retry_count++; + if (err == -EAGAIN && retry_count <= MAX_SEND_MESSAGE_RETRIES) { + ALOGE("%s: CEC line busy, retrying", __FUNCTION__); + } else { + break; + } + } + + if (err < 0) { + if (err == -ENXIO) { + ALOGI("%s: No device exists with the destination address", + __FUNCTION__); + return HDMI_RESULT_NACK; + } else if (err == -EAGAIN) { + ALOGE("%s: CEC line is busy, max retry count exceeded", + __FUNCTION__); + return HDMI_RESULT_BUSY; + } else { + return HDMI_RESULT_FAIL; + ALOGE("%s: Failed to send CEC message err: %zd - %s", + __FUNCTION__, err, strerror(int(-err))); + } + } else { + ALOGD_IF(DEBUG, "%s: Sent CEC message - %zd bytes written", + __FUNCTION__, err); + return HDMI_RESULT_SUCCESS; + } +} + +void cec_receive_message(cec_context_t *ctx, char *msg, ssize_t len) +{ + if(!ctx->system_control) + return; + + char dump[128]; + if(len > 0) { + hex_to_string(msg, len, dump); + ALOGD_IF(DEBUG, "%s: Message from driver: %s", __FUNCTION__, dump); + } + + hdmi_event_t event; + event.type = HDMI_EVENT_CEC_MESSAGE; + event.dev = (hdmi_cec_device *) ctx; + // Remove initiator/destination from this calculation + event.cec.length = msg[CEC_OFFSET_FRAME_LENGTH] - 1; + event.cec.initiator = (cec_logical_address_t) msg[CEC_OFFSET_SENDER_ID]; + event.cec.destination = (cec_logical_address_t) msg[CEC_OFFSET_RECEIVER_ID]; + //Copy opcode and operand + size_t copy_size = event.cec.length > sizeof(event.cec.body) ? + sizeof(event.cec.body) : event.cec.length; + memcpy(event.cec.body, &msg[CEC_OFFSET_OPCODE],copy_size); + hex_to_string((char *) event.cec.body, copy_size, dump); + ALOGD_IF(DEBUG, "%s: Message to framework: %s", __FUNCTION__, dump); + ctx->callback.callback_func(&event, ctx->callback.callback_arg); +} + +void cec_hdmi_hotplug(cec_context_t *ctx, int connected) +{ + //Ignore unplug events when system control is disabled + if(!ctx->system_control && connected == 0) + return; + hdmi_event_t event; + event.type = HDMI_EVENT_HOT_PLUG; + event.dev = (hdmi_cec_device *) ctx; + event.hotplug.connected = connected ? HDMI_CONNECTED : HDMI_NOT_CONNECTED; + ctx->callback.callback_func(&event, ctx->callback.callback_arg); +} + +static void cec_register_event_callback(const struct hdmi_cec_device* dev, + event_callback_t callback, void* arg) +{ + ALOGD_IF(DEBUG, "%s: Registering callback", __FUNCTION__); + cec_context_t* ctx = (cec_context_t*)(dev); + ctx->callback.callback_func = callback; + ctx->callback.callback_arg = arg; +} + +static void cec_get_version(const struct hdmi_cec_device* dev, int* version) +{ + cec_context_t* ctx = (cec_context_t*)(dev); + *version = ctx->version; + ALOGD_IF(DEBUG, "%s: version: %d", __FUNCTION__, *version); +} + +static void cec_get_vendor_id(const struct hdmi_cec_device* dev, + uint32_t* vendor_id) +{ + cec_context_t* ctx = (cec_context_t*)(dev); + *vendor_id = ctx->vendor_id; + ALOGD_IF(DEBUG, "%s: vendor id: %u", __FUNCTION__, *vendor_id); +} + +static void cec_get_port_info(const struct hdmi_cec_device* dev, + struct hdmi_port_info* list[], int* total) +{ + ALOGD_IF(DEBUG, "%s: Get port info", __FUNCTION__); + cec_context_t* ctx = (cec_context_t*)(dev); + *total = NUM_HDMI_PORTS; + *list = ctx->port_info; +} + +static void cec_set_option(const struct hdmi_cec_device* dev, int flag, + int value) +{ + cec_context_t* ctx = (cec_context_t*)(dev); + switch (flag) { + case HDMI_OPTION_WAKEUP: + ALOGD_IF(DEBUG, "%s: Wakeup: value: %d", __FUNCTION__, value); + //XXX + break; + case HDMI_OPTION_ENABLE_CEC: + ALOGD_IF(DEBUG, "%s: Enable CEC: value: %d", __FUNCTION__, value); + cec_enable(ctx, value? 1 : 0); + break; + case HDMI_OPTION_SYSTEM_CEC_CONTROL: + ALOGD_IF(DEBUG, "%s: system_control: value: %d", + __FUNCTION__, value); + ctx->system_control = !!value; + break; + } +} + +static void cec_set_audio_return_channel(const struct hdmi_cec_device* dev, + int port, int flag) +{ + cec_context_t* ctx = (cec_context_t*)(dev); + ctx->arc_enabled = flag ? true : false; + ALOGD_IF(DEBUG, "%s: ARC flag: %d port: %d", __FUNCTION__, flag, port); +} + +static int cec_is_connected(const struct hdmi_cec_device* dev, int port_id) +{ + // Ignore port_id since we have only one port + int connected = 0; + cec_context_t* ctx = (cec_context_t*)(dev); + std::string connected_path; + char connected_data[MAX_SYSFS_DATA]; + connected_path = ctx->fb_sysfs_path; + connected_path.append("/connected"); + ssize_t err = read_node(connected_path.c_str(), connected_data); + connected = atoi(connected_data); + + ALOGD_IF(DEBUG, "%s: HDMI at port %d is - %s", __FUNCTION__, port_id, + connected ? "connected":"disconnected"); + if (err < 0) + return (int) err; + else + return connected; +} + +static int cec_device_close(struct hw_device_t *dev) +{ + ALOGD_IF(DEBUG, "%s: Close CEC HAL ", __FUNCTION__); + if (!dev) { + ALOGE("%s: NULL device pointer", __FUNCTION__); + return -EINVAL; + } + cec_context_t* ctx = (cec_context_t*)(dev); + cec_close_context(ctx); + free(dev); + return 0; +} + +static int cec_enable(cec_context_t *ctx, int enable) +{ + ssize_t err; + // Enable CEC + int value = enable ? 0x3 : 0x0; + err = write_int_to_node(ctx, "cec/enable", value); + if(err < 0) { + ALOGE("%s: Failed to toggle CEC: enable: %d", + __FUNCTION__, enable); + return (int) err; + } + ctx->enabled = enable; + return 0; +} + +static void cec_init_context(cec_context_t *ctx) +{ + ALOGD_IF(DEBUG, "%s: Initializing context", __FUNCTION__); + int err = -EINVAL; + cec_get_fb_node_number(ctx); + + //Initialize ports - We support only one output port + ctx->port_info = new hdmi_port_info[NUM_HDMI_PORTS]; + ctx->port_info[0].type = HDMI_OUTPUT; + ctx->port_info[0].port_id = 1; + ctx->port_info[0].cec_supported = 1; + //XXX: Enable ARC if supported + ctx->port_info[0].arc_supported = 0; + cec_get_physical_address((hdmi_cec_device *) ctx, + &ctx->port_info[0].physical_address ); + + ctx->version = 0x4; + ctx->vendor_id = 0xA47733; + cec_clear_logical_address((hdmi_cec_device_t*)ctx); + + //Enable CEC - framework expects it to be enabled by default + cec_enable(ctx, true); + + ALOGD("%s: CEC enabled", __FUNCTION__); + + ctx->node_list.push_back("cec_msg_event"); + ctx->node_list.push_back("hotplug_event"); + ctx->node_list.push_back("exit_event"); + + err = populate_event_data(ctx, &ctx->event_data_list); + if (err < 0) { + ALOGE("Failed to populate poll parameters for monitoring HDMI CEC events. Exiting."); + cec_enable(ctx, false); + return; + } + + ctx->hdmi_cec_monitor = std::thread(event_monitor, ctx); + +} + +static void cec_close_context(cec_context_t* ctx __unused) +{ + ALOGD("%s: Closing context", __FUNCTION__); + + uint64_t exit_value = 1; + long int write_size = write(ctx->exit_fd, &exit_value, sizeof(uint64_t)); + + if (write_size != sizeof(uint64_t)) { + ALOGE("Error triggering exit_fd (%d). write size = %ld, error = %s", + ctx->exit_fd, write_size, strerror(errno)); + return; + } + + if (ctx->hdmi_cec_monitor.joinable()) { + ctx->hdmi_cec_monitor.join(); + } +} + +static int cec_device_open(const struct hw_module_t* module, + const char* name, + struct hw_device_t** device) +{ + ALOGD_IF(DEBUG, "%s: name: %s", __FUNCTION__, name); + int status = -EINVAL; + if (!strcmp(name, HDMI_CEC_HARDWARE_INTERFACE )) { + struct cec_context_t *dev; + dev = (cec_context_t *) calloc (1, sizeof(*dev)); + if (dev) { + cec_init_context(dev); + //Setup CEC methods + dev->device.common.tag = HARDWARE_DEVICE_TAG; + dev->device.common.version = HDMI_CEC_DEVICE_API_VERSION_1_0; + dev->device.common.module = const_cast<hw_module_t* >(module); + dev->device.common.close = cec_device_close; + dev->device.add_logical_address = cec_add_logical_address; + dev->device.clear_logical_address = cec_clear_logical_address; + dev->device.get_physical_address = cec_get_physical_address; + dev->device.send_message = cec_send_message; + dev->device.register_event_callback = cec_register_event_callback; + dev->device.get_version = cec_get_version; + dev->device.get_vendor_id = cec_get_vendor_id; + dev->device.get_port_info = cec_get_port_info; + dev->device.set_option = cec_set_option; + dev->device.set_audio_return_channel = cec_set_audio_return_channel; + dev->device.is_connected = cec_is_connected; + + *device = &dev->device.common; + status = 0; + } else { + status = -EINVAL; + } + } + return status; +} + +void event_monitor(cec_context_t* ctx) { + ALOGD("%s IN", __FUNCTION__); + int err = -EINVAL; + + prctl(PR_SET_NAME, "cec_monitor", 0, 0, 0); + setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY); + + while (!ctx->cec_exit_thread) { + err = poll(ctx->poll_fds.data(), (nfds_t)ctx->event_data_list.size(), -1); + if ( err <= 0 ) { + ALOGI("Failed to poll, Error %s", strerror(errno)); + continue; + } + + for (uint32_t event = 0; event < ctx->event_data_list.size(); event++) { + pollfd &poll_fd = ctx->poll_fds[event]; + + if (poll_fd.revents & POLLIN || poll_fd.revents & POLLPRI) { + ctx->event_data_list[event].event_parser(ctx, event); + } + } + } + + cec_monitor_deinit(ctx); + ALOGD("%s OUT", __FUNCTION__); + return; +} + +static int populate_event_data(cec_context_t* ctx, std::vector<eventData> *event_data_list) { + int err = -EINVAL; + ctx->poll_fds.resize(ctx->node_list.size()); + + for (uint32_t event = 0; event < ctx->node_list.size(); event++) { + const char *event_name = ctx->node_list.at(event).c_str(); + eventData event_data; + event_data.event_name = event_name; + err = set_event_params(ctx, event, &event_data); + if (err < 0) { + ALOGE("Failed to set poll event parameters"); + return err; + } + + event_data_list->push_back(event_data); + } + + return 0; +} + +static int set_event_params(cec_context_t* ctx, uint32_t node_event, eventData *event_data) { + pollfd poll_fd; + poll_fd.fd = -EINVAL; + + if (!strncmp(event_data->event_name, "cec_msg_event", strlen("cec_msg_event"))) { + char node_path[MAX_STRING_LENGTH] = {0}; + + snprintf(node_path, sizeof(node_path), "%s%d/%s", FB_PATH, ctx->fb_num, "cec/rd_msg"); + poll_fd.fd = open(node_path, O_RDONLY); + if (poll_fd.fd < 0) { + ALOGE("Node open failed for display %d event %s error %s", + ctx->fb_num, "cec/rd_msg", strerror(errno)); + return poll_fd.fd; + } + + poll_fd.events |= POLLPRI | POLLERR; + // Read once on fd to clear the data + pread(poll_fd.fd, ctx->data, MAX_STRING_LENGTH, 0); + event_data->event_parser = &handle_cec_msg_event; + } else if (!strncmp(event_data->event_name, "hotplug_event", strlen("hotplug_event"))) { + if (!uevent_init(&poll_fd.fd)) { + ALOGE("Failed to register uevent for hotplug detection"); + return -1; + } + + poll_fd.events |= POLLIN | POLLERR; + event_data->event_parser = &handle_hdmihotplug_event; + } else if (!strncmp(event_data->event_name, "exit_event", strlen("exit_event"))) { + poll_fd.fd = eventfd(0, 0); + poll_fd.events |= POLLIN; + event_data->event_parser = &handle_exit_event; + ctx->exit_fd = poll_fd.fd; + } + + ctx->poll_fds[node_event] = poll_fd; + return 0; +} + +static void handle_cec_msg_event(cec_context_t* ctx, uint32_t node_event) { + if ((ctx->poll_fds[node_event].revents & POLLPRI) && + (pread(ctx->poll_fds[node_event].fd, ctx->data, MAX_STRING_LENGTH, 0) > 0)) { + ALOGD_IF(DEBUG, "Handling CEC message %s", __FUNCTION__); + cec_receive_message(ctx, ctx->data, 0); + } + + return; +} + +static void handle_hdmihotplug_event(cec_context_t* ctx, uint32_t node_event) { + char uevent_data[PAGE_SIZE]; + int count = 0; + + if (ctx->poll_fds[node_event].revents & POLLIN) { + count = static_cast<int> (recv(ctx->poll_fds[node_event].fd, uevent_data, + (INT32(sizeof(uevent_data))) - 2, 0)); + + if ((count > 0) && (strcasestr(UEVENT_SWITCH_HDMI, uevent_data))) { + int connected = get_event_value(uevent_data, count, "SWITCH_STATE="); + ALOGD("HDMI CEC is %s", connected ? "connected" : "disconnected"); + cec_hdmi_hotplug(ctx, connected); + } + } + + return; +} + +static void handle_exit_event(cec_context_t* ctx, uint32_t node_event) { + ALOGD_IF(DEBUG, "Enter %s", __FUNCTION__); + + if (ctx->poll_fds[node_event].revents & POLLIN) { + ctx->cec_exit_thread = true; + } + + return; +} + +static void cec_monitor_deinit(cec_context_t* ctx) { + for (uint32_t event = 0; event < ctx->poll_fds.size(); event++) { + close(ctx->poll_fds[event].fd); + ctx->poll_fds[event].fd = -1; + } +} + +static int get_event_value(const char *uevent_data, int length, const char *event_info) { + const char *iterator_str = uevent_data; + while (((iterator_str - uevent_data) <= length) && (*iterator_str)) { + const char *pstr = strstr(iterator_str, event_info); + if (pstr != NULL) { + return (atoi(iterator_str + strlen(event_info))); + } + iterator_str += strlen(iterator_str) + 1; + } + return -1; +} + +/* Returns 0 on failure, 1 on success */ +static int uevent_init(int *uevent_fd) { + struct sockaddr_nl addr; + int sz = 64*1024; + int s; + + memset(&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; + addr.nl_pid = getpid(); + addr.nl_groups = 0xffffffff; + + s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); + if (s < 0) + return 0; + + setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)); + + if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + close(s); + return 0; + } + + *uevent_fd = s; + return (*uevent_fd > 0); +} + +}; //namespace qhdmicec + +// Standard HAL module, should be outside qhdmicec namespace +static struct hw_module_methods_t cec_module_methods = { + .open = qhdmicec::cec_device_open +}; + +hdmi_module_t HAL_MODULE_INFO_SYM = { + .common = { + .tag = HARDWARE_MODULE_TAG, + .version_major = 1, + .version_minor = 0, + .id = HDMI_CEC_HARDWARE_MODULE_ID, + .name = "QTI HDMI CEC module", + .author = "The Linux Foundation", + .methods = &cec_module_methods, + } +}; diff --git a/msm8909/hdmi_cec/qhdmi_cec.h b/msm8909/hdmi_cec/qhdmi_cec.h new file mode 100644 index 00000000..e2c97552 --- /dev/null +++ b/msm8909/hdmi_cec/qhdmi_cec.h @@ -0,0 +1,91 @@ +/* +* Copyright (c) 2017 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 QHDMI_CEC_H +#define QHDMI_CEC_H + +#include <hardware/hdmi_cec.h> +#include <sys/poll.h> +#include <sys/prctl.h> +#include <sys/socket.h> +#include <sys/resource.h> +#include <linux/netlink.h> +#include <thread> +#include <vector> + +namespace qhdmicec { + +static const int MAX_STRING_LENGTH = 1024; + +struct cec_callback_t { + // Function in HDMI service to call back on CEC messages + event_callback_t callback_func; + // This stores the object to pass back to the framework + void* callback_arg; + +}; + +struct eventData; + +struct cec_context_t { + hdmi_cec_device_t device; // Device for HW module + cec_callback_t callback; // Struct storing callback object + bool enabled; + bool arc_enabled; + bool system_control; // If true, HAL/driver handle CEC messages + int fb_num; // Framebuffer node for HDMI + std::string fb_sysfs_path; + hdmi_port_info *port_info; // HDMI port info + + // Logical address is stored in an array, the index of the array is the + // logical address and the value in the index shows whether it is set or not + int logical_address[CEC_ADDR_BROADCAST]; + int version; + uint32_t vendor_id; + + std::vector<pollfd> poll_fds; // poll fds for cec message monitor and exit signal + // on cec message monitor thread + int exit_fd = -1; + bool cec_exit_thread = false; + std::thread hdmi_cec_monitor; // hdmi plugin monitor thread variable + char data[MAX_STRING_LENGTH] = {0}; + + std::vector<std::string> node_list = {}; + std::vector<eventData> event_data_list = {}; +}; + +struct eventData { + const char* event_name = NULL; + void (*event_parser)(cec_context_t* ctx, uint32_t node_event) = NULL; +}; + +void cec_receive_message(cec_context_t *ctx, char *msg, ssize_t len); +void cec_hdmi_hotplug(cec_context_t *ctx, int connected); + +}; //namespace +#endif /* end of include guard: QHDMI_CEC_H */ diff --git a/msm8909/include/Android.mk b/msm8909/include/Android.mk new file mode 100644 index 00000000..74c37afe --- /dev/null +++ b/msm8909/include/Android.mk @@ -0,0 +1,20 @@ +LOCAL_PATH:= $(call my-dir) +include $(LOCAL_PATH)/../common.mk +include $(CLEAR_VARS) + +# Legacy header copy. This is deprecated. +# Modules using these headers should shift to using +# LOCAL_HEADER_LIBRARIES := display_headers +LOCAL_VENDOR_MODULE := true +LOCAL_COPY_HEADERS_TO := $(common_header_export_path) +LOCAL_COPY_HEADERS := color_metadata.h \ + display_properties.h \ + ../libqdutils/qd_utils.h \ + ../libqdutils/qdMetaData.h \ + ../libqdutils/display_config.h \ + ../libqservice/QServiceUtils.h \ + ../libqservice/IQService.h \ + ../libqservice/IQHDMIClient.h \ + ../libqservice/IQClient.h + +include $(BUILD_COPY_HEADERS) diff --git a/msm8909/include/color_metadata.h b/msm8909/include/color_metadata.h new file mode 100644 index 00000000..aff6fc93 --- /dev/null +++ b/msm8909/include/color_metadata.h @@ -0,0 +1,189 @@ +/* +* 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 __COLOR_METADATA_H__ +#define __COLOR_METADATA_H__ + +#ifdef __cplusplus +extern "C" { +#else +#include <stdbool.h> +#endif + +typedef enum ColorRange { + Range_Limited = 0, + Range_Full = 1, + Range_Max = 0xff, +} ColorRange; + +// The following values matches the HEVC spec +typedef enum ColorPrimaries { + // Unused = 0; + ColorPrimaries_BT709_5 = 1, // ITU-R BT.709-5 or equivalent + /* Unspecified = 2, Reserved = 3*/ + ColorPrimaries_BT470_6M = 4, // ITU-R BT.470-6 System M or equivalent + ColorPrimaries_BT601_6_625 = 5, // ITU-R BT.601-6 625 or equivalent + ColorPrimaries_BT601_6_525 = 6, // ITU-R BT.601-6 525 or equivalent + ColorPrimaries_SMPTE_240M = 7, // SMPTE_240M + ColorPrimaries_GenericFilm = 8, // Generic Film + ColorPrimaries_BT2020 = 9, // ITU-R BT.2020 or equivalent + ColorPrimaries_SMPTE_ST428 = 10, // SMPTE_240M + ColorPrimaries_AdobeRGB = 11, + ColorPrimaries_DCIP3 = 12, + ColorPrimaries_EBU3213 = 22, + ColorPrimaries_Max = 0xff, +} ColorPrimaries; + +typedef enum GammaTransfer { + // Unused = 0; + Transfer_sRGB = 1, // ITR-BT.709-5 + /* Unspecified = 2, Reserved = 3 */ + Transfer_Gamma2_2 = 4, + Transfer_Gamma2_8 = 5, + Transfer_SMPTE_170M = 6, // BT.601-6 525 or 625 + Transfer_SMPTE_240M = 7, // SMPTE_240M + Transfer_Linear = 8, + Transfer_Log = 9, + Transfer_Log_Sqrt = 10, + Transfer_XvYCC = 11, // IEC 61966-2-4 + Transfer_BT1361 = 12, // Rec.ITU-R BT.1361 extended gamut + Transfer_sYCC = 13, // IEC 61966-2-1 sRGB or sYCC + Transfer_BT2020_2_1 = 14, // Rec. ITU-R BT.2020-2 (same as the values 1, 6, and 15) + Transfer_BT2020_2_2 = 15, // Rec. ITU-R BT.2020-2 (same as the values 1, 6, and 14) + Transfer_SMPTE_ST2084 = 16, // 2084 + // transfers unlikely to be required by Android + Transfer_ST_428 = 17, // SMPTE ST 428-1 + Transfer_HLG = 18, // ARIB STD-B67 + Transfer_Max = 0xff, +} GammaTransfer; + +typedef enum MatrixCoEfficients { + MatrixCoEff_Identity = 0, + MatrixCoEff_BT709_5 = 1, + /* Unspecified = 2, Reserved = 3 */ + MatrixCoeff_FCC_73_682 = 4, + MatrixCoEff_BT601_6_625 = 5, + MatrixCoEff_BT601_6_525 = 6, + MatrixCoEff_SMPTE240M = 7, // used with 601_525_Unadjusted + MatrixCoEff_YCgCo = 8, + MatrixCoEff_BT2020 = 9, + MatrixCoEff_BT2020Constant = 10, + MatrixCoEff_BT601_6_Unadjusted = 11, // Used with BT601_625(KR=0.222, KB=0.071) + MatrixCoEff_DCIP3 = 12, + MatrixCoEff_Chroma_NonConstant = 13, + MatrixCoEff_Max = 0xff, +} MatrixCoEfficients; + +typedef struct Primaries { + uint32_t rgbPrimaries[3][2]; // unit 1/50000; + uint32_t whitePoint[2]; // unit 1/50000; +} Primaries; + +typedef struct MasteringDisplay { + bool colorVolumeSEIEnabled; + Primaries primaries; + uint32_t maxDisplayLuminance; // unit: cd/m^2. + uint32_t minDisplayLuminance; // unit: 1/10000 cd/m^2. +} MasteringDisplay; + +typedef struct ContentLightLevel { + bool lightLevelSEIEnabled; + uint32_t maxContentLightLevel; // unit: cd/m^2. + uint32_t minPicAverageLightLevel; // unit: 1/10000 cd/m^2. +} ContentLightLevel; + +typedef struct ColorRemappingInfo { + bool criEnabled; + uint32_t crId; + uint32_t crCancelFlag; + uint32_t crPersistenceFlag; + uint32_t crVideoSignalInfoPresentFlag; + uint32_t crRange; + ColorPrimaries crPrimaries; + GammaTransfer crTransferFunction; + MatrixCoEfficients crMatrixCoefficients; + uint32_t crInputBitDepth; + uint32_t crOutputBitDepth; + uint32_t crPreLutNumValMinusOne[3]; + uint32_t crPreLutCodedValue[3*33]; + uint32_t crPreLutTargetValue[3*33]; + uint32_t crMatrixPresentFlag; + uint32_t crLog2MatrixDenom; + int32_t crCoefficients[3*3]; + uint32_t crPostLutNumValMinusOne[3]; + uint32_t crPostLutCodedValue[3*33]; + uint32_t crPostLutTargetValue[3*33]; +} ColorRemappingInfo; + +typedef struct ColorMetaData { + // Default values based on sRGB, needs to be overridden in gralloc + // based on the format and size. + ColorPrimaries colorPrimaries; + ColorRange range; + GammaTransfer transfer; + MatrixCoEfficients matrixCoefficients; + + MasteringDisplay masteringDisplayInfo; + ContentLightLevel contentLightLevel; + ColorRemappingInfo cRI; +} ColorMetaData; + +typedef struct Color10Bit { + uint32_t R: 10; + uint32_t G: 10; + uint32_t B: 10; + uint32_t A: 2; +} Color10Bit; + +typedef struct Lut3d { + uint16_t dim; // dimension of each side of LUT cube (ex: 13, 17)in lutEntries + uint16_t gridSize; // number of elements in the gridEntries + /* Matrix ordering convension + for (b = 0; b < dim; b++) { + for (g = 0; g < dim; g++) { + for (r = 0; r < dim; r++) { + read/write [mR mG mB] associated w/ 3DLUT[r][g][b] to/from file + } + } + } */ + Color10Bit *lutEntries; + bool validLutEntries; // Indicates if entries are valid and can be used. + /* + The grid is a 1D LUT for each of the R,G,B channels that can be + used to apply an independent nonlinear transformation to each + channel before it is used as a coordinate for addressing + the uniform 3D LUT. This effectively creates a non-uniformly + sampled 3D LUT. This is useful for having independent control + of the sampling grid density along each dimension for greater + precision in spite of having a relatively small number of samples.i + */ + Color10Bit *gridEntries; + bool validGridEntries; // Indicates if entries are valid and can be used. +} Lut3d; + +#ifdef __cplusplus +} +#endif + +#endif // __COLOR_METADATA_H__ diff --git a/msm8909/include/display_properties.h b/msm8909/include/display_properties.h new file mode 100644 index 00000000..b9c8971a --- /dev/null +++ b/msm8909/include/display_properties.h @@ -0,0 +1,101 @@ +/* +* Copyright (c) 2018, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __DISPLAY_PROPERTIES_H__ +#define __DISPLAY_PROPERTIES_H__ + +#define DISP_PROP_PREFIX "vendor.display." +#define GRALLOC_PROP_PREFIX "vendor.gralloc." +#define RO_DISP_PROP_PREFIX "ro.vendor.display." +#define PERSIST_DISP_PROP_PREFIX "persist.vendor.display." + +#define DISPLAY_PROP(prop_name) DISP_PROP_PREFIX prop_name +#define GRALLOC_PROP(prop_name) GRALLOC_PROP_PREFIX prop_name +#define RO_DISPLAY_PROP(prop_name) RO_DISP_PROP_PREFIX prop_name +#define PERSIST_DISPLAY_PROP(prop_name) PERSIST_DISP_PROP_PREFIX prop_name + +#define COMPOSITION_MASK_PROP DISPLAY_PROP("comp_mask") +#define HDMI_CONFIG_INDEX_PROP DISPLAY_PROP("hdmi_cfg_idx") +#define IDLE_TIME_PROP DISPLAY_PROP("idle_time") +#define IDLE_TIME_INACTIVE_PROP DISPLAY_PROP("idle_time_inactive") +#define BOOT_ANIMATION_LAYER_COUNT_PROP DISPLAY_PROP("boot_anim_layer_count") +#define DISABLE_ROTATOR_DOWNSCALE_PROP DISPLAY_PROP("disable_rotator_downscale") +#define DISABLE_DECIMATION_PROP DISPLAY_PROP("disable_decimation") +#define PRIMARY_MIXER_STAGES_PROP DISPLAY_PROP("primary_mixer_stages") +#define EXTERNAL_MIXER_STAGES_PROP DISPLAY_PROP("external_mixer_stages") +#define VIRTUAL_MIXER_STAGES_PROP DISPLAY_PROP("virtual_mixer_stages") +#define MAX_UPSCALE_PROP DISPLAY_PROP("max_upscale") +#define VIDEO_MODE_PANEL_PROP DISPLAY_PROP("video_mode_panel") +#define DISABLE_ROTATOR_UBWC_PROP DISPLAY_PROP("disable_rotator_ubwc") +#define DISABLE_ROTATOR_SPLIT_PROP DISPLAY_PROP("disable_rotator_split") +#define DISABLE_SCALER_PROP DISPLAY_PROP("disable_scaler") +#define DISABLE_AVR_PROP DISPLAY_PROP("disable_avr") +#define DISABLE_EXTERNAL_ANIMATION_PROP DISPLAY_PROP("disable_ext_anim") +#define DISABLE_PARTIAL_SPLIT_PROP DISPLAY_PROP("disable_partial_split") +#define PREFER_SOURCE_SPLIT_PROP DISPLAY_PROP("prefer_source_split") +#define MIXER_RESOLUTION_PROP DISPLAY_PROP("mixer_resolution") +#define SIMULATED_CONFIG_PROP DISPLAY_PROP("simulated_config") +#define MAX_EXTERNAL_LAYERS_PROP DISPLAY_PROP("max_external_layers") +#define PERF_HINT_WINDOW_PROP DISPLAY_PROP("perf_hint_window") +#define ENABLE_EXTERNAL_DOWNSCALE_PROP DISPLAY_PROP("enable_external_downscale") +#define EXTERNAL_ACTION_SAFE_WIDTH_PROP DISPLAY_PROP("external_action_safe_width") +#define EXTERNAL_ACTION_SAFE_HEIGHT_PROP DISPLAY_PROP("external_action_safe_height") +#define FB_WIDTH_PROP DISPLAY_PROP("fb_width") +#define FB_HEIGHT_PROP DISPLAY_PROP("fb_height") +#define DISABLE_METADATA_DYNAMIC_FPS_PROP DISPLAY_PROP("disable_metadata_dynamic_fps") +#define DISABLE_BLIT_COMPOSITION_PROP DISPLAY_PROP("disable_blit_comp") +#define DISABLE_SKIP_VALIDATE_PROP DISPLAY_PROP("disable_skip_validate") +#define HDMI_S3D_MODE_PROP DISPLAY_PROP("hdmi_s3d_mode") +#define DISABLE_DESTINATION_SCALER_PROP DISPLAY_PROP("disable_dest_scaler") +#define ENABLE_PARTIAL_UPDATE_PROP DISPLAY_PROP("enable_partial_update") +#define ENABLE_ROTATOR_SYNC_ALLOC DISPLAY_PROP("rotator_sync_alloc") +#define WRITEBACK_SUPPORTED DISPLAY_PROP("support_writeback") +#define DISABLE_UBWC_PROP GRALLOC_PROP("disable_ubwc") +#define ENABLE_FB_UBWC_PROP GRALLOC_PROP("enable_fb_ubwc") +#define MAP_FB_MEMORY_PROP GRALLOC_PROP("map_fb_memory") + +#define MAX_BLIT_FACTOR_PROP DISPLAY_PROP("max_blit_factor") +#define DISABLE_SECURE_INLINE_ROTATOR_PROP DISPLAY_PROP("disable_secure_inline_rotator") +#define DISABLE_MULTIRECT_PROP DISPLAY_PROP("disable_multirect") +#define DISABLE_UBWC_FF_VOTING_PROP DISPLAY_PROP("disable_ubwc_ff_voting") +#define DISABLE_INLINE_ROTATOR_PROP DISPLAY_PROP("disable_inline_rotator") +#define DISABLE_FB_CROPPING_PROP DISPLAY_PROP("disable_fb_cropping") +#define PRIORITIZE_CACHE_COMPOSITION_PROP DISPLAY_PROP("prioritize_cache_comp") + +#define DISABLE_HDR_LUT_GEN DISPLAY_PROP("disable_hdr_lut_gen") +#define ENABLE_DEFAULT_COLOR_MODE DISPLAY_PROP("enable_default_color_mode") +#define DISABLE_HDR DISPLAY_PROP("disable_hdr") + +#define HDR_CONFIG_PROP RO_DISPLAY_PROP("hdr.config") +#define QDCM_PCC_TRANS_PROP DISPLAY_PROP("qdcm.pcc_for_trans") +#define QDCM_DIAGONAL_MATRIXMODE_PROP DISPLAY_PROP("qdcm.diagonal_matrix_mode") +#define QDCM_DISABLE_TIMEOUT_PROP PERSIST_DISPLAY_PROP("qdcm.disable_timeout") + + +#endif // __DISPLAY_PROPERTIES_H__ diff --git a/msm8909/libcopybit/Android.mk b/msm8909/libcopybit/Android.mk index f2c78b21..6e906c36 100644 --- a/msm8909/libcopybit/Android.mk +++ b/msm8909/libcopybit/Android.mk @@ -14,22 +14,24 @@ LOCAL_PATH:= $(call my-dir) include $(LOCAL_PATH)/../common.mk - include $(CLEAR_VARS) + LOCAL_COPY_HEADERS_TO := $(common_header_export_path) LOCAL_COPY_HEADERS := copybit.h copybit_priv.h c2d2.h +#Copy the headers regardless of whether copybit is built include $(BUILD_COPY_HEADERS) include $(CLEAR_VARS) +ifneq ($(TARGET_USES_GRALLOC1), true) LOCAL_MODULE := copybit.$(TARGET_BOARD_PLATFORM) +LOCAL_VENDOR_MODULE := true LOCAL_MODULE_RELATIVE_PATH := hw -LOCAL_PROPRIETARY_MODULE := true LOCAL_MODULE_TAGS := optional LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes) LOCAL_SHARED_LIBRARIES := $(common_libs) libdl libmemalloc -LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdcopybit\" +LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdcopybit\" -Wno-sign-conversion LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) -LOCAL_CLANG := $(common_clang_flags) +LOCAL_CLANG := true ifeq ($(TARGET_USES_C2D_COMPOSITION),true) LOCAL_CFLAGS += -DCOPYBIT_Z180=1 -DC2D_SUPPORT_DISPLAY=1 @@ -48,3 +50,4 @@ else endif endif endif +endif diff --git a/msm8909/libcopybit/c2d2.h b/msm8909/libcopybit/c2d2.h index 886f38a2..315a3ba5 100644 --- a/msm8909/libcopybit/c2d2.h +++ b/msm8909/libcopybit/c2d2.h @@ -72,6 +72,7 @@ typedef enum { C2D_FORMAT_MACROTILED = (1 << 16), /* tiled in macro level */ C2D_FORMAT_TILED_4x4 = (1 << 17), /* 4x4 tiled format */ C2D_FORMAT_SWAP_RB = (1 << 18), /* Swap R & B color components */ + C2D_FORMAT_UBWC_COMPRESSED = (1 << 23), /* UBWC compressed format */ } C2D_FORMAT_MODE; /* Definitions of supported RGB formats, used in C2D_RGB_SURFACE_DEF. @@ -408,7 +409,8 @@ typedef enum { C2D_DRIVER_SUPPORTS_TARGET_RECT_OP = (1 << 15), C2D_DRIVER_SUPPORTS_ROTATE_OP = (1 << 16), /* all rotations */ C2D_DRIVER_SUPPORTS_FLUSH_WITH_FENCE_FD_OP = (1 << 17), /* all rotations */ - C2D_DRIVER_SUPPORTS_ALL_CAPABILITIES_OP = ((0xFFFFFFFF) >> (31 - 17)) /* mask for all capabilities supported */ + C2D_DRIVER_SUPPORTS_UBWC_COMPRESSED_OP = (1 << 18), /* UBWC Compression */ + C2D_DRIVER_SUPPORTS_ALL_CAPABILITIES_OP = ((0xFFFFFFFF) >> (31 - 18)) /* mask for all capabilities supported */ } C2D_DRIVER_CAPABILITIES; /* 2D driver workaround bits used by the 2D applications */ diff --git a/msm8909/libcopybit/copybit.cpp b/msm8909/libcopybit/copybit.cpp index c2790f8d..bd49edc2 100644 --- a/msm8909/libcopybit/copybit.cpp +++ b/msm8909/libcopybit/copybit.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 The Android Open Source Project - * Copyright (c) 2010 - 2014,2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2010 - 2014, The Linux Foundation. All rights reserved. * * Not a Contribution, Apache license notifications and license are retained * for attribution purposes only. @@ -18,7 +18,7 @@ * limitations under the License. */ -#include <cutils/log.h> +#include <log/log.h> #include <linux/msm_mdp.h> #include <linux/fb.h> @@ -75,22 +75,22 @@ static int open_copybit(const struct hw_module_t* module, const char* name, struct hw_device_t** device); static struct hw_module_methods_t copybit_module_methods = { - .open = open_copybit +open: open_copybit }; /* * The COPYBIT Module */ struct copybit_module_t HAL_MODULE_INFO_SYM = { - .common = { - .tag = HARDWARE_MODULE_TAG, - .version_major = 1, - .version_minor = 0, - .id = COPYBIT_HARDWARE_MODULE_ID, - .name = "QCT MSM7K COPYBIT Module", - .author = "Google, Inc.", - .methods = ©bit_module_methods - } +common: { +tag: HARDWARE_MODULE_TAG, + version_major: 1, + version_minor: 0, + id: COPYBIT_HARDWARE_MODULE_ID, + name: "QCT MSM7K COPYBIT Module", + author: "Google, Inc.", + methods: ©bit_module_methods + } }; /******************************************************************************/ @@ -131,6 +131,8 @@ static bool validateCopybitRect(struct copybit_rect_t *rect) { static int get_format(int format) { switch (format) { case HAL_PIXEL_FORMAT_RGB_565: return MDP_RGB_565; + case HAL_PIXEL_FORMAT_RGBA_5551: return MDP_RGBA_5551; + case HAL_PIXEL_FORMAT_RGBA_4444: return MDP_RGBA_4444; case HAL_PIXEL_FORMAT_RGBX_8888: return MDP_RGBX_8888; case HAL_PIXEL_FORMAT_BGRX_8888: return MDP_BGRX_8888; case HAL_PIXEL_FORMAT_RGB_888: return MDP_RGB_888; @@ -144,7 +146,10 @@ static int get_format(int format) { case HAL_PIXEL_FORMAT_YCbCr_420_SP: return MDP_Y_CBCR_H2V2; case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: return MDP_Y_CBCR_H2V2_ADRENO; case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: return MDP_Y_CBCR_H2V2_VENUS; + case HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS: return MDP_Y_CRCB_H2V2_VENUS; case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: return MDP_Y_CBCR_H2V2; + case HAL_PIXEL_FORMAT_CbYCrY_422_I: return MDP_CBYCRY_H2V1; + case HAL_PIXEL_FORMAT_BGR_888: return MDP_BGR_888; } return -1; } @@ -454,6 +459,8 @@ static int stretch_copybit( // we don't support plane alpha with RGBA formats case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_BGRA_8888: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: ALOGE ("%s : Unsupported Pixel format %d", __FUNCTION__, src->format); return -EINVAL; diff --git a/msm8909/libcopybit/copybit.h b/msm8909/libcopybit/copybit.h index b4af0214..de585ee3 100644 --- a/msm8909/libcopybit/copybit.h +++ b/msm8909/libcopybit/copybit.h @@ -49,6 +49,8 @@ enum { COPYBIT_FORMAT_RGB_888 = HAL_PIXEL_FORMAT_RGB_888, COPYBIT_FORMAT_RGB_565 = HAL_PIXEL_FORMAT_RGB_565, COPYBIT_FORMAT_BGRA_8888 = HAL_PIXEL_FORMAT_BGRA_8888, + COPYBIT_FORMAT_RGBA_5551 = HAL_PIXEL_FORMAT_RGBA_5551, + COPYBIT_FORMAT_RGBA_4444 = HAL_PIXEL_FORMAT_RGBA_4444, COPYBIT_FORMAT_YCbCr_422_SP = 0x10, COPYBIT_FORMAT_YCrCb_420_SP = 0x11, }; @@ -78,6 +80,10 @@ enum { COPYBIT_FRAMEBUFFER_HEIGHT = 8, COPYBIT_FG_LAYER = 9, COPYBIT_DYNAMIC_FPS = 10, + /* Source Format Mode */ + COPYBIT_SRC_FORMAT_MODE = 11, + /* Destination Format Mode */ + COPYBIT_DST_FORMAT_MODE = 12, }; /* values for copybit_set_parameter(COPYBIT_TRANSFORM) */ @@ -114,6 +120,13 @@ enum { COPYBIT_BLENDING_COVERAGE = 0x0405 }; +enum { + /* Linear format mode*/ + COPYBIT_LINEAR = 0x0000, + /* UBWC format mode*/ + COPYBIT_UBWC_COMPRESSED = 0x0001, +}; + /* use get_static_info() to query static informations about the hardware */ enum { /* Maximum amount of minification supported by the hardware*/ @@ -124,6 +137,8 @@ enum { COPYBIT_SCALING_FRAC_BITS = 3, /* Supported rotation step in degres. */ COPYBIT_ROTATION_STEP_DEG = 4, + /* UBWC support*/ + COPYBIT_UBWC_SUPPORT = 5, }; /* Image structure */ diff --git a/msm8909/libcopybit/copybit_c2d.cpp b/msm8909/libcopybit/copybit_c2d.cpp index 43408555..63c13790 100644 --- a/msm8909/libcopybit/copybit_c2d.cpp +++ b/msm8909/libcopybit/copybit_c2d.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 The Android Open Source Project - * Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2015, The Linux Foundation. All rights reserved. * * Not a Contribution, Apache license notifications and license are retained * for attribution purposes only. @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include <cutils/log.h> +#include <log/log.h> #include <sys/resource.h> #include <sys/prctl.h> @@ -124,7 +124,8 @@ enum eConversionType { enum eC2DFlags { FLAGS_PREMULTIPLIED_ALPHA = 1<<0, FLAGS_YUV_DESTINATION = 1<<1, - FLAGS_TEMP_SRC_DST = 1<<2 + FLAGS_TEMP_SRC_DST = 1<<2, + FLAGS_UBWC_FORMAT_MODE = 1<<3 }; static gralloc::IAllocController* sAlloc = 0; @@ -159,6 +160,8 @@ struct copybit_context_t { void* time_stamp; bool dst_surface_mapped; // Set when dst surface is mapped to GPU addr void* dst_surface_base; // Stores the dst surface addr + bool is_src_ubwc_format; + bool is_dst_ubwc_format; // used for signaling the wait thread bool wait_timestamp; @@ -264,6 +267,8 @@ static int get_format(int format) { case HAL_PIXEL_FORMAT_RGBA_8888: return C2D_COLOR_FORMAT_8888_ARGB | C2D_FORMAT_SWAP_RB; case HAL_PIXEL_FORMAT_BGRA_8888: return C2D_COLOR_FORMAT_8888_ARGB; + case HAL_PIXEL_FORMAT_RGBA_5551: return C2D_COLOR_FORMAT_5551_RGBA; + case HAL_PIXEL_FORMAT_RGBA_4444: return C2D_COLOR_FORMAT_4444_RGBA; case HAL_PIXEL_FORMAT_YCbCr_420_SP: return C2D_COLOR_FORMAT_420_NV12; case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:return C2D_COLOR_FORMAT_420_NV12; case HAL_PIXEL_FORMAT_YCrCb_420_SP: return C2D_COLOR_FORMAT_420_NV21; @@ -348,12 +353,7 @@ static size_t c2d_get_gpuaddr(copybit_context_t* ctx, if(!handle) return 0; - if (handle->flags & (private_handle_t::PRIV_FLAGS_USES_PMEM | - private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP)) - memtype = KGSL_USER_MEM_TYPE_PMEM; - else if (handle->flags & private_handle_t::PRIV_FLAGS_USES_ASHMEM) - memtype = KGSL_USER_MEM_TYPE_ASHMEM; - else if (handle->flags & private_handle_t::PRIV_FLAGS_USES_ION) + if (handle->flags & private_handle_t::PRIV_FLAGS_USES_ION) memtype = KGSL_USER_MEM_TYPE_ION; else { ALOGE("Invalid handle flags: 0x%x", handle->flags); @@ -402,7 +402,9 @@ static int is_supported_rgb_format(int format) case HAL_PIXEL_FORMAT_RGBX_8888: case HAL_PIXEL_FORMAT_RGB_888: case HAL_PIXEL_FORMAT_RGB_565: - case HAL_PIXEL_FORMAT_BGRA_8888: { + case HAL_PIXEL_FORMAT_BGRA_8888: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: { return COPYBIT_SUCCESS; } default: @@ -544,6 +546,10 @@ static int set_image(copybit_context_t* ctx, uint32 surfaceId, surfaceDef.format = c2d_format | ((flags & FLAGS_PREMULTIPLIED_ALPHA) ? C2D_FORMAT_PREMULTIPLIED : 0); + + surfaceDef.format = surfaceDef.format | + ((flags & FLAGS_UBWC_FORMAT_MODE) ? C2D_FORMAT_UBWC_COMPRESSED : 0); + surfaceDef.width = rhs->w; surfaceDef.height = rhs->h; int aligned_width = ALIGN((int)surfaceDef.width,32); @@ -700,6 +706,8 @@ static int clear_copybit(struct copybit_device_t *dev, int flags = FLAGS_PREMULTIPLIED_ALPHA; int mapped_dst_idx = -1; struct copybit_context_t* ctx = (struct copybit_context_t*)dev; + if (ctx->is_dst_ubwc_format) + flags |= FLAGS_UBWC_FORMAT_MODE; C2D_RECT c2drect = {rect->l, rect->t, rect->r - rect->l, rect->b - rect->t}; pthread_mutex_lock(&ctx->wait_cleanup_lock); if(!ctx->dst_surface_mapped) { @@ -865,6 +873,12 @@ static int set_parameter_copybit( case COPYBIT_BLIT_TO_FRAMEBUFFER: // Do nothing break; + case COPYBIT_SRC_FORMAT_MODE: + ctx->is_src_ubwc_format = (value == COPYBIT_UBWC_COMPRESSED); + break; + case COPYBIT_DST_FORMAT_MODE: + ctx->is_dst_ubwc_format = (value == COPYBIT_UBWC_COMPRESSED); + break; default: ALOGE("%s: default case param=0x%x", __FUNCTION__, name); status = -EINVAL; @@ -898,6 +912,12 @@ static int get(struct copybit_device_t *dev, int name) case COPYBIT_ROTATION_STEP_DEG: value = 1; break; + case COPYBIT_UBWC_SUPPORT: + value = 0; + if (ctx->c2d_driver_info.capabilities_mask & C2D_DRIVER_SUPPORTS_UBWC_COMPRESSED_OP) { + value = 1; + } + break; default: ALOGE("%s: default case param=0x%x", __FUNCTION__, name); value = -EINVAL; @@ -980,7 +1000,7 @@ static int get_temp_buffer(const bufferInfo& info, alloc_data& data) data.size = get_size(info); data.align = getpagesize(); data.uncached = true; - int allocFlags = GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP; + int allocFlags = 0; if (sAlloc == 0) { sAlloc = gralloc::IAllocController::getInstance(); @@ -1103,6 +1123,9 @@ static int stretch_copybit_internal( } int dst_surface_type; + if (ctx->is_dst_ubwc_format) + flags |= FLAGS_UBWC_FORMAT_MODE; + if (is_supported_rgb_format(dst->format) == COPYBIT_SUCCESS) { dst_surface_type = RGB_SURFACE; flags |= FLAGS_PREMULTIPLIED_ALPHA; @@ -1285,6 +1308,7 @@ static int stretch_copybit_internal( flags |= (ctx->is_premultiplied_alpha) ? FLAGS_PREMULTIPLIED_ALPHA : 0; flags |= (ctx->dst_surface_type != RGB_SURFACE) ? FLAGS_YUV_DESTINATION : 0; + flags |= (ctx->is_src_ubwc_format) ? FLAGS_UBWC_FORMAT_MODE : 0; status = set_image(ctx, src_surface.surface_id, &src_image, (eC2DFlags)flags, mapped_src_idx); if(status) { diff --git a/msm8909/libcopybit/software_converter.cpp b/msm8909/libcopybit/software_converter.cpp index 5b41d41a..1aa3ce60 100644 --- a/msm8909/libcopybit/software_converter.cpp +++ b/msm8909/libcopybit/software_converter.cpp @@ -27,8 +27,7 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <cutils/log.h> -#include <string.h> +#include <log/log.h> #include <stdlib.h> #include <errno.h> #include "software_converter.h" diff --git a/msm8909/libcopybit/software_converter.h b/msm8909/libcopybit/software_converter.h index 6e53e164..cc6ae342 100644 --- a/msm8909/libcopybit/software_converter.h +++ b/msm8909/libcopybit/software_converter.h @@ -31,11 +31,12 @@ #include <copybit.h> #include "gralloc_priv.h" -#include "gr.h" #define COPYBIT_SUCCESS 0 #define COPYBIT_FAILURE -1 +#define ALIGN(x, y) (((x) + y - 1) & (~(y - 1))) + int convertYV12toYCrCb420SP(const copybit_image_t *src,private_handle_t *yv12_handle); /* diff --git a/msm8909/libdisplayconfig/Android.mk b/msm8909/libdisplayconfig/Android.mk new file mode 100644 index 00000000..3d44444c --- /dev/null +++ b/msm8909/libdisplayconfig/Android.mk @@ -0,0 +1,13 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := libdisplayconfig +LOCAL_MODULE_TAGS := optional +LOCAL_C_INCLUDES := $(common_includes) +LOCAL_HEADER_LIBRARIES := display_headers +LOCAL_SRC_FILES := DisplayConfig.cpp +LOCAL_SHARED_LIBRARIES := libhidlbase libhidltransport libutils \ + vendor.display.config@1.0 +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) + +include $(BUILD_SHARED_LIBRARY) diff --git a/msm8909/libdisplayconfig/DisplayConfig.cpp b/msm8909/libdisplayconfig/DisplayConfig.cpp new file mode 100644 index 00000000..29fcc940 --- /dev/null +++ b/msm8909/libdisplayconfig/DisplayConfig.cpp @@ -0,0 +1,363 @@ +/* +* Copyright (c) 2017 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 <vendor/display/config/1.0/IDisplayConfig.h> + +#include "DisplayConfig.h" + +namespace display { + +using vendor::display::config::V1_0::IDisplayConfig; + +//============================================================================= +// The functions below run in the client process and wherever necessary +// do a binder call to HWC to get/set data. + +IDisplayConfig::DisplayType MapDisplayType(int dpy) { + switch (dpy) { + case DISPLAY_PRIMARY: + return IDisplayConfig::DisplayType::DISPLAY_PRIMARY; + + case DISPLAY_EXTERNAL: + return IDisplayConfig::DisplayType::DISPLAY_EXTERNAL; + + case DISPLAY_VIRTUAL: + return IDisplayConfig::DisplayType::DISPLAY_VIRTUAL; + + default: + break; + } + + return IDisplayConfig::DisplayType::INVALID; +} + +IDisplayConfig::DisplayExternalStatus MapExternalStatus(uint32_t status) { + switch (status) { + case EXTERNAL_OFFLINE: + return IDisplayConfig::DisplayExternalStatus::EXTERNAL_OFFLINE; + + case EXTERNAL_ONLINE: + return IDisplayConfig::DisplayExternalStatus::EXTERNAL_ONLINE; + + case EXTERNAL_PAUSE: + return IDisplayConfig::DisplayExternalStatus::EXTERNAL_PAUSE; + + case EXTERNAL_RESUME: + return IDisplayConfig::DisplayExternalStatus::EXTERNAL_RESUME; + + default: + break; + } + + return IDisplayConfig::DisplayExternalStatus::INVALID; +} + +IDisplayConfig::DisplayDynRefreshRateOp MapDynRefreshRateOp(uint32_t op) { + switch (op) { + case DISABLE_METADATA_DYN_REFRESH_RATE: + return IDisplayConfig::DisplayDynRefreshRateOp::DISABLE_METADATA_DYN_REFRESH_RATE; + + case ENABLE_METADATA_DYN_REFRESH_RATE: + return IDisplayConfig::DisplayDynRefreshRateOp::ENABLE_METADATA_DYN_REFRESH_RATE; + + case SET_BINDER_DYN_REFRESH_RATE: + return IDisplayConfig::DisplayDynRefreshRateOp::SET_BINDER_DYN_REFRESH_RATE; + + default: + break; + } + + return IDisplayConfig::DisplayDynRefreshRateOp::INVALID; +} + +int MapDisplayPortType(IDisplayConfig::DisplayPortType panelType) { + switch (panelType) { + case IDisplayConfig::DisplayPortType::DISPLAY_PORT_DEFAULT: + return DISPLAY_PORT_DEFAULT; + + case IDisplayConfig::DisplayPortType::DISPLAY_PORT_DSI: + return DISPLAY_PORT_DSI; + + case IDisplayConfig::DisplayPortType::DISPLAY_PORT_DTV: + return DISPLAY_PORT_DTV; + + case IDisplayConfig::DisplayPortType::DISPLAY_PORT_WRITEBACK: + return DISPLAY_PORT_WRITEBACK; + + case IDisplayConfig::DisplayPortType::DISPLAY_PORT_LVDS: + return DISPLAY_PORT_LVDS; + + case IDisplayConfig::DisplayPortType::DISPLAY_PORT_EDP: + return DISPLAY_PORT_EDP; + + case IDisplayConfig::DisplayPortType::DISPLAY_PORT_DP: + return DISPLAY_PORT_DP; + + default: + break; + } + + return -1; +} + +int isExternalConnected() { + android::sp<IDisplayConfig> intf = IDisplayConfig::getService(); + if (intf == NULL) { + return 0; + } + + int connected = 0; + intf->isDisplayConnected(IDisplayConfig::DisplayType::DISPLAY_EXTERNAL, + [&](const auto &tmpError, const auto &tmpStatus) { + if (tmpError) { + return; + } + + connected = tmpStatus; + }); + + return connected; +} + +int setSecondayDisplayStatus(int dpy, uint32_t status) { + android::sp<IDisplayConfig> intf = IDisplayConfig::getService(); + if (intf == NULL) { + return -1; + } + + return intf->setSecondayDisplayStatus(MapDisplayType(dpy), MapExternalStatus(status)); +} + +int configureDynRefeshRate(uint32_t op, uint32_t refreshRate) { + android::sp<IDisplayConfig> intf = IDisplayConfig::getService(); + if (intf == NULL) { + return -1; + } + + return intf->configureDynRefeshRate(MapDynRefreshRateOp(op), refreshRate); +} + +int getConfigCount(int dpy) { + android::sp<IDisplayConfig> intf = IDisplayConfig::getService(); + if (intf == NULL) { + return -1; + } + + int count = 0; + intf->getConfigCount(MapDisplayType(dpy), + [&](const auto &tmpError, const auto &tmpCount) { + if (tmpError) { + return; + } + + count = tmpCount; + }); + + return count; +} + +int getActiveConfig(int dpy) { + android::sp<IDisplayConfig> intf = IDisplayConfig::getService(); + if (intf == NULL) { + return -1; + } + + int config = 0; + intf->getActiveConfig(MapDisplayType(dpy), + [&](const auto &tmpError, const auto &tmpConfig) { + if (tmpError) { + return; + } + + config = tmpConfig; + }); + + return config; +} + +int setActiveConfig(int dpy, uint32_t config) { + android::sp<IDisplayConfig> intf = IDisplayConfig::getService(); + if (intf == NULL) { + return -1; + } + + return intf->setActiveConfig(MapDisplayType(dpy), config); +} + +DisplayAttributes getDisplayAttributes(uint32_t configIndex, int dpy) { + DisplayAttributes attributes; + + android::sp<IDisplayConfig> intf = IDisplayConfig::getService(); + if (intf == NULL) { + return attributes; + } + + intf->getDisplayAttributes(configIndex, MapDisplayType(dpy), + [&](const auto &tmpError, const auto &tmpAttributes) { + if (tmpError) { + return; + } + + attributes.vsync_period = tmpAttributes.vsyncPeriod; + attributes.xres = tmpAttributes.xRes; + attributes.yres = tmpAttributes.yRes; + attributes.xdpi = tmpAttributes.xDpi; + attributes.ydpi = tmpAttributes.yDpi; + attributes.panel_type = MapDisplayPortType(tmpAttributes.panelType); + attributes.is_yuv = tmpAttributes.isYuv; + }); + + return attributes; +} + +int setPanelBrightness(uint32_t level) { + android::sp<IDisplayConfig> intf = IDisplayConfig::getService(); + if (intf == NULL) { + return -1; + } + + return intf->setPanelBrightness(level); +} + +uint32_t getPanelBrightness() { + android::sp<IDisplayConfig> intf = IDisplayConfig::getService(); + if (intf == NULL) { + return 0; + } + + int level = 0; + intf->getPanelBrightness( + [&](const auto &tmpError, const auto &tmpLevel) { + if (tmpError) { + return; + } + + level = tmpLevel; + }); + + return level; +} + +int minHdcpEncryptionLevelChanged(int dpy, uint32_t min_enc_level) { + android::sp<IDisplayConfig> intf = IDisplayConfig::getService(); + if (intf == NULL) { + return -1; + } + + return intf->minHdcpEncryptionLevelChanged(MapDisplayType(dpy), min_enc_level); +} + +int refreshScreen() { + android::sp<IDisplayConfig> intf = IDisplayConfig::getService(); + if (intf == NULL) { + return -1; + } + + return intf->refreshScreen(); +} + +int controlPartialUpdate(int dpy, bool enable) { + android::sp<IDisplayConfig> intf = IDisplayConfig::getService(); + if (intf == NULL) { + return -1; + } + + return intf->controlPartialUpdate(MapDisplayType(dpy), enable); +} + +int toggleScreenUpdate(uint32_t on) { + android::sp<IDisplayConfig> intf = IDisplayConfig::getService(); + if (intf == NULL) { + return -1; + } + + return intf->toggleScreenUpdate(on == 1); +} + +int setIdleTimeout(uint32_t value) { + android::sp<IDisplayConfig> intf = IDisplayConfig::getService(); + if (intf == NULL) { + return -1; + } + + return intf->setIdleTimeout(value); +} + +int getHDRCapabilities(int dpy, DisplayHDRCapabilities *caps) { + android::sp<IDisplayConfig> intf = IDisplayConfig::getService(); + if (intf == NULL || caps == NULL) { + return -1; + } + + int error = -1; + intf->getHDRCapabilities(MapDisplayType(dpy), + [&](const auto &tmpError, const auto &tmpCaps) { + error = tmpError; + if (error) { + return; + } + + caps->supported_hdr_types = tmpCaps.supportedHdrTypes; + caps->max_luminance = tmpCaps.maxLuminance; + caps->max_avg_luminance = tmpCaps.maxAvgLuminance; + caps->min_luminance = tmpCaps.minLuminance; + }); + + return error; +} + +int setCameraLaunchStatus(uint32_t on) { + android::sp<IDisplayConfig> intf = IDisplayConfig::getService(); + if (intf == NULL) { + return -1; + } + + return intf->setCameraLaunchStatus(on); +} + +bool displayBWTransactionPending() { + android::sp<IDisplayConfig> intf = IDisplayConfig::getService(); + if (intf == NULL) { + return 0; + } + + int status = 0; + intf->displayBWTransactionPending( + [&](const auto &tmpError, const auto &tmpStatus) { + if (tmpError) { + return; + } + + status = tmpStatus; + }); + + return status; +} + +} // namespace display diff --git a/msm8909/libdisplayconfig/DisplayConfig.h b/msm8909/libdisplayconfig/DisplayConfig.h new file mode 100644 index 00000000..17b6421e --- /dev/null +++ b/msm8909/libdisplayconfig/DisplayConfig.h @@ -0,0 +1,110 @@ +/* +* Copyright (c) 2017 The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation. nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __DISPLAY_CONFIG_H__ +#define __DISPLAY_CONFIG_H__ + +#include <stdint.h> +#include <vector> + +// This header is for clients to use to set/get global display configuration. + +namespace display { + +enum { + DISPLAY_PRIMARY = 0, + DISPLAY_EXTERNAL, + DISPLAY_VIRTUAL, +}; + +enum { + EXTERNAL_OFFLINE = 0, + EXTERNAL_ONLINE, + EXTERNAL_PAUSE, + EXTERNAL_RESUME, +}; + +enum { + DISABLE_METADATA_DYN_REFRESH_RATE = 0, + ENABLE_METADATA_DYN_REFRESH_RATE, + SET_BINDER_DYN_REFRESH_RATE, +}; + +enum { + DISPLAY_PORT_DEFAULT = 0, + DISPLAY_PORT_DSI, + DISPLAY_PORT_DTV, + DISPLAY_PORT_WRITEBACK, + DISPLAY_PORT_LVDS, + DISPLAY_PORT_EDP, + DISPLAY_PORT_DP, +}; + +struct DisplayAttributes { + uint32_t vsync_period = 0; //nanoseconds + uint32_t xres = 0; + uint32_t yres = 0; + float xdpi = 0.0f; + float ydpi = 0.0f; + int panel_type = DISPLAY_PORT_DEFAULT; + bool is_yuv = false; +}; + +struct DisplayHDRCapabilities { + std::vector<int32_t> supported_hdr_types; + float max_luminance = 0.0f; + float max_avg_luminance = 0.0f; + float min_luminance = 0.0f; +}; + +//============================================================================= +// The functions below run in the client pocess and wherever necessary +// do a binder call to HWC to get/set data. + +int isExternalConnected(); +int setSecondayDisplayStatus(int dpy, uint32_t status); +int configureDynRefeshRate(uint32_t op, uint32_t refreshRate); +int getConfigCount(int dpy); +int getActiveConfig(int dpy); +int setActiveConfig(int dpy, uint32_t config); +DisplayAttributes getDisplayAttributes(uint32_t configIndex, int dpy); +int setPanelBrightness(uint32_t level); +uint32_t getPanelBrightness(); +int minHdcpEncryptionLevelChanged(int dpy, uint32_t min_enc_level); +int refreshScreen(); +int controlPartialUpdate(int dpy, bool enable); +int toggleScreenUpdate(uint32_t on); +int setIdleTimeout(uint32_t value); +int getHDRCapabilities(int dpy, DisplayHDRCapabilities *caps); +int setCameraLaunchStatus(uint32_t on); +bool displayBWTransactionPending(); + +} // namespace display + +#endif // __DISPLAY_CONFIG_H__ diff --git a/msm8909/libdrmutils/Android.mk b/msm8909/libdrmutils/Android.mk new file mode 100644 index 00000000..ebcfc8a0 --- /dev/null +++ b/msm8909/libdrmutils/Android.mk @@ -0,0 +1,17 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE := libdrmutils +LOCAL_VENDOR_MODULE := true +LOCAL_MODULE_TAGS := optional +LOCAL_C_INCLUDES := external/libdrm \ + $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_SHARED_LIBRARIES := libdrm libdl +LOCAL_CFLAGS := -DLOG_TAG=\"DRMUTILS\" -Wall -std=c++11 -Werror -fno-operator-names +LOCAL_CLANG := true +LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr +LOCAL_SRC_FILES := drm_master.cpp drm_res_mgr.cpp drm_lib_loader.cpp +LOCAL_COPY_HEADERS_TO := qcom/display +LOCAL_COPY_HEADERS := drm_master.h drm_res_mgr.h drm_lib_loader.h drm_logger.h drm_interface.h + +include $(BUILD_SHARED_LIBRARY) diff --git a/msm8909/libdrmutils/drm_interface.h b/msm8909/libdrmutils/drm_interface.h new file mode 100644 index 00000000..4c37e8c7 --- /dev/null +++ b/msm8909/libdrmutils/drm_interface.h @@ -0,0 +1,449 @@ +/* +* Copyright (c) 2017, 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 __DRM_INTERFACE_H__ +#define __DRM_INTERFACE_H__ + +#include <map> +#include <string> +#include <utility> +#include <vector> + +#include "xf86drm.h" +#include "xf86drmMode.h" + +namespace sde_drm { +/* + * Drm Atomic Operation Codes + */ +enum struct DRMOps { + /* + * Op: Sets plane source crop + * Arg: uint32_t - Plane ID + * DRMRect - Source Rectangle + */ + PLANE_SET_SRC_RECT, + /* + * Op: Sets plane destination rect + * Arg: uint32_t - Plane ID + * DRMRect - Dst Rectangle + */ + PLANE_SET_DST_RECT, + /* + * Op: Sets plane zorder + * Arg: uint32_t - Plane ID + * uint32_t - zorder + */ + PLANE_SET_ZORDER, + /* + * Op: Sets plane rotation flags + * Arg: uint32_t - Plane ID + * uint32_t - bit mask of rotation flags (See drm_mode.h for enums) + */ + PLANE_SET_ROTATION, + /* + * Op: Sets plane alpha + * Arg: uint32_t - Plane ID + * uint32_t - alpha value + */ + PLANE_SET_ALPHA, + /* + * Op: Sets the blend type + * Arg: uint32_t - Plane ID + * uint32_t - blend type (see DRMBlendType) + */ + PLANE_SET_BLEND_TYPE, + /* + * Op: Sets horizontal decimation + * Arg: uint32_t - Plane ID + * uint32_t - decimation factor + */ + PLANE_SET_H_DECIMATION, + /* + * Op: Sets vertical decimation + * Arg: uint32_t - Plane ID + * uint32_t - decimation factor + */ + PLANE_SET_V_DECIMATION, + /* + * Op: Sets source config flags + * Arg: uint32_t - Plane ID + * uint32_t - flags to enable or disable a specific op. E.g. deinterlacing + */ + PLANE_SET_SRC_CONFIG, + /* + * Op: Sets frame buffer ID for plane. Set together with CRTC. + * Arg: uint32_t - Plane ID + * uint32_t - Framebuffer ID + */ + PLANE_SET_FB_ID, + /* + * Op: Sets the crtc for this plane. Set together with FB_ID. + * Arg: uint32_t - Plane ID + * uint32_t - CRTC ID + */ + PLANE_SET_CRTC, + /* + * Op: Sets acquire fence for this plane's buffer. Set together with FB_ID, CRTC. + * Arg: uint32_t - Plane ID + * uint32_t - Input fence + */ + PLANE_SET_INPUT_FENCE, + /* + * Op: Sets scaler config on this plane. + * Arg: uint32_t - Plane ID + * uint64_t - Address of the scaler config object (version based) + */ + PLANE_SET_SCALER_CONFIG, + /* + * Op: Activate or deactivate a CRTC + * Arg: uint32_t - CRTC ID + * uint32_t - 1 to enable, 0 to disable + */ + CRTC_SET_ACTIVE, + /* + * Op: Sets display mode + * Arg: uint32_t - CRTC ID + * drmModeModeInfo* - Pointer to display mode + */ + CRTC_SET_MODE, + /* + * Op: Sets an offset indicating when a release fence should be signalled. + * Arg: uint32_t - offset + * 0: non-speculative, default + * 1: speculative + */ + CRTC_SET_OUTPUT_FENCE_OFFSET, + /* + * Op: Returns release fence for this frame. Should be called after Commit() on + * DRMAtomicReqInterface. + * Arg: uint32_t - CRTC ID + * int * - Pointer to an integer that will hold the returned fence + */ + CRTC_GET_RELEASE_FENCE, + /* + * Op: Sets PP feature + * Arg: uint32_t - CRTC ID + * DRMPPFeatureInfo * - PP feature data pointer + */ + CRTC_SET_POST_PROC, + /* + * Op: Returns retire fence for this commit. Should be called after Commit() on + * DRMAtomicReqInterface. + * Arg: uint32_t - Connector ID + * int * - Pointer to an integer that will hold the returned fence + */ + CONNECTOR_GET_RETIRE_FENCE, + /* + * Op: Sets writeback connector destination rect + * Arg: uint32_t - Connector ID + * DRMRect - Dst Rectangle + */ + CONNECTOR_SET_OUTPUT_RECT, + /* + * Op: Sets frame buffer ID for writeback connector. + * Arg: uint32_t - Connector ID + * uint32_t - Framebuffer ID + */ + CONNECTOR_SET_OUTPUT_FB_ID, +}; + +enum struct DRMRotation { + FLIP_H = 0x1, + FLIP_V = 0x2, + ROT_90 = 0x4, +}; + +enum struct DRMBlendType { + UNDEFINED = 0, + OPAQUE = 1, + PREMULTIPLIED = 2, + COVERAGE = 3, +}; + +enum struct DRMSrcConfig { + DEINTERLACE = 0, +}; + +/* Display type to identify a suitable connector */ +enum struct DRMDisplayType { + PERIPHERAL, + TV, + VIRTUAL, +}; + +struct DRMRect { + uint32_t left; // Left-most pixel coordinate. + uint32_t top; // Top-most pixel coordinate. + uint32_t right; // Right-most pixel coordinate. + uint32_t bottom; // Bottom-most pixel coordinate. +}; + +//------------------------------------------------------------------------ +// DRM Info Query Types +//------------------------------------------------------------------------ + +enum struct QSEEDVersion { + V1, + V2, + V3, +}; + +enum struct SmartDMARevision { + V1, + V2, +}; + +/* Per CRTC Resource Info*/ +struct DRMCrtcInfo { + bool has_src_split; + uint32_t max_blend_stages; + QSEEDVersion qseed_version; + SmartDMARevision smart_dma_rev; +}; + +enum struct DRMPlaneType { + // Has CSC and scaling capability + VIG = 0, + // Has scaling capability but no CSC + RGB, + // No scaling support + DMA, + // Supports a small dimension and doesn't use a CRTC stage + CURSOR, + MAX, +}; + +struct DRMPlaneTypeInfo { + DRMPlaneType type; + uint32_t master_plane_id; + // FourCC format enum and modifier + std::vector<std::pair<uint32_t, uint64_t>> formats_supported; + uint32_t max_linewidth; + uint32_t max_upscale; + uint32_t max_downscale; + uint32_t max_horizontal_deci; + uint32_t max_vertical_deci; +}; + +// All DRM Planes as map<Plane_id , plane_type_info> listed from highest to lowest priority +typedef std::vector<std::pair<uint32_t, DRMPlaneTypeInfo>> DRMPlanesInfo; + +enum struct DRMTopology { + UNKNOWN, // To be compat with driver defs in sde_kms.h + SINGLE_LM, + DUAL_LM, + PPSPLIT, + DUAL_LM_MERGE, +}; + +enum struct DRMPanelMode { + VIDEO, + COMMAND, +}; + +/* Per Connector Info*/ +struct DRMConnectorInfo { + uint32_t mmWidth; + uint32_t mmHeight; + uint32_t type; + uint32_t num_modes; + drmModeModeInfo *modes; + DRMTopology topology; + std::string panel_name; + DRMPanelMode panel_mode; + bool is_primary; + // Valid only if DRMPanelMode is VIDEO + bool dynamic_fps; + // FourCC format enum and modifier + std::vector<std::pair<uint32_t, uint64_t>> formats_supported; + // Valid only if type is DRM_MODE_CONNECTOR_VIRTUAL + uint32_t max_linewidth; +}; + +/* Identifier token for a display */ +struct DRMDisplayToken { + uint32_t conn_id; + uint32_t crtc_id; +}; + +enum DRMPPFeatureID { + kFeaturePcc, + kFeatureIgc, + kFeaturePgc, + kFeatureMixerGc, + kFeaturePaV2, + kFeatureDither, + kFeatureGamut, + kFeaturePADither, + kPPFeaturesMax, +}; + +enum DRMPPPropType { + kPropEnum, + kPropRange, + kPropBlob, + kPropTypeMax, +}; + +struct DRMPPFeatureInfo { + DRMPPFeatureID id; + DRMPPPropType type; + uint32_t version; + uint32_t payload_size; + void *payload; +}; + +struct DRMScalerLUTInfo { + uint32_t dir_lut_size = 0; + uint32_t cir_lut_size = 0; + uint32_t sep_lut_size = 0; + uint64_t dir_lut = 0; + uint64_t cir_lut = 0; + uint64_t sep_lut = 0; +}; + +/* DRM Atomic Request Property Set. + * + * Helper class to create and populate atomic properties of DRM components + * when rendered in DRM atomic mode */ +class DRMAtomicReqInterface { + public: + virtual ~DRMAtomicReqInterface() {} + /* Perform request operation. + * + * [input]: opcode: operation code from DRMOps list. + * var_arg: arguments for DRMOps's can differ in number and + * data type. Refer above DRMOps to details. + * [return]: Error code if the API fails, 0 on success. + */ + virtual int Perform(DRMOps opcode, ...) = 0; + + /* + * Commit the params set via Perform(). Also resets the properties after commit. Needs to be + * called every frame. + * [input]: synchronous: Determines if the call should block until a h/w flip + * [return]: Error code if the API fails, 0 on success. + */ + virtual int Commit(bool synchronous) = 0; + /* + * Validate the params set via Perform(). + * [return]: Error code if the API fails, 0 on success. + */ + virtual int Validate() = 0; +}; + +class DRMManagerInterface; + +/* Populates a singleton instance of DRMManager */ +typedef int (*GetDRMManager)(int fd, DRMManagerInterface **intf); + +/* Destroy DRMManager instance */ +typedef int (*DestroyDRMManager)(); + +/* + * DRM Manager Interface - Any class which plans to implement helper function for vendor + * specific DRM driver implementation must implement the below interface routines to work + * with SDM. + */ + +class DRMManagerInterface { + public: + virtual ~DRMManagerInterface() {} + + /* + * Since SDM completely manages the planes. GetPlanesInfo will provide all + * the plane information. + * [output]: DRMPlanesInfo: Resource Info for planes. + */ + virtual void GetPlanesInfo(DRMPlanesInfo *info) = 0; + + /* + * Will provide all the information of a selected crtc. + * [input]: Use crtc id 0 to obtain system wide info + * [output]: DRMCrtcInfo: Resource Info for the given CRTC id. + */ + virtual void GetCrtcInfo(uint32_t crtc_id, DRMCrtcInfo *info) = 0; + + /* + * Will provide all the information of a selected connector. + * [output]: DRMConnectorInfo: Resource Info for the given connector id + */ + virtual void GetConnectorInfo(uint32_t conn_id, DRMConnectorInfo *info) = 0; + + /* + * Will query post propcessing feature info of a CRTC. + * [output]: DRMPPFeatureInfo: CRTC post processing feature info + */ + virtual void GetCrtcPPInfo(uint32_t crtc_id, DRMPPFeatureInfo &info) = 0; + /* + * Register a logical display to receive a token. + * Each display pipeline in DRM is identified by its CRTC and Connector(s). + * On display connect(bootup or hotplug), clients should invoke this interface to + * establish the pipeline for the display and should get a DisplayToken + * populated with crtc and connnector(s) id's. Here onwards, Client should + * use this token to represent the display for any Perform operations if + * needed. + * + * [input]: disp_type - Peripheral / TV / Virtual + * [output]: DRMDisplayToken - CRTC and Connector id's for the display + * [return]: 0 on success, a negative error value otherwise + */ + virtual int RegisterDisplay(DRMDisplayType disp_type, DRMDisplayToken *tok) = 0; + + /* Client should invoke this interface on display disconnect. + * [input]: DRMDisplayToken - identifier for the display. + */ + virtual void UnregisterDisplay(const DRMDisplayToken &token) = 0; + + /* + * Creates and returns an instance of DRMAtomicReqInterface corresponding to a display token + * returned as part of RegisterDisplay API. Needs to be called per display. + * [input]: DRMDisplayToken that identifies a display pipeline + * [output]: Pointer to an instance of DRMAtomicReqInterface. + * [return]: Error code if the API fails, 0 on success. + */ + virtual int CreateAtomicReq(const DRMDisplayToken &token, DRMAtomicReqInterface **intf) = 0; + + /* + * Destroys the instance of DRMAtomicReqInterface + * [input]: Pointer to a DRMAtomicReqInterface + * [return]: Error code if the API fails, 0 on success. + */ + virtual int DestroyAtomicReq(DRMAtomicReqInterface *intf) = 0; + /* + * Sets the global scaler LUT + * [input]: LUT Info + * [return]: Error code if the API fails, 0 on success. + */ + virtual int SetScalerLUT(const DRMScalerLUTInfo &lut_info) = 0; +}; + +} // namespace sde_drm +#endif // __DRM_INTERFACE_H__ diff --git a/msm8909/libdrmutils/drm_lib_loader.cpp b/msm8909/libdrmutils/drm_lib_loader.cpp new file mode 100644 index 00000000..83c9f1b5 --- /dev/null +++ b/msm8909/libdrmutils/drm_lib_loader.cpp @@ -0,0 +1,92 @@ +/* +* Copyright (c) 2017, 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 "drm_lib_loader.h" + +#define __CLASS__ "DRMLibLoader" + +using std::mutex; +using std::lock_guard; + +namespace drm_utils { + +DRMLibLoader *DRMLibLoader::s_instance = nullptr; +mutex DRMLibLoader::s_lock; + +DRMLibLoader *DRMLibLoader::GetInstance() { + lock_guard<mutex> obj(s_lock); + + if (!s_instance) { + s_instance = new DRMLibLoader(); + } + + return s_instance; +} + +void DRMLibLoader::Destroy() { + lock_guard<mutex> obj(s_lock); + if (s_instance) { + delete s_instance; + s_instance = nullptr; + } +} + +DRMLibLoader::DRMLibLoader() { + if (Open("libsdedrm.so")) { + if (Sym("GetDRMManager", reinterpret_cast<void **>(&func_get_drm_manager_)) && + Sym("DestroyDRMManager", reinterpret_cast<void **>(&func_destroy_drm_manager_))) { + is_loaded_ = true; + } + } +} + +DRMLibLoader::~DRMLibLoader() { + if (lib_) { + ::dlclose(lib_); + lib_ = nullptr; + } +} + +bool DRMLibLoader::Open(const char *lib_name) { + lib_ = ::dlopen(lib_name, RTLD_NOW); + + return (lib_ != nullptr); +} + +bool DRMLibLoader::Sym(const char *func_name, void **func_ptr) { + if (lib_) { + *func_ptr = ::dlsym(lib_, func_name); + } + + return (*func_ptr != nullptr); +} + +} // namespace drm_utils diff --git a/msm8909/libdrmutils/drm_lib_loader.h b/msm8909/libdrmutils/drm_lib_loader.h new file mode 100644 index 00000000..d132d69c --- /dev/null +++ b/msm8909/libdrmutils/drm_lib_loader.h @@ -0,0 +1,64 @@ +/* +* Copyright (c) 2017, 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 __DRM_LIB_LOADER_H__ +#define __DRM_LIB_LOADER_H__ + +#include <drm_interface.h> +#include <mutex> + +namespace drm_utils { + +class DRMLibLoader { + public: + ~DRMLibLoader(); + bool IsLoaded() { return is_loaded_; } + sde_drm::GetDRMManager FuncGetDRMManager() { return func_get_drm_manager_; } + sde_drm::DestroyDRMManager FuncDestroyDRMManager() { return func_destroy_drm_manager_; } + + static DRMLibLoader *GetInstance(); + static void Destroy(); + + private: + DRMLibLoader(); + bool Open(const char *lib_name); + bool Sym(const char *func_name, void **func_ptr); + + void *lib_ = {}; + sde_drm::GetDRMManager func_get_drm_manager_ = {}; + sde_drm::DestroyDRMManager func_destroy_drm_manager_ = {}; + bool is_loaded_ = false; + + static DRMLibLoader *s_instance; // Singleton instance + static std::mutex s_lock; +}; + +} // namespace drm_utils + +#endif // __DRM_LIB_LOADER_H__ diff --git a/msm8909/libdrmutils/drm_logger.h b/msm8909/libdrmutils/drm_logger.h new file mode 100644 index 00000000..d0b07738 --- /dev/null +++ b/msm8909/libdrmutils/drm_logger.h @@ -0,0 +1,69 @@ +/* +* Copyright (c) 2017, 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 __DRM_LOGGER_H__ +#define __DRM_LOGGER_H__ + +#include <utility> + +namespace drm_utils { + +class DRMLogger { + public: + virtual ~DRMLogger() {} + virtual void Error(const char *format, ...) = 0; + virtual void Warning(const char *format, ...) = 0; + virtual void Info(const char *format, ...) = 0; + virtual void Debug(const char *format, ...) = 0; + + static void Set(DRMLogger *logger) { s_instance = logger; } + static DRMLogger *Get() { return s_instance; } + + private: + static DRMLogger *s_instance; +}; + +#define DRM_LOG(method, format, ...) \ + if (drm_utils::DRMLogger::Get()) { \ + drm_utils::DRMLogger::Get()->method(format, ##__VA_ARGS__); \ + } + +#define DRM_LOG_CONTEXT(method, format, ...) \ + DRM_LOG(method, __CLASS__ "::%s: " format, __FUNCTION__, ##__VA_ARGS__); + +#define DRM_LOGE(format, ...) DRM_LOG_CONTEXT(Error, format, ##__VA_ARGS__) +#define DRM_LOGW(format, ...) DRM_LOG_CONTEXT(Warning, format, ##__VA_ARGS__) +#define DRM_LOGI(format, ...) DRM_LOG_CONTEXT(Info, format, ##__VA_ARGS__) +#define DRM_LOGD_IF(pred, format, ...) \ + if (pred) \ + DRM_LOG_CONTEXT(Debug, format, ##__VA_ARGS__) + +} // namespace drm_utils + +#endif // __DRM_LOGGER_H__ diff --git a/msm8909/libdrmutils/drm_master.cpp b/msm8909/libdrmutils/drm_master.cpp new file mode 100644 index 00000000..09e0729e --- /dev/null +++ b/msm8909/libdrmutils/drm_master.cpp @@ -0,0 +1,149 @@ +/* +* Copyright (c) 2017, 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 <errno.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <unistd.h> +#include <xf86drm.h> +#include <xf86drmMode.h> +// Intentionally included after xf86 headers so that they in-turn include libdrm version of drm.h +// that doesn't use keyword "virtual" for a variable name. Not doing so leads to the kernel version +// of drm.h being included causing compilation to fail +#include <drm/msm_drm.h> +#include <algorithm> +#include <iterator> + +#include "drm_master.h" + +#define __CLASS__ "DRMMaster" + +using std::mutex; +using std::lock_guard; +using std::begin; +using std::copy; +using std::end; +using std::fill; + +namespace drm_utils { + +DRMLogger *DRMLogger::s_instance = nullptr; +DRMMaster *DRMMaster::s_instance = nullptr; +mutex DRMMaster::s_lock; + +int DRMMaster::GetInstance(DRMMaster **master) { + lock_guard<mutex> obj(s_lock); + + if (!s_instance) { + s_instance = new DRMMaster(); + if (s_instance->Init() < 0) { + delete s_instance; + s_instance = nullptr; + return -ENODEV; + } + } + + *master = s_instance; + return 0; +} + +void DRMMaster::DestroyInstance() { + lock_guard<mutex> obj(s_lock); + delete s_instance; + s_instance = nullptr; +} + +int DRMMaster::Init() { + dev_fd_ = drmOpen("msm_drm", nullptr); + if (dev_fd_ < 0) { + DRM_LOGE("drmOpen failed with error %d", dev_fd_); + return -ENODEV; + } + + return 0; +} + +DRMMaster::~DRMMaster() { + drmClose(dev_fd_); + dev_fd_ = -1; +} + +int DRMMaster::CreateFbId(const DRMBuffer &drm_buffer, uint32_t *fb_id) { + uint32_t gem_handle = 0; + int ret = drmPrimeFDToHandle(dev_fd_, drm_buffer.fd, &gem_handle); + if (ret) { + DRM_LOGE("drmPrimeFDToHandle failed with error %d", ret); + return ret; + } + + struct drm_mode_fb_cmd2 cmd2 {}; + cmd2.width = drm_buffer.width; + cmd2.height = drm_buffer.height; + cmd2.pixel_format = drm_buffer.drm_format; + cmd2.flags = DRM_MODE_FB_MODIFIERS; + fill(begin(cmd2.handles), begin(cmd2.handles) + drm_buffer.num_planes, gem_handle); + copy(begin(drm_buffer.stride), end(drm_buffer.stride), begin(cmd2.pitches)); + copy(begin(drm_buffer.offset), end(drm_buffer.offset), begin(cmd2.offsets)); + fill(begin(cmd2.modifier), begin(cmd2.modifier) + drm_buffer.num_planes, + drm_buffer.drm_format_modifier); + + if ((ret = drmIoctl(dev_fd_, DRM_IOCTL_MODE_ADDFB2, &cmd2))) { + DRM_LOGE("DRM_IOCTL_MODE_ADDFB2 failed with error %d", ret); + } else { + *fb_id = cmd2.fb_id; + } + + struct drm_gem_close gem_close = {}; + gem_close.handle = gem_handle; + int ret1 = drmIoctl(dev_fd_, DRM_IOCTL_GEM_CLOSE, &gem_close); + if (ret1) { + DRM_LOGE("drmIoctl::DRM_IOCTL_GEM_CLOSE failed with error %d", ret1); + return ret1; + } + + return ret; +} + +int DRMMaster::RemoveFbId(uint32_t fb_id) { + int ret = 0; +#ifdef DRM_IOCTL_MSM_RMFB2 + ret = drmIoctl(dev_fd_, DRM_IOCTL_MSM_RMFB2, &fb_id); + if (ret) { + DRM_LOGE("drmIoctl::DRM_IOCTL_MSM_RMFB2 failed for fb_id %d with error %d", fb_id, errno); + } +#else + ret = drmModeRmFB(dev_fd_, fb_id); + if (ret) { + DRM_LOGE("drmModeRmFB failed for fb_id %d with error %d", fb_id, ret); + } +#endif + return ret; +} + +} // namespace drm_utils diff --git a/msm8909/libdrmutils/drm_master.h b/msm8909/libdrmutils/drm_master.h new file mode 100644 index 00000000..52a8b028 --- /dev/null +++ b/msm8909/libdrmutils/drm_master.h @@ -0,0 +1,95 @@ +/* +* Copyright (c) 2017, 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 __DRM_MASTER_H__ +#define __DRM_MASTER_H__ + +#include <mutex> + +#include "drm_logger.h" + +namespace drm_utils { + +struct DRMBuffer { + int fd = -1; + uint32_t width = 0; + uint32_t height = 0; + uint32_t drm_format = 0; + uint64_t drm_format_modifier = 0; + uint32_t stride[4] = {}; + uint32_t offset[4] = {}; + uint32_t num_planes = 1; +}; + +class DRMMaster { + public: + ~DRMMaster(); + /* Converts from ION fd --> Prime Handle --> FB_ID. + * Input: + * drm_buffer: A DRMBuffer obj that packages description of buffer + * Output: + * fb_id: Pointer to store DRM framebuffer id into + * Returns: + * ioctl error code + */ + int CreateFbId(const DRMBuffer &drm_buffer, uint32_t *fb_id); + /* Removes the fb_id from DRM + * Input: + * fb_id: DRM FB to be removed + * Returns: + * ioctl error code + */ + int RemoveFbId(uint32_t fb_id); + /* Poplulates master DRM fd + * Input: + * fd: Pointer to store master fd into + */ + void GetHandle(int *fd) { *fd = dev_fd_; } + + /* Creates an instance of DRMMaster if it doesn't exist and initializes it. Threadsafe. + * Input: + * master: Pointer to store a pointer to the instance + * Returns: + * -ENODEV if device cannot be opened or initilization fails + */ + static int GetInstance(DRMMaster **master); + static void DestroyInstance(); + + private: + DRMMaster() {} + int Init(); + + int dev_fd_ = -1; // Master fd for DRM + static DRMMaster *s_instance; // Singleton instance + static std::mutex s_lock; +}; + +} // namespace drm_utils + +#endif // __DRM_MASTER_H__ diff --git a/msm8909/libdrmutils/drm_res_mgr.cpp b/msm8909/libdrmutils/drm_res_mgr.cpp new file mode 100644 index 00000000..1d29495d --- /dev/null +++ b/msm8909/libdrmutils/drm_res_mgr.cpp @@ -0,0 +1,151 @@ +/* +* Copyright (c) 2017, 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 <errno.h> + +#include "drm_master.h" +#include "drm_res_mgr.h" + +#define DEBUG 0 +#define __CLASS__ "DRMResMgr" + +using std::mutex; +using std::lock_guard; + +namespace drm_utils { + +DRMResMgr *DRMResMgr::s_instance = nullptr; +mutex DRMResMgr::s_lock; + +static bool GetConnector(int dev_fd, drmModeRes *res, drmModeConnector **connector) { + for (auto i = 0; i < res->count_connectors; i++) { + drmModeConnector *conn = drmModeGetConnector(dev_fd, res->connectors[i]); + if (conn && conn->connector_type == DRM_MODE_CONNECTOR_DSI && conn->count_modes && + conn->connection == DRM_MODE_CONNECTED) { + *connector = conn; + DRM_LOGI("Found connector %d", conn->connector_id); + return true; + } + } + + return false; +} + +static bool GetEncoder(int dev_fd, drmModeConnector *conn, drmModeEncoder **encoder) { + for (auto i = 0; i < conn->count_encoders; i++) { + drmModeEncoder *enc = drmModeGetEncoder(dev_fd, conn->encoders[i]); + if (enc && enc->encoder_type == DRM_MODE_ENCODER_DSI) { + *encoder = enc; + DRM_LOGI("Found encoder %d", enc->encoder_id); + return true; + } + } + return false; +} + +static bool GetCrtc(int dev_fd, drmModeRes *res, drmModeEncoder *enc, drmModeCrtc **crtc) { + for (auto i = 0; i < res->count_crtcs; i++) { + if (enc->possible_crtcs & (1 << i)) { + drmModeCrtc *c = drmModeGetCrtc(dev_fd, res->crtcs[i]); + if (c) { + *crtc = c; + DRM_LOGI("Found crtc %d", c->crtc_id); + return true; + } + } + } + + return false; +} + +#define __CLASS__ "DRMResMgr" + +int DRMResMgr::GetInstance(DRMResMgr **res_mgr) { + lock_guard<mutex> obj(s_lock); + + if (!s_instance) { + s_instance = new DRMResMgr(); + if (s_instance->Init() < 0) { + delete s_instance; + s_instance = nullptr; + return -ENODEV; + } + } + + *res_mgr = s_instance; + return 0; +} + +int DRMResMgr::Init() { + DRMMaster *master = nullptr; + int dev_fd = -1; + + int ret = DRMMaster::GetInstance(&master); + if (ret < 0) { + return ret; + } + + master->GetHandle(&dev_fd); + drmModeRes *res = drmModeGetResources(dev_fd); + if (res == nullptr) { + DRM_LOGE("drmModeGetResources failed"); + return -ENODEV; + } + + drmModeConnector *conn = nullptr; + if (!GetConnector(dev_fd, res, &conn)) { + DRM_LOGE("Failed to find a connector"); + return -ENODEV; + } + + drmModeEncoder *enc = nullptr; + if (!GetEncoder(dev_fd, conn, &enc)) { + DRM_LOGE("Failed to find an encoder"); + drmModeFreeConnector(conn); + return -ENODEV; + } + + drmModeCrtc *crtc = nullptr; + if (!GetCrtc(dev_fd, res, enc, &crtc)) { + DRM_LOGE("Failed to find a crtc"); + drmModeFreeEncoder(enc); + drmModeFreeConnector(conn); + drmModeFreeResources(res); + return -ENODEV; + } + + res_ = res; + conn_ = conn; + enc_ = enc; + crtc_ = crtc; + + return 0; +} + +} // namespace drm_utils diff --git a/msm8909/libdrmutils/drm_res_mgr.h b/msm8909/libdrmutils/drm_res_mgr.h new file mode 100644 index 00000000..3a8378c5 --- /dev/null +++ b/msm8909/libdrmutils/drm_res_mgr.h @@ -0,0 +1,72 @@ +/* +* Copyright (c) 2017, 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 __DRM_RES_MGR_H__ +#define __DRM_RES_MGR_H__ + +#include <xf86drm.h> +#include <xf86drmMode.h> + +#include <mutex> + +namespace drm_utils { + +class DRMResMgr { + public: + /* Returns the default connector id for primary panel */ + void GetConnectorId(uint32_t *id) { *id = conn_->connector_id; } + /* Returns the default crtc id for primary pipeline */ + void GetCrtcId(uint32_t *id) { *id = crtc_->crtc_id; } + /* Returns the default mode currently used by the connector */ + void GetMode(drmModeModeInfo *mode) { *mode = conn_->modes[0]; } + /* Returns the panel dimensions in mm */ + void GetDisplayDimInMM(uint32_t *w, uint32_t *h) { + *w = conn_->mmWidth; + *h = conn_->mmHeight; + } + + /* Creates and initializes an instance of DRMResMgr. On success, returns a pointer to it, on + * failure returns -ENODEV */ + static int GetInstance(DRMResMgr **res_mgr); + + private: + int Init(); + + drmModeRes *res_ = nullptr; + drmModeConnector *conn_ = nullptr; + drmModeEncoder *enc_ = nullptr; + drmModeCrtc *crtc_ = nullptr; + + static DRMResMgr *s_instance; + static std::mutex s_lock; +}; + +} // namespace drm_utils + +#endif // __DRM_RES_MGR_H__ diff --git a/msm8909/libgralloc/Android.mk b/msm8909/libgralloc/Android.mk index b6e3a8d3..86c0f042 100644 --- a/msm8909/libgralloc/Android.mk +++ b/msm8909/libgralloc/Android.mk @@ -18,18 +18,20 @@ include $(LOCAL_PATH)/../common.mk include $(CLEAR_VARS) LOCAL_MODULE := gralloc.$(TARGET_BOARD_PLATFORM) +LOCAL_VENDOR_MODULE := true LOCAL_MODULE_RELATIVE_PATH := hw -LOCAL_PROPRIETARY_MODULE := true LOCAL_MODULE_TAGS := optional LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes) -LOCAL_SHARED_LIBRARIES := $(common_libs) libmemalloc libqdMetaData -LOCAL_SHARED_LIBRARIES += libqdutils libGLESv1_CM -LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdgralloc\" -LOCAL_CLANG := $(common_clang_flags) +LOCAL_HEADER_LIBRARIES := display_headers +LOCAL_SHARED_LIBRARIES := $(common_libs) libmemalloc libqdMetaData libqdutils +ifneq ($(TARGET_IS_HEADLESS), true) +LOCAL_SHARED_LIBRARIES += libGLESv1_CM +endif +LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdgralloc\" -Wno-sign-conversion LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps) LOCAL_SRC_FILES := gpu.cpp gralloc.cpp framebuffer.cpp mapper.cpp LOCAL_COPY_HEADERS_TO := $(common_header_export_path) -LOCAL_COPY_HEADERS := gralloc_priv.h gr.h +LOCAL_COPY_HEADERS := gralloc_priv.h gr.h adreno_utils.h include $(BUILD_SHARED_LIBRARY) @@ -37,11 +39,12 @@ include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libmemalloc +LOCAL_VENDOR_MODULE := true LOCAL_MODULE_TAGS := optional LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes) +LOCAL_HEADER_LIBRARIES := display_headers LOCAL_SHARED_LIBRARIES := $(common_libs) libqdutils libdl -LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdmemalloc\" -LOCAL_CLANG := $(common_clang_flags) +LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdmemalloc\" -Wno-sign-conversion LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps) LOCAL_SRC_FILES := ionalloc.cpp alloc_controller.cpp LOCAL_COPY_HEADERS := alloc_controller.h memalloc.h diff --git a/msm8909/libgralloc/Makefile.am b/msm8909/libgralloc/Makefile.am new file mode 100644 index 00000000..3cf39601 --- /dev/null +++ b/msm8909/libgralloc/Makefile.am @@ -0,0 +1,42 @@ +HEADER_PATH := ${WORKSPACE}/display/display-hal/include +h_sources = alloc_controller.h \ + memalloc.h + +cpp_sources = ionalloc.cpp \ + alloc_controller.cpp + +memalloc_includedir = $(pkgincludedir) +memalloc_include_HEADERS = $(h_sources) + +lib_LTLIBRARIES = libmemalloc.la +libmemalloc_la_CC = @CC@ +libmemalloc_la_SOURCES = $(cpp_sources) +libmemalloc_la_CFLAGS = $(COMMON_CFLAGS) -DLOG_TAG=\"qdmemalloc\" +libmemalloc_la_CPPFLAGS = $(AM_CPPFLAGS) +libmemalloc_la_LIBADD = ../libqdutils/libqdutils.la +libmemalloc_la_LIBADD += -lhardware -lcutils -llog -lutils -ldl +libmemalloc_la_LDFLAGS = -shared -avoid-version + +header_sources = gralloc_priv.h \ + gr.h \ + adreno_utils.h \ + $(HEADER_PATH)/color_metadata.h + +c_sources = gpu.cpp \ + gralloc.cpp \ + framebuffer.cpp \ + mapper.cpp + +library_includedir = $(pkgincludedir) +library_include_HEADERS = $(header_sources) + +lib_LTLIBRARIES += libgralloc.la +libgralloc_la_CC = @CC@ +libgralloc_la_SOURCES = $(c_sources) +libgralloc_la_CFLAGS = $(COMMON_CFLAGS) -DLOG_TAG=\"qdgralloc\" +libgralloc_la_CPPFLAGS = $(AM_CPPFLAGS) +libgralloc_la_LIBADD = ../libqdutils/libqdutils.la +libgralloc_la_LIBADD += ../libqdutils/libqdMetaData.la +libgralloc_la_LIBADD += -lhardware -lcutils -llog -lutils -lbinder +libgralloc_la_LIBADD += libmemalloc.la +libgralloc_la_LDFLAGS = -shared -avoid-version diff --git a/msm8909/libgralloc/adreno_utils.h b/msm8909/libgralloc/adreno_utils.h new file mode 100644 index 00000000..baecef99 --- /dev/null +++ b/msm8909/libgralloc/adreno_utils.h @@ -0,0 +1,59 @@ +/* +* Copyright (c) 2015 - 2017, 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. +*/ + +// Adreno Pixel Formats +typedef enum { + + ADRENO_PIXELFORMAT_UNKNOWN = 0, + ADRENO_PIXELFORMAT_R10G10B10A2_UNORM = 24, // Vertex, Normalized GL_UNSIGNED_INT_10_10_10_2_OES + ADRENO_PIXELFORMAT_R8G8B8A8 = 28, + ADRENO_PIXELFORMAT_R8G8B8A8_SRGB = 29, + ADRENO_PIXELFORMAT_B5G6R5 = 85, + ADRENO_PIXELFORMAT_B5G5R5A1 = 86, + ADRENO_PIXELFORMAT_B8G8R8A8 = 90, + ADRENO_PIXELFORMAT_B8G8R8A8_SRGB = 91, + ADRENO_PIXELFORMAT_B8G8R8X8_SRGB = 93, + ADRENO_PIXELFORMAT_NV12 = 103, + ADRENO_PIXELFORMAT_P010 = 104, + ADRENO_PIXELFORMAT_YUY2 = 107, + ADRENO_PIXELFORMAT_B4G4R4A4 = 115, + ADRENO_PIXELFORMAT_NV12_EXT = 506, // NV12 with non-std alignment and offsets + ADRENO_PIXELFORMAT_R8G8B8X8 = 507, // GL_RGB8 (Internal) + ADRENO_PIXELFORMAT_R8G8B8 = 508, // GL_RGB8 + ADRENO_PIXELFORMAT_A1B5G5R5 = 519, // GL_RGB5_A1 + ADRENO_PIXELFORMAT_R8G8B8X8_SRGB = 520, // GL_SRGB8 + ADRENO_PIXELFORMAT_R8G8B8_SRGB = 521, // GL_SRGB8 + ADRENO_PIXELFORMAT_A2B10G10R10_UNORM = 532, + // Vertex, Normalized GL_UNSIGNED_INT_10_10_10_2_OES + ADRENO_PIXELFORMAT_R10G10B10X2_UNORM = 537, + // Vertex, Normalized GL_UNSIGNED_INT_10_10_10_2_OES + ADRENO_PIXELFORMAT_R5G6B5 = 610, // RGBA version of B5G6R5 + ADRENO_PIXELFORMAT_R5G5B5A1 = 611, // RGBA version of B5G5R5A1 + ADRENO_PIXELFORMAT_R4G4B4A4 = 612, // RGBA version of B4G4R4A4 + ADRENO_PIXELFORMAT_UYVY = 614, // YUV 4:2:2 packed progressive (1 plane) + ADRENO_PIXELFORMAT_NV21 = 619, + ADRENO_PIXELFORMAT_Y8U8V8A8 = 620, // YUV 4:4:4 packed (1 plane) + ADRENO_PIXELFORMAT_Y8 = 625, // Single 8-bit luma only channel YUV format + ADRENO_PIXELFORMAT_TP10 = 654, // YUV 4:2:0 planar 10 bits/comp (2 planes) +} ADRENOPIXELFORMAT; diff --git a/msm8909/libgralloc/alloc_controller.cpp b/msm8909/libgralloc/alloc_controller.cpp index c7ba7c9e..d2a522ed 100644 --- a/msm8909/libgralloc/alloc_controller.cpp +++ b/msm8909/libgralloc/alloc_controller.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2014,2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2011 - 2017, 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 @@ -30,74 +30,92 @@ #include <cutils/log.h> #include <fcntl.h> #include <dlfcn.h> +#include <media/msm_media_info.h> +#include <qdMetaData.h> +#include <utils/Singleton.h> +#include <utils/Mutex.h> +#include <algorithm> + #include "gralloc_priv.h" #include "alloc_controller.h" #include "memalloc.h" #include "ionalloc.h" #include "gr.h" -#include "comptype.h" -#include "mdp_version.h" +#include "qd_utils.h" -#ifdef VENUS_COLOR_FORMAT -#include <media/msm_media_info.h> -#else -#define VENUS_Y_STRIDE(args...) 0 -#define VENUS_Y_SCANLINES(args...) 0 -#define VENUS_BUFFER_SIZE(args...) 0 +#define ASTC_BLOCK_SIZE 16 + +#ifndef ION_FLAG_CP_PIXEL +#define ION_FLAG_CP_PIXEL 0 #endif -#define ASTC_BLOCK_SIZE 16 +#ifndef ION_FLAG_ALLOW_NON_CONTIG +#define ION_FLAG_ALLOW_NON_CONTIG 0 +#endif + +#ifndef ION_FLAG_CP_CAMERA_PREVIEW +#define ION_FLAG_CP_CAMERA_PREVIEW 0 +#endif + +#ifdef MASTER_SIDE_CP +#define CP_HEAP_ID ION_SECURE_HEAP_ID +#define SD_HEAP_ID ION_SECURE_DISPLAY_HEAP_ID +#define ION_CP_FLAGS (ION_SECURE | ION_FLAG_CP_PIXEL) +#define ION_SD_FLAGS (ION_SECURE | ION_FLAG_CP_SEC_DISPLAY) +#define ION_SC_FLAGS (ION_SECURE | ION_FLAG_CP_CAMERA) +#define ION_SC_PREVIEW_FLAGS (ION_SECURE | ION_FLAG_CP_CAMERA_PREVIEW) +#else // SLAVE_SIDE_CP +#define CP_HEAP_ID ION_CP_MM_HEAP_ID +#define SD_HEAP_ID CP_HEAP_ID +#define ION_CP_FLAGS (ION_SECURE | ION_FLAG_ALLOW_NON_CONTIG) +#define ION_SD_FLAGS ION_SECURE +#define ION_SC_FLAGS ION_SECURE +#define ION_SC_PREVIEW_FLAGS ION_SECURE +#endif + +#ifndef COLOR_FMT_P010_UBWC +#define COLOR_FMT_P010_UBWC 9 +#endif using namespace gralloc; using namespace qdutils; +using namespace android; ANDROID_SINGLETON_STATIC_INSTANCE(AdrenoMemInfo); +ANDROID_SINGLETON_STATIC_INSTANCE(MDPCapabilityInfo); + +static void getYuvUBwcWidthHeight(int, int, int, int&, int&); +static unsigned int getUBwcSize(int, int, int, const int, const int); //Common functions -static bool canFallback(int usage, bool triedSystem) -{ - // Fallback to system heap when alloc fails unless - // 1. Composition type is MDP - // 2. Alloc from system heap was already tried - // 3. The heap type is requsted explicitly - // 4. The heap type is protected - // 5. The buffer is meant for external display only - - if(QCCompositionType::getInstance().getCompositionType() & - COMPOSITION_TYPE_MDP) - return false; - if(triedSystem) - return false; - if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_PROTECTED)) - return false; - if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY)) - return false; - //Return true by default - return true; -} /* The default policy is to return cached buffers unless the client explicity * sets the PRIVATE_UNCACHED flag or indicates that the buffer will be rarely * read or written in software. Any combination with a _RARELY_ flag will be * treated as uncached. */ static bool useUncached(const int& usage) { - if((usage & GRALLOC_USAGE_PRIVATE_UNCACHED) or - ((usage & GRALLOC_USAGE_SW_WRITE_MASK) == - GRALLOC_USAGE_SW_WRITE_RARELY) or - ((usage & GRALLOC_USAGE_SW_READ_MASK) == - GRALLOC_USAGE_SW_READ_RARELY)) + if ((usage & GRALLOC_USAGE_PROTECTED) or + (usage & GRALLOC_USAGE_PRIVATE_UNCACHED) or + ((usage & GRALLOC_USAGE_SW_WRITE_MASK) == GRALLOC_USAGE_SW_WRITE_RARELY) or + ((usage & GRALLOC_USAGE_SW_READ_MASK) == GRALLOC_USAGE_SW_READ_RARELY)) return true; return false; } -//-------------- AdrenoMemInfo-----------------------// +//------------- MDPCapabilityInfo-----------------------// +MDPCapabilityInfo :: MDPCapabilityInfo() { + qdutils::querySDEInfo(HAS_UBWC, &isUBwcSupported); + qdutils::querySDEInfo(HAS_WB_UBWC, &isWBUBWCSupported); +} + +//------------- AdrenoMemInfo-----------------------// AdrenoMemInfo::AdrenoMemInfo() { LINK_adreno_compute_aligned_width_and_height = NULL; LINK_adreno_compute_padding = NULL; - LINK_adreno_isMacroTilingSupportedByGpu = NULL; LINK_adreno_compute_compressedfmt_aligned_width_and_height = NULL; + LINK_adreno_isUBWCSupportedByGpu = NULL; LINK_adreno_get_gpu_pixel_alignment = NULL; libadreno_utils = ::dlopen("libadreno_utils.so", RTLD_NOW); @@ -106,14 +124,24 @@ AdrenoMemInfo::AdrenoMemInfo() ::dlsym(libadreno_utils, "compute_aligned_width_and_height"); *(void **)&LINK_adreno_compute_padding = ::dlsym(libadreno_utils, "compute_surface_padding"); - *(void **)&LINK_adreno_isMacroTilingSupportedByGpu = - ::dlsym(libadreno_utils, "isMacroTilingSupportedByGpu"); *(void **)&LINK_adreno_compute_compressedfmt_aligned_width_and_height = ::dlsym(libadreno_utils, "compute_compressedfmt_aligned_width_and_height"); + *(void **)&LINK_adreno_isUBWCSupportedByGpu = + ::dlsym(libadreno_utils, "isUBWCSupportedByGpu"); *(void **)&LINK_adreno_get_gpu_pixel_alignment = ::dlsym(libadreno_utils, "get_gpu_pixel_alignment"); } + + // Check if the overriding property debug.gralloc.gfx_ubwc_disable + // that disables UBWC allocations for the graphics stack is set + gfx_ubwc_disable = 0; + char property[PROPERTY_VALUE_MAX]; + property_get("debug.gralloc.gfx_ubwc_disable", property, "0"); + if(!(strncmp(property, "1", PROPERTY_VALUE_MAX)) || + !(strncmp(property, "true", PROPERTY_VALUE_MAX))) { + gfx_ubwc_disable = 1; + } } AdrenoMemInfo::~AdrenoMemInfo() @@ -123,78 +151,115 @@ AdrenoMemInfo::~AdrenoMemInfo() } } -int AdrenoMemInfo::isMacroTilingSupportedByGPU() -{ - if ((libadreno_utils)) { - if(LINK_adreno_isMacroTilingSupportedByGpu) { - return LINK_adreno_isMacroTilingSupportedByGpu(); +void AdrenoMemInfo::getAlignedWidthAndHeight(const private_handle_t *hnd, int& aligned_w, + int& aligned_h) { + MetaData_t *metadata = (MetaData_t *)hnd->base_metadata; + if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) { + int w = metadata->bufferDim.sliceWidth; + int h = metadata->bufferDim.sliceHeight; + int f = hnd->format; + int usage = 0; + + if (hnd->flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) { + usage = GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; } + + getAlignedWidthAndHeight(w, h, f, usage, aligned_w, aligned_h); + } else { + aligned_w = hnd->width; + aligned_h = hnd->height; + } + +} + +void AdrenoMemInfo::getUnalignedWidthAndHeight(const private_handle_t *hnd, int& unaligned_w, + int& unaligned_h) { + MetaData_t *metadata = (MetaData_t *)hnd->base_metadata; + if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) { + unaligned_w = metadata->bufferDim.sliceWidth; + unaligned_h = metadata->bufferDim.sliceHeight; + } else { + unaligned_w = hnd->unaligned_width; + unaligned_h = hnd->unaligned_height; } - return 0; } +bool isUncompressedRgbFormat(int format) +{ + bool is_rgb_format = false; + + switch (format) + { + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_RGB_888: + case HAL_PIXEL_FORMAT_RGB_565: + case HAL_PIXEL_FORMAT_BGR_565: + case HAL_PIXEL_FORMAT_BGRA_8888: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: + case HAL_PIXEL_FORMAT_R_8: + case HAL_PIXEL_FORMAT_RG_88: + case HAL_PIXEL_FORMAT_BGRX_8888: + case HAL_PIXEL_FORMAT_BGR_888: + case HAL_PIXEL_FORMAT_RGBA_1010102: + case HAL_PIXEL_FORMAT_ARGB_2101010: + case HAL_PIXEL_FORMAT_RGBX_1010102: + case HAL_PIXEL_FORMAT_XRGB_2101010: + case HAL_PIXEL_FORMAT_BGRA_1010102: + case HAL_PIXEL_FORMAT_ABGR_2101010: + case HAL_PIXEL_FORMAT_BGRX_1010102: + case HAL_PIXEL_FORMAT_XBGR_2101010: // Intentional fallthrough + is_rgb_format = true; + break; + default: + break; + } + + return is_rgb_format; +} void AdrenoMemInfo::getAlignedWidthAndHeight(int width, int height, int format, - int tile_enabled, int& aligned_w, int& aligned_h) + int usage, int& aligned_w, int& aligned_h) { - aligned_w = width; - aligned_h = height; - // Currently surface padding is only computed for RGB* surfaces. - if (format <= HAL_PIXEL_FORMAT_BGRA_8888) { - aligned_w = ALIGN(width, 32); - aligned_h = ALIGN(height, 32); + bool ubwc_enabled = isUBwcEnabled(format, usage); - int bpp = 4; - switch(format) - { - case HAL_PIXEL_FORMAT_RGBA_FP16: - bpp = 8; - break; - case HAL_PIXEL_FORMAT_RGB_888: - bpp = 3; - break; - case HAL_PIXEL_FORMAT_RGB_565: - bpp = 2; - break; - default: break; - } - if (libadreno_utils) { - int raster_mode = 0; // Adreno unknown raster mode. - int padding_threshold = 512; // Threshold for padding surfaces. - // the function below computes aligned width and aligned height - // based on linear or macro tile mode selected. - if(LINK_adreno_compute_aligned_width_and_height) { - LINK_adreno_compute_aligned_width_and_height(width, - height, bpp, tile_enabled, - raster_mode, padding_threshold, - &aligned_w, &aligned_h); - - } else if(LINK_adreno_compute_padding) { - int surface_tile_height = 1; // Linear surface - aligned_w = LINK_adreno_compute_padding(width, bpp, - surface_tile_height, raster_mode, - padding_threshold); - ALOGW("%s: Warning!! Old GFX API is used to calculate stride", - __FUNCTION__); - } else { - ALOGW("%s: Warning!! Symbols compute_surface_padding and " \ - "compute_aligned_width_and_height not found", __FUNCTION__); - } - } + // Currently surface padding is only computed for RGB* surfaces. + if (isUncompressedRgbFormat(format) == true) { + int tileEnabled = ubwc_enabled; + getGpuAlignedWidthHeight(width, height, format, tileEnabled, aligned_w, aligned_h); + } else if (ubwc_enabled) { + getYuvUBwcWidthHeight(width, height, format, aligned_w, aligned_h); } else { + aligned_w = width; + aligned_h = height; int alignment = 32; switch (format) { case HAL_PIXEL_FORMAT_YCrCb_420_SP: case HAL_PIXEL_FORMAT_YCbCr_420_SP: if (LINK_adreno_get_gpu_pixel_alignment) { - alignment = LINK_adreno_get_gpu_pixel_alignment(); + alignment = LINK_adreno_get_gpu_pixel_alignment(); } aligned_w = ALIGN(width, alignment); break; case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: aligned_w = ALIGN(width, alignment); break; + case HAL_PIXEL_FORMAT_RAW16: + case HAL_PIXEL_FORMAT_Y16: + case HAL_PIXEL_FORMAT_Y8: + aligned_w = ALIGN(width, 16); + break; + case HAL_PIXEL_FORMAT_RAW12: + aligned_w = ALIGN(width * 12 / 8, 8); + break; + case HAL_PIXEL_FORMAT_RAW10: + aligned_w = ALIGN(width * 10 / 8, 8); + break; + case HAL_PIXEL_FORMAT_RAW8: + aligned_w = ALIGN(width, 8); + break; case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: aligned_w = ALIGN(width, 128); break; @@ -203,6 +268,8 @@ void AdrenoMemInfo::getAlignedWidthAndHeight(int width, int height, int format, case HAL_PIXEL_FORMAT_YCrCb_422_SP: case HAL_PIXEL_FORMAT_YCbCr_422_I: case HAL_PIXEL_FORMAT_YCrCb_422_I: + case HAL_PIXEL_FORMAT_YCbCr_420_P010: + case HAL_PIXEL_FORMAT_CbYCrY_422_I: aligned_w = ALIGN(width, 16); break; case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: @@ -210,7 +277,12 @@ void AdrenoMemInfo::getAlignedWidthAndHeight(int width, int height, int format, aligned_w = VENUS_Y_STRIDE(COLOR_FMT_NV12, width); aligned_h = VENUS_Y_SCANLINES(COLOR_FMT_NV12, height); break; + case HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS: + aligned_w = VENUS_Y_STRIDE(COLOR_FMT_NV21, width); + aligned_h = VENUS_Y_SCANLINES(COLOR_FMT_NV21, height); + break; case HAL_PIXEL_FORMAT_BLOB: + case HAL_PIXEL_FORMAT_RAW_OPAQUE: break; case HAL_PIXEL_FORMAT_NV21_ZSL: aligned_w = ALIGN(width, 64); @@ -253,7 +325,6 @@ void AdrenoMemInfo::getAlignedWidthAndHeight(int width, int height, int format, LINK_adreno_compute_compressedfmt_aligned_width_and_height( width, height, format, 0,raster_mode, padding_threshold, &aligned_w, &aligned_h, &bytesPerPixel); - } else { ALOGW("%s: Warning!! Symbols" \ " compute_compressedfmt_aligned_width_and_height" \ @@ -265,6 +336,106 @@ void AdrenoMemInfo::getAlignedWidthAndHeight(int width, int height, int format, } } +void AdrenoMemInfo::getGpuAlignedWidthHeight(int width, int height, int format, + int tile_enabled, int& aligned_w, int& aligned_h) +{ + aligned_w = ALIGN(width, 32); + aligned_h = ALIGN(height, 32); + + // Don't add any additional padding if debug.gralloc.map_fb_memory + // is enabled + char property[PROPERTY_VALUE_MAX]; + if((property_get("debug.gralloc.map_fb_memory", property, NULL) > 0) && + (!strncmp(property, "1", PROPERTY_VALUE_MAX ) || + (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) { + return; + } + + int bpp = 4; + switch(format) + { + case HAL_PIXEL_FORMAT_RGB_888: + bpp = 3; + break; + case HAL_PIXEL_FORMAT_RGB_565: + case HAL_PIXEL_FORMAT_BGR_565: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: + bpp = 2; + break; + default: break; + } + + if (libadreno_utils) { + int raster_mode = 0; // Adreno unknown raster mode. + int padding_threshold = 512; // Threshold for padding surfaces. + // the function below computes aligned width and aligned height + // based on linear or macro tile mode selected. + if(LINK_adreno_compute_aligned_width_and_height) { + LINK_adreno_compute_aligned_width_and_height(width, + height, bpp, tile_enabled, + raster_mode, padding_threshold, + &aligned_w, &aligned_h); + + } else if(LINK_adreno_compute_padding) { + int surface_tile_height = 1; // Linear surface + aligned_w = LINK_adreno_compute_padding(width, bpp, + surface_tile_height, raster_mode, + padding_threshold); + ALOGW("%s: Warning!! Old GFX API is used to calculate stride", + __FUNCTION__); + } else { + ALOGW("%s: Warning!! Symbols compute_surface_padding and " \ + "compute_aligned_width_and_height not found", __FUNCTION__); + } + } +} + +int AdrenoMemInfo::isUBWCSupportedByGPU(int format) +{ + if (!gfx_ubwc_disable && libadreno_utils) { + if (LINK_adreno_isUBWCSupportedByGpu) { + ADRENOPIXELFORMAT gpu_format = getGpuPixelFormat(format); + return LINK_adreno_isUBWCSupportedByGpu(gpu_format); + } + } + return 0; +} + +ADRENOPIXELFORMAT AdrenoMemInfo::getGpuPixelFormat(int hal_format) +{ + switch (hal_format) { + case HAL_PIXEL_FORMAT_RGBA_8888: + return ADRENO_PIXELFORMAT_R8G8B8A8; + case HAL_PIXEL_FORMAT_RGBX_8888: + return ADRENO_PIXELFORMAT_R8G8B8X8; + case HAL_PIXEL_FORMAT_RGB_565: + return ADRENO_PIXELFORMAT_B5G6R5; + case HAL_PIXEL_FORMAT_BGR_565: + return ADRENO_PIXELFORMAT_R5G6B5; + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + return ADRENO_PIXELFORMAT_NV12; + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC: + return ADRENO_PIXELFORMAT_NV12_EXT; + case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC: + return ADRENO_PIXELFORMAT_TP10; + case HAL_PIXEL_FORMAT_YCbCr_420_P010: + case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC: + return ADRENO_PIXELFORMAT_P010; + case HAL_PIXEL_FORMAT_RGBA_1010102: + return ADRENO_PIXELFORMAT_R10G10B10A2_UNORM; + case HAL_PIXEL_FORMAT_RGBX_1010102: + return ADRENO_PIXELFORMAT_R10G10B10X2_UNORM; + case HAL_PIXEL_FORMAT_ABGR_2101010: + return ADRENO_PIXELFORMAT_A2B10G10R10_UNORM; + default: + ALOGE("%s: No map for format: 0x%x", __FUNCTION__, hal_format); + break; + } + return ADRENO_PIXELFORMAT_UNKNOWN; +} + //-------------- IAllocController-----------------------// IAllocController* IAllocController::sController = NULL; IAllocController* IAllocController::getInstance(void) @@ -280,6 +451,10 @@ IAllocController* IAllocController::getInstance(void) IonController::IonController() { allocateIonMem(); + + char property[PROPERTY_VALUE_MAX]; + property_get("video.disable.ubwc", property, "0"); + mDisableUBWCForEncode = atoi(property); } void IonController::allocateIonMem() @@ -290,68 +465,59 @@ void IonController::allocateIonMem() int IonController::allocate(alloc_data& data, int usage) { int ionFlags = 0; + int ionHeapId = 0; int ret; data.uncached = useUncached(usage); data.allocType = 0; - if(usage & GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP) - ionFlags |= ION_HEAP(ION_SF_HEAP_ID); - - if(usage & GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP) - ionFlags |= ION_HEAP(ION_SYSTEM_HEAP_ID); - - if(usage & GRALLOC_USAGE_PRIVATE_IOMMU_HEAP) - ionFlags |= ION_HEAP(ION_IOMMU_HEAP_ID); - if(usage & GRALLOC_USAGE_PROTECTED) { - if (usage & GRALLOC_USAGE_PRIVATE_MM_HEAP) { - ionFlags |= ION_HEAP(ION_CP_MM_HEAP_ID); - ionFlags |= ION_SECURE; + if (usage & GRALLOC_USAGE_PRIVATE_SECURE_DISPLAY) { + ionHeapId = ION_HEAP(SD_HEAP_ID); + /* + * There is currently no flag in ION for Secure Display + * VM. Please add it to the define once available. + */ + ionFlags |= ION_SD_FLAGS; + } else if (usage & GRALLOC_USAGE_HW_CAMERA_MASK) { + ionHeapId = ION_HEAP(SD_HEAP_ID); + ionFlags |= (usage & GRALLOC_USAGE_HW_COMPOSER) ? ION_SC_PREVIEW_FLAGS : ION_SC_FLAGS; } else { - // for targets/OEMs which do not need HW level protection - // do not set ion secure flag & MM heap. Fallback to IOMMU heap. - ionFlags |= ION_HEAP(ION_IOMMU_HEAP_ID); + ionHeapId = ION_HEAP(CP_HEAP_ID); + ionFlags |= ION_CP_FLAGS; } } else if(usage & GRALLOC_USAGE_PRIVATE_MM_HEAP) { //MM Heap is exclusively a secure heap. //If it is used for non secure cases, fallback to IOMMU heap ALOGW("GRALLOC_USAGE_PRIVATE_MM_HEAP \ cannot be used as an insecure heap!\ - trying to use IOMMU instead !!"); - ionFlags |= ION_HEAP(ION_IOMMU_HEAP_ID); + trying to use system heap instead !!"); + ionHeapId |= ION_HEAP(ION_SYSTEM_HEAP_ID); } if(usage & GRALLOC_USAGE_PRIVATE_CAMERA_HEAP) - ionFlags |= ION_HEAP(ION_CAMERA_HEAP_ID); + ionHeapId |= ION_HEAP(ION_CAMERA_HEAP_ID); if(usage & GRALLOC_USAGE_PRIVATE_ADSP_HEAP) - ionFlags |= ION_HEAP(ION_ADSP_HEAP_ID); + ionHeapId |= ION_HEAP(ION_ADSP_HEAP_ID); if(ionFlags & ION_SECURE) data.allocType |= private_handle_t::PRIV_FLAGS_SECURE_BUFFER; - // if no flags are set, default to - // SF + IOMMU heaps, so that bypass can work - // we can fall back to system heap if - // we run out. - if(!ionFlags) - ionFlags = ION_HEAP(ION_SF_HEAP_ID) | ION_HEAP(ION_IOMMU_HEAP_ID); + // if no ion heap flags are set, default to system heap + if(!ionHeapId) + ionHeapId = ION_HEAP(ION_SYSTEM_HEAP_ID); + //At this point we should have the right heap set, there is no fallback data.flags = ionFlags; + data.heapId = ionHeapId; ret = mIonAlloc->alloc_buffer(data); - // Fallback - if(ret < 0 && canFallback(usage, - (ionFlags & ION_SYSTEM_HEAP_ID))) - { - ALOGW("Falling back to system heap"); - data.flags = ION_HEAP(ION_SYSTEM_HEAP_ID); - ret = mIonAlloc->alloc_buffer(data); - } - if(ret >= 0 ) { data.allocType |= private_handle_t::PRIV_FLAGS_USES_ION; + } else { + ALOGE("%s: Failed to allocate buffer - heap: 0x%x flags: 0x%x", + __FUNCTION__, ionHeapId, ionFlags); } return ret; @@ -369,61 +535,50 @@ IMemAlloc* IonController::getAllocator(int flags) return memalloc; } -bool isMacroTileEnabled(int format, int usage) -{ - bool tileEnabled = false; +// helper function +unsigned int getSize(int format, int width, int height, int usage, + const int alignedw, const int alignedh) { - // Check whether GPU & MDSS supports MacroTiling feature - if(AdrenoMemInfo::getInstance().isMacroTilingSupportedByGPU() && - qdutils::MDPVersion::getInstance().supportsMacroTile()) - { - // check the format - switch(format) - { - case HAL_PIXEL_FORMAT_RGBA_8888: - case HAL_PIXEL_FORMAT_RGBX_8888: - case HAL_PIXEL_FORMAT_BGRA_8888: - case HAL_PIXEL_FORMAT_RGB_565: - { - tileEnabled = true; - // check the usage flags - if (usage & (GRALLOC_USAGE_SW_READ_MASK | - GRALLOC_USAGE_SW_WRITE_MASK)) { - // Application intends to use CPU for rendering - tileEnabled = false; - } - break; - } - default: - break; - } + if (isUBwcEnabled(format, usage)) { + return getUBwcSize(width, height, format, alignedw, alignedh); } - return tileEnabled; -} -// helper function -unsigned int getSize(int format, int width, int height, const int alignedw, - const int alignedh) { unsigned int size = 0; - switch (format) { - case HAL_PIXEL_FORMAT_RGBA_FP16: - size = alignedw * alignedh * 8; - break; case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_RGBX_8888: case HAL_PIXEL_FORMAT_BGRA_8888: case HAL_PIXEL_FORMAT_RGBA_1010102: + case HAL_PIXEL_FORMAT_ARGB_2101010: + case HAL_PIXEL_FORMAT_RGBX_1010102: + case HAL_PIXEL_FORMAT_XRGB_2101010: + case HAL_PIXEL_FORMAT_BGRA_1010102: + case HAL_PIXEL_FORMAT_ABGR_2101010: + case HAL_PIXEL_FORMAT_BGRX_1010102: + case HAL_PIXEL_FORMAT_XBGR_2101010: size = alignedw * alignedh * 4; break; case HAL_PIXEL_FORMAT_RGB_888: size = alignedw * alignedh * 3; break; case HAL_PIXEL_FORMAT_RGB_565: + case HAL_PIXEL_FORMAT_BGR_565: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: case HAL_PIXEL_FORMAT_RAW16: + case HAL_PIXEL_FORMAT_Y16: size = alignedw * alignedh * 2; break; - + case HAL_PIXEL_FORMAT_RAW12: + size = ALIGN(alignedw * alignedh, 4096); + break; + case HAL_PIXEL_FORMAT_RAW10: + size = ALIGN(alignedw * alignedh, 4096); + break; + case HAL_PIXEL_FORMAT_RAW8: + case HAL_PIXEL_FORMAT_Y8: + size = alignedw * alignedh; + break; // adreno formats case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: // NV21 size = ALIGN(alignedw*alignedh, 4096); @@ -449,10 +604,14 @@ unsigned int getSize(int format, int width, int height, const int alignedw, case HAL_PIXEL_FORMAT_YCrCb_420_SP: size = ALIGN((alignedw*alignedh) + (alignedw* alignedh)/2 + 1, 4096); break; + case HAL_PIXEL_FORMAT_YCbCr_420_P010: + size = ALIGN((alignedw * alignedh * 2) + (alignedw * alignedh) + 1, 4096); + break; case HAL_PIXEL_FORMAT_YCbCr_422_SP: case HAL_PIXEL_FORMAT_YCrCb_422_SP: case HAL_PIXEL_FORMAT_YCbCr_422_I: case HAL_PIXEL_FORMAT_YCrCb_422_I: + case HAL_PIXEL_FORMAT_CbYCrY_422_I: if(width & 1) { ALOGE("width is odd for the YUV422_SP format"); return 0; @@ -463,7 +622,11 @@ unsigned int getSize(int format, int width, int height, const int alignedw, case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: size = VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height); break; + case HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS: + size = VENUS_BUFFER_SIZE(COLOR_FMT_NV21, width, height); + break; case HAL_PIXEL_FORMAT_BLOB: + case HAL_PIXEL_FORMAT_RAW_OPAQUE: if(height != 1) { ALOGE("%s: Buffers with format HAL_PIXEL_FORMAT_BLOB \ must have height==1 ", __FUNCTION__); @@ -519,11 +682,11 @@ unsigned int getBufferSizeAndDimensions(int width, int height, int format, AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width, height, format, - false, + 0, alignedw, alignedh); - size = getSize(format, width, height, alignedw, alignedh); + size = getSize(format, width, height, 0 /* usage */, alignedw, alignedh); return size; } @@ -533,91 +696,166 @@ unsigned int getBufferSizeAndDimensions(int width, int height, int format, int usage, int& alignedw, int &alignedh) { unsigned int size; - int tileEnabled = isMacroTileEnabled(format, usage); AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width, height, format, - tileEnabled, + usage, alignedw, alignedh); - size = getSize(format, width, height, alignedw, alignedh); + size = getSize(format, width, height, usage, alignedw, alignedh); return size; } +void getYuvUbwcSPPlaneInfo(uint64_t base, int width, int height, + int color_format, struct android_ycbcr* ycbcr) +{ + // UBWC buffer has these 4 planes in the following sequence: + // Y_Meta_Plane, Y_Plane, UV_Meta_Plane, UV_Plane + unsigned int y_meta_stride, y_meta_height, y_meta_size; + unsigned int y_stride, y_height, y_size; + unsigned int c_meta_stride, c_meta_height, c_meta_size; + unsigned int alignment = 4096; + + y_meta_stride = VENUS_Y_META_STRIDE(color_format, width); + y_meta_height = VENUS_Y_META_SCANLINES(color_format, height); + y_meta_size = ALIGN((y_meta_stride * y_meta_height), alignment); + + y_stride = VENUS_Y_STRIDE(color_format, width); + y_height = VENUS_Y_SCANLINES(color_format, height); + y_size = ALIGN((y_stride * y_height), alignment); + + c_meta_stride = VENUS_UV_META_STRIDE(color_format, width); + c_meta_height = VENUS_UV_META_SCANLINES(color_format, height); + c_meta_size = ALIGN((c_meta_stride * c_meta_height), alignment); + + ycbcr->y = (void*)(base + y_meta_size); + ycbcr->cb = (void*)(base + y_meta_size + y_size + c_meta_size); + ycbcr->cr = (void*)(base + y_meta_size + y_size + + c_meta_size + 1); + ycbcr->ystride = y_stride; + ycbcr->cstride = VENUS_UV_STRIDE(color_format, width); +} -void getBufferAttributes(int width, int height, int format, int usage, - int& alignedw, int &alignedh, int& tileEnabled, unsigned int& size) +void getYuvSPPlaneInfo(uint64_t base, int width, int height, int bpp, + struct android_ycbcr* ycbcr) { - tileEnabled = isMacroTileEnabled(format, usage); + unsigned int ystride, cstride; - AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width, - height, - format, - tileEnabled, - alignedw, - alignedh); - size = getSize(format, width, height, alignedw, alignedh); + ystride = cstride = width * bpp; + ycbcr->y = (void*)base; + ycbcr->cb = (void*)(base + ystride * height); + ycbcr->cr = (void*)(base + ystride * height + 1); + ycbcr->ystride = ystride; + ycbcr->cstride = cstride; + ycbcr->chroma_step = 2 * bpp; } int getYUVPlaneInfo(private_handle_t* hnd, struct android_ycbcr* ycbcr) { int err = 0; + int width = hnd->width; + int height = hnd->height; + int format = hnd->format; + unsigned int ystride, cstride; + memset(ycbcr->reserved, 0, sizeof(ycbcr->reserved)); + MetaData_t *metadata = (MetaData_t *)hnd->base_metadata; + + // Check if UBWC buffer has been rendered in linear format. + if (metadata && (metadata->operation & LINEAR_FORMAT)) { + format = metadata->linearFormat; + } + + // Check metadata if the geometry has been updated. + if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) { + int usage = 0; + + if (hnd->flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) { + usage = GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + } + + AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(metadata->bufferDim.sliceWidth, + metadata->bufferDim.sliceHeight, format, usage, width, height); + } // Get the chroma offsets from the handle width/height. We take advantage // of the fact the width _is_ the stride - switch (hnd->format) { + switch (format) { //Semiplanar case HAL_PIXEL_FORMAT_YCbCr_420_SP: case HAL_PIXEL_FORMAT_YCbCr_422_SP: case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: //Same as YCbCr_420_SP_VENUS - ystride = cstride = hnd->width; - ycbcr->y = (void*)hnd->base; - ycbcr->cb = (void*)(hnd->base + ystride * hnd->height); - ycbcr->cr = (void*)(hnd->base + ystride * hnd->height + 1); - ycbcr->ystride = ystride; - ycbcr->cstride = cstride; + getYuvSPPlaneInfo(hnd->base, width, height, 1, ycbcr); + break; + + case HAL_PIXEL_FORMAT_YCbCr_420_P010: + getYuvSPPlaneInfo(hnd->base, width, height, 2, ycbcr); + break; + + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC: + getYuvUbwcSPPlaneInfo(hnd->base, width, height, + COLOR_FMT_NV12_UBWC, ycbcr); ycbcr->chroma_step = 2; break; + case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC: + getYuvUbwcSPPlaneInfo(hnd->base, width, height, + COLOR_FMT_NV12_BPP10_UBWC, ycbcr); + ycbcr->chroma_step = 3; + break; + case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC: + getYuvUbwcSPPlaneInfo(hnd->base, width, height, + COLOR_FMT_P010_UBWC, ycbcr); + ycbcr->chroma_step = 4; + break; case HAL_PIXEL_FORMAT_YCrCb_420_SP: case HAL_PIXEL_FORMAT_YCrCb_422_SP: case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: + case HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS: case HAL_PIXEL_FORMAT_NV21_ZSL: - ystride = cstride = hnd->width; - ycbcr->y = (void*)hnd->base; - ycbcr->cr = (void*)(hnd->base + ystride * hnd->height); - ycbcr->cb = (void*)(hnd->base + ystride * hnd->height + 1); - ycbcr->ystride = ystride; - ycbcr->cstride = cstride; - ycbcr->chroma_step = 2; + case HAL_PIXEL_FORMAT_RAW16: + case HAL_PIXEL_FORMAT_Y16: + case HAL_PIXEL_FORMAT_RAW12: + case HAL_PIXEL_FORMAT_RAW10: + case HAL_PIXEL_FORMAT_RAW8: + case HAL_PIXEL_FORMAT_Y8: + getYuvSPPlaneInfo(hnd->base, width, height, 1, ycbcr); + std::swap(ycbcr->cb, ycbcr->cr); break; //Planar case HAL_PIXEL_FORMAT_YV12: - ystride = hnd->width; - cstride = ALIGN(hnd->width/2, 16); + ystride = width; + cstride = ALIGN(width/2, 16); ycbcr->y = (void*)hnd->base; - ycbcr->cr = (void*)(hnd->base + ystride * hnd->height); - ycbcr->cb = (void*)(hnd->base + ystride * hnd->height + - cstride * hnd->height/2); + ycbcr->cr = (void*)(hnd->base + ystride * height); + ycbcr->cb = (void*)(hnd->base + ystride * height + + cstride * height/2); ycbcr->ystride = ystride; ycbcr->cstride = cstride; ycbcr->chroma_step = 1; - + break; + case HAL_PIXEL_FORMAT_CbYCrY_422_I: + ystride = width * 2; + cstride = 0; + ycbcr->y = (void*)hnd->base; + ycbcr->cr = NULL; + ycbcr->cb = NULL; + ycbcr->ystride = ystride; + ycbcr->cstride = 0; + ycbcr->chroma_step = 0; break; //Unsupported formats case HAL_PIXEL_FORMAT_YCbCr_422_I: case HAL_PIXEL_FORMAT_YCrCb_422_I: case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: default: - ALOGD("%s: Invalid format passed: 0x%x", __FUNCTION__, - hnd->format); + ALOGD("%s: Invalid format passed: 0x%x", __FUNCTION__, format); err = -EINVAL; } return err; @@ -651,9 +889,13 @@ int alloc_buffer(private_handle_t **pHnd, int w, int h, int format, int usage) return -ENOMEM; } + if(isUBwcEnabled(format, usage)) { + data.allocType |= private_handle_t::PRIV_FLAGS_UBWC_ALIGNED; + } + private_handle_t* hnd = new private_handle_t(data.fd, data.size, data.allocType, 0, format, - alignedw, alignedh); + alignedw, alignedh, -1, 0, 0, w, h); hnd->base = (uint64_t) data.base; hnd->offset = data.offset; hnd->gpuaddr = 0; @@ -673,3 +915,309 @@ void free_buffer(private_handle_t *hnd) delete hnd; } + +// UBWC helper functions +static bool isUBwcFormat(int format) +{ + // Explicitly defined UBWC formats + switch(format) + { + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC: + case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC: + case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC: + return true; + default: + return false; + } +} + +static bool isUBwcSupported(int format) +{ + if (MDPCapabilityInfo::getInstance().isUBwcSupportedByMDP()) { + // Existing HAL formats with UBWC support + switch(format) + { + case HAL_PIXEL_FORMAT_BGR_565: + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: + case HAL_PIXEL_FORMAT_RGBA_1010102: + case HAL_PIXEL_FORMAT_RGBX_1010102: + return true; + default: + break; + } + } + return false; +} + +bool isUBwcEnabled(int format, int usage) +{ + // Allow UBWC, if client is using an explicitly defined UBWC pixel format. + if (isUBwcFormat(format)) + return true; + + if ((usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) && + gralloc::IAllocController::getInstance()->isDisableUBWCForEncoder()) { + return false; + } + + // Allow UBWC, if an OpenGL client sets UBWC usage flag and GPU plus MDP + // support the format. OR if a non-OpenGL client like Rotator, sets UBWC + // usage flag and MDP supports the format. + if ((usage & GRALLOC_USAGE_PRIVATE_ALLOC_UBWC) && isUBwcSupported(format)) { + bool enable = true; + // Query GPU for UBWC only if buffer is intended to be used by GPU. + if (usage & (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER)) { + enable = AdrenoMemInfo::getInstance().isUBWCSupportedByGPU(format); + } + // Allow UBWC, only if CPU usage flags are not set + if (enable && !(usage & (GRALLOC_USAGE_SW_READ_MASK | + GRALLOC_USAGE_SW_WRITE_MASK))) { + return true; + } + } + return false; +} + +static void getYuvUBwcWidthHeight(int width, int height, int format, + int& aligned_w, int& aligned_h) +{ + switch (format) + { + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC: + aligned_w = VENUS_Y_STRIDE(COLOR_FMT_NV12_UBWC, width); + aligned_h = VENUS_Y_SCANLINES(COLOR_FMT_NV12_UBWC, height); + break; + case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC: + // The macro returns the stride which is 4/3 times the width, hence * 3/4 + aligned_w = (VENUS_Y_STRIDE(COLOR_FMT_NV12_BPP10_UBWC, width) * 3) / 4; + aligned_h = VENUS_Y_SCANLINES(COLOR_FMT_NV12_BPP10_UBWC, height); + break; + case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC: + // The macro returns the stride which is 2 times the width, hence / 2 + aligned_w = (VENUS_Y_STRIDE(COLOR_FMT_P010_UBWC, width) / 2); + aligned_h = VENUS_Y_SCANLINES(COLOR_FMT_P010_UBWC, height); + break; + default: + ALOGE("%s: Unsupported pixel format: 0x%x", __FUNCTION__, format); + aligned_w = 0; + aligned_h = 0; + break; + } +} + +static void getRgbUBwcBlockSize(int bpp, int& block_width, int& block_height) +{ + block_width = 0; + block_height = 0; + + switch(bpp) + { + case 2: + case 4: + block_width = 16; + block_height = 4; + break; + case 8: + block_width = 8; + block_height = 4; + break; + case 16: + block_width = 4; + block_height = 4; + break; + default: + ALOGE("%s: Unsupported bpp: %d", __FUNCTION__, bpp); + break; + } +} + +static unsigned int getRgbUBwcMetaBufferSize(int width, int height, int bpp) +{ + unsigned int size = 0; + int meta_width, meta_height; + int block_width, block_height; + + getRgbUBwcBlockSize(bpp, block_width, block_height); + + if (!block_width || !block_height) { + ALOGE("%s: Unsupported bpp: %d", __FUNCTION__, bpp); + return size; + } + + // Align meta buffer height to 16 blocks + meta_height = ALIGN(((height + block_height - 1) / block_height), 16); + + // Align meta buffer width to 64 blocks + meta_width = ALIGN(((width + block_width - 1) / block_width), 64); + + // Align meta buffer size to 4K + size = ALIGN((meta_width * meta_height), 4096); + return size; +} + +static unsigned int getUBwcSize(int width, int height, int format, + const int alignedw, const int alignedh) { + + unsigned int size = 0; + switch (format) { + case HAL_PIXEL_FORMAT_BGR_565: + size = alignedw * alignedh * 2; + size += getRgbUBwcMetaBufferSize(width, height, 2); + break; + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_RGBA_1010102: + case HAL_PIXEL_FORMAT_RGBX_1010102: + size = alignedw * alignedh * 4; + size += getRgbUBwcMetaBufferSize(width, height, 4); + break; + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC: + size = VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC, width, height); + break; + case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC: + size = VENUS_BUFFER_SIZE(COLOR_FMT_NV12_BPP10_UBWC, width, height); + break; + case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC: + size = VENUS_BUFFER_SIZE(COLOR_FMT_P010_UBWC, width, height); + break; + default: + ALOGE("%s: Unsupported pixel format: 0x%x", __FUNCTION__, format); + break; + } + return size; +} + +int getRgbDataAddress(private_handle_t* hnd, void** rgb_data) +{ + int err = 0; + + // This api is for RGB* formats + if (!isUncompressedRgbFormat(hnd->format)) { + return -EINVAL; + } + + // linear buffer + if (!(hnd->flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED)) { + *rgb_data = (void*)hnd->base; + return err; + } + + // Ubwc buffers + unsigned int meta_size = 0; + switch (hnd->format) { + case HAL_PIXEL_FORMAT_BGR_565: + meta_size = getRgbUBwcMetaBufferSize(hnd->width, hnd->height, 2); + break; + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_RGBA_1010102: + case HAL_PIXEL_FORMAT_RGBX_1010102: + meta_size = getRgbUBwcMetaBufferSize(hnd->width, hnd->height, 4); + break; + default: + ALOGE("%s:Unsupported RGB format: 0x%x", __FUNCTION__, hnd->format); + err = -EINVAL; + break; + } + + *rgb_data = (void*)(hnd->base + meta_size); + return err; +} + +int getBufferLayout(private_handle_t *hnd, uint32_t stride[4], + uint32_t offset[4], uint32_t *num_planes) { + if (!hnd || !stride || !offset || !num_planes) { + return -EINVAL; + } + + struct android_ycbcr yuvInfo = {}; + *num_planes = 1; + stride[0] = 0; + + switch (hnd->format) { + case HAL_PIXEL_FORMAT_RGB_565: + case HAL_PIXEL_FORMAT_BGR_565: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: + stride[0] = hnd->width * 2; + break; + case HAL_PIXEL_FORMAT_RGB_888: + stride[0] = hnd->width * 3; + break; + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_BGRA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_BGRX_8888: + case HAL_PIXEL_FORMAT_RGBA_1010102: + case HAL_PIXEL_FORMAT_ARGB_2101010: + case HAL_PIXEL_FORMAT_RGBX_1010102: + case HAL_PIXEL_FORMAT_XRGB_2101010: + case HAL_PIXEL_FORMAT_BGRA_1010102: + case HAL_PIXEL_FORMAT_ABGR_2101010: + case HAL_PIXEL_FORMAT_BGRX_1010102: + case HAL_PIXEL_FORMAT_XBGR_2101010: + stride[0] = hnd->width * 4; + break; + } + + // Format is RGB + if (stride[0]) { + return 0; + } + + (*num_planes)++; + int ret = getYUVPlaneInfo(hnd, &yuvInfo); + if (ret < 0) { + ALOGE("%s failed", __FUNCTION__); + return ret; + } + + stride[0] = static_cast<uint32_t>(yuvInfo.ystride); + offset[0] = static_cast<uint32_t>( + reinterpret_cast<uint64_t>(yuvInfo.y) - hnd->base); + stride[1] = static_cast<uint32_t>(yuvInfo.cstride); + switch (hnd->format) { + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC: + case HAL_PIXEL_FORMAT_YCbCr_420_P010: + case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC: + case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC: + offset[1] = static_cast<uint32_t>( + reinterpret_cast<uint64_t>(yuvInfo.cb) - hnd->base); + break; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS: + case HAL_PIXEL_FORMAT_YCrCb_422_SP: + offset[1] = static_cast<uint32_t>( + reinterpret_cast<uint64_t>(yuvInfo.cr) - hnd->base); + break; + case HAL_PIXEL_FORMAT_YV12: + offset[1] = static_cast<uint32_t>( + reinterpret_cast<uint64_t>(yuvInfo.cr) - hnd->base); + stride[2] = static_cast<uint32_t>(yuvInfo.cstride); + offset[2] = static_cast<uint32_t>( + reinterpret_cast<uint64_t>(yuvInfo.cb) - hnd->base); + (*num_planes)++; + break; + default: + ALOGW("%s: Unsupported format %s", __FUNCTION__, + qdutils::GetHALPixelFormatString(hnd->format)); + ret = -EINVAL; + } + + if (hnd->flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) { + std::fill(offset, offset + 4, 0); + } + + return 0; +} diff --git a/msm8909/libgralloc/alloc_controller.h b/msm8909/libgralloc/alloc_controller.h index f0b8ed9a..45977e2b 100644 --- a/msm8909/libgralloc/alloc_controller.h +++ b/msm8909/libgralloc/alloc_controller.h @@ -29,6 +29,17 @@ #ifndef GRALLOC_ALLOCCONTROLLER_H #define GRALLOC_ALLOCCONTROLLER_H +#define SZ_2M 0x200000 +#define SZ_1M 0x100000 +#define SZ_4K 0x1000 + +/* TODO: Move this to the common makefile */ +#ifdef MASTER_SIDE_CP +#define SECURE_ALIGN SZ_4K +#else +#define SECURE_ALIGN SZ_1M +#endif + namespace gralloc { struct alloc_data; @@ -45,6 +56,8 @@ class IAllocController { virtual IMemAlloc* getAllocator(int flags) = 0; + virtual bool isDisableUBWCForEncoder() = 0; + virtual ~IAllocController() {}; static IAllocController* getInstance(void); @@ -61,10 +74,15 @@ class IonController : public IAllocController { virtual IMemAlloc* getAllocator(int flags); + virtual bool isDisableUBWCForEncoder() { + return mDisableUBWCForEncode; + } + IonController(); private: IonAlloc* mIonAlloc; + bool mDisableUBWCForEncode; void allocateIonMem(); }; diff --git a/msm8909/libgralloc/framebuffer.cpp b/msm8909/libgralloc/framebuffer.cpp index b0a9a1e7..dd4842f2 100644 --- a/msm8909/libgralloc/framebuffer.cpp +++ b/msm8909/libgralloc/framebuffer.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 The Android Open Source Project - * Copyright (c) 2010-2014,2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2010-2014 The Linux Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,7 +34,9 @@ #include <linux/fb.h> #include <linux/msm_mdp.h> +#ifndef TARGET_HEADLESS #include <GLES/gl.h> +#endif #include "gralloc_priv.h" #include "fb_priv.h" @@ -57,7 +59,6 @@ struct fb_context_t { static int fb_setSwapInterval(struct framebuffer_device_t* dev, int interval) { -#ifdef DEBUG_SWAPINTERVAL //XXX: Get the value here and implement along with //single vsync in HWC char pval[PROPERTY_VALUE_MAX]; @@ -65,7 +66,6 @@ static int fb_setSwapInterval(struct framebuffer_device_t* dev, int property_interval = atoi(pval); if (property_interval >= 0) interval = property_interval; -#endif private_module_t* m = reinterpret_cast<private_module_t*>( dev->common.module); @@ -101,7 +101,9 @@ static int fb_compositionComplete(struct framebuffer_device_t* dev) if(!dev) { return -1; } +#ifndef TARGET_HEADLESS glFinish(); +#endif return 0; } diff --git a/msm8909/libgralloc/gpu.cpp b/msm8909/libgralloc/gpu.cpp index b95077fc..c57ff902 100644 --- a/msm8909/libgralloc/gpu.cpp +++ b/msm8909/libgralloc/gpu.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 The Android Open Source Project - * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2014,2017 The Linux Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,17 +20,17 @@ #include <fcntl.h> #include <cutils/properties.h> #include <sys/mman.h> +#include <linux/msm_ion.h> +#include <qdMetaData.h> +#include <algorithm> #include "gr.h" #include "gpu.h" #include "memalloc.h" #include "alloc_controller.h" -#include <qdMetaData.h> using namespace gralloc; -#define SZ_1M 0x100000 - gpu_context_t::gpu_context_t(const private_module_t* module, IAllocController* alloc_ctrl ) : mAllocCtrl(alloc_ctrl) @@ -54,6 +54,16 @@ int gpu_context_t::gralloc_alloc_buffer(unsigned int size, int usage, { int err = 0; int flags = 0; + int alignedw = 0; + int alignedh = 0; + + AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width, + height, + format, + usage, + alignedw, + alignedh); + size = roundUpToPageSize(size); alloc_data data; data.offset = 0; @@ -64,14 +74,16 @@ int gpu_context_t::gralloc_alloc_buffer(unsigned int size, int usage, else data.align = getpagesize(); - /* force 1MB alignment selectively for secure buffers, MDP5 onwards */ -#ifdef MDSS_TARGET - if ((usage & GRALLOC_USAGE_PROTECTED) && - (usage & GRALLOC_USAGE_PRIVATE_MM_HEAP)) { - data.align = ALIGN((int) data.align, SZ_1M); + if (usage & GRALLOC_USAGE_PROTECTED) { + if ((usage & GRALLOC_USAGE_PRIVATE_SECURE_DISPLAY) || + (usage & GRALLOC_USAGE_HW_CAMERA_MASK)) { + /* The alignment here reflects qsee mmu V7L/V8L requirement */ + data.align = SZ_2M; + } else { + data.align = SECURE_ALIGN; + } size = ALIGN(size, data.align); } -#endif data.size = size; data.pHandle = (uintptr_t) pHandle; @@ -86,7 +98,7 @@ int gpu_context_t::gralloc_alloc_buffer(unsigned int size, int usage, eData.size = ROUND_UP_PAGESIZE(sizeof(MetaData_t)); eData.pHandle = data.pHandle; eData.align = getpagesize(); - int eDataUsage = GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP; + int eDataUsage = 0; int eDataErr = mAllocCtrl->allocate(eData, eDataUsage); ALOGE_IF(eDataErr, "gralloc failed for eDataErr=%s", strerror(-eDataErr)); @@ -94,36 +106,11 @@ int gpu_context_t::gralloc_alloc_buffer(unsigned int size, int usage, if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY) { flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY; } + if (usage & GRALLOC_USAGE_PRIVATE_INTERNAL_ONLY) { flags |= private_handle_t::PRIV_FLAGS_INTERNAL_ONLY; } - ColorSpace_t colorSpace = ITU_R_601; - flags |= private_handle_t::PRIV_FLAGS_ITU_R_601; - if (bufferType == BUFFER_TYPE_VIDEO) { - if (usage & GRALLOC_USAGE_HW_CAMERA_WRITE) { -#ifndef MDSS_TARGET - colorSpace = ITU_R_601_FR; - flags |= private_handle_t::PRIV_FLAGS_ITU_R_601_FR; -#else - // Per the camera spec ITU 709 format should be set only for - // video encoding. - // It should be set to ITU 601 full range format for any other - // camera buffer - // - if (usage & GRALLOC_USAGE_HW_CAMERA_MASK) { - if (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) { - flags |= private_handle_t::PRIV_FLAGS_ITU_R_709; - colorSpace = ITU_R_709; - } else { - flags |= private_handle_t::PRIV_FLAGS_ITU_R_601_FR; - colorSpace = ITU_R_601_FR; - } - } -#endif - } - } - if (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER ) { flags |= private_handle_t::PRIV_FLAGS_VIDEO_ENCODER; } @@ -148,8 +135,8 @@ int gpu_context_t::gralloc_alloc_buffer(unsigned int size, int usage, flags |= private_handle_t::PRIV_FLAGS_SECURE_DISPLAY; } - if(isMacroTileEnabled(format, usage)) { - flags |= private_handle_t::PRIV_FLAGS_TILE_RENDERED; + if (isUBwcEnabled(format, usage)) { + flags |= private_handle_t::PRIV_FLAGS_UBWC_ALIGNED; } if(usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) { @@ -163,6 +150,10 @@ int gpu_context_t::gralloc_alloc_buffer(unsigned int size, int usage, flags |= private_handle_t::PRIV_FLAGS_NON_CPU_WRITER; } + if(usage & GRALLOC_USAGE_HW_COMPOSER) { + flags |= private_handle_t::PRIV_FLAGS_DISP_CONSUMER; + } + if(false == data.uncached) { flags |= private_handle_t::PRIV_FLAGS_CACHED; } @@ -170,19 +161,18 @@ int gpu_context_t::gralloc_alloc_buffer(unsigned int size, int usage, flags |= data.allocType; uint64_t eBaseAddr = (uint64_t)(eData.base) + eData.offset; private_handle_t *hnd = new private_handle_t(data.fd, size, flags, - bufferType, format, width, height, eData.fd, eData.offset, - eBaseAddr); + bufferType, format, alignedw, alignedh, + eData.fd, eData.offset, eBaseAddr, width, height); hnd->offset = data.offset; hnd->base = (uint64_t)(data.base) + data.offset; hnd->gpuaddr = 0; + ColorSpace_t colorSpace = ITU_R_601; setMetaData(hnd, UPDATE_COLOR_SPACE, (void*) &colorSpace); - *pHandle = hnd; } ALOGE_IF(err, "gralloc failed err=%s", strerror(-err)); - return err; } @@ -191,12 +181,9 @@ void gpu_context_t::getGrallocInformationFromFormat(int inputFormat, { *bufferType = BUFFER_TYPE_VIDEO; - if (inputFormat <= HAL_PIXEL_FORMAT_BGRA_8888) { + if (isUncompressedRgbFormat(inputFormat) == TRUE) { // RGB formats *bufferType = BUFFER_TYPE_UI; - } else if ((inputFormat == HAL_PIXEL_FORMAT_R_8) || - (inputFormat == HAL_PIXEL_FORMAT_RG_88)) { - *bufferType = BUFFER_TYPE_UI; } } @@ -205,10 +192,7 @@ int gpu_context_t::gralloc_alloc_framebuffer_locked(int usage, { private_module_t* m = reinterpret_cast<private_module_t*>(common.module); - // we don't support framebuffer allocations with graphics heap flags - if (usage & GRALLOC_HEAP_MASK) { - return -EINVAL; - } + // This allocation will only happen when gralloc is in fb mode if (m->framebuffer == NULL) { ALOGE("%s: Invalid framebuffer", __FUNCTION__); @@ -287,22 +271,54 @@ int gpu_context_t::alloc_impl(int w, int h, int format, int usage, //the usage bits, gralloc assigns a format. if(format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED || format == HAL_PIXEL_FORMAT_YCbCr_420_888) { - if(usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) - grallocFormat = HAL_PIXEL_FORMAT_NV12_ENCODEABLE; //NV12 - else if((usage & GRALLOC_USAGE_HW_CAMERA_MASK) + if (usage & GRALLOC_USAGE_PRIVATE_ALLOC_UBWC) + grallocFormat = HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC; + else if(usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) { + if(MDPCapabilityInfo::getInstance().isWBUBWCSupportedByMDP() && + !IAllocController::getInstance()->isDisableUBWCForEncoder() && + usage & GRALLOC_USAGE_HW_COMPOSER) + grallocFormat = HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC; + else + grallocFormat = HAL_PIXEL_FORMAT_NV12_ENCODEABLE; //NV12 + } else if((usage & GRALLOC_USAGE_HW_CAMERA_MASK) == GRALLOC_USAGE_HW_CAMERA_ZSL) grallocFormat = HAL_PIXEL_FORMAT_NV21_ZSL; //NV21 ZSL else if(usage & GRALLOC_USAGE_HW_CAMERA_READ) grallocFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP; //NV21 - else if(usage & GRALLOC_USAGE_HW_CAMERA_WRITE) - grallocFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP; //NV21 - else if(usage & GRALLOC_USAGE_HW_COMPOSER) + else if(usage & GRALLOC_USAGE_HW_CAMERA_WRITE) { + if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) { + grallocFormat = HAL_PIXEL_FORMAT_NV21_ZSL; //NV21 + } else { + grallocFormat = HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS; //NV12 preview + } + } else if(usage & GRALLOC_USAGE_HW_COMPOSER) //XXX: If we still haven't set a format, default to RGBA8888 grallocFormat = HAL_PIXEL_FORMAT_RGBA_8888; - //If no other usage flags are detected, default the - //flexible YUV format to NV21. - else if(format == HAL_PIXEL_FORMAT_YCbCr_420_888) - grallocFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP; + else if(format == HAL_PIXEL_FORMAT_YCbCr_420_888) { + //If no other usage flags are detected, default the + //flexible YUV format to NV21_ZSL + grallocFormat = HAL_PIXEL_FORMAT_NV21_ZSL; + } + } + + bool useFbMem = false; + char property[PROPERTY_VALUE_MAX]; + char isUBWC[PROPERTY_VALUE_MAX]; + if (usage & GRALLOC_USAGE_HW_FB) { + if ((property_get("debug.gralloc.map_fb_memory", property, NULL) > 0) && + (!strncmp(property, "1", PROPERTY_VALUE_MAX ) || + (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) { + useFbMem = true; + } else { + usage &= ~GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + if (property_get("debug.gralloc.enable_fb_ubwc", isUBWC, NULL) > 0){ + if ((!strncmp(isUBWC, "1", PROPERTY_VALUE_MAX)) || + (!strncasecmp(isUBWC, "true", PROPERTY_VALUE_MAX))) { + // Allocate UBWC aligned framebuffer + usage |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + } + } + } } getGrallocInformationFromFormat(grallocFormat, &bufferType); @@ -314,8 +330,12 @@ int gpu_context_t::alloc_impl(int w, int h, int format, int usage, size = (bufferSize >= size)? bufferSize : size; int err = 0; - err = gralloc_alloc_buffer(size, usage, pHandle, bufferType, - grallocFormat, alignedw, alignedh); + if(useFbMem) { + err = gralloc_alloc_framebuffer(usage, pHandle); + } else { + err = gralloc_alloc_buffer(size, usage, pHandle, bufferType, + grallocFormat, w, h); + } if (err < 0) { return err; @@ -348,6 +368,7 @@ int gpu_context_t::free_impl(private_handle_t const* hnd) { if (err) return err; } + delete hnd; return 0; } diff --git a/msm8909/libgralloc/gpu.h b/msm8909/libgralloc/gpu.h index 82d49a1a..2248d30d 100644 --- a/msm8909/libgralloc/gpu.h +++ b/msm8909/libgralloc/gpu.h @@ -23,7 +23,7 @@ #include <stdlib.h> #include <string.h> -#include <log/log.h> +#include <cutils/log.h> #include "gralloc_priv.h" #include "fb_priv.h" diff --git a/msm8909/libgralloc/gr.h b/msm8909/libgralloc/gr.h index 1f902a55..dad4a38a 100644 --- a/msm8909/libgralloc/gr.h +++ b/msm8909/libgralloc/gr.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 The Android Open Source Project - * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * Copyright (c) 2011 - 2017, The Linux Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,9 +24,11 @@ #include <hardware/gralloc.h> #include <pthread.h> #include <errno.h> +#include <unistd.h> #include <cutils/native_handle.h> #include <utils/Singleton.h> +#include "adreno_utils.h" /*****************************************************************************/ @@ -34,7 +36,7 @@ struct private_module_t; struct private_handle_t; inline unsigned int roundUpToPageSize(unsigned int x) { - return (x + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1); + return (x + (getpagesize()-1)) & ~(getpagesize()-1); } template <class Type> @@ -52,15 +54,6 @@ unsigned int getBufferSizeAndDimensions(int width, int height, int format, unsigned int getBufferSizeAndDimensions(int width, int height, int format, int& alignedw, int &alignedh); - -// Attributes include aligned width, aligned height, tileEnabled and size of the buffer -void getBufferAttributes(int width, int height, int format, int usage, - int& alignedw, int &alignedh, - int& tileEnabled, unsigned int &size); - - -bool isMacroTileEnabled(int format, int usage); - int decideBufferHandlingMechanism(int format, const char *compositionUsed, int hasBlitEngine, int *needConversion, int *useBufferDirectly); @@ -70,7 +63,17 @@ int decideBufferHandlingMechanism(int format, const char *compositionUsed, int alloc_buffer(private_handle_t **pHnd, int w, int h, int format, int usage); void free_buffer(private_handle_t *hnd); int getYUVPlaneInfo(private_handle_t* pHnd, struct android_ycbcr* ycbcr); +int getRgbDataAddress(private_handle_t* pHnd, void** rgb_data); +// To query if UBWC is enabled, based on format and usage flags +bool isUBwcEnabled(int format, int usage); + +// Function to check if the format is an RGB format +bool isUncompressedRgbFormat(int format); + +// Returns number of planes, stride and offset of each plane for a given w,h,f +int getBufferLayout(private_handle_t *hnd, uint32_t stride[4], + uint32_t offset[4], uint32_t *num_planes); /*****************************************************************************/ class Locker { @@ -106,23 +109,54 @@ class AdrenoMemInfo : public android::Singleton <AdrenoMemInfo> ~AdrenoMemInfo(); /* + * Function to compute aligned width and aligned height based on + * width, height, format and usage flags. + * + * @return aligned width, aligned height + */ + void getAlignedWidthAndHeight(int width, int height, int format, + int usage, int& aligned_w, int& aligned_h); + + /* + * Function to compute aligned width and aligned height based on + * private handle + * + * @return aligned width, aligned height + */ + void getAlignedWidthAndHeight(const private_handle_t *hnd, int& aligned_w, int& aligned_h); + + /* * Function to compute the adreno aligned width and aligned height * based on the width and format. * * @return aligned width, aligned height */ - void getAlignedWidthAndHeight(int width, int height, int format, + void getGpuAlignedWidthHeight(int width, int height, int format, int tileEnabled, int& alignedw, int &alignedh); /* - * Function to return whether GPU support MacroTile feature + * Function to compute unaligned width and unaligned height based on + * private handle * - * @return >0 : supported - * 0 : not supported + * @return unaligned width, unaligned height + */ + void getUnalignedWidthAndHeight(const private_handle_t *hnd, int& unaligned_w, + int& unaligned_h); + /* + * Function to query whether GPU supports UBWC for given HAL format + * @return > 0 : supported + * 0 : not supported */ - int isMacroTilingSupportedByGPU(); + int isUBWCSupportedByGPU(int format); + + /* + * Function to get the corresponding Adreno format for given HAL format + */ + ADRENOPIXELFORMAT getGpuPixelFormat(int hal_format); private: + // Overriding flag to disable UBWC alloc for graphics stack + int gfx_ubwc_disable; // Pointer to the padding library. void *libadreno_utils; @@ -141,8 +175,6 @@ class AdrenoMemInfo : public android::Singleton <AdrenoMemInfo> int *aligned_w, int *aligned_h); - int (*LINK_adreno_isMacroTilingSupportedByGpu) (void); - void(*LINK_adreno_compute_compressedfmt_aligned_width_and_height)( int width, int height, @@ -154,6 +186,33 @@ class AdrenoMemInfo : public android::Singleton <AdrenoMemInfo> int *aligned_h, int *bpp); + int (*LINK_adreno_isUBWCSupportedByGpu) (ADRENOPIXELFORMAT format); + unsigned int (*LINK_adreno_get_gpu_pixel_alignment) (); }; + + +class MDPCapabilityInfo : public android::Singleton <MDPCapabilityInfo> +{ + int isUBwcSupported = 0; + int isWBUBWCSupported = 0; + + public: + MDPCapabilityInfo(); + /* + * Function to return whether MDP supports UBWC feature + * + * @return 1 : supported + * 0 : not supported + */ + int isUBwcSupportedByMDP() { return isUBwcSupported; } + /* + * Function to return whether MDP WB block outputs UBWC format + * + * @return 1 : supported + * 0 : not supported + */ + int isWBUBWCSupportedByMDP() { return isWBUBWCSupported; } +}; + #endif /* GR_H_ */ diff --git a/msm8909/libgralloc/gralloc.cpp b/msm8909/libgralloc/gralloc.cpp index 79e2e9cc..237b8a80 100644 --- a/msm8909/libgralloc/gralloc.cpp +++ b/msm8909/libgralloc/gralloc.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008, The Android Open Source Project - * Copyright (c) 2011-2012,2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/msm8909/libgralloc/gralloc_priv.h b/msm8909/libgralloc/gralloc_priv.h deleted file mode 100644 index 4452b5af..00000000 --- a/msm8909/libgralloc/gralloc_priv.h +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. - * - * 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 GRALLOC_PRIV_H_ -#define GRALLOC_PRIV_H_ - -#include <stdint.h> -#include <limits.h> -#include <sys/cdefs.h> -#include <hardware/gralloc.h> -#include <pthread.h> -#include <errno.h> -#include <unistd.h> - -#include <cutils/native_handle.h> - -#include <cutils/log.h> - -#define ROUND_UP_PAGESIZE(x) ( (((unsigned long)(x)) + PAGE_SIZE-1) & \ - (~(PAGE_SIZE-1)) ) - -enum { - /* gralloc usage bits indicating the type - * of allocation that should be used */ - - /* SYSTEM heap comes from kernel vmalloc, - * can never be uncached, is not secured*/ - GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP = GRALLOC_USAGE_PRIVATE_0, - /* SF heap is used for application buffers, is not secured */ - GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP = GRALLOC_USAGE_PRIVATE_1, - /* IOMMU heap comes from manually allocated pages, - * can be cached/uncached, is not secured */ - GRALLOC_USAGE_PRIVATE_IOMMU_HEAP = GRALLOC_USAGE_PRIVATE_2, - /* MM heap is a carveout heap for video, can be secured*/ - GRALLOC_USAGE_PRIVATE_MM_HEAP = GRALLOC_USAGE_PRIVATE_3, - /* ADSP heap is a carveout heap, is not secured*/ - GRALLOC_USAGE_PRIVATE_ADSP_HEAP = 0x01000000, - - /* Set this for allocating uncached memory (using O_DSYNC) - * cannot be used with noncontiguous heaps */ - GRALLOC_USAGE_PRIVATE_UNCACHED = 0x02000000, - - /* Buffer content should be displayed on an primary display only */ - GRALLOC_USAGE_PRIVATE_INTERNAL_ONLY = 0x04000000, - - /* Buffer content should be displayed on an external display only */ - GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY = 0x08000000, - - /* This flag is set for WFD usecase */ - GRALLOC_USAGE_PRIVATE_WFD = 0x00200000, - - /* CAMERA heap is a carveout heap for camera, is not secured*/ - GRALLOC_USAGE_PRIVATE_CAMERA_HEAP = 0x00400000, - - /* This flag is used for SECURE display usecase */ - GRALLOC_USAGE_PRIVATE_SECURE_DISPLAY = 0x00800000, -}; - -enum { - /* Gralloc perform enums - */ - GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER = 1, - // This will be deprecated from latest graphics drivers. This is kept - // for those backward compatibility i.e., newer Display HAL + older graphics - // libraries - GRALLOC_MODULE_PERFORM_GET_STRIDE, - GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_FROM_HANDLE, - GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_AND_HEIGHT_FROM_HANDLE, - GRALLOC_MODULE_PERFORM_GET_ATTRIBUTES, - GRALLOC_MODULE_PERFORM_GET_COLOR_SPACE_FROM_HANDLE, - GRALLOC_MODULE_PERFORM_GET_YUV_PLANE_INFO, -}; - -#define GRALLOC_HEAP_MASK (GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP |\ - GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP |\ - GRALLOC_USAGE_PRIVATE_IOMMU_HEAP |\ - GRALLOC_USAGE_PRIVATE_MM_HEAP |\ - GRALLOC_USAGE_PRIVATE_ADSP_HEAP) - -#define INTERLACE_MASK 0x80 -#define S3D_FORMAT_MASK 0xFF000 -/*****************************************************************************/ -enum { - /* OEM specific HAL formats */ - HAL_PIXEL_FORMAT_RGBA_5551 = 6, - HAL_PIXEL_FORMAT_RGBA_4444 = 7, - HAL_PIXEL_FORMAT_NV12_ENCODEABLE = 0x102, - HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS = 0x7FA30C04, - HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED = 0x7FA30C03, - HAL_PIXEL_FORMAT_YCbCr_420_SP = 0x109, - HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO = 0x7FA30C01, - HAL_PIXEL_FORMAT_YCrCb_422_SP = 0x10B, - HAL_PIXEL_FORMAT_R_8 = 0x10D, - HAL_PIXEL_FORMAT_RG_88 = 0x10E, - HAL_PIXEL_FORMAT_YCbCr_444_SP = 0x10F, - HAL_PIXEL_FORMAT_YCrCb_444_SP = 0x110, - HAL_PIXEL_FORMAT_YCrCb_422_I = 0x111, - HAL_PIXEL_FORMAT_BGRX_8888 = 0x112, - HAL_PIXEL_FORMAT_NV21_ZSL = 0x113, - HAL_PIXEL_FORMAT_INTERLACE = 0x180, - //v4l2_fourcc('Y', 'U', 'Y', 'L'). 24 bpp YUYV 4:2:2 10 bit per component - HAL_PIXEL_FORMAT_YCbCr_422_I_10BIT = 0x4C595559, - //v4l2_fourcc('Y', 'B', 'W', 'C'). 10 bit per component. This compressed - //format reduces the memory access bandwidth - HAL_PIXEL_FORMAT_YCbCr_422_I_10BIT_COMPRESSED = 0x43574259, - - //Khronos ASTC formats - HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_4x4_KHR = 0x93B0, - HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_5x4_KHR = 0x93B1, - HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_5x5_KHR = 0x93B2, - HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_6x5_KHR = 0x93B3, - HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_6x6_KHR = 0x93B4, - HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x5_KHR = 0x93B5, - HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x6_KHR = 0x93B6, - HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x8_KHR = 0x93B7, - HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x5_KHR = 0x93B8, - HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x6_KHR = 0x93B9, - HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x8_KHR = 0x93BA, - HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x10_KHR = 0x93BB, - HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_12x10_KHR = 0x93BC, - HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_12x12_KHR = 0x93BD, - HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR = 0x93D0, - HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR = 0x93D1, - HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR = 0x93D2, - HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR = 0x93D3, - HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR = 0x93D4, - HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR = 0x93D5, - HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR = 0x93D6, - HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR = 0x93D7, - HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR = 0x93D8, - HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR = 0x93D9, - HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR = 0x93DA, - HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR = 0x93DB, - HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR = 0x93DC, - HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR = 0x93DD, -}; - -/* possible formats for 3D content*/ -enum { - HAL_NO_3D = 0x0000, - HAL_3D_IN_SIDE_BY_SIDE_L_R = 0x10000, - HAL_3D_IN_TOP_BOTTOM = 0x20000, - HAL_3D_IN_INTERLEAVE = 0x40000, - HAL_3D_IN_SIDE_BY_SIDE_R_L = 0x80000, - HAL_3D_OUT_SIDE_BY_SIDE = 0x1000, - HAL_3D_OUT_TOP_BOTTOM = 0x2000, - HAL_3D_OUT_INTERLEAVE = 0x4000, - HAL_3D_OUT_MONOSCOPIC = 0x8000 -}; - -enum { - BUFFER_TYPE_UI = 0, - BUFFER_TYPE_VIDEO -}; - -/*****************************************************************************/ - -#ifdef __cplusplus -struct private_handle_t : public native_handle { -#else - struct private_handle_t { - native_handle_t nativeHandle; -#endif - enum { - PRIV_FLAGS_FRAMEBUFFER = 0x00000001, - PRIV_FLAGS_USES_PMEM = 0x00000002, - PRIV_FLAGS_USES_PMEM_ADSP = 0x00000004, - PRIV_FLAGS_USES_ION = 0x00000008, - PRIV_FLAGS_USES_ASHMEM = 0x00000010, - PRIV_FLAGS_NEEDS_FLUSH = 0x00000020, - PRIV_FLAGS_INTERNAL_ONLY = 0x00000040, - PRIV_FLAGS_NON_CPU_WRITER = 0x00000080, - PRIV_FLAGS_NONCONTIGUOUS_MEM = 0x00000100, - PRIV_FLAGS_CACHED = 0x00000200, - PRIV_FLAGS_SECURE_BUFFER = 0x00000400, - // For explicit synchronization - PRIV_FLAGS_UNSYNCHRONIZED = 0x00000800, - // Not mapped in userspace - PRIV_FLAGS_NOT_MAPPED = 0x00001000, - // Display on external only - PRIV_FLAGS_EXTERNAL_ONLY = 0x00002000, - PRIV_FLAGS_VIDEO_ENCODER = 0x00010000, - PRIV_FLAGS_CAMERA_WRITE = 0x00020000, - PRIV_FLAGS_CAMERA_READ = 0x00040000, - PRIV_FLAGS_HW_COMPOSER = 0x00080000, - PRIV_FLAGS_HW_TEXTURE = 0x00100000, - PRIV_FLAGS_ITU_R_601 = 0x00200000, - PRIV_FLAGS_ITU_R_601_FR = 0x00400000, - PRIV_FLAGS_ITU_R_709 = 0x00800000, - PRIV_FLAGS_SECURE_DISPLAY = 0x01000000, - // Buffer is rendered in Tile Format - PRIV_FLAGS_TILE_RENDERED = 0x02000000, - // Buffer rendered using CPU/SW renderer - PRIV_FLAGS_CPU_RENDERED = 0x04000000 - }; - - // file-descriptors - int fd; - int fd_metadata; // fd for the meta-data - // ints - int magic; - int flags; - unsigned int size; - unsigned int offset; - int bufferType; - uint64_t base __attribute__((aligned(8))); - unsigned int offset_metadata; - // The gpu address mapped into the mmu. - uint64_t gpuaddr __attribute__((aligned(8))); - int format; - int width; - int height; - uint64_t base_metadata __attribute__((aligned(8))); - -#ifdef __cplusplus - static const int sNumFds = 2; - static inline int sNumInts() { - return ((sizeof(private_handle_t) - sizeof(native_handle_t)) / - sizeof(int)) - sNumFds; - } - static const int sMagic = 'gmsm'; - - private_handle_t(int fd, unsigned int size, int flags, int bufferType, - int format, int width, int height, int eFd = -1, - unsigned int eOffset = 0, uint64_t eBase = 0) : - fd(fd), fd_metadata(eFd), magic(sMagic), - flags(flags), size(size), offset(0), bufferType(bufferType), - base(0), offset_metadata(eOffset), gpuaddr(0), - format(format), width(width), height(height), - base_metadata(eBase) - { - version = (int) sizeof(native_handle); - numInts = sNumInts(); - numFds = sNumFds; - } - ~private_handle_t() { - base_metadata = 0; - magic = 0; - fd_metadata = 0; - } - - bool usesPhysicallyContiguousMemory() { - return (flags & PRIV_FLAGS_USES_PMEM) != 0; - } - - static int validate(const native_handle* h) { - const private_handle_t* hnd = (const private_handle_t*)h; - if (!h || h->version != sizeof(native_handle) || - h->numInts != sNumInts() || h->numFds != sNumFds || - hnd->magic != sMagic) - { - ALOGE("Invalid gralloc handle (at %p): " - "ver(%d/%zu) ints(%d/%d) fds(%d/%d)" - "magic(%c%c%c%c/%c%c%c%c)", - h, - h ? h->version : -1, sizeof(native_handle), - h ? h->numInts : -1, sNumInts(), - h ? h->numFds : -1, sNumFds, - hnd ? (((hnd->magic >> 24) & 0xFF)? - ((hnd->magic >> 24) & 0xFF) : '-') : '?', - hnd ? (((hnd->magic >> 16) & 0xFF)? - ((hnd->magic >> 16) & 0xFF) : '-') : '?', - hnd ? (((hnd->magic >> 8) & 0xFF)? - ((hnd->magic >> 8) & 0xFF) : '-') : '?', - hnd ? (((hnd->magic >> 0) & 0xFF)? - ((hnd->magic >> 0) & 0xFF) : '-') : '?', - (sMagic >> 24) & 0xFF, - (sMagic >> 16) & 0xFF, - (sMagic >> 8) & 0xFF, - (sMagic >> 0) & 0xFF); - return -EINVAL; - } - return 0; - } - - static private_handle_t* dynamicCast(const native_handle* in) { - if (validate(in) == 0) { - return (private_handle_t*) in; - } - return NULL; - } -#endif - }; - -#endif /* GRALLOC_PRIV_H_ */ diff --git a/msm8909/libgralloc/ionalloc.cpp b/msm8909/libgralloc/ionalloc.cpp index 5329e880..329e30f7 100644 --- a/msm8909/libgralloc/ionalloc.cpp +++ b/msm8909/libgralloc/ionalloc.cpp @@ -35,8 +35,8 @@ #include <fcntl.h> #include <cutils/log.h> #include <errno.h> -#include <string.h> #include <utils/Trace.h> +#include <cutils/trace.h> #include "gralloc_priv.h" #include "ionalloc.h" @@ -77,13 +77,9 @@ int IonAlloc::alloc_buffer(alloc_data& data) ionAllocData.len = data.size; ionAllocData.align = data.align; - ionAllocData.heap_id_mask = data.flags & ~ION_SECURE; - ionAllocData.flags = data.uncached ? 0 : ION_FLAG_CACHED; - // ToDo: replace usage of alloc data structure with - // ionallocdata structure. - if (data.flags & ION_SECURE) - ionAllocData.flags |= ION_SECURE; - + ionAllocData.heap_id_mask = data.heapId; + ionAllocData.flags = data.flags; + ionAllocData.flags |= data.uncached ? 0 : ION_FLAG_CACHED; err = open_device(); if (err) return err; diff --git a/msm8909/libgralloc/mapper.cpp b/msm8909/libgralloc/mapper.cpp index 99d309cd..e9830e2d 100644 --- a/msm8909/libgralloc/mapper.cpp +++ b/msm8909/libgralloc/mapper.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 The Android Open Source Project - * Copyright (c) 2011-2014,2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -55,6 +55,27 @@ static IMemAlloc* getAllocator(int flags) return memalloc; } +static int gralloc_map_metadata(buffer_handle_t handle) { + private_handle_t* hnd = (private_handle_t*)handle; + hnd->base_metadata = 0; + IMemAlloc* memalloc = getAllocator(hnd->flags) ; + void *mappedAddress = MAP_FAILED; + unsigned int size = 0; + if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) { + mappedAddress = MAP_FAILED; + size = ROUND_UP_PAGESIZE(sizeof(MetaData_t)); + int ret = memalloc->map_buffer(&mappedAddress, size, + hnd->offset_metadata, hnd->fd_metadata); + if(ret || mappedAddress == MAP_FAILED) { + ALOGE("Could not mmap metadata for handle %p, fd=%d (%s)", + hnd, hnd->fd_metadata, strerror(errno)); + return -errno; + } + hnd->base_metadata = uint64_t(mappedAddress); + } + return 0; +} + static int gralloc_map(gralloc_module_t const* module, buffer_handle_t handle) { @@ -66,8 +87,10 @@ static int gralloc_map(gralloc_module_t const* module, unsigned int size = 0; int err = 0; IMemAlloc* memalloc = getAllocator(hnd->flags) ; - void *mappedAddress; - // Dont map FRAMEBUFFER and SECURE_BUFFERS + void *mappedAddress = MAP_FAILED; + hnd->base = 0; + + // Dont map framebuffer and secure buffers if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) && !(hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER)) { size = hnd->size; @@ -76,60 +99,62 @@ static int gralloc_map(gralloc_module_t const* module, if(err || mappedAddress == MAP_FAILED) { ALOGE("Could not mmap handle %p, fd=%d (%s)", handle, hnd->fd, strerror(errno)); - hnd->base = 0; return -errno; } - hnd->base = uint64_t(mappedAddress) + hnd->offset; + hnd->base = uint64_t(mappedAddress); + } else { + // Cannot map secure buffers or framebuffers, but still need to map + // metadata for secure buffers. + // If mapping a secure buffers fails, the framework needs to get + // an error code. + err = -EACCES; } - //Allow mapping of metadata for all buffers and SECURE_BUFFER - if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) { - mappedAddress = MAP_FAILED; - size = ROUND_UP_PAGESIZE(sizeof(MetaData_t)); - err = memalloc->map_buffer(&mappedAddress, size, - hnd->offset_metadata, hnd->fd_metadata); - if(err || mappedAddress == MAP_FAILED) { - ALOGE("Could not mmap handle %p, fd=%d (%s)", - handle, hnd->fd_metadata, strerror(errno)); - hnd->base_metadata = 0; - return -errno; - } - hnd->base_metadata = uint64_t(mappedAddress) + hnd->offset_metadata; + //Allow mapping of metadata for all buffers including secure ones, but not + //of framebuffer + int metadata_err = gralloc_map_metadata(handle); + if (!err) { + err = metadata_err; } - return 0; + return err; } static int gralloc_unmap(gralloc_module_t const* module, buffer_handle_t handle) { ATRACE_CALL(); + int err = -EINVAL; if(!module) - return -EINVAL; + return err; private_handle_t* hnd = (private_handle_t*)handle; - if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) { - int err = -EINVAL; - void* base = (void*)hnd->base; - unsigned int size = hnd->size; - IMemAlloc* memalloc = getAllocator(hnd->flags) ; - if(memalloc != NULL) { - err = memalloc->unmap_buffer(base, size, hnd->offset); - if (err) { - ALOGE("Could not unmap memory at address %p", (void*)base); - } - base = (void*)hnd->base_metadata; - size = ROUND_UP_PAGESIZE(sizeof(MetaData_t)); - err = memalloc->unmap_buffer(base, size, hnd->offset_metadata); - if (err) { - ALOGE("Could not unmap memory at address %p", (void*)base); - } + IMemAlloc* memalloc = getAllocator(hnd->flags) ; + if(!memalloc) + return err; + + if(hnd->base) { + err = memalloc->unmap_buffer((void*)hnd->base, hnd->size, hnd->offset); + if (err) { + ALOGE("Could not unmap memory at address %p, %s", (void*) hnd->base, + strerror(errno)); + return -errno; } + hnd->base = 0; } - /* need to initialize the pointer to NULL otherwise unmapping for that - * buffer happens twice which leads to crash */ - hnd->base = 0; - hnd->base_metadata = 0; + + if(hnd->base_metadata) { + unsigned int size = ROUND_UP_PAGESIZE(sizeof(MetaData_t)); + err = memalloc->unmap_buffer((void*)hnd->base_metadata, + size, hnd->offset_metadata); + if (err) { + ALOGE("Could not unmap memory at address %p, %s", + (void*) hnd->base_metadata, strerror(errno)); + return -errno; + } + hnd->base_metadata = 0; + } + return 0; } @@ -146,25 +171,11 @@ int gralloc_register_buffer(gralloc_module_t const* module, if (!module || private_handle_t::validate(handle) < 0) return -EINVAL; - // In this implementation, we don't need to do anything here - - /* NOTE: we need to initialize the buffer as not mapped/not locked - * because it shouldn't when this function is called the first time - * in a new process. Ideally these flags shouldn't be part of the - * handle, but instead maintained in the kernel or at least - * out-of-line - */ - - private_handle_t* hnd = (private_handle_t*)handle; - hnd->base = 0; - hnd->base_metadata = 0; - int err = gralloc_map(module, handle); - if (err) { - ALOGE("%s: gralloc_map failed", __FUNCTION__); - return err; - } - - return 0; + int err = gralloc_map(module, handle); + /* Do not fail register_buffer for secure buffers*/ + if (err == -EACCES) + err = 0; + return err; } int gralloc_unregister_buffer(gralloc_module_t const* module, @@ -178,16 +189,9 @@ int gralloc_unregister_buffer(gralloc_module_t const* module, * If the buffer has been mapped during a lock operation, it's time * to un-map it. It's an error to be here with a locked buffer. * NOTE: the framebuffer is handled differently and is never unmapped. + * Also base and base_metadata are reset. */ - - private_handle_t* hnd = (private_handle_t*)handle; - - if (hnd->base != 0) { - gralloc_unmap(module, handle); - } - hnd->base = 0; - hnd->base_metadata = 0; - return 0; + return gralloc_unmap(module, handle); } int terminateBuffer(gralloc_module_t const* module, @@ -200,23 +204,10 @@ int terminateBuffer(gralloc_module_t const* module, /* * If the buffer has been mapped during a lock operation, it's time * to un-map it. It's an error to be here with a locked buffer. + * NOTE: the framebuffer is handled differently and is never unmapped. + * Also base and base_metadata are reset. */ - - if (hnd->base != 0) { - // this buffer was mapped, unmap it now - if (hnd->flags & (private_handle_t::PRIV_FLAGS_USES_PMEM | - private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP | - private_handle_t::PRIV_FLAGS_USES_ASHMEM | - private_handle_t::PRIV_FLAGS_USES_ION)) { - gralloc_unmap(module, hnd); - } else { - ALOGE("terminateBuffer: unmapping a non pmem/ashmem buffer flags = 0x%x", - hnd->flags); - gralloc_unmap(module, hnd); - } - } - - return 0; + return gralloc_unmap(module, hnd); } static int gralloc_map_and_invalidate (gralloc_module_t const* module, @@ -327,6 +318,7 @@ int gralloc_perform(struct gralloc_module_t const* module, int width = va_arg(args, int); int height = va_arg(args, int); int format = va_arg(args, int); + int alignedw = 0, alignedh = 0; native_handle_t** handle = va_arg(args, native_handle_t**); private_handle_t* hnd = (private_handle_t*)native_handle_create( @@ -339,8 +331,12 @@ int gralloc_perform(struct gralloc_module_t const* module, hnd->offset = offset; hnd->base = uint64_t(base) + offset; hnd->gpuaddr = 0; - hnd->width = width; - hnd->height = height; + AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width, + height, format, 0, alignedw, alignedh); + hnd->width = alignedw; + hnd->height = alignedh; + hnd->unaligned_width = width; + hnd->unaligned_height = height; hnd->format = format; *handle = (native_handle_t *)hnd; res = 0; @@ -355,45 +351,40 @@ int gralloc_perform(struct gralloc_module_t const* module, int *stride = va_arg(args, int *); int alignedw = 0, alignedh = 0; AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width, - 0, format, false, alignedw, alignedh); + 0, format, 0, alignedw, alignedh); *stride = alignedw; res = 0; } break; case GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_FROM_HANDLE: { - private_handle_t* hnd = va_arg(args, private_handle_t*); + const private_handle_t* hnd = va_arg(args, private_handle_t*); int *stride = va_arg(args, int *); if (private_handle_t::validate(hnd)) { - va_end(args); return res; } - MetaData_t *metadata = (MetaData_t *)hnd->base_metadata; - if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) { - *stride = metadata->bufferDim.sliceWidth; - } else { - *stride = hnd->width; - } + + int alignedw = 0, alignedh = 0; + AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(hnd, alignedw, alignedh); + *stride = alignedw; + res = 0; } break; case GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_AND_HEIGHT_FROM_HANDLE: { - private_handle_t* hnd = va_arg(args, private_handle_t*); + const private_handle_t* hnd = va_arg(args, private_handle_t*); int *stride = va_arg(args, int *); int *height = va_arg(args, int *); if (private_handle_t::validate(hnd)) { - va_end(args); return res; } - MetaData_t *metadata = (MetaData_t *)hnd->base_metadata; - if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) { - *stride = metadata->bufferDim.sliceWidth; - *height = metadata->bufferDim.sliceHeight; - } else { - *stride = hnd->width; - *height = hnd->height; - } + + int alignedw = 0, alignedh = 0; + AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(hnd, alignedw, alignedh); + *stride = alignedw; + *height = alignedh; + res = 0; } break; @@ -406,10 +397,9 @@ int gralloc_perform(struct gralloc_module_t const* module, int *alignedWidth = va_arg(args, int *); int *alignedHeight = va_arg(args, int *); int *tileEnabled = va_arg(args,int *); - *tileEnabled = isMacroTileEnabled(format, usage); + *tileEnabled = isUBwcEnabled(format, usage); AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width, - height, format, *tileEnabled, *alignedWidth, - *alignedHeight); + height, format, usage, *alignedWidth, *alignedHeight); res = 0; } break; @@ -418,15 +408,38 @@ int gralloc_perform(struct gralloc_module_t const* module, private_handle_t* hnd = va_arg(args, private_handle_t*); int *color_space = va_arg(args, int *); if (private_handle_t::validate(hnd)) { - va_end(args); return res; } MetaData_t *metadata = (MetaData_t *)hnd->base_metadata; - if(metadata && metadata->operation & UPDATE_COLOR_SPACE) { + if (!metadata) { + break; +#ifdef USE_COLOR_METADATA + } else if (metadata->operation & COLOR_METADATA) { + ColorMetaData *colorMetadata = &metadata->color; + res = 0; + switch (colorMetadata->colorPrimaries) { + case ColorPrimaries_BT709_5: + *color_space = HAL_CSC_ITU_R_709; + break; + case ColorPrimaries_BT601_6_525: + *color_space = ((colorMetadata->range) ? + HAL_CSC_ITU_R_601_FR : HAL_CSC_ITU_R_601); + break; + case ColorPrimaries_BT2020: + *color_space = (colorMetadata->range) ? + HAL_CSC_ITU_R_2020_FR : HAL_CSC_ITU_R_2020; + break; + default: + res = -EINVAL; + break; + } +#endif + } else if(metadata->operation & UPDATE_COLOR_SPACE) { *color_space = metadata->colorSpace; res = 0; } } break; + case GRALLOC_MODULE_PERFORM_GET_YUV_PLANE_INFO: { private_handle_t* hnd = va_arg(args, private_handle_t*); @@ -436,6 +449,72 @@ int gralloc_perform(struct gralloc_module_t const* module, } } break; + case GRALLOC_MODULE_PERFORM_GET_MAP_SECURE_BUFFER_INFO: + { + private_handle_t* hnd = va_arg(args, private_handle_t*); + int *map_secure_buffer = va_arg(args, int *); + if (private_handle_t::validate(hnd)) { + return res; + } + MetaData_t *metadata = (MetaData_t *)hnd->base_metadata; + if(metadata && metadata->operation & MAP_SECURE_BUFFER) { + *map_secure_buffer = metadata->mapSecureBuffer; + res = 0; + } else { + *map_secure_buffer = 0; + } + } break; + + case GRALLOC_MODULE_PERFORM_GET_UBWC_FLAG: + { + private_handle_t* hnd = va_arg(args, private_handle_t*); + int *flag = va_arg(args, int *); + if (private_handle_t::validate(hnd)) { + return res; + } + *flag = hnd->flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED; + MetaData_t *metadata = (MetaData_t *)hnd->base_metadata; + if (metadata && (metadata->operation & LINEAR_FORMAT)) { + *flag = 0; + } + res = 0; + } break; + + case GRALLOC_MODULE_PERFORM_GET_RGB_DATA_ADDRESS: + { + private_handle_t* hnd = va_arg(args, private_handle_t*); + void** rgb_data = va_arg(args, void**); + if (!private_handle_t::validate(hnd)) { + res = getRgbDataAddress(hnd, rgb_data); + } + } break; + + case GRALLOC_MODULE_PERFORM_GET_IGC: + { + private_handle_t* hnd = va_arg(args, private_handle_t*); + uint32_t *igc = va_arg(args, uint32_t *); + if (!private_handle_t::validate(hnd) && igc) { + MetaData_t *metadata = (MetaData_t *)hnd->base_metadata; + if (metadata && (metadata->operation & SET_IGC)) { + *igc = metadata->igc; + res = 0; + } + } + } break; + + case GRALLOC_MODULE_PERFORM_SET_IGC: + res = 0; + break; + + case GRALLOC_MODULE_PERFORM_SET_SINGLE_BUFFER_MODE: + { + private_handle_t* hnd = va_arg(args, private_handle_t*); + uint32_t *enable = va_arg(args, uint32_t*); + if (!private_handle_t::validate(hnd)) { + setMetaData(hnd, SET_SINGLE_BUFFER_MODE, enable); + res = 0; + } + } break; default: break; } diff --git a/msm8909/libgralloc/memalloc.h b/msm8909/libgralloc/memalloc.h index 2bc1ddf8..598d983e 100644 --- a/msm8909/libgralloc/memalloc.h +++ b/msm8909/libgralloc/memalloc.h @@ -49,6 +49,7 @@ struct alloc_data { uintptr_t pHandle; bool uncached; unsigned int flags; + unsigned int heapId; int allocType; }; diff --git a/msm8909/libhdmi/Android.mk b/msm8909/libhdmi/Android.mk deleted file mode 100644 index b75bf40b..00000000 --- a/msm8909/libhdmi/Android.mk +++ /dev/null @@ -1,18 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(LOCAL_PATH)/../common.mk -include $(CLEAR_VARS) - -LOCAL_MODULE := libhdmi -LOCAL_MODULE_TAGS := optional -LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes) -LOCAL_SHARED_LIBRARIES := $(common_libs) liboverlay libqdutils -LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdhdmi\" -Wno-float-conversion -LOCAL_CLANG := true -LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) - -ifeq ($(TARGET_SUPPORTS_WEARABLES),true) -LOCAL_SRC_FILES := hdmi_stub.cpp -else -LOCAL_SRC_FILES := hdmi.cpp -endif -include $(BUILD_SHARED_LIBRARY) diff --git a/msm8909/libhdmi/hdmi.cpp b/msm8909/libhdmi/hdmi.cpp deleted file mode 100644 index c20efbff..00000000 --- a/msm8909/libhdmi/hdmi.cpp +++ /dev/null @@ -1,699 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012-2014, 2016, The Linux Foundation. All rights reserved. - * - * Not a Contribution, Apache license notifications and license are - * retained for attribution purposes only. - * - * 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. - */ - -#define DEBUG 0 -#include <fcntl.h> -#include <linux/msm_mdp.h> -#include <video/msm_hdmi_modes.h> -#include <linux/fb.h> -#include <sys/ioctl.h> -#include <cutils/properties.h> -#include "hwc_utils.h" -#include "hdmi.h" -#include "overlayUtils.h" -#include "overlay.h" -#include "qd_utils.h" - -using namespace android; -using namespace qdutils; - -namespace qhwc { -#define UNKNOWN_STRING "unknown" -#define SPD_NAME_LENGTH 16 - -/* The array gEDIDData contains a list of modes currently - * supported by HDMI and display, and modes that are not - * supported i.e. interlaced modes. - - * In order to add support for a new mode, the mode must be - * appended to the end of the array. - * - * Each new entry must contain the following: - * -Mode: a video format defined in msm_hdmi_modes.h - * -Width: x resolution for the mode - * -Height: y resolution for the mode - * -FPS: the frame rate for the mode - * -Mode Order: the priority for the new mode that is used when determining - * the best mode when the HDMI display is connected. - */ -EDIDData gEDIDData [] = { - EDIDData(HDMI_VFRMT_1440x480i60_4_3, 1440, 480, 60, 1), - EDIDData(HDMI_VFRMT_1440x480i60_16_9, 1440, 480, 60, 2), - EDIDData(HDMI_VFRMT_1440x576i50_4_3, 1440, 576, 50, 3), - EDIDData(HDMI_VFRMT_1440x576i50_16_9, 1440, 576, 50, 4), - EDIDData(HDMI_VFRMT_1920x1080i60_16_9, 1920, 1080, 60, 5), - EDIDData(HDMI_VFRMT_640x480p60_4_3, 640, 480, 60, 6), - EDIDData(HDMI_VFRMT_720x480p60_4_3, 720, 480, 60, 7), - EDIDData(HDMI_VFRMT_720x480p60_16_9, 720, 480, 60, 8), - EDIDData(HDMI_VFRMT_720x576p50_4_3, 720, 576, 50, 9), - EDIDData(HDMI_VFRMT_720x576p50_16_9, 720, 576, 50, 10), - EDIDData(HDMI_VFRMT_800x600p60_4_3, 800, 600, 60, 11), - EDIDData(HDMI_VFRMT_848x480p60_16_9, 848, 480, 60, 12), - EDIDData(HDMI_VFRMT_1024x768p60_4_3, 1024, 768, 60, 13), - EDIDData(HDMI_VFRMT_1280x1024p60_5_4, 1280, 1024, 60, 14), - EDIDData(HDMI_VFRMT_1280x720p50_16_9, 1280, 720, 50, 15), - EDIDData(HDMI_VFRMT_1280x720p60_16_9, 1280, 720, 60, 16), - EDIDData(HDMI_VFRMT_1280x800p60_16_10, 1280, 800, 60, 17), - EDIDData(HDMI_VFRMT_1280x960p60_4_3, 1280, 960, 60, 18), - EDIDData(HDMI_VFRMT_1360x768p60_16_9, 1360, 768, 60, 19), - EDIDData(HDMI_VFRMT_1366x768p60_16_10, 1366, 768, 60, 20), - EDIDData(HDMI_VFRMT_1440x900p60_16_10, 1440, 900, 60, 21), - EDIDData(HDMI_VFRMT_1400x1050p60_4_3, 1400, 1050, 60, 22), - EDIDData(HDMI_VFRMT_1680x1050p60_16_10, 1680, 1050, 60, 23), - EDIDData(HDMI_VFRMT_1600x1200p60_4_3, 1600, 1200, 60, 24), - EDIDData(HDMI_VFRMT_1920x1080p24_16_9, 1920, 1080, 24, 25), - EDIDData(HDMI_VFRMT_1920x1080p25_16_9, 1920, 1080, 25, 26), - EDIDData(HDMI_VFRMT_1920x1080p30_16_9, 1920, 1080, 30, 27), - EDIDData(HDMI_VFRMT_1920x1080p50_16_9, 1920, 1080, 50, 28), - EDIDData(HDMI_VFRMT_1920x1080p60_16_9, 1920, 1080, 60, 29), - EDIDData(HDMI_VFRMT_1920x1200p60_16_10, 1920, 1200, 60, 30), - EDIDData(HDMI_VFRMT_2560x1600p60_16_9, 2560, 1600, 60, 31), - EDIDData(HDMI_VFRMT_3840x2160p24_16_9, 3840, 2160, 24, 32), - EDIDData(HDMI_VFRMT_3840x2160p25_16_9, 3840, 2160, 25, 33), - EDIDData(HDMI_VFRMT_3840x2160p30_16_9, 3840, 2160, 30, 34), - EDIDData(HDMI_EVFRMT_4096x2160p24_16_9, 4096, 2160, 24, 35), -}; - -// Number of modes in gEDIDData -const int gEDIDCount = (sizeof(gEDIDData)/sizeof(gEDIDData)[0]); - -int HDMIDisplay::configure() { - if(!openFrameBuffer()) { - ALOGE("%s: Failed to open FB: %d", __FUNCTION__, mFbNum); - return -1; - } - readCEUnderscanInfo(); - readResolution(); - // TODO: Move this to activate - /* Used for changing the resolution - * getUserMode will get the preferred - * mode set thru adb shell */ - mCurrentMode = getUserMode(); - if (mCurrentMode == -1) { - //Get the best mode and set - mCurrentMode = getBestMode(); - } - setAttributes(); - // set system property - property_set("hw.hdmiON", "1"); - - // Read the system property to determine if downscale feature is enabled. - char value[PROPERTY_VALUE_MAX]; - mMDPDownscaleEnabled = false; - if(property_get("sys.hwc.mdp_downscale_enabled", value, "false") - && !strcmp(value, "true")) { - mMDPDownscaleEnabled = true; - } - return 0; -} - -void HDMIDisplay::getAttributes(uint32_t& width, uint32_t& height) { - uint32_t fps = 0; - getAttrForMode(width, height, fps); -} - -int HDMIDisplay::teardown() { - closeFrameBuffer(); - resetInfo(); - // unset system property - property_set("hw.hdmiON", "0"); - return 0; -} - -HDMIDisplay::HDMIDisplay():mFd(-1), - mCurrentMode(-1), mModeCount(0), mPrimaryWidth(0), mPrimaryHeight(0), - mUnderscanSupported(false) -{ - memset(&mVInfo, 0, sizeof(mVInfo)); - - mDisplayId = HWC_DISPLAY_EXTERNAL; - // Update the display if HDMI is connected as primary - if (isHDMIPrimaryDisplay()) { - mDisplayId = HWC_DISPLAY_PRIMARY; - } - - mFbNum = overlay::Overlay::getInstance()->getFbForDpy(mDisplayId); - // disable HPD at start, it will be enabled later - // when the display powers on - // This helps for framework reboot or adb shell stop/start - writeHPDOption(0); - - // for HDMI - retreive all the modes supported by the driver - if(mFbNum != -1) { - supported_video_mode_lut = - new msm_hdmi_mode_timing_info[HDMI_VFRMT_MAX]; - // Populate the mode table for supported modes - MSM_HDMI_MODES_INIT_TIMINGS(supported_video_mode_lut); - MSM_HDMI_MODES_SET_SUPP_TIMINGS(supported_video_mode_lut, - MSM_HDMI_MODES_ALL); - // Update the Source Product Information - // Vendor Name - setSPDInfo("vendor_name", "ro.product.manufacturer"); - // Product Description - setSPDInfo("product_description", "ro.product.name"); - } - - ALOGD_IF(DEBUG, "%s mDisplayId(%d) mFbNum(%d)", - __FUNCTION__, mDisplayId, mFbNum); -} -/* gets the product manufacturer and product name and writes it - * to the sysfs node, so that the driver can get that information - * Used to show QCOM 8974 instead of Input 1 for example - */ -void HDMIDisplay::setSPDInfo(const char* node, const char* property) { - char info[PROPERTY_VALUE_MAX]; - ssize_t err = -1; - int spdFile = openDeviceNode(node, O_RDWR); - if (spdFile >= 0) { - memset(info, 0, sizeof(info)); - property_get(property, info, UNKNOWN_STRING); - ALOGD_IF(DEBUG, "In %s: %s = %s", - __FUNCTION__, property, info); - if (strncmp(info, UNKNOWN_STRING, SPD_NAME_LENGTH)) { - err = write(spdFile, info, strlen(info)); - if (err <= 0) { - ALOGE("%s: file write failed for '%s'" - "err no = %d", __FUNCTION__, node, errno); - } - } else { - ALOGD_IF(DEBUG, "%s: property_get failed for SPD %s", - __FUNCTION__, node); - } - close(spdFile); - } -} - -void HDMIDisplay::setHPD(uint32_t value) { - ALOGD_IF(DEBUG,"HPD enabled=%d", value); - writeHPDOption(value); -} - -void HDMIDisplay::setActionSafeDimension(int w, int h) { - ALOGD_IF(DEBUG,"ActionSafe w=%d h=%d", w, h); - char actionsafeWidth[PROPERTY_VALUE_MAX]; - char actionsafeHeight[PROPERTY_VALUE_MAX]; - snprintf(actionsafeWidth, sizeof(actionsafeWidth), "%d", w); - property_set("persist.sys.actionsafe.width", actionsafeWidth); - snprintf(actionsafeHeight, sizeof(actionsafeHeight), "%d", h); - property_set("persist.sys.actionsafe.height", actionsafeHeight); -} - -int HDMIDisplay::getModeCount() const { - ALOGD_IF(DEBUG,"HPD mModeCount=%d", mModeCount); - return mModeCount; -} - -void HDMIDisplay::readCEUnderscanInfo() -{ - int hdmiScanInfoFile = -1; - ssize_t len = -1; - char scanInfo[17]; - char *ce_info_str = NULL; - char *save_ptr; - const char token[] = ", \n"; - int ce_info = -1; - - memset(scanInfo, 0, sizeof(scanInfo)); - hdmiScanInfoFile = openDeviceNode("scan_info", O_RDONLY); - if (hdmiScanInfoFile < 0) { - return; - } else { - len = read(hdmiScanInfoFile, scanInfo, sizeof(scanInfo)-1); - ALOGD("%s: Scan Info string: %s length = %zu", - __FUNCTION__, scanInfo, len); - if (len <= 0) { - close(hdmiScanInfoFile); - ALOGE("%s: Scan Info file empty", __FUNCTION__); - return; - } - scanInfo[len] = '\0'; /* null terminate the string */ - close(hdmiScanInfoFile); - } - - /* - * The scan_info contains the three fields - * PT - preferred video format - * IT - video format - * CE video format - containing the underscan support information - */ - - /* PT */ - ce_info_str = strtok_r(scanInfo, token, &save_ptr); - if (ce_info_str) { - /* IT */ - ce_info_str = strtok_r(NULL, token, &save_ptr); - if (ce_info_str) { - /* CE */ - ce_info_str = strtok_r(NULL, token, &save_ptr); - if (ce_info_str) - ce_info = atoi(ce_info_str); - } - } - - if (ce_info_str) { - // ce_info contains the underscan information - if (ce_info == HDMI_SCAN_ALWAYS_UNDERSCANED || - ce_info == HDMI_SCAN_BOTH_SUPPORTED) - // if TV supported underscan, then driver will always underscan - // hence no need to apply action safe rectangle - mUnderscanSupported = true; - } else { - ALOGE("%s: scan_info string error", __FUNCTION__); - } - - // Store underscan support info in a system property - const char* prop = (mUnderscanSupported) ? "1" : "0"; - property_set("hw.underscan_supported", prop); - return; -} - -HDMIDisplay::~HDMIDisplay() -{ - delete [] supported_video_mode_lut; - closeFrameBuffer(); -} - -/* - * sets the fb_var_screeninfo from the hdmi_mode_timing_info - */ -void setDisplayTiming(struct fb_var_screeninfo &info, - const msm_hdmi_mode_timing_info* mode) -{ - info.reserved[0] = 0; - info.reserved[1] = 0; - info.reserved[2] = 0; -#ifndef FB_METADATA_VIDEO_INFO_CODE_SUPPORT - info.reserved[3] = (info.reserved[3] & 0xFFFF) | - (mode->video_format << 16); -#endif - info.xoffset = 0; - info.yoffset = 0; - info.xres = mode->active_h; - info.yres = mode->active_v; - - info.pixclock = (mode->pixel_freq)*1000; - info.vmode = mode->interlaced ? - FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED; - - info.right_margin = mode->front_porch_h; - info.hsync_len = mode->pulse_width_h; - info.left_margin = mode->back_porch_h; - info.lower_margin = mode->front_porch_v; - info.vsync_len = mode->pulse_width_v; - info.upper_margin = mode->back_porch_v; -} - -int HDMIDisplay::parseResolution(char* edidStr) -{ - char delim = ','; - int count = 0; - char *start, *end; - // EDIDs are string delimited by ',' - // Ex: 16,4,5,3,32,34,1 - // Parse this string to get mode(int) - start = (char*) edidStr; - end = &delim; - while(*end == delim) { - mEDIDModes[count] = (int) strtol(start, &end, 10); - start = end+1; - count++; - } - ALOGD_IF(DEBUG, "In %s: count = %d", __FUNCTION__, count); - for (int i = 0; i < count; i++) - ALOGD_IF(DEBUG, "Mode[%d] = %d", i, mEDIDModes[i]); - return count; -} - -bool HDMIDisplay::readResolution() -{ - ssize_t len = -1; - char edidStr[128] = {'\0'}; - - int hdmiEDIDFile = openDeviceNode("edid_modes", O_RDONLY); - if (hdmiEDIDFile < 0) { - return false; - } else { - len = read(hdmiEDIDFile, edidStr, sizeof(edidStr)-1); - ALOGD_IF(DEBUG, "%s: EDID string: %s length = %zu", - __FUNCTION__, edidStr, len); - if (len <= 0) { - ALOGE("%s: edid_modes file empty", __FUNCTION__); - edidStr[0] = '\0'; - } - else { - while (len > 1 && isspace(edidStr[len-1])) { - --len; - } - edidStr[len] = '\0'; - } - close(hdmiEDIDFile); - } - if(len > 0) { - // Get EDID modes from the EDID strings - mModeCount = parseResolution(edidStr); - ALOGD_IF(DEBUG, "%s: mModeCount = %d", __FUNCTION__, - mModeCount); - } - - return (len > 0); -} - -bool HDMIDisplay::openFrameBuffer() -{ - if (mFd == -1) { - char strDevPath[MAX_SYSFS_FILE_PATH]; - snprintf(strDevPath, MAX_SYSFS_FILE_PATH, "/dev/graphics/fb%d", mFbNum); - mFd = open(strDevPath, O_RDWR); - if (mFd < 0) - ALOGE("%s: %s is not available", __FUNCTION__, strDevPath); - } - return (mFd > 0); -} - -bool HDMIDisplay::closeFrameBuffer() -{ - int ret = 0; - if(mFd >= 0) { - ret = close(mFd); - mFd = -1; - } - return (ret == 0); -} - -// clears the vinfo, edid, best modes -void HDMIDisplay::resetInfo() -{ - memset(&mVInfo, 0, sizeof(mVInfo)); - memset(mEDIDModes, 0, sizeof(mEDIDModes)); - mModeCount = 0; - mCurrentMode = -1; - mUnderscanSupported = false; - mXres = 0; - mYres = 0; - mVsyncPeriod = 0; - mMDPScalingMode = false; - // Reset the underscan supported system property - const char* prop = "0"; - property_set("hw.underscan_supported", prop); -} - -int HDMIDisplay::getModeOrder(int mode) -{ - for (int dataIndex = 0; dataIndex < gEDIDCount; dataIndex++) { - if (gEDIDData[dataIndex].mMode == mode) { - return gEDIDData[dataIndex].mModeOrder; - } - } - ALOGE("%s Mode not found: %d", __FUNCTION__, mode); - return -1; -} - -/// Returns the user mode set(if any) using adb shell -int HDMIDisplay::getUserMode() { - /* Based on the property set the resolution */ - char property_value[PROPERTY_VALUE_MAX]; - property_get("hw.hdmi.resolution", property_value, "-1"); - int mode = atoi(property_value); - // We dont support interlaced modes - if(isValidMode(mode) && !isInterlacedMode(mode)) { - ALOGD_IF(DEBUG, "%s: setting the HDMI mode = %d", __FUNCTION__, mode); - return mode; - } - return -1; -} - -// Get the best mode for the current HD TV -int HDMIDisplay::getBestMode() { - int bestOrder = 0; - int bestMode = HDMI_VFRMT_640x480p60_4_3; - // for all the edid read, get the best mode - for(int i = 0; i < mModeCount; i++) { - int mode = mEDIDModes[i]; - int order = getModeOrder(mode); - if (order > bestOrder) { - bestOrder = order; - bestMode = mode; - } - } - return bestMode; -} - -inline bool HDMIDisplay::isValidMode(int ID) -{ - bool valid = false; - for (int i = 0; i < mModeCount; i++) { - if(ID == mEDIDModes[i]) { - valid = true; - break; - } - } - return valid; -} - -// returns true if the mode(ID) is interlaced mode format -bool HDMIDisplay::isInterlacedMode(int ID) { - bool interlaced = false; - switch(ID) { - case HDMI_VFRMT_1440x480i60_4_3: - case HDMI_VFRMT_1440x480i60_16_9: - case HDMI_VFRMT_1440x576i50_4_3: - case HDMI_VFRMT_1440x576i50_16_9: - case HDMI_VFRMT_1920x1080i60_16_9: - interlaced = true; - break; - default: - interlaced = false; - break; - } - return interlaced; -} - -// Does a put_vscreen info on the HDMI interface which will update -// the configuration (resolution, timing info) to match mCurrentMode -void HDMIDisplay::activateDisplay() -{ - int ret = 0; - ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo); - if(ret < 0) { - ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__, - strerror(errno)); - } - ALOGD_IF(DEBUG, "%s: GET Info<ID=%d %dx%d (%d,%d,%d)," - "(%d,%d,%d) %dMHz>", __FUNCTION__, - mVInfo.reserved[3], mVInfo.xres, mVInfo.yres, - mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin, - mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin, - mVInfo.pixclock/1000/1000); - - const struct msm_hdmi_mode_timing_info *mode = - &supported_video_mode_lut[0]; - for (unsigned int i = 0; i < HDMI_VFRMT_MAX; ++i) { - const struct msm_hdmi_mode_timing_info *cur = - &supported_video_mode_lut[i]; - if (cur->video_format == (uint32_t)mCurrentMode) { - mode = cur; - break; - } - } - setDisplayTiming(mVInfo, mode); - ALOGD_IF(DEBUG, "%s: SET Info<ID=%d => Info<ID=%d %dx %d" - "(%d,%d,%d), (%d,%d,%d) %dMHz>", __FUNCTION__, mCurrentMode, - mode->video_format, mVInfo.xres, mVInfo.yres, - mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin, - mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin, - mVInfo.pixclock/1000/1000); -#ifdef FB_METADATA_VIDEO_INFO_CODE_SUPPORT - struct msmfb_metadata metadata; - memset(&metadata, 0 , sizeof(metadata)); - metadata.op = metadata_op_vic; - metadata.data.video_info_code = mode->video_format; - if (ioctl(mFd, MSMFB_METADATA_SET, &metadata) == -1) { - ALOGD("In %s: MSMFB_METADATA_SET failed Err Str = %s", - __FUNCTION__, strerror(errno)); - } -#endif - mVInfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE; - ret = ioctl(mFd, FBIOPUT_VSCREENINFO, &mVInfo); - if(ret < 0) { - ALOGD("In %s: FBIOPUT_VSCREENINFO failed Err Str = %s", - __FUNCTION__, strerror(errno)); - } -} - -bool HDMIDisplay::writeHPDOption(int userOption) const -{ - bool ret = true; - if(mFbNum != -1) { - int hdmiHPDFile = openDeviceNode("hpd", O_RDWR); - if (hdmiHPDFile >= 0) { - ssize_t err = -1; - ALOGD_IF(DEBUG, "%s: option = %d", - __FUNCTION__, userOption); - if(userOption) - err = write(hdmiHPDFile, "1", 2); - else - err = write(hdmiHPDFile, "0" , 2); - if (err <= 0) { - ALOGE("%s: file write failed 'hpd'", __FUNCTION__); - ret = false; - } - close(hdmiHPDFile); - } - } - return ret; -} - - -void HDMIDisplay::setAttributes() { - uint32_t fps = 0; - // Always set dpyAttr res to mVInfo res - getAttrForMode(mXres, mYres, fps); - mMDPScalingMode = false; - - if(overlay::Overlay::getInstance()->isUIScalingOnExternalSupported() - && mMDPDownscaleEnabled) { - // if primary resolution is more than the hdmi resolution - // configure dpy attr to primary resolution and set MDP - // scaling mode - // Restrict this upto 1080p resolution max, if target does not - // support source split feature. - uint32_t primaryArea = mPrimaryWidth * mPrimaryHeight; - if(((primaryArea) > (mXres * mYres)) && - (((primaryArea) <= SUPPORTED_DOWNSCALE_AREA) || - qdutils::MDPVersion::getInstance().isSrcSplit())) { - // tmpW and tmpH will hold the primary dimensions before we - // update the aspect ratio if necessary. - int tmpW = mPrimaryWidth; - int tmpH = mPrimaryHeight; - // HDMI is always in landscape, so always assign the higher - // dimension to hdmi's xres - if(mPrimaryHeight > mPrimaryWidth) { - tmpW = mPrimaryHeight; - tmpH = mPrimaryWidth; - } - // The aspect ratios of the external and primary displays - // can be different. As a result, directly assigning primary - // resolution could lead to an incorrect final image. - // We get around this by calculating a new resolution by - // keeping aspect ratio intact. - hwc_rect r = {0, 0, 0, 0}; - qdutils::getAspectRatioPosition(tmpW, tmpH, mXres, mYres, r); - uint32_t newExtW = r.right - r.left; - uint32_t newExtH = r.bottom - r.top; - uint32_t alignedExtW; - uint32_t alignedExtH; - // On 8994 and below targets MDP supports only 4X downscaling, - // Restricting selected external resolution to be exactly 4X - // greater resolution than actual external resolution - uint32_t maxMDPDownScale = - qdutils::MDPVersion::getInstance().getMaxMDPDownscale(); - if((mXres * mYres * maxMDPDownScale) < (newExtW * newExtH)) { - float upScaleFactor = (float)maxMDPDownScale / 2.0f; - newExtW = (int)((float)mXres * upScaleFactor); - newExtH = (int)((float)mYres * upScaleFactor); - } - // Align it down so that the new aligned resolution does not - // exceed the maxMDPDownscale factor - alignedExtW = overlay::utils::aligndown(newExtW, 4); - alignedExtH = overlay::utils::aligndown(newExtH, 4); - mXres = alignedExtW; - mYres = alignedExtH; - // Set External Display MDP Downscale mode indicator - mMDPScalingMode = true; - } - } - ALOGD_IF(DEBUG_MDPDOWNSCALE, "Selected external resolution [%d X %d] " - "maxMDPDownScale %d mMDPScalingMode %d srcSplitEnabled %d " - "MDPDownscale feature %d", - mXres, mYres, - qdutils::MDPVersion::getInstance().getMaxMDPDownscale(), - mMDPScalingMode, qdutils::MDPVersion::getInstance().isSrcSplit(), - mMDPDownscaleEnabled); - mVsyncPeriod = (int) 1000000000l / fps; - ALOGD_IF(DEBUG, "%s xres=%d, yres=%d", __FUNCTION__, mXres, mYres); -} - -void HDMIDisplay::getAttrForMode(uint32_t& width, uint32_t& height, - uint32_t& fps) { - for (int dataIndex = 0; dataIndex < gEDIDCount; dataIndex++) { - if (gEDIDData[dataIndex].mMode == mCurrentMode) { - width = gEDIDData[dataIndex].mWidth; - height = gEDIDData[dataIndex].mHeight; - fps = gEDIDData[dataIndex].mFps; - return; - } - } - ALOGE("%s Unable to get attributes for %d", __FUNCTION__, mCurrentMode); -} - -/* returns the fd related to the node specified*/ -int HDMIDisplay::openDeviceNode(const char* node, int fileMode) const { - char sysFsFilePath[MAX_SYSFS_FILE_PATH]; - memset(sysFsFilePath, 0, sizeof(sysFsFilePath)); - snprintf(sysFsFilePath , sizeof(sysFsFilePath), - "/sys/devices/virtual/graphics/fb%d/%s", - mFbNum, node); - - int fd = open(sysFsFilePath, fileMode, 0); - - if (fd < 0) { - ALOGE("%s: file '%s' not found : ret = %d err str: %s", - __FUNCTION__, sysFsFilePath, fd, strerror(errno)); - } - return fd; -} - -bool HDMIDisplay::isHDMIPrimaryDisplay() { - int hdmiNode = qdutils::getHDMINode(); - return (hdmiNode == HWC_DISPLAY_PRIMARY); -} - -int HDMIDisplay::getConnectedState() { - int ret = -1; - int mFbNum = qdutils::getHDMINode(); - int connectedNode = openDeviceNode("connected", O_RDONLY); - if(connectedNode >= 0) { - char opStr[4]; - ssize_t bytesRead = read(connectedNode, opStr, sizeof(opStr) - 1); - if(bytesRead > 0) { - opStr[bytesRead] = '\0'; - ret = atoi(opStr); - ALOGD_IF(DEBUG, "%s: Read %d from connected", __FUNCTION__, ret); - } else if(bytesRead == 0) { - ALOGE("%s: HDMI connected node empty", __FUNCTION__); - } else { - ALOGE("%s: Read from HDMI connected node failed with error %s", - __FUNCTION__, strerror(errno)); - } - close(connectedNode); - } else { - ALOGD("%s: /sys/class/graphics/fb%d/connected could not be opened : %s", - __FUNCTION__, mFbNum, strerror(errno)); - } - return ret; -} - -void HDMIDisplay::setPrimaryAttributes(uint32_t primaryWidth, - uint32_t primaryHeight) { - mPrimaryHeight = primaryHeight; - mPrimaryWidth = primaryWidth; -} - -}; diff --git a/msm8909/libhdmi/hdmi.h b/msm8909/libhdmi/hdmi.h deleted file mode 100644 index 605d9be8..00000000 --- a/msm8909/libhdmi/hdmi.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved. - * - * Not a Contribution, Apache license notifications and license are - * retained for attribution purposes only. - - * 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_HDMI_DISPLAY_H -#define HWC_HDMI_DISPLAY_H - -#include <linux/fb.h> - -struct msm_hdmi_mode_timing_info; - -namespace qhwc { - -//Type of scanning of EDID(Video Capability Data Block) -enum hdmi_scansupport_type { - HDMI_SCAN_NOT_SUPPORTED = 0, - HDMI_SCAN_ALWAYS_OVERSCANED = 1, - HDMI_SCAN_ALWAYS_UNDERSCANED = 2, - HDMI_SCAN_BOTH_SUPPORTED = 3 -}; - -// Structure to store EDID related data -struct EDIDData { - int mMode, mWidth, mHeight, mFps; - // Predetermined ordering for each mode - int mModeOrder; - EDIDData(int mode, int width, int height, int fps, int order) - : mMode(mode), mWidth(width), mHeight(height), mFps(fps), mModeOrder(order) - { } -}; - -class HDMIDisplay -{ -public: - HDMIDisplay(); - ~HDMIDisplay(); - void setHPD(uint32_t startEnd); - void setActionSafeDimension(int w, int h); - bool isCEUnderscanSupported() { return mUnderscanSupported; } - int configure(); - void getAttributes(uint32_t& width, uint32_t& height); - int teardown(); - uint32_t getWidth() const { return mXres; }; - uint32_t getHeight() const { return mYres; }; - uint32_t getVsyncPeriod() const { return mVsyncPeriod; }; - int getFd() const { return mFd; }; - bool getMDPScalingMode() const { return mMDPScalingMode; } - void activateDisplay(); - /* Returns true if HDMI is the PRIMARY display device*/ - bool isHDMIPrimaryDisplay(); - int getConnectedState(); - /* when HDMI is an EXTERNAL display, PRIMARY display attributes are needed - for scaling mode */ - void setPrimaryAttributes(uint32_t primaryWidth, uint32_t primaryHeight); - -private: - int getModeCount() const; - void setSPDInfo(const char* node, const char* property); - void readCEUnderscanInfo(); - bool readResolution(); - int parseResolution(char* edidMode); - bool openFrameBuffer(); - bool closeFrameBuffer(); - bool writeHPDOption(int userOption) const; - bool isValidMode(int mode); - int getModeOrder(int mode); - int getUserMode(); - int getBestMode(); - bool isInterlacedMode(int mode); - void resetInfo(); - void setAttributes(); - void getAttrForMode(uint32_t& width, uint32_t& height, uint32_t& fps); - int openDeviceNode(const char* node, int fileMode) const; - - int mFd; - int mFbNum; - int mCurrentMode; - int mEDIDModes[64]; - int mModeCount; - fb_var_screeninfo mVInfo; - // Holds all the HDMI modes and timing info supported by driver - msm_hdmi_mode_timing_info* supported_video_mode_lut; - uint32_t mXres, mYres, mVsyncPeriod, mPrimaryWidth, mPrimaryHeight; - bool mMDPScalingMode; - bool mUnderscanSupported; - // Downscale feature switch, set via system property - // sys.hwc.mdp_downscale_enabled - bool mMDPDownscaleEnabled; - int mDisplayId; -}; - -}; //qhwc -// --------------------------------------------------------------------------- -#endif //HWC_HDMI_DISPLAY_H diff --git a/msm8909/libhwcomposer/Android.mk b/msm8909/libhwcomposer/Android.mk deleted file mode 100644 index 1eafaf0f..00000000 --- a/msm8909/libhwcomposer/Android.mk +++ /dev/null @@ -1,71 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(LOCAL_PATH)/../common.mk -include $(CLEAR_VARS) - -LOCAL_MODULE := hwcomposer.$(TARGET_BOARD_PLATFORM) -LOCAL_MODULE_RELATIVE_PATH := hw -LOCAL_PROPRIETARY_MODULE := true -LOCAL_MODULE_TAGS := optional -LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes) \ - $(TOP)/external/skia/include/core \ - $(TOP)/external/skia/include/images - -ifeq ($(strip $(TARGET_USES_QCOM_DISPLAY_PP)),true) -LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/qdcm/inc \ - $(TARGET_OUT_HEADERS)/common/inc \ - $(TARGET_OUT_HEADERS)/pp/inc -endif - -LOCAL_SHARED_LIBRARIES := $(common_libs) libEGL liboverlay \ - libhdmi libqdutils libhardware_legacy \ - libdl libmemalloc libqservice libsync \ - libbinder libmedia - -LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdhwcomposer\" -Wno-absolute-value \ - -Wno-float-conversion - -LOCAL_CLANG := true - -ifeq ($(TARGET_USES_QCOM_BSP),true) -LOCAL_SHARED_LIBRARIES += libhwui -ifeq ($(GET_FRAMEBUFFER_FORMAT_FROM_HWC),true) - LOCAL_CFLAGS += -DGET_FRAMEBUFFER_FORMAT_FROM_HWC -endif -endif #TARGET_USES_QCOM_BSP - -#Enable Dynamic FPS if PHASE_OFFSET is not set -ifeq ($(VSYNC_EVENT_PHASE_OFFSET_NS),) - LOCAL_CFLAGS += -DDYNAMIC_FPS -endif - -LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) -LOCAL_SRC_FILES := hwc.cpp \ - hwc_utils.cpp \ - hwc_uevents.cpp \ - hwc_vsync.cpp \ - hwc_fbupdate.cpp \ - hwc_mdpcomp.cpp \ - hwc_copybit.cpp \ - hwc_qclient.cpp \ - hwc_dump_layers.cpp \ - hwc_ad.cpp \ - hwc_virtual.cpp - -TARGET_MIGRATE_QDCM_LIST := msm8909 -TARGET_MIGRATE_QDCM := $(call is-board-platform-in-list,$(TARGET_MIGRATE_QDCM_LIST)) - -ifeq ($(TARGET_MIGRATE_QDCM), true) -ifeq ($(strip $(TARGET_USES_QCOM_DISPLAY_PP)),true) -LOCAL_SRC_FILES += hwc_qdcm.cpp -else -LOCAL_SRC_FILES += hwc_qdcm_legacy.cpp -endif -else -LOCAL_SRC_FILES += hwc_qdcm_legacy.cpp -endif - -ifeq ($(TARGET_SUPPORTS_ANDROID_WEAR), true) - LOCAL_CFLAGS += -DSUPPORT_BLIT_TO_FB -endif - -include $(BUILD_SHARED_LIBRARY) diff --git a/msm8909/libhwcomposer/hwc.cpp b/msm8909/libhwcomposer/hwc.cpp deleted file mode 100644 index c6a7e0a6..00000000 --- a/msm8909/libhwcomposer/hwc.cpp +++ /dev/null @@ -1,977 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012-2016, The Linux Foundation. All rights reserved. - * - * Not a Contribution, Apache license notifications and license are retained - * for attribution purposes only. - * - * 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. - */ -#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL) -#include <fcntl.h> -#include <errno.h> - -#include <cutils/log.h> -#include <cutils/atomic.h> -#include <EGL/egl.h> -#include <utils/Trace.h> -#include <sys/ioctl.h> -#include <overlay.h> -#include <overlayRotator.h> -#include <overlayWriteback.h> -#include <mdp_version.h> -#include "hwc_utils.h" -#include "hwc_fbupdate.h" -#include "hwc_mdpcomp.h" -#include "hwc_dump_layers.h" -#include "hdmi.h" -#include "hwc_copybit.h" -#include "hwc_ad.h" -#include "profiler.h" -#include "hwc_virtual.h" -#include "hwc_qdcm.h" - -using namespace qhwc; -using namespace overlay; -using namespace qQdcm; - -#define VSYNC_DEBUG 0 -#define POWER_MODE_DEBUG 1 - -static int hwc_device_open(const struct hw_module_t* module, - const char* name, - struct hw_device_t** device); - -static struct hw_module_methods_t hwc_module_methods = { - .open = hwc_device_open -}; - -static void reset_panel(struct hwc_composer_device_1* dev); - -hwc_module_t HAL_MODULE_INFO_SYM = { - .common = { - .tag = HARDWARE_MODULE_TAG, - .version_major = 2, - .version_minor = 0, - .id = HWC_HARDWARE_MODULE_ID, - .name = "Qualcomm Hardware Composer Module", - .author = "CodeAurora Forum", - .methods = &hwc_module_methods, - .dso = 0, - .reserved = {0}, - } -}; - -/* - * Save callback functions registered to HWC - */ -static void hwc_registerProcs(struct hwc_composer_device_1* dev, - hwc_procs_t const* procs) -{ - ALOGI("%s", __FUNCTION__); - hwc_context_t* ctx = (hwc_context_t*)(dev); - if(!ctx) { - ALOGE("%s: Invalid context", __FUNCTION__); - return; - } - ctx->proc = procs; - - // Now that we have the functions needed, kick off - // the uevent & vsync threads - init_uevent_thread(ctx); - init_vsync_thread(ctx); -} - -static void setPaddingRound(hwc_context_t *ctx, int numDisplays, - hwc_display_contents_1_t** displays) { - ctx->isPaddingRound = false; - for(int i = 0; i < numDisplays; i++) { - hwc_display_contents_1_t *list = displays[i]; - if (LIKELY(list && list->numHwLayers > 0)) { - if((ctx->mPrevHwLayerCount[i] == 1 or - ctx->mPrevHwLayerCount[i] == 0) and - (list->numHwLayers > 1)) { - /* If the previous cycle for dpy 'i' has 0 AppLayers and the - * current cycle has atleast 1 AppLayer, padding round needs - * to be invoked in current cycle on all the active displays - * to free up the resources. - */ - ctx->isPaddingRound = true; - } - ctx->mPrevHwLayerCount[i] = (int)list->numHwLayers; - } else { - ctx->mPrevHwLayerCount[i] = 0; - } - } -} - -/* Based on certain conditions, isPaddingRound will be set - * to make this function self-contained */ -static void setDMAState(hwc_context_t *ctx, int numDisplays, - hwc_display_contents_1_t** displays) { - - if(ctx->mRotMgr->getNumActiveSessions() == 0) - Overlay::setDMAMode(Overlay::DMA_LINE_MODE); - - for(int dpy = 0; dpy < numDisplays; dpy++) { - hwc_display_contents_1_t *list = displays[dpy]; - if (LIKELY(list && list->numHwLayers > 0)) { - for(size_t layerIndex = 0; layerIndex < list->numHwLayers; - layerIndex++) { - if(list->hwLayers[layerIndex].compositionType != - HWC_FRAMEBUFFER_TARGET) - { - hwc_layer_1_t const* layer = &list->hwLayers[layerIndex]; - private_handle_t *hnd = (private_handle_t *)layer->handle; - - /* If a layer requires rotation, set the DMA state - * to BLOCK_MODE */ - - if (canUseRotator(ctx, dpy) && - (has90Transform(layer) || getRotDownscale(ctx, layer)) - && isRotationDoable(ctx, hnd)) { - if(not (ctx->mOverlay->isDMAMultiplexingSupported() && - dpy)) { - if(ctx->mOverlay->isPipeTypeAttached( - overlay::utils::OV_MDP_PIPE_DMA)) - ctx->isPaddingRound = true; - } - Overlay::setDMAMode(Overlay::DMA_BLOCK_MODE); - } - } - } - if(dpy) { - /* Uncomment the below code for testing purpose. - Assuming the orientation value is in terms of HAL_TRANSFORM, - this needs mapping to HAL, if its in different convention */ - - /* char value[PROPERTY_VALUE_MAX]; - property_get("sys.ext_orientation", value, "0"); - ctx->mExtOrientation = atoi(value);*/ - - if(ctx->mExtOrientation || ctx->mBufferMirrorMode) { - if(ctx->mOverlay->isPipeTypeAttached( - overlay::utils::OV_MDP_PIPE_DMA)) { - ctx->isPaddingRound = true; - } - Overlay::setDMAMode(Overlay::DMA_BLOCK_MODE); - } - } - } - } -} - -static void setNumActiveDisplays(hwc_context_t *ctx, int numDisplays, - hwc_display_contents_1_t** displays) { - - ctx->numActiveDisplays = 0; - for(int i = 0; i < numDisplays; i++) { - hwc_display_contents_1_t *list = displays[i]; - if (LIKELY(list && list->numHwLayers > 0)) { - /* For display devices like SSD and screenrecord, we cannot - * rely on isActive and connected attributes of dpyAttr to - * determine if the displaydevice is active. Hence in case if - * the layer-list is non-null and numHwLayers > 0, we assume - * the display device to be active. - */ - ctx->numActiveDisplays += 1; - } - } -} - -static bool validDisplay(int disp) { - switch(disp) { - case HWC_DISPLAY_PRIMARY: - case HWC_DISPLAY_EXTERNAL: - case HWC_DISPLAY_VIRTUAL: - return true; - break; - default: - return false; - } -} - -static void reset(hwc_context_t *ctx, int numDisplays, - hwc_display_contents_1_t** displays) { - - - for(int i = 0; i < numDisplays; i++) { - hwc_display_contents_1_t *list = displays[i]; - // XXX:SurfaceFlinger no longer guarantees that this - // value is reset on every prepare. However, for the layer - // cache we need to reset it. - // We can probably rethink that later on - if (LIKELY(list && list->numHwLayers > 0)) { - for(size_t j = 0; j < list->numHwLayers; j++) { - if(list->hwLayers[j].compositionType != HWC_FRAMEBUFFER_TARGET) - list->hwLayers[j].compositionType = HWC_FRAMEBUFFER; - } - - } - - if(ctx->mMDPComp[i]) - ctx->mMDPComp[i]->reset(); - if(ctx->mFBUpdate[i]) - ctx->mFBUpdate[i]->reset(); - if(ctx->mCopyBit[i]) - ctx->mCopyBit[i]->reset(); - if(ctx->mLayerRotMap[i]) - ctx->mLayerRotMap[i]->reset(); - } - - ctx->mAD->reset(); - -} - -static void scaleDisplayFrame(hwc_context_t *ctx, int dpy, - hwc_display_contents_1_t *list) { - uint32_t origXres = ctx->dpyAttr[dpy].xres; - uint32_t origYres = ctx->dpyAttr[dpy].yres; - uint32_t newXres = ctx->dpyAttr[dpy].xres_new; - uint32_t newYres = ctx->dpyAttr[dpy].yres_new; - float xresRatio = (float)origXres / (float)newXres; - float yresRatio = (float)origYres / (float)newYres; - for (size_t i = 0; i < list->numHwLayers; i++) { - hwc_layer_1_t *layer = &list->hwLayers[i]; - hwc_rect_t& displayFrame = layer->displayFrame; - uint32_t layerWidth = displayFrame.right - displayFrame.left; - uint32_t layerHeight = displayFrame.bottom - displayFrame.top; - displayFrame.left = (int)(xresRatio * (float)displayFrame.left); - displayFrame.top = (int)(yresRatio * (float)displayFrame.top); - displayFrame.right = (int)((float)displayFrame.left + - (float)layerWidth * xresRatio); - displayFrame.bottom = (int)((float)displayFrame.top + - (float)layerHeight * yresRatio); - } -} - -static int hwc_prepare_primary(hwc_composer_device_1 *dev, - hwc_display_contents_1_t *list) { - ATRACE_CALL(); - hwc_context_t* ctx = (hwc_context_t*)(dev); - const int dpy = HWC_DISPLAY_PRIMARY; - bool fbComp = false; - static int compStart = false; - if (!ctx->mBootAnimCompleted) - processBootAnimCompleted(ctx); - - if (LIKELY(list && (list->numHwLayers > 1 || - (ctx->mMDP.version < qdutils::MDP_V4_0 && compStart))) && - (ctx->dpyAttr[dpy].isActive || - ctx->mHDMIDisplay->isHDMIPrimaryDisplay()) - && !ctx->dpyAttr[dpy].isPause) { - compStart = true; - - // When HDMI is primary we should rely on the first valid - // draw call in order to activate the display - if (!ctx->dpyAttr[dpy].isActive) { - // If the cable is connected after HWC initialization and before - // the UEvent thread is initialized then we will miss the ONLINE - // event. We need to update the display appropriately when we get - // the first valid frame. - int cableConnected = ctx->mHDMIDisplay->getConnectedState(); - if ((cableConnected == 1) && !ctx->dpyAttr[dpy].connected) { - qhwc::handle_online(ctx, dpy); - } - ctx->mHDMIDisplay->activateDisplay(); - ctx->dpyAttr[dpy].isActive = true; - } - - if (ctx->dpyAttr[dpy].customFBSize && - list->flags & HWC_GEOMETRY_CHANGED) - scaleDisplayFrame(ctx, dpy, list); - - reset_layer_prop(ctx, dpy, (int)list->numHwLayers - 1); - setListStats(ctx, list, dpy); - - fbComp = (ctx->mMDPComp[dpy]->prepare(ctx, list) < 0); - - if (fbComp) { - const int fbZ = 0; - if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ)) { - ctx->mOverlay->clear(dpy); - ctx->mLayerRotMap[dpy]->clear(); - } - } - - if (ctx->mMDP.version < qdutils::MDP_V4_0) { - if(ctx->mCopyBit[dpy]) - ctx->mCopyBit[dpy]->prepare(ctx, list, dpy); - } - setGPUHint(ctx, list); - } - return 0; -} - -static int hwc_prepare_external(hwc_composer_device_1 *dev, - hwc_display_contents_1_t *list) { - ATRACE_CALL(); - hwc_context_t* ctx = (hwc_context_t*)(dev); - const int dpy = HWC_DISPLAY_EXTERNAL; - - if (LIKELY(list && list->numHwLayers > 1) && - ctx->dpyAttr[dpy].isActive && - ctx->dpyAttr[dpy].connected) { - reset_layer_prop(ctx, dpy, (int)list->numHwLayers - 1); - if(!ctx->dpyAttr[dpy].isPause) { - ctx->dpyAttr[dpy].isConfiguring = false; - setListStats(ctx, list, dpy); - if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) { - const int fbZ = 0; - if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ)) - { - ctx->mOverlay->clear(dpy); - ctx->mLayerRotMap[dpy]->clear(); - } - } - } else { - /* External Display is in Pause state. - * Mark all application layers as OVERLAY so that - * GPU will not compose. - */ - for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) { - hwc_layer_1_t *layer = &list->hwLayers[i]; - layer->compositionType = HWC_OVERLAY; - } - } - } - return 0; -} - -static int hwc_prepare(hwc_composer_device_1 *dev, size_t numDisplays, - hwc_display_contents_1_t** displays) -{ - int ret = 0; - hwc_context_t* ctx = (hwc_context_t*)(dev); - - if (ctx->mPanelResetStatus) { - ALOGW("%s: panel is in bad state. reset the panel", __FUNCTION__); - reset_panel(dev); - } - - //Will be unlocked at the end of set - ctx->mDrawLock.lock(); - setPaddingRound(ctx, (int)numDisplays, displays); - setDMAState(ctx, (int)numDisplays, displays); - setNumActiveDisplays(ctx, (int)numDisplays, displays); - reset(ctx, (int)numDisplays, displays); - - ctx->mOverlay->configBegin(); - ctx->mRotMgr->configBegin(); - overlay::Writeback::configBegin(); - - for (int32_t dpy = ((int32_t)numDisplays-1); dpy >=0 ; dpy--) { - hwc_display_contents_1_t *list = displays[dpy]; - resetROI(ctx, dpy); - switch(dpy) { - case HWC_DISPLAY_PRIMARY: - ret = hwc_prepare_primary(dev, list); - break; - case HWC_DISPLAY_EXTERNAL: - ret = hwc_prepare_external(dev, list); - break; - case HWC_DISPLAY_VIRTUAL: - if(ctx->mHWCVirtual) - ret = ctx->mHWCVirtual->prepare(dev, list); - break; - default: - ret = -EINVAL; - } - } - - ctx->mOverlay->configDone(); - ctx->mRotMgr->configDone(); - overlay::Writeback::configDone(); - // If VD list is deleted, mdp overlay pipe objects and writeback object - // are deleted as part of configDone functions. - // Proceed with HWCVirtualVDS object deletion. - if(ctx->mHWCVirtual) - ctx->mHWCVirtual->destroy(ctx, numDisplays, displays); - - return ret; -} - -static int hwc_eventControl(struct hwc_composer_device_1* dev, int dpy, - int event, int enable) -{ - ATRACE_CALL(); - int ret = 0; - hwc_context_t* ctx = (hwc_context_t*)(dev); - if(!validDisplay(dpy)) { - return -EINVAL; - } - - switch(event) { - case HWC_EVENT_VSYNC: - if (ctx->vstate.enable == enable) - break; - ret = hwc_vsync_control(ctx, dpy, enable); - if(ret == 0) - ctx->vstate.enable = !!enable; - ALOGD_IF (VSYNC_DEBUG, "VSYNC state changed to %s", - (enable)?"ENABLED":"DISABLED"); - break; -#ifdef QTI_BSP - case HWC_EVENT_ORIENTATION: - if(dpy == HWC_DISPLAY_PRIMARY) { - Locker::Autolock _l(ctx->mDrawLock); - // store the primary display orientation - ctx->deviceOrientation = enable; - } - break; -#endif - default: - ret = -EINVAL; - } - return ret; -} - -static int hwc_setPowerMode(struct hwc_composer_device_1* dev, int dpy, - int mode) -{ - ATRACE_CALL(); - hwc_context_t* ctx = (hwc_context_t*)(dev); - int ret = 0, value = 0; - - Locker::Autolock _l(ctx->mDrawLock); - - if(!validDisplay(dpy)) { - return -EINVAL; - } - - ALOGD_IF(POWER_MODE_DEBUG, "%s: Setting mode %d on display: %d", - __FUNCTION__, mode, dpy); - - switch(mode) { - case HWC_POWER_MODE_OFF: - // free up all the overlay pipes in use - // when we get a blank for either display - // makes sure that all pipes are freed - ctx->mOverlay->configBegin(); - ctx->mOverlay->configDone(); - ctx->mRotMgr->clear(); - // If VDS is connected, do not clear WB object as it - // will end up detaching IOMMU. This is required - // to send black frame to WFD sink on power suspend. - // Note: With this change, we keep the WriteBack object - // alive on power suspend for AD use case. - value = FB_BLANK_POWERDOWN; - break; - case HWC_POWER_MODE_DOZE: - case HWC_POWER_MODE_DOZE_SUSPEND: - value = FB_BLANK_VSYNC_SUSPEND; - break; - case HWC_POWER_MODE_NORMAL: - value = FB_BLANK_UNBLANK; - break; - } - - switch(dpy) { - case HWC_DISPLAY_PRIMARY: - if(ctx->mHDMIDisplay->isHDMIPrimaryDisplay()) { - if(ctx->dpyAttr[dpy].connected) { - // When HDMI is connected as primary we clean up resources - // and call commit to generate a black frame on the interface. - // However, we do not call blank since we need the timing - // generator and HDMI core to remain turned on. - if((mode == HWC_POWER_MODE_OFF) && - (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd))) { - ALOGE("%s: display commit fail for %d", __FUNCTION__, dpy); - ret = -1; - } - } - } else { - if(ioctl(ctx->dpyAttr[dpy].fd, FBIOBLANK, value) < 0 ) { - ALOGE("%s: ioctl FBIOBLANK failed for Primary with error %s" - " value %d", __FUNCTION__, strerror(errno), value); - return -errno; - } - - if(mode == HWC_POWER_MODE_NORMAL) { - // Enable HPD here, as during bootup POWER_MODE_NORMAL is set - // when SF is completely initialized - ctx->mHDMIDisplay->setHPD(1); - } - - ctx->dpyAttr[dpy].isActive = not(mode == HWC_POWER_MODE_OFF); - } - //Deliberate fall through since there is no explicit power mode for - //virtual displays. - case HWC_DISPLAY_VIRTUAL: - if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected) { - const int dpy = HWC_DISPLAY_VIRTUAL; - if(mode == HWC_POWER_MODE_OFF and - (not ctx->dpyAttr[dpy].isPause)) { - if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) { - ALOGE("%s: displayCommit failed for virtual", __FUNCTION__); - ret = -1; - } - } - ctx->dpyAttr[dpy].isActive = not(mode == HWC_POWER_MODE_OFF); - } - break; - case HWC_DISPLAY_EXTERNAL: - if(mode == HWC_POWER_MODE_OFF) { - if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) { - ALOGE("%s: displayCommit failed for external", __FUNCTION__); - ret = -1; - } - } - ctx->dpyAttr[dpy].isActive = not(mode == HWC_POWER_MODE_OFF); - break; - default: - return -EINVAL; - } - - ALOGD_IF(POWER_MODE_DEBUG, "%s: Done setting mode %d on display %d", - __FUNCTION__, mode, dpy); - return ret; -} - -static void reset_panel(struct hwc_composer_device_1* dev) -{ - int ret = 0; - hwc_context_t* ctx = (hwc_context_t*)(dev); - - if (!ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isActive) { - ALOGD ("%s : Display OFF - Skip BLANK & UNBLANK", __FUNCTION__); - ctx->mPanelResetStatus = false; - return; - } - - ALOGD("%s: setting power mode off", __FUNCTION__); - ret = hwc_setPowerMode(dev, HWC_DISPLAY_PRIMARY, HWC_POWER_MODE_OFF); - if (ret < 0) { - ALOGE("%s: FBIOBLANK failed to BLANK: %s", __FUNCTION__, - strerror(errno)); - } - - ALOGD("%s: setting power mode normal and enabling vsync", __FUNCTION__); - ret = hwc_setPowerMode(dev, HWC_DISPLAY_PRIMARY, HWC_POWER_MODE_NORMAL); - if (ret < 0) { - ALOGE("%s: FBIOBLANK failed to UNBLANK : %s", __FUNCTION__, - strerror(errno)); - } - hwc_vsync_control(ctx, HWC_DISPLAY_PRIMARY, 1); - - ctx->mPanelResetStatus = false; -} - - -static int hwc_query(struct hwc_composer_device_1* dev, - int param, int* value) -{ - hwc_context_t* ctx = (hwc_context_t*)(dev); - int supported = HWC_DISPLAY_PRIMARY_BIT; - - switch (param) { - case HWC_BACKGROUND_LAYER_SUPPORTED: - // Not supported for now - value[0] = 0; - break; - case HWC_DISPLAY_TYPES_SUPPORTED: - if(ctx->mMDP.hasOverlay) { - supported |= HWC_DISPLAY_VIRTUAL_BIT; - if(!(qdutils::MDPVersion::getInstance().is8x26() || - qdutils::MDPVersion::getInstance().is8x16() || - qdutils::MDPVersion::getInstance().is8x39())) - supported |= HWC_DISPLAY_EXTERNAL_BIT; - } - value[0] = supported; - break; - case HWC_FORMAT_RB_SWAP: - value[0] = 1; - break; - case HWC_COLOR_FILL: - value[0] = 1; - break; - default: - return -EINVAL; - } - return 0; - -} - - -static int hwc_set_primary(hwc_context_t *ctx, hwc_display_contents_1_t* list) { - ATRACE_CALL(); - int ret = 0; - const int dpy = HWC_DISPLAY_PRIMARY; - if (LIKELY(list) && ctx->dpyAttr[dpy].isActive - && !ctx->dpyAttr[dpy].isPause) { - size_t last = list->numHwLayers - 1; - hwc_layer_1_t *fbLayer = &list->hwLayers[last]; - int fd = -1; //FenceFD from the Copybit(valid in async mode) - bool copybitDone = false; - - if (ctx->mCopyBit[dpy]) { - if (ctx->mMDP.version < qdutils::MDP_V4_0) - copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd); - else - fd = ctx->mMDPComp[dpy]->drawOverlap(ctx, list); - } - - if(list->numHwLayers > 1) - hwc_sync(ctx, list, dpy, fd); - - // Dump the layers for primary - if(ctx->mHwcDebug[dpy]) - ctx->mHwcDebug[dpy]->dumpLayers(list); - - if (!ctx->mMDPComp[dpy]->draw(ctx, list)) { - ALOGE("%s: MDPComp draw failed", __FUNCTION__); - ret = -1; - } - - //TODO We dont check for SKIP flag on this layer because we need PAN - //always. Last layer is always FB - private_handle_t *hnd = (private_handle_t *)fbLayer->handle; - if(copybitDone && ((ctx->mMDP.version >= qdutils::MDP_V4_0) -#ifdef SUPPORT_BLIT_TO_FB - || (ctx->mMDP.version == qdutils::MDP_V3_0_5) -#endif - )) { - hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer(); - } - - if(isAbcInUse(ctx) == true) { - int index = ctx->listStats[dpy].renderBufIndexforABC; - hwc_layer_1_t *tempLayer = &list->hwLayers[index]; - hnd = (private_handle_t *)tempLayer->handle; - } - - if(hnd) { - if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) { - ALOGE("%s: FBUpdate draw failed", __FUNCTION__); - ret = -1; - } - } - - int lSplit = getLeftSplit(ctx, dpy); - qhwc::ovutils::Dim lRoi = qhwc::ovutils::Dim( - ctx->listStats[dpy].lRoi.left, - ctx->listStats[dpy].lRoi.top, - ctx->listStats[dpy].lRoi.right - ctx->listStats[dpy].lRoi.left, - ctx->listStats[dpy].lRoi.bottom - ctx->listStats[dpy].lRoi.top); - - qhwc::ovutils::Dim rRoi = qhwc::ovutils::Dim( - ctx->listStats[dpy].rRoi.left - lSplit, - ctx->listStats[dpy].rRoi.top, - ctx->listStats[dpy].rRoi.right - ctx->listStats[dpy].rRoi.left, - ctx->listStats[dpy].rRoi.bottom - ctx->listStats[dpy].rRoi.top); - - if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd, lRoi, rRoi)) { - ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy); - ret = -1; - } - - } - - closeAcquireFds(list); - return ret; -} - -static int hwc_set_external(hwc_context_t *ctx, - hwc_display_contents_1_t* list) -{ - ATRACE_CALL(); - int ret = 0; - - const int dpy = HWC_DISPLAY_EXTERNAL; - - if (LIKELY(list) && ctx->dpyAttr[dpy].isActive && - ctx->dpyAttr[dpy].connected && - !ctx->dpyAttr[dpy].isPause) { - size_t last = list->numHwLayers - 1; - hwc_layer_1_t *fbLayer = &list->hwLayers[last]; - int fd = -1; //FenceFD from the Copybit(valid in async mode) - bool copybitDone = false; - if(ctx->mCopyBit[dpy]) - copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd); - - if(list->numHwLayers > 1) - hwc_sync(ctx, list, dpy, fd); - - // Dump the layers for external - if(ctx->mHwcDebug[dpy]) - ctx->mHwcDebug[dpy]->dumpLayers(list); - - if (!ctx->mMDPComp[dpy]->draw(ctx, list)) { - ALOGE("%s: MDPComp draw failed", __FUNCTION__); - ret = -1; - } - - private_handle_t *hnd = (private_handle_t *)fbLayer->handle; - if(copybitDone) { - hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer(); - } - - if(hnd) { - if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) { - ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__); - ret = -1; - } - } - - if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) { - ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy); - ret = -1; - } - } - - closeAcquireFds(list); - return ret; -} - -static int hwc_set(hwc_composer_device_1 *dev, - size_t numDisplays, - hwc_display_contents_1_t** displays) -{ - int ret = 0; - hwc_context_t* ctx = (hwc_context_t*)(dev); - for (int dpy = 0; dpy < (int)numDisplays; dpy++) { - hwc_display_contents_1_t* list = displays[dpy]; - switch(dpy) { - case HWC_DISPLAY_PRIMARY: - ret = hwc_set_primary(ctx, list); - break; - case HWC_DISPLAY_EXTERNAL: - ret = hwc_set_external(ctx, list); - break; - case HWC_DISPLAY_VIRTUAL: - if(ctx->mHWCVirtual) - ret = ctx->mHWCVirtual->set(ctx, list); - break; - default: - ret = -EINVAL; - } - } - // This is only indicative of how many times SurfaceFlinger posts - // frames to the display. - CALC_FPS(); - MDPComp::resetIdleFallBack(); - ctx->mVideoTransFlag = false; - //Was locked at the beginning of prepare - ctx->mDrawLock.unlock(); - return ret; -} - -int hwc_getDisplayConfigs(struct hwc_composer_device_1* dev, int disp, - uint32_t* configs, size_t* numConfigs) { - int ret = 0; - hwc_context_t* ctx = (hwc_context_t*)(dev); - - Locker::Autolock _l(ctx->mDrawLock); - - if(!validDisplay(disp)) { - return -EINVAL; - } - //Currently we allow only 1 config, reported as config id # 0 - //This config is passed in to getDisplayAttributes. Ignored for now. - - switch(disp) { - case HWC_DISPLAY_PRIMARY: - if(*numConfigs > 0) { - configs[0] = 0; - *numConfigs = 1; - } - ret = 0; //NO_ERROR - break; - case HWC_DISPLAY_EXTERNAL: - case HWC_DISPLAY_VIRTUAL: - ret = -1; //Not connected - if(ctx->dpyAttr[disp].connected) { - ret = 0; //NO_ERROR - if(*numConfigs > 0) { - configs[0] = 0; - *numConfigs = 1; - } - } - break; - } - return ret; -} - -int hwc_getDisplayAttributes(struct hwc_composer_device_1* dev, int disp, - uint32_t /*config*/, const uint32_t* attributes, int32_t* values) { - - hwc_context_t* ctx = (hwc_context_t*)(dev); - - Locker::Autolock _l(ctx->mDrawLock); - - if(!validDisplay(disp)) { - return -EINVAL; - } - //If hotpluggable displays(i.e, HDMI, WFD) are inactive return error - if( (disp != HWC_DISPLAY_PRIMARY) && !ctx->dpyAttr[disp].connected) { - return -1; - } - - //From HWComposer - static const uint32_t DISPLAY_ATTRIBUTES[] = { - HWC_DISPLAY_VSYNC_PERIOD, - HWC_DISPLAY_WIDTH, - HWC_DISPLAY_HEIGHT, - HWC_DISPLAY_DPI_X, - HWC_DISPLAY_DPI_Y, -#ifdef GET_FRAMEBUFFER_FORMAT_FROM_HWC - HWC_DISPLAY_FBFORMAT, -#endif - HWC_DISPLAY_NO_ATTRIBUTE, - }; - - const size_t NUM_DISPLAY_ATTRIBUTES = (sizeof(DISPLAY_ATTRIBUTES) / - sizeof(DISPLAY_ATTRIBUTES)[0]); - - for (size_t i = 0; i < NUM_DISPLAY_ATTRIBUTES - 1; i++) { - switch (attributes[i]) { - case HWC_DISPLAY_VSYNC_PERIOD: - values[i] = ctx->dpyAttr[disp].vsync_period; - break; - case HWC_DISPLAY_WIDTH: - if (ctx->dpyAttr[disp].customFBSize) - values[i] = ctx->dpyAttr[disp].xres_new; - else - values[i] = ctx->dpyAttr[disp].xres; - - ALOGD("%s disp = %d, width = %d",__FUNCTION__, disp, - values[i]); - break; - case HWC_DISPLAY_HEIGHT: - if (ctx->dpyAttr[disp].customFBSize) - values[i] = ctx->dpyAttr[disp].yres_new; - else - values[i] = ctx->dpyAttr[disp].yres; - ALOGD("%s disp = %d, height = %d",__FUNCTION__, disp, - values[i]); - break; - case HWC_DISPLAY_DPI_X: - values[i] = (int32_t) (ctx->dpyAttr[disp].xdpi*1000.0); - break; - case HWC_DISPLAY_DPI_Y: - values[i] = (int32_t) (ctx->dpyAttr[disp].ydpi*1000.0); - break; -#ifdef GET_FRAMEBUFFER_FORMAT_FROM_HWC - case HWC_DISPLAY_FBFORMAT: - values[i] = ctx->dpyAttr[disp].fbformat; - break; -#endif - default: - ALOGE("Unknown display attribute %d", - attributes[i]); - return -EINVAL; - } - } - return 0; -} - -void hwc_dump(struct hwc_composer_device_1* dev, char *buff, int buff_len) -{ - hwc_context_t* ctx = (hwc_context_t*)(dev); - Locker::Autolock _l(ctx->mDrawLock); - android::String8 aBuf(""); - dumpsys_log(aBuf, "Qualcomm HWC state:\n"); - dumpsys_log(aBuf, " MDPVersion=%d\n", ctx->mMDP.version); - dumpsys_log(aBuf, " DisplayPanel=%c\n", ctx->mMDP.panel); - dumpsys_log(aBuf, " DynRefreshRate=%d\n", - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].dynRefreshRate); - for(int dpy = 0; dpy < HWC_NUM_DISPLAY_TYPES; dpy++) { - if(ctx->mMDPComp[dpy]) - ctx->mMDPComp[dpy]->dump(aBuf, ctx); - } - char ovDump[2048] = {'\0'}; - ctx->mOverlay->getDump(ovDump, 2048); - dumpsys_log(aBuf, ovDump); - ovDump[0] = '\0'; - ctx->mRotMgr->getDump(ovDump, 1024); - dumpsys_log(aBuf, ovDump); - ovDump[0] = '\0'; - if(Writeback::getDump(ovDump, 1024)) { - dumpsys_log(aBuf, ovDump); - ovDump[0] = '\0'; - } - dumpsys_log(aBuf, "Copybit::isAbcInUse=%d\n\n",isAbcInUse(ctx) ? 1 : 0); - strlcpy(buff, aBuf.string(), buff_len); -} - -int hwc_getActiveConfig(struct hwc_composer_device_1* dev, int disp) { - hwc_context_t* ctx = (hwc_context_t*)(dev); - Locker::Autolock _l(ctx->mDrawLock); - if(!validDisplay(disp)) { - return -EINVAL; - } - - //Supports only the default config (0th index) for now - return 0; -} - -int hwc_setActiveConfig(struct hwc_composer_device_1* dev, int disp, - int index) { - hwc_context_t* ctx = (hwc_context_t*)(dev); - Locker::Autolock _l(ctx->mDrawLock); - if(!validDisplay(disp)) { - return -EINVAL; - } - - //Supports only the default config (0th index) for now - return (index == 0) ? index : -EINVAL; -} - -static int hwc_device_close(struct hw_device_t *dev) -{ - if(!dev) { - ALOGE("%s: NULL device pointer", __FUNCTION__); - return -1; - } - closeContext((hwc_context_t*)dev); - free(dev); - - return 0; -} - -static int hwc_device_open(const struct hw_module_t* module, const char* name, - struct hw_device_t** device) -{ - int status = -EINVAL; - - if (!strcmp(name, HWC_HARDWARE_COMPOSER)) { - struct hwc_context_t *dev; - dev = (hwc_context_t*)malloc(sizeof(*dev)); - if(dev == NULL) - return status; - memset(dev, 0, sizeof(*dev)); - - //Initialize hwc context - initContext(dev); - - //Setup HWC methods - dev->device.common.tag = HARDWARE_DEVICE_TAG; - dev->device.common.version = HWC_DEVICE_API_VERSION_1_5; - dev->device.common.module = const_cast<hw_module_t*>(module); - dev->device.common.close = hwc_device_close; - dev->device.prepare = hwc_prepare; - dev->device.set = hwc_set; - dev->device.eventControl = hwc_eventControl; - dev->device.setPowerMode = hwc_setPowerMode; - dev->device.query = hwc_query; - dev->device.registerProcs = hwc_registerProcs; - dev->device.dump = hwc_dump; - dev->device.getDisplayConfigs = hwc_getDisplayConfigs; - dev->device.getDisplayAttributes = hwc_getDisplayAttributes; - dev->device.getActiveConfig = hwc_getActiveConfig; - dev->device.setActiveConfig = hwc_setActiveConfig; - *device = &dev->device.common; - status = 0; - } - return status; -} diff --git a/msm8909/libhwcomposer/hwc_ad.cpp b/msm8909/libhwcomposer/hwc_ad.cpp deleted file mode 100644 index 7e96d97e..00000000 --- a/msm8909/libhwcomposer/hwc_ad.cpp +++ /dev/null @@ -1,278 +0,0 @@ -/* -* Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are -* met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above -* copyright notice, this list of conditions and the following -* disclaimer in the documentation and/or other materials provided -* with the distribution. -* * Neither the name of The Linux Foundation. nor the names of its -* contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include <unistd.h> -#include <overlay.h> -#include <overlayUtils.h> -#include <overlayWriteback.h> -#include <mdp_version.h> -#include "hwc_ad.h" -#include "hwc_utils.h" - -#define DEBUG 0 -using namespace overlay; -using namespace overlay::utils; -namespace qhwc { - -//Helper to write data to ad node -static void adWrite(const int& value) { - const int wbFbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK); - char wbFbPath[256]; - snprintf (wbFbPath, sizeof(wbFbPath), - "/sys/class/graphics/fb%d/ad", wbFbNum); - int adFd = open(wbFbPath, O_WRONLY); - if(adFd >= 0) { - char opStr[4] = ""; - snprintf(opStr, sizeof(opStr), "%d", value); - ssize_t ret = write(adFd, opStr, strlen(opStr)); - if(ret < 0) { - ALOGE("%s: Failed to write %d with error %s", - __func__, value, strerror(errno)); - } else if (ret == 0){ - ALOGE("%s Nothing written to ad", __func__); - } else { - ALOGD_IF(DEBUG, "%s: Wrote %d to ad", __func__, value); - } - close(adFd); - } else { - ALOGE("%s: Failed to open /sys/class/graphics/fb%d/ad with error %s", - __func__, wbFbNum, strerror(errno)); - } -} - -//Helper to read data from ad node -static int adRead() { - const int wbFbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK); - int ret = -1; - char wbFbPath[256]; - snprintf (wbFbPath, sizeof(wbFbPath), - "/sys/class/graphics/fb%d/ad", wbFbNum); - int adFd = open(wbFbPath, O_RDONLY); - if(adFd >= 0) { - char opStr[4]; - ssize_t bytesRead = read(adFd, opStr, sizeof(opStr) - 1); - if(bytesRead > 0) { - opStr[bytesRead] = '\0'; - //Should return -1, 0 or 1 - ret = atoi(opStr); - ALOGD_IF(DEBUG, "%s: Read %d from ad", __func__, ret); - } else if(bytesRead == 0) { - ALOGE("%s: ad node empty", __func__); - } else { - ALOGE("%s: Read from ad node failed with error %s", __func__, - strerror(errno)); - } - close(adFd); - } else { - ALOGD("%s: /sys/class/graphics/fb%d/ad could not be opened : %s", - __func__, wbFbNum, strerror(errno)); - } - return ret; -} - -AssertiveDisplay::AssertiveDisplay(hwc_context_t *ctx) : - mTurnedOff(true), mFeatureEnabled(false), - mDest(overlay::utils::OV_INVALID) -{ - //Values in ad node: - //-1 means feature is disabled on device - // 0 means feature exists but turned off, will be turned on by hwc - // 1 means feature is turned on by hwc - // Plus, we do this feature only on split primary displays. - // Plus, we do this feature only if ro.qcom.ad=2 - - char property[PROPERTY_VALUE_MAX]; - const int ENABLED = 2; - int val = 0; - - if(property_get("ro.qcom.ad", property, "0") > 0) { - val = atoi(property); - } - - if(adRead() >= 0 && isDisplaySplit(ctx, HWC_DISPLAY_PRIMARY) && - val == ENABLED) { - ALOGD_IF(DEBUG, "Assertive display feature supported"); - mFeatureEnabled = true; - // If feature exists but is turned off, set mTurnedOff to true - mTurnedOff = adRead() > 0 ? false : true; - } -} - -void AssertiveDisplay::markDoable(hwc_context_t *ctx, - const hwc_display_contents_1_t* list) { - mDoable = false; - if(mFeatureEnabled && - !isSecondaryConnected(ctx) && - ctx->listStats[HWC_DISPLAY_PRIMARY].yuvCount == 1) { - int nYuvIndex = ctx->listStats[HWC_DISPLAY_PRIMARY].yuvIndices[0]; - const hwc_layer_1_t* layer = &list->hwLayers[nYuvIndex]; - private_handle_t *hnd = (private_handle_t *)layer->handle; - qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance(); - if(hnd && hnd->width <= (int) mdpHw.getMaxMixerWidth()) { - mDoable = true; - } - } -} - -void AssertiveDisplay::turnOffAD() { - if(mFeatureEnabled) { - if(!mTurnedOff) { - const int off = 0; - adWrite(off); - mTurnedOff = true; - } - } - mDoable = false; -} - -bool AssertiveDisplay::prepare(hwc_context_t *ctx, - const hwc_rect_t& crop, - const Whf& whf, - const private_handle_t *hnd) { - if(!isDoable()) { - //Cleanup one time during this switch - turnOffAD(); - return false; - } - - Overlay::PipeSpecs pipeSpecs; - pipeSpecs.formatClass = Overlay::FORMAT_YUV; - pipeSpecs.dpy = overlay::Overlay::DPY_WRITEBACK; - pipeSpecs.fb = false; - - ovutils::eDest dest = ctx->mOverlay->getPipe(pipeSpecs); - if(dest == OV_INVALID) { - ALOGE("%s failed: No VG pipe available", __func__); - mDoable = false; - return false; - } - - overlay::Writeback *wb = overlay::Writeback::getInstance(); - - //Set Security flag on writeback - if(isSecureBuffer(hnd)) { - if(!wb->setSecure(isSecureBuffer(hnd))) { - ALOGE("Failure in setting WB secure flag for ad"); - return false; - } - } - - if(!wb->configureDpyInfo(hnd->width, hnd->height)) { - ALOGE("%s: config display failed", __func__); - mDoable = false; - return false; - } - - int tmpW, tmpH; - size_t size; - int format = ovutils::getHALFormat(wb->getOutputFormat()); - if(format < 0) { - ALOGE("%s invalid format %d", __func__, format); - mDoable = false; - return false; - } - - size = getBufferSizeAndDimensions(hnd->width, hnd->height, - format, tmpW, tmpH); - - if(!wb->configureMemory((uint32_t)size)) { - ALOGE("%s: config memory failed", __func__); - mDoable = false; - return false; - } - - eMdpFlags mdpFlags = OV_MDP_FLAGS_NONE; - if(isSecureBuffer(hnd)) { - ovutils::setMdpFlags(mdpFlags, - ovutils::OV_MDP_SECURE_OVERLAY_SESSION); - } - - PipeArgs parg(mdpFlags, whf, ZORDER_0, - ROT_FLAGS_NONE); - hwc_rect_t dst = crop; //input same as output - - if(configMdp(ctx->mOverlay, parg, OVERLAY_TRANSFORM_0, crop, dst, NULL, - dest) < 0) { - ALOGE("%s: configMdp failed", __func__); - mDoable = false; - return false; - } - - mDest = dest; - int wbFd = wb->getFbFd(); - if(mFeatureEnabled && wbFd >= 0 && - !ctx->mOverlay->validateAndSet(overlay::Overlay::DPY_WRITEBACK, wbFd)) - { - ALOGE("%s: Failed to validate and set overlay for dpy %d" - ,__FUNCTION__, overlay::Overlay::DPY_WRITEBACK); - turnOffAD(); - return false; - } - - // Only turn on AD if there are no errors during configuration stage - // and if it was previously in OFF state. - if(mFeatureEnabled && mTurnedOff) { - //write to sysfs, one time during this switch - const int on = 1; - adWrite(on); - mTurnedOff = false; - } - - return true; -} - -bool AssertiveDisplay::draw(hwc_context_t *ctx, int fd, uint32_t offset) { - if(!isDoable()) { - return false; - } - - if (!ctx->mOverlay->queueBuffer(fd, offset, mDest)) { - ALOGE("%s: queueBuffer failed", __func__); - return false; - } - - overlay::Writeback *wb = overlay::Writeback::getInstance(); - if(!wb->writeSync()) { - return false; - } - - return true; -} - -int AssertiveDisplay::getDstFd() const { - overlay::Writeback *wb = overlay::Writeback::getInstance(); - return wb->getDstFd(); -} - -uint32_t AssertiveDisplay::getDstOffset() const { - overlay::Writeback *wb = overlay::Writeback::getInstance(); - return wb->getOffset(); -} - -} diff --git a/msm8909/libhwcomposer/hwc_copybit.cpp b/msm8909/libhwcomposer/hwc_copybit.cpp deleted file mode 100644 index 4b70b130..00000000 --- a/msm8909/libhwcomposer/hwc_copybit.cpp +++ /dev/null @@ -1,1382 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012-2016, The Linux Foundation. All rights reserved. - * - * Not a Contribution. - * - * 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. - */ - -#define DEBUG_COPYBIT 0 -#include <copybit.h> -#include <utils/Timers.h> -#include <mdp_version.h> -#include "hwc_copybit.h" -#include "comptype.h" -#include "gr.h" -#include "cb_utils.h" -#include "cb_swap_rect.h" -#include "math.h" -#include "sync/sync.h" - -using namespace qdutils; -namespace qhwc { - -struct range { - int current; - int end; -}; -struct region_iterator : public copybit_region_t { - - region_iterator(hwc_region_t region) { - mRegion = region; - r.end = (int)region.numRects; - r.current = 0; - this->next = iterate; - } - -private: - static int iterate(copybit_region_t const * self, copybit_rect_t* rect){ - if (!self || !rect) { - ALOGE("iterate invalid parameters"); - return 0; - } - - region_iterator const* me = - static_cast<region_iterator const*>(self); - if (me->r.current != me->r.end) { - rect->l = me->mRegion.rects[me->r.current].left; - rect->t = me->mRegion.rects[me->r.current].top; - rect->r = me->mRegion.rects[me->r.current].right; - rect->b = me->mRegion.rects[me->r.current].bottom; - me->r.current++; - return 1; - } - return 0; - } - - hwc_region_t mRegion; - mutable range r; -}; - -void CopyBit::reset() { - mIsModeOn = false; - mCopyBitDraw = false; -} - -bool CopyBit::canUseCopybitForYUV(hwc_context_t *ctx) { - // return true for non-overlay targets - if(ctx->mMDP.hasOverlay && ctx->mMDP.version >= qdutils::MDP_V4_0) { - return false; - } - return true; -} - -bool CopyBit::isSmartBlitPossible(const hwc_display_contents_1_t *list){ - if(list->numHwLayers > 2) { - hwc_rect_t displayFrame0 = {0, 0, 0, 0}; - hwc_rect_t displayFrame1 = {0, 0, 0, 0}; - int layer0_transform = 0; - int layer1_transform = 0; - int isYuvLayer0 = 0; - int isYuvLayer1 = 0; - for (unsigned int i=0; i<list->numHwLayers -1; i++) { - hwc_rect_t displayFrame = list->hwLayers[i].displayFrame; - if (mSwapRect) - displayFrame = getIntersection(mDirtyRect, - list->hwLayers[i].displayFrame); - if (isValidRect(displayFrame) && !isValidRect(displayFrame0)) { - displayFrame0 = displayFrame; - private_handle_t *hnd =(private_handle_t *)list->hwLayers[i].handle; - isYuvLayer0 = isYuvBuffer(hnd); - layer0_transform = list->hwLayers[i].transform; - } else if(isValidRect(displayFrame)) { - displayFrame1 = displayFrame; - layer1_transform = list->hwLayers[i].transform; - private_handle_t *hnd =(private_handle_t *)list->hwLayers[i].handle; - isYuvLayer1 = isYuvBuffer(hnd); - break; - } - } - /* - * smart blit enable only if - * 1. Both layers should have same ROI. - * 2. Both layers can't be video layer. - * 3. Should not be any rotation for base RGB layer. - * 4. In case of base layer as video, next above RGB layer - * should not contains any rotation. - */ - if((displayFrame0 == displayFrame1) && not (isYuvLayer1 && isYuvLayer0)) { - if (isYuvLayer0) { - if (not layer1_transform) { - ALOGD_IF(DEBUG_COPYBIT,"%s:Smart Bilt Possible",__FUNCTION__); - return true; - } - } else if (not layer0_transform) { - ALOGD_IF(DEBUG_COPYBIT,"%s:Smart Bilt Possible",__FUNCTION__); - return true; - } - } - } - return false; -} - -bool CopyBit::canUseCopybitForRGB(hwc_context_t *ctx, - hwc_display_contents_1_t *list, - int dpy) { - int compositionType = qdutils::QCCompositionType:: - getInstance().getCompositionType(); - - if (compositionType & qdutils::COMPOSITION_TYPE_DYN) { - // DYN Composition: - // use copybit, if (TotalRGBRenderArea < threashold * FB Area) - // this is done based on perf inputs in ICS - // TODO: Above condition needs to be re-evaluated in JB - int fbWidth = ctx->dpyAttr[dpy].xres; - int fbHeight = ctx->dpyAttr[dpy].yres; - unsigned int fbArea = (fbWidth * fbHeight); - unsigned int renderArea = getRGBRenderingArea(ctx, list); - ALOGD_IF (DEBUG_COPYBIT, "%s:renderArea %u, fbArea %u", - __FUNCTION__, renderArea, fbArea); - double dynThreshold = mDynThreshold; - if(not isSmartBlitPossible(list)) - dynThreshold -= 1; - - if (renderArea < (dynThreshold * fbArea)) { - return true; - } - } else if ((compositionType & qdutils::COMPOSITION_TYPE_MDP)) { - // MDP composition, use COPYBIT always - return true; - } else if ((compositionType & qdutils::COMPOSITION_TYPE_C2D)) { - // C2D composition, use COPYBIT - return true; - } - return false; -} - -unsigned int CopyBit::getRGBRenderingArea (const hwc_context_t *ctx, - const hwc_display_contents_1_t *list) { - //Calculates total rendering area for RGB layers - unsigned int renderArea = 0; - unsigned int w=0, h=0; - // Skipping last layer since FrameBuffer layer should not affect - // which composition to choose - for (unsigned int i=0; i<list->numHwLayers -1; i++) { - private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle; - if (hnd) { - if (BUFFER_TYPE_UI == hnd->bufferType && !ctx->copybitDrop[i]) { - getLayerResolution(&list->hwLayers[i], w, h); - renderArea += (w*h); - } - } - } - return renderArea; -} - -bool CopyBit::isLayerChanging(hwc_context_t *ctx, - hwc_display_contents_1_t *list, int k) { - if((mLayerCache.hnd[k] != list->hwLayers[k].handle) || - (mLayerCache.drop[k] != ctx->copybitDrop[k]) || - (mLayerCache.displayFrame[k].left != - list->hwLayers[k].displayFrame.left) || - (mLayerCache.displayFrame[k].top != - list->hwLayers[k].displayFrame.top) || - (mLayerCache.displayFrame[k].right != - list->hwLayers[k].displayFrame.right) || - (mLayerCache.displayFrame[k].bottom != - list->hwLayers[k].displayFrame.bottom)) { - return 1; - } - return 0; -} - -bool CopyBit::prepareSwapRect(hwc_context_t *ctx, - hwc_display_contents_1_t *list, - int dpy) { - bool canUseSwapRect = 0; - hwc_rect_t dirtyRect = {0, 0, 0, 0}; - hwc_rect_t displayRect = {0, 0, 0, 0}; - hwc_rect fullFrame = (struct hwc_rect) {0, 0,(int)ctx->dpyAttr[dpy].xres, - (int)ctx->dpyAttr[dpy].yres}; - if((mLayerCache.layerCount != ctx->listStats[dpy].numAppLayers) || - list->flags & HWC_GEOMETRY_CHANGED || not mSwapRectEnable) { - mLayerCache.reset(); - mFbCache.reset(); - mLayerCache.updateCounts(ctx,list,dpy); - mDirtyRect = displayRect; - return 0; - } - - int updatingLayerCount = 0; - for (int k = ctx->listStats[dpy].numAppLayers-1; k >= 0 ; k--){ - //swap rect will kick in only for single updating layer - if(isLayerChanging(ctx, list, k)) { - updatingLayerCount ++; - hwc_layer_1_t layer = list->hwLayers[k]; - canUseSwapRect = 1; -#ifdef QTI_BSP - dirtyRect = getUnion(dirtyRect, calculateDirtyRect(&layer,fullFrame)); -#else - (void)fullFrame; -#endif - displayRect = getUnion(displayRect, layer.displayFrame); - } - } - //since we are using more than one framebuffers,we have to - //kick in swap rect only if we are getting continuous same - //dirty rect for same layer at least equal of number of - //framebuffers - - if (canUseSwapRect || updatingLayerCount == 0) { - if (updatingLayerCount == 0) { - dirtyRect.left = INVALID_DIMENSION; - dirtyRect.top = INVALID_DIMENSION; - dirtyRect.right = INVALID_DIMENSION; - dirtyRect.bottom = INVALID_DIMENSION; - canUseSwapRect = 1; - } - - for (int k = ctx->listStats[dpy].numAppLayers-1; k >= 0 ; k--) { - //disable swap rect in case of scaling and video . - private_handle_t *hnd =(private_handle_t *)list->hwLayers[k].handle; - if(needsScaling(&list->hwLayers[k])||( hnd && isYuvBuffer(hnd)) || - (list->hwLayers[k].transform & HAL_TRANSFORM_ROT_90)) { - mFbCache.reset(); - displayRect.bottom = 0; - displayRect.top = 0; - displayRect.right = 0; - displayRect.bottom = 0; - mDirtyRect = displayRect; - return 0; - } - } - - if(mFbCache.getUnchangedFbDRCount(dirtyRect, displayRect) < - NUM_RENDER_BUFFERS) { - mFbCache.insertAndUpdateFbCache(dirtyRect, displayRect); - canUseSwapRect = 0; - displayRect.bottom = 0; - displayRect.top = 0; - displayRect.right = 0; - displayRect.bottom = 0; - } - } else { - mFbCache.reset(); - canUseSwapRect = 0; - displayRect.bottom = 0; - displayRect.top = 0; - displayRect.right = 0; - displayRect.bottom = 0; - - } - mDirtyRect = displayRect; - mLayerCache.updateCounts(ctx,list,dpy); - return canUseSwapRect; -} - -bool CopyBit::prepareOverlap(hwc_context_t *ctx, - hwc_display_contents_1_t *list) { - - if (ctx->mMDP.version < qdutils::MDP_V4_0) { - ALOGE("%s: Invalid request", __FUNCTION__); - return false; - } - - if (mEngine == NULL || !(validateParams(ctx, list))) { - ALOGE("%s: Invalid Params", __FUNCTION__); - return false; - } - PtorInfo* ptorInfo = &(ctx->mPtorInfo); - - // Allocate render buffers if they're not allocated - int alignW = 0, alignH = 0; - int finalW = 0, finalH = 0; - for (int i = 0; i < ptorInfo->count; i++) { - int ovlapIndex = ptorInfo->layerIndex[i]; - hwc_rect_t overlap = list->hwLayers[ovlapIndex].displayFrame; - // render buffer width will be the max of two layers - // Align Widht and height to 32, Mdp would be configured - // with Aligned overlap w/h - finalW = max(finalW, ALIGN((overlap.right - overlap.left), 32)); - finalH += ALIGN((overlap.bottom - overlap.top), 32); - if(finalH > ALIGN((overlap.bottom - overlap.top), 32)) { - // Calculate the dest top, left will always be zero - ptorInfo->displayFrame[i].top = (finalH - - (ALIGN((overlap.bottom - overlap.top), 32))); - } - // calculate the right and bottom values - ptorInfo->displayFrame[i].right = ptorInfo->displayFrame[i].left + - (overlap.right - overlap.left); - ptorInfo->displayFrame[i].bottom = ptorInfo->displayFrame[i].top + - (overlap.bottom - overlap.top); - } - - getBufferSizeAndDimensions(finalW, finalH, HAL_PIXEL_FORMAT_RGBA_8888, - alignW, alignH); - - if ((mAlignedWidth != alignW) || (mAlignedHeight != alignH)) { - // Overlap rect has changed, so free render buffers - freeRenderBuffers(); - } - - int ret = allocRenderBuffers(alignW, alignH, HAL_PIXEL_FORMAT_RGBA_8888); - - if (ret < 0) { - ALOGE("%s: Render buffer allocation failed", __FUNCTION__); - return false; - } - - mAlignedWidth = alignW; - mAlignedHeight = alignH; - mCurRenderBufferIndex = (mCurRenderBufferIndex + 1) % NUM_RENDER_BUFFERS; - return true; -} - -bool CopyBit::prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list, - int dpy) { - - if(mEngine == NULL) { - // No copybit device found - cannot use copybit - return false; - } - - if(ctx->mThermalBurstMode) { - ALOGD_IF (DEBUG_COPYBIT, "%s:Copybit failed," - "Running in Thermal Burst mode",__FUNCTION__); - return false; - } - - int compositionType = qdutils::QCCompositionType:: - getInstance().getCompositionType(); - - if ((compositionType == qdutils::COMPOSITION_TYPE_GPU) || - (compositionType == qdutils::COMPOSITION_TYPE_CPU)) { - //GPU/CPU composition, don't change layer composition type - return true; - } - - if(!(validateParams(ctx, list))) { - ALOGE("%s:Invalid Params", __FUNCTION__); - return false; - } - - if(ctx->listStats[dpy].skipCount) { - //GPU will be anyways used - return false; - } - - if (ctx->listStats[dpy].numAppLayers > MAX_NUM_APP_LAYERS) { - // Reached max layers supported by HWC. - return false; - } - - int last = (uint32_t)list->numHwLayers - 1; - mDirtyRect = list->hwLayers[last].displayFrame; - mSwapRect = prepareSwapRect(ctx, list, dpy); - ALOGD_IF (DEBUG_COPYBIT, "%s: mSwapRect: %d mDirtyRect: [%d, %d, %d, %d]", - __FUNCTION__, mSwapRect, mDirtyRect.left, - mDirtyRect.top, mDirtyRect.right, mDirtyRect.bottom); - - bool useCopybitForYUV = canUseCopybitForYUV(ctx); - bool useCopybitForRGB = canUseCopybitForRGB(ctx, list, dpy); - LayerProp *layerProp = ctx->layerProp[dpy]; - - // Following are MDP3 limitations for which we - // need to fallback to GPU composition: - // 1. Plane alpha is not supported by MDP3. - // 2. Scaling is within range - if (qdutils::MDPVersion::getInstance().getMDPVersion() < 400) { - for (int i = ctx->listStats[dpy].numAppLayers-1; i >= 0 ; i--) { - int dst_h, dst_w, src_h, src_w; - float dx, dy; - if(ctx->copybitDrop[i]) { - continue; - } - hwc_layer_1_t *layer = (hwc_layer_1_t *) &list->hwLayers[i]; - if (layer->planeAlpha != 0xFF) - return true; - - if (layer->transform) { - ALOGD_IF (DEBUG_COPYBIT, "%s: Do GPU comp Transform : %d", - __FUNCTION__, layer->transform); - return true; - } - hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf); - - if (has90Transform(layer)) { - src_h = sourceCrop.right - sourceCrop.left; - src_w = sourceCrop.bottom - sourceCrop.top; - } else { - src_h = sourceCrop.bottom - sourceCrop.top; - src_w = sourceCrop.right - sourceCrop.left; - } - dst_h = layer->displayFrame.bottom - layer->displayFrame.top; - dst_w = layer->displayFrame.right - layer->displayFrame.left; - - if(src_w <=0 || src_h<=0 ||dst_w<=0 || dst_h<=0 ) { - ALOGE("%s: wrong params for display screen_w=%d \ - src_crop_width=%d screen_h=%d src_crop_height=%d", - __FUNCTION__, dst_w,src_w,dst_h,src_h); - return false; - } - dx = (float)dst_w/(float)src_w; - dy = (float)dst_h/(float)src_h; - - float scale_factor_max = MAX_SCALE_FACTOR; - float scale_factor_min = MIN_SCALE_FACTOR; - - if (isAlphaPresent(layer)) { - scale_factor_max = MAX_SCALE_FACTOR/4; - scale_factor_min = MIN_SCALE_FACTOR*4; - } - - if (dx > scale_factor_max || dx < scale_factor_min) - return false; - - if (dy > scale_factor_max || dy < scale_factor_min) - return false; - } - } - - //Allocate render buffers if they're not allocated - if ((ctx->mMDP.version != qdutils::MDP_V3_0_4 && -#ifdef SUPPORT_BLIT_TO_FB - ctx->mMDP.version == qdutils::MDP_V3_0_5 -#else - ctx->mMDP.version != qdutils::MDP_V3_0_5 -#endif - ) && (useCopybitForYUV || useCopybitForRGB)) { - int ret = allocRenderBuffers(mAlignedWidth, - mAlignedHeight, - HAL_PIXEL_FORMAT_RGBA_8888); - if (ret < 0) { - return false; - } else { - mCurRenderBufferIndex = (mCurRenderBufferIndex + 1) % - NUM_RENDER_BUFFERS; - } - } - - // We cannot mix copybit layer with layers marked to be drawn on FB - if (!useCopybitForYUV && ctx->listStats[dpy].yuvCount) - return true; - - mCopyBitDraw = false; - if (useCopybitForRGB && - (useCopybitForYUV || !ctx->listStats[dpy].yuvCount)) { - mCopyBitDraw = true; - // numAppLayers-1, as we iterate till 0th layer index - // Mark all layers to be drawn by copybit - for (int i = ctx->listStats[dpy].numAppLayers-1; i >= 0 ; i--) { - layerProp[i].mFlags |= HWC_COPYBIT; -#ifdef QTI_BSP - if (ctx->mMDP.version == qdutils::MDP_V3_0_4 || - ctx->mMDP.version == qdutils::MDP_V3_0_5) - list->hwLayers[i].compositionType = HWC_BLIT; - else -#endif - list->hwLayers[i].compositionType = HWC_OVERLAY; - } - } - - return true; -} - -int CopyBit::clear (private_handle_t* hnd, hwc_rect_t& rect) -{ - int ret = 0; - copybit_rect_t clear_rect = {rect.left, rect.top, - rect.right, - rect.bottom}; - - copybit_image_t buf; - buf.w = ALIGN(getWidth(hnd),32); - buf.h = getHeight(hnd); - buf.format = hnd->format; - buf.base = (void *)hnd->base; - buf.handle = (native_handle_t *)hnd; - - copybit_device_t *copybit = mEngine; - ret = copybit->clear(copybit, &buf, &clear_rect); - return ret; -} - -bool CopyBit::drawUsingAppBufferComposition(hwc_context_t *ctx, - hwc_display_contents_1_t *list, - int dpy, int *copybitFd) { - int layerCount = 0; - uint32_t last = (uint32_t)list->numHwLayers - 1; - hwc_layer_1_t *fbLayer = &list->hwLayers[last]; - private_handle_t *fbhnd = (private_handle_t *)fbLayer->handle; - - if(ctx->enableABC == false) - return false; - - if(ctx->listStats[dpy].numAppLayers > MAX_LAYERS_FOR_ABC ) - return false; - - layerCount = ctx->listStats[dpy].numAppLayers; - //bottom most layer should - //equal to FB - hwc_layer_1_t *tmpLayer = &list->hwLayers[0]; - private_handle_t *hnd = (private_handle_t *)tmpLayer->handle; - if(hnd && fbhnd && (hnd->size == fbhnd->size) && - (hnd->width == fbhnd->width) && (hnd->height == fbhnd->height)){ - if(tmpLayer->transform || - (list->flags & HWC_GEOMETRY_CHANGED) || - (!(hnd->format == HAL_PIXEL_FORMAT_RGBA_8888 || - hnd->format == HAL_PIXEL_FORMAT_RGBX_8888)) || - (needsScaling(tmpLayer) == true)) { - return false; - }else { - ctx->listStats[dpy].renderBufIndexforABC = 0; - } - } - - if(ctx->listStats[dpy].renderBufIndexforABC == 0) { - if(layerCount == 1) - return true; - - if(layerCount == MAX_LAYERS_FOR_ABC) { - int abcRenderBufIdx = ctx->listStats[dpy].renderBufIndexforABC; - //enable ABC only for non intersecting layers. - hwc_rect_t displayFrame = - list->hwLayers[abcRenderBufIdx].displayFrame; - for (int i = abcRenderBufIdx + 1; i < layerCount; i++) { - hwc_rect_t tmpDisplayFrame = list->hwLayers[i].displayFrame; - hwc_rect_t result = getIntersection(displayFrame,tmpDisplayFrame); - if (isValidRect(result)) { - ctx->listStats[dpy].renderBufIndexforABC = -1; - return false; - } - } - // Pass the Acquire Fence FD to driver for base layer - private_handle_t *renderBuffer = - (private_handle_t *)list->hwLayers[abcRenderBufIdx].handle; - copybit_device_t *copybit = getCopyBitDevice(); - if(list->hwLayers[abcRenderBufIdx].acquireFenceFd >=0){ - copybit->set_sync(copybit, - list->hwLayers[abcRenderBufIdx].acquireFenceFd); - } - for(int i = abcRenderBufIdx + 1; i < layerCount; i++){ - mSwapRect = 0; - int retVal = drawLayerUsingCopybit(ctx, - &(list->hwLayers[i]),renderBuffer, 0); - if(retVal < 0) { - ALOGE("%s : Copybit failed", __FUNCTION__); - } - } - // Get Release Fence FD of copybit for the App layer(s) - copybit->flush_get_fence(copybit, copybitFd); - close(list->hwLayers[last].acquireFenceFd); - list->hwLayers[last].acquireFenceFd = -1; - return true; - } - } - return false; -} - -bool CopyBit::draw(hwc_context_t *ctx, hwc_display_contents_1_t *list, - int dpy, int32_t *fd) { - // draw layers marked for COPYBIT - int retVal = true; - int copybitLayerCount = 0; - uint32_t last = 0; - LayerProp *layerProp = ctx->layerProp[dpy]; - private_handle_t *renderBuffer; - - if(mCopyBitDraw == false){ - mFbCache.reset(); // there is no layer marked for copybit - return false ; - } - - if(drawUsingAppBufferComposition(ctx, list, dpy, fd)) { - mFbCache.reset(); - return true; - } - //render buffer - if (ctx->mMDP.version == qdutils::MDP_V3_0_4 || -#ifdef SUPPORT_BLIT_TO_FB - ctx->mMDP.version != qdutils::MDP_V3_0_5 -#else - ctx->mMDP.version == qdutils::MDP_V3_0_5 -#endif - ) { - last = (uint32_t)list->numHwLayers - 1; - renderBuffer = (private_handle_t *)list->hwLayers[last].handle; - } else { - renderBuffer = getCurrentRenderBuffer(); - } - if (!renderBuffer) { - ALOGE("%s: Render buffer layer handle is NULL", __FUNCTION__); - return false; - } - - if ((ctx->mMDP.version >= qdutils::MDP_V4_0) -#ifdef SUPPORT_BLIT_TO_FB - || (ctx->mMDP.version == qdutils::MDP_V3_0_5) -#endif - ) { - //Wait for the previous frame to complete before rendering onto it - if(mRelFd[mCurRenderBufferIndex] >=0) { - sync_wait(mRelFd[mCurRenderBufferIndex], 1000); - close(mRelFd[mCurRenderBufferIndex]); - mRelFd[mCurRenderBufferIndex] = -1; - } - } else { - if(list->hwLayers[last].acquireFenceFd >=0) { - copybit_device_t *copybit = getCopyBitDevice(); - copybit->set_sync(copybit, list->hwLayers[last].acquireFenceFd); - } - } - - //if swap rect on and not getting valid dirtyRect - //means calling only commit without any draw. Hence avoid - //clear call as well. - if (not mSwapRect || isValidRect(mDirtyRect)) { - if (not CBUtils::uiClearRegion(list, ctx->mMDP.version, layerProp, - mDirtyRect, mEngine, renderBuffer)){ - mSwapRect = 0; - } - } - - // numAppLayers-1, as we iterate from 0th layer index with HWC_COPYBIT flag - for (int i = 0; i <= (ctx->listStats[dpy].numAppLayers-1); i++) { - if(!(layerProp[i].mFlags & HWC_COPYBIT)) { - ALOGD_IF(DEBUG_COPYBIT, "%s: Not Marked for copybit", __FUNCTION__); - continue; - } - if(ctx->copybitDrop[i]) { - continue; - } - int ret = -1; - if (list->hwLayers[i].acquireFenceFd != -1 - && ctx->mMDP.version >= qdutils::MDP_V4_0) { - // Wait for acquire Fence on the App buffers. - ret = sync_wait(list->hwLayers[i].acquireFenceFd, 1000); - if(ret < 0) { - ALOGE("%s: sync_wait error!! error no = %d err str = %s", - __FUNCTION__, errno, strerror(errno)); - } - close(list->hwLayers[i].acquireFenceFd); - list->hwLayers[i].acquireFenceFd = -1; - } - retVal = drawLayerUsingCopybit(ctx, &(list->hwLayers[i]), - renderBuffer, !i); - copybitLayerCount++; - if(retVal < 0) { - ALOGE("%s : drawLayerUsingCopybit failed", __FUNCTION__); - } - } - - if (copybitLayerCount) { - copybit_device_t *copybit = getCopyBitDevice(); - // Async mode - copybit->flush_get_fence(copybit, fd); - if((ctx->mMDP.version == qdutils::MDP_V3_0_4 || -#ifdef SUPPORT_BLIT_TO_FB - ctx->mMDP.version != qdutils::MDP_V3_0_5 -#else - ctx->mMDP.version == qdutils::MDP_V3_0_5 -#endif - ) && list->hwLayers[last].acquireFenceFd >= 0) { - close(list->hwLayers[last].acquireFenceFd); - list->hwLayers[last].acquireFenceFd = -1; - } - } - return true; -} - -int CopyBit::drawOverlap(hwc_context_t *ctx, hwc_display_contents_1_t *list) { - int fd = -1; - PtorInfo* ptorInfo = &(ctx->mPtorInfo); - - if (ctx->mMDP.version < qdutils::MDP_V4_0) { - ALOGE("%s: Invalid request", __FUNCTION__); - return fd; - } - - private_handle_t *renderBuffer = getCurrentRenderBuffer(); - - if (!renderBuffer) { - ALOGE("%s: Render buffer layer handle is NULL", __FUNCTION__); - return fd; - } - - //Clear the transparent or left out region on the render buffer - LayerProp *layerProp = ctx->layerProp[0]; - hwc_rect_t clearRegion = {0, 0, 0, 0}; - CBUtils::uiClearRegion(list, ctx->mMDP.version, layerProp, clearRegion, - mEngine, renderBuffer); - - int copybitLayerCount = 0; - for(int j = 0; j < ptorInfo->count; j++) { - int ovlapIndex = ptorInfo->layerIndex[j]; - hwc_rect_t overlap = list->hwLayers[ovlapIndex].displayFrame; - if(j) { - /** - * It's possible that 2 PTOR layers might have overlapping. - * In such case, remove the intersection(again if peripheral) - * from the lower PTOR layer to avoid overlapping. - * If intersection is not on peripheral then compromise - * by reducing number of PTOR layers. - **/ - int prevOvlapIndex = ptorInfo->layerIndex[0]; - hwc_rect_t prevOvlap = list->hwLayers[prevOvlapIndex].displayFrame; - hwc_rect_t commonRect = getIntersection(prevOvlap, overlap); - if(isValidRect(commonRect)) { - overlap = deductRect(overlap, commonRect); - } - } - - // Draw overlapped content of layers on render buffer - for (int i = 0; i <= ovlapIndex; i++) { - hwc_layer_1_t *layer = &list->hwLayers[i]; - if(!isValidRect(getIntersection(layer->displayFrame, - overlap))) { - continue; - } - if ((list->hwLayers[i].acquireFenceFd != -1)) { - // Wait for acquire fence on the App buffers. - if(sync_wait(list->hwLayers[i].acquireFenceFd, 1000) < 0) { - ALOGE("%s: sync_wait error!! error no = %d err str = %s", - __FUNCTION__, errno, strerror(errno)); - } - close(list->hwLayers[i].acquireFenceFd); - list->hwLayers[i].acquireFenceFd = -1; - } - /* - * Find the intersection of layer display frame with PTOR layer - * with respect to screen co-ordinates - * - * Calculated the destination rect by transforming the overlapping - * region of layer display frame with respect to PTOR display frame - * - * Transform the destination rect on to render buffer - * */ - hwc_rect_t destRect = getIntersection(overlap, layer->displayFrame); - destRect.left = destRect.left - overlap.left + - ptorInfo->displayFrame[j].left; - destRect.right = destRect.right- overlap.left + - ptorInfo->displayFrame[j].left; - destRect.top = destRect.top - overlap.top + - ptorInfo->displayFrame[j].top; - destRect.bottom = destRect.bottom - overlap.top + - ptorInfo->displayFrame[j].top; - - int retVal = drawRectUsingCopybit(ctx, layer, renderBuffer, - overlap, destRect); - copybitLayerCount++; - if(retVal < 0) { - ALOGE("%s: drawRectUsingCopybit failed", __FUNCTION__); - copybitLayerCount = 0; - } - } - } - - if (copybitLayerCount) { - copybit_device_t *copybit = getCopyBitDevice(); - copybit->flush_get_fence(copybit, &fd); - } - - ALOGD_IF(DEBUG_COPYBIT, "%s: done! copybitLayerCount = %d", __FUNCTION__, - copybitLayerCount); - return fd; -} - -int CopyBit::drawRectUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer, - private_handle_t *renderBuffer, hwc_rect_t overlap, - hwc_rect_t destRect) -{ - hwc_context_t* ctx = (hwc_context_t*)(dev); - if (!ctx) { - ALOGE("%s: null context ", __FUNCTION__); - return -1; - } - - private_handle_t *hnd = (private_handle_t *)layer->handle; - if (!hnd) { - ALOGE("%s: invalid handle", __FUNCTION__); - return -1; - } - - private_handle_t *dstHandle = (private_handle_t *)renderBuffer; - if (!dstHandle) { - ALOGE("%s: RenderBuffer handle is NULL", __FUNCTION__); - return -1; - } - - // Set the Copybit Source - copybit_image_t src; - src.handle = (native_handle_t *)layer->handle; - src.w = hnd->width; - src.h = hnd->height; - src.base = (void *)hnd->base; - src.format = hnd->format; - src.horiz_padding = 0; - src.vert_padding = 0; - - - hwc_rect_t dispFrame = layer->displayFrame; - hwc_rect_t iRect = getIntersection(dispFrame, overlap); - hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf); - qhwc::calculate_crop_rects(crop, dispFrame, iRect, - layer->transform); - - // Copybit source rect - copybit_rect_t srcRect = {crop.left, crop.top, crop.right, - crop.bottom}; - - // Copybit destination rect - copybit_rect_t dstRect = {destRect.left, destRect.top, destRect.right, - destRect.bottom}; - - // Copybit dst - copybit_image_t dst; - dst.handle = (native_handle_t *)dstHandle; - dst.w = ALIGN(dstHandle->width, 32); - dst.h = dstHandle->height; - dst.base = (void *)dstHandle->base; - dst.format = dstHandle->format; - - copybit_device_t *copybit = mEngine; - - // Copybit region is the destRect - hwc_rect_t regRect = {dstRect.l,dstRect.t, dstRect.r, dstRect.b}; - hwc_region_t region; - region.numRects = 1; - region.rects = ®Rect; - region_iterator copybitRegion(region); - int acquireFd = layer->acquireFenceFd; - - copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_WIDTH, - renderBuffer->width); - copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_HEIGHT, - renderBuffer->height); - copybit->set_parameter(copybit, COPYBIT_TRANSFORM, layer->transform); - copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, layer->planeAlpha); - copybit->set_parameter(copybit, COPYBIT_BLEND_MODE, layer->blending); - copybit->set_parameter(copybit, COPYBIT_DITHER, - (dst.format == HAL_PIXEL_FORMAT_RGB_565) ? COPYBIT_ENABLE : - COPYBIT_DISABLE); - copybit->set_sync(copybit, acquireFd); - int err = copybit->stretch(copybit, &dst, &src, &dstRect, &srcRect, - ©bitRegion); - - if (err < 0) - ALOGE("%s: copybit stretch failed",__FUNCTION__); - - return err; -} - -int CopyBit::drawLayerUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer, - private_handle_t *renderBuffer, bool isFG) -{ - hwc_context_t* ctx = (hwc_context_t*)(dev); - int err = 0, acquireFd; - if(!ctx) { - ALOGE("%s: null context ", __FUNCTION__); - return -1; - } - - private_handle_t *hnd = (private_handle_t *)layer->handle; - if(!hnd) { - if (layer->flags & HWC_COLOR_FILL) { // Color layer - return fillColorUsingCopybit(layer, renderBuffer); - } - ALOGE("%s: invalid handle", __FUNCTION__); - return -1; - } - - private_handle_t *fbHandle = (private_handle_t *)renderBuffer; - if(!fbHandle) { - ALOGE("%s: Framebuffer handle is NULL", __FUNCTION__); - return -1; - } - uint32_t dynamic_fps = 0; -#ifdef DYNAMIC_FPS - MetaData_t *mdata = hnd ? (MetaData_t *)hnd->base_metadata : NULL; - if (mdata && (mdata->operation & UPDATE_REFRESH_RATE)) { - dynamic_fps = roundOff(mdata->refreshrate); - } -#endif - // Set the copybit source: - copybit_image_t src; - src.w = getWidth(hnd); - src.h = getHeight(hnd); - src.format = hnd->format; - - // Handle R/B swap - if ((layer->flags & HWC_FORMAT_RB_SWAP)) { - if (src.format == HAL_PIXEL_FORMAT_RGBA_8888) { - src.format = HAL_PIXEL_FORMAT_BGRA_8888; - } else if (src.format == HAL_PIXEL_FORMAT_RGBX_8888) { - src.format = HAL_PIXEL_FORMAT_BGRX_8888; - } - } - - src.base = (void *)hnd->base; - src.handle = (native_handle_t *)layer->handle; - src.horiz_padding = src.w - getWidth(hnd); - // Initialize vertical padding to zero for now, - // this needs to change to accomodate vertical stride - // if needed in the future - src.vert_padding = 0; - - int layerTransform = layer->transform ; - // When flip and rotation(90) are present alter the flip, - // as GPU is doing the flip and rotation in opposite order - // to that of MDP3.0 - // For 270 degrees, we get 90 + (H+V) which is same as doing - // flip first and then rotation (H+V) + 90 - if (qdutils::MDPVersion::getInstance().getMDPVersion() < 400) { - if (((layer->transform& HAL_TRANSFORM_FLIP_H) || - (layer->transform & HAL_TRANSFORM_FLIP_V)) && - (layer->transform & HAL_TRANSFORM_ROT_90) && - !(layer->transform == HAL_TRANSFORM_ROT_270)){ - if(layer->transform & HAL_TRANSFORM_FLIP_H){ - layerTransform ^= HAL_TRANSFORM_FLIP_H; - layerTransform |= HAL_TRANSFORM_FLIP_V; - } - if(layer->transform & HAL_TRANSFORM_FLIP_V){ - layerTransform ^= HAL_TRANSFORM_FLIP_V; - layerTransform |= HAL_TRANSFORM_FLIP_H; - } - } - } - // Copybit source rect - hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf); - copybit_rect_t srcRect = {sourceCrop.left, sourceCrop.top, - sourceCrop.right, - sourceCrop.bottom}; - - // Copybit destination rect - hwc_rect_t displayFrame = layer->displayFrame; - copybit_rect_t dstRect = {displayFrame.left, displayFrame.top, - displayFrame.right, - displayFrame.bottom}; -#ifdef QTI_BSP - //change src and dst with dirtyRect - if(mSwapRect) { - hwc_rect_t result = getIntersection(displayFrame, mDirtyRect); - if(!isValidRect(result)) - return true; - dstRect.l = result.left; - dstRect.t = result.top; - dstRect.r = result.right; - dstRect.b = result.bottom; - - srcRect.l += (result.left - displayFrame.left); - srcRect.t += (result.top - displayFrame.top); - srcRect.r -= (displayFrame.right - result.right); - srcRect.b -= (displayFrame.bottom - result.bottom); - } -#endif - // Copybit dst - copybit_image_t dst; - dst.w = ALIGN(fbHandle->width,32); - dst.h = fbHandle->height; - dst.format = fbHandle->format; - dst.base = (void *)fbHandle->base; - dst.handle = (native_handle_t *)fbHandle; - - copybit_device_t *copybit = mEngine; - - int32_t screen_w = displayFrame.right - displayFrame.left; - int32_t screen_h = displayFrame.bottom - displayFrame.top; - int32_t src_crop_width = sourceCrop.right - sourceCrop.left; - int32_t src_crop_height = sourceCrop.bottom -sourceCrop.top; - - // Copybit dst - float copybitsMaxScale = - (float)copybit->get(copybit,COPYBIT_MAGNIFICATION_LIMIT); - float copybitsMinScale = - (float)copybit->get(copybit,COPYBIT_MINIFICATION_LIMIT); - - if (layer->transform & HWC_TRANSFORM_ROT_90) { - //swap screen width and height - int tmp = screen_w; - screen_w = screen_h; - screen_h = tmp; - } - private_handle_t *tmpHnd = NULL; - - if(screen_w <=0 || screen_h<=0 ||src_crop_width<=0 || src_crop_height<=0 ) { - ALOGE("%s: wrong params for display screen_w=%d src_crop_width=%d \ - screen_h=%d src_crop_height=%d", __FUNCTION__, screen_w, - src_crop_width,screen_h,src_crop_height); - return -1; - } - - float dsdx = (float)screen_w/(float)src_crop_width; - float dtdy = (float)screen_h/(float)src_crop_height; - - float scaleLimitMax = copybitsMaxScale * copybitsMaxScale; - float scaleLimitMin = copybitsMinScale * copybitsMinScale; - if(dsdx > scaleLimitMax || - dtdy > scaleLimitMax || - dsdx < 1/scaleLimitMin || - dtdy < 1/scaleLimitMin) { - ALOGW("%s: greater than max supported size dsdx=%f dtdy=%f \ - scaleLimitMax=%f scaleLimitMin=%f", __FUNCTION__,dsdx,dtdy, - scaleLimitMax,1/scaleLimitMin); - return -1; - } - acquireFd = layer->acquireFenceFd; - if(dsdx > copybitsMaxScale || - dtdy > copybitsMaxScale || - dsdx < 1/copybitsMinScale || - dtdy < 1/copybitsMinScale){ - // The requested scale is out of the range the hardware - // can support. - ALOGD("%s:%d::Need to scale twice dsdx=%f, dtdy=%f,copybitsMaxScale=%f,\ - copybitsMinScale=%f,screen_w=%d,screen_h=%d \ - src_crop_width=%d src_crop_height=%d",__FUNCTION__,__LINE__, - dsdx,dtdy,copybitsMaxScale,1/copybitsMinScale,screen_w,screen_h, - src_crop_width,src_crop_height); - - - int tmp_w = src_crop_width; - int tmp_h = src_crop_height; - - if (dsdx > copybitsMaxScale) - tmp_w = (int)((float)src_crop_width*copybitsMaxScale); - if (dtdy > copybitsMaxScale) - tmp_h = (int)((float)src_crop_height*copybitsMaxScale); - // ceil the tmp_w and tmp_h value to maintain proper ratio - // b/w src and dst (should not cross the desired scale limit - // due to float -> int ) - if (dsdx < 1/copybitsMinScale) - tmp_w = (int)ceil((float)src_crop_width/copybitsMinScale); - if (dtdy < 1/copybitsMinScale) - tmp_h = (int)ceil((float)src_crop_height/copybitsMinScale); - - ALOGD("%s:%d::tmp_w = %d,tmp_h = %d",__FUNCTION__,__LINE__,tmp_w,tmp_h); - - int usage = GRALLOC_USAGE_PRIVATE_IOMMU_HEAP; - int format = fbHandle->format; - - // We do not want copybit to generate alpha values from nothing - if (format == HAL_PIXEL_FORMAT_RGBA_8888 && - src.format != HAL_PIXEL_FORMAT_RGBA_8888) { - format = HAL_PIXEL_FORMAT_RGBX_8888; - } - if (0 == alloc_buffer(&tmpHnd, tmp_w, tmp_h, format, usage) && tmpHnd) { - copybit_image_t tmp_dst; - copybit_rect_t tmp_rect; - tmp_dst.w = tmp_w; - tmp_dst.h = tmp_h; - tmp_dst.format = tmpHnd->format; - tmp_dst.handle = tmpHnd; - tmp_dst.horiz_padding = src.horiz_padding; - tmp_dst.vert_padding = src.vert_padding; - tmp_rect.l = 0; - tmp_rect.t = 0; - tmp_rect.r = tmp_dst.w; - tmp_rect.b = tmp_dst.h; - //create one clip region - hwc_rect tmp_hwc_rect = {0,0,tmp_rect.r,tmp_rect.b}; - hwc_region_t tmp_hwc_reg = {1,(hwc_rect_t const*)&tmp_hwc_rect}; - region_iterator tmp_it(tmp_hwc_reg); - copybit->set_parameter(copybit,COPYBIT_TRANSFORM,0); - //TODO: once, we are able to read layer alpha, update this - copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255); - copybit->set_sync(copybit, acquireFd); - err = copybit->stretch(copybit,&tmp_dst, &src, &tmp_rect, - &srcRect, &tmp_it); - if(err < 0){ - ALOGE("%s:%d::tmp copybit stretch failed",__FUNCTION__, - __LINE__); - if(tmpHnd) - free_buffer(tmpHnd); - return err; - } - // use release fence as aquire fd for next stretch - if (ctx->mMDP.version < qdutils::MDP_V4_0) { - copybit->flush_get_fence(copybit, &acquireFd); - close(acquireFd); - acquireFd = -1; - } - // copy new src and src rect crop - src = tmp_dst; - srcRect = tmp_rect; - } - } - // Copybit region - hwc_region_t region = layer->visibleRegionScreen; - //Do not use visible regions in case of scaling - if (region.numRects > 1) { - if (needsScaling(layer)) { - region.numRects = 1; - region.rects = &layer->displayFrame; - } - } - - region_iterator copybitRegion(region); - - copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_WIDTH, - renderBuffer->width); - copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_HEIGHT, - renderBuffer->height); - copybit->set_parameter(copybit, COPYBIT_TRANSFORM, - layerTransform); - //TODO: once, we are able to read layer alpha, update this - copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255); - copybit->set_parameter(copybit, COPYBIT_DYNAMIC_FPS, dynamic_fps); - copybit->set_parameter(copybit, COPYBIT_BLEND_MODE, - layer->blending); - copybit->set_parameter(copybit, COPYBIT_DITHER, - (dst.format == HAL_PIXEL_FORMAT_RGB_565)? - COPYBIT_ENABLE : COPYBIT_DISABLE); - copybit->set_parameter(copybit, COPYBIT_FG_LAYER, - (layer->blending == HWC_BLENDING_NONE || isFG ) ? - COPYBIT_ENABLE : COPYBIT_DISABLE); - - copybit->set_parameter(copybit, COPYBIT_BLIT_TO_FRAMEBUFFER, - COPYBIT_ENABLE); - copybit->set_sync(copybit, acquireFd); - err = copybit->stretch(copybit, &dst, &src, &dstRect, &srcRect, - ©bitRegion); - copybit->set_parameter(copybit, COPYBIT_BLIT_TO_FRAMEBUFFER, - COPYBIT_DISABLE); - - if(tmpHnd) { - if (ctx->mMDP.version < qdutils::MDP_V4_0){ - int ret = -1, releaseFd; - // we need to wait for the buffer before freeing - copybit->flush_get_fence(copybit, &releaseFd); - ret = sync_wait(releaseFd, 1000); - if(ret < 0) { - ALOGE("%s: sync_wait error!! error no = %d err str = %s", - __FUNCTION__, errno, strerror(errno)); - } - close(releaseFd); - } - free_buffer(tmpHnd); - } - - if(err < 0) - ALOGE("%s: copybit stretch failed",__FUNCTION__); - return err; -} - -int CopyBit::fillColorUsingCopybit(hwc_layer_1_t *layer, - private_handle_t *renderBuffer) -{ - if (!renderBuffer) { - ALOGE("%s: Render Buffer is NULL", __FUNCTION__); - return -1; - } - - // Copybit dst - copybit_image_t dst; - dst.w = ALIGN(renderBuffer->width, 32); - dst.h = renderBuffer->height; - dst.format = renderBuffer->format; - dst.base = (void *)renderBuffer->base; - dst.handle = (native_handle_t *)renderBuffer; - - // Copybit dst rect - hwc_rect_t displayFrame = layer->displayFrame; - copybit_rect_t dstRect = {displayFrame.left, displayFrame.top, - displayFrame.right, displayFrame.bottom}; - - uint32_t color = layer->transform; - copybit_device_t *copybit = mEngine; - copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_WIDTH, - renderBuffer->width); - copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_HEIGHT, - renderBuffer->height); - copybit->set_parameter(copybit, COPYBIT_DITHER, - (dst.format == HAL_PIXEL_FORMAT_RGB_565) ? - COPYBIT_ENABLE : COPYBIT_DISABLE); - copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0); - copybit->set_parameter(copybit, COPYBIT_BLEND_MODE, layer->blending); - copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, layer->planeAlpha); - copybit->set_parameter(copybit, COPYBIT_BLIT_TO_FRAMEBUFFER,COPYBIT_ENABLE); - int res = copybit->fill_color(copybit, &dst, &dstRect, color); - copybit->set_parameter(copybit,COPYBIT_BLIT_TO_FRAMEBUFFER,COPYBIT_DISABLE); - return res; -} - -void CopyBit::getLayerResolution(const hwc_layer_1_t* layer, - unsigned int& width, unsigned int& height) -{ - hwc_rect_t result = layer->displayFrame; - if (mSwapRect) - result = getIntersection(mDirtyRect, result); - - width = result.right - result.left; - height = result.bottom - result.top; -} - -bool CopyBit::validateParams(hwc_context_t *ctx, - const hwc_display_contents_1_t *list) { - //Validate parameters - if (!ctx) { - ALOGE("%s:Invalid HWC context", __FUNCTION__); - return false; - } else if (!list) { - ALOGE("%s:Invalid HWC layer list", __FUNCTION__); - return false; - } - return true; -} - - -int CopyBit::allocRenderBuffers(int w, int h, int f) -{ - int ret = 0; - for (int i = 0; i < NUM_RENDER_BUFFERS; i++) { - if (mRenderBuffer[i] == NULL) { - ret = alloc_buffer(&mRenderBuffer[i], - w, h, f, - GRALLOC_USAGE_PRIVATE_IOMMU_HEAP); - } - if(ret < 0) { - freeRenderBuffers(); - break; - } - } - return ret; -} - -void CopyBit::freeRenderBuffers() -{ - for (int i = 0; i < NUM_RENDER_BUFFERS; i++) { - if(mRenderBuffer[i]) { - //Since we are freeing buffer close the fence if it has a valid one. - if(mRelFd[i] >= 0) { - close(mRelFd[i]); - mRelFd[i] = -1; - } - free_buffer(mRenderBuffer[i]); - mRenderBuffer[i] = NULL; - } - } -} - -private_handle_t * CopyBit::getCurrentRenderBuffer() { - return mRenderBuffer[mCurRenderBufferIndex]; -} - -void CopyBit::setReleaseFd(int fd) { - if(mRelFd[mCurRenderBufferIndex] >=0) - close(mRelFd[mCurRenderBufferIndex]); - mRelFd[mCurRenderBufferIndex] = dup(fd); -} - -void CopyBit::setReleaseFdSync(int fd) { - if (mRelFd[mCurRenderBufferIndex] >=0) { - int ret = -1; - ret = sync_wait(mRelFd[mCurRenderBufferIndex], 1000); - if (ret < 0) - ALOGE("%s: sync_wait error! errno = %d, err str = %s", - __FUNCTION__, errno, strerror(errno)); - close(mRelFd[mCurRenderBufferIndex]); - } - mRelFd[mCurRenderBufferIndex] = dup(fd); -} - -struct copybit_device_t* CopyBit::getCopyBitDevice() { - return mEngine; -} - -CopyBit::CopyBit(hwc_context_t *ctx, const int& dpy) : mEngine(0), - mIsModeOn(false), mCopyBitDraw(false), mCurRenderBufferIndex(0) { - - getBufferSizeAndDimensions(ctx->dpyAttr[dpy].xres, - ctx->dpyAttr[dpy].yres, - HAL_PIXEL_FORMAT_RGBA_8888, - mAlignedWidth, - mAlignedHeight); - - hw_module_t const *module; - for (int i = 0; i < NUM_RENDER_BUFFERS; i++) { - mRenderBuffer[i] = NULL; - mRelFd[i] = -1; - } - - char value[PROPERTY_VALUE_MAX]; - property_get("debug.hwc.dynThreshold", value, "2"); - mDynThreshold = atof(value); - - property_get("debug.sf.swaprect", value, "0"); - mSwapRectEnable = atoi(value) ? true:false ; - mSwapRect = 0; - if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) { - if(copybit_open(module, &mEngine) < 0) { - ALOGE("FATAL ERROR: copybit open failed."); - } - } else { - ALOGE("FATAL ERROR: copybit hw module not found"); - } -} - -CopyBit::~CopyBit() -{ - freeRenderBuffers(); - if(mEngine) - { - copybit_close(mEngine); - mEngine = NULL; - } -} -CopyBit::LayerCache::LayerCache() { - reset(); -} -void CopyBit::LayerCache::reset() { - memset(&hnd, 0, sizeof(hnd)); - layerCount = 0; -} -void CopyBit::LayerCache::updateCounts(hwc_context_t *ctx, - hwc_display_contents_1_t *list, int dpy) -{ - layerCount = ctx->listStats[dpy].numAppLayers; - for (int i=0; i<ctx->listStats[dpy].numAppLayers; i++){ - hnd[i] = list->hwLayers[i].handle; - displayFrame[i] = list->hwLayers[i].displayFrame; - drop[i] = ctx->copybitDrop[i]; - } -} - -CopyBit::FbCache::FbCache() { - reset(); -} -void CopyBit::FbCache::reset() { - memset(&FbdirtyRect, 0, sizeof(FbdirtyRect)); - memset(&FbdisplayRect, 0, sizeof(FbdisplayRect)); - FbIndex =0; -} - -void CopyBit::FbCache::insertAndUpdateFbCache(hwc_rect_t dirtyRect, - hwc_rect_t displayRect) { - FbIndex = FbIndex % NUM_RENDER_BUFFERS; - FbdirtyRect[FbIndex] = dirtyRect; - FbdisplayRect[FbIndex] = displayRect; - FbIndex++; -} - -int CopyBit::FbCache::getUnchangedFbDRCount(hwc_rect_t dirtyRect, - hwc_rect_t displayRect){ - int sameDirtyCount = 0; - for (int i = 0 ; i < NUM_RENDER_BUFFERS ; i++ ){ - if( FbdirtyRect[i] == dirtyRect && - FbdisplayRect[i] == displayRect) - sameDirtyCount++; - } - return sameDirtyCount; -} - -}; //namespace qhwc diff --git a/msm8909/libhwcomposer/hwc_copybit.h b/msm8909/libhwcomposer/hwc_copybit.h deleted file mode 100644 index c527a4ec..00000000 --- a/msm8909/libhwcomposer/hwc_copybit.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved. - * - * Not a Contribution, Apache license notifications and license are retained - * for attribution purposes only. - * - * 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_COPYBIT_H -#define HWC_COPYBIT_H -#include "hwc_utils.h" - -#define NUM_RENDER_BUFFERS 3 -//These scaling factors are specific for MDP3. Normally scaling factor -//is only 4, but copybit will create temp buffer to let it run through -//twice -#define MAX_SCALE_FACTOR 16 -#define MIN_SCALE_FACTOR 0.0625 -#define MAX_LAYERS_FOR_ABC 2 -#define INVALID_DIMENSION -1 -#define NO_UPDATING_LAYER -2 -namespace qhwc { - -class CopyBit { -public: - CopyBit(hwc_context_t *ctx, const int& dpy); - ~CopyBit(); - // API to get copybit engine(non static) - struct copybit_device_t *getCopyBitDevice(); - //Sets up members and prepares copybit if conditions are met - bool prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list, - int dpy); - //Draws layer if the layer is set for copybit in prepare - bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list, - int dpy, int* fd); - // resets the values - void reset(); - - private_handle_t * getCurrentRenderBuffer(); - - void setReleaseFd(int fd); - - void setReleaseFdSync(int fd); - - bool prepareOverlap(hwc_context_t *ctx, hwc_display_contents_1_t *list); - - int drawOverlap(hwc_context_t *ctx, hwc_display_contents_1_t *list); - -private: - /* cached data */ - struct LayerCache { - int layerCount; - buffer_handle_t hnd[MAX_NUM_APP_LAYERS]; - hwc_rect_t displayFrame[MAX_NUM_APP_LAYERS]; - bool drop[MAX_NUM_APP_LAYERS]; - /* c'tor */ - LayerCache(); - /* clear caching info*/ - void reset(); - void updateCounts(hwc_context_t *ctx, hwc_display_contents_1_t *list, - int dpy); - }; - /* framebuffer cache*/ - struct FbCache { - hwc_rect_t FbdirtyRect[NUM_RENDER_BUFFERS]; - hwc_rect_t FbdisplayRect[NUM_RENDER_BUFFERS]; - int FbIndex; - FbCache(); - void reset(); - void insertAndUpdateFbCache(hwc_rect_t dirtyRect, - hwc_rect_t displayRect); - int getUnchangedFbDRCount(hwc_rect_t dirtyRect, - hwc_rect_t displayRect); - }; - - // holds the copybit device - struct copybit_device_t *mEngine; - bool drawUsingAppBufferComposition(hwc_context_t *ctx, - hwc_display_contents_1_t *list, - int dpy, int *fd); - // Helper functions for copybit composition - int drawLayerUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer, - private_handle_t *renderBuffer, bool isFG); - // Helper function to draw copybit layer for PTOR comp - int drawRectUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer, - private_handle_t *renderBuffer, hwc_rect_t overlap, - hwc_rect_t destRect); - int fillColorUsingCopybit(hwc_layer_1_t *layer, - private_handle_t *renderBuffer); - bool canUseCopybitForYUV (hwc_context_t *ctx); - bool canUseCopybitForRGB (hwc_context_t *ctx, - hwc_display_contents_1_t *list, int dpy); - bool validateParams (hwc_context_t *ctx, - const hwc_display_contents_1_t *list); - //Flags if this feature is on. - bool mIsModeOn; - // flag that indicates whether CopyBit composition is enabled for this cycle - bool mCopyBitDraw; - - unsigned int getRGBRenderingArea (const hwc_context_t *ctx, - const hwc_display_contents_1_t *list); - - void getLayerResolution(const hwc_layer_1_t* layer, - unsigned int &width, unsigned int& height); - - int allocRenderBuffers(int w, int h, int f); - - void freeRenderBuffers(); - - int clear (private_handle_t* hnd, hwc_rect_t& rect); - - private_handle_t* mRenderBuffer[NUM_RENDER_BUFFERS]; - - // Index of the current intermediate render buffer - int mCurRenderBufferIndex; - - // Release FDs of the intermediate render buffer - int mRelFd[NUM_RENDER_BUFFERS]; - - //Dynamic composition threshold for deciding copybit usage. - double mDynThreshold; - bool mSwapRectEnable; - int mAlignedWidth; - int mAlignedHeight; - int mSwapRect; - LayerCache mLayerCache; - FbCache mFbCache; - hwc_rect_t mDirtyRect; - bool prepareSwapRect(hwc_context_t *ctx, hwc_display_contents_1_t *list, - int dpy); - bool isLayerChanging(hwc_context_t *ctx, - hwc_display_contents_1_t *list, int k); - bool isSmartBlitPossible(const hwc_display_contents_1_t *list); -}; - -}; //namespace qhwc - -#endif //HWC_COPYBIT_H diff --git a/msm8909/libhwcomposer/hwc_dump_layers.cpp b/msm8909/libhwcomposer/hwc_dump_layers.cpp deleted file mode 100644 index 7833823e..00000000 --- a/msm8909/libhwcomposer/hwc_dump_layers.cpp +++ /dev/null @@ -1,454 +0,0 @@ -/* - * Copyright (c) 2012-2014,2016 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 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 LOG_TAG -#define LOG_TAG "qsfdump" -#endif -#define LOG_NDEBUG 0 -#include <hwc_utils.h> -#include <hwc_dump_layers.h> -#include <cutils/log.h> -#include <sys/stat.h> -#include <comptype.h> -#ifdef QTI_BSP -// Ignore W(float)conversion errors for external headers -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#pragma GCC diagnostic ignored "-Wfloat-conversion" -#include <SkBitmap.h> -#include <SkImageEncoder.h> -#pragma GCC diagnostic pop -#endif -#ifdef STDC_FORMAT_MACROS -#include <inttypes.h> -#endif - -namespace qhwc { - -// MAX_ALLOWED_FRAMEDUMPS must be capped to (LONG_MAX - 1) -// 60fps => 216000 frames per hour -// Below setting of 216000 * 24 * 7 => 1 week or 168 hours of capture. - enum { - MAX_ALLOWED_FRAMEDUMPS = (216000 * 24 * 7) - }; - -bool HwcDebug::sDumpEnable = false; - -HwcDebug::HwcDebug(uint32_t dpy): - mDumpCntLimRaw(0), - mDumpCntrRaw(1), - mDumpCntLimPng(0), - mDumpCntrPng(1), - mDpy(dpy) { - char dumpPropStr[PROPERTY_VALUE_MAX]; - if(mDpy) { - strlcpy(mDisplayName, "external", sizeof(mDisplayName)); - } else { - strlcpy(mDisplayName, "primary", sizeof(mDisplayName)); - } - snprintf(mDumpPropKeyDisplayType, sizeof(mDumpPropKeyDisplayType), - "debug.sf.dump.%s", (char *)mDisplayName); - - if ((property_get("debug.sf.dump.enable", dumpPropStr, NULL) > 0)) { - if(!strncmp(dumpPropStr, "true", strlen("true"))) { - sDumpEnable = true; - } - } -} - -void HwcDebug::dumpLayers(hwc_display_contents_1_t* list) -{ - // Check need for dumping layers for debugging. - if (UNLIKELY(sDumpEnable) && UNLIKELY(needToDumpLayers()) && LIKELY(list)) { - logHwcProps(list->flags); - for (size_t i = 0; i < list->numHwLayers; i++) { - logLayer(i, list->hwLayers); - dumpLayer(i, list->hwLayers); - } - } -} - -bool HwcDebug::needToDumpLayers() -{ - bool bDumpLayer = false; - char dumpPropStr[PROPERTY_VALUE_MAX]; - // Enable primary dump and disable external dump by default. - bool bDumpEnable = !mDpy; - time_t timeNow; - tm dumpTime; - - // Override the bDumpEnable based on the property value, if the property - // is present in the build.prop file. - if ((property_get(mDumpPropKeyDisplayType, dumpPropStr, NULL) > 0)) { - if(!strncmp(dumpPropStr, "true", strlen("true"))) - bDumpEnable = true; - else - bDumpEnable = false; - } - - if (false == bDumpEnable) - return false; - - time(&timeNow); - localtime_r(&timeNow, &dumpTime); - - if ((property_get("debug.sf.dump.png", dumpPropStr, NULL) > 0) && - (strncmp(dumpPropStr, mDumpPropStrPng, PROPERTY_VALUE_MAX - 1))) { - // Strings exist & not equal implies it has changed, so trigger a dump - strlcpy(mDumpPropStrPng, dumpPropStr, sizeof(mDumpPropStrPng)); - mDumpCntLimPng = atoi(dumpPropStr); - if (mDumpCntLimPng > MAX_ALLOWED_FRAMEDUMPS) { - ALOGW("Warning: Using debug.sf.dump.png %d (= max)", - MAX_ALLOWED_FRAMEDUMPS); - mDumpCntLimPng = MAX_ALLOWED_FRAMEDUMPS; - } - mDumpCntLimPng = (mDumpCntLimPng < 0) ? 0: mDumpCntLimPng; - if (mDumpCntLimPng) { - snprintf(mDumpDirPng, sizeof(mDumpDirPng), - "/data/sfdump.png.%04d.%02d.%02d.%02d.%02d.%02d", - dumpTime.tm_year + 1900, dumpTime.tm_mon + 1, - dumpTime.tm_mday, dumpTime.tm_hour, - dumpTime.tm_min, dumpTime.tm_sec); - if (0 == mkdir(mDumpDirPng, 0777)) - mDumpCntrPng = 0; - else { - ALOGE("Error: %s. Failed to create sfdump directory: %s", - strerror(errno), mDumpDirPng); - mDumpCntrPng = mDumpCntLimPng + 1; - } - } - } - - if (mDumpCntrPng <= mDumpCntLimPng) - mDumpCntrPng++; - - if ((property_get("debug.sf.dump", dumpPropStr, NULL) > 0) && - (strncmp(dumpPropStr, mDumpPropStrRaw, PROPERTY_VALUE_MAX - 1))) { - // Strings exist & not equal implies it has changed, so trigger a dump - strlcpy(mDumpPropStrRaw, dumpPropStr, sizeof(mDumpPropStrRaw)); - mDumpCntLimRaw = atoi(dumpPropStr); - if (mDumpCntLimRaw > MAX_ALLOWED_FRAMEDUMPS) { - ALOGW("Warning: Using debug.sf.dump %d (= max)", - MAX_ALLOWED_FRAMEDUMPS); - mDumpCntLimRaw = MAX_ALLOWED_FRAMEDUMPS; - } - mDumpCntLimRaw = (mDumpCntLimRaw < 0) ? 0: mDumpCntLimRaw; - if (mDumpCntLimRaw) { - snprintf(mDumpDirRaw, sizeof(mDumpDirRaw), - "/data/sfdump.raw.%04d.%02d.%02d.%02d.%02d.%02d", - dumpTime.tm_year + 1900, dumpTime.tm_mon + 1, - dumpTime.tm_mday, dumpTime.tm_hour, - dumpTime.tm_min, dumpTime.tm_sec); - if (0 == mkdir(mDumpDirRaw, 0777)) - mDumpCntrRaw = 0; - else { - ALOGE("Error: %s. Failed to create sfdump directory: %s", - strerror(errno), mDumpDirRaw); - mDumpCntrRaw = mDumpCntLimRaw + 1; - } - } - } - - if (mDumpCntrRaw <= mDumpCntLimRaw) - mDumpCntrRaw++; - - bDumpLayer = (mDumpCntLimPng || mDumpCntLimRaw)? true : false; - return bDumpLayer; -} - -void HwcDebug::logHwcProps(uint32_t listFlags) -{ - static int hwcModuleCompType = -1; - static int sMdpCompMaxLayers = 0; - static String8 hwcModuleCompTypeLog(""); - if (-1 == hwcModuleCompType) { - // One time stuff - char mdpCompPropStr[PROPERTY_VALUE_MAX]; - if (property_get("debug.mdpcomp.maxlayer", mdpCompPropStr, NULL) > 0) { - sMdpCompMaxLayers = atoi(mdpCompPropStr); - } - hwcModuleCompType = - qdutils::QCCompositionType::getInstance().getCompositionType(); - hwcModuleCompTypeLog.appendFormat("%s%s%s%s%s%s", - // Is hwc module composition type now a bit-field?! - (hwcModuleCompType == qdutils::COMPOSITION_TYPE_GPU)? - "[GPU]": "", - (hwcModuleCompType & qdutils::COMPOSITION_TYPE_MDP)? - "[MDP]": "", - (hwcModuleCompType & qdutils::COMPOSITION_TYPE_C2D)? - "[C2D]": "", - (hwcModuleCompType & qdutils::COMPOSITION_TYPE_CPU)? - "[CPU]": "", - (hwcModuleCompType & qdutils::COMPOSITION_TYPE_DYN)? - "[DYN]": "", - (hwcModuleCompType >= (qdutils::COMPOSITION_TYPE_DYN << 1))? - "[???]": ""); - } - ALOGI("Display[%s] Layer[*] %s-HwcModuleCompType, %d-layer MdpComp %s", - mDisplayName, hwcModuleCompTypeLog.string(), sMdpCompMaxLayers, - (listFlags & HWC_GEOMETRY_CHANGED)? "[HwcList Geometry Changed]": ""); -} - -void HwcDebug::logLayer(size_t layerIndex, hwc_layer_1_t hwLayers[]) -{ - if (NULL == hwLayers) { - ALOGE("Display[%s] Layer[%zu] Error. No hwc layers to log.", - mDisplayName, layerIndex); - return; - } - - hwc_layer_1_t *layer = &hwLayers[layerIndex]; - hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf); - hwc_rect_t displayFrame = layer->displayFrame; - size_t numHwcRects = layer->visibleRegionScreen.numRects; - hwc_rect_t const *hwcRects = layer->visibleRegionScreen.rects; - private_handle_t *hnd = (private_handle_t *)layer->handle; - - char pixFormatStr[32] = "None"; - String8 hwcVisRegsScrLog("[None]"); - - for (size_t i = 0 ; (hwcRects && (i < numHwcRects)); i++) { - if (0 == i) - hwcVisRegsScrLog.clear(); - hwcVisRegsScrLog.appendFormat("[%dl, %dt, %dr, %db]", - hwcRects[i].left, hwcRects[i].top, - hwcRects[i].right, hwcRects[i].bottom); - } - - if (hnd) - getHalPixelFormatStr(hnd->format, pixFormatStr, sizeof(pixFormatStr)); - - // Log Line 1 - ALOGI("Display[%s] Layer[%zu] SrcBuff[%dx%d] SrcCrop[%dl, %dt, %dr, %db] " - "DispFrame[%dl, %dt, %dr, %db] VisRegsScr%s", mDisplayName, layerIndex, - (hnd)? getWidth(hnd) : -1, (hnd)? getHeight(hnd) : -1, - sourceCrop.left, sourceCrop.top, - sourceCrop.right, sourceCrop.bottom, - displayFrame.left, displayFrame.top, - displayFrame.right, displayFrame.bottom, - hwcVisRegsScrLog.string()); - // Log Line 2 - ALOGI("Display[%s] Layer[%zu] LayerCompType = %s, Format = %s, " - "Orientation = %s, Flags = %s%s%s, Hints = %s%s%s, " - "Blending = %s%s%s", mDisplayName, layerIndex, - (layer->compositionType == HWC_FRAMEBUFFER)? "Framebuffer(GPU)": - (layer->compositionType == HWC_OVERLAY)? "Overlay": - (layer->compositionType == HWC_BACKGROUND)? "Background":"???", - pixFormatStr, - (layer->transform == 0)? "ROT_0": - (layer->transform == HWC_TRANSFORM_FLIP_H)? "FLIP_H": - (layer->transform == HWC_TRANSFORM_FLIP_V)? "FLIP_V": - (layer->transform == HWC_TRANSFORM_ROT_90)? "ROT_90": - "ROT_INVALID", - (layer->flags)? "": "[None]", - (layer->flags & HWC_SKIP_LAYER)? "[Skip layer]":"", - (layer->flags & qhwc::HWC_MDPCOMP)? "[MDP Comp]":"", - (layer->hints)? "":"[None]", - (layer->hints & HWC_HINT_TRIPLE_BUFFER)? "[Triple Buffer]":"", - (layer->hints & HWC_HINT_CLEAR_FB)? "[Clear FB]":"", - (layer->blending == HWC_BLENDING_NONE)? "[None]":"", - (layer->blending == HWC_BLENDING_PREMULT)? "[PreMult]":"", - (layer->blending == HWC_BLENDING_COVERAGE)? "[Coverage]":""); -} - -void HwcDebug::dumpLayer(size_t layerIndex, hwc_layer_1_t hwLayers[]) -{ - char dumpLogStrPng[128] = ""; - char dumpLogStrRaw[128] = ""; - bool needDumpPng = (mDumpCntrPng <= mDumpCntLimPng)? true:false; - bool needDumpRaw = (mDumpCntrRaw <= mDumpCntLimRaw)? true:false; - - if (needDumpPng) { - snprintf(dumpLogStrPng, sizeof(dumpLogStrPng), - "[png-dump-frame: %03d of %03d]", mDumpCntrPng, - mDumpCntLimPng); - } - if (needDumpRaw) { - snprintf(dumpLogStrRaw, sizeof(dumpLogStrRaw), - "[raw-dump-frame: %03d of %03d]", mDumpCntrRaw, - mDumpCntLimRaw); - } - - if (!(needDumpPng || needDumpRaw)) - return; - - if (NULL == hwLayers) { - ALOGE("Display[%s] Layer[%zu] %s%s Error: No hwc layers to dump.", - mDisplayName, layerIndex, dumpLogStrRaw, dumpLogStrPng); - return; - } - - hwc_layer_1_t *layer = &hwLayers[layerIndex]; - private_handle_t *hnd = (private_handle_t *)layer->handle; - char pixFormatStr[32] = "None"; - - if (NULL == hnd) { - ALOGI("Display[%s] Layer[%zu] %s%s Skipping dump: Bufferless layer.", - mDisplayName, layerIndex, dumpLogStrRaw, dumpLogStrPng); - return; - } - - getHalPixelFormatStr(hnd->format, pixFormatStr, sizeof(pixFormatStr)); -#ifdef QTI_BSP - if (needDumpPng && hnd->base) { - bool bResult = false; - char dumpFilename[PATH_MAX]; - SkColorType colorType = kUnknown_SkColorType; - SkAlphaType alphaType = kUnknown_SkAlphaType; - snprintf(dumpFilename, sizeof(dumpFilename), - "%s/sfdump%03d.layer%zu.%s.png", mDumpDirPng, - mDumpCntrPng, layerIndex, mDisplayName); - - switch (hnd->format) { - case HAL_PIXEL_FORMAT_RGBA_8888: - alphaType = kPremul_SkAlphaType; - colorType = kRGBA_8888_SkColorType; - break; - case HAL_PIXEL_FORMAT_RGBX_8888: - alphaType = kOpaque_SkAlphaType; - colorType = kRGBA_8888_SkColorType; - break; - case HAL_PIXEL_FORMAT_BGRA_8888: - alphaType = kPremul_SkAlphaType; - colorType = kBGRA_8888_SkColorType; - break; - case HAL_PIXEL_FORMAT_RGB_565: - alphaType = kOpaque_SkAlphaType; - colorType = kRGB_565_SkColorType; - break; - default: - break; - } - if (kUnknown_SkColorType != colorType) { - SkImageInfo info = SkImageInfo::Make(getWidth(hnd), getHeight(hnd), - colorType, alphaType); - SkPixmap pixmap(info, (const void*)hnd->base, info.minRowBytes()); - SkFILEWStream file(dumpFilename); - bResult = SkEncodeImage(&file, pixmap, SkEncodedImageFormat::kPNG, 100); - ALOGI("Display[%s] Layer[%zu] %s Dump to %s: %s", - mDisplayName, layerIndex, dumpLogStrPng, - dumpFilename, bResult ? "Success" : "Fail"); - } else { - ALOGI("Display[%s] Layer[%zu] %s Skipping dump: Unsupported layer" - " format %s for png encoder", - mDisplayName, layerIndex, dumpLogStrPng, pixFormatStr); - } - } -#endif - if (needDumpRaw && hnd->base) { - char dumpFilename[PATH_MAX]; - bool bResult = false; - snprintf(dumpFilename, sizeof(dumpFilename), - "%s/sfdump%03d.layer%zu.%dx%d.%s.%s.raw", - mDumpDirRaw, mDumpCntrRaw, - layerIndex, getWidth(hnd), getHeight(hnd), - pixFormatStr, mDisplayName); - FILE* fp = fopen(dumpFilename, "w+"); - if (NULL != fp) { - bResult = (bool) fwrite((void*)hnd->base, hnd->size, 1, fp); - fclose(fp); - } - ALOGI("Display[%s] Layer[%zu] %s Dump to %s: %s", - mDisplayName, layerIndex, dumpLogStrRaw, - dumpFilename, bResult ? "Success" : "Fail"); - } -} - -void HwcDebug::getHalPixelFormatStr(int format, char pixFormatStr[], size_t arraySize) -{ - if (!pixFormatStr) - return; - - switch(format) { - case HAL_PIXEL_FORMAT_RGBA_8888: - strlcpy(pixFormatStr, "RGBA_8888", arraySize); - break; - case HAL_PIXEL_FORMAT_RGBX_8888: - strlcpy(pixFormatStr, "RGBX_8888", arraySize); - break; - case HAL_PIXEL_FORMAT_RGB_888: - strlcpy(pixFormatStr, "RGB_888", arraySize); - break; - case HAL_PIXEL_FORMAT_RGB_565: - strlcpy(pixFormatStr, "RGB_565", arraySize); - break; - case HAL_PIXEL_FORMAT_BGRA_8888: - strlcpy(pixFormatStr, "BGRA_8888", arraySize); - break; - case HAL_PIXEL_FORMAT_YV12: - strlcpy(pixFormatStr, "YV12", arraySize); - break; - case HAL_PIXEL_FORMAT_YCbCr_422_SP: - strlcpy(pixFormatStr, "YCbCr_422_SP_NV16", arraySize); - break; - case HAL_PIXEL_FORMAT_YCrCb_420_SP: - strlcpy(pixFormatStr, "YCrCb_420_SP_NV21", arraySize); - break; - case HAL_PIXEL_FORMAT_YCbCr_422_I: - strlcpy(pixFormatStr, "YCbCr_422_I_YUY2", arraySize); - break; - case HAL_PIXEL_FORMAT_YCrCb_422_I: - strlcpy(pixFormatStr, "YCrCb_422_I_YVYU", arraySize); - break; - case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: - strlcpy(pixFormatStr, "NV12_ENCODEABLE", arraySize); - break; - case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: - strlcpy(pixFormatStr, "YCbCr_420_SP_TILED_TILE_4x2", - arraySize); - break; - case HAL_PIXEL_FORMAT_YCbCr_420_SP: - strlcpy(pixFormatStr, "YCbCr_420_SP", arraySize); - break; - case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: - strlcpy(pixFormatStr, "YCrCb_420_SP_ADRENO", arraySize); - break; - case HAL_PIXEL_FORMAT_YCrCb_422_SP: - strlcpy(pixFormatStr, "YCrCb_422_SP", arraySize); - break; - case HAL_PIXEL_FORMAT_R_8: - strlcpy(pixFormatStr, "R_8", arraySize); - break; - case HAL_PIXEL_FORMAT_RG_88: - strlcpy(pixFormatStr, "RG_88", arraySize); - break; - case HAL_PIXEL_FORMAT_INTERLACE: - strlcpy(pixFormatStr, "INTERLACE", arraySize); - break; - case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: - strlcpy(pixFormatStr, "YCbCr_420_SP_VENUS", arraySize); - break; - default: - snprintf(pixFormatStr, arraySize, "Unknown0x%X", format); - break; - } -} - -} // namespace qhwc - diff --git a/msm8909/libhwcomposer/hwc_dump_layers.h b/msm8909/libhwcomposer/hwc_dump_layers.h deleted file mode 100644 index 83e56c0f..00000000 --- a/msm8909/libhwcomposer/hwc_dump_layers.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2012-2013,2016 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 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_DUMP_LAYERS_H -#define HWC_DUMP_LAYERS_H - -#include <gralloc_priv.h> -#include <comptype.h> -#include <hardware/hwcomposer.h> - -namespace qhwc { - -class HwcDebug { -private: - -// Using static variables for layer dumping since "property_set("debug.sf.dump", -// property)" does not work. - int mDumpCntLimRaw; - int mDumpCntrRaw; - char mDumpPropStrRaw[PROPERTY_VALUE_MAX]; - char mDumpDirRaw[PATH_MAX]; - int mDumpCntLimPng; - int mDumpCntrPng; - char mDumpPropStrPng[PROPERTY_VALUE_MAX]; - char mDumpDirPng[PATH_MAX]; - uint32_t mDpy; - char mDisplayName[PROPERTY_VALUE_MAX]; - char mDumpPropKeyDisplayType[PROPERTY_KEY_MAX]; - static bool sDumpEnable; - -public: - HwcDebug(uint32_t dpy); - ~HwcDebug() {}; - - /* - * Dump layers for debugging based on "debug.sf.dump*" system property. - * See needToDumpLayers() for usage. - * - * @param: list - The HWC layer-list to dump. - * - */ - void dumpLayers(hwc_display_contents_1_t* list); - -/* - * Checks if layers need to be dumped based on system property "debug.sf.dump" - * for raw dumps and "debug.sf.dump.png" for png dumps. - * - * Note: Set "debug.sf.dump.primary" or "debug.sf.dump.external" as true - * in the device's /system/build.prop file to enable layer logging/capturing - * feature for primary or external respectively. The feature is disabled by - * default to avoid per-frame property_get() calls. - * - * To turn on layer dump, set "debug.sf.dump.enable" to true in build.prop. - * By default debug.sf.dump.primary will be set to true for user convenience. - * - * To turn on layer dump for primary, do, - * adb shell setprop debug.sf.dump.primary true - * - * To turn on layer dump for external, do, - * adb shell setprop debug.sf.dump.external true - * - * For example, to dump 25 frames in raw format, do, - * adb shell setprop debug.sf.dump 25 - * Layers are dumped in a time-stamped location: /data/sfdump*. - * - * To dump 10 frames in png format, do, - * adb shell setprop debug.sf.dump.png 10 - * To dump another 25 or so frames in raw format, do, - * adb shell setprop debug.sf.dump 26 - * - * To turn off logcat logging of layer-info, set both properties to 0, - * adb shell setprop debug.sf.dump.png 0 - * adb shell setprop debug.sf.dump 0 - * - * @return: true if layers need to be dumped (or logcat-ed). - */ -bool needToDumpLayers(); - -/* - * Log a few per-frame hwc properties into logcat. - * - * @param: listFlags - Flags used in hwcomposer's list. - * - */ -void logHwcProps(uint32_t listFlags); - -/* - * Log a layer's info into logcat. - * - * @param: layerIndex - Index of layer being dumped. - * @param: hwLayers - Address of hwc_layer_1_t to log and dump. - * - */ -void logLayer(size_t layerIndex, hwc_layer_1_t hwLayers[]); - -/* - * Dumps a layer buffer into raw/png files. - * - * @param: layerIndex - Index of layer being dumped. - * @param: hwLayers - Address of hwc_layer_1_t to log and dump. - * - */ -void dumpLayer(size_t layerIndex, hwc_layer_1_t hwLayers[]); - -void getHalPixelFormatStr(int format, char pixelformatstr[], size_t arraySize); -}; - -} // namespace qhwc - -#endif /* HWC_DUMP_LAYERS_H */ diff --git a/msm8909/libhwcomposer/hwc_fbupdate.cpp b/msm8909/libhwcomposer/hwc_fbupdate.cpp deleted file mode 100644 index b0032661..00000000 --- a/msm8909/libhwcomposer/hwc_fbupdate.cpp +++ /dev/null @@ -1,565 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved. - * - * Not a Contribution, Apache license notifications and license are - * retained for attribution purposes only. - * - * 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. - */ - -#define DEBUG_FBUPDATE 0 -#include <cutils/properties.h> -#include <gralloc_priv.h> -#include <overlay.h> -#include <overlayRotator.h> -#include "hwc_fbupdate.h" -#include "mdp_version.h" - -using namespace qdutils; -using namespace overlay; -using overlay::Rotator; -using namespace overlay::utils; - -namespace qhwc { - -namespace ovutils = overlay::utils; - -IFBUpdate* IFBUpdate::getObject(hwc_context_t *ctx, const int& dpy) { - if(qdutils::MDPVersion::getInstance().isSrcSplit()) { - return new FBSrcSplit(ctx, dpy); - } else if(isDisplaySplit(ctx, dpy)) { - return new FBUpdateSplit(ctx, dpy); - } - return new FBUpdateNonSplit(ctx, dpy); -} - -IFBUpdate::IFBUpdate(hwc_context_t *ctx, const int& dpy) : mDpy(dpy) { - unsigned int size = 0; - uint32_t xres = ctx->dpyAttr[mDpy].xres; - uint32_t yres = ctx->dpyAttr[mDpy].yres; - if (ctx->dpyAttr[dpy].customFBSize) { - //GPU will render and compose at new resolution - //So need to have FB at new resolution - xres = ctx->dpyAttr[mDpy].xres_new; - yres = ctx->dpyAttr[mDpy].yres_new; - } - getBufferAttributes((int)xres, (int)yres, - ctx->dpyAttr[mDpy].fbformat, - 0, - mAlignedFBWidth, - mAlignedFBHeight, - mTileEnabled, size); -} - -void IFBUpdate::reset() { - mModeOn = false; - mRot = NULL; -} - -bool IFBUpdate::prepareAndValidate(hwc_context_t *ctx, - hwc_display_contents_1 *list, int fbZorder) { - hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1]; - mModeOn = prepare(ctx, list, layer->displayFrame, fbZorder) && - ctx->mOverlay->validateAndSet(mDpy, ctx->dpyAttr[mDpy].fd); - return mModeOn; -} - -//================= Low res==================================== -FBUpdateNonSplit::FBUpdateNonSplit(hwc_context_t *ctx, const int& dpy): - IFBUpdate(ctx, dpy) {} - -void FBUpdateNonSplit::reset() { - IFBUpdate::reset(); - mDest = ovutils::OV_INVALID; -} - -bool FBUpdateNonSplit::preRotateExtDisplay(hwc_context_t *ctx, - hwc_layer_1_t *layer, - ovutils::Whf &info, - hwc_rect_t& sourceCrop, - ovutils::eMdpFlags& mdpFlags, - int& rotFlags) -{ - int extOrient = getExtOrientation(ctx); - ovutils::eTransform orient = static_cast<ovutils::eTransform >(extOrient); - if(mDpy && (extOrient & HWC_TRANSFORM_ROT_90)) { - mRot = ctx->mRotMgr->getNext(); - if(mRot == NULL) return false; - ctx->mLayerRotMap[mDpy]->add(layer, mRot); - // Composed FB content will have black bars, if the viewFrame of the - // external is different from {0, 0, fbWidth, fbHeight}, so intersect - // viewFrame with sourceCrop to avoid those black bars - sourceCrop = getIntersection(sourceCrop, ctx->mViewFrame[mDpy]); - //Configure rotator for pre-rotation - if(configRotator(mRot, info, sourceCrop, mdpFlags, orient, 0) < 0) { - ALOGE("%s: configRotator Failed!", __FUNCTION__); - mRot = NULL; - return false; - } - updateSource(orient, info, sourceCrop, mRot); - rotFlags |= ovutils::ROT_PREROTATED; - } - return true; -} - -bool FBUpdateNonSplit::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list, - hwc_rect_t fbUpdatingRect, int fbZorder) { - if(!ctx->mMDP.hasOverlay) { - ALOGD_IF(DEBUG_FBUPDATE, "%s, this hw doesnt support overlays", - __FUNCTION__); - return false; - } - mModeOn = configure(ctx, list, fbUpdatingRect, fbZorder); - return mModeOn; -} - -// Configure -bool FBUpdateNonSplit::configure(hwc_context_t *ctx, hwc_display_contents_1 *list, - hwc_rect_t fbUpdatingRect, int fbZorder) { - bool ret = false; - hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1]; - if (LIKELY(ctx->mOverlay)) { - overlay::Overlay& ov = *(ctx->mOverlay); - - ovutils::Whf info(mAlignedFBWidth, mAlignedFBHeight, - ovutils::getMdpFormat(ctx->dpyAttr[mDpy].fbformat, - mTileEnabled)); - - Overlay::PipeSpecs pipeSpecs; - pipeSpecs.formatClass = Overlay::FORMAT_RGB; - pipeSpecs.needsScaling = qhwc::needsScaling(layer); - pipeSpecs.dpy = mDpy; - pipeSpecs.mixer = Overlay::MIXER_DEFAULT; - pipeSpecs.fb = true; - - ovutils::eDest dest = ov.getPipe(pipeSpecs); - if(dest == ovutils::OV_INVALID) { //None available - ALOGE("%s: No pipes available to configure fb for dpy %d", - __FUNCTION__, mDpy); - return false; - } - mDest = dest; - - if((mDpy && ctx->deviceOrientation) && - ctx->listStats[mDpy].isDisplayAnimating) { - fbZorder = 0; - } - - ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_BLEND_FG_PREMULT; - ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder); - - hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf); - hwc_rect_t displayFrame = layer->displayFrame; - - // No FB update optimization on (1) Custom FB resolution, - // (2) External Mirror mode, (3) External orientation - if(!ctx->dpyAttr[mDpy].customFBSize && !ctx->mBufferMirrorMode - && !ctx->mExtOrientation) { - sourceCrop = fbUpdatingRect; - displayFrame = fbUpdatingRect; - } - - int transform = layer->transform; - int rotFlags = ovutils::ROT_FLAGS_NONE; - - ovutils::eTransform orient = - static_cast<ovutils::eTransform>(transform); - // use ext orientation if any - int extOrient = getExtOrientation(ctx); - - // Do not use getNonWormholeRegion() function to calculate the - // sourceCrop during animation on external display and - // Dont do wormhole calculation when extorientation is set on External - // Dont do wormhole calculation when scaling mode is set on External - if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) { - sourceCrop = layer->displayFrame; - } else if((mDpy && !extOrient - && !ctx->dpyAttr[mDpy].mMDPScalingMode)) { - if(ctx->mOverlay->isUIScalingOnExternalSupported() && - !ctx->dpyAttr[mDpy].customFBSize) { - getNonWormholeRegion(list, sourceCrop); - displayFrame = sourceCrop; - } - } - calcExtDisplayPosition(ctx, NULL, mDpy, sourceCrop, displayFrame, - transform, orient); - //Store the displayFrame, will be used in getDisplayViewFrame - ctx->dpyAttr[mDpy].mDstRect = displayFrame; - setMdpFlags(ctx, layer, mdpFlags, 0, transform); - // For External use rotator if there is a rotation value set - ret = preRotateExtDisplay(ctx, layer, info, - sourceCrop, mdpFlags, rotFlags); - if(!ret) { - ALOGE("%s: preRotate for external Failed!", __FUNCTION__); - return false; - } - //For the mdp, since either we are pre-rotating or MDP does flips - orient = ovutils::OVERLAY_TRANSFORM_0; - transform = 0; - ovutils::PipeArgs parg(mdpFlags, info, zOrder, - static_cast<ovutils::eRotFlags>(rotFlags), - ovutils::DEFAULT_PLANE_ALPHA, - (ovutils::eBlending) - getBlending(layer->blending)); - ret = true; - if(configMdp(ctx->mOverlay, parg, orient, sourceCrop, displayFrame, - NULL, mDest) < 0) { - ALOGE("%s: configMdp failed for dpy %d", __FUNCTION__, mDpy); - ret = false; - } - } - return ret; -} - -bool FBUpdateNonSplit::draw(hwc_context_t *ctx, private_handle_t *hnd) -{ - if(!mModeOn) { - return true; - } - bool ret = true; - overlay::Overlay& ov = *(ctx->mOverlay); - ovutils::eDest dest = mDest; - int fd = hnd->fd; - uint32_t offset = (uint32_t)hnd->offset; - if(mRot) { - if(!mRot->queueBuffer(fd, offset)) - return false; - fd = mRot->getDstMemId(); - offset = mRot->getDstOffset(); - } - if (!ov.queueBuffer(fd, offset, dest)) { - ALOGE("%s: queueBuffer failed for FBUpdate", __FUNCTION__); - ret = false; - } - return ret; -} - -//================= High res==================================== -FBUpdateSplit::FBUpdateSplit(hwc_context_t *ctx, const int& dpy): - IFBUpdate(ctx, dpy) {} - -void FBUpdateSplit::reset() { - IFBUpdate::reset(); - mDestLeft = ovutils::OV_INVALID; - mDestRight = ovutils::OV_INVALID; - mRot = NULL; -} - -bool FBUpdateSplit::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list, - hwc_rect_t fbUpdatingRect, int fbZorder) { - if(!ctx->mMDP.hasOverlay) { - ALOGD_IF(DEBUG_FBUPDATE, "%s, this hw doesnt support overlays", - __FUNCTION__); - return false; - } - mModeOn = configure(ctx, list, fbUpdatingRect, fbZorder); - ALOGD_IF(DEBUG_FBUPDATE, "%s, mModeOn = %d", __FUNCTION__, mModeOn); - return mModeOn; -} - -// Configure -bool FBUpdateSplit::configure(hwc_context_t *ctx, - hwc_display_contents_1 *list, hwc_rect_t fbUpdatingRect, int fbZorder) { - bool ret = false; - hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1]; - if (LIKELY(ctx->mOverlay)) { - ovutils::Whf info(mAlignedFBWidth, mAlignedFBHeight, - ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888, - mTileEnabled)); - - overlay::Overlay& ov = *(ctx->mOverlay); - ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_BLEND_FG_PREMULT; - ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder); - ovutils::eTransform orient = - static_cast<ovutils::eTransform>(layer->transform); - const int hw_w = ctx->dpyAttr[mDpy].xres; - const int hw_h = ctx->dpyAttr[mDpy].yres; - const int lSplit = getLeftSplit(ctx, mDpy); - mDestLeft = ovutils::OV_INVALID; - mDestRight = ovutils::OV_INVALID; - hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf); - hwc_rect_t displayFrame = layer->displayFrame; - - // No FB update optimization on (1) Custom FB resolution, - // (2) External Mirror mode, (3) External orientation - if(!ctx->dpyAttr[mDpy].customFBSize && !ctx->mBufferMirrorMode - && !ctx->mExtOrientation) { - sourceCrop = fbUpdatingRect; - displayFrame = fbUpdatingRect; - } - - int transform = layer->transform; - // use ext orientation if any - int extOrient = getExtOrientation(ctx); - - // Do not use getNonWormholeRegion() function to calculate the - // sourceCrop during animation on external display and - // Dont do wormhole calculation when extorientation is set on External - // Dont do wormhole calculation when scaling mode is set on External - if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) { - sourceCrop = layer->displayFrame; - } else if((mDpy && !extOrient - && !ctx->dpyAttr[mDpy].mMDPScalingMode)) { - if(!qdutils::MDPVersion::getInstance().is8x26() && - !ctx->dpyAttr[mDpy].customFBSize) { - getNonWormholeRegion(list, sourceCrop); - displayFrame = sourceCrop; - } - } - - calcExtDisplayPosition(ctx, NULL, mDpy, sourceCrop, displayFrame, - transform, orient); - - ret = true; - Overlay::PipeSpecs pipeSpecs; - pipeSpecs.formatClass = Overlay::FORMAT_RGB; - pipeSpecs.needsScaling = qhwc::needsScaling(layer); - pipeSpecs.dpy = mDpy; - pipeSpecs.fb = true; - - /* Configure left pipe */ - if(displayFrame.left < lSplit) { - pipeSpecs.mixer = Overlay::MIXER_LEFT; - ovutils::eDest destL = ov.getPipe(pipeSpecs); - if(destL == ovutils::OV_INVALID) { //None available - ALOGE("%s: No pipes available to configure fb for dpy %d's left" - " mixer", __FUNCTION__, mDpy); - return false; - } - - mDestLeft = destL; - - //XXX: FB layer plane alpha is currently sent as zero from - //surfaceflinger - ovutils::PipeArgs pargL(mdpFlags, - info, - zOrder, - ovutils::ROT_FLAGS_NONE, - ovutils::DEFAULT_PLANE_ALPHA, - (ovutils::eBlending) - getBlending(layer->blending)); - hwc_rect_t cropL = sourceCrop; - hwc_rect_t dstL = displayFrame; - hwc_rect_t scissorL = {0, 0, lSplit, hw_h }; - qhwc::calculate_crop_rects(cropL, dstL, scissorL, 0); - - if (configMdp(ctx->mOverlay, pargL, orient, cropL, - dstL, NULL, destL)< 0) { - ALOGE("%s: configMdp fails for left FB", __FUNCTION__); - ret = false; - } - } - - /* Configure right pipe */ - if(displayFrame.right > lSplit) { - pipeSpecs.mixer = Overlay::MIXER_RIGHT; - ovutils::eDest destR = ov.getPipe(pipeSpecs); - if(destR == ovutils::OV_INVALID) { //None available - ALOGE("%s: No pipes available to configure fb for dpy %d's" - " right mixer", __FUNCTION__, mDpy); - return false; - } - - mDestRight = destR; - ovutils::eMdpFlags mdpFlagsR = mdpFlags; - ovutils::setMdpFlags(mdpFlagsR, ovutils::OV_MDSS_MDP_RIGHT_MIXER); - - //XXX: FB layer plane alpha is currently sent as zero from - //surfaceflinger - ovutils::PipeArgs pargR(mdpFlagsR, - info, - zOrder, - ovutils::ROT_FLAGS_NONE, - ovutils::DEFAULT_PLANE_ALPHA, - (ovutils::eBlending) - getBlending(layer->blending)); - - hwc_rect_t cropR = sourceCrop; - hwc_rect_t dstR = displayFrame; - hwc_rect_t scissorR = {lSplit, 0, hw_w, hw_h }; - qhwc::calculate_crop_rects(cropR, dstR, scissorR, 0); - - dstR.left -= lSplit; - dstR.right -= lSplit; - - if (configMdp(ctx->mOverlay, pargR, orient, cropR, - dstR, NULL, destR) < 0) { - ALOGE("%s: configMdp fails for right FB", __FUNCTION__); - ret = false; - } - } - } - return ret; -} - -bool FBUpdateSplit::draw(hwc_context_t *ctx, private_handle_t *hnd) -{ - if(!mModeOn) { - return true; - } - bool ret = true; - overlay::Overlay& ov = *(ctx->mOverlay); - if(mDestLeft != ovutils::OV_INVALID) { - if (!ov.queueBuffer(hnd->fd, (uint32_t)hnd->offset, mDestLeft)) { - ALOGE("%s: queue failed for left of dpy = %d", - __FUNCTION__, mDpy); - ret = false; - } - } - if(mDestRight != ovutils::OV_INVALID) { - if (!ov.queueBuffer(hnd->fd, (uint32_t)hnd->offset, mDestRight)) { - ALOGE("%s: queue failed for right of dpy = %d", - __FUNCTION__, mDpy); - ret = false; - } - } - return ret; -} - -//=================FBSrcSplit==================================== -FBSrcSplit::FBSrcSplit(hwc_context_t *ctx, const int& dpy): - FBUpdateSplit(ctx, dpy) {} - -bool FBSrcSplit::configure(hwc_context_t *ctx, hwc_display_contents_1 *list, - hwc_rect_t fbUpdatingRect, int fbZorder) { - hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1]; - overlay::Overlay& ov = *(ctx->mOverlay); - - ovutils::Whf info(mAlignedFBWidth, - mAlignedFBHeight, - ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888, - mTileEnabled)); - - ovutils::eMdpFlags mdpFlags = OV_MDP_BLEND_FG_PREMULT; - ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder); - - ovutils::PipeArgs parg(mdpFlags, - info, - zOrder, - ovutils::ROT_FLAGS_NONE, - ovutils::DEFAULT_PLANE_ALPHA, - (ovutils::eBlending) - getBlending(layer->blending)); - - hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf); - hwc_rect_t displayFrame = layer->displayFrame; - - // No FB update optimization on (1) Custom FB resolution, - // (2) External Mirror mode, (3) External orientation - if(!ctx->dpyAttr[mDpy].customFBSize && !ctx->mBufferMirrorMode - && !ctx->mExtOrientation) { - sourceCrop = fbUpdatingRect; - displayFrame = fbUpdatingRect; - } - int transform = layer->transform; - ovutils::eTransform orient = - static_cast<ovutils::eTransform>(transform); - - // use ext orientation if any - int extOrient = getExtOrientation(ctx); - - // Do not use getNonWormholeRegion() function to calculate the - // sourceCrop during animation on external display and - // Dont do wormhole calculation when extorientation is set on External - // Dont do wormhole calculation when scaling mode is set on External - if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) { - sourceCrop = layer->displayFrame; - } else if((mDpy && !extOrient - && !ctx->dpyAttr[mDpy].mMDPScalingMode)) { - if(!qdutils::MDPVersion::getInstance().is8x26() && - !ctx->dpyAttr[mDpy].customFBSize) { - getNonWormholeRegion(list, sourceCrop); - displayFrame = sourceCrop; - } - } - - calcExtDisplayPosition(ctx, NULL, mDpy, sourceCrop, displayFrame, - transform, orient); - hwc_rect_t cropL = sourceCrop; - hwc_rect_t cropR = sourceCrop; - hwc_rect_t dstL = displayFrame; - hwc_rect_t dstR = displayFrame; - - //Request left pipe (or 1 by default) - Overlay::PipeSpecs pipeSpecs; - pipeSpecs.formatClass = Overlay::FORMAT_RGB; - pipeSpecs.needsScaling = qhwc::needsScaling(layer); - pipeSpecs.dpy = mDpy; - pipeSpecs.mixer = Overlay::MIXER_DEFAULT; - pipeSpecs.fb = true; - ovutils::eDest destL = ov.getPipe(pipeSpecs); - if(destL == ovutils::OV_INVALID) { - ALOGE("%s: No pipes available to configure fb for dpy %d's left" - " mixer", __FUNCTION__, mDpy); - return false; - } - - ovutils::eDest destR = ovutils::OV_INVALID; - - /* Use 2 pipes IF - a) FB's width is > Mixer width or - b) On primary, driver has indicated with caps to split always. This is - based on an empirically derived value of panel height. - */ - - const bool primarySplitAlways = (mDpy == HWC_DISPLAY_PRIMARY) and - qdutils::MDPVersion::getInstance().isSrcSplitAlways(); - const uint32_t lSplit = getLeftSplit(ctx, mDpy); - const uint32_t cropWidth = sourceCrop.right - sourceCrop.left; - - if((cropWidth > qdutils::MDPVersion::getInstance().getMaxMixerWidth()) or - (primarySplitAlways and cropWidth > lSplit)) { - destR = ov.getPipe(pipeSpecs); - if(destR == ovutils::OV_INVALID) { - ALOGE("%s: No pipes available to configure fb for dpy %d's right" - " mixer", __FUNCTION__, mDpy); - return false; - } - - if(ctx->mOverlay->comparePipePriority(destL, destR) == -1) { - qhwc::swap(destL, destR); - } - - //Split crop equally when using 2 pipes - cropL.right = (sourceCrop.right + sourceCrop.left) / 2; - cropR.left = cropL.right; - dstL.right = (displayFrame.right + displayFrame.left) / 2; - dstR.left = dstL.right; - } - - mDestLeft = destL; - mDestRight = destR; - - if(destL != OV_INVALID) { - if(configMdp(ctx->mOverlay, parg, orient, - cropL, dstL, NULL /*metadata*/, destL) < 0) { - ALOGE("%s: commit failed for left mixer config", __FUNCTION__); - return false; - } - } - - //configure right pipe - if(destR != OV_INVALID) { - if(configMdp(ctx->mOverlay, parg, orient, - cropR, dstR, NULL /*metadata*/, destR) < 0) { - ALOGE("%s: commit failed for right mixer config", __FUNCTION__); - return false; - } - } - - return true; -} - -//--------------------------------------------------------------------- -}; //namespace qhwc diff --git a/msm8909/libhwcomposer/hwc_fbupdate.h b/msm8909/libhwcomposer/hwc_fbupdate.h deleted file mode 100644 index 545f5bd0..00000000 --- a/msm8909/libhwcomposer/hwc_fbupdate.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012, The Linux Foundation. All rights reserved. - * - * Not a Contribution, Apache license notifications and license are - * retained for attribution purposes only. - * - * 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_FBUPDATE_H -#define HWC_FBUPDATE_H -#include "hwc_utils.h" -#include "overlay.h" - -#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) -#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) - -namespace overlay { - class Rotator; -} - -namespace qhwc { -namespace ovutils = overlay::utils; - -//Framebuffer update Interface -class IFBUpdate { -public: - explicit IFBUpdate(hwc_context_t *ctx, const int& dpy); - virtual ~IFBUpdate() {}; - // Sets up members and prepares overlay if conditions are met - virtual bool prepare(hwc_context_t *ctx, hwc_display_contents_1 *list, - hwc_rect_t fbUpdatingRect, int fbZorder) = 0; - virtual bool prepareAndValidate(hwc_context_t *ctx, - hwc_display_contents_1 *list, int fbZorder); - // Draws layer - virtual bool draw(hwc_context_t *ctx, private_handle_t *hnd) = 0; - //Reset values - virtual void reset(); - //Factory method that returns a low-res or high-res version - static IFBUpdate *getObject(hwc_context_t *ctx, const int& dpy); - -protected: - const int mDpy; // display to update - bool mModeOn; // if prepare happened - overlay::Rotator *mRot; - int mAlignedFBWidth; - int mAlignedFBHeight; - int mTileEnabled; -}; - -//Non-Split panel handler. -class FBUpdateNonSplit : public IFBUpdate { -public: - explicit FBUpdateNonSplit(hwc_context_t *ctx, const int& dpy); - virtual ~FBUpdateNonSplit() {}; - bool prepare(hwc_context_t *ctx, hwc_display_contents_1 *list, - hwc_rect_t fbUpdatingRect, int fbZorder); - bool draw(hwc_context_t *ctx, private_handle_t *hnd); - void reset(); -private: - bool configure(hwc_context_t *ctx, hwc_display_contents_1 *list, - hwc_rect_t fbUpdatingRect, int fbZorder); - bool preRotateExtDisplay(hwc_context_t *ctx, - hwc_layer_1_t *layer, - ovutils::Whf &info, - hwc_rect_t& sourceCrop, - ovutils::eMdpFlags& mdpFlags, - int& rotFlags); - ovutils::eDest mDest; //pipe to draw on -}; - -//Split panel handler. -class FBUpdateSplit : public IFBUpdate { -public: - explicit FBUpdateSplit(hwc_context_t *ctx, const int& dpy); - virtual ~FBUpdateSplit() {}; - bool prepare(hwc_context_t *ctx, hwc_display_contents_1 *list, - hwc_rect_t fbUpdatingRect, int fbZorder); - bool draw(hwc_context_t *ctx, private_handle_t *hnd); - void reset(); - -protected: - virtual bool configure(hwc_context_t *ctx, hwc_display_contents_1 *list, - hwc_rect_t fbUpdatingRect, int fbZorder); - ovutils::eDest mDestLeft; //left pipe to draw on - ovutils::eDest mDestRight; //right pipe to draw on -}; - -//Source Split Handler -class FBSrcSplit : public FBUpdateSplit { -public: - explicit FBSrcSplit(hwc_context_t *ctx, const int& dpy); - virtual ~FBSrcSplit() {}; -private: - bool configure(hwc_context_t *ctx, hwc_display_contents_1 *list, - hwc_rect_t fbUpdatingRect, int fbZorder); -}; - -}; //namespace qhwc - -#endif //HWC_FBUPDATE_H diff --git a/msm8909/libhwcomposer/hwc_mdpcomp.cpp b/msm8909/libhwcomposer/hwc_mdpcomp.cpp deleted file mode 100644 index 93e09455..00000000 --- a/msm8909/libhwcomposer/hwc_mdpcomp.cpp +++ /dev/null @@ -1,2827 +0,0 @@ -/* - * Copyright (C) 2012-2016, The Linux Foundation. All rights reserved. - * Not a Contribution, Apache license notifications and license are retained - * for attribution purposes only. - * - * 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 <math.h> -#include "hwc_mdpcomp.h" -#include <sys/ioctl.h> -#include "hdmi.h" -#include "qdMetaData.h" -#include "mdp_version.h" -#include "hwc_fbupdate.h" -#include "hwc_ad.h" -#include <overlayRotator.h> -#include "hwc_copybit.h" -#include "qd_utils.h" - -using namespace overlay; -using namespace qdutils; -using namespace overlay::utils; -namespace ovutils = overlay::utils; - -namespace qhwc { - -//==============MDPComp======================================================== - -IdleInvalidator *MDPComp::sIdleInvalidator = NULL; -bool MDPComp::sIdleFallBack = false; -bool MDPComp::sDebugLogs = false; -bool MDPComp::sEnabled = false; -bool MDPComp::sEnableMixedMode = true; -int MDPComp::sSimulationFlags = 0; -int MDPComp::sMaxPipesPerMixer = MAX_PIPES_PER_MIXER; -bool MDPComp::sEnableYUVsplit = false; -bool MDPComp::sSrcSplitEnabled = false; -bool MDPComp::enablePartialUpdateForMDP3 = false; -bool MDPComp::sIsPartialUpdateActive = true; -MDPComp* MDPComp::getObject(hwc_context_t *ctx, const int& dpy) { - if(qdutils::MDPVersion::getInstance().isSrcSplit()) { - sSrcSplitEnabled = true; - return new MDPCompSrcSplit(dpy); - } else if(isDisplaySplit(ctx, dpy)) { - return new MDPCompSplit(dpy); - } - return new MDPCompNonSplit(dpy); -} - -MDPComp::MDPComp(int dpy) : mDpy(dpy), mModeOn(false), mPrevModeOn(false) { -}; - -void MDPComp::dump(android::String8& buf, hwc_context_t *ctx) -{ - if(mCurrentFrame.layerCount > MAX_NUM_APP_LAYERS) - return; - - dumpsys_log(buf,"HWC Map for Dpy: %s \n", - (mDpy == 0) ? "\"PRIMARY\"" : - (mDpy == 1) ? "\"EXTERNAL\"" : "\"VIRTUAL\""); - dumpsys_log(buf,"CURR_FRAME: layerCount:%2d mdpCount:%2d " - "fbCount:%2d \n", mCurrentFrame.layerCount, - mCurrentFrame.mdpCount, mCurrentFrame.fbCount); - dumpsys_log(buf,"needsFBRedraw:%3s pipesUsed:%2d MaxPipesPerMixer: %d \n", - (mCurrentFrame.needsRedraw? "YES" : "NO"), - mCurrentFrame.mdpCount, sMaxPipesPerMixer); - if(isDisplaySplit(ctx, mDpy)) { - dumpsys_log(buf, "Programmed ROI's: Left: [%d, %d, %d, %d] " - "Right: [%d, %d, %d, %d] \n", - ctx->listStats[mDpy].lRoi.left, ctx->listStats[mDpy].lRoi.top, - ctx->listStats[mDpy].lRoi.right, - ctx->listStats[mDpy].lRoi.bottom, - ctx->listStats[mDpy].rRoi.left,ctx->listStats[mDpy].rRoi.top, - ctx->listStats[mDpy].rRoi.right, - ctx->listStats[mDpy].rRoi.bottom); - } else { - dumpsys_log(buf, "Programmed ROI: [%d, %d, %d, %d] \n", - ctx->listStats[mDpy].lRoi.left,ctx->listStats[mDpy].lRoi.top, - ctx->listStats[mDpy].lRoi.right, - ctx->listStats[mDpy].lRoi.bottom); - } - dumpsys_log(buf," --------------------------------------------- \n"); - dumpsys_log(buf," listIdx | cached? | mdpIndex | comptype | Z \n"); - dumpsys_log(buf," --------------------------------------------- \n"); - for(int index = 0; index < mCurrentFrame.layerCount; index++ ) - dumpsys_log(buf," %7d | %7s | %8d | %9s | %2d \n", - index, - (mCurrentFrame.isFBComposed[index] ? "YES" : "NO"), - mCurrentFrame.layerToMDP[index], - (mCurrentFrame.isFBComposed[index] ? - (mCurrentFrame.drop[index] ? "DROP" : - (mCurrentFrame.needsRedraw ? "GLES" : "CACHE")) : "MDP"), - (mCurrentFrame.isFBComposed[index] ? mCurrentFrame.fbZ : - mCurrentFrame.mdpToLayer[mCurrentFrame.layerToMDP[index]].pipeInfo->zOrder)); - dumpsys_log(buf,"\n"); -} - -bool MDPComp::init(hwc_context_t *ctx) { - - if(!ctx) { - ALOGE("%s: Invalid hwc context!!",__FUNCTION__); - return false; - } - - char property[PROPERTY_VALUE_MAX] = {0}; - - sEnabled = false; - if((ctx->mMDP.version >= qdutils::MDP_V4_0) && - (property_get("persist.hwc.mdpcomp.enable", property, NULL) > 0) && - (!strncmp(property, "1", PROPERTY_VALUE_MAX ) || - (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) { - sEnabled = true; - } - - sEnableMixedMode = true; - if((property_get("debug.mdpcomp.mixedmode.disable", property, NULL) > 0) && - (!strncmp(property, "1", PROPERTY_VALUE_MAX ) || - (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) { - sEnableMixedMode = false; - } - - sMaxPipesPerMixer = MAX_PIPES_PER_MIXER; - if(property_get("debug.mdpcomp.maxpermixer", property, "-1") > 0) { - int val = atoi(property); - if(val >= 0) - sMaxPipesPerMixer = min(val, MAX_PIPES_PER_MIXER); - } - - if(ctx->mMDP.panel != MIPI_CMD_PANEL && - (ctx->mMDP.version >= qdutils::MDP_V4_0)) { - sIdleInvalidator = IdleInvalidator::getInstance(); - if(sIdleInvalidator->init(timeout_handler, ctx) < 0) { - delete sIdleInvalidator; - sIdleInvalidator = NULL; - } - } - - if(!qdutils::MDPVersion::getInstance().isSrcSplit() && - !qdutils::MDPVersion::getInstance().isRotDownscaleEnabled() && - property_get("persist.mdpcomp.4k2kSplit", property, "0") > 0 && - (!strncmp(property, "1", PROPERTY_VALUE_MAX) || - !strncasecmp(property,"true", PROPERTY_VALUE_MAX))) { - sEnableYUVsplit = true; - } - - bool defaultPTOR = false; - //Enable PTOR when "persist.hwc.ptor.enable" is not defined for - //8x16 and 8x39 targets by default - if((property_get("persist.hwc.ptor.enable", property, NULL) <= 0) && - (qdutils::MDPVersion::getInstance().is8x16() || - qdutils::MDPVersion::getInstance().is8x39())) { - defaultPTOR = true; - } - - if (defaultPTOR || (!strncasecmp(property, "true", PROPERTY_VALUE_MAX)) || - (!strncmp(property, "1", PROPERTY_VALUE_MAX ))) { - ctx->mCopyBit[HWC_DISPLAY_PRIMARY] = new CopyBit(ctx, - HWC_DISPLAY_PRIMARY); - } - - if((property_get("persist.mdp3.partialUpdate", property, NULL) <= 0) && - (ctx->mMDP.version == qdutils::MDP_V3_0_5)) { - enablePartialUpdateForMDP3 = true; - } - - if(!enablePartialUpdateForMDP3 && - (!strncmp(property, "1", PROPERTY_VALUE_MAX ) || - (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) { - enablePartialUpdateForMDP3 = true; - } - - int retPartialUpdatePref = getPartialUpdatePref(ctx); - if(retPartialUpdatePref >= 0) - sIsPartialUpdateActive = (retPartialUpdatePref != 0); - - return true; -} - -void MDPComp::reset(hwc_context_t *ctx) { - const int numLayers = ctx->listStats[mDpy].numAppLayers; - mCurrentFrame.reset(numLayers); - ctx->mOverlay->clear(mDpy); - ctx->mLayerRotMap[mDpy]->clear(); - resetROI(ctx, mDpy); - memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop)); - mCurrentFrame.dropCount = 0; -} - -void MDPComp::reset() { - mPrevModeOn = mModeOn; - mModeOn = false; -} - -void MDPComp::timeout_handler(void *udata) { - struct hwc_context_t* ctx = (struct hwc_context_t*)(udata); - bool handleTimeout = false; - - if(!ctx) { - ALOGE("%s: received empty data in timer callback", __FUNCTION__); - return; - } - - ctx->mDrawLock.lock(); - - /* Handle timeout event only if the previous composition - on any display is MDP or MIXED*/ - for(int i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) { - if(ctx->mMDPComp[i]) - handleTimeout = - ctx->mMDPComp[i]->isMDPComp() || handleTimeout; - } - - if(!handleTimeout) { - ALOGD_IF(isDebug(), "%s:Do not handle this timeout", __FUNCTION__); - ctx->mDrawLock.unlock(); - return; - } - if(!ctx->proc) { - ALOGE("%s: HWC proc not registered", __FUNCTION__); - ctx->mDrawLock.unlock(); - return; - } - sIdleFallBack = true; - ctx->mDrawLock.unlock(); - /* Trigger SF to redraw the current frame */ - ctx->proc->invalidate(ctx->proc); -} - -void MDPComp::setIdleTimeout(const uint32_t& timeout) { - enum { ONE_REFRESH_PERIOD_MS = 17, ONE_BILLION_MS = 1000000000 }; - - if(sIdleInvalidator) { - if(timeout <= ONE_REFRESH_PERIOD_MS) { - //If the specified timeout is < 1 draw cycle worth, "virtually" - //disable idle timeout. The ideal way for clients to disable - //timeout is to set it to 0 - sIdleInvalidator->setIdleTimeout(ONE_BILLION_MS); - ALOGI("Disabled idle timeout"); - return; - } - sIdleInvalidator->setIdleTimeout(timeout); - ALOGI("Idle timeout set to %u", timeout); - } else { - ALOGW("Cannot set idle timeout, IdleInvalidator not enabled"); - } -} - -void MDPComp::setMDPCompLayerFlags(hwc_context_t *ctx, - hwc_display_contents_1_t* list) { - LayerProp *layerProp = ctx->layerProp[mDpy]; - - for(int index = 0; index < ctx->listStats[mDpy].numAppLayers; index++) { - hwc_layer_1_t* layer = &(list->hwLayers[index]); - if(!mCurrentFrame.isFBComposed[index]) { - layerProp[index].mFlags |= HWC_MDPCOMP; - layer->compositionType = HWC_OVERLAY; - layer->hints |= HWC_HINT_CLEAR_FB; - } else { - /* Drop the layer when its already present in FB OR when it lies - * outside frame's ROI */ - if(!mCurrentFrame.needsRedraw || mCurrentFrame.drop[index]) { - layer->compositionType = HWC_OVERLAY; - } - } - } -} - -void MDPComp::setRedraw(hwc_context_t *ctx, - hwc_display_contents_1_t* list) { - mCurrentFrame.needsRedraw = false; - if(!mCachedFrame.isSameFrame(mCurrentFrame, list) || - (list->flags & HWC_GEOMETRY_CHANGED) || - isSkipPresent(ctx, mDpy)) { - mCurrentFrame.needsRedraw = true; - } -} - -MDPComp::FrameInfo::FrameInfo() { - memset(&mdpToLayer, 0, sizeof(mdpToLayer)); - reset(0); -} - -void MDPComp::FrameInfo::reset(const int& numLayers) { - for(int i = 0; i < MAX_PIPES_PER_MIXER; i++) { - if(mdpToLayer[i].pipeInfo) { - delete mdpToLayer[i].pipeInfo; - mdpToLayer[i].pipeInfo = NULL; - //We dont own the rotator - mdpToLayer[i].rot = NULL; - } - } - - memset(&mdpToLayer, 0, sizeof(mdpToLayer)); - memset(&layerToMDP, -1, sizeof(layerToMDP)); - memset(&isFBComposed, 1, sizeof(isFBComposed)); - - layerCount = numLayers; - fbCount = numLayers; - mdpCount = 0; - needsRedraw = true; - fbZ = -1; -} - -void MDPComp::FrameInfo::map() { - // populate layer and MDP maps - int mdpIdx = 0; - for(int idx = 0; idx < layerCount; idx++) { - if(!isFBComposed[idx]) { - mdpToLayer[mdpIdx].listIndex = idx; - layerToMDP[idx] = mdpIdx++; - } - } -} - -MDPComp::LayerCache::LayerCache() { - reset(); -} - -void MDPComp::LayerCache::reset() { - memset(&isFBComposed, true, sizeof(isFBComposed)); - memset(&drop, false, sizeof(drop)); - layerCount = 0; -} - -void MDPComp::LayerCache::updateCounts(const FrameInfo& curFrame) { - layerCount = curFrame.layerCount; - memcpy(&isFBComposed, &curFrame.isFBComposed, sizeof(isFBComposed)); - memcpy(&drop, &curFrame.drop, sizeof(drop)); -} - -bool MDPComp::LayerCache::isSameFrame(const FrameInfo& curFrame, - hwc_display_contents_1_t* list) { - if(layerCount != curFrame.layerCount) - return false; - for(int i = 0; i < curFrame.layerCount; i++) { - if((curFrame.isFBComposed[i] != isFBComposed[i]) || - (curFrame.drop[i] != drop[i])) { - return false; - } - hwc_layer_1_t const* layer = &list->hwLayers[i]; - if(curFrame.isFBComposed[i] && layerUpdating(layer)) { - return false; - } - } - return true; -} - -bool MDPComp::LayerCache::isSameFrame(hwc_context_t *ctx, int dpy, - hwc_display_contents_1_t* list) { - - if(layerCount != ctx->listStats[dpy].numAppLayers) - return false; - - if((list->flags & HWC_GEOMETRY_CHANGED) || - isSkipPresent(ctx, dpy)) { - return false; - } - - for(int i = 0; i < layerCount; i++) { - hwc_layer_1_t const* layer = &list->hwLayers[i]; - if(layerUpdating(layer)) - return false; - } - - return true; -} - -bool MDPComp::isSupportedForMDPComp(hwc_context_t *ctx, hwc_layer_1_t* layer) { - private_handle_t *hnd = (private_handle_t *)layer->handle; - if((has90Transform(layer) and (not isRotationDoable(ctx, hnd))) || - (not isValidDimension(ctx,layer)) || - isSkipLayer(layer)) { - //More conditions here, sRGB+Blend etc - return false; - } - return true; -} - -bool MDPComp::isValidDimension(hwc_context_t *ctx, hwc_layer_1_t *layer) { - private_handle_t *hnd = (private_handle_t *)layer->handle; - - if(!hnd) { - if (layer->flags & HWC_COLOR_FILL) { - // Color layer - return true; - } - ALOGD_IF(isDebug(), "%s: layer handle is NULL", __FUNCTION__); - return false; - } - - //XXX: Investigate doing this with pixel phase on MDSS - if(!isSecureBuffer(hnd) && isNonIntegralSourceCrop(layer->sourceCropf)) - return false; - - hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf); - hwc_rect_t dst = layer->displayFrame; - bool rotated90 = (bool)(layer->transform & HAL_TRANSFORM_ROT_90); - int crop_w = rotated90 ? crop.bottom - crop.top : crop.right - crop.left; - int crop_h = rotated90 ? crop.right - crop.left : crop.bottom - crop.top; - int dst_w = dst.right - dst.left; - int dst_h = dst.bottom - dst.top; - float w_scale = ((float)crop_w / (float)dst_w); - float h_scale = ((float)crop_h / (float)dst_h); - MDPVersion& mdpHw = MDPVersion::getInstance(); - - /* Workaround for MDP HW limitation in DSI command mode panels where - * FPS will not go beyond 30 if buffers on RGB pipes are of width or height - * less than 5 pixels - * There also is a HW limilation in MDP, minimum block size is 2x2 - * Fallback to GPU if height is less than 2. - */ - if(mdpHw.hasMinCropWidthLimitation() and (crop_w < 5 or crop_h < 5)) - return false; - - if((w_scale > 1.0f) || (h_scale > 1.0f)) { - const uint32_t maxMDPDownscale = mdpHw.getMaxMDPDownscale(); - const float w_dscale = w_scale; - const float h_dscale = h_scale; - - if(ctx->mMDP.version >= qdutils::MDSS_V5) { - - if(!mdpHw.supportsDecimation()) { - /* On targets that doesnt support Decimation (eg.,8x26) - * maximum downscale support is overlay pipe downscale. - */ - if(crop_w > (int) mdpHw.getMaxMixerWidth() || - w_dscale > maxMDPDownscale || - h_dscale > maxMDPDownscale) - return false; - } else { - // Decimation on macrotile format layers is not supported. - if(isTileRendered(hnd)) { - /* Bail out if - * 1. Src crop > Mixer limit on nonsplit MDPComp - * 2. exceeds maximum downscale limit - */ - if(((crop_w > (int) mdpHw.getMaxMixerWidth()) && - !sSrcSplitEnabled) || - w_dscale > maxMDPDownscale || - h_dscale > maxMDPDownscale) { - return false; - } - } else if(w_dscale > 64 || h_dscale > 64) - return false; - } - } else { //A-family - if(w_dscale > maxMDPDownscale || h_dscale > maxMDPDownscale) - return false; - } - } - - if((w_scale < 1.0f) || (h_scale < 1.0f)) { - const uint32_t upscale = mdpHw.getMaxMDPUpscale(); - const float w_uscale = 1.0f / w_scale; - const float h_uscale = 1.0f / h_scale; - - if(w_uscale > upscale || h_uscale > upscale) - return false; - } - - return true; -} - -bool MDPComp::isFrameDoable(hwc_context_t *ctx) { - bool ret = true; - - if(!isEnabled()) { - ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled.", __FUNCTION__); - ret = false; - } else if((qdutils::MDPVersion::getInstance().is8x26() || - qdutils::MDPVersion::getInstance().is8x16() || - qdutils::MDPVersion::getInstance().is8x39()) && - ctx->mVideoTransFlag && - isSecondaryConnected(ctx)) { - //1 Padding round to shift pipes across mixers - ALOGD_IF(isDebug(),"%s: MDP Comp. video transition padding round", - __FUNCTION__); - ret = false; - } else if((qdutils::MDPVersion::getInstance().is8x26() || - qdutils::MDPVersion::getInstance().is8x16() || - qdutils::MDPVersion::getInstance().is8x39()) && - !mDpy && isSecondaryAnimating(ctx) && - isYuvPresent(ctx,HWC_DISPLAY_VIRTUAL)) { - ALOGD_IF(isDebug(),"%s: Display animation in progress", - __FUNCTION__); - ret = false; - } else if(qdutils::MDPVersion::getInstance().getTotalPipes() < 8) { - /* TODO: freeing up all the resources only for the targets having total - number of pipes < 8. Need to analyze number of VIG pipes used - for primary in previous draw cycle and accordingly decide - whether to fall back to full GPU comp or video only comp - */ - if(isSecondaryConfiguring(ctx)) { - ALOGD_IF( isDebug(),"%s: External Display connection is pending", - __FUNCTION__); - ret = false; - } else if(ctx->isPaddingRound) { - ALOGD_IF(isDebug(), "%s: padding round invoked for dpy %d", - __FUNCTION__,mDpy); - ret = false; - } - } - return ret; -} - -void MDPCompNonSplit::trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect) { - hwc_rect_t roi = ctx->listStats[mDpy].lRoi; - fbRect = getIntersection(fbRect, roi); -} - -/* 1) Identify layers that are not visible or lying outside the updating ROI and - * drop them from composition. - * 2) If we have a scaling layer which needs cropping against generated - * ROI, reset ROI to full resolution. */ -bool MDPCompNonSplit::validateAndApplyROI(hwc_context_t *ctx, - hwc_display_contents_1_t* list) { - int numAppLayers = ctx->listStats[mDpy].numAppLayers; - hwc_rect_t visibleRect = ctx->listStats[mDpy].lRoi; - - for(int i = numAppLayers - 1; i >= 0; i--){ - if(!isValidRect(visibleRect)) { - mCurrentFrame.drop[i] = true; - mCurrentFrame.dropCount++; - continue; - } - - const hwc_layer_1_t* layer = &list->hwLayers[i]; - hwc_rect_t dstRect = layer->displayFrame; - hwc_rect_t res = getIntersection(visibleRect, dstRect); - - if(!isValidRect(res)) { - mCurrentFrame.drop[i] = true; - mCurrentFrame.dropCount++; - } else { - /* Reset frame ROI when any layer which needs scaling also needs ROI - * cropping */ - if(!isSameRect(res, dstRect) && needsScaling (layer)) { - ALOGI("%s: Resetting ROI due to scaling", __FUNCTION__); - memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop)); - mCurrentFrame.dropCount = 0; - return false; - } - - /* deduct any opaque region from visibleRect */ - if (layer->blending == HWC_BLENDING_NONE && - layer->planeAlpha == 0xFF) - visibleRect = deductRect(visibleRect, res); - } - } - return true; -} - -/* Calculate ROI for the frame by accounting all the layer's dispalyFrame which - * are updating. If DirtyRegion is applicable, calculate it by accounting all - * the changing layer's dirtyRegion. */ -void MDPCompNonSplit::generateROI(hwc_context_t *ctx, - hwc_display_contents_1_t* list) { - int numAppLayers = ctx->listStats[mDpy].numAppLayers; - if(!canPartialUpdate(ctx, list)) - return; - - struct hwc_rect roi = (struct hwc_rect){0, 0, 0, 0}; - hwc_rect fullFrame = (struct hwc_rect) {0, 0,(int)ctx->dpyAttr[mDpy].xres, - (int)ctx->dpyAttr[mDpy].yres}; - - for(int index = 0; index < numAppLayers; index++ ) { - hwc_layer_1_t* layer = &list->hwLayers[index]; - if (layerUpdating(layer) || - isYuvBuffer((private_handle_t *)layer->handle)) { - hwc_rect_t dirtyRect = (struct hwc_rect){0, 0, 0, 0};; - if(!needsScaling(layer) && !layer->transform && - (!isYuvBuffer((private_handle_t *)layer->handle))) - { - dirtyRect = calculateDirtyRect(layer, fullFrame); - } - - roi = getUnion(roi, dirtyRect); - } - } - - /* No layer is updating. Still SF wants a refresh.*/ - if(!isValidRect(roi)) - return; - - // Align ROI coordinates to panel restrictions - roi = getSanitizeROI(roi, fullFrame); - - ctx->listStats[mDpy].lRoi = roi; - if(!validateAndApplyROI(ctx, list)) - resetROI(ctx, mDpy); - - ALOGD_IF(isDebug(),"%s: generated ROI: [%d, %d, %d, %d]", __FUNCTION__, - ctx->listStats[mDpy].lRoi.left, ctx->listStats[mDpy].lRoi.top, - ctx->listStats[mDpy].lRoi.right, ctx->listStats[mDpy].lRoi.bottom); -} - -void MDPCompSplit::trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect) { - hwc_rect l_roi = ctx->listStats[mDpy].lRoi; - hwc_rect r_roi = ctx->listStats[mDpy].rRoi; - - hwc_rect_t l_fbRect = getIntersection(fbRect, l_roi); - hwc_rect_t r_fbRect = getIntersection(fbRect, r_roi); - fbRect = getUnion(l_fbRect, r_fbRect); -} -/* 1) Identify layers that are not visible or lying outside BOTH the updating - * ROI's and drop them from composition. If a layer is spanning across both - * the halves of the screen but needed by only ROI, the non-contributing - * half will not be programmed for MDP. - * 2) If we have a scaling layer which needs cropping against generated - * ROI, reset ROI to full resolution. */ -bool MDPCompSplit::validateAndApplyROI(hwc_context_t *ctx, - hwc_display_contents_1_t* list) { - - int numAppLayers = ctx->listStats[mDpy].numAppLayers; - - hwc_rect_t visibleRectL = ctx->listStats[mDpy].lRoi; - hwc_rect_t visibleRectR = ctx->listStats[mDpy].rRoi; - - for(int i = numAppLayers - 1; i >= 0; i--){ - if(!isValidRect(visibleRectL) && !isValidRect(visibleRectR)) - { - mCurrentFrame.drop[i] = true; - mCurrentFrame.dropCount++; - continue; - } - - const hwc_layer_1_t* layer = &list->hwLayers[i]; - hwc_rect_t dstRect = layer->displayFrame; - - hwc_rect_t l_res = getIntersection(visibleRectL, dstRect); - hwc_rect_t r_res = getIntersection(visibleRectR, dstRect); - hwc_rect_t res = getUnion(l_res, r_res); - - if(!isValidRect(l_res) && !isValidRect(r_res)) { - mCurrentFrame.drop[i] = true; - mCurrentFrame.dropCount++; - } else { - /* Reset frame ROI when any layer which needs scaling also needs ROI - * cropping */ - if(!isSameRect(res, dstRect) && needsScaling (layer)) { - memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop)); - mCurrentFrame.dropCount = 0; - return false; - } - - if (layer->blending == HWC_BLENDING_NONE && - layer->planeAlpha == 0xFF) { - visibleRectL = deductRect(visibleRectL, l_res); - visibleRectR = deductRect(visibleRectR, r_res); - } - } - } - return true; -} -/* Calculate ROI for the frame by accounting all the layer's dispalyFrame which - * are updating. If DirtyRegion is applicable, calculate it by accounting all - * the changing layer's dirtyRegion. */ -void MDPCompSplit::generateROI(hwc_context_t *ctx, - hwc_display_contents_1_t* list) { - if(!canPartialUpdate(ctx, list)) - return; - - int numAppLayers = ctx->listStats[mDpy].numAppLayers; - int lSplit = getLeftSplit(ctx, mDpy); - - int hw_h = (int)ctx->dpyAttr[mDpy].yres; - int hw_w = (int)ctx->dpyAttr[mDpy].xres; - - struct hwc_rect l_frame = (struct hwc_rect){0, 0, lSplit, hw_h}; - struct hwc_rect r_frame = (struct hwc_rect){lSplit, 0, hw_w, hw_h}; - - struct hwc_rect l_roi = (struct hwc_rect){0, 0, 0, 0}; - struct hwc_rect r_roi = (struct hwc_rect){0, 0, 0, 0}; - - for(int index = 0; index < numAppLayers; index++ ) { - hwc_layer_1_t* layer = &list->hwLayers[index]; - private_handle_t *hnd = (private_handle_t *)layer->handle; - if (layerUpdating(layer) || isYuvBuffer(hnd)) { - hwc_rect_t l_dirtyRect = (struct hwc_rect){0, 0, 0, 0}; - hwc_rect_t r_dirtyRect = (struct hwc_rect){0, 0, 0, 0}; - if(!needsScaling(layer) && !layer->transform) - { - l_dirtyRect = calculateDirtyRect(layer, l_frame); - r_dirtyRect = calculateDirtyRect(layer, r_frame); - } - if(isValidRect(l_dirtyRect)) - l_roi = getUnion(l_roi, l_dirtyRect); - - if(isValidRect(r_dirtyRect)) - r_roi = getUnion(r_roi, r_dirtyRect); - } - } - - /* For panels that cannot accept commands in both the interfaces, we cannot - * send two ROI's (for each half). We merge them into single ROI and split - * them across lSplit for MDP mixer use. The ROI's will be merged again - * finally before udpating the panel in the driver. */ - if(qdutils::MDPVersion::getInstance().needsROIMerge()) { - hwc_rect_t temp_roi = getUnion(l_roi, r_roi); - l_roi = getIntersection(temp_roi, l_frame); - r_roi = getIntersection(temp_roi, r_frame); - } - - /* No layer is updating. Still SF wants a refresh. */ - if(!isValidRect(l_roi) && !isValidRect(r_roi)) - return; - - l_roi = getSanitizeROI(l_roi, l_frame); - r_roi = getSanitizeROI(r_roi, r_frame); - - ctx->listStats[mDpy].lRoi = l_roi; - ctx->listStats[mDpy].rRoi = r_roi; - - if(!validateAndApplyROI(ctx, list)) - resetROI(ctx, mDpy); - - ALOGD_IF(isDebug(),"%s: generated L_ROI: [%d, %d, %d, %d]" - "R_ROI: [%d, %d, %d, %d]", __FUNCTION__, - ctx->listStats[mDpy].lRoi.left, ctx->listStats[mDpy].lRoi.top, - ctx->listStats[mDpy].lRoi.right, ctx->listStats[mDpy].lRoi.bottom, - ctx->listStats[mDpy].rRoi.left, ctx->listStats[mDpy].rRoi.top, - ctx->listStats[mDpy].rRoi.right, ctx->listStats[mDpy].rRoi.bottom); -} - -/* Checks for conditions where all the layers marked for MDP comp cannot be - * bypassed. On such conditions we try to bypass atleast YUV layers */ -bool MDPComp::tryFullFrame(hwc_context_t *ctx, - hwc_display_contents_1_t* list){ - - const int numAppLayers = ctx->listStats[mDpy].numAppLayers; - int priDispW = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres; - - // Fall back to video only composition, if AIV video mode is enabled - if(ctx->listStats[mDpy].mAIVVideoMode) { - ALOGD_IF(isDebug(), "%s: AIV Video Mode enabled dpy %d", - __FUNCTION__, mDpy); - return false; - } - - // No Idle fall back, if secure display or secure RGB layers are present or - // if there's only a single layer being composed - if(sIdleFallBack && (!ctx->listStats[mDpy].secureUI && - !ctx->listStats[mDpy].secureRGBCount) && - (ctx->listStats[mDpy].numAppLayers != 1)) { - ALOGD_IF(isDebug(), "%s: Idle fallback dpy %d",__FUNCTION__, mDpy); - return false; - } - - if(!mDpy && isSecondaryAnimating(ctx) && - (isYuvPresent(ctx,HWC_DISPLAY_EXTERNAL) || - isYuvPresent(ctx,HWC_DISPLAY_VIRTUAL)) ) { - ALOGD_IF(isDebug(),"%s: Display animation in progress", - __FUNCTION__); - return false; - } - - // if secondary is configuring or Padding round, fall back to video only - // composition and release all assigned non VIG pipes from primary. - if(isSecondaryConfiguring(ctx)) { - ALOGD_IF( isDebug(),"%s: External Display connection is pending", - __FUNCTION__); - return false; - } else if(ctx->isPaddingRound) { - ALOGD_IF(isDebug(), "%s: padding round invoked for dpy %d", - __FUNCTION__,mDpy); - return false; - } - - MDPVersion& mdpHw = MDPVersion::getInstance(); - if(mDpy > HWC_DISPLAY_PRIMARY && - (priDispW > (int) mdpHw.getMaxMixerWidth()) && - (ctx->dpyAttr[mDpy].xres < mdpHw.getMaxMixerWidth())) { - // Disable MDP comp on Secondary when the primary is highres panel and - // the secondary is a normal 1080p, because, MDP comp on secondary under - // in such usecase, decimation gets used for downscale and there will be - // a quality mismatch when there will be a fallback to GPU comp - ALOGD_IF(isDebug(), "%s: Disable MDP Compositon for Secondary Disp", - __FUNCTION__); - return false; - } - - // check for action safe flag and MDP scaling mode which requires scaling. - if(ctx->dpyAttr[mDpy].mActionSafePresent - || ctx->dpyAttr[mDpy].mMDPScalingMode) { - ALOGD_IF(isDebug(), "%s: Scaling needed for this frame",__FUNCTION__); - return false; - } - - for(int i = 0; i < numAppLayers; ++i) { - hwc_layer_1_t* layer = &list->hwLayers[i]; - private_handle_t *hnd = (private_handle_t *)layer->handle; - - if(has90Transform(layer) && isRotationDoable(ctx, hnd)) { - if(!canUseRotator(ctx, mDpy)) { - ALOGD_IF(isDebug(), "%s: Can't use rotator for dpy %d", - __FUNCTION__, mDpy); - return false; - } - } - - //For 8x26 with panel width>1k, if RGB layer needs HFLIP fail mdp comp - // may not need it if Gfx pre-rotation can handle all flips & rotations - int transform = (layer->flags & HWC_COLOR_FILL) ? 0 : layer->transform; - if( mdpHw.is8x26() && (ctx->dpyAttr[mDpy].xres > 1024) && - (transform & HWC_TRANSFORM_FLIP_H) && (!isYuvBuffer(hnd))) - return false; - } - - if(ctx->mAD->isDoable()) { - return false; - } - - //If all above hard conditions are met we can do full or partial MDP comp. - bool ret = false; - if(fullMDPComp(ctx, list)) { - ret = true; - } else if(fullMDPCompWithPTOR(ctx, list)) { - ret = true; - } else if(partialMDPComp(ctx, list)) { - ret = true; - } - - return ret; -} - -bool MDPComp::fullMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list) { - - if(sSimulationFlags & MDPCOMP_AVOID_FULL_MDP) - return false; - - //Will benefit presentation / secondary-only layer. - if((mDpy > HWC_DISPLAY_PRIMARY) && - (list->numHwLayers - 1) > MAX_SEC_LAYERS) { - ALOGD_IF(isDebug(), "%s: Exceeds max secondary pipes",__FUNCTION__); - return false; - } - - const int numAppLayers = ctx->listStats[mDpy].numAppLayers; - for(int i = 0; i < numAppLayers; i++) { - hwc_layer_1_t* layer = &list->hwLayers[i]; - if(not mCurrentFrame.drop[i] and - not isSupportedForMDPComp(ctx, layer)) { - ALOGD_IF(isDebug(), "%s: Unsupported layer in list",__FUNCTION__); - return false; - } - } - - if(!mDpy && isSecondaryConnected(ctx) && - (qdutils::MDPVersion::getInstance().is8x16() || - qdutils::MDPVersion::getInstance().is8x26() || - qdutils::MDPVersion::getInstance().is8x39()) && - isYuvPresent(ctx, HWC_DISPLAY_VIRTUAL)) { - ALOGD_IF(isDebug(), "%s: YUV layer present on secondary", __FUNCTION__); - return false; - } - - mCurrentFrame.fbCount = 0; - memcpy(&mCurrentFrame.isFBComposed, &mCurrentFrame.drop, - sizeof(mCurrentFrame.isFBComposed)); - mCurrentFrame.mdpCount = mCurrentFrame.layerCount - mCurrentFrame.fbCount - - mCurrentFrame.dropCount; - - if(sEnableYUVsplit){ - adjustForSourceSplit(ctx, list); - } - - if(!postHeuristicsHandling(ctx, list)) { - ALOGD_IF(isDebug(), "post heuristic handling failed"); - reset(ctx); - return false; - } - ALOGD_IF(sSimulationFlags,"%s: FULL_MDP_COMP SUCCEEDED", - __FUNCTION__); - return true; -} - -/* Full MDP Composition with Peripheral Tiny Overlap Removal. - * MDP bandwidth limitations can be avoided, if the overlap region - * covered by the smallest layer at a higher z-order, gets composed - * by Copybit on a render buffer, which can be queued to MDP. - */ -bool MDPComp::fullMDPCompWithPTOR(hwc_context_t *ctx, - hwc_display_contents_1_t* list) { - - const int numAppLayers = ctx->listStats[mDpy].numAppLayers; - const int stagesForMDP = min(sMaxPipesPerMixer, - ctx->mOverlay->availablePipes(mDpy, Overlay::MIXER_DEFAULT)); - - // Hard checks where we cannot use this mode - if (mDpy || !ctx->mCopyBit[mDpy]) { - ALOGD_IF(isDebug(), "%s: Feature not supported!", __FUNCTION__); - return false; - } - - // Frame level checks - if ((numAppLayers > stagesForMDP) || isSkipPresent(ctx, mDpy) || - isYuvPresent(ctx, mDpy) || mCurrentFrame.dropCount || - isSecurePresent(ctx, mDpy)) { - ALOGD_IF(isDebug(), "%s: Frame not supported!", __FUNCTION__); - return false; - } - // MDP comp checks - for(int i = 0; i < numAppLayers; i++) { - hwc_layer_1_t* layer = &list->hwLayers[i]; - if(not isSupportedForMDPComp(ctx, layer)) { - ALOGD_IF(isDebug(), "%s: Unsupported layer in list",__FUNCTION__); - return false; - } - } - - if(!mDpy && isSecondaryConnected(ctx) && - (qdutils::MDPVersion::getInstance().is8x16() || - qdutils::MDPVersion::getInstance().is8x26() || - qdutils::MDPVersion::getInstance().is8x39()) && - isYuvPresent(ctx, HWC_DISPLAY_VIRTUAL)) { - ALOGD_IF(isDebug(), "%s: YUV layer present on secondary", __FUNCTION__); - return false; - } - - /* We cannot use this composition mode, if: - 1. A below layer needs scaling. - 2. Overlap is not peripheral to display. - 3. Overlap or a below layer has 90 degree transform. - 4. Overlap area > (1/3 * FrameBuffer) area, based on Perf inputs. - */ - - int minLayerIndex[MAX_PTOR_LAYERS] = { -1, -1}; - hwc_rect_t overlapRect[MAX_PTOR_LAYERS]; - memset(overlapRect, 0, sizeof(overlapRect)); - int layerPixelCount, minPixelCount = 0; - int numPTORLayersFound = 0; - for (int i = numAppLayers-1; (i >= 0 && - numPTORLayersFound < MAX_PTOR_LAYERS); i--) { - hwc_layer_1_t* layer = &list->hwLayers[i]; - hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf); - hwc_rect_t dispFrame = layer->displayFrame; - layerPixelCount = (crop.right - crop.left) * (crop.bottom - crop.top); - // PTOR layer should be peripheral and cannot have transform - if (!isPeripheral(dispFrame, ctx->mViewFrame[mDpy]) || - has90Transform(layer)) { - continue; - } - if((3 * (layerPixelCount + minPixelCount)) > - ((int)ctx->dpyAttr[mDpy].xres * (int)ctx->dpyAttr[mDpy].yres)) { - // Overlap area > (1/3 * FrameBuffer) area, based on Perf inputs. - continue; - } - bool found = false; - for (int j = i-1; j >= 0; j--) { - // Check if the layers below this layer qualifies for PTOR comp - hwc_layer_1_t* layer = &list->hwLayers[j]; - hwc_rect_t disFrame = layer->displayFrame; - // Layer below PTOR is intersecting and has 90 degree transform or - // needs scaling cannot be supported. - if (isValidRect(getIntersection(dispFrame, disFrame))) { - if (has90Transform(layer) || needsScaling(layer)) { - found = false; - break; - } - found = true; - } - } - // Store the minLayer Index - if(found) { - minLayerIndex[numPTORLayersFound] = i; - overlapRect[numPTORLayersFound] = list->hwLayers[i].displayFrame; - minPixelCount += layerPixelCount; - numPTORLayersFound++; - } - } - - // No overlap layers - if (!numPTORLayersFound) - return false; - - // Store the displayFrame and the sourceCrops of the layers - hwc_rect_t displayFrame[numAppLayers]; - hwc_rect_t sourceCrop[numAppLayers]; - for(int i = 0; i < numAppLayers; i++) { - hwc_layer_1_t* layer = &list->hwLayers[i]; - displayFrame[i] = layer->displayFrame; - sourceCrop[i] = integerizeSourceCrop(layer->sourceCropf); - } - - /** - * It's possible that 2 PTOR layers might have overlapping. - * In such case, remove the intersection(again if peripheral) - * from the lower PTOR layer to avoid overlapping. - * If intersection is not on peripheral then compromise - * by reducing number of PTOR layers. - **/ - hwc_rect_t commonRect = getIntersection(overlapRect[0], overlapRect[1]); - if(isValidRect(commonRect)) { - overlapRect[1] = deductRect(overlapRect[1], commonRect); - list->hwLayers[minLayerIndex[1]].displayFrame = overlapRect[1]; - } - - ctx->mPtorInfo.count = numPTORLayersFound; - for(int i = 0; i < MAX_PTOR_LAYERS; i++) { - ctx->mPtorInfo.layerIndex[i] = minLayerIndex[i]; - } - - if (!ctx->mCopyBit[mDpy]->prepareOverlap(ctx, list)) { - // reset PTOR - ctx->mPtorInfo.count = 0; - if(isValidRect(commonRect)) { - // If PTORs are intersecting restore displayframe of PTOR[1] - // before returning, as we have modified it above. - list->hwLayers[minLayerIndex[1]].displayFrame = - displayFrame[minLayerIndex[1]]; - } - return false; - } - private_handle_t *renderBuf = ctx->mCopyBit[mDpy]->getCurrentRenderBuffer(); - Whf layerWhf[MAX_PTOR_LAYERS]; // To store w,h,f of PTOR layers - - // Store the blending mode, planeAlpha, and transform of PTOR layers - int32_t blending[numPTORLayersFound]; - uint8_t planeAlpha[numPTORLayersFound]; - uint32_t transform[numPTORLayersFound]; - - for(int j = 0; j < numPTORLayersFound; j++) { - int index = ctx->mPtorInfo.layerIndex[j]; - - // Update src crop of PTOR layer - hwc_layer_1_t* layer = &list->hwLayers[index]; - layer->sourceCropf.left = (float)ctx->mPtorInfo.displayFrame[j].left; - layer->sourceCropf.top = (float)ctx->mPtorInfo.displayFrame[j].top; - layer->sourceCropf.right = (float)ctx->mPtorInfo.displayFrame[j].right; - layer->sourceCropf.bottom =(float)ctx->mPtorInfo.displayFrame[j].bottom; - - // Store & update w, h, format of PTOR layer - private_handle_t *hnd = (private_handle_t *)layer->handle; - Whf whf(hnd->width, hnd->height, hnd->format, hnd->size); - layerWhf[j] = whf; - hnd->width = renderBuf->width; - hnd->height = renderBuf->height; - hnd->format = renderBuf->format; - - // Store & update blending mode, planeAlpha and transform of PTOR layer - blending[j] = layer->blending; - planeAlpha[j] = layer->planeAlpha; - transform[j] = layer->transform; - layer->blending = HWC_BLENDING_NONE; - layer->planeAlpha = 0xFF; - layer->transform = 0; - - // Remove overlap from crop & displayFrame of below layers - for (int i = 0; i < index && index !=-1; i++) { - layer = &list->hwLayers[i]; - if(!isValidRect(getIntersection(layer->displayFrame, - overlapRect[j]))) { - continue; - } - // Update layer attributes - hwc_rect_t srcCrop = integerizeSourceCrop(layer->sourceCropf); - hwc_rect_t destRect = deductRect(layer->displayFrame, - getIntersection(layer->displayFrame, overlapRect[j])); - qhwc::calculate_crop_rects(srcCrop, layer->displayFrame, destRect, - layer->transform); - layer->sourceCropf.left = (float)srcCrop.left; - layer->sourceCropf.top = (float)srcCrop.top; - layer->sourceCropf.right = (float)srcCrop.right; - layer->sourceCropf.bottom = (float)srcCrop.bottom; - } - } - - mCurrentFrame.mdpCount = numAppLayers; - mCurrentFrame.fbCount = 0; - mCurrentFrame.fbZ = -1; - - for (int j = 0; j < numAppLayers; j++) { - if(isValidRect(list->hwLayers[j].displayFrame)) { - mCurrentFrame.isFBComposed[j] = false; - } else { - mCurrentFrame.mdpCount--; - mCurrentFrame.drop[j] = true; - } - } - - bool result = postHeuristicsHandling(ctx, list); - - // Restore layer attributes - for(int i = 0; i < numAppLayers; i++) { - hwc_layer_1_t* layer = &list->hwLayers[i]; - layer->displayFrame = displayFrame[i]; - layer->sourceCropf.left = (float)sourceCrop[i].left; - layer->sourceCropf.top = (float)sourceCrop[i].top; - layer->sourceCropf.right = (float)sourceCrop[i].right; - layer->sourceCropf.bottom = (float)sourceCrop[i].bottom; - } - - // Restore w,h,f, blending attributes, and transform of PTOR layers - for (int i = 0; i < numPTORLayersFound; i++) { - int idx = ctx->mPtorInfo.layerIndex[i]; - hwc_layer_1_t* layer = &list->hwLayers[idx]; - private_handle_t *hnd = (private_handle_t *)list->hwLayers[idx].handle; - hnd->width = layerWhf[i].w; - hnd->height = layerWhf[i].h; - hnd->format = layerWhf[i].format; - layer->blending = blending[i]; - layer->planeAlpha = planeAlpha[i]; - layer->transform = transform[i]; - } - - if (!result) { - // reset PTOR - ctx->mPtorInfo.count = 0; - reset(ctx); - } else { - ALOGD_IF(isDebug(), "%s: PTOR Indexes: %d and %d", __FUNCTION__, - ctx->mPtorInfo.layerIndex[0], ctx->mPtorInfo.layerIndex[1]); - } - - ALOGD_IF(isDebug(), "%s: Postheuristics %s!", __FUNCTION__, - (result ? "successful" : "failed")); - return result; -} - -bool MDPComp::partialMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list) -{ - if(!sEnableMixedMode || !isAlphaPresentinFB(ctx, mDpy)) { - //Mixed mode is disabled/can't be used. No need to even try caching. - return false; - } - - bool ret = false; - if(isSkipPresent(ctx, mDpy) or list->flags & HWC_GEOMETRY_CHANGED) { - //Try load based first - ret = loadBasedComp(ctx, list) or - cacheBasedComp(ctx, list); - } else { - ret = cacheBasedComp(ctx, list) or - loadBasedComp(ctx, list); - } - - return ret; -} - -bool MDPComp::cacheBasedComp(hwc_context_t *ctx, - hwc_display_contents_1_t* list) { - if(sSimulationFlags & MDPCOMP_AVOID_CACHE_MDP) - return false; - - int numAppLayers = ctx->listStats[mDpy].numAppLayers; - mCurrentFrame.reset(numAppLayers); - updateLayerCache(ctx, list, mCurrentFrame); - - //If an MDP marked layer is unsupported cannot do partial MDP Comp - for(int i = 0; i < numAppLayers; i++) { - if(!mCurrentFrame.isFBComposed[i]) { - hwc_layer_1_t* layer = &list->hwLayers[i]; - if(not isSupportedForMDPComp(ctx, layer)) { - ALOGD_IF(isDebug(), "%s: Unsupported layer in list", - __FUNCTION__); - reset(ctx); - return false; - } - } - } - - updateYUV(ctx, list, false /*secure only*/, mCurrentFrame); - /* mark secure RGB layers for MDP comp */ - updateSecureRGB(ctx, list); - bool ret = markLayersForCaching(ctx, list); //sets up fbZ also - if(!ret) { - ALOGD_IF(isDebug(),"%s: batching failed, dpy %d",__FUNCTION__, mDpy); - reset(ctx); - return false; - } - - int mdpCount = mCurrentFrame.mdpCount; - - if(sEnableYUVsplit){ - adjustForSourceSplit(ctx, list); - } - - //Will benefit cases where a video has non-updating background. - if((mDpy > HWC_DISPLAY_PRIMARY) and - (mdpCount > MAX_SEC_LAYERS)) { - ALOGD_IF(isDebug(), "%s: Exceeds max secondary pipes",__FUNCTION__); - reset(ctx); - return false; - } - - if(!postHeuristicsHandling(ctx, list)) { - ALOGD_IF(isDebug(), "post heuristic handling failed"); - reset(ctx); - return false; - } - ALOGD_IF(sSimulationFlags,"%s: CACHE_MDP_COMP SUCCEEDED", - __FUNCTION__); - - return true; -} - -bool MDPComp::loadBasedComp(hwc_context_t *ctx, - hwc_display_contents_1_t* list) { - if(sSimulationFlags & MDPCOMP_AVOID_LOAD_MDP) - return false; - - if(not isLoadBasedCompDoable(ctx)) { - return false; - } - - const int numAppLayers = ctx->listStats[mDpy].numAppLayers; - const int numNonDroppedLayers = numAppLayers - mCurrentFrame.dropCount; - const int stagesForMDP = min(sMaxPipesPerMixer, - ctx->mOverlay->availablePipes(mDpy, Overlay::MIXER_DEFAULT)); - - int mdpBatchSize = stagesForMDP - 1; //1 stage for FB - int fbBatchSize = numNonDroppedLayers - mdpBatchSize; - int lastMDPSupportedIndex = numAppLayers; - int dropCount = 0; - - //Find the minimum MDP batch size - for(int i = 0; i < numAppLayers;i++) { - if(mCurrentFrame.drop[i]) { - dropCount++; - continue; - } - hwc_layer_1_t* layer = &list->hwLayers[i]; - if(not isSupportedForMDPComp(ctx, layer)) { - lastMDPSupportedIndex = i; - mdpBatchSize = min(i - dropCount, stagesForMDP - 1); - fbBatchSize = numNonDroppedLayers - mdpBatchSize; - break; - } - } - - ALOGD_IF(isDebug(), "%s:Before optimizing fbBatch, mdpbatch %d, fbbatch %d " - "dropped %d", __FUNCTION__, mdpBatchSize, fbBatchSize, - mCurrentFrame.dropCount); - - //Start at a point where the fb batch should at least have 2 layers, for - //this mode to be justified. - while(fbBatchSize < 2) { - ++fbBatchSize; - --mdpBatchSize; - } - - //If there are no layers for MDP, this mode doesnt make sense. - if(mdpBatchSize < 1) { - ALOGD_IF(isDebug(), "%s: No MDP layers after optimizing for fbBatch", - __FUNCTION__); - return false; - } - - mCurrentFrame.reset(numAppLayers); - - //Try with successively smaller mdp batch sizes until we succeed or reach 1 - while(mdpBatchSize > 0) { - //Mark layers for MDP comp - int mdpBatchLeft = mdpBatchSize; - for(int i = 0; i < lastMDPSupportedIndex and mdpBatchLeft; i++) { - if(mCurrentFrame.drop[i]) { - continue; - } - mCurrentFrame.isFBComposed[i] = false; - --mdpBatchLeft; - } - - mCurrentFrame.fbZ = mdpBatchSize; - mCurrentFrame.fbCount = fbBatchSize; - mCurrentFrame.mdpCount = mdpBatchSize; - - ALOGD_IF(isDebug(), "%s:Trying with: mdpbatch %d fbbatch %d dropped %d", - __FUNCTION__, mdpBatchSize, fbBatchSize, - mCurrentFrame.dropCount); - - if(postHeuristicsHandling(ctx, list)) { - ALOGD_IF(isDebug(), "%s: Postheuristics handling succeeded", - __FUNCTION__); - ALOGD_IF(sSimulationFlags,"%s: LOAD_MDP_COMP SUCCEEDED", - __FUNCTION__); - return true; - } - - reset(ctx); - --mdpBatchSize; - ++fbBatchSize; - } - - return false; -} - -bool MDPComp::isLoadBasedCompDoable(hwc_context_t *ctx) { - if(mDpy or isSecurePresent(ctx, mDpy) or - isYuvPresent(ctx, mDpy)) { - return false; - } - return true; -} - -bool MDPComp::canPartialUpdate(hwc_context_t *ctx, - hwc_display_contents_1_t* list){ - if(!qdutils::MDPVersion::getInstance().isPartialUpdateEnabled() || - isSkipPresent(ctx, mDpy) || (list->flags & HWC_GEOMETRY_CHANGED) || - !sIsPartialUpdateActive || mDpy ) { - return false; - } - if(ctx->listStats[mDpy].secureUI) - return false; - return true; -} - -bool MDPComp::tryVideoOnly(hwc_context_t *ctx, - hwc_display_contents_1_t* list) { - const bool secureOnly = true; - return videoOnlyComp(ctx, list, not secureOnly) or - videoOnlyComp(ctx, list, secureOnly); -} - -bool MDPComp::videoOnlyComp(hwc_context_t *ctx, - hwc_display_contents_1_t* list, bool secureOnly) { - if(sSimulationFlags & MDPCOMP_AVOID_VIDEO_ONLY) - return false; - int numAppLayers = ctx->listStats[mDpy].numAppLayers; - - mCurrentFrame.reset(numAppLayers); - mCurrentFrame.fbCount -= mCurrentFrame.dropCount; - updateYUV(ctx, list, secureOnly, mCurrentFrame); - int mdpCount = mCurrentFrame.mdpCount; - - if(!isYuvPresent(ctx, mDpy) or (mdpCount == 0)) { - reset(ctx); - return false; - } - - /* Bail out if we are processing only secured video layers - * and we dont have any */ - if(!isSecurePresent(ctx, mDpy) && secureOnly){ - reset(ctx); - return false; - } - - if(mCurrentFrame.fbCount) - mCurrentFrame.fbZ = mCurrentFrame.mdpCount; - - if(sEnableYUVsplit){ - adjustForSourceSplit(ctx, list); - } - - if(!postHeuristicsHandling(ctx, list)) { - ALOGD_IF(isDebug(), "post heuristic handling failed"); - reset(ctx); - return false; - } - - ALOGD_IF(sSimulationFlags,"%s: VIDEO_ONLY_COMP SUCCEEDED", - __FUNCTION__); - return true; -} - -/* if tryFullFrame fails, try to push all video and secure RGB layers to MDP */ -bool MDPComp::tryMDPOnlyLayers(hwc_context_t *ctx, - hwc_display_contents_1_t* list) { - // Fall back to video only composition, if AIV video mode is enabled - if(ctx->listStats[mDpy].mAIVVideoMode) { - ALOGD_IF(isDebug(), "%s: AIV Video Mode enabled dpy %d", - __FUNCTION__, mDpy); - return false; - } - - const bool secureOnly = true; - return mdpOnlyLayersComp(ctx, list, not secureOnly) or - mdpOnlyLayersComp(ctx, list, secureOnly); - -} - -bool MDPComp::mdpOnlyLayersComp(hwc_context_t *ctx, - hwc_display_contents_1_t* list, bool secureOnly) { - - if(sSimulationFlags & MDPCOMP_AVOID_MDP_ONLY_LAYERS) - return false; - - /* Bail out if we are processing only secured video layers - * and we dont have any */ - if(!isSecurePresent(ctx, mDpy) && secureOnly){ - reset(ctx); - return false; - } - - int numAppLayers = ctx->listStats[mDpy].numAppLayers; - mCurrentFrame.reset(numAppLayers); - mCurrentFrame.fbCount -= mCurrentFrame.dropCount; - - updateYUV(ctx, list, secureOnly, mCurrentFrame); - /* mark secure RGB layers for MDP comp */ - updateSecureRGB(ctx, list); - - if(mCurrentFrame.mdpCount == 0) { - reset(ctx); - return false; - } - - /* find the maximum batch of layers to be marked for framebuffer */ - bool ret = markLayersForCaching(ctx, list); //sets up fbZ also - if(!ret) { - ALOGD_IF(isDebug(),"%s: batching failed, dpy %d",__FUNCTION__, mDpy); - reset(ctx); - return false; - } - - if(sEnableYUVsplit){ - adjustForSourceSplit(ctx, list); - } - - if(!postHeuristicsHandling(ctx, list)) { - ALOGD_IF(isDebug(), "post heuristic handling failed"); - reset(ctx); - return false; - } - - ALOGD_IF(sSimulationFlags,"%s: MDP_ONLY_LAYERS_COMP SUCCEEDED", - __FUNCTION__); - return true; -} - -/* Checks for conditions where YUV layers cannot be bypassed */ -bool MDPComp::isYUVDoable(hwc_context_t* ctx, hwc_layer_1_t* layer) { - if(isSkipLayer(layer)) { - ALOGD_IF(isDebug(), "%s: Video marked SKIP dpy %d", __FUNCTION__, mDpy); - return false; - } - - if(has90Transform(layer) && !canUseRotator(ctx, mDpy)) { - ALOGD_IF(isDebug(), "%s: no free DMA pipe",__FUNCTION__); - return false; - } - - if(isSecuring(ctx, layer)) { - ALOGD_IF(isDebug(), "%s: MDP securing is active", __FUNCTION__); - return false; - } - - if(!isValidDimension(ctx, layer)) { - ALOGD_IF(isDebug(), "%s: Buffer is of invalid width", - __FUNCTION__); - return false; - } - - if(layer->planeAlpha < 0xFF) { - ALOGD_IF(isDebug(), "%s: Cannot handle YUV layer with plane alpha\ - in video only mode", - __FUNCTION__); - return false; - } - - return true; -} - -/* Checks for conditions where Secure RGB layers cannot be bypassed */ -bool MDPComp::isSecureRGBDoable(hwc_context_t* ctx, hwc_layer_1_t* layer) { - if(isSkipLayer(layer)) { - ALOGD_IF(isDebug(), "%s: Secure RGB layer marked SKIP dpy %d", - __FUNCTION__, mDpy); - return false; - } - - if(isSecuring(ctx, layer)) { - ALOGD_IF(isDebug(), "%s: MDP securing is active", __FUNCTION__); - return false; - } - - if(not isSupportedForMDPComp(ctx, layer)) { - ALOGD_IF(isDebug(), "%s: Unsupported secure RGB layer", - __FUNCTION__); - return false; - } - return true; -} - -/* starts at fromIndex and check for each layer to find - * if it it has overlapping with any Updating layer above it in zorder - * till the end of the batch. returns true if it finds any intersection */ -bool MDPComp::canPushBatchToTop(const hwc_display_contents_1_t* list, - int fromIndex, int toIndex) { - for(int i = fromIndex; i < toIndex; i++) { - if(mCurrentFrame.isFBComposed[i] && !mCurrentFrame.drop[i]) { - if(intersectingUpdatingLayers(list, i+1, toIndex, i)) { - return false; - } - } - } - return true; -} - -/* Checks if given layer at targetLayerIndex has any - * intersection with all the updating layers in beween - * fromIndex and toIndex. Returns true if it finds intersectiion */ -bool MDPComp::intersectingUpdatingLayers(const hwc_display_contents_1_t* list, - int fromIndex, int toIndex, int targetLayerIndex) { - for(int i = fromIndex; i <= toIndex; i++) { - if(!mCurrentFrame.isFBComposed[i]) { - if(areLayersIntersecting(&list->hwLayers[i], - &list->hwLayers[targetLayerIndex])) { - return true; - } - } - } - return false; -} - -int MDPComp::getBatch(hwc_display_contents_1_t* list, - int& maxBatchStart, int& maxBatchEnd, - int& maxBatchCount) { - int i = 0; - int fbZOrder =-1; - int droppedLayerCt = 0; - while (i < mCurrentFrame.layerCount) { - int batchCount = 0; - int batchStart = i; - int batchEnd = i; - /* Adjust batch Z order with the dropped layers so far */ - int fbZ = batchStart - droppedLayerCt; - int firstZReverseIndex = -1; - int updatingLayersAbove = 0;//Updating layer count in middle of batch - while(i < mCurrentFrame.layerCount) { - if(!mCurrentFrame.isFBComposed[i]) { - if(!batchCount) { - i++; - break; - } - updatingLayersAbove++; - i++; - continue; - } else { - if(mCurrentFrame.drop[i]) { - i++; - droppedLayerCt++; - continue; - } else if(updatingLayersAbove <= 0) { - batchCount++; - batchEnd = i; - i++; - continue; - } else { //Layer is FBComposed, not a drop & updatingLayer > 0 - - // We have a valid updating layer already. If layer-i not - // have overlapping with all updating layers in between - // batch-start and i, then we can add layer i to batch. - if(!intersectingUpdatingLayers(list, batchStart, i-1, i)) { - batchCount++; - batchEnd = i; - i++; - continue; - } else if(canPushBatchToTop(list, batchStart, i)) { - //If All the non-updating layers with in this batch - //does not have intersection with the updating layers - //above in z-order, then we can safely move the batch to - //higher z-order. Increment fbZ as it is moving up. - if( firstZReverseIndex < 0) { - firstZReverseIndex = i; - } - batchCount++; - batchEnd = i; - fbZ += updatingLayersAbove; - i++; - updatingLayersAbove = 0; - continue; - } else { - //both failed.start the loop again from here. - if(firstZReverseIndex >= 0) { - i = firstZReverseIndex; - } - break; - } - } - } - } - if(batchCount > maxBatchCount) { - maxBatchCount = batchCount; - maxBatchStart = batchStart; - maxBatchEnd = batchEnd; - fbZOrder = fbZ; - } - } - return fbZOrder; -} - -bool MDPComp::markLayersForCaching(hwc_context_t* ctx, - hwc_display_contents_1_t* list) { - /* Idea is to keep as many non-updating(cached) layers in FB and - * send rest of them through MDP. This is done in 2 steps. - * 1. Find the maximum contiguous batch of non-updating layers. - * 2. See if we can improve this batch size for caching by adding - * opaque layers around the batch, if they don't have - * any overlapping with the updating layers in between. - * NEVER mark an updating layer for caching. - * But cached ones can be marked for MDP */ - - int maxBatchStart = -1; - int maxBatchEnd = -1; - int maxBatchCount = 0; - int fbZ = -1; - - /* Nothing is cached. No batching needed */ - if(mCurrentFrame.fbCount == 0) { - return true; - } - - /* No MDP comp layers, try to use other comp modes */ - if(mCurrentFrame.mdpCount == 0) { - return false; - } - - fbZ = getBatch(list, maxBatchStart, maxBatchEnd, maxBatchCount); - - /* reset rest of the layers lying inside ROI for MDP comp */ - for(int i = 0; i < mCurrentFrame.layerCount; i++) { - hwc_layer_1_t* layer = &list->hwLayers[i]; - if((i < maxBatchStart || i > maxBatchEnd) && - mCurrentFrame.isFBComposed[i]){ - if(!mCurrentFrame.drop[i]){ - //If an unsupported layer is being attempted to - //be pulled out we should fail - if(not isSupportedForMDPComp(ctx, layer)) { - return false; - } - mCurrentFrame.isFBComposed[i] = false; - } - } - } - - // update the frame data - mCurrentFrame.fbZ = fbZ; - mCurrentFrame.fbCount = maxBatchCount; - mCurrentFrame.mdpCount = mCurrentFrame.layerCount - - mCurrentFrame.fbCount - mCurrentFrame.dropCount; - - ALOGD_IF(isDebug(),"%s: cached count: %d",__FUNCTION__, - mCurrentFrame.fbCount); - - return true; -} - -void MDPComp::updateLayerCache(hwc_context_t* ctx, - hwc_display_contents_1_t* list, FrameInfo& frame) { - int numAppLayers = ctx->listStats[mDpy].numAppLayers; - int fbCount = 0; - - for(int i = 0; i < numAppLayers; i++) { - hwc_layer_1_t * layer = &list->hwLayers[i]; - if (!layerUpdating(layer)) { - if(!frame.drop[i]) - fbCount++; - frame.isFBComposed[i] = true; - } else { - frame.isFBComposed[i] = false; - } - } - - frame.fbCount = fbCount; - frame.mdpCount = frame.layerCount - frame.fbCount - - frame.dropCount; - - ALOGD_IF(isDebug(),"%s: MDP count: %d FB count %d drop count: %d", - __FUNCTION__, frame.mdpCount, frame.fbCount, frame.dropCount); -} - -// drop other non-AIV layers from external display list. -void MDPComp::dropNonAIVLayers(hwc_context_t* ctx, - hwc_display_contents_1_t* list) { - for (size_t i = 0; i < (size_t)ctx->listStats[mDpy].numAppLayers; i++) { - hwc_layer_1_t * layer = &list->hwLayers[i]; - if(!(isAIVVideoLayer(layer) || isAIVCCLayer(layer))) { - mCurrentFrame.dropCount++; - mCurrentFrame.drop[i] = true; - } - } - mCurrentFrame.fbCount -= mCurrentFrame.dropCount; - mCurrentFrame.mdpCount = mCurrentFrame.layerCount - - mCurrentFrame.fbCount - mCurrentFrame.dropCount; - ALOGD_IF(isDebug(),"%s: fb count: %d mdp count %d drop count %d", - __FUNCTION__, mCurrentFrame.fbCount, mCurrentFrame.mdpCount, - mCurrentFrame.dropCount); -} - -void MDPComp::updateYUV(hwc_context_t* ctx, hwc_display_contents_1_t* list, - bool secureOnly, FrameInfo& frame) { - int nYuvCount = ctx->listStats[mDpy].yuvCount; - for(int index = 0;index < nYuvCount; index++){ - int nYuvIndex = ctx->listStats[mDpy].yuvIndices[index]; - hwc_layer_1_t* layer = &list->hwLayers[nYuvIndex]; - - if(mCurrentFrame.drop[nYuvIndex]) { - continue; - } - - if(!isYUVDoable(ctx, layer)) { - if(!frame.isFBComposed[nYuvIndex]) { - frame.isFBComposed[nYuvIndex] = true; - frame.fbCount++; - } - } else { - if(frame.isFBComposed[nYuvIndex]) { - private_handle_t *hnd = (private_handle_t *)layer->handle; - if(!secureOnly || isSecureBuffer(hnd)) { - frame.isFBComposed[nYuvIndex] = false; - frame.fbCount--; - } - } - } - } - - frame.mdpCount = frame.layerCount - frame.fbCount - frame.dropCount; - ALOGD_IF(isDebug(),"%s: fb count: %d",__FUNCTION__, frame.fbCount); -} - -void MDPComp::updateSecureRGB(hwc_context_t* ctx, - hwc_display_contents_1_t* list) { - int nSecureRGBCount = ctx->listStats[mDpy].secureRGBCount; - for(int index = 0;index < nSecureRGBCount; index++){ - int nSecureRGBIndex = ctx->listStats[mDpy].secureRGBIndices[index]; - hwc_layer_1_t* layer = &list->hwLayers[nSecureRGBIndex]; - - if(!isSecureRGBDoable(ctx, layer)) { - if(!mCurrentFrame.isFBComposed[nSecureRGBIndex]) { - mCurrentFrame.isFBComposed[nSecureRGBIndex] = true; - mCurrentFrame.fbCount++; - } - } else { - if(mCurrentFrame.isFBComposed[nSecureRGBIndex]) { - mCurrentFrame.isFBComposed[nSecureRGBIndex] = false; - mCurrentFrame.fbCount--; - } - } - } - - mCurrentFrame.mdpCount = mCurrentFrame.layerCount - - mCurrentFrame.fbCount - mCurrentFrame.dropCount; - ALOGD_IF(isDebug(),"%s: fb count: %d",__FUNCTION__, - mCurrentFrame.fbCount); -} - -hwc_rect_t MDPComp::getUpdatingFBRect(hwc_context_t *ctx, - hwc_display_contents_1_t* list){ - hwc_rect_t fbRect = (struct hwc_rect){0, 0, 0, 0}; - - /* Update only the region of FB needed for composition */ - for(int i = 0; i < mCurrentFrame.layerCount; i++ ) { - if(mCurrentFrame.isFBComposed[i] && !mCurrentFrame.drop[i]) { - hwc_layer_1_t* layer = &list->hwLayers[i]; - hwc_rect_t dst = layer->displayFrame; - fbRect = getUnion(fbRect, dst); - } - } - trimAgainstROI(ctx, fbRect); - return fbRect; -} - -bool MDPComp::postHeuristicsHandling(hwc_context_t *ctx, - hwc_display_contents_1_t* list) { - - //Capability checks - if(!resourceCheck(ctx, list)) { - ALOGD_IF(isDebug(), "%s: resource check failed", __FUNCTION__); - return false; - } - - //Limitations checks - if(!hwLimitationsCheck(ctx, list)) { - ALOGD_IF(isDebug(), "%s: HW limitations",__FUNCTION__); - return false; - } - - //Configure framebuffer first if applicable - if(mCurrentFrame.fbZ >= 0) { - hwc_rect_t fbRect = getUpdatingFBRect(ctx, list); - if(!ctx->mFBUpdate[mDpy]->prepare(ctx, list, fbRect, mCurrentFrame.fbZ)) - { - ALOGD_IF(isDebug(), "%s configure framebuffer failed", - __FUNCTION__); - return false; - } - } - - mCurrentFrame.map(); - - if(!allocLayerPipes(ctx, list)) { - ALOGD_IF(isDebug(), "%s: Unable to allocate MDP pipes", __FUNCTION__); - return false; - } - - for (int index = 0, mdpNextZOrder = 0; index < mCurrentFrame.layerCount; - index++) { - if(!mCurrentFrame.isFBComposed[index]) { - int mdpIndex = mCurrentFrame.layerToMDP[index]; - hwc_layer_1_t* layer = &list->hwLayers[index]; - - //Leave fbZ for framebuffer. CACHE/GLES layers go here. - if(mdpNextZOrder == mCurrentFrame.fbZ) { - mdpNextZOrder++; - } - MdpPipeInfo* cur_pipe = mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo; - cur_pipe->zOrder = mdpNextZOrder++; - - private_handle_t *hnd = (private_handle_t *)layer->handle; - if(isYUVSplitNeeded(hnd) && sEnableYUVsplit){ - if(configure4k2kYuv(ctx, layer, - mCurrentFrame.mdpToLayer[mdpIndex]) - != 0 ){ - ALOGD_IF(isDebug(), "%s: Failed to configure split pipes \ - for layer %d",__FUNCTION__, index); - return false; - } - else{ - mdpNextZOrder++; - } - continue; - } - if(configure(ctx, layer, mCurrentFrame.mdpToLayer[mdpIndex]) != 0 ){ - ALOGD_IF(isDebug(), "%s: Failed to configure overlay for \ - layer %d",__FUNCTION__, index); - return false; - } - } - } - - if(!ctx->mOverlay->validateAndSet(mDpy, ctx->dpyAttr[mDpy].fd)) { - ALOGD_IF(isDebug(), "%s: Failed to validate and set overlay for dpy %d" - ,__FUNCTION__, mDpy); - return false; - } - - setRedraw(ctx, list); - return true; -} - -bool MDPComp::resourceCheck(hwc_context_t* ctx, - hwc_display_contents_1_t* list) { - const bool fbUsed = mCurrentFrame.fbCount; - if(mCurrentFrame.mdpCount > sMaxPipesPerMixer - fbUsed) { - ALOGD_IF(isDebug(), "%s: Exceeds MAX_PIPES_PER_MIXER",__FUNCTION__); - return false; - } - // Init rotCount to number of rotate sessions used by other displays - int rotCount = ctx->mRotMgr->getNumActiveSessions(); - // Count the number of rotator sessions required for current display - for (int index = 0; index < mCurrentFrame.layerCount; index++) { - if(!mCurrentFrame.isFBComposed[index]) { - hwc_layer_1_t* layer = &list->hwLayers[index]; - private_handle_t *hnd = (private_handle_t *)layer->handle; - if(has90Transform(layer) && isRotationDoable(ctx, hnd)) { - rotCount++; - } - } - } - // if number of layers to rotate exceeds max rotator sessions, bail out. - if(rotCount > RotMgr::MAX_ROT_SESS) { - ALOGD_IF(isDebug(), "%s: Exceeds max rotator sessions %d", - __FUNCTION__, mDpy); - return false; - } - return true; -} - -bool MDPComp::hwLimitationsCheck(hwc_context_t* ctx, - hwc_display_contents_1_t* list) { - - //A-family hw limitation: - //If a layer need alpha scaling, MDP can not support. - if(ctx->mMDP.version < qdutils::MDSS_V5) { - for(int i = 0; i < mCurrentFrame.layerCount; ++i) { - if(!mCurrentFrame.isFBComposed[i] && - isAlphaScaled( &list->hwLayers[i])) { - ALOGD_IF(isDebug(), "%s:frame needs alphaScaling",__FUNCTION__); - return false; - } - } - } - - // On 8x26 & 8974 hw, we have a limitation of downscaling+blending. - //If multiple layers requires downscaling and also they are overlapping - //fall back to GPU since MDSS can not handle it. - if(qdutils::MDPVersion::getInstance().is8x74v2() || - qdutils::MDPVersion::getInstance().is8x26()) { - for(int i = 0; i < mCurrentFrame.layerCount-1; ++i) { - hwc_layer_1_t* botLayer = &list->hwLayers[i]; - if(!mCurrentFrame.isFBComposed[i] && - isDownscaleRequired(botLayer)) { - //if layer-i is marked for MDP and needs downscaling - //check if any MDP layer on top of i & overlaps with layer-i - for(int j = i+1; j < mCurrentFrame.layerCount; ++j) { - hwc_layer_1_t* topLayer = &list->hwLayers[j]; - if(!mCurrentFrame.isFBComposed[j] && - isDownscaleRequired(topLayer)) { - hwc_rect_t r = getIntersection(botLayer->displayFrame, - topLayer->displayFrame); - if(isValidRect(r)) - return false; - } - } - } - } - } - return true; -} - -void MDPComp::setDynRefreshRate(hwc_context_t *ctx, hwc_display_contents_1_t* list) { - //For primary display, set the dynamic refreshrate - if(!mDpy && qdutils::MDPVersion::getInstance().isDynFpsSupported() && - ctx->mUseMetaDataRefreshRate) { - FrameInfo frame; - frame.reset(mCurrentFrame.layerCount); - memset(&frame.drop, 0, sizeof(frame.drop)); - frame.dropCount = 0; - ALOGD_IF(isDebug(), "%s: Update Cache and YUVInfo for Dyn Refresh Rate", - __FUNCTION__); - updateLayerCache(ctx, list, frame); - updateYUV(ctx, list, false /*secure only*/, frame); - uint32_t refreshRate = ctx->dpyAttr[mDpy].refreshRate; - MDPVersion& mdpHw = MDPVersion::getInstance(); - if(sIdleFallBack) { - //Set minimum panel refresh rate during idle timeout - refreshRate = mdpHw.getMinFpsSupported(); - } else if((ctx->listStats[mDpy].yuvCount == frame.mdpCount) || - (frame.layerCount == 1)) { - //Set the new fresh rate, if there is only one updating YUV layer - //or there is one single RGB layer with this request - refreshRate = ctx->listStats[mDpy].refreshRateRequest; - } - setRefreshRate(ctx, mDpy, refreshRate); - } -} - -int MDPComp::prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list) { - int ret = 0; - char property[PROPERTY_VALUE_MAX]; - - if(!ctx || !list) { - ALOGE("%s: Invalid context or list",__FUNCTION__); - mCachedFrame.reset(); - return -1; - } - - const int numLayers = ctx->listStats[mDpy].numAppLayers; - if(mDpy == HWC_DISPLAY_PRIMARY) { - sSimulationFlags = 0; - if(property_get("debug.hwc.simulate", property, NULL) > 0) { - int currentFlags = atoi(property); - if(currentFlags != sSimulationFlags) { - sSimulationFlags = currentFlags; - ALOGI("%s: Simulation Flag read: 0x%x (%d)", __FUNCTION__, - sSimulationFlags, sSimulationFlags); - } - } - } - // reset PTOR - if(!mDpy) - memset(&(ctx->mPtorInfo), 0, sizeof(ctx->mPtorInfo)); - - //reset old data - mCurrentFrame.reset(numLayers); - memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop)); - mCurrentFrame.dropCount = 0; - - //Do not cache the information for next draw cycle. - if(numLayers > MAX_NUM_APP_LAYERS or (!numLayers)) { - ALOGI("%s: Unsupported layer count for mdp composition", - __FUNCTION__); - mCachedFrame.reset(); -#ifdef DYNAMIC_FPS - // Reset refresh rate - setRefreshRate(ctx, mDpy, ctx->dpyAttr[mDpy].refreshRate); -#endif - return -1; - } - - // Detect the start of animation and fall back to GPU only once to cache - // all the layers in FB and display FB content untill animation completes. - if(ctx->listStats[mDpy].isDisplayAnimating) { - mCurrentFrame.needsRedraw = false; - if(ctx->mAnimationState[mDpy] == ANIMATION_STOPPED) { - mCurrentFrame.needsRedraw = true; - ctx->mAnimationState[mDpy] = ANIMATION_STARTED; - } - setMDPCompLayerFlags(ctx, list); - mCachedFrame.updateCounts(mCurrentFrame); -#ifdef DYNAMIC_FPS - // Reset refresh rate - setRefreshRate(ctx, mDpy, ctx->dpyAttr[mDpy].refreshRate); -#endif - ret = -1; - return ret; - } else { - ctx->mAnimationState[mDpy] = ANIMATION_STOPPED; - } - - if(!mDpy and !isSecondaryConnected(ctx) and !mPrevModeOn and - mCachedFrame.isSameFrame(ctx,mDpy,list)) { - - ALOGD_IF(isDebug(),"%s: Avoid new composition",__FUNCTION__); - mCurrentFrame.needsRedraw = false; - setMDPCompLayerFlags(ctx, list); - mCachedFrame.updateCounts(mCurrentFrame); - return -1; - - } - - //Hard conditions, if not met, cannot do MDP comp - if(isFrameDoable(ctx)) { - generateROI(ctx, list); - // if AIV Video mode is enabled, drop all non AIV layers from the - // external display list. - if(ctx->listStats[mDpy].mAIVVideoMode) { - dropNonAIVLayers(ctx, list); - } - - // if tryFullFrame fails, try to push all video and secure RGB layers - // to MDP for composition. - mModeOn = tryFullFrame(ctx, list) || tryMDPOnlyLayers(ctx, list) || - tryVideoOnly(ctx, list); - if(mModeOn) { - setMDPCompLayerFlags(ctx, list); - } else { - resetROI(ctx, mDpy); - reset(ctx); - memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop)); - mCurrentFrame.dropCount = 0; - ret = -1; - ALOGE_IF(sSimulationFlags && (mDpy == HWC_DISPLAY_PRIMARY), - "MDP Composition Strategies Failed"); - } - } else { - if ((ctx->mMDP.version == qdutils::MDP_V3_0_5) && ctx->mCopyBit[mDpy] && - enablePartialUpdateForMDP3) { - generateROI(ctx, list); - for(int i = 0; i < ctx->listStats[mDpy].numAppLayers; i++) { - ctx->copybitDrop[i] = mCurrentFrame.drop[i]; - } - } - ALOGD_IF( isDebug(),"%s: MDP Comp not possible for this frame", - __FUNCTION__); - ret = -1; - } - - if(isDebug()) { - ALOGD("GEOMETRY change: %d", - (list->flags & HWC_GEOMETRY_CHANGED)); - android::String8 sDump(""); - dump(sDump, ctx); - ALOGD("%s",sDump.string()); - } - -#ifdef DYNAMIC_FPS - setDynRefreshRate(ctx, list); -#endif - - mCachedFrame.updateCounts(mCurrentFrame); - return ret; -} - -bool MDPComp::allocSplitVGPipesfor4k2k(hwc_context_t *ctx, int index) { - - bool bRet = true; - int mdpIndex = mCurrentFrame.layerToMDP[index]; - PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex]; - info.pipeInfo = new MdpYUVPipeInfo; - info.rot = NULL; - MdpYUVPipeInfo& pipe_info = *(MdpYUVPipeInfo*)info.pipeInfo; - - pipe_info.lIndex = ovutils::OV_INVALID; - pipe_info.rIndex = ovutils::OV_INVALID; - - Overlay::PipeSpecs pipeSpecs; - pipeSpecs.formatClass = Overlay::FORMAT_YUV; - pipeSpecs.needsScaling = true; - pipeSpecs.dpy = mDpy; - pipeSpecs.fb = false; - - pipe_info.lIndex = ctx->mOverlay->getPipe(pipeSpecs); - if(pipe_info.lIndex == ovutils::OV_INVALID){ - bRet = false; - ALOGD_IF(isDebug(),"%s: allocating first VG pipe failed", - __FUNCTION__); - } - pipe_info.rIndex = ctx->mOverlay->getPipe(pipeSpecs); - if(pipe_info.rIndex == ovutils::OV_INVALID){ - bRet = false; - ALOGD_IF(isDebug(),"%s: allocating second VG pipe failed", - __FUNCTION__); - } - return bRet; -} - -int MDPComp::drawOverlap(hwc_context_t *ctx, hwc_display_contents_1_t* list) { - int fd = -1; - if (ctx->mPtorInfo.isActive()) { - fd = ctx->mCopyBit[mDpy]->drawOverlap(ctx, list); - if (fd < 0) { - ALOGD_IF(isDebug(),"%s: failed", __FUNCTION__); - } - } - return fd; -} -//=============MDPCompNonSplit================================================== - -void MDPCompNonSplit::adjustForSourceSplit(hwc_context_t *ctx, - hwc_display_contents_1_t* list) { - //If 4k2k Yuv layer split is possible, and if - //fbz is above 4k2k layer, increment fb zorder by 1 - //as we split 4k2k layer and increment zorder for right half - //of the layer - if(!ctx) - return; - if(mCurrentFrame.fbZ >= 0) { - for (int index = 0, mdpNextZOrder = 0; index < mCurrentFrame.layerCount; - index++) { - if(!mCurrentFrame.isFBComposed[index]) { - if(mdpNextZOrder == mCurrentFrame.fbZ) { - mdpNextZOrder++; - } - mdpNextZOrder++; - hwc_layer_1_t* layer = &list->hwLayers[index]; - private_handle_t *hnd = (private_handle_t *)layer->handle; - if(isYUVSplitNeeded(hnd)) { - if(mdpNextZOrder <= mCurrentFrame.fbZ) - mCurrentFrame.fbZ += 1; - mdpNextZOrder++; - //As we split 4kx2k yuv layer and program to 2 VG pipes - //(if available) increase mdpcount by 1. - mCurrentFrame.mdpCount++; - } - } - } - } -} - -/* - * Configures pipe(s) for MDP composition - */ -int MDPCompNonSplit::configure(hwc_context_t *ctx, hwc_layer_1_t *layer, - PipeLayerPair& PipeLayerPair) { - MdpPipeInfoNonSplit& mdp_info = - *(static_cast<MdpPipeInfoNonSplit*>(PipeLayerPair.pipeInfo)); - eMdpFlags mdpFlags = OV_MDP_BACKEND_COMPOSITION; - eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder); - eDest dest = mdp_info.index; - - ALOGD_IF(isDebug(),"%s: configuring: layer: %p z_order: %d dest_pipe: %d", - __FUNCTION__, layer, zOrder, dest); - - return configureNonSplit(ctx, layer, mDpy, mdpFlags, zOrder, dest, - &PipeLayerPair.rot); -} - -bool MDPCompNonSplit::allocLayerPipes(hwc_context_t *ctx, - hwc_display_contents_1_t* list) { - for(int index = 0; index < mCurrentFrame.layerCount; index++) { - - if(mCurrentFrame.isFBComposed[index]) continue; - - hwc_layer_1_t* layer = &list->hwLayers[index]; - private_handle_t *hnd = (private_handle_t *)layer->handle; - if(isYUVSplitNeeded(hnd) && sEnableYUVsplit){ - if(allocSplitVGPipesfor4k2k(ctx, index)){ - continue; - } - } - - int mdpIndex = mCurrentFrame.layerToMDP[index]; - PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex]; - info.pipeInfo = new MdpPipeInfoNonSplit; - info.rot = NULL; - MdpPipeInfoNonSplit& pipe_info = *(MdpPipeInfoNonSplit*)info.pipeInfo; - - Overlay::PipeSpecs pipeSpecs; - pipeSpecs.formatClass = isYuvBuffer(hnd) ? - Overlay::FORMAT_YUV : Overlay::FORMAT_RGB; - pipeSpecs.needsScaling = qhwc::needsScaling(layer) or - (qdutils::MDPVersion::getInstance().is8x26() and - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres > 1024); - pipeSpecs.dpy = mDpy; - pipeSpecs.fb = false; - pipeSpecs.numActiveDisplays = ctx->numActiveDisplays; - - pipe_info.index = ctx->mOverlay->getPipe(pipeSpecs); - - if(pipe_info.index == ovutils::OV_INVALID) { - ALOGD_IF(isDebug(), "%s: Unable to get pipe", __FUNCTION__); - return false; - } - } - return true; -} - -int MDPCompNonSplit::configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer, - PipeLayerPair& PipeLayerPair) { - MdpYUVPipeInfo& mdp_info = - *(static_cast<MdpYUVPipeInfo*>(PipeLayerPair.pipeInfo)); - eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder); - eMdpFlags mdpFlagsL = OV_MDP_BACKEND_COMPOSITION; - eDest lDest = mdp_info.lIndex; - eDest rDest = mdp_info.rIndex; - - return configureSourceSplit(ctx, layer, mDpy, mdpFlagsL, zOrder, - lDest, rDest, &PipeLayerPair.rot); -} - -bool MDPCompNonSplit::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) { - - if(!isEnabled() or !mModeOn) { - ALOGD_IF(isDebug(),"%s: MDP Comp not enabled/configured", __FUNCTION__); - return true; - } - - overlay::Overlay& ov = *ctx->mOverlay; - LayerProp *layerProp = ctx->layerProp[mDpy]; - - int numHwLayers = ctx->listStats[mDpy].numAppLayers; - for(int i = 0; i < numHwLayers && mCurrentFrame.mdpCount; i++ ) - { - if(mCurrentFrame.isFBComposed[i]) continue; - - hwc_layer_1_t *layer = &list->hwLayers[i]; - private_handle_t *hnd = (private_handle_t *)layer->handle; - if(!hnd) { - if (!(layer->flags & HWC_COLOR_FILL)) { - ALOGE("%s handle null", __FUNCTION__); - return false; - } - // No PLAY for Color layer - layerProp[i].mFlags &= ~HWC_MDPCOMP; - continue; - } - - int mdpIndex = mCurrentFrame.layerToMDP[i]; - - if(isYUVSplitNeeded(hnd) && sEnableYUVsplit) - { - MdpYUVPipeInfo& pipe_info = - *(MdpYUVPipeInfo*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo; - Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot; - ovutils::eDest indexL = pipe_info.lIndex; - ovutils::eDest indexR = pipe_info.rIndex; - int fd = hnd->fd; - uint32_t offset = (uint32_t)hnd->offset; - if(rot) { - rot->queueBuffer(fd, offset); - fd = rot->getDstMemId(); - offset = rot->getDstOffset(); - } - if(indexL != ovutils::OV_INVALID) { - ovutils::eDest destL = (ovutils::eDest)indexL; - ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \ - using pipe: %d", __FUNCTION__, layer, hnd, indexL ); - if (!ov.queueBuffer(fd, offset, destL)) { - ALOGE("%s: queueBuffer failed for display:%d", - __FUNCTION__, mDpy); - return false; - } - } - - if(indexR != ovutils::OV_INVALID) { - ovutils::eDest destR = (ovutils::eDest)indexR; - ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \ - using pipe: %d", __FUNCTION__, layer, hnd, indexR ); - if (!ov.queueBuffer(fd, offset, destR)) { - ALOGE("%s: queueBuffer failed for display:%d", - __FUNCTION__, mDpy); - return false; - } - } - } - else{ - MdpPipeInfoNonSplit& pipe_info = - *(MdpPipeInfoNonSplit*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo; - ovutils::eDest dest = pipe_info.index; - if(dest == ovutils::OV_INVALID) { - ALOGE("%s: Invalid pipe index (%d)", __FUNCTION__, dest); - return false; - } - - if(!(layerProp[i].mFlags & HWC_MDPCOMP)) { - continue; - } - - int fd = hnd->fd; - uint32_t offset = (uint32_t)hnd->offset; - int index = ctx->mPtorInfo.getPTORArrayIndex(i); - if (!mDpy && (index != -1)) { - hnd = ctx->mCopyBit[mDpy]->getCurrentRenderBuffer(); - fd = hnd->fd; - offset = 0; - } - - ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \ - using pipe: %d", __FUNCTION__, layer, - hnd, dest ); - - Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot; - if(rot) { - if(!rot->queueBuffer(fd, offset)) - return false; - fd = rot->getDstMemId(); - offset = rot->getDstOffset(); - } - - if (!ov.queueBuffer(fd, offset, dest)) { - ALOGE("%s: queueBuffer failed for display:%d ", - __FUNCTION__, mDpy); - return false; - } - } - - layerProp[i].mFlags &= ~HWC_MDPCOMP; - } - return true; -} - -//=============MDPCompSplit=================================================== - -void MDPCompSplit::adjustForSourceSplit(hwc_context_t *ctx, - hwc_display_contents_1_t* list){ - //if 4kx2k yuv layer is totally present in either in left half - //or right half then try splitting the yuv layer to avoid decimation - const int lSplit = getLeftSplit(ctx, mDpy); - if(mCurrentFrame.fbZ >= 0) { - for (int index = 0, mdpNextZOrder = 0; index < mCurrentFrame.layerCount; - index++) { - if(!mCurrentFrame.isFBComposed[index]) { - if(mdpNextZOrder == mCurrentFrame.fbZ) { - mdpNextZOrder++; - } - mdpNextZOrder++; - hwc_layer_1_t* layer = &list->hwLayers[index]; - private_handle_t *hnd = (private_handle_t *)layer->handle; - if(isYUVSplitNeeded(hnd)) { - hwc_rect_t dst = layer->displayFrame; - if((dst.left > lSplit) || (dst.right < lSplit)) { - mCurrentFrame.mdpCount += 1; - } - if(mdpNextZOrder <= mCurrentFrame.fbZ) - mCurrentFrame.fbZ += 1; - mdpNextZOrder++; - } - } - } - } -} - -bool MDPCompSplit::acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer, - MdpPipeInfoSplit& pipe_info) { - - const int lSplit = getLeftSplit(ctx, mDpy); - private_handle_t *hnd = (private_handle_t *)layer->handle; - hwc_rect_t dst = layer->displayFrame; - pipe_info.lIndex = ovutils::OV_INVALID; - pipe_info.rIndex = ovutils::OV_INVALID; - - Overlay::PipeSpecs pipeSpecs; - pipeSpecs.formatClass = isYuvBuffer(hnd) ? - Overlay::FORMAT_YUV : Overlay::FORMAT_RGB; - pipeSpecs.needsScaling = qhwc::needsScalingWithSplit(ctx, layer, mDpy); - pipeSpecs.dpy = mDpy; - pipeSpecs.mixer = Overlay::MIXER_LEFT; - pipeSpecs.fb = false; - - // Acquire pipe only for the updating half - hwc_rect_t l_roi = ctx->listStats[mDpy].lRoi; - hwc_rect_t r_roi = ctx->listStats[mDpy].rRoi; - - if (dst.left < lSplit && isValidRect(getIntersection(dst, l_roi))) { - pipe_info.lIndex = ctx->mOverlay->getPipe(pipeSpecs); - if(pipe_info.lIndex == ovutils::OV_INVALID) - return false; - } - - if(dst.right > lSplit && isValidRect(getIntersection(dst, r_roi))) { - pipeSpecs.mixer = Overlay::MIXER_RIGHT; - pipe_info.rIndex = ctx->mOverlay->getPipe(pipeSpecs); - if(pipe_info.rIndex == ovutils::OV_INVALID) - return false; - } - - return true; -} - -bool MDPCompSplit::allocLayerPipes(hwc_context_t *ctx, - hwc_display_contents_1_t* list) { - for(int index = 0 ; index < mCurrentFrame.layerCount; index++) { - - if(mCurrentFrame.isFBComposed[index]) continue; - - hwc_layer_1_t* layer = &list->hwLayers[index]; - private_handle_t *hnd = (private_handle_t *)layer->handle; - hwc_rect_t dst = layer->displayFrame; - const int lSplit = getLeftSplit(ctx, mDpy); - if(isYUVSplitNeeded(hnd) && sEnableYUVsplit){ - if((dst.left > lSplit)||(dst.right < lSplit)){ - if(allocSplitVGPipesfor4k2k(ctx, index)){ - continue; - } - } - } - int mdpIndex = mCurrentFrame.layerToMDP[index]; - PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex]; - info.pipeInfo = new MdpPipeInfoSplit; - info.rot = NULL; - MdpPipeInfoSplit& pipe_info = *(MdpPipeInfoSplit*)info.pipeInfo; - - if(!acquireMDPPipes(ctx, layer, pipe_info)) { - ALOGD_IF(isDebug(), "%s: Unable to get pipe for type", - __FUNCTION__); - return false; - } - } - return true; -} - -int MDPCompSplit::configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer, - PipeLayerPair& PipeLayerPair) { - const int lSplit = getLeftSplit(ctx, mDpy); - hwc_rect_t dst = layer->displayFrame; - if((dst.left > lSplit)||(dst.right < lSplit)){ - MdpYUVPipeInfo& mdp_info = - *(static_cast<MdpYUVPipeInfo*>(PipeLayerPair.pipeInfo)); - eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder); - eMdpFlags mdpFlagsL = OV_MDP_BACKEND_COMPOSITION; - eDest lDest = mdp_info.lIndex; - eDest rDest = mdp_info.rIndex; - - return configureSourceSplit(ctx, layer, mDpy, mdpFlagsL, zOrder, - lDest, rDest, &PipeLayerPair.rot); - } - else{ - return configure(ctx, layer, PipeLayerPair); - } -} - -/* - * Configures pipe(s) for MDP composition - */ -int MDPCompSplit::configure(hwc_context_t *ctx, hwc_layer_1_t *layer, - PipeLayerPair& PipeLayerPair) { - MdpPipeInfoSplit& mdp_info = - *(static_cast<MdpPipeInfoSplit*>(PipeLayerPair.pipeInfo)); - eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder); - eMdpFlags mdpFlagsL = OV_MDP_BACKEND_COMPOSITION; - eDest lDest = mdp_info.lIndex; - eDest rDest = mdp_info.rIndex; - - ALOGD_IF(isDebug(),"%s: configuring: layer: %p z_order: %d dest_pipeL: %d" - "dest_pipeR: %d",__FUNCTION__, layer, zOrder, lDest, rDest); - - return configureSplit(ctx, layer, mDpy, mdpFlagsL, zOrder, lDest, - rDest, &PipeLayerPair.rot); -} - -bool MDPCompSplit::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) { - - if(!isEnabled() or !mModeOn) { - ALOGD_IF(isDebug(),"%s: MDP Comp not enabled/configured", __FUNCTION__); - return true; - } - - overlay::Overlay& ov = *ctx->mOverlay; - LayerProp *layerProp = ctx->layerProp[mDpy]; - - int numHwLayers = ctx->listStats[mDpy].numAppLayers; - for(int i = 0; i < numHwLayers && mCurrentFrame.mdpCount; i++ ) - { - if(mCurrentFrame.isFBComposed[i]) continue; - - hwc_layer_1_t *layer = &list->hwLayers[i]; - private_handle_t *hnd = (private_handle_t *)layer->handle; - if(!hnd) { - ALOGE("%s handle null", __FUNCTION__); - return false; - } - - if(!(layerProp[i].mFlags & HWC_MDPCOMP)) { - continue; - } - - int mdpIndex = mCurrentFrame.layerToMDP[i]; - - if(isYUVSplitNeeded(hnd) && sEnableYUVsplit) - { - MdpYUVPipeInfo& pipe_info = - *(MdpYUVPipeInfo*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo; - Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot; - ovutils::eDest indexL = pipe_info.lIndex; - ovutils::eDest indexR = pipe_info.rIndex; - int fd = hnd->fd; - uint32_t offset = (uint32_t)hnd->offset; - if(rot) { - rot->queueBuffer(fd, offset); - fd = rot->getDstMemId(); - offset = rot->getDstOffset(); - } - if(indexL != ovutils::OV_INVALID) { - ovutils::eDest destL = (ovutils::eDest)indexL; - ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \ - using pipe: %d", __FUNCTION__, layer, hnd, indexL ); - if (!ov.queueBuffer(fd, offset, destL)) { - ALOGE("%s: queueBuffer failed for display:%d", - __FUNCTION__, mDpy); - return false; - } - } - - if(indexR != ovutils::OV_INVALID) { - ovutils::eDest destR = (ovutils::eDest)indexR; - ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \ - using pipe: %d", __FUNCTION__, layer, hnd, indexR ); - if (!ov.queueBuffer(fd, offset, destR)) { - ALOGE("%s: queueBuffer failed for display:%d", - __FUNCTION__, mDpy); - return false; - } - } - } - else{ - MdpPipeInfoSplit& pipe_info = - *(MdpPipeInfoSplit*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo; - Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot; - - ovutils::eDest indexL = pipe_info.lIndex; - ovutils::eDest indexR = pipe_info.rIndex; - - int fd = hnd->fd; - uint32_t offset = (uint32_t)hnd->offset; - int index = ctx->mPtorInfo.getPTORArrayIndex(i); - if (!mDpy && (index != -1)) { - hnd = ctx->mCopyBit[mDpy]->getCurrentRenderBuffer(); - fd = hnd->fd; - offset = 0; - } - - if(ctx->mAD->draw(ctx, fd, offset)) { - fd = ctx->mAD->getDstFd(); - offset = ctx->mAD->getDstOffset(); - } - - if(rot) { - rot->queueBuffer(fd, offset); - fd = rot->getDstMemId(); - offset = rot->getDstOffset(); - } - - //************* play left mixer ********** - if(indexL != ovutils::OV_INVALID) { - ovutils::eDest destL = (ovutils::eDest)indexL; - ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \ - using pipe: %d", __FUNCTION__, layer, hnd, indexL ); - if (!ov.queueBuffer(fd, offset, destL)) { - ALOGE("%s: queueBuffer failed for left mixer", - __FUNCTION__); - return false; - } - } - - //************* play right mixer ********** - if(indexR != ovutils::OV_INVALID) { - ovutils::eDest destR = (ovutils::eDest)indexR; - ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \ - using pipe: %d", __FUNCTION__, layer, hnd, indexR ); - if (!ov.queueBuffer(fd, offset, destR)) { - ALOGE("%s: queueBuffer failed for right mixer", - __FUNCTION__); - return false; - } - } - } - - layerProp[i].mFlags &= ~HWC_MDPCOMP; - } - - return true; -} - -//================MDPCompSrcSplit============================================== -bool MDPCompSrcSplit::acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer, - MdpPipeInfoSplit& pipe_info) { - private_handle_t *hnd = (private_handle_t *)layer->handle; - hwc_rect_t dst = layer->displayFrame; - hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf); - pipe_info.lIndex = ovutils::OV_INVALID; - pipe_info.rIndex = ovutils::OV_INVALID; - - //If 2 pipes are staged on a single stage of a mixer, then the left pipe - //should have a higher priority than the right one. Pipe priorities are - //starting with VG0, VG1 ... , RGB0 ..., DMA1 - - Overlay::PipeSpecs pipeSpecs; - pipeSpecs.formatClass = isYuvBuffer(hnd) ? - Overlay::FORMAT_YUV : Overlay::FORMAT_RGB; - pipeSpecs.needsScaling = qhwc::needsScaling(layer); - pipeSpecs.dpy = mDpy; - pipeSpecs.fb = false; - - //1 pipe by default for a layer - pipe_info.lIndex = ctx->mOverlay->getPipe(pipeSpecs); - if(pipe_info.lIndex == ovutils::OV_INVALID) { - return false; - } - - /* Use 2 pipes IF - a) Layer's crop width is > 2048 or - b) Layer's dest width > 2048 or - c) On primary, driver has indicated with caps to split always. This is - based on an empirically derived value of panel height. Applied only - if the layer's width is > mixer's width - */ - - MDPVersion& mdpHw = MDPVersion::getInstance(); - bool primarySplitAlways = (mDpy == HWC_DISPLAY_PRIMARY) and - mdpHw.isSrcSplitAlways(); - int lSplit = getLeftSplit(ctx, mDpy); - int dstWidth = dst.right - dst.left; - int cropWidth = has90Transform(layer) ? crop.bottom - crop.top : - crop.right - crop.left; - - //TODO Even if a 4k video is going to be rot-downscaled to dimensions under - //pipe line length, we are still using 2 pipes. This is fine just because - //this is source split where destination doesn't matter. Evaluate later to - //see if going through all the calcs to save a pipe is worth it - if(dstWidth > (int) mdpHw.getMaxMixerWidth() or - cropWidth > (int) mdpHw.getMaxMixerWidth() or - (primarySplitAlways and (cropWidth > lSplit))) { - pipe_info.rIndex = ctx->mOverlay->getPipe(pipeSpecs); - if(pipe_info.rIndex == ovutils::OV_INVALID) { - return false; - } - - // Return values - // 1 Left pipe is higher priority, do nothing. - // 0 Pipes of same priority. - //-1 Right pipe is of higher priority, needs swap. - if(ctx->mOverlay->comparePipePriority(pipe_info.lIndex, - pipe_info.rIndex) == -1) { - qhwc::swap(pipe_info.lIndex, pipe_info.rIndex); - } - } - - return true; -} - -int MDPCompSrcSplit::configure(hwc_context_t *ctx, hwc_layer_1_t *layer, - PipeLayerPair& PipeLayerPair) { - private_handle_t *hnd = (private_handle_t *)layer->handle; - if(!hnd) { - ALOGE("%s: layer handle is NULL", __FUNCTION__); - return -1; - } - MetaData_t *metadata = (MetaData_t *)hnd->base_metadata; - MdpPipeInfoSplit& mdp_info = - *(static_cast<MdpPipeInfoSplit*>(PipeLayerPair.pipeInfo)); - Rotator **rot = &PipeLayerPair.rot; - eZorder z = static_cast<eZorder>(mdp_info.zOrder); - eDest lDest = mdp_info.lIndex; - eDest rDest = mdp_info.rIndex; - hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf); - hwc_rect_t dst = layer->displayFrame; - int transform = layer->transform; - eTransform orient = static_cast<eTransform>(transform); - int rotFlags = ROT_FLAGS_NONE; - uint32_t format = ovutils::getMdpFormat(hnd->format, isTileRendered(hnd)); - Whf whf(getWidth(hnd), getHeight(hnd), format, hnd->size); - - ALOGD_IF(isDebug(),"%s: configuring: layer: %p z_order: %d dest_pipeL: %d" - "dest_pipeR: %d",__FUNCTION__, layer, z, lDest, rDest); - - // Handle R/B swap - if (layer->flags & HWC_FORMAT_RB_SWAP) { - if (hnd->format == HAL_PIXEL_FORMAT_RGBA_8888) - whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRA_8888); - else if (hnd->format == HAL_PIXEL_FORMAT_RGBX_8888) - whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRX_8888); - } - // update source crop and destination position of AIV video layer. - if(ctx->listStats[mDpy].mAIVVideoMode && isYuvBuffer(hnd)) { - updateCoordinates(ctx, crop, dst, mDpy); - } - /* Calculate the external display position based on MDP downscale, - ActionSafe, and extorientation features. */ - calcExtDisplayPosition(ctx, hnd, mDpy, crop, dst, transform, orient); - - int downscale = getRotDownscale(ctx, layer); - eMdpFlags mdpFlags = OV_MDP_BACKEND_COMPOSITION; - setMdpFlags(ctx, layer, mdpFlags, downscale, transform); - - if(lDest != OV_INVALID && rDest != OV_INVALID) { - //Enable overfetch - setMdpFlags(mdpFlags, OV_MDSS_MDP_DUAL_PIPE); - } - - if((has90Transform(layer) or downscale) and isRotationDoable(ctx, hnd)) { - (*rot) = ctx->mRotMgr->getNext(); - if((*rot) == NULL) return -1; - ctx->mLayerRotMap[mDpy]->add(layer, *rot); - //If the video is using a single pipe, enable BWC - if(rDest == OV_INVALID) { - BwcPM::setBwc(crop, dst, transform, downscale, mdpFlags); - } - //Configure rotator for pre-rotation - if(configRotator(*rot, whf, crop, mdpFlags, orient, downscale) < 0) { - ALOGE("%s: configRotator failed!", __FUNCTION__); - return -1; - } - updateSource(orient, whf, crop, *rot); - rotFlags |= ovutils::ROT_PREROTATED; - } - - //If 2 pipes being used, divide layer into half, crop and dst - hwc_rect_t cropL = crop; - hwc_rect_t cropR = crop; - hwc_rect_t dstL = dst; - hwc_rect_t dstR = dst; - if(lDest != OV_INVALID && rDest != OV_INVALID) { - cropL.right = (crop.right + crop.left) / 2; - cropR.left = cropL.right; - sanitizeSourceCrop(cropL, cropR, hnd); - - bool cropSwap = false; - //Swap crops on H flip since 2 pipes are being used - if((orient & OVERLAY_TRANSFORM_FLIP_H) && (*rot) == NULL) { - hwc_rect_t tmp = cropL; - cropL = cropR; - cropR = tmp; - cropSwap = true; - } - - //cropSwap trick: If the src and dst widths are both odd, let us say - //2507, then splitting both into half would cause left width to be 1253 - //and right 1254. If crop is swapped because of H flip, this will cause - //left crop width to be 1254, whereas left dst width remains 1253, thus - //inducing a scaling that is unaccounted for. To overcome that we add 1 - //to the dst width if there is a cropSwap. So if the original width was - //2507, the left dst width will be 1254. Even if the original width was - //even for ex: 2508, the left dst width will still remain 1254. - dstL.right = (dst.right + dst.left + cropSwap) / 2; - dstR.left = dstL.right; - } - - //For the mdp, since either we are pre-rotating or MDP does flips - orient = OVERLAY_TRANSFORM_0; - transform = 0; - - //configure left pipe - if(lDest != OV_INVALID) { - PipeArgs pargL(mdpFlags, whf, z, - static_cast<eRotFlags>(rotFlags), layer->planeAlpha, - (ovutils::eBlending) getBlending(layer->blending)); - - if(configMdp(ctx->mOverlay, pargL, orient, - cropL, dstL, metadata, lDest) < 0) { - ALOGE("%s: commit failed for left mixer config", __FUNCTION__); - return -1; - } - } - - //configure right pipe - if(rDest != OV_INVALID) { - PipeArgs pargR(mdpFlags, whf, z, - static_cast<eRotFlags>(rotFlags), - layer->planeAlpha, - (ovutils::eBlending) getBlending(layer->blending)); - if(configMdp(ctx->mOverlay, pargR, orient, - cropR, dstR, metadata, rDest) < 0) { - ALOGE("%s: commit failed for right mixer config", __FUNCTION__); - return -1; - } - } - - return 0; -} - -int MDPComp::getPartialUpdatePref(hwc_context_t *ctx) { - Locker::Autolock _l(ctx->mDrawLock); - const int fbNum = Overlay::getFbForDpy(Overlay::DPY_PRIMARY); - char path[MAX_SYSFS_FILE_PATH]; - snprintf (path, sizeof(path), "sys/class/graphics/fb%d/dyn_pu", fbNum); - int fd = open(path, O_RDONLY); - if(fd < 0) { - ALOGE("%s: Failed to open sysfs node: %s", __FUNCTION__, path); - return -1; - } - char value[4]; - ssize_t size_read = read(fd, value, sizeof(value)-1); - if(size_read <= 0) { - ALOGE("%s: Failed to read sysfs node: %s", __FUNCTION__, path); - close(fd); - return -1; - } - close(fd); - value[size_read] = '\0'; - return atoi(value); -} - -int MDPComp::setPartialUpdatePref(hwc_context_t *ctx, bool enable) { - Locker::Autolock _l(ctx->mDrawLock); - const int fbNum = Overlay::getFbForDpy(Overlay::DPY_PRIMARY); - char path[MAX_SYSFS_FILE_PATH]; - snprintf (path, sizeof(path), "sys/class/graphics/fb%d/dyn_pu", fbNum); - int fd = open(path, O_WRONLY); - if(fd < 0) { - ALOGE("%s: Failed to open sysfs node: %s", __FUNCTION__, path); - return -1; - } - char value[4]; - snprintf(value, sizeof(value), "%d", (int)enable); - ssize_t ret = write(fd, value, strlen(value)); - if(ret <= 0) { - ALOGE("%s: Failed to write to sysfs nodes: %s", __FUNCTION__, path); - close(fd); - return -1; - } - close(fd); - return 0; -} -}; //namespace - diff --git a/msm8909/libhwcomposer/hwc_mdpcomp.h b/msm8909/libhwcomposer/hwc_mdpcomp.h deleted file mode 100644 index e6b02282..00000000 --- a/msm8909/libhwcomposer/hwc_mdpcomp.h +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Copyright (C) 2012-2015, The Linux Foundation. All rights reserved. - * - * Not a Contribution, Apache license notifications and license are retained - * for attribution purposes only. - * - * 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_MDP_COMP -#define HWC_MDP_COMP - -#include <hwc_utils.h> -#include <idle_invalidator.h> -#include <cutils/properties.h> -#include <overlay.h> - -#define MAX_PIPES_PER_MIXER 4 - -namespace overlay { -class Rotator; -}; - -namespace qhwc { -namespace ovutils = overlay::utils; - -class MDPComp { -public: - explicit MDPComp(int); - virtual ~MDPComp(){}; - /*sets up mdp comp for the current frame */ - int prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list); - /* draw */ - virtual bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list) = 0; - //Reset values - void reset(); - /* dumpsys */ - void dump(android::String8& buf, hwc_context_t *ctx); - bool isGLESOnlyComp() { return (mCurrentFrame.mdpCount == 0); } - bool isMDPComp() { return mModeOn; } - int drawOverlap(hwc_context_t *ctx, hwc_display_contents_1_t* list); - static MDPComp* getObject(hwc_context_t *ctx, const int& dpy); - /* Handler to invoke frame redraw on Idle Timer expiry */ - static void timeout_handler(void *udata); - /* Initialize MDP comp*/ - static bool init(hwc_context_t *ctx); - static void resetIdleFallBack() { sIdleFallBack = false; } - static bool isIdleFallback() { return sIdleFallBack; } - static void dynamicDebug(bool enable){ sDebugLogs = enable; } - static void setIdleTimeout(const uint32_t& timeout); - static int setPartialUpdatePref(hwc_context_t *ctx, bool enable); - void setDynRefreshRate(hwc_context_t *ctx, hwc_display_contents_1_t* list); - static int getPartialUpdatePref(hwc_context_t *ctx); - static void enablePartialUpdate(bool enable) - { sIsPartialUpdateActive = enable; }; - -protected: - enum { MAX_SEC_LAYERS = 1 }; //TODO add property support - - enum ePipeType { - MDPCOMP_OV_RGB = ovutils::OV_MDP_PIPE_RGB, - MDPCOMP_OV_VG = ovutils::OV_MDP_PIPE_VG, - MDPCOMP_OV_DMA = ovutils::OV_MDP_PIPE_DMA, - MDPCOMP_OV_ANY, - }; - - //Simulation flags - enum { - MDPCOMP_AVOID_FULL_MDP = 0x001, - MDPCOMP_AVOID_CACHE_MDP = 0x002, - MDPCOMP_AVOID_LOAD_MDP = 0x004, - MDPCOMP_AVOID_VIDEO_ONLY = 0x008, - MDPCOMP_AVOID_MDP_ONLY_LAYERS = 0x010, - }; - - /* mdp pipe data */ - struct MdpPipeInfo { - int zOrder; - virtual ~MdpPipeInfo(){}; - }; - - struct MdpYUVPipeInfo : public MdpPipeInfo{ - ovutils::eDest lIndex; - ovutils::eDest rIndex; - virtual ~MdpYUVPipeInfo(){}; - }; - - /* per layer data */ - struct PipeLayerPair { - MdpPipeInfo *pipeInfo; - overlay::Rotator* rot; - int listIndex; - }; - - /* per frame data */ - struct FrameInfo { - /* maps layer list to mdp list */ - int layerCount; - int layerToMDP[MAX_NUM_APP_LAYERS]; - - /* maps mdp list to layer list */ - int mdpCount; - struct PipeLayerPair mdpToLayer[MAX_PIPES_PER_MIXER]; - - /* layer composing on FB? */ - int fbCount; - bool isFBComposed[MAX_NUM_APP_LAYERS]; - /* layers lying outside ROI. Will - * be dropped off from the composition */ - int dropCount; - bool drop[MAX_NUM_APP_LAYERS]; - - bool needsRedraw; - int fbZ; - - /* c'tor */ - FrameInfo(); - /* clear old frame data */ - void reset(const int& numLayers); - void map(); - }; - - /* cached data */ - struct LayerCache { - int layerCount; - bool isFBComposed[MAX_NUM_APP_LAYERS]; - bool drop[MAX_NUM_APP_LAYERS]; - - /* c'tor */ - LayerCache(); - /* clear caching info*/ - void reset(); - void updateCounts(const FrameInfo&); - bool isSameFrame(const FrameInfo& curFrame, - hwc_display_contents_1_t* list); - bool isSameFrame(hwc_context_t *ctx, int dpy, - hwc_display_contents_1_t* list); - }; - - /* allocates pipe from pipe book */ - virtual bool allocLayerPipes(hwc_context_t *ctx, - hwc_display_contents_1_t* list) = 0; - /* configures MPD pipes */ - virtual int configure(hwc_context_t *ctx, hwc_layer_1_t *layer, - PipeLayerPair& pipeLayerPair) = 0; - /* Increments mdpCount if 4k2k yuv layer split is enabled. - * updates framebuffer z order if fb lies above source-split layer */ - virtual void adjustForSourceSplit(hwc_context_t *ctx, - hwc_display_contents_1_t* list) = 0; - /* configures 4kx2k yuv layer*/ - virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer, - PipeLayerPair& PipeLayerPair) = 0; - /* generates ROI based on the modified area of the frame */ - virtual void generateROI(hwc_context_t *ctx, - hwc_display_contents_1_t* list) = 0; - /* validates the ROI generated for fallback conditions */ - virtual bool validateAndApplyROI(hwc_context_t *ctx, - hwc_display_contents_1_t* list) = 0; - /* Trims fbRect calculated against ROI generated */ - virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect) = 0; - - /* set/reset flags for MDPComp */ - void setMDPCompLayerFlags(hwc_context_t *ctx, - hwc_display_contents_1_t* list); - void setRedraw(hwc_context_t *ctx, - hwc_display_contents_1_t* list); - /* checks for conditions where mdpcomp is not possible */ - bool isFrameDoable(hwc_context_t *ctx); - /* checks for conditions where RGB layers cannot be bypassed */ - bool tryFullFrame(hwc_context_t *ctx, hwc_display_contents_1_t* list); - /* checks if full MDP comp can be done */ - bool fullMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list); - /* Full MDP Composition with Peripheral Tiny Overlap Removal */ - bool fullMDPCompWithPTOR(hwc_context_t *ctx,hwc_display_contents_1_t* list); - /* check if we can use layer cache to do at least partial MDP comp */ - bool partialMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list); - /* Partial MDP comp that uses caching to save power as primary goal */ - bool cacheBasedComp(hwc_context_t *ctx, hwc_display_contents_1_t* list); - /* Partial MDP comp that balances the load between MDP and GPU such that - * MDP is loaded to the max of its capacity. The lower z order layers are - * fed to MDP, whereas the upper ones to GPU, because the upper ones have - * lower number of pixels and can reduce GPU processing time */ - bool loadBasedComp(hwc_context_t *ctx, hwc_display_contents_1_t* list); - /* Checks if its worth doing load based partial comp */ - bool isLoadBasedCompDoable(hwc_context_t *ctx); - /* checks for conditions where only video can be bypassed */ - bool tryVideoOnly(hwc_context_t *ctx, hwc_display_contents_1_t* list); - bool videoOnlyComp(hwc_context_t *ctx, hwc_display_contents_1_t* list, - bool secureOnly); - /* checks for conditions where only secure RGB and video can be bypassed */ - bool tryMDPOnlyLayers(hwc_context_t *ctx, hwc_display_contents_1_t* list); - bool mdpOnlyLayersComp(hwc_context_t *ctx, hwc_display_contents_1_t* list, - bool secureOnly); - /* checks for conditions where YUV layers cannot be bypassed */ - bool isYUVDoable(hwc_context_t* ctx, hwc_layer_1_t* layer); - /* checks for conditions where Secure RGB layers cannot be bypassed */ - bool isSecureRGBDoable(hwc_context_t* ctx, hwc_layer_1_t* layer); - /* checks if MDP/MDSS can process current list w.r.to HW limitations - * All peculiar HW limitations should go here */ - bool hwLimitationsCheck(hwc_context_t* ctx, hwc_display_contents_1_t* list); - /* Is debug enabled */ - static bool isDebug() { return sDebugLogs ? true : false; }; - /* Is feature enabled */ - static bool isEnabled() { return sEnabled; }; - /* checks for mdp comp dimension limitation */ - bool isValidDimension(hwc_context_t *ctx, hwc_layer_1_t *layer); - /* tracks non updating layers*/ - void updateLayerCache(hwc_context_t* ctx, hwc_display_contents_1_t* list, - FrameInfo& frame); - /* optimize layers for mdp comp*/ - bool markLayersForCaching(hwc_context_t* ctx, - hwc_display_contents_1_t* list); - int getBatch(hwc_display_contents_1_t* list, - int& maxBatchStart, int& maxBatchEnd, - int& maxBatchCount); - bool canPushBatchToTop(const hwc_display_contents_1_t* list, - int fromIndex, int toIndex); - bool intersectingUpdatingLayers(const hwc_display_contents_1_t* list, - int fromIndex, int toIndex, int targetLayerIndex); - - /* drop other non-AIV layers from external display list.*/ - void dropNonAIVLayers(hwc_context_t* ctx, hwc_display_contents_1_t* list); - - /* updates cache map with YUV info */ - void updateYUV(hwc_context_t* ctx, hwc_display_contents_1_t* list, - bool secureOnly, FrameInfo& frame); - /* updates cache map with secure RGB info */ - void updateSecureRGB(hwc_context_t* ctx, - hwc_display_contents_1_t* list); - /* Validates if the GPU/MDP layer split chosen by a strategy is supported - * by MDP. - * Sets up MDP comp data structures to reflect covnversion from layers to - * overlay pipes. - * Configures overlay. - * Configures if GPU should redraw. - */ - bool postHeuristicsHandling(hwc_context_t *ctx, - hwc_display_contents_1_t* list); - void reset(hwc_context_t *ctx); - bool isSupportedForMDPComp(hwc_context_t *ctx, hwc_layer_1_t* layer); - bool resourceCheck(hwc_context_t* ctx, hwc_display_contents_1_t* list); - hwc_rect_t getUpdatingFBRect(hwc_context_t *ctx, - hwc_display_contents_1_t* list); - /* checks for conditions to enable partial udpate */ - bool canPartialUpdate(hwc_context_t *ctx, hwc_display_contents_1_t* list); - - int mDpy; - static bool sEnabled; - static bool sEnableMixedMode; - static int sSimulationFlags; - static bool sDebugLogs; - static bool sIdleFallBack; - static int sMaxPipesPerMixer; - static bool sSrcSplitEnabled; - static IdleInvalidator *sIdleInvalidator; - struct FrameInfo mCurrentFrame; - struct LayerCache mCachedFrame; - static bool sIsPartialUpdateActive; - //Enable 4kx2k yuv layer split - static bool sEnableYUVsplit; - bool mModeOn; // if prepare happened - bool allocSplitVGPipesfor4k2k(hwc_context_t *ctx, int index); - bool mPrevModeOn; //if previous prepare happened - //Enable Partial Update for MDP3 targets - static bool enablePartialUpdateForMDP3; -}; - -class MDPCompNonSplit : public MDPComp { -public: - explicit MDPCompNonSplit(int dpy):MDPComp(dpy){}; - virtual ~MDPCompNonSplit(){}; - virtual bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list); - -private: - struct MdpPipeInfoNonSplit : public MdpPipeInfo { - ovutils::eDest index; - virtual ~MdpPipeInfoNonSplit() {}; - }; - - /* configure's overlay pipes for the frame */ - virtual int configure(hwc_context_t *ctx, hwc_layer_1_t *layer, - PipeLayerPair& pipeLayerPair); - - /* allocates pipes to selected candidates */ - virtual bool allocLayerPipes(hwc_context_t *ctx, - hwc_display_contents_1_t* list); - - /* Increments mdpCount if 4k2k yuv layer split is enabled. - * updates framebuffer z order if fb lies above source-split layer */ - virtual void adjustForSourceSplit(hwc_context_t *ctx, - hwc_display_contents_1_t* list); - - /* configures 4kx2k yuv layer to 2 VG pipes*/ - virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer, - PipeLayerPair& PipeLayerPair); - /* generates ROI based on the modified area of the frame */ - virtual void generateROI(hwc_context_t *ctx, - hwc_display_contents_1_t* list); - /* validates the ROI generated for fallback conditions */ - virtual bool validateAndApplyROI(hwc_context_t *ctx, - hwc_display_contents_1_t* list); - /* Trims fbRect calculated against ROI generated */ - virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect); -}; - -class MDPCompSplit : public MDPComp { -public: - explicit MDPCompSplit(int dpy):MDPComp(dpy){}; - virtual ~MDPCompSplit(){}; - virtual bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list); - -protected: - struct MdpPipeInfoSplit : public MdpPipeInfo { - ovutils::eDest lIndex; - ovutils::eDest rIndex; - virtual ~MdpPipeInfoSplit() {}; - }; - - virtual bool acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer, - MdpPipeInfoSplit& pipe_info); - - /* configure's overlay pipes for the frame */ - virtual int configure(hwc_context_t *ctx, hwc_layer_1_t *layer, - PipeLayerPair& pipeLayerPair); - - /* allocates pipes to selected candidates */ - virtual bool allocLayerPipes(hwc_context_t *ctx, - hwc_display_contents_1_t* list); -private: - /* Increments mdpCount if 4k2k yuv layer split is enabled. - * updates framebuffer z order if fb lies above source-split layer */ - virtual void adjustForSourceSplit(hwc_context_t *ctx, - hwc_display_contents_1_t* list); - - /* configures 4kx2k yuv layer*/ - virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer, - PipeLayerPair& PipeLayerPair); - /* generates ROI based on the modified area of the frame */ - virtual void generateROI(hwc_context_t *ctx, - hwc_display_contents_1_t* list); - /* validates the ROI generated for fallback conditions */ - virtual bool validateAndApplyROI(hwc_context_t *ctx, - hwc_display_contents_1_t* list); - /* Trims fbRect calculated against ROI generated */ - virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect); -}; - -class MDPCompSrcSplit : public MDPCompSplit { -public: - explicit MDPCompSrcSplit(int dpy) : MDPCompSplit(dpy){}; - virtual ~MDPCompSrcSplit(){}; -private: - virtual bool acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer, - MdpPipeInfoSplit& pipe_info); - - virtual int configure(hwc_context_t *ctx, hwc_layer_1_t *layer, - PipeLayerPair& pipeLayerPair); -}; - -}; //namespace -#endif diff --git a/msm8909/libhwcomposer/hwc_qclient.cpp b/msm8909/libhwcomposer/hwc_qclient.cpp deleted file mode 100644 index 4db4fa7e..00000000 --- a/msm8909/libhwcomposer/hwc_qclient.cpp +++ /dev/null @@ -1,401 +0,0 @@ -/* - * Copyright (c) 2013-15, 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 CLIENTS; 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 <hwc_qclient.h> -#include <IQService.h> -#include <hwc_utils.h> -#include <mdp_version.h> -#include <hwc_mdpcomp.h> -#include <hwc_virtual.h> -#include <overlay.h> -#include <display_config.h> -#include <hwc_qdcm.h> - -#define QCLIENT_DEBUG 0 - -using namespace android; -using namespace qService; -using namespace qhwc; -using namespace overlay; -using namespace qdutils; -using namespace qQdcm; - -namespace qClient { - -// ---------------------------------------------------------------------------- -QClient::QClient(hwc_context_t *ctx) : mHwcContext(ctx), - mMPDeathNotifier(new MPDeathNotifier(ctx)) -{ - ALOGD_IF(QCLIENT_DEBUG, "QClient Constructor invoked"); -} - -QClient::~QClient() -{ - ALOGD_IF(QCLIENT_DEBUG,"QClient Destructor invoked"); -} - -static void securing(hwc_context_t *ctx, uint32_t startEnd) { - //The only way to make this class in this process subscribe to media - //player's death. - IMediaDeathNotifier::getMediaPlayerService(); - - ctx->mDrawLock.lock(); - ctx->mSecuring = startEnd; - //We're done securing - if(startEnd == IQService::END) - ctx->mSecureMode = true; - ctx->mDrawLock.unlock(); - - if(ctx->proc) - ctx->proc->invalidate(ctx->proc); -} - -static void unsecuring(hwc_context_t *ctx, uint32_t startEnd) { - ctx->mDrawLock.lock(); - ctx->mSecuring = startEnd; - //We're done unsecuring - if(startEnd == IQService::END) - ctx->mSecureMode = false; - ctx->mDrawLock.unlock(); - - if(ctx->proc) - ctx->proc->invalidate(ctx->proc); -} - -void QClient::MPDeathNotifier::died() { - mHwcContext->mDrawLock.lock(); - ALOGD_IF(QCLIENT_DEBUG, "Media Player died"); - mHwcContext->mSecuring = false; - mHwcContext->mSecureMode = false; - mHwcContext->mDrawLock.unlock(); - if(mHwcContext->proc) - mHwcContext->proc->invalidate(mHwcContext->proc); -} - -static android::status_t screenRefresh(hwc_context_t *ctx) { - status_t result = NO_INIT; - if(ctx->proc) { - ctx->proc->invalidate(ctx->proc); - result = NO_ERROR; - } - return result; -} - -static void setExtOrientation(hwc_context_t *ctx, uint32_t orientation) { - ctx->mExtOrientation = orientation; -} - -static void isExternalConnected(hwc_context_t* ctx, Parcel* outParcel) { - int connected; - connected = ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected ? 1 : 0; - outParcel->writeInt32(connected); -} - -static void getDisplayAttributes(hwc_context_t* ctx, const Parcel* inParcel, - Parcel* outParcel) { - int dpy = inParcel->readInt32(); - outParcel->writeInt32(ctx->dpyAttr[dpy].vsync_period); - if (ctx->dpyAttr[dpy].customFBSize) { - outParcel->writeInt32(ctx->dpyAttr[dpy].xres_new); - outParcel->writeInt32(ctx->dpyAttr[dpy].yres_new); - } else { - outParcel->writeInt32(ctx->dpyAttr[dpy].xres); - outParcel->writeInt32(ctx->dpyAttr[dpy].yres); - } - outParcel->writeFloat(ctx->dpyAttr[dpy].xdpi); - outParcel->writeFloat(ctx->dpyAttr[dpy].ydpi); - //XXX: Need to check what to return for HDMI - outParcel->writeInt32(ctx->mMDP.panel); -} -static void setHSIC(const Parcel* inParcel) { - int dpy = inParcel->readInt32(); - ALOGD_IF(0, "In %s: dpy = %d", __FUNCTION__, dpy); - HSICData_t hsic_data; - hsic_data.hue = inParcel->readInt32(); - hsic_data.saturation = inParcel->readFloat(); - hsic_data.intensity = inParcel->readInt32(); - hsic_data.contrast = inParcel->readFloat(); - //XXX: Actually set the HSIC data through ABL lib -} - - -static void setBufferMirrorMode(hwc_context_t *ctx, uint32_t enable) { - ctx->mBufferMirrorMode = enable; -} - -static status_t getDisplayVisibleRegion(hwc_context_t* ctx, int dpy, - Parcel* outParcel) { - // Get the info only if the dpy is valid - if(dpy >= HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) { - Locker::Autolock _sl(ctx->mDrawLock); - if(dpy && (ctx->mExtOrientation || ctx->mBufferMirrorMode)) { - // Return the destRect on external, if external orienation - // is enabled - outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.left); - outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.top); - outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.right); - outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.bottom); - } else { - outParcel->writeInt32(ctx->mViewFrame[dpy].left); - outParcel->writeInt32(ctx->mViewFrame[dpy].top); - outParcel->writeInt32(ctx->mViewFrame[dpy].right); - outParcel->writeInt32(ctx->mViewFrame[dpy].bottom); - } - return NO_ERROR; - } else { - ALOGE("In %s: invalid dpy index %d", __FUNCTION__, dpy); - return BAD_VALUE; - } -} - -// USed for setting the secondary(hdmi/wfd) status -static void setSecondaryDisplayStatus(hwc_context_t *ctx, - const Parcel* inParcel) { - uint32_t dpy = inParcel->readInt32(); - uint32_t status = inParcel->readInt32(); - ALOGD_IF(QCLIENT_DEBUG, "%s: dpy = %d status = %s", __FUNCTION__, - dpy, getExternalDisplayState(status)); - - if(dpy > HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) { - if(dpy == HWC_DISPLAY_VIRTUAL && status == qdutils::EXTERNAL_OFFLINE) { - ctx->mWfdSyncLock.lock(); - ctx->mWfdSyncLock.signal(); - ctx->mWfdSyncLock.unlock(); - } else if(status == qdutils::EXTERNAL_PAUSE) { - handle_pause(ctx, dpy); - } else if(status == qdutils::EXTERNAL_RESUME) { - handle_resume(ctx, dpy); - } - } else { - ALOGE("%s: Invalid dpy %d", __FUNCTION__, dpy); - return; - } -} - - -static status_t setViewFrame(hwc_context_t* ctx, const Parcel* inParcel) { - int dpy = inParcel->readInt32(); - if(dpy >= HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) { - Locker::Autolock _sl(ctx->mDrawLock); - ctx->mViewFrame[dpy].left = inParcel->readInt32(); - ctx->mViewFrame[dpy].top = inParcel->readInt32(); - ctx->mViewFrame[dpy].right = inParcel->readInt32(); - ctx->mViewFrame[dpy].bottom = inParcel->readInt32(); - ALOGD_IF(QCLIENT_DEBUG, "%s: mViewFrame[%d] = [%d %d %d %d]", - __FUNCTION__, dpy, - ctx->mViewFrame[dpy].left, ctx->mViewFrame[dpy].top, - ctx->mViewFrame[dpy].right, ctx->mViewFrame[dpy].bottom); - return NO_ERROR; - } else { - ALOGE("In %s: invalid dpy index %d", __FUNCTION__, dpy); - return BAD_VALUE; - } -} - -static void toggleDynamicDebug(hwc_context_t* ctx, const Parcel* inParcel) { - int debug_type = inParcel->readInt32(); - bool enable = !!inParcel->readInt32(); - ALOGD("%s: debug_type: %d enable:%d", - __FUNCTION__, debug_type, enable); - Locker::Autolock _sl(ctx->mDrawLock); - switch (debug_type) { - //break is ignored for DEBUG_ALL to toggle all of them at once - case IQService::DEBUG_ALL: - case IQService::DEBUG_MDPCOMP: - qhwc::MDPComp::dynamicDebug(enable); - if (debug_type != IQService::DEBUG_ALL) - break; - case IQService::DEBUG_VSYNC: - ctx->vstate.debug = enable; - if (debug_type != IQService::DEBUG_ALL) - break; - case IQService::DEBUG_VD: - HWCVirtualVDS::dynamicDebug(enable); - if (debug_type != IQService::DEBUG_ALL) - break; - case IQService::DEBUG_PIPE_LIFECYCLE: - Overlay::debugPipeLifecycle(enable); - if (debug_type != IQService::DEBUG_ALL) - break; - } -} - -static void setIdleTimeout(hwc_context_t* ctx, const Parcel* inParcel) { - uint32_t timeout = (uint32_t)inParcel->readInt32(); - ALOGD("%s :%u ms", __FUNCTION__, timeout); - Locker::Autolock _sl(ctx->mDrawLock); - MDPComp::setIdleTimeout(timeout); -} - -static void configureDynRefreshRate(hwc_context_t* ctx, - const Parcel* inParcel) { - uint32_t op = (uint32_t)inParcel->readInt32(); - uint32_t refresh_rate = (uint32_t)inParcel->readInt32(); - MDPVersion& mdpHw = MDPVersion::getInstance(); - uint32_t dpy = HWC_DISPLAY_PRIMARY; - - if(mdpHw.isDynFpsSupported()) { - Locker::Autolock _sl(ctx->mDrawLock); - - switch (op) { - case DISABLE_METADATA_DYN_REFRESH_RATE: - ctx->mUseMetaDataRefreshRate = false; - setRefreshRate(ctx, dpy, ctx->dpyAttr[dpy].refreshRate); - break; - case ENABLE_METADATA_DYN_REFRESH_RATE: - ctx->mUseMetaDataRefreshRate = true; - setRefreshRate(ctx, dpy, ctx->dpyAttr[dpy].refreshRate); - break; - case SET_BINDER_DYN_REFRESH_RATE: - if(ctx->mUseMetaDataRefreshRate) - ALOGW("%s: Ignoring binder request to change refresh-rate", - __FUNCTION__); - else { - uint32_t rate = roundOff(refresh_rate); - if((rate >= mdpHw.getMinFpsSupported() && - rate <= mdpHw.getMaxFpsSupported())) { - setRefreshRate(ctx, dpy, rate); - } else { - ALOGE("%s: Requested refresh-rate should be between \ - (%d) and (%d). Given (%d)", __FUNCTION__, - mdpHw.getMinFpsSupported(), - mdpHw.getMaxFpsSupported(), rate); - } - } - break; - default: - ALOGE("%s: Invalid op %d",__FUNCTION__,op); - } - } -} - -static status_t setPartialUpdateState(hwc_context_t *ctx, uint32_t state) { - ALOGD("%s: state: %d", __FUNCTION__, state); - switch(state) { - case IQService::PREF_PARTIAL_UPDATE: - if(qhwc::MDPComp::setPartialUpdatePref(ctx, true) < 0) - return NO_INIT; - return NO_ERROR; - case IQService::PREF_POST_PROCESSING: - if(qhwc::MDPComp::setPartialUpdatePref(ctx, false) < 0) - return NO_INIT; - qhwc::MDPComp::enablePartialUpdate(false); - return NO_ERROR; - case IQService::ENABLE_PARTIAL_UPDATE: - qhwc::MDPComp::enablePartialUpdate(true); - return NO_ERROR; - default: - ALOGE("%s: Invalid state", __FUNCTION__); - return NO_ERROR; - }; -} - -static void toggleScreenUpdate(hwc_context_t* ctx, uint32_t on) { - ALOGD("%s: toggle update: %d", __FUNCTION__, on); - if (on == 0) { - ctx->mDrawLock.lock(); - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isPause = true; - ctx->mOverlay->configBegin(); - ctx->mOverlay->configDone(); - ctx->mRotMgr->clear(); - if(!Overlay::displayCommit(ctx->dpyAttr[0].fd)) { - ALOGE("%s: Display commit failed", __FUNCTION__); - } - ctx->mDrawLock.unlock(); - } else { - ctx->mDrawLock.lock(); - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isPause = false; - ctx->mDrawLock.unlock(); - ctx->proc->invalidate(ctx->proc); - } -} - -status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel, - Parcel* outParcel) { - status_t ret = NO_ERROR; - - switch(command) { - case IQService::SECURING: - securing(mHwcContext, inParcel->readInt32()); - break; - case IQService::UNSECURING: - unsecuring(mHwcContext, inParcel->readInt32()); - break; - case IQService::SCREEN_REFRESH: - return screenRefresh(mHwcContext); - break; - case IQService::EXTERNAL_ORIENTATION: - setExtOrientation(mHwcContext, inParcel->readInt32()); - break; - case IQService::BUFFER_MIRRORMODE: - setBufferMirrorMode(mHwcContext, inParcel->readInt32()); - break; - case IQService::GET_DISPLAY_VISIBLE_REGION: - ret = getDisplayVisibleRegion(mHwcContext, inParcel->readInt32(), - outParcel); - break; - case IQService::CHECK_EXTERNAL_STATUS: - isExternalConnected(mHwcContext, outParcel); - break; - case IQService::GET_DISPLAY_ATTRIBUTES: - getDisplayAttributes(mHwcContext, inParcel, outParcel); - break; - case IQService::SET_HSIC_DATA: - setHSIC(inParcel); - break; - case IQService::SET_SECONDARY_DISPLAY_STATUS: - setSecondaryDisplayStatus(mHwcContext, inParcel); - break; - case IQService::SET_VIEW_FRAME: - setViewFrame(mHwcContext, inParcel); - break; - case IQService::DYNAMIC_DEBUG: - toggleDynamicDebug(mHwcContext, inParcel); - break; - case IQService::SET_IDLE_TIMEOUT: - setIdleTimeout(mHwcContext, inParcel); - break; - case IQService::SET_PARTIAL_UPDATE: - ret = setPartialUpdateState(mHwcContext, inParcel->readInt32()); - break; - case IQService::CONFIGURE_DYN_REFRESH_RATE: - configureDynRefreshRate(mHwcContext, inParcel); - case IQService::QDCM_SVC_CMDS: - qdcmCmdsHandler(mHwcContext, inParcel, outParcel); - break; - case IQService::TOGGLE_SCREEN_UPDATE: - toggleScreenUpdate(mHwcContext, inParcel->readInt32()); - break; - default: - ret = NO_ERROR; - } - return ret; -} - -} diff --git a/msm8909/libhwcomposer/hwc_qdcm.cpp b/msm8909/libhwcomposer/hwc_qdcm.cpp deleted file mode 100644 index 9821e4e6..00000000 --- a/msm8909/libhwcomposer/hwc_qdcm.cpp +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (c) 2014, The Linux Foundation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of The Linux Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <hwc_qdcm.h> -#include <hwc_utils.h> -#include <utils/String16.h> -#include <mdp_version.h> -#include "mode_manager.h" -#include "libmm-disp-apis.h" -#include "IQService.h" - -using namespace android; -using namespace qService; -using namespace qhwc; -using namespace qmode; - -namespace qQdcm { -//---------------------------------------------------------------------------- -void qdcmInitContext(hwc_context_t *ctx) -{ - loadQdcmLibrary(ctx); -} - -void qdcmCloseContext(hwc_context_t *ctx) -{ - if (ctx->mQdcmInfo.mQdcmMode) { - unloadQdcmLibrary(ctx); - } -} - -void qdcmApplyDefaultAfterBootAnimationDone(hwc_context_t *ctx) -{ - if (ctx->mQdcmInfo.mQdcmMode) - ctx->mQdcmInfo.mQdcmMode->applyDefaultMode(0); -} - -static void qdcmSetActiveMode(hwc_context_t *ctx, const Parcel *in, Parcel *out) -{ - int ret = 0; - - if (ctx->mQdcmInfo.mQdcmMode && in && out) { - - struct SET_MODE_PROP_IN params = - { (disp_id_type)in->readInt32(), in->readInt32()}; - - ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_SET_ACTIVE_MODE, - (void *)¶ms, (void *)NULL); - - out->writeInt32(ret); //return operation status via binder. - } -} - -static void qdcmSetDefaultMode(hwc_context_t *ctx, const Parcel *in, Parcel *out) -{ - int ret = 0; - - if (ctx->mQdcmInfo.mQdcmMode && in && out) { - - struct SET_MODE_PROP_IN params = - { (disp_id_type)in->readInt32(), in->readInt32()}; - - ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_SET_DEFAULT_MODE, - (void *)¶ms, (void *)NULL); - - out->writeInt32(ret); //return operation status via binder. - } -} - -static void qdcmGetDefaultMode(hwc_context_t *ctx, - const Parcel *in, Parcel *out) -{ - int ret = 0; - - if (ctx->mQdcmInfo.mQdcmMode && in && out) { - - int params = in->readInt32(); - int modeid = 0; - - ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_GET_DEFAULT_MODE, - (const void *)¶ms, (void *)&modeid); - - out->writeInt32(modeid); - out->writeInt32(ret); //return operation status via binder. - } -} - -static void qdcmGetColorBalanceRange(hwc_context_t *ctx __unused, - const Parcel *in __unused, Parcel *out __unused) -{ -} - -static void qdcmGetColorBalance(hwc_context_t *ctx, - const Parcel *in, Parcel *out) -{ - int ret = 0; - - if (ctx->mQdcmInfo.mQdcmMode && in && out) { - - int params = in->readInt32(); - int warmness = 0; - - ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_GET_CB, - (const void *)¶ms, (void *)&warmness); - - out->writeInt32(warmness); - out->writeInt32(ret); //return operation status via binder. - } -} - -static void qdcmSetColorBalance(hwc_context_t *ctx, - const Parcel *in, Parcel *out) -{ - int ret = 0; - - if (ctx->mQdcmInfo.mQdcmMode && in && out) { - - struct SET_CB_IN params = - { (disp_id_type)in->readInt32(), in->readInt32() }; - - ALOGD_IF(QDCM_DEBUG, "%s dispID = %d, warmness = %d\n", - __FUNCTION__, params.id, params.warmness); - - ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_SET_CB, - (const void *)¶ms, NULL); - - out->writeInt32(ret); //return operation status via binder. - } -} - -static void qdcmSaveModeV2(hwc_context_t *ctx, const Parcel *in, Parcel *out) -{ - int ret = 0; - - if (ctx->mQdcmInfo.mQdcmMode && in && out) { - - struct SAVE_DISPLAY_MODE_V2_IN params = - { (disp_id_type)in->readInt32(), - in->readCString(), - (uint32_t)in->readInt32(), - in->readInt32() - }; - int value = 0; - - ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_SAVE_MODE_V2, - (const void *)¶ms, (void *)&value); - - out->writeInt32(value); - out->writeInt32(ret); //return operation status via binder. - } -} - -static void qdcmSetPaConfig(hwc_context_t *ctx, const Parcel *in, Parcel *out) -{ - int ret = 0; - - if (ctx->mQdcmInfo.mQdcmMode && in && out) { - - struct SET_PA_CONFIG_IN params; - - params.id = (disp_id_type)in->readInt32(); - params.pa.ops = in->readInt32(); - params.pa.data.hue = in->readInt32(); - params.pa.data.saturation = in->readInt32(); - params.pa.data.value = in->readInt32(); - params.pa.data.contrast = in->readInt32(); - params.pa.data.sat_thresh = in->readInt32(); - - ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_SET_PA_CONFIG, - (const void *)¶ms, NULL); - - out->writeInt32(ret); //return operation status via binder. - } -} - -static void qdcmGetPaConfig(hwc_context_t *ctx, const Parcel *in, Parcel *out) -{ - int ret = 0; - - if (ctx->mQdcmInfo.mQdcmMode && in && out) { - - int params = in->readInt32(); - struct disp_pa_config value; - - ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_GET_PA_CONFIG, - (const void *)¶ms, (void *)&value); - - out->writeInt32(value.ops); - out->writeInt32(value.data.hue); - out->writeInt32(value.data.saturation); - out->writeInt32(value.data.value); - out->writeInt32(value.data.contrast); - out->writeInt32(value.data.sat_thresh); - - out->writeInt32(ret); //return operation status via binder. - } -} - -static void qdcmGetPaRange(hwc_context_t *ctx, const Parcel *in, Parcel *out) -{ - int ret = 0; - - if (ctx->mQdcmInfo.mQdcmMode && in && out) { - - int params = in->readInt32(); - struct disp_pa_range value; - - ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_GET_PA_RANGE, - (const void *)¶ms, (void *)&value); - - out->writeInt32(value.max.hue); - out->writeInt32(value.max.saturation); - out->writeInt32(value.max.value); - out->writeInt32(value.max.contrast); - out->writeInt32(value.max.sat_thresh); - out->writeInt32(value.min.hue); - out->writeInt32(value.min.saturation); - out->writeInt32(value.min.value); - out->writeInt32(value.min.contrast); - out->writeInt32(value.min.sat_thresh); - - out->writeInt32(ret); //return operation status via binder. - } -} - -void qdcmCmdsHandler(hwc_context_t *ctx, const Parcel *in, Parcel *out) -{ - int subcmd = in->readInt32(); - - ALOGD_IF(QDCM_DEBUG, "%s enter subcmd = %d\n", __FUNCTION__, subcmd); - switch (subcmd) { - case CMD_SET_ACTIVE_MODE: - qdcmSetActiveMode(ctx, in, out); - break; - case CMD_SET_DEFAULT_MODE: - qdcmSetDefaultMode(ctx, in, out); - break; - case CMD_GET_DEFAULT_MODE: - qdcmGetDefaultMode(ctx, in, out); - break; - case CMD_GET_CB_RANGE: - qdcmGetColorBalanceRange(ctx, in, out); - break; - case CMD_GET_CB: - qdcmGetColorBalance(ctx, in, out); - break; - case CMD_SET_CB: - qdcmSetColorBalance(ctx, in, out); - break; - case CMD_SAVE_MODE_V2: - qdcmSaveModeV2(ctx, in, out); - break; - case CMD_SET_PA_CONFIG: - qdcmSetPaConfig(ctx, in, out); - break; - case CMD_GET_PA_CONFIG: - qdcmGetPaConfig(ctx, in, out); - break; - case CMD_GET_PA_RANGE: - qdcmGetPaRange(ctx, in, out); - break; - } -} - - -} //namespace qQdcm - diff --git a/msm8909/libhwcomposer/hwc_qdcm.h b/msm8909/libhwcomposer/hwc_qdcm.h deleted file mode 100644 index 64531596..00000000 --- a/msm8909/libhwcomposer/hwc_qdcm.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2014, The Linux Foundation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of The Linux Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef ANDROID_QDCM_H -#define ANDROID_QDCM_H - -#include <utils/Errors.h> -#include <sys/types.h> -#include <cutils/log.h> -#include <hwc_utils.h> -#include <dlfcn.h> -#include <binder/Parcel.h> -#include <cutils/properties.h> - -#define QDCM_DEBUG 0 - -namespace qmode { -class ModeManager; -} - -using namespace android; - -namespace qQdcm { -// ---------------------------------------------------------------------------- - -//function prototypes used for QDCM library and service -static inline void loadQdcmLibrary(hwc_context_t *ctx) -{ - ctx->mQdcmInfo.mQdcmLib = dlopen("libmm-qdcm.so", RTLD_NOW); - qmode::ModeManager* (*factory)() = NULL; - - if (ctx->mQdcmInfo.mQdcmLib) - *(void **)&factory = dlsym(ctx->mQdcmInfo.mQdcmLib, "getObject"); - - if (factory) { - ctx->mQdcmInfo.mQdcmMode = factory(); - } else { - ctx->mQdcmInfo.mQdcmMode = NULL; - ALOGE("QDCM LIbrary load failing!"); - } - - ALOGD_IF(QDCM_DEBUG, "QDCM LIbrary loaded successfully!"); -} - -static inline void unloadQdcmLibrary(hwc_context_t *ctx) -{ - void (*destroy)(qmode::ModeManager*) = NULL; - - if (ctx->mQdcmInfo.mQdcmLib) { - *(void **)&destroy = dlsym(ctx->mQdcmInfo.mQdcmLib, "deleteObject"); - - if (destroy) { - destroy(ctx->mQdcmInfo.mQdcmMode); - ctx->mQdcmInfo.mQdcmMode = NULL; - } - - dlclose(ctx->mQdcmInfo.mQdcmLib); - ctx->mQdcmInfo.mQdcmLib = NULL; - } -} - -void qdcmInitContext(hwc_context_t *); -void qdcmCloseContext(hwc_context_t *); -void qdcmApplyDefaultAfterBootAnimationDone(hwc_context_t *); -void qdcmCmdsHandler(hwc_context_t*, const Parcel*, Parcel*); - -}; // namespace qQdcm -#endif // ANDROID_QDCM_H diff --git a/msm8909/libhwcomposer/hwc_uevents.cpp b/msm8909/libhwcomposer/hwc_uevents.cpp deleted file mode 100644 index 0c85a8db..00000000 --- a/msm8909/libhwcomposer/hwc_uevents.cpp +++ /dev/null @@ -1,243 +0,0 @@ - -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012-14, The Linux Foundation. All rights reserved. - * - * Not a Contribution, Apache license notifications and license are - * retained for attribution purposes only. - - * 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. - */ -#define UEVENT_DEBUG 0 -#include <hardware_legacy/uevent.h> -#include <utils/Log.h> -#include <sys/resource.h> -#include <sys/prctl.h> -#include <string.h> -#include <stdlib.h> -#include "hwc_utils.h" -#include "hwc_fbupdate.h" -#include "hwc_mdpcomp.h" -#include "hwc_copybit.h" -#include "comptype.h" -#include "hdmi.h" -#include "hwc_virtual.h" -#include "mdp_version.h" -using namespace overlay; -namespace qhwc { -#define HWC_UEVENT_SWITCH_STR "change@/devices/virtual/switch/" -#define HWC_UEVENT_THREAD_NAME "hwcUeventThread" - -/* Parse uevent data for devices which we are interested */ -static int getConnectedDisplay(hwc_context_t* ctx, const char* strUdata) -{ - int ret = -1; - // Switch node for HDMI as PRIMARY/EXTERNAL - if(strcasestr("change@/devices/virtual/switch/hdmi", strUdata)) { - if (ctx->mHDMIDisplay->isHDMIPrimaryDisplay()) { - ret = HWC_DISPLAY_PRIMARY; - } else { - ret = HWC_DISPLAY_EXTERNAL; - } - } - return ret; -} - -static bool getPanelResetStatus(hwc_context_t* ctx, const char* strUdata, int len) -{ - const char* iter_str = strUdata; - if (strcasestr("change@/devices/virtual/graphics/fb0", strUdata)) { - while(((iter_str - strUdata) <= len) && (*iter_str)) { - const char* pstr = strstr(iter_str, "PANEL_ALIVE=0"); - if (pstr != NULL) { - ALOGI("%s: got change event in fb0 with PANEL_ALIVE=0", - __FUNCTION__); - ctx->mPanelResetStatus = true; - return true; - } - iter_str += strlen(iter_str)+1; - } - } - return false; -} - -/* Parse uevent data for action requested for the display */ -static int getConnectedState(const char* strUdata, int len) -{ - const char* iter_str = strUdata; - while(((iter_str - strUdata) <= len) && (*iter_str)) { - const char* pstr = strstr(iter_str, "SWITCH_STATE="); - if (pstr != NULL) { - return (atoi(pstr + strlen("SWITCH_STATE="))); - } - iter_str += strlen(iter_str)+1; - } - return -1; -} - -static void handle_uevent(hwc_context_t* ctx, const char* udata, int len) -{ - bool bpanelReset = getPanelResetStatus(ctx, udata, len); - if (bpanelReset) { - ctx->proc->invalidate(ctx->proc); - return; - } - - int dpy = getConnectedDisplay(ctx, udata); - if(dpy < 0) { - ALOGD_IF(UEVENT_DEBUG, "%s: Not disp Event ", __FUNCTION__); - return; - } - - int switch_state = getConnectedState(udata, len); - - ALOGE_IF(UEVENT_DEBUG,"%s: uevent received: %s switch state: %d", - __FUNCTION__,udata, switch_state); - - switch(switch_state) { - case EXTERNAL_OFFLINE: - { - /* Display not connected */ - if(!ctx->dpyAttr[dpy].connected){ - ALOGE_IF(UEVENT_DEBUG,"%s: Ignoring EXTERNAL_OFFLINE event" - "for display: %d", __FUNCTION__, dpy); - break; - } - - ctx->mDrawLock.lock(); - handle_offline(ctx, dpy); - ctx->mDrawLock.unlock(); - - /* We need to send hotplug to SF only when we are disconnecting - * HDMI as an external display. */ - if(dpy == HWC_DISPLAY_EXTERNAL) { - ALOGE_IF(UEVENT_DEBUG,"%s:Sending EXTERNAL OFFLINE hotplug" - "event", __FUNCTION__); - ctx->proc->hotplug(ctx->proc, dpy, EXTERNAL_OFFLINE); - } - break; - } - case EXTERNAL_ONLINE: - { - /* Display already connected */ - if(ctx->dpyAttr[dpy].connected) { - ALOGE_IF(UEVENT_DEBUG,"%s: Ignoring EXTERNAL_ONLINE event" - "for display: %d", __FUNCTION__, dpy); - break; - } - - if (ctx->mHDMIDisplay->isHDMIPrimaryDisplay()) { - ctx->mDrawLock.lock(); - handle_online(ctx, dpy); - ctx->mDrawLock.unlock(); - - ctx->proc->invalidate(ctx->proc); - break; - } else { - ctx->mDrawLock.lock(); - //Force composition to give up resources like pipes and - //close fb. For example if assertive display is going on, - //fb2 could be open, thus connecting Layer Mixer#0 to - //WriteBack module. If HDMI attempts to open fb1, the driver - //will try to attach Layer Mixer#0 to HDMI INT, which will - //fail, since Layer Mixer#0 is still connected to WriteBack. - //This block will force composition to close fb2 in above - //example. - ctx->dpyAttr[dpy].isConfiguring = true; - ctx->mDrawLock.unlock(); - - ctx->proc->invalidate(ctx->proc); - } - //2 cycles for slower content - usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period - * 2 / 1000); - - if(isVDConnected(ctx)) { - // Do not initiate WFD teardown if WFD architecture is based - // on VDS mechanism. - // WFD Stack listens to HDMI intent and initiates virtual - // display teardown. - // ToDo: Currently non-WFD Virtual display clients do not - // involve HWC. If there is a change, we need to come up - // with mechanism of how to address non-WFD Virtual display - // clients + HDMI - ctx->mWfdSyncLock.lock(); - ALOGD_IF(HWC_WFDDISPSYNC_LOG, - "%s: Waiting for wfd-teardown to be signalled", - __FUNCTION__); - ctx->mWfdSyncLock.wait(); - ALOGD_IF(HWC_WFDDISPSYNC_LOG, - "%s: Teardown signalled. Completed waiting in" - "uevent thread", __FUNCTION__); - ctx->mWfdSyncLock.unlock(); - } - ctx->mHDMIDisplay->configure(); - ctx->mHDMIDisplay->activateDisplay(); - - ctx->mDrawLock.lock(); - updateDisplayInfo(ctx, dpy); - initCompositionResources(ctx, dpy); - ctx->dpyAttr[dpy].isPause = false; - ctx->dpyAttr[dpy].connected = true; - ctx->dpyAttr[dpy].isConfiguring = true; - ctx->mDrawLock.unlock(); - - /* External display is HDMI */ - ALOGE_IF(UEVENT_DEBUG, "%s: Sending EXTERNAL ONLINE" - "hotplug event", __FUNCTION__); - ctx->proc->hotplug(ctx->proc, dpy, EXTERNAL_ONLINE); - break; - } - default: - { - ALOGE("%s: Invalid state to swtich:%d", __FUNCTION__, switch_state); - break; - } - } -} - -static void *uevent_loop(void *param) -{ - int len = 0; - static char udata[PAGE_SIZE]; - hwc_context_t * ctx = reinterpret_cast<hwc_context_t *>(param); - char thread_name[64] = HWC_UEVENT_THREAD_NAME; - prctl(PR_SET_NAME, (unsigned long) &thread_name, 0, 0, 0); - setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY); - if(!uevent_init()) { - ALOGE("%s: failed to init uevent ",__FUNCTION__); - return NULL; - } - - while(1) { - len = uevent_next_event(udata, (int)sizeof(udata) - 2); - handle_uevent(ctx, udata, len); - } - - return NULL; -} - -void init_uevent_thread(hwc_context_t* ctx) -{ - pthread_t uevent_thread; - int ret; - - ALOGI("Initializing UEVENT Thread"); - ret = pthread_create(&uevent_thread, NULL, uevent_loop, (void*) ctx); - if (ret) { - ALOGE("%s: failed to create %s: %s", __FUNCTION__, - HWC_UEVENT_THREAD_NAME, strerror(ret)); - } -} - -}; //namespace diff --git a/msm8909/libhwcomposer/hwc_utils.cpp b/msm8909/libhwcomposer/hwc_utils.cpp deleted file mode 100644 index 3b320728..00000000 --- a/msm8909/libhwcomposer/hwc_utils.cpp +++ /dev/null @@ -1,2907 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012-2014,2016, The Linux Foundation All rights reserved. - * - * Not a Contribution, Apache license notifications and license are retained - * for attribution purposes only. - * - * 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. - */ -#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL) -#define HWC_UTILS_DEBUG 0 -#include <math.h> -#include <sys/ioctl.h> -#include <linux/fb.h> -#include <binder/IServiceManager.h> -#include <EGL/egl.h> -#include <cutils/properties.h> -#include <utils/Trace.h> -#include <gralloc_priv.h> -#include <overlay.h> -#include <overlayRotator.h> -#include <overlayWriteback.h> -#include "hwc_utils.h" -#include "hwc_mdpcomp.h" -#include "hwc_fbupdate.h" -#include "hwc_ad.h" -#include "mdp_version.h" -#include "hwc_copybit.h" -#include "hwc_dump_layers.h" -#include "hdmi.h" -#include "hwc_qclient.h" -#include "QService.h" -#include "comptype.h" -#include "hwc_virtual.h" -#include "qd_utils.h" -#include "hwc_qdcm.h" -#include <sys/sysinfo.h> -#include <dlfcn.h> - -using namespace qClient; -using namespace qService; -using namespace android; -using namespace overlay; -using namespace overlay::utils; -using namespace qQdcm; -namespace ovutils = overlay::utils; - -#ifdef QTI_BSP - -#define EGL_GPU_HINT_1 0x32D0 -#define EGL_GPU_HINT_2 0x32D1 - -#define EGL_GPU_LEVEL_0 0x0 -#define EGL_GPU_LEVEL_1 0x1 -#define EGL_GPU_LEVEL_2 0x2 -#define EGL_GPU_LEVEL_3 0x3 -#define EGL_GPU_LEVEL_4 0x4 -#define EGL_GPU_LEVEL_5 0x5 - -#endif - -#define PROP_DEFAULT_APPBUFFER "hw.sf.app_buff_count" -#define MAX_RAM_SIZE 512*1024*1024 -#define qHD_WIDTH 540 - - -namespace qhwc { - -// Std refresh rates for digital videos- 24p, 30p, 48p and 60p -uint32_t stdRefreshRates[] = { 30, 24, 48, 60 }; - -static uint32_t getFBformat(fb_var_screeninfo /*vinfo*/) { - uint32_t fbformat = HAL_PIXEL_FORMAT_RGBA_8888; - -#ifdef GET_FRAMEBUFFER_FORMAT_FROM_HWC - // Here, we are adding the formats that are supported by both GPU and MDP. - // The formats that fall in this category are RGBA_8888, RGB_565, RGB_888 - switch(vinfo.bits_per_pixel) { - case 16: - fbformat = HAL_PIXEL_FORMAT_RGB_565; - break; - case 24: - if ((vinfo.transp.offset == 0) && (vinfo.transp.length == 0)) - fbformat = HAL_PIXEL_FORMAT_RGB_888; - break; - case 32: - if ((vinfo.red.offset == 0) && (vinfo.green.offset == 8) && - (vinfo.blue.offset == 16) && (vinfo.transp.offset == 24)) - fbformat = HAL_PIXEL_FORMAT_RGBA_8888; - break; - default: - fbformat = HAL_PIXEL_FORMAT_RGBA_8888; - } -#endif - return fbformat; -} - -bool isValidResolution(hwc_context_t *ctx, uint32_t xres, uint32_t yres) -{ - return !((xres > qdutils::MDPVersion::getInstance().getMaxMixerWidth() && - !isDisplaySplit(ctx, HWC_DISPLAY_PRIMARY)) || - (xres < MIN_DISPLAY_XRES || yres < MIN_DISPLAY_YRES)); -} - -void changeResolution(hwc_context_t *ctx, int xres_orig, int yres_orig, - int width, int height) { - //Store original display resolution. - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres_new = xres_orig; - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres_new = yres_orig; - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].customFBSize = false; - char property[PROPERTY_VALUE_MAX] = {'\0'}; - char *yptr = NULL; - if (property_get("debug.hwc.fbsize", property, NULL) > 0) { - yptr = strcasestr(property,"x"); - if(yptr) { - int xres_new = atoi(property); - int yres_new = atoi(yptr + 1); - if (isValidResolution(ctx,xres_new,yres_new) && - xres_new != xres_orig && yres_new != yres_orig) { - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres_new = xres_new; - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres_new = yres_new; - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].customFBSize = true; - - //Caluculate DPI according to changed resolution. - float xdpi = ((float)xres_new * 25.4f) / (float)width; - float ydpi = ((float)yres_new * 25.4f) / (float)height; - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xdpi = xdpi; - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].ydpi = ydpi; - } - } - } -} - -// Initialize hdmi display attributes based on -// hdmi display class state -void updateDisplayInfo(hwc_context_t* ctx, int dpy) { - struct fb_var_screeninfo info; - - if (ioctl(ctx->mHDMIDisplay->getFd(), FBIOGET_VSCREENINFO, &info) == -1) { - ALOGE("%s:Error in ioctl FBIOGET_VSCREENINFO: %s", - __FUNCTION__, strerror(errno)); - } - - ctx->dpyAttr[dpy].fbformat = getFBformat(info); - ctx->dpyAttr[dpy].fd = ctx->mHDMIDisplay->getFd(); - ctx->dpyAttr[dpy].xres = ctx->mHDMIDisplay->getWidth(); - ctx->dpyAttr[dpy].yres = ctx->mHDMIDisplay->getHeight(); - ctx->dpyAttr[dpy].mMDPScalingMode = ctx->mHDMIDisplay->getMDPScalingMode(); - ctx->dpyAttr[dpy].vsync_period = ctx->mHDMIDisplay->getVsyncPeriod(); - ctx->mViewFrame[dpy].left = 0; - ctx->mViewFrame[dpy].top = 0; - ctx->mViewFrame[dpy].right = ctx->dpyAttr[dpy].xres; - ctx->mViewFrame[dpy].bottom = ctx->dpyAttr[dpy].yres; -} - -// Reset hdmi display attributes and list stats structures -void resetDisplayInfo(hwc_context_t* ctx, int dpy) { - memset(&(ctx->dpyAttr[dpy]), 0, sizeof(ctx->dpyAttr[dpy])); - memset(&(ctx->listStats[dpy]), 0, sizeof(ctx->listStats[dpy])); - // We reset the fd to -1 here but External display class is responsible - // for it when the display is disconnected. This is handled as part of - // EXTERNAL_OFFLINE event. - ctx->dpyAttr[dpy].fd = -1; -} - -// Initialize composition resources -void initCompositionResources(hwc_context_t* ctx, int dpy) { - ctx->mFBUpdate[dpy] = IFBUpdate::getObject(ctx, dpy); - ctx->mMDPComp[dpy] = MDPComp::getObject(ctx, dpy); -} - -void destroyCompositionResources(hwc_context_t* ctx, int dpy) { - if(ctx->mFBUpdate[dpy]) { - delete ctx->mFBUpdate[dpy]; - ctx->mFBUpdate[dpy] = NULL; - } - if(ctx->mMDPComp[dpy]) { - delete ctx->mMDPComp[dpy]; - ctx->mMDPComp[dpy] = NULL; - } -} - -static int openFramebufferDevice(hwc_context_t *ctx) -{ - struct fb_fix_screeninfo finfo; - struct fb_var_screeninfo info; - - int fb_fd = openFb(HWC_DISPLAY_PRIMARY); - if(fb_fd < 0) { - ALOGE("%s: Error Opening FB : %s", __FUNCTION__, strerror(errno)); - return -errno; - } - - if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &info) == -1) { - ALOGE("%s:Error in ioctl FBIOGET_VSCREENINFO: %s", __FUNCTION__, - strerror(errno)); - close(fb_fd); - return -errno; - } - - if (int(info.width) <= 0 || int(info.height) <= 0) { - // the driver doesn't return that information - // default to 160 dpi - info.width = (int)(((float)info.xres * 25.4f)/160.0f + 0.5f); - info.height = (int)(((float)info.yres * 25.4f)/160.0f + 0.5f); - } - - float xdpi = ((float)info.xres * 25.4f) / (float)info.width; - float ydpi = ((float)info.yres * 25.4f) / (float)info.height; - -#ifdef MSMFB_METADATA_GET - struct msmfb_metadata metadata; - memset(&metadata, 0 , sizeof(metadata)); - metadata.op = metadata_op_frame_rate; - - if (ioctl(fb_fd, MSMFB_METADATA_GET, &metadata) == -1) { - ALOGE("%s:Error retrieving panel frame rate: %s", __FUNCTION__, - strerror(errno)); - close(fb_fd); - return -errno; - } - - float fps = (float)metadata.data.panel_frame_rate; -#else - //XXX: Remove reserved field usage on all baselines - //The reserved[3] field is used to store FPS by the driver. - float fps = info.reserved[3] & 0xFF; -#endif - - if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo) == -1) { - ALOGE("%s:Error in ioctl FBIOGET_FSCREENINFO: %s", __FUNCTION__, - strerror(errno)); - close(fb_fd); - return -errno; - } - - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd = fb_fd; - //xres, yres may not be 32 aligned - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].stride = finfo.line_length /(info.xres/8); - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres = info.xres; - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres = info.yres; - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xdpi = xdpi; - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].ydpi = ydpi; - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].refreshRate = (uint32_t)fps; - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].dynRefreshRate = (uint32_t)fps; - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period = - (uint32_t)(1000000000l / fps); - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fbformat = getFBformat(info); - - //To change resolution of primary display - changeResolution(ctx, info.xres, info.yres, info.width, info.height); - - //Unblank primary on first boot - if(ioctl(fb_fd, FBIOBLANK,FB_BLANK_UNBLANK) < 0) { - ALOGE("%s: Failed to unblank display", __FUNCTION__); - return -errno; - } - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isActive = true; - - return 0; -} - -static void changeDefaultAppBufferCount() { - struct sysinfo info; - unsigned long int ramSize = 0; - if (!sysinfo(&info)) { - ramSize = info.totalram ; - } - int fb_fd = -1; - struct fb_var_screeninfo sInfo ={0}; - fb_fd = open("/dev/graphics/fb0", O_RDONLY); - if (fb_fd >=0) { - ioctl(fb_fd, FBIOGET_VSCREENINFO, &sInfo); - close(fb_fd); - } - if ((ramSize && ramSize < MAX_RAM_SIZE) && - (sInfo.xres && sInfo.xres <= qHD_WIDTH )) { - property_set(PROP_DEFAULT_APPBUFFER, "3"); - } -} - -void initContext(hwc_context_t *ctx) -{ - overlay::Overlay::initOverlay(); - ctx->mHDMIDisplay = new HDMIDisplay(); - uint32_t priW = 0, priH = 0; - // 1. HDMI as Primary - // -If HDMI cable is connected, read display configs from edid data - // -If HDMI cable is not connected then use default data in vscreeninfo - // 2. HDMI as External - // -Initialize HDMI class for use with external display - // -Use vscreeninfo to populate display configs - if(ctx->mHDMIDisplay->isHDMIPrimaryDisplay()) { - int connected = ctx->mHDMIDisplay->getConnectedState(); - if(connected == 1) { - ctx->mHDMIDisplay->configure(); - updateDisplayInfo(ctx, HWC_DISPLAY_PRIMARY); - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].connected = true; - } else { - openFramebufferDevice(ctx); - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].connected = false; - } - } else { - openFramebufferDevice(ctx); - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].connected = true; - // Send the primary resolution to the hdmi display class - // to be used for MDP scaling functionality - priW = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres; - priH = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres; - ctx->mHDMIDisplay->setPrimaryAttributes(priW, priH); - } - - char value[PROPERTY_VALUE_MAX]; - ctx->mMDP.version = qdutils::MDPVersion::getInstance().getMDPVersion(); - ctx->mMDP.hasOverlay = qdutils::MDPVersion::getInstance().hasOverlay(); - ctx->mMDP.panel = qdutils::MDPVersion::getInstance().getPanelType(); - ctx->mOverlay = overlay::Overlay::getInstance(); - ctx->mRotMgr = RotMgr::getInstance(); - - //default_app_buffer for ferrum - if (ctx->mMDP.version == qdutils::MDP_V3_0_5) { - changeDefaultAppBufferCount(); - } - // Initialize composition objects for the primary display - initCompositionResources(ctx, HWC_DISPLAY_PRIMARY); - - // Check if the target supports copybit compostion (dyn/mdp) to - // decide if we need to open the copybit module. - int compositionType = - qdutils::QCCompositionType::getInstance().getCompositionType(); - - // Only MDP copybit is used - if ((compositionType & (qdutils::COMPOSITION_TYPE_DYN | - qdutils::COMPOSITION_TYPE_MDP)) && - ((qdutils::MDPVersion::getInstance().getMDPVersion() == - qdutils::MDP_V3_0_4) || - (qdutils::MDPVersion::getInstance().getMDPVersion() == - qdutils::MDP_V3_0_5))) { - ctx->mCopyBit[HWC_DISPLAY_PRIMARY] = new CopyBit(ctx, - HWC_DISPLAY_PRIMARY); - } - - ctx->mHWCVirtual = new HWCVirtualVDS(); - ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive = false; - ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected = false; - ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = false; - ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected = false; - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].mMDPScalingMode= false; - ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].mMDPScalingMode = false; - ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].mMDPScalingMode = false; - - //Initialize the primary display viewFrame info - ctx->mViewFrame[HWC_DISPLAY_PRIMARY].left = 0; - ctx->mViewFrame[HWC_DISPLAY_PRIMARY].top = 0; - ctx->mViewFrame[HWC_DISPLAY_PRIMARY].right = - (int)ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres; - ctx->mViewFrame[HWC_DISPLAY_PRIMARY].bottom = - (int)ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres; - - for (uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) { - ctx->mHwcDebug[i] = new HwcDebug(i); - ctx->mLayerRotMap[i] = new LayerRotMap(); - ctx->mAnimationState[i] = ANIMATION_STOPPED; - ctx->dpyAttr[i].mActionSafePresent = false; - ctx->dpyAttr[i].mAsWidthRatio = 0; - ctx->dpyAttr[i].mAsHeightRatio = 0; - } - - for (uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) { - ctx->mPrevHwLayerCount[i] = 0; - } - - MDPComp::init(ctx); - ctx->mAD = new AssertiveDisplay(ctx); - - ctx->vstate.enable = false; - ctx->vstate.fakevsync = false; - ctx->mExtOrientation = 0; - ctx->numActiveDisplays = 1; - - //Right now hwc starts the service but anybody could do it, or it could be - //independent process as well. - QService::init(); - sp<IQClient> client = new QClient(ctx); - android::sp<qService::IQService> qservice_sp = interface_cast<IQService>( - defaultServiceManager()->getService( - String16("display.qservice"))); - if (qservice_sp.get()) { - qservice_sp->connect(client); - } else { - ALOGE("%s: Failed to acquire service pointer", __FUNCTION__); - return ; - } - - // Initialize device orientation to its default orientation - ctx->deviceOrientation = 0; - ctx->mBufferMirrorMode = false; - - property_get("sys.hwc.windowbox_aspect_ratio_tolerance", value, "0"); - ctx->mAspectRatioToleranceLevel = (((float)atoi(value)) / 100.0f); - - ctx->enableABC = false; - property_get("debug.sf.hwc.canUseABC", value, "0"); - ctx->enableABC = atoi(value) ? true : false; - - // Initializing boot anim completed check to false - ctx->mBootAnimCompleted = false; - - // Initialize gpu perfomance hint related parameters -#ifdef QTI_BSP - ctx->mEglLib = NULL; - ctx->mpfn_eglGpuPerfHintQCOM = NULL; - ctx->mpfn_eglGetCurrentDisplay = NULL; - ctx->mpfn_eglGetCurrentContext = NULL; - ctx->mGPUHintInfo.mGpuPerfModeEnable = false; - ctx->mGPUHintInfo.mEGLDisplay = NULL; - ctx->mGPUHintInfo.mEGLContext = NULL; - ctx->mGPUHintInfo.mCompositionState = COMPOSITION_STATE_MDP; - ctx->mGPUHintInfo.mCurrGPUPerfMode = EGL_GPU_LEVEL_0; - if(property_get("sys.hwc.gpu_perf_mode", value, "0") > 0) { - int val = atoi(value); - if(val > 0 && loadEglLib(ctx)) { - ctx->mGPUHintInfo.mGpuPerfModeEnable = true; - } - } -#endif - // Read the system property to determine if windowboxing feature is enabled. - ctx->mWindowboxFeature = false; - if(property_get("sys.hwc.windowbox_feature", value, "false") - && !strcmp(value, "true")) { - ctx->mWindowboxFeature = true; - } - - ctx->mUseMetaDataRefreshRate = true; - if(property_get("persist.metadata_dynfps.disable", value, "false") - && !strcmp(value, "true")) { - ctx->mUseMetaDataRefreshRate = false; - } - - memset(&(ctx->mPtorInfo), 0, sizeof(ctx->mPtorInfo)); - - //init qdcm service related context. - qdcmInitContext(ctx); - - ALOGI("Initializing Qualcomm Hardware Composer"); - ALOGI("MDP version: %d", ctx->mMDP.version); -} - -void closeContext(hwc_context_t *ctx) -{ - //close qdcm service related context. - qdcmCloseContext(ctx); - - if(ctx->mOverlay) { - delete ctx->mOverlay; - ctx->mOverlay = NULL; - } - - if(ctx->mRotMgr) { - delete ctx->mRotMgr; - ctx->mRotMgr = NULL; - } - - for(int i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) { - if(ctx->mCopyBit[i]) { - delete ctx->mCopyBit[i]; - ctx->mCopyBit[i] = NULL; - } - } - - if(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd) { - close(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd); - ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd = -1; - } - - if(ctx->mHDMIDisplay) { - delete ctx->mHDMIDisplay; - ctx->mHDMIDisplay = NULL; - } - - for(int i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) { - destroyCompositionResources(ctx, i); - - if(ctx->mHwcDebug[i]) { - delete ctx->mHwcDebug[i]; - ctx->mHwcDebug[i] = NULL; - } - if(ctx->mLayerRotMap[i]) { - delete ctx->mLayerRotMap[i]; - ctx->mLayerRotMap[i] = NULL; - } - } - if(ctx->mHWCVirtual) { - delete ctx->mHWCVirtual; - ctx->mHWCVirtual = NULL; - } - if(ctx->mAD) { - delete ctx->mAD; - ctx->mAD = NULL; - } - -#ifdef QTI_BSP - ctx->mpfn_eglGpuPerfHintQCOM = NULL; - ctx->mpfn_eglGetCurrentDisplay = NULL; - ctx->mpfn_eglGetCurrentContext = NULL; - if(ctx->mEglLib) { - dlclose(ctx->mEglLib); - ctx->mEglLib = NULL; - } -#endif -} - -uint32_t getRefreshRate(hwc_context_t* ctx, uint32_t requestedRefreshRate) { - - qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance(); - int dpy = HWC_DISPLAY_PRIMARY; - uint32_t defaultRefreshRate = ctx->dpyAttr[dpy].refreshRate; - uint32_t rate = defaultRefreshRate; - - if(!requestedRefreshRate) - return defaultRefreshRate; - - uint32_t maxNumIterations = - (uint32_t)ceil( - (float)mdpHw.getMaxFpsSupported()/ - (float)requestedRefreshRate); - - for(uint32_t i = 1; i <= maxNumIterations; i++) { - rate = i * roundOff(requestedRefreshRate); - if(rate < mdpHw.getMinFpsSupported()) { - continue; - } else if((rate >= mdpHw.getMinFpsSupported() && - rate <= mdpHw.getMaxFpsSupported())) { - break; - } else { - rate = defaultRefreshRate; - break; - } - } - return rate; -} - -//Helper to roundoff the refreshrates to the std refresh-rates -uint32_t roundOff(uint32_t refreshRate) { - int count = (int) (sizeof(stdRefreshRates)/sizeof(stdRefreshRates[0])); - uint32_t rate = refreshRate; - for(int i=0; i< count; i++) { - if(abs((int)(stdRefreshRates[i] - refreshRate)) < 2) { - // Most likely used for video, the fps can fluctuate - // Ex: b/w 29 and 30 for 30 fps clip - rate = stdRefreshRates[i]; - break; - } - } - return rate; -} - -//Helper func to set the dyn fps -void setRefreshRate(hwc_context_t* ctx, int dpy, uint32_t refreshRate) { - //Update only if different - if(!ctx || refreshRate == ctx->dpyAttr[dpy].dynRefreshRate) - return; - const int fbNum = Overlay::getFbForDpy(dpy); - char sysfsPath[qdutils::MAX_SYSFS_FILE_PATH]; - snprintf (sysfsPath, sizeof(sysfsPath), - "/sys/class/graphics/fb%d/dynamic_fps", fbNum); - - int fd = open(sysfsPath, O_WRONLY); - if(fd >= 0) { - char str[64]; - snprintf(str, sizeof(str), "%d", refreshRate); - ssize_t ret = write(fd, str, strlen(str)); - if(ret < 0) { - ALOGE("%s: Failed to write %d with error %s", - __FUNCTION__, refreshRate, strerror(errno)); - } else { - ctx->dpyAttr[dpy].dynRefreshRate = refreshRate; - ALOGD_IF(HWC_UTILS_DEBUG, "%s: Wrote %d to dynamic_fps", - __FUNCTION__, refreshRate); - } - close(fd); - } else { - ALOGE("%s: Failed to open %s with error %s", __FUNCTION__, sysfsPath, - strerror(errno)); - } -} - -void dumpsys_log(android::String8& buf, const char* fmt, ...) -{ - va_list varargs; - va_start(varargs, fmt); - buf.appendFormatV(fmt, varargs); - va_end(varargs); -} - -int getExtOrientation(hwc_context_t* ctx) { - int extOrient = ctx->mExtOrientation; - if(ctx->mBufferMirrorMode) - extOrient = getMirrorModeOrientation(ctx); - return extOrient; -} - -/* Calculates the destination position based on the action safe rectangle */ -void getActionSafePosition(hwc_context_t *ctx, int dpy, hwc_rect_t& rect) { - // Position - int x = rect.left, y = rect.top; - int w = rect.right - rect.left; - int h = rect.bottom - rect.top; - - if(!ctx->dpyAttr[dpy].mActionSafePresent) - return; - // Read action safe properties - int asWidthRatio = ctx->dpyAttr[dpy].mAsWidthRatio; - int asHeightRatio = ctx->dpyAttr[dpy].mAsHeightRatio; - - float wRatio = 1.0; - float hRatio = 1.0; - float xRatio = 1.0; - float yRatio = 1.0; - - uint32_t fbWidth = ctx->dpyAttr[dpy].xres; - uint32_t fbHeight = ctx->dpyAttr[dpy].yres; - if(ctx->dpyAttr[dpy].mMDPScalingMode) { - // if MDP scaling mode is enabled for external, need to query - // the actual width and height, as that is the physical w & h - ctx->mHDMIDisplay->getAttributes(fbWidth, fbHeight); - } - - - // Since external is rotated 90, need to swap width/height - int extOrient = getExtOrientation(ctx); - - if(extOrient & HWC_TRANSFORM_ROT_90) - swap(fbWidth, fbHeight); - - float asX = 0; - float asY = 0; - float asW = (float)fbWidth; - float asH = (float)fbHeight; - - // based on the action safe ratio, get the Action safe rectangle - asW = ((float)fbWidth * (1.0f - (float)asWidthRatio / 100.0f)); - asH = ((float)fbHeight * (1.0f - (float)asHeightRatio / 100.0f)); - asX = ((float)fbWidth - asW) / 2; - asY = ((float)fbHeight - asH) / 2; - - // calculate the position ratio - xRatio = (float)x/(float)fbWidth; - yRatio = (float)y/(float)fbHeight; - wRatio = (float)w/(float)fbWidth; - hRatio = (float)h/(float)fbHeight; - - //Calculate the position... - x = int((xRatio * asW) + asX); - y = int((yRatio * asH) + asY); - w = int(wRatio * asW); - h = int(hRatio * asH); - - // Convert it back to hwc_rect_t - rect.left = x; - rect.top = y; - rect.right = w + rect.left; - rect.bottom = h + rect.top; - - return; -} - -// This function gets the destination position for Seconday display -// based on the position and aspect ratio with orientation -void getAspectRatioPosition(hwc_context_t* ctx, int dpy, int extOrientation, - hwc_rect_t& inRect, hwc_rect_t& outRect) { - // Physical display resolution - float fbWidth = (float)ctx->dpyAttr[dpy].xres; - float fbHeight = (float)ctx->dpyAttr[dpy].yres; - //display position(x,y,w,h) in correct aspectratio after rotation - int xPos = 0; - int yPos = 0; - float width = fbWidth; - float height = fbHeight; - // Width/Height used for calculation, after rotation - float actualWidth = fbWidth; - float actualHeight = fbHeight; - - float wRatio = 1.0; - float hRatio = 1.0; - float xRatio = 1.0; - float yRatio = 1.0; - hwc_rect_t rect = {0, 0, (int)fbWidth, (int)fbHeight}; - - Dim inPos(inRect.left, inRect.top, inRect.right - inRect.left, - inRect.bottom - inRect.top); - Dim outPos(outRect.left, outRect.top, outRect.right - outRect.left, - outRect.bottom - outRect.top); - - Whf whf((uint32_t)fbWidth, (uint32_t)fbHeight, 0); - eTransform extorient = static_cast<eTransform>(extOrientation); - // To calculate the destination co-ordinates in the new orientation - preRotateSource(extorient, whf, inPos); - - if(extOrientation & HAL_TRANSFORM_ROT_90) { - // Swap width/height for input position - swapWidthHeight(actualWidth, actualHeight); - qdutils::getAspectRatioPosition((int)fbWidth, (int)fbHeight, - (int)actualWidth, (int)actualHeight, rect); - xPos = rect.left; - yPos = rect.top; - width = float(rect.right - rect.left); - height = float(rect.bottom - rect.top); - } - xRatio = (float)((float)inPos.x/actualWidth); - yRatio = (float)((float)inPos.y/actualHeight); - wRatio = (float)((float)inPos.w/actualWidth); - hRatio = (float)((float)inPos.h/actualHeight); - - //Calculate the pos9ition... - outPos.x = uint32_t((xRatio * width) + (float)xPos); - outPos.y = uint32_t((yRatio * height) + (float)yPos); - outPos.w = uint32_t(wRatio * width); - outPos.h = uint32_t(hRatio * height); - ALOGD_IF(HWC_UTILS_DEBUG, "%s: Calculated AspectRatio Position: x = %d," - "y = %d w = %d h = %d", __FUNCTION__, outPos.x, outPos.y, - outPos.w, outPos.h); - - // For sidesync, the dest fb will be in portrait orientation, and the crop - // will be updated to avoid the black side bands, and it will be upscaled - // to fit the dest RB, so recalculate - // the position based on the new width and height - if ((extOrientation & HWC_TRANSFORM_ROT_90) && - isOrientationPortrait(ctx)) { - hwc_rect_t r = {0, 0, 0, 0}; - //Calculate the position - xRatio = (float)(outPos.x - xPos)/width; - // GetaspectRatio -- tricky to get the correct aspect ratio - // But we need to do this. - qdutils::getAspectRatioPosition((int)width, (int)height, - (int)width,(int)height, r); - xPos = r.left; - yPos = r.top; - float tempHeight = float(r.bottom - r.top); - yRatio = (float)yPos/height; - wRatio = (float)outPos.w/width; - hRatio = tempHeight/height; - - //Map the coordinates back to Framebuffer domain - outPos.x = uint32_t(xRatio * fbWidth); - outPos.y = uint32_t(yRatio * fbHeight); - outPos.w = uint32_t(wRatio * fbWidth); - outPos.h = uint32_t(hRatio * fbHeight); - - ALOGD_IF(HWC_UTILS_DEBUG, "%s: Calculated AspectRatio for device in" - "portrait: x = %d,y = %d w = %d h = %d", __FUNCTION__, - outPos.x, outPos.y, - outPos.w, outPos.h); - } - if(ctx->dpyAttr[dpy].mMDPScalingMode) { - uint32_t extW = 0, extH = 0; - if(dpy == HWC_DISPLAY_EXTERNAL) { - ctx->mHDMIDisplay->getAttributes(extW, extH); - } else if(dpy == HWC_DISPLAY_VIRTUAL) { - extW = ctx->mHWCVirtual->getScalingWidth(); - extH = ctx->mHWCVirtual->getScalingHeight(); - } - ALOGD_IF(HWC_UTILS_DEBUG, "%s: Scaling mode extW=%d extH=%d", - __FUNCTION__, extW, extH); - - fbWidth = (float)ctx->dpyAttr[dpy].xres; - fbHeight = (float)ctx->dpyAttr[dpy].yres; - //Calculate the position... - xRatio = (float)outPos.x/fbWidth; - yRatio = (float)outPos.y/fbHeight; - wRatio = (float)outPos.w/fbWidth; - hRatio = (float)outPos.h/fbHeight; - - outPos.x = uint32_t(xRatio * (float)extW); - outPos.y = uint32_t(yRatio * (float)extH); - outPos.w = uint32_t(wRatio * (float)extW); - outPos.h = uint32_t(hRatio * (float)extH); - } - // Convert Dim to hwc_rect_t - outRect.left = outPos.x; - outRect.top = outPos.y; - outRect.right = outPos.x + outPos.w; - outRect.bottom = outPos.y + outPos.h; - - return; -} - -bool isPrimaryPortrait(hwc_context_t *ctx) { - int fbWidth = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres; - int fbHeight = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres; - if(fbWidth < fbHeight) { - return true; - } - return false; -} - -bool isOrientationPortrait(hwc_context_t *ctx) { - if(isPrimaryPortrait(ctx)) { - return !(ctx->deviceOrientation & 0x1); - } - return (ctx->deviceOrientation & 0x1); -} - -void calcExtDisplayPosition(hwc_context_t *ctx, - private_handle_t *hnd, - int dpy, - hwc_rect_t& sourceCrop, - hwc_rect_t& displayFrame, - int& transform, - ovutils::eTransform& orient) { - // Swap width and height when there is a 90deg transform - int extOrient = getExtOrientation(ctx); - if(dpy && ctx->mOverlay->isUIScalingOnExternalSupported()) { - if(!isYuvBuffer(hnd)) { - if(extOrient & HWC_TRANSFORM_ROT_90) { - int dstWidth = ctx->dpyAttr[dpy].xres; - int dstHeight = ctx->dpyAttr[dpy].yres;; - int srcWidth = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres; - int srcHeight = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres; - if(!isPrimaryPortrait(ctx)) { - swap(srcWidth, srcHeight); - } // Get Aspect Ratio for external - qdutils::getAspectRatioPosition(dstWidth, dstHeight, srcWidth, - srcHeight, displayFrame); - // Crop - this is needed, because for sidesync, the dest fb will - // be in portrait orientation, so update the crop to not show the - // black side bands. - if (isOrientationPortrait(ctx)) { - sourceCrop = displayFrame; - displayFrame.left = 0; - displayFrame.top = 0; - displayFrame.right = dstWidth; - displayFrame.bottom = dstHeight; - } - } - if(ctx->dpyAttr[dpy].mMDPScalingMode) { - uint32_t extW = 0, extH = 0; - // if MDP scaling mode is enabled, map the co-ordinates to new - // domain(downscaled) - float fbWidth = (float)ctx->dpyAttr[dpy].xres; - float fbHeight = (float)ctx->dpyAttr[dpy].yres; - // query MDP configured attributes - if(dpy == HWC_DISPLAY_EXTERNAL) { - ctx->mHDMIDisplay->getAttributes(extW, extH); - } else if(dpy == HWC_DISPLAY_VIRTUAL) { - extW = ctx->mHWCVirtual->getScalingWidth(); - extH = ctx->mHWCVirtual->getScalingHeight(); - } - ALOGD_IF(HWC_UTILS_DEBUG, "%s: Scaling mode extW=%d extH=%d", - __FUNCTION__, extW, extH); - - //Calculate the ratio... - float wRatio = ((float)extW)/fbWidth; - float hRatio = ((float)extH)/fbHeight; - - //convert Dim to hwc_rect_t - displayFrame.left = int(wRatio*(float)displayFrame.left); - displayFrame.top = int(hRatio*(float)displayFrame.top); - displayFrame.right = int(wRatio*(float)displayFrame.right); - displayFrame.bottom = int(hRatio*(float)displayFrame.bottom); - ALOGD_IF(DEBUG_MDPDOWNSCALE, "Calculated external display frame" - " for MDPDownscale feature [%d %d %d %d]", - displayFrame.left, displayFrame.top, - displayFrame.right, displayFrame.bottom); - } - }else { - if(extOrient || ctx->dpyAttr[dpy].mMDPScalingMode) { - getAspectRatioPosition(ctx, dpy, extOrient, - displayFrame, displayFrame); - } - } - // If there is a external orientation set, use that - if(extOrient) { - transform = extOrient; - orient = static_cast<ovutils::eTransform >(extOrient); - } - // Calculate the actionsafe dimensions for External(dpy = 1 or 2) - getActionSafePosition(ctx, dpy, displayFrame); - } -} - -/* Returns the orientation which needs to be set on External for - * SideSync/Buffer Mirrormode - */ -int getMirrorModeOrientation(hwc_context_t *ctx) { - int extOrientation = 0; - int deviceOrientation = ctx->deviceOrientation; - if(!isPrimaryPortrait(ctx)) - deviceOrientation = (deviceOrientation + 1) % 4; - if (deviceOrientation == 0) - extOrientation = HWC_TRANSFORM_ROT_270; - else if (deviceOrientation == 1)//90 - extOrientation = 0; - else if (deviceOrientation == 2)//180 - extOrientation = HWC_TRANSFORM_ROT_90; - else if (deviceOrientation == 3)//270 - extOrientation = HWC_TRANSFORM_FLIP_V | HWC_TRANSFORM_FLIP_H; - - return extOrientation; -} - -/* Get External State names */ -const char* getExternalDisplayState(uint32_t external_state) { - static const char* externalStates[EXTERNAL_MAXSTATES] = {0}; - externalStates[EXTERNAL_OFFLINE] = STR(EXTERNAL_OFFLINE); - externalStates[EXTERNAL_ONLINE] = STR(EXTERNAL_ONLINE); - externalStates[EXTERNAL_PAUSE] = STR(EXTERNAL_PAUSE); - externalStates[EXTERNAL_RESUME] = STR(EXTERNAL_RESUME); - - if(external_state >= EXTERNAL_MAXSTATES) { - return "EXTERNAL_INVALID"; - } - - return externalStates[external_state]; -} - -bool isDownscaleRequired(hwc_layer_1_t const* layer) { - hwc_rect_t displayFrame = layer->displayFrame; - hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf); - int dst_w, dst_h, src_w, src_h; - dst_w = displayFrame.right - displayFrame.left; - dst_h = displayFrame.bottom - displayFrame.top; - src_w = sourceCrop.right - sourceCrop.left; - src_h = sourceCrop.bottom - sourceCrop.top; - - if(((src_w > dst_w) || (src_h > dst_h))) - return true; - - return false; -} -bool needsScaling(hwc_layer_1_t const* layer) { - int dst_w, dst_h, src_w, src_h; - hwc_rect_t displayFrame = layer->displayFrame; - hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf); - - dst_w = displayFrame.right - displayFrame.left; - dst_h = displayFrame.bottom - displayFrame.top; - src_w = sourceCrop.right - sourceCrop.left; - src_h = sourceCrop.bottom - sourceCrop.top; - - if(((src_w != dst_w) || (src_h != dst_h))) - return true; - - return false; -} - -// Checks if layer needs scaling with split -bool needsScalingWithSplit(hwc_context_t* ctx, hwc_layer_1_t const* layer, - const int& dpy) { - - int src_width_l, src_height_l; - int src_width_r, src_height_r; - int dst_width_l, dst_height_l; - int dst_width_r, dst_height_r; - int hw_w = ctx->dpyAttr[dpy].xres; - int hw_h = ctx->dpyAttr[dpy].yres; - hwc_rect_t cropL, dstL, cropR, dstR; - const int lSplit = getLeftSplit(ctx, dpy); - hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf); - hwc_rect_t displayFrame = layer->displayFrame; - private_handle_t *hnd = (private_handle_t *)layer->handle; - - cropL = sourceCrop; - dstL = displayFrame; - hwc_rect_t scissorL = { 0, 0, lSplit, hw_h }; - scissorL = getIntersection(ctx->mViewFrame[dpy], scissorL); - qhwc::calculate_crop_rects(cropL, dstL, scissorL, 0); - - cropR = sourceCrop; - dstR = displayFrame; - hwc_rect_t scissorR = { lSplit, 0, hw_w, hw_h }; - scissorR = getIntersection(ctx->mViewFrame[dpy], scissorR); - qhwc::calculate_crop_rects(cropR, dstR, scissorR, 0); - - // Sanitize Crop to stitch - sanitizeSourceCrop(cropL, cropR, hnd); - - // Calculate the left dst - dst_width_l = dstL.right - dstL.left; - dst_height_l = dstL.bottom - dstL.top; - src_width_l = cropL.right - cropL.left; - src_height_l = cropL.bottom - cropL.top; - - // check if there is any scaling on the left - if(((src_width_l != dst_width_l) || (src_height_l != dst_height_l))) - return true; - - // Calculate the right dst - dst_width_r = dstR.right - dstR.left; - dst_height_r = dstR.bottom - dstR.top; - src_width_r = cropR.right - cropR.left; - src_height_r = cropR.bottom - cropR.top; - - // check if there is any scaling on the right - if(((src_width_r != dst_width_r) || (src_height_r != dst_height_r))) - return true; - - return false; -} - -bool isAlphaScaled(hwc_layer_1_t const* layer) { - if(needsScaling(layer) && isAlphaPresent(layer)) { - return true; - } - return false; -} - -bool isAlphaPresent(hwc_layer_1_t const* layer) { - private_handle_t *hnd = (private_handle_t *)layer->handle; - if(hnd) { - int format = hnd->format; - switch(format) { - case HAL_PIXEL_FORMAT_RGBA_8888: - case HAL_PIXEL_FORMAT_BGRA_8888: - // In any more formats with Alpha go here.. - return true; - default : return false; - } - } - return false; -} - -bool isAlphaPresentinFB(hwc_context_t *ctx, int dpy) { - switch(ctx->dpyAttr[dpy].fbformat) { - case HAL_PIXEL_FORMAT_RGBA_8888: - case HAL_PIXEL_FORMAT_BGRA_8888: - return true; - default : return false; - } - return false; -} - -static void trimLayer(hwc_context_t *ctx, const int& dpy, const int& transform, - hwc_rect_t& crop, hwc_rect_t& dst) { - int hw_w = ctx->dpyAttr[dpy].xres; - int hw_h = ctx->dpyAttr[dpy].yres; - if(dst.left < 0 || dst.top < 0 || - dst.right > hw_w || dst.bottom > hw_h) { - hwc_rect_t scissor = {0, 0, hw_w, hw_h }; - scissor = getIntersection(ctx->mViewFrame[dpy], scissor); - qhwc::calculate_crop_rects(crop, dst, scissor, transform); - } -} - -static void trimList(hwc_context_t *ctx, hwc_display_contents_1_t *list, - const int& dpy) { - for(uint32_t i = 0; i < list->numHwLayers - 1; i++) { - hwc_layer_1_t *layer = &list->hwLayers[i]; - hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf); - int transform = (list->hwLayers[i].flags & HWC_COLOR_FILL) ? 0 : - list->hwLayers[i].transform; - trimLayer(ctx, dpy, - transform, - (hwc_rect_t&)crop, - (hwc_rect_t&)list->hwLayers[i].displayFrame); - layer->sourceCropf.left = (float)crop.left; - layer->sourceCropf.right = (float)crop.right; - layer->sourceCropf.top = (float)crop.top; - layer->sourceCropf.bottom = (float)crop.bottom; - } -} - -void setListStats(hwc_context_t *ctx, - hwc_display_contents_1_t *list, int dpy) { - const int prevYuvCount = ctx->listStats[dpy].yuvCount; - memset(&ctx->listStats[dpy], 0, sizeof(ListStats)); - ctx->listStats[dpy].numAppLayers = (int)list->numHwLayers - 1; - ctx->listStats[dpy].fbLayerIndex = (int)list->numHwLayers - 1; - ctx->listStats[dpy].skipCount = 0; - ctx->listStats[dpy].preMultipliedAlpha = false; - ctx->listStats[dpy].isSecurePresent = false; - ctx->listStats[dpy].yuvCount = 0; - char property[PROPERTY_VALUE_MAX]; - ctx->listStats[dpy].isDisplayAnimating = false; - ctx->listStats[dpy].secureUI = false; - ctx->listStats[dpy].yuv4k2kCount = 0; - ctx->dpyAttr[dpy].mActionSafePresent = isActionSafePresent(ctx, dpy); - ctx->listStats[dpy].renderBufIndexforABC = -1; - ctx->listStats[dpy].secureRGBCount = 0; - ctx->listStats[dpy].refreshRateRequest = ctx->dpyAttr[dpy].refreshRate; - uint32_t refreshRate = 0; - qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance(); - - ctx->listStats[dpy].mAIVVideoMode = false; - resetROI(ctx, dpy); - - trimList(ctx, list, dpy); - optimizeLayerRects(list); - for (size_t i = 0; i < (size_t)ctx->listStats[dpy].numAppLayers; i++) { - hwc_layer_1_t const* layer = &list->hwLayers[i]; - private_handle_t *hnd = (private_handle_t *)layer->handle; - -#ifdef QTI_BSP - // Window boxing feature is applicable obly for external display, So - // enable mAIVVideoMode only for external display - if(ctx->mWindowboxFeature && dpy && isAIVVideoLayer(layer)) { - ctx->listStats[dpy].mAIVVideoMode = true; - } - if (layer->flags & HWC_SCREENSHOT_ANIMATOR_LAYER) { - ctx->listStats[dpy].isDisplayAnimating = true; - } - if(isSecureDisplayBuffer(hnd)) { - ctx->listStats[dpy].secureUI = true; - } -#endif - // continue if number of app layers exceeds MAX_NUM_APP_LAYERS - if(ctx->listStats[dpy].numAppLayers > MAX_NUM_APP_LAYERS) - continue; - - //reset yuv indices - ctx->listStats[dpy].yuvIndices[i] = -1; - ctx->listStats[dpy].yuv4k2kIndices[i] = -1; - - if (isSecureBuffer(hnd)) { - ctx->listStats[dpy].isSecurePresent = true; - if(not isYuvBuffer(hnd)) { - // cache secureRGB layer parameters like we cache for YUV layers - int& secureRGBCount = ctx->listStats[dpy].secureRGBCount; - ctx->listStats[dpy].secureRGBIndices[secureRGBCount] = (int)i; - secureRGBCount++; - } - } - - if (isSkipLayer(&list->hwLayers[i])) { - ctx->listStats[dpy].skipCount++; - } - - if (UNLIKELY(isYuvBuffer(hnd))) { - int& yuvCount = ctx->listStats[dpy].yuvCount; - ctx->listStats[dpy].yuvIndices[yuvCount] = (int)i; - yuvCount++; - - if(UNLIKELY(isYUVSplitNeeded(hnd))){ - int& yuv4k2kCount = ctx->listStats[dpy].yuv4k2kCount; - ctx->listStats[dpy].yuv4k2kIndices[yuv4k2kCount] = (int)i; - yuv4k2kCount++; - } - } - if(layer->blending == HWC_BLENDING_PREMULT) - ctx->listStats[dpy].preMultipliedAlpha = true; - -#ifdef DYNAMIC_FPS - if (!dpy && mdpHw.isDynFpsSupported() && ctx->mUseMetaDataRefreshRate){ - /* Dyn fps: get refreshrate from metadata */ - MetaData_t *mdata = hnd ? (MetaData_t *)hnd->base_metadata : NULL; - if (mdata && (mdata->operation & UPDATE_REFRESH_RATE)) { - // Valid refreshRate in metadata and within the range - uint32_t rate = getRefreshRate(ctx, mdata->refreshrate); - if (!refreshRate) { - refreshRate = rate; - } else if(refreshRate != rate) { - /* Support multiple refresh rates if they are same - * else set to default. - */ - refreshRate = ctx->dpyAttr[dpy].refreshRate; - } - } - } -#endif - } - if(ctx->listStats[dpy].yuvCount > 0) { - if (property_get("hw.cabl.yuv", property, NULL) > 0) { - if (atoi(property) != 1) { - property_set("hw.cabl.yuv", "1"); - } - } - } else { - if (property_get("hw.cabl.yuv", property, NULL) > 0) { - if (atoi(property) != 0) { - property_set("hw.cabl.yuv", "0"); - } - } - } - - //The marking of video begin/end is useful on some targets where we need - //to have a padding round to be able to shift pipes across mixers. - if(prevYuvCount != ctx->listStats[dpy].yuvCount) { - ctx->mVideoTransFlag = true; - } - - if(dpy == HWC_DISPLAY_PRIMARY) { - ctx->mAD->markDoable(ctx, list); - //Store the requested fresh rate - ctx->listStats[dpy].refreshRateRequest = refreshRate ? - refreshRate : ctx->dpyAttr[dpy].refreshRate; - } -} - - -static void calc_cut(double& leftCutRatio, double& topCutRatio, - double& rightCutRatio, double& bottomCutRatio, int orient) { - if(orient & HAL_TRANSFORM_FLIP_H) { - swap(leftCutRatio, rightCutRatio); - } - if(orient & HAL_TRANSFORM_FLIP_V) { - swap(topCutRatio, bottomCutRatio); - } - if(orient & HAL_TRANSFORM_ROT_90) { - //Anti clock swapping - double tmpCutRatio = leftCutRatio; - leftCutRatio = topCutRatio; - topCutRatio = rightCutRatio; - rightCutRatio = bottomCutRatio; - bottomCutRatio = tmpCutRatio; - } -} - -bool isSecuring(hwc_context_t* ctx, hwc_layer_1_t const* layer) { - if((ctx->mMDP.version < qdutils::MDSS_V5) && - (ctx->mMDP.version > qdutils::MDP_V3_0) && - ctx->mSecuring) { - return true; - } - if (isSecureModePolicy(ctx->mMDP.version)) { - private_handle_t *hnd = (private_handle_t *)layer->handle; - if(ctx->mSecureMode) { - if (! isSecureBuffer(hnd)) { - ALOGD_IF(HWC_UTILS_DEBUG,"%s:Securing Turning ON ...", - __FUNCTION__); - return true; - } - } else { - if (isSecureBuffer(hnd)) { - ALOGD_IF(HWC_UTILS_DEBUG,"%s:Securing Turning OFF ...", - __FUNCTION__); - return true; - } - } - } - return false; -} - -bool isSecureModePolicy(int mdpVersion) { - if (mdpVersion < qdutils::MDSS_V5) - return true; - else - return false; -} - -bool isRotatorSupportedFormat(private_handle_t *hnd) { - // Following rotator src formats are supported by mdp driver - // TODO: Add more formats in future, if mdp driver adds support - switch(hnd->format) { - case HAL_PIXEL_FORMAT_RGBA_8888: - case HAL_PIXEL_FORMAT_RGB_565: - case HAL_PIXEL_FORMAT_RGB_888: - case HAL_PIXEL_FORMAT_BGRA_8888: - return true; - default: - return false; - } - return false; -} - -bool isRotationDoable(hwc_context_t *ctx, private_handle_t *hnd) { - // Rotate layers, if it is YUV type or rendered by CPU and not - // for the MDP versions below MDP5 - if((isCPURendered(hnd) && isRotatorSupportedFormat(hnd) && - !(ctx->mMDP.version < qdutils::MDSS_V5)) - || isYuvBuffer(hnd)) { - return true; - } - return false; -} - -// returns true if Action safe dimensions are set and target supports Actionsafe -bool isActionSafePresent(hwc_context_t *ctx, int dpy) { - // if external supports underscan, do nothing - // it will be taken care in the driver - // Disable Action safe for 8974 due to HW limitation for downscaling - // layers with overlapped region - // Disable Actionsafe for non HDMI displays. - if(!(dpy == HWC_DISPLAY_EXTERNAL) || - qdutils::MDPVersion::getInstance().is8x74v2() || - ctx->mHDMIDisplay->isCEUnderscanSupported()) { - return false; - } - - char value[PROPERTY_VALUE_MAX]; - // Read action safe properties - property_get("persist.sys.actionsafe.width", value, "0"); - ctx->dpyAttr[dpy].mAsWidthRatio = atoi(value); - property_get("persist.sys.actionsafe.height", value, "0"); - ctx->dpyAttr[dpy].mAsHeightRatio = atoi(value); - - if(!ctx->dpyAttr[dpy].mAsWidthRatio && !ctx->dpyAttr[dpy].mAsHeightRatio) { - //No action safe ratio set, return - return false; - } - return true; -} - -int getBlending(int blending) { - switch(blending) { - case HWC_BLENDING_NONE: - return overlay::utils::OVERLAY_BLENDING_OPAQUE; - case HWC_BLENDING_PREMULT: - return overlay::utils::OVERLAY_BLENDING_PREMULT; - case HWC_BLENDING_COVERAGE : - default: - return overlay::utils::OVERLAY_BLENDING_COVERAGE; - } -} - -//Crops source buffer against destination and FB boundaries -void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst, - const hwc_rect_t& scissor, int orient) { - - int& crop_l = crop.left; - int& crop_t = crop.top; - int& crop_r = crop.right; - int& crop_b = crop.bottom; - int crop_w = crop.right - crop.left; - int crop_h = crop.bottom - crop.top; - - int& dst_l = dst.left; - int& dst_t = dst.top; - int& dst_r = dst.right; - int& dst_b = dst.bottom; - int dst_w = abs(dst.right - dst.left); - int dst_h = abs(dst.bottom - dst.top); - - const int& sci_l = scissor.left; - const int& sci_t = scissor.top; - const int& sci_r = scissor.right; - const int& sci_b = scissor.bottom; - - double leftCutRatio = 0.0, rightCutRatio = 0.0, topCutRatio = 0.0, - bottomCutRatio = 0.0; - - if(dst_l < sci_l) { - leftCutRatio = (double)(sci_l - dst_l) / (double)dst_w; - dst_l = sci_l; - } - - if(dst_r > sci_r) { - rightCutRatio = (double)(dst_r - sci_r) / (double)dst_w; - dst_r = sci_r; - } - - if(dst_t < sci_t) { - topCutRatio = (double)(sci_t - dst_t) / (double)dst_h; - dst_t = sci_t; - } - - if(dst_b > sci_b) { - bottomCutRatio = (double)(dst_b - sci_b) / (double)dst_h; - dst_b = sci_b; - } - - calc_cut(leftCutRatio, topCutRatio, rightCutRatio, bottomCutRatio, orient); - crop_l += (int)round((double)crop_w * leftCutRatio); - crop_t += (int)round((double)crop_h * topCutRatio); - crop_r -= (int)round((double)crop_w * rightCutRatio); - crop_b -= (int)round((double)crop_h * bottomCutRatio); -} - -bool areLayersIntersecting(const hwc_layer_1_t* layer1, - const hwc_layer_1_t* layer2) { - hwc_rect_t irect = getIntersection(layer1->displayFrame, - layer2->displayFrame); - return isValidRect(irect); -} - -bool isSameRect(const hwc_rect& rect1, const hwc_rect& rect2) -{ - return ((rect1.left == rect2.left) && (rect1.top == rect2.top) && - (rect1.right == rect2.right) && (rect1.bottom == rect2.bottom)); -} - -bool isValidRect(const hwc_rect& rect) -{ - return ((rect.bottom > rect.top) && (rect.right > rect.left)) ; -} - -bool operator ==(const hwc_rect_t& lhs, const hwc_rect_t& rhs) { - if(lhs.left == rhs.left && lhs.top == rhs.top && - lhs.right == rhs.right && lhs.bottom == rhs.bottom ) - return true ; - return false; -} - -bool layerUpdating(const hwc_layer_1_t* layer) { - hwc_region_t surfDamage = layer->surfaceDamage; - return ((surfDamage.numRects == 0) || - isValidRect(layer->surfaceDamage.rects[0])); -} - -hwc_rect_t calculateDirtyRect(const hwc_layer_1_t* layer, - hwc_rect_t& scissor) { - hwc_region_t surfDamage = layer->surfaceDamage; - hwc_rect_t src = integerizeSourceCrop(layer->sourceCropf); - hwc_rect_t dst = layer->displayFrame; - int x_off = dst.left - src.left; - int y_off = dst.top - src.top; - hwc_rect dirtyRect = (hwc_rect){0, 0, 0, 0}; - hwc_rect_t updatingRect = dst; - - if (surfDamage.numRects == 0) { - // full layer updating, dirty rect is full frame - dirtyRect = getIntersection(layer->displayFrame, scissor); - } else { - for(uint32_t i = 0; i < surfDamage.numRects; i++) { - updatingRect = moveRect(surfDamage.rects[i], x_off, y_off); - hwc_rect_t intersect = getIntersection(updatingRect, scissor); - if(isValidRect(intersect)) { - dirtyRect = getUnion(intersect, dirtyRect); - } - } - } - return dirtyRect; -} - -hwc_rect_t moveRect(const hwc_rect_t& rect, const int& x_off, const int& y_off) -{ - hwc_rect_t res; - - if(!isValidRect(rect)) - return (hwc_rect_t){0, 0, 0, 0}; - - res.left = rect.left + x_off; - res.top = rect.top + y_off; - res.right = rect.right + x_off; - res.bottom = rect.bottom + y_off; - - return res; -} - -/* computes the intersection of two rects */ -hwc_rect_t getIntersection(const hwc_rect_t& rect1, const hwc_rect_t& rect2) -{ - hwc_rect_t res; - - if(!isValidRect(rect1) || !isValidRect(rect2)){ - return (hwc_rect_t){0, 0, 0, 0}; - } - - - res.left = max(rect1.left, rect2.left); - res.top = max(rect1.top, rect2.top); - res.right = min(rect1.right, rect2.right); - res.bottom = min(rect1.bottom, rect2.bottom); - - if(!isValidRect(res)) - return (hwc_rect_t){0, 0, 0, 0}; - - return res; -} - -/* computes the union of two rects */ -hwc_rect_t getUnion(const hwc_rect &rect1, const hwc_rect &rect2) -{ - hwc_rect_t res; - - if(!isValidRect(rect1)){ - return rect2; - } - - if(!isValidRect(rect2)){ - return rect1; - } - - res.left = min(rect1.left, rect2.left); - res.top = min(rect1.top, rect2.top); - res.right = max(rect1.right, rect2.right); - res.bottom = max(rect1.bottom, rect2.bottom); - - return res; -} - -/* Not a geometrical rect deduction. Deducts rect2 from rect1 only if it results - * a single rect */ -hwc_rect_t deductRect(const hwc_rect_t& rect1, const hwc_rect_t& rect2) { - - hwc_rect_t res = rect1; - - if((rect1.left == rect2.left) && (rect1.right == rect2.right)) { - if((rect1.top == rect2.top) && (rect2.bottom <= rect1.bottom)) - res.top = rect2.bottom; - else if((rect1.bottom == rect2.bottom)&& (rect2.top >= rect1.top)) - res.bottom = rect2.top; - } - else if((rect1.top == rect2.top) && (rect1.bottom == rect2.bottom)) { - if((rect1.left == rect2.left) && (rect2.right <= rect1.right)) - res.left = rect2.right; - else if((rect1.right == rect2.right)&& (rect2.left >= rect1.left)) - res.right = rect2.left; - } - return res; -} - -void optimizeLayerRects(const hwc_display_contents_1_t *list) { - int i= (int)list->numHwLayers-2; - while(i > 0) { - //see if there is no blending required. - //If it is opaque see if we can substract this region from below - //layers. - if(list->hwLayers[i].blending == HWC_BLENDING_NONE && - list->hwLayers[i].planeAlpha == 0xFF) { - int j= i-1; - hwc_rect_t& topframe = - (hwc_rect_t&)list->hwLayers[i].displayFrame; - while(j >= 0) { - if(!needsScaling(&list->hwLayers[j])) { - hwc_layer_1_t* layer = (hwc_layer_1_t*)&list->hwLayers[j]; - hwc_rect_t& bottomframe = layer->displayFrame; - hwc_rect_t bottomCrop = - integerizeSourceCrop(layer->sourceCropf); - int transform = (layer->flags & HWC_COLOR_FILL) ? 0 : - layer->transform; - - hwc_rect_t irect = getIntersection(bottomframe, topframe); - if(isValidRect(irect)) { - hwc_rect_t dest_rect; - //if intersection is valid rect, deduct it - dest_rect = deductRect(bottomframe, irect); - qhwc::calculate_crop_rects(bottomCrop, bottomframe, - dest_rect, transform); - //Update layer sourceCropf - layer->sourceCropf.left =(float)bottomCrop.left; - layer->sourceCropf.top = (float)bottomCrop.top; - layer->sourceCropf.right = (float)bottomCrop.right; - layer->sourceCropf.bottom = (float)bottomCrop.bottom; - } - } - j--; - } - } - i--; - } -} - -void getNonWormholeRegion(hwc_display_contents_1_t* list, - hwc_rect_t& nwr) -{ - size_t last = list->numHwLayers - 1; - hwc_rect_t fbDisplayFrame = list->hwLayers[last].displayFrame; - //Initiliaze nwr to first frame - nwr.left = list->hwLayers[0].displayFrame.left; - nwr.top = list->hwLayers[0].displayFrame.top; - nwr.right = list->hwLayers[0].displayFrame.right; - nwr.bottom = list->hwLayers[0].displayFrame.bottom; - - for (size_t i = 1; i < last; i++) { - hwc_rect_t displayFrame = list->hwLayers[i].displayFrame; - nwr = getUnion(nwr, displayFrame); - } - - //Intersect with the framebuffer - nwr = getIntersection(nwr, fbDisplayFrame); -} - -bool isExternalActive(hwc_context_t* ctx) { - return ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive; -} - -void closeAcquireFds(hwc_display_contents_1_t* list) { - if(LIKELY(list)) { - for(uint32_t i = 0; i < list->numHwLayers; i++) { - //Close the acquireFenceFds - //HWC_FRAMEBUFFER are -1 already by SF, rest we close. - if(list->hwLayers[i].acquireFenceFd >= 0) { - close(list->hwLayers[i].acquireFenceFd); - list->hwLayers[i].acquireFenceFd = -1; - } - } - //Writeback - if(list->outbufAcquireFenceFd >= 0) { - close(list->outbufAcquireFenceFd); - list->outbufAcquireFenceFd = -1; - } - } -} - -int hwc_sync(hwc_context_t *ctx, hwc_display_contents_1_t* list, int dpy, - int fd) { - ATRACE_CALL(); - int ret = 0; - int acquireFd[MAX_NUM_APP_LAYERS]; - int count = 0; - int releaseFd = -1; - int retireFd = -1; - int fbFd = -1; - bool swapzero = false; - - struct mdp_buf_sync data; - memset(&data, 0, sizeof(data)); - data.acq_fen_fd = acquireFd; - data.rel_fen_fd = &releaseFd; - data.retire_fen_fd = &retireFd; - data.flags = MDP_BUF_SYNC_FLAG_RETIRE_FENCE; - -#ifdef DEBUG_SWAPINTERVAL - char property[PROPERTY_VALUE_MAX]; - if(property_get("debug.egl.swapinterval", property, "1") > 0) { - if(atoi(property) == 0) - swapzero = true; - } -#endif - - bool isExtAnimating = false; - if(dpy) - isExtAnimating = ctx->listStats[dpy].isDisplayAnimating; - - //Send acquireFenceFds to rotator - for(uint32_t i = 0; i < ctx->mLayerRotMap[dpy]->getCount(); i++) { - int rotFd = ctx->mRotMgr->getRotDevFd(); - int rotReleaseFd = -1; - overlay::Rotator* currRot = ctx->mLayerRotMap[dpy]->getRot(i); - hwc_layer_1_t* currLayer = ctx->mLayerRotMap[dpy]->getLayer(i); - if((currRot == NULL) || (currLayer == NULL)) { - continue; - } - struct mdp_buf_sync rotData; - memset(&rotData, 0, sizeof(rotData)); - rotData.acq_fen_fd = - &currLayer->acquireFenceFd; - rotData.rel_fen_fd = &rotReleaseFd; //driver to populate this - rotData.session_id = currRot->getSessId(); - if(currLayer->acquireFenceFd >= 0) { - rotData.acq_fen_fd_cnt = 1; //1 ioctl call per rot session - } - int ret = 0; - if(LIKELY(!swapzero) and (not ctx->mLayerRotMap[dpy]->isRotCached(i))) - ret = ioctl(rotFd, MSMFB_BUFFER_SYNC, &rotData); - - if(ret < 0) { - ALOGE("%s: ioctl MSMFB_BUFFER_SYNC failed for rot sync, err=%s", - __FUNCTION__, strerror(errno)); - close(rotReleaseFd); - } else { - close(currLayer->acquireFenceFd); - //For MDP to wait on. - currLayer->acquireFenceFd = - dup(rotReleaseFd); - //A buffer is free to be used by producer as soon as its copied to - //rotator - currLayer->releaseFenceFd = - rotReleaseFd; - } - } - - //Accumulate acquireFenceFds for MDP Overlays - if(list->outbufAcquireFenceFd >= 0) { - //Writeback output buffer - if(LIKELY(!swapzero) ) - acquireFd[count++] = list->outbufAcquireFenceFd; - } - - for(uint32_t i = 0; i < list->numHwLayers; i++) { - if(((isAbcInUse(ctx)== true ) || - (list->hwLayers[i].compositionType == HWC_OVERLAY)) && - list->hwLayers[i].acquireFenceFd >= 0) { - if(LIKELY(!swapzero) ) { - // if ABC is enabled for more than one layer. - // renderBufIndexforABC will work as FB.Hence - // set the acquireFD from fd - which is coming from copybit - if(fd >= 0 && (isAbcInUse(ctx) == true)) { - if(ctx->listStats[dpy].renderBufIndexforABC ==(int32_t)i) - acquireFd[count++] = fd; - else - continue; - } else - acquireFd[count++] = list->hwLayers[i].acquireFenceFd; - } - } - if(list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) { - if(LIKELY(!swapzero) ) { - if(fd >= 0) { - //set the acquireFD from fd - which is coming from c2d - acquireFd[count++] = fd; - // Buffer sync IOCTL should be async when using c2d fence is - // used - data.flags &= ~MDP_BUF_SYNC_FLAG_WAIT; - } else if(list->hwLayers[i].acquireFenceFd >= 0) - acquireFd[count++] = list->hwLayers[i].acquireFenceFd; - } - } - } - - if ((fd >= 0) && !dpy && ctx->mPtorInfo.isActive()) { - // Acquire c2d fence of Overlap render buffer - if(LIKELY(!swapzero) ) - acquireFd[count++] = fd; - } - - data.acq_fen_fd_cnt = count; - fbFd = ctx->dpyAttr[dpy].fd; - - //Waits for acquire fences, returns a release fence - if(LIKELY(!swapzero)) { - ret = ioctl(fbFd, MSMFB_BUFFER_SYNC, &data); - } - - if(ret < 0) { - ALOGE("%s: ioctl MSMFB_BUFFER_SYNC failed, err=%s", - __FUNCTION__, strerror(errno)); - ALOGE("%s: acq_fen_fd_cnt=%d flags=%d fd=%d dpy=%d numHwLayers=%zu", - __FUNCTION__, data.acq_fen_fd_cnt, data.flags, fbFd, - dpy, list->numHwLayers); - close(releaseFd); - releaseFd = -1; - close(retireFd); - retireFd = -1; - } - - for(uint32_t i = 0; i < list->numHwLayers; i++) { - if(list->hwLayers[i].compositionType == HWC_OVERLAY || -#ifdef QTI_BSP - list->hwLayers[i].compositionType == HWC_BLIT || -#endif - list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) { - //Populate releaseFenceFds. - if(UNLIKELY(swapzero)) { - list->hwLayers[i].releaseFenceFd = -1; - } else if(isExtAnimating) { - // Release all the app layer fds immediately, - // if animation is in progress. - list->hwLayers[i].releaseFenceFd = -1; - } else if(list->hwLayers[i].releaseFenceFd < 0 ) { -#ifdef QTI_BSP - //If rotator has not already populated this field - // & if it's a not VPU layer - - // if ABC is enabled for more than one layer - if(fd >= 0 && (isAbcInUse(ctx) == true) && - ctx->listStats[dpy].renderBufIndexforABC !=(int32_t)i){ - list->hwLayers[i].releaseFenceFd = dup(fd); - } else if((list->hwLayers[i].compositionType == HWC_BLIT)&& - (isAbcInUse(ctx) == false)){ - //For Blit, the app layers should be released when the Blit - //is complete. This fd was passed from copybit->draw - list->hwLayers[i].releaseFenceFd = dup(fd); - } else -#endif - { - list->hwLayers[i].releaseFenceFd = dup(releaseFd); - } - } - } - } - - if(fd >= 0) { - close(fd); - fd = -1; - } - - if (ctx->mCopyBit[dpy]) { - if (!dpy && ctx->mPtorInfo.isActive()) - ctx->mCopyBit[dpy]->setReleaseFdSync(releaseFd); - else - ctx->mCopyBit[dpy]->setReleaseFd(releaseFd); - } - - //Signals when MDP finishes reading rotator buffers. - ctx->mLayerRotMap[dpy]->setReleaseFd(releaseFd); - close(releaseFd); - releaseFd = -1; - - if(UNLIKELY(swapzero)) { - list->retireFenceFd = -1; - } else { - list->retireFenceFd = retireFd; - } - return ret; -} - -void setMdpFlags(hwc_context_t *ctx, hwc_layer_1_t *layer, - ovutils::eMdpFlags &mdpFlags, - int rotDownscale, int transform) { - private_handle_t *hnd = (private_handle_t *)layer->handle; - MetaData_t *metadata = hnd ? (MetaData_t *)hnd->base_metadata : NULL; - - if(layer->blending == HWC_BLENDING_PREMULT) { - ovutils::setMdpFlags(mdpFlags, - ovutils::OV_MDP_BLEND_FG_PREMULT); - } - - if(metadata && (metadata->operation & PP_PARAM_INTERLACED) && - metadata->interlaced) { - ovutils::setMdpFlags(mdpFlags, - ovutils::OV_MDP_DEINTERLACE); - } - - // Mark MDP flags with SECURE_OVERLAY_SESSION for driver - if(isSecureBuffer(hnd)) { - ovutils::setMdpFlags(mdpFlags, - ovutils::OV_MDP_SECURE_OVERLAY_SESSION); - } - - if(isSecureDisplayBuffer(hnd)) { - // Mark MDP flags with SECURE_DISPLAY_OVERLAY_SESSION for driver - ovutils::setMdpFlags(mdpFlags, - ovutils::OV_MDP_SECURE_DISPLAY_OVERLAY_SESSION); - } - - //Pre-rotation will be used using rotator. - if(has90Transform(layer) && isRotationDoable(ctx, hnd)) { - ovutils::setMdpFlags(mdpFlags, - ovutils::OV_MDP_SOURCE_ROTATED_90); - } - //No 90 component and no rot-downscale then flips done by MDP - //If we use rot then it might as well do flips - if(!(transform & HWC_TRANSFORM_ROT_90) && !rotDownscale) { - if(transform & HWC_TRANSFORM_FLIP_H) { - ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_FLIP_H); - } - - if(transform & HWC_TRANSFORM_FLIP_V) { - ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_FLIP_V); - } - } - - if(metadata && - ((metadata->operation & PP_PARAM_HSIC) - || (metadata->operation & PP_PARAM_IGC) - || (metadata->operation & PP_PARAM_SHARP2))) { - ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_PP_EN); - } -} - -int configRotator(Rotator *rot, Whf& whf, - hwc_rect_t& crop, const eMdpFlags& mdpFlags, - const eTransform& orient, const int& downscale) { - - // Fix alignments for TILED format - if(whf.format == MDP_Y_CRCB_H2V2_TILE || - whf.format == MDP_Y_CBCR_H2V2_TILE) { - whf.w = utils::alignup(whf.w, 64); - whf.h = utils::alignup(whf.h, 32); - } - rot->setSource(whf); - - if (qdutils::MDPVersion::getInstance().getMDPVersion() >= - qdutils::MDSS_V5) { - Dim rotCrop(crop.left, crop.top, crop.right - crop.left, - crop.bottom - crop.top); - rot->setCrop(rotCrop); - } - - rot->setFlags(mdpFlags); - rot->setTransform(orient); - rot->setDownscale(downscale); - if(!rot->commit()) return -1; - return 0; -} - -int configMdp(Overlay *ov, const PipeArgs& parg, - const eTransform& orient, const hwc_rect_t& crop, - const hwc_rect_t& pos, const MetaData_t *metadata, - const eDest& dest) { - ov->setSource(parg, dest); - ov->setTransform(orient, dest); - - int crop_w = crop.right - crop.left; - int crop_h = crop.bottom - crop.top; - Dim dcrop(crop.left, crop.top, crop_w, crop_h); - ov->setCrop(dcrop, dest); - - int posW = pos.right - pos.left; - int posH = pos.bottom - pos.top; - Dim position(pos.left, pos.top, posW, posH); - ov->setPosition(position, dest); - - if (metadata) - ov->setVisualParams(*metadata, dest); - - if (!ov->commit(dest)) { - return -1; - } - return 0; -} - -int configColorLayer(hwc_context_t *ctx, hwc_layer_1_t *layer, - const int& dpy, eMdpFlags& mdpFlags, eZorder& z, - const eDest& dest) { - - hwc_rect_t dst = layer->displayFrame; - trimLayer(ctx, dpy, 0, dst, dst); - - int w = ctx->dpyAttr[dpy].xres; - int h = ctx->dpyAttr[dpy].yres; - int dst_w = dst.right - dst.left; - int dst_h = dst.bottom - dst.top; - uint32_t color = layer->transform; - Whf whf(w, h, getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888), 0); - - ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_SOLID_FILL); - if (layer->blending == HWC_BLENDING_PREMULT) - ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_BLEND_FG_PREMULT); - - PipeArgs parg(mdpFlags, whf, z, static_cast<eRotFlags>(0), - layer->planeAlpha, - (ovutils::eBlending) getBlending(layer->blending)); - - // Configure MDP pipe for Color layer - Dim pos(dst.left, dst.top, dst_w, dst_h); - ctx->mOverlay->setSource(parg, dest); - ctx->mOverlay->setColor(color, dest); - ctx->mOverlay->setTransform(0, dest); - ctx->mOverlay->setCrop(pos, dest); - ctx->mOverlay->setPosition(pos, dest); - - if (!ctx->mOverlay->commit(dest)) { - ALOGE("%s: Configure color layer failed!", __FUNCTION__); - return -1; - } - return 0; -} - -void updateSource(eTransform& orient, Whf& whf, - hwc_rect_t& crop, Rotator *rot) { - Dim transformedCrop(crop.left, crop.top, - crop.right - crop.left, - crop.bottom - crop.top); - if (qdutils::MDPVersion::getInstance().getMDPVersion() >= - qdutils::MDSS_V5) { - //B-family rotator internally could modify destination dimensions if - //downscaling is supported - whf = rot->getDstWhf(); - transformedCrop = rot->getDstDimensions(); - } else { - //A-family rotator rotates entire buffer irrespective of crop, forcing - //us to recompute the crop based on transform - orient = static_cast<eTransform>(ovutils::getMdpOrient(orient)); - preRotateSource(orient, whf, transformedCrop); - } - - crop.left = transformedCrop.x; - crop.top = transformedCrop.y; - crop.right = transformedCrop.x + transformedCrop.w; - crop.bottom = transformedCrop.y + transformedCrop.h; -} - -int getRotDownscale(hwc_context_t *ctx, const hwc_layer_1_t *layer) { - if(not qdutils::MDPVersion::getInstance().isRotDownscaleEnabled()) { - return 0; - } - - int downscale = 0; - hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf); - hwc_rect_t dst = layer->displayFrame; - private_handle_t *hnd = (private_handle_t *)layer->handle; - - if(not hnd) { - return 0; - } - - MetaData_t *metadata = (MetaData_t *)hnd->base_metadata; - bool isInterlaced = metadata && (metadata->operation & PP_PARAM_INTERLACED) - && metadata->interlaced; - int transform = layer->transform; - uint32_t format = ovutils::getMdpFormat(hnd->format, isTileRendered(hnd)); - - if(isYuvBuffer(hnd)) { - if(ctx->mMDP.version >= qdutils::MDP_V4_2 && - ctx->mMDP.version < qdutils::MDSS_V5) { - downscale = Rotator::getDownscaleFactor(crop.right - crop.left, - crop.bottom - crop.top, dst.right - dst.left, - dst.bottom - dst.top, format, isInterlaced); - } else { - Dim adjCrop(crop.left, crop.top, crop.right - crop.left, - crop.bottom - crop.top); - Dim pos(dst.left, dst.top, dst.right - dst.left, - dst.bottom - dst.top); - if(transform & HAL_TRANSFORM_ROT_90) { - swap(adjCrop.w, adjCrop.h); - } - downscale = Rotator::getDownscaleFactor(adjCrop.w, adjCrop.h, pos.w, - pos.h, format, isInterlaced); - } - } - return downscale; -} - -bool isZoomModeEnabled(hwc_rect_t crop) { - // This does not work for zooming in top left corner of the image - return(crop.top > 0 || crop.left > 0); -} - -void updateCropAIVVideoMode(hwc_context_t *ctx, hwc_rect_t& crop, int dpy) { - ALOGD_IF(HWC_UTILS_DEBUG, "dpy %d Source crop [%d %d %d %d]", dpy, - crop.left, crop.top, crop.right, crop.bottom); - if(isZoomModeEnabled(crop)) { - Dim srcCrop(crop.left, crop.top, - crop.right - crop.left, - crop.bottom - crop.top); - int extW = ctx->dpyAttr[dpy].xres; - int extH = ctx->dpyAttr[dpy].yres; - //Crop the original video in order to fit external display aspect ratio - if(srcCrop.w * extH < extW * srcCrop.h) { - int offset = (srcCrop.h - ((srcCrop.w * extH) / extW)) / 2; - crop.top += offset; - crop.bottom -= offset; - } else { - int offset = (srcCrop.w - ((extW * srcCrop.h) / extH)) / 2; - crop.left += offset; - crop.right -= offset; - } - ALOGD_IF(HWC_UTILS_DEBUG, "External Resolution [%d %d] dpy %d Modified" - " source crop [%d %d %d %d]", extW, extH, dpy, - crop.left, crop.top, crop.right, crop.bottom); - } -} - -void updateDestAIVVideoMode(hwc_context_t *ctx, hwc_rect_t crop, - hwc_rect_t& dst, int dpy) { - ALOGD_IF(HWC_UTILS_DEBUG, "dpy %d Destination position [%d %d %d %d]", dpy, - dst.left, dst.top, dst.right, dst.bottom); - Dim srcCrop(crop.left, crop.top, - crop.right - crop.left, - crop.bottom - crop.top); - int extW = ctx->dpyAttr[dpy].xres; - int extH = ctx->dpyAttr[dpy].yres; - // Set the destination coordinates of external display to full screen, - // when zoom in mode is enabled or the ratio between video aspect ratio - // and external display aspect ratio is below the minimum tolerance level - // and above maximum tolerance level - float videoAspectRatio = ((float)srcCrop.w / (float)srcCrop.h); - float extDisplayAspectRatio = ((float)extW / (float)extH); - float videoToExternalRatio = videoAspectRatio / extDisplayAspectRatio; - if((fabs(1.0f - videoToExternalRatio) <= ctx->mAspectRatioToleranceLevel) || - (isZoomModeEnabled(crop))) { - dst.left = 0; - dst.top = 0; - dst.right = extW; - dst.bottom = extH; - } - ALOGD_IF(HWC_UTILS_DEBUG, "External Resolution [%d %d] dpy %d Modified" - " Destination position [%d %d %d %d] Source crop [%d %d %d %d]", - extW, extH, dpy, dst.left, dst.top, dst.right, dst.bottom, - crop.left, crop.top, crop.right, crop.bottom); -} - -void updateCoordinates(hwc_context_t *ctx, hwc_rect_t& crop, - hwc_rect_t& dst, int dpy) { - updateCropAIVVideoMode(ctx, crop, dpy); - updateDestAIVVideoMode(ctx, crop, dst, dpy); -} - -int configureNonSplit(hwc_context_t *ctx, hwc_layer_1_t *layer, - const int& dpy, eMdpFlags& mdpFlags, eZorder& z, - const eDest& dest, Rotator **rot) { - - private_handle_t *hnd = (private_handle_t *)layer->handle; - - if(!hnd) { - if (layer->flags & HWC_COLOR_FILL) { - // Configure Color layer - return configColorLayer(ctx, layer, dpy, mdpFlags, z, dest); - } - ALOGE("%s: layer handle is NULL", __FUNCTION__); - return -1; - } - - MetaData_t *metadata = (MetaData_t *)hnd->base_metadata; - - hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf); - hwc_rect_t dst = layer->displayFrame; - int transform = layer->transform; - eTransform orient = static_cast<eTransform>(transform); - int rotFlags = ovutils::ROT_FLAGS_NONE; - uint32_t format = ovutils::getMdpFormat(hnd->format, isTileRendered(hnd)); - Whf whf(getWidth(hnd), getHeight(hnd), format, (uint32_t)hnd->size); - - // Handle R/B swap - if (layer->flags & HWC_FORMAT_RB_SWAP) { - if (hnd->format == HAL_PIXEL_FORMAT_RGBA_8888) - whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRA_8888); - else if (hnd->format == HAL_PIXEL_FORMAT_RGBX_8888) - whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRX_8888); - } - // update source crop and destination position of AIV video layer. - if(ctx->listStats[dpy].mAIVVideoMode && isYuvBuffer(hnd)) { - updateCoordinates(ctx, crop, dst, dpy); - } - calcExtDisplayPosition(ctx, hnd, dpy, crop, dst, transform, orient); - int downscale = getRotDownscale(ctx, layer); - setMdpFlags(ctx, layer, mdpFlags, downscale, transform); - - //if 90 component or downscale, use rot - if((has90Transform(layer) or downscale) and isRotationDoable(ctx, hnd)) { - *rot = ctx->mRotMgr->getNext(); - if(*rot == NULL) return -1; - ctx->mLayerRotMap[dpy]->add(layer, *rot); - // BWC is not tested for other formats So enable it only for YUV format - if(!dpy && isYuvBuffer(hnd)) - BwcPM::setBwc(crop, dst, transform, downscale, mdpFlags); - //Configure rotator for pre-rotation - if(configRotator(*rot, whf, crop, mdpFlags, orient, downscale) < 0) { - ALOGE("%s: configRotator failed!", __FUNCTION__); - return -1; - } - updateSource(orient, whf, crop, *rot); - rotFlags |= ROT_PREROTATED; - } - - //For the mdp, since either we are pre-rotating or MDP does flips - orient = OVERLAY_TRANSFORM_0; - transform = 0; - PipeArgs parg(mdpFlags, whf, z, - static_cast<eRotFlags>(rotFlags), layer->planeAlpha, - (ovutils::eBlending) getBlending(layer->blending)); - - if(configMdp(ctx->mOverlay, parg, orient, crop, dst, metadata, dest) < 0) { - ALOGE("%s: commit failed for low res panel", __FUNCTION__); - return -1; - } - return 0; -} - -//Helper to 1) Ensure crops dont have gaps 2) Ensure L and W are even -void sanitizeSourceCrop(hwc_rect_t& cropL, hwc_rect_t& cropR, - private_handle_t *hnd) { - if(cropL.right - cropL.left) { - if(isYuvBuffer(hnd)) { - //Always safe to even down left - ovutils::even_floor(cropL.left); - //If right is even, automatically width is even, since left is - //already even - ovutils::even_floor(cropL.right); - } - //Make sure there are no gaps between left and right splits if the layer - //is spread across BOTH halves - if(cropR.right - cropR.left) { - cropR.left = cropL.right; - } - } - - if(cropR.right - cropR.left) { - if(isYuvBuffer(hnd)) { - //Always safe to even down left - ovutils::even_floor(cropR.left); - //If right is even, automatically width is even, since left is - //already even - ovutils::even_floor(cropR.right); - } - } -} - -int configureSplit(hwc_context_t *ctx, hwc_layer_1_t *layer, - const int& dpy, eMdpFlags& mdpFlagsL, eZorder& z, - const eDest& lDest, const eDest& rDest, - Rotator **rot) { - private_handle_t *hnd = (private_handle_t *)layer->handle; - if(!hnd) { - ALOGE("%s: layer handle is NULL", __FUNCTION__); - return -1; - } - - MetaData_t *metadata = (MetaData_t *)hnd->base_metadata; - - int hw_w = ctx->dpyAttr[dpy].xres; - int hw_h = ctx->dpyAttr[dpy].yres; - hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf); - hwc_rect_t dst = layer->displayFrame; - int transform = layer->transform; - eTransform orient = static_cast<eTransform>(transform); - int rotFlags = ROT_FLAGS_NONE; - uint32_t format = ovutils::getMdpFormat(hnd->format, isTileRendered(hnd)); - Whf whf(getWidth(hnd), getHeight(hnd), format, (uint32_t)hnd->size); - - // Handle R/B swap - if (layer->flags & HWC_FORMAT_RB_SWAP) { - if (hnd->format == HAL_PIXEL_FORMAT_RGBA_8888) - whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRA_8888); - else if (hnd->format == HAL_PIXEL_FORMAT_RGBX_8888) - whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRX_8888); - } - - // update source crop and destination position of AIV video layer. - if(ctx->listStats[dpy].mAIVVideoMode && isYuvBuffer(hnd)) { - updateCoordinates(ctx, crop, dst, dpy); - } - - /* Calculate the external display position based on MDP downscale, - ActionSafe, and extorientation features. */ - calcExtDisplayPosition(ctx, hnd, dpy, crop, dst, transform, orient); - int downscale = getRotDownscale(ctx, layer); - setMdpFlags(ctx, layer, mdpFlagsL, downscale, transform); - - if(lDest != OV_INVALID && rDest != OV_INVALID) { - //Enable overfetch - setMdpFlags(mdpFlagsL, OV_MDSS_MDP_DUAL_PIPE); - } - - //Will do something only if feature enabled and conditions suitable - //hollow call otherwise - if(ctx->mAD->prepare(ctx, crop, whf, hnd)) { - overlay::Writeback *wb = overlay::Writeback::getInstance(); - whf.format = wb->getOutputFormat(); - } - - if((has90Transform(layer) or downscale) and isRotationDoable(ctx, hnd)) { - (*rot) = ctx->mRotMgr->getNext(); - if((*rot) == NULL) return -1; - ctx->mLayerRotMap[dpy]->add(layer, *rot); - //Configure rotator for pre-rotation - if(configRotator(*rot, whf, crop, mdpFlagsL, orient, downscale) < 0) { - ALOGE("%s: configRotator failed!", __FUNCTION__); - return -1; - } - updateSource(orient, whf, crop, *rot); - rotFlags |= ROT_PREROTATED; - } - - eMdpFlags mdpFlagsR = mdpFlagsL; - setMdpFlags(mdpFlagsR, OV_MDSS_MDP_RIGHT_MIXER); - - hwc_rect_t tmp_cropL = {0}, tmp_dstL = {0}; - hwc_rect_t tmp_cropR = {0}, tmp_dstR = {0}; - - const int lSplit = getLeftSplit(ctx, dpy); - - // Calculate Left rects - if(dst.left < lSplit) { - tmp_cropL = crop; - tmp_dstL = dst; - hwc_rect_t scissor = {0, 0, lSplit, hw_h }; - scissor = getIntersection(ctx->mViewFrame[dpy], scissor); - qhwc::calculate_crop_rects(tmp_cropL, tmp_dstL, scissor, 0); - } - - // Calculate Right rects - if(dst.right > lSplit) { - tmp_cropR = crop; - tmp_dstR = dst; - hwc_rect_t scissor = {lSplit, 0, hw_w, hw_h }; - scissor = getIntersection(ctx->mViewFrame[dpy], scissor); - qhwc::calculate_crop_rects(tmp_cropR, tmp_dstR, scissor, 0); - } - - sanitizeSourceCrop(tmp_cropL, tmp_cropR, hnd); - - //When buffer is H-flipped, contents of mixer config also needs to swapped - //Not needed if the layer is confined to one half of the screen. - //If rotator has been used then it has also done the flips, so ignore them. - if((orient & OVERLAY_TRANSFORM_FLIP_H) && (dst.left < lSplit) && - (dst.right > lSplit) && (*rot) == NULL) { - hwc_rect_t new_cropR; - new_cropR.left = tmp_cropL.left; - new_cropR.right = new_cropR.left + (tmp_cropR.right - tmp_cropR.left); - - hwc_rect_t new_cropL; - new_cropL.left = new_cropR.right; - new_cropL.right = tmp_cropR.right; - - tmp_cropL.left = new_cropL.left; - tmp_cropL.right = new_cropL.right; - - tmp_cropR.left = new_cropR.left; - tmp_cropR.right = new_cropR.right; - - } - - //For the mdp, since either we are pre-rotating or MDP does flips - orient = OVERLAY_TRANSFORM_0; - transform = 0; - - //configure left mixer - if(lDest != OV_INVALID) { - PipeArgs pargL(mdpFlagsL, whf, z, - static_cast<eRotFlags>(rotFlags), layer->planeAlpha, - (ovutils::eBlending) getBlending(layer->blending)); - - if(configMdp(ctx->mOverlay, pargL, orient, - tmp_cropL, tmp_dstL, metadata, lDest) < 0) { - ALOGE("%s: commit failed for left mixer config", __FUNCTION__); - return -1; - } - } - - //configure right mixer - if(rDest != OV_INVALID) { - PipeArgs pargR(mdpFlagsR, whf, z, - static_cast<eRotFlags>(rotFlags), - layer->planeAlpha, - (ovutils::eBlending) getBlending(layer->blending)); - tmp_dstR.right = tmp_dstR.right - lSplit; - tmp_dstR.left = tmp_dstR.left - lSplit; - if(configMdp(ctx->mOverlay, pargR, orient, - tmp_cropR, tmp_dstR, metadata, rDest) < 0) { - ALOGE("%s: commit failed for right mixer config", __FUNCTION__); - return -1; - } - } - - return 0; -} - -int configureSourceSplit(hwc_context_t *ctx, hwc_layer_1_t *layer, - const int& dpy, eMdpFlags& mdpFlagsL, eZorder& z, - const eDest& lDest, const eDest& rDest, - Rotator **rot) { - private_handle_t *hnd = (private_handle_t *)layer->handle; - if(!hnd) { - ALOGE("%s: layer handle is NULL", __FUNCTION__); - return -1; - } - - MetaData_t *metadata = (MetaData_t *)hnd->base_metadata; - - hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);; - hwc_rect_t dst = layer->displayFrame; - int transform = layer->transform; - eTransform orient = static_cast<eTransform>(transform); - const int downscale = 0; - int rotFlags = ROT_FLAGS_NONE; - //Splitting only YUV layer on primary panel needs different zorders - //for both layers as both the layers are configured to single mixer - eZorder lz = z; - eZorder rz = (eZorder)(z + 1); - - Whf whf(getWidth(hnd), getHeight(hnd), - getMdpFormat(hnd->format), (uint32_t)hnd->size); - - // update source crop and destination position of AIV video layer. - if(ctx->listStats[dpy].mAIVVideoMode && isYuvBuffer(hnd)) { - updateCoordinates(ctx, crop, dst, dpy); - } - - /* Calculate the external display position based on MDP downscale, - ActionSafe, and extorientation features. */ - calcExtDisplayPosition(ctx, hnd, dpy, crop, dst, transform, orient); - - setMdpFlags(ctx, layer, mdpFlagsL, 0, transform); - trimLayer(ctx, dpy, transform, crop, dst); - - if(has90Transform(layer) && isRotationDoable(ctx, hnd)) { - (*rot) = ctx->mRotMgr->getNext(); - if((*rot) == NULL) return -1; - ctx->mLayerRotMap[dpy]->add(layer, *rot); - // BWC is not tested for other formats So enable it only for YUV format - if(!dpy && isYuvBuffer(hnd)) - BwcPM::setBwc(crop, dst, transform, downscale, mdpFlagsL); - //Configure rotator for pre-rotation - if(configRotator(*rot, whf, crop, mdpFlagsL, orient, downscale) < 0) { - ALOGE("%s: configRotator failed!", __FUNCTION__); - return -1; - } - updateSource(orient, whf, crop, *rot); - rotFlags |= ROT_PREROTATED; - } - - eMdpFlags mdpFlagsR = mdpFlagsL; - int lSplit = dst.left + (dst.right - dst.left)/2; - - hwc_rect_t tmp_cropL = {0}, tmp_dstL = {0}; - hwc_rect_t tmp_cropR = {0}, tmp_dstR = {0}; - - if(lDest != OV_INVALID) { - tmp_cropL = crop; - tmp_dstL = dst; - hwc_rect_t scissor = {dst.left, dst.top, lSplit, dst.bottom }; - qhwc::calculate_crop_rects(tmp_cropL, tmp_dstL, scissor, 0); - } - if(rDest != OV_INVALID) { - tmp_cropR = crop; - tmp_dstR = dst; - hwc_rect_t scissor = {lSplit, dst.top, dst.right, dst.bottom }; - qhwc::calculate_crop_rects(tmp_cropR, tmp_dstR, scissor, 0); - } - - sanitizeSourceCrop(tmp_cropL, tmp_cropR, hnd); - - //When buffer is H-flipped, contents of mixer config also needs to swapped - //Not needed if the layer is confined to one half of the screen. - //If rotator has been used then it has also done the flips, so ignore them. - if((orient & OVERLAY_TRANSFORM_FLIP_H) && lDest != OV_INVALID - && rDest != OV_INVALID && (*rot) == NULL) { - hwc_rect_t new_cropR; - new_cropR.left = tmp_cropL.left; - new_cropR.right = new_cropR.left + (tmp_cropR.right - tmp_cropR.left); - - hwc_rect_t new_cropL; - new_cropL.left = new_cropR.right; - new_cropL.right = tmp_cropR.right; - - tmp_cropL.left = new_cropL.left; - tmp_cropL.right = new_cropL.right; - - tmp_cropR.left = new_cropR.left; - tmp_cropR.right = new_cropR.right; - - } - - //For the mdp, since either we are pre-rotating or MDP does flips - orient = OVERLAY_TRANSFORM_0; - transform = 0; - - //configure left half - if(lDest != OV_INVALID) { - PipeArgs pargL(mdpFlagsL, whf, lz, - static_cast<eRotFlags>(rotFlags), layer->planeAlpha, - (ovutils::eBlending) getBlending(layer->blending)); - - if(configMdp(ctx->mOverlay, pargL, orient, - tmp_cropL, tmp_dstL, metadata, lDest) < 0) { - ALOGE("%s: commit failed for left half config", __FUNCTION__); - return -1; - } - } - - //configure right half - if(rDest != OV_INVALID) { - PipeArgs pargR(mdpFlagsR, whf, rz, - static_cast<eRotFlags>(rotFlags), - layer->planeAlpha, - (ovutils::eBlending) getBlending(layer->blending)); - if(configMdp(ctx->mOverlay, pargR, orient, - tmp_cropR, tmp_dstR, metadata, rDest) < 0) { - ALOGE("%s: commit failed for right half config", __FUNCTION__); - return -1; - } - } - - return 0; -} - -bool canUseRotator(hwc_context_t *ctx, int dpy) { - if(ctx->mOverlay->isDMAMultiplexingSupported() && - isSecondaryConnected(ctx) && - !ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isPause) { - /* mdss driver on certain targets support multiplexing of DMA pipe - * in LINE and BLOCK modes for writeback panels. - */ - if(dpy == HWC_DISPLAY_PRIMARY) - return false; - } - if((ctx->mMDP.version == qdutils::MDP_V3_0_4) - ||(ctx->mMDP.version == qdutils::MDP_V3_0_5)) - return false; - return true; -} - -int getLeftSplit(hwc_context_t *ctx, const int& dpy) { - //Default even split for all displays with high res - int lSplit = ctx->dpyAttr[dpy].xres / 2; - if(dpy == HWC_DISPLAY_PRIMARY && - qdutils::MDPVersion::getInstance().getLeftSplit()) { - //Override if split published by driver for primary - lSplit = qdutils::MDPVersion::getInstance().getLeftSplit(); - } - return lSplit; -} - -bool isDisplaySplit(hwc_context_t* ctx, int dpy) { - qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance(); - if(ctx->dpyAttr[dpy].xres > mdpHw.getMaxMixerWidth()) { - return true; - } - //For testing we could split primary via device tree values - if(dpy == HWC_DISPLAY_PRIMARY && mdpHw.getRightSplit()) { - return true; - } - return false; -} - -//clear prev layer prop flags and realloc for current frame -void reset_layer_prop(hwc_context_t* ctx, int dpy, int numAppLayers) { - if(ctx->layerProp[dpy]) { - delete[] ctx->layerProp[dpy]; - ctx->layerProp[dpy] = NULL; - } - ctx->layerProp[dpy] = new LayerProp[numAppLayers]; -} - -bool isAbcInUse(hwc_context_t *ctx){ - return (ctx->enableABC && ctx->listStats[0].renderBufIndexforABC == 0); -} - -void dumpBuffer(private_handle_t *ohnd, char *bufferName) { - if (ohnd != NULL && ohnd->base) { - char dumpFilename[PATH_MAX]; - bool bResult = false; - int width = getWidth(ohnd); - int height = getHeight(ohnd); - int format = ohnd->format; - //dummy aligned w & h. - int alW = 0, alH = 0; - int size = getBufferSizeAndDimensions(width, height, format, alW, alH); - snprintf(dumpFilename, sizeof(dumpFilename), "/data/%s.%s.%dx%d.raw", - bufferName, - overlay::utils::getFormatString(utils::getMdpFormat(format)), - width, height); - FILE* fp = fopen(dumpFilename, "w+"); - if (NULL != fp) { - bResult = (bool) fwrite((void*)ohnd->base, size, 1, fp); - fclose(fp); - } - ALOGD("Buffer[%s] Dump to %s: %s", - bufferName, dumpFilename, bResult ? "Success" : "Fail"); - } -} - -bool isGLESComp(hwc_context_t *ctx, - hwc_display_contents_1_t* list) { - int numAppLayers = ctx->listStats[HWC_DISPLAY_PRIMARY].numAppLayers; - for(int index = 0; index < numAppLayers; index++) { - hwc_layer_1_t* layer = &(list->hwLayers[index]); - if(layer->compositionType == HWC_FRAMEBUFFER) - return true; - } - return false; -} - -void setGPUHint(hwc_context_t* ctx, hwc_display_contents_1_t* list) { -#ifdef QTI_BSP - struct gpu_hint_info *gpuHint = &ctx->mGPUHintInfo; - if(!gpuHint->mGpuPerfModeEnable || !ctx || !list) - return; - - /* Set the GPU hint flag to high for MIXED/GPU composition only for - first frame after MDP -> GPU/MIXED mode transition. Set the GPU - hint to default if the previous composition is GPU or current GPU - composition is due to idle fallback */ - if(!gpuHint->mEGLDisplay || !gpuHint->mEGLContext) { - gpuHint->mEGLDisplay = (*(ctx->mpfn_eglGetCurrentDisplay))(); - if(!gpuHint->mEGLDisplay) { - ALOGW("%s Warning: EGL current display is NULL", __FUNCTION__); - return; - } - gpuHint->mEGLContext = (*(ctx->mpfn_eglGetCurrentContext))(); - if(!gpuHint->mEGLContext) { - ALOGW("%s Warning: EGL current context is NULL", __FUNCTION__); - return; - } - } - if(isGLESComp(ctx, list)) { - if(gpuHint->mCompositionState != COMPOSITION_STATE_GPU - && !MDPComp::isIdleFallback()) { - EGLint attr_list[] = {EGL_GPU_HINT_1, - EGL_GPU_LEVEL_3, - EGL_NONE }; - if((gpuHint->mCurrGPUPerfMode != EGL_GPU_LEVEL_3) && - !((*(ctx->mpfn_eglGpuPerfHintQCOM))(gpuHint->mEGLDisplay, - gpuHint->mEGLContext, attr_list))) { - ALOGW("eglGpuPerfHintQCOM failed for Built in display"); - } else { - gpuHint->mCurrGPUPerfMode = EGL_GPU_LEVEL_3; - gpuHint->mCompositionState = COMPOSITION_STATE_GPU; - } - } else { - EGLint attr_list[] = {EGL_GPU_HINT_1, - EGL_GPU_LEVEL_0, - EGL_NONE }; - if((gpuHint->mCurrGPUPerfMode != EGL_GPU_LEVEL_0) && - !((*(ctx->mpfn_eglGpuPerfHintQCOM))(gpuHint->mEGLDisplay, - gpuHint->mEGLContext, attr_list))) { - ALOGW("eglGpuPerfHintQCOM failed for Built in display"); - } else { - gpuHint->mCurrGPUPerfMode = EGL_GPU_LEVEL_0; - } - if(MDPComp::isIdleFallback()) { - gpuHint->mCompositionState = COMPOSITION_STATE_IDLE_FALLBACK; - } - } - } else { - /* set the GPU hint flag to default for MDP composition */ - EGLint attr_list[] = {EGL_GPU_HINT_1, - EGL_GPU_LEVEL_0, - EGL_NONE }; - if((gpuHint->mCurrGPUPerfMode != EGL_GPU_LEVEL_0) && - !((*(ctx->mpfn_eglGpuPerfHintQCOM))(gpuHint->mEGLDisplay, - gpuHint->mEGLContext, attr_list))) { - ALOGW("eglGpuPerfHintQCOM failed for Built in display"); - } else { - gpuHint->mCurrGPUPerfMode = EGL_GPU_LEVEL_0; - } - gpuHint->mCompositionState = COMPOSITION_STATE_MDP; - } -#else - (void) ctx; - (void) list; -#endif -} - -bool isPeripheral(const hwc_rect_t& rect1, const hwc_rect_t& rect2) { - // To be peripheral, 3 boundaries should match. - uint8_t eqBounds = 0; - if (rect1.left == rect2.left) - eqBounds++; - if (rect1.top == rect2.top) - eqBounds++; - if (rect1.right == rect2.right) - eqBounds++; - if (rect1.bottom == rect2.bottom) - eqBounds++; - return (eqBounds == 3); -} - -void processBootAnimCompleted(hwc_context_t *ctx) { - char value[PROPERTY_VALUE_MAX]; - - // Applying default mode after bootanimation is finished - property_get("init.svc.bootanim", value, "running"); - - if (!strncmp(value,"stopped",strlen("stopped"))) { - ctx->mBootAnimCompleted = true; - - //one-shot action check if bootanimation completed then apply - //default display mode. - qdcmApplyDefaultAfterBootAnimationDone(ctx); - } -} - -void BwcPM::setBwc(const hwc_rect_t& crop, const hwc_rect_t& dst, - const int& transform,const int& downscale, - ovutils::eMdpFlags& mdpFlags) { - //BWC not supported with rot-downscale - if(downscale) return; - - //Target doesnt support Bwc - qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance(); - if(!mdpHw.supportsBWC()) { - return; - } - int src_w = crop.right - crop.left; - int src_h = crop.bottom - crop.top; - int dst_w = dst.right - dst.left; - int dst_h = dst.bottom - dst.top; - if(transform & HAL_TRANSFORM_ROT_90) { - swap(src_w, src_h); - } - //src width > MAX mixer supported dim - if(src_w > (int) qdutils::MDPVersion::getInstance().getMaxMixerWidth()) { - return; - } - //Decimation necessary, cannot use BWC. H/W requirement. - if(qdutils::MDPVersion::getInstance().supportsDecimation()) { - uint8_t horzDeci = 0; - uint8_t vertDeci = 0; - ovutils::getDecimationFactor(src_w, src_h, dst_w, dst_h, horzDeci, - vertDeci); - if(horzDeci || vertDeci) return; - } - //Property - char value[PROPERTY_VALUE_MAX]; - property_get("debug.disable.bwc", value, "0"); - if(atoi(value)) return; - - ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDSS_MDP_BWC_EN); -} - -void LayerRotMap::add(hwc_layer_1_t* layer, Rotator *rot) { - if(mCount >= RotMgr::MAX_ROT_SESS) return; - mLayer[mCount] = layer; - mRot[mCount] = rot; - mCount++; -} - -void LayerRotMap::reset() { - for (int i = 0; i < RotMgr::MAX_ROT_SESS; i++) { - mLayer[i] = 0; - mRot[i] = 0; - } - mCount = 0; -} - -void LayerRotMap::clear() { - RotMgr::getInstance()->markUnusedTop(mCount); - reset(); -} - -bool LayerRotMap::isRotCached(uint32_t index) const { - overlay::Rotator* rot = getRot(index); - hwc_layer_1_t* layer = getLayer(index); - - if(rot and layer and layer->handle) { - private_handle_t *hnd = (private_handle_t *)(layer->handle); - return (rot->isRotCached(hnd->fd,(uint32_t)(hnd->offset))); - } - return false; -} - -void LayerRotMap::setReleaseFd(const int& fence) { - for(uint32_t i = 0; i < mCount; i++) { - if(mRot[i] and mLayer[i] and mLayer[i]->handle) { - /* Ensure that none of the above (Rotator-instance, - * layer and layer-handle) are NULL*/ - if(isRotCached(i)) - mRot[i]->setPrevBufReleaseFd(dup(fence)); - else - mRot[i]->setCurrBufReleaseFd(dup(fence)); - } - } -} - -void resetROI(hwc_context_t *ctx, const int dpy) { - const int fbXRes = (int)ctx->dpyAttr[dpy].xres; - const int fbYRes = (int)ctx->dpyAttr[dpy].yres; - if(isDisplaySplit(ctx, dpy)) { - const int lSplit = getLeftSplit(ctx, dpy); - ctx->listStats[dpy].lRoi = (struct hwc_rect){0, 0, lSplit, fbYRes}; - ctx->listStats[dpy].rRoi = (struct hwc_rect){lSplit, 0, fbXRes, fbYRes}; - } else { - ctx->listStats[dpy].lRoi = (struct hwc_rect){0, 0,fbXRes, fbYRes}; - ctx->listStats[dpy].rRoi = (struct hwc_rect){0, 0, 0, 0}; - } -} - -hwc_rect_t getSanitizeROI(struct hwc_rect roi, hwc_rect boundary) -{ - if(!isValidRect(roi)) - return roi; - - struct hwc_rect t_roi = roi; - - const int LEFT_ALIGN = qdutils::MDPVersion::getInstance().getLeftAlign(); - const int WIDTH_ALIGN = qdutils::MDPVersion::getInstance().getWidthAlign(); - const int TOP_ALIGN = qdutils::MDPVersion::getInstance().getTopAlign(); - const int HEIGHT_ALIGN = qdutils::MDPVersion::getInstance().getHeightAlign(); - const int MIN_WIDTH = qdutils::MDPVersion::getInstance().getMinROIWidth(); - const int MIN_HEIGHT = qdutils::MDPVersion::getInstance().getMinROIHeight(); - - /* Align to minimum width recommended by the panel */ - if((t_roi.right - t_roi.left) < MIN_WIDTH) { - if((t_roi.left + MIN_WIDTH) > boundary.right) - t_roi.left = t_roi.right - MIN_WIDTH; - else - t_roi.right = t_roi.left + MIN_WIDTH; - } - - /* Align to minimum height recommended by the panel */ - if((t_roi.bottom - t_roi.top) < MIN_HEIGHT) { - if((t_roi.top + MIN_HEIGHT) > boundary.bottom) - t_roi.top = t_roi.bottom - MIN_HEIGHT; - else - t_roi.bottom = t_roi.top + MIN_HEIGHT; - } - - /* Align left and width to meet panel restrictions */ - if(LEFT_ALIGN) - t_roi.left = t_roi.left - (t_roi.left % LEFT_ALIGN); - - if(WIDTH_ALIGN) { - int width = t_roi.right - t_roi.left; - width = WIDTH_ALIGN * ((width + (WIDTH_ALIGN - 1)) / WIDTH_ALIGN); - t_roi.right = t_roi.left + width; - - if(t_roi.right > boundary.right) { - t_roi.right = boundary.right; - t_roi.left = t_roi.right - width; - - if(LEFT_ALIGN) - t_roi.left = t_roi.left - (t_roi.left % LEFT_ALIGN); - } - } - - - /* Align top and height to meet panel restrictions */ - if(TOP_ALIGN) - t_roi.top = t_roi.top - (t_roi.top % TOP_ALIGN); - - if(HEIGHT_ALIGN) { - int height = t_roi.bottom - t_roi.top; - height = HEIGHT_ALIGN * ((height + (HEIGHT_ALIGN - 1)) / HEIGHT_ALIGN); - t_roi.bottom = t_roi.top + height; - - if(t_roi.bottom > boundary.bottom) { - t_roi.bottom = boundary.bottom; - t_roi.top = t_roi.bottom - height; - - if(TOP_ALIGN) - t_roi.top = t_roi.top - (t_roi.top % TOP_ALIGN); - } - } - - - return t_roi; -} - -void handle_pause(hwc_context_t* ctx, int dpy) { - if(ctx->dpyAttr[dpy].connected) { - ctx->mDrawLock.lock(); - ctx->dpyAttr[dpy].isActive = true; - ctx->dpyAttr[dpy].isPause = true; - ctx->mDrawLock.unlock(); - ctx->proc->invalidate(ctx->proc); - - usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period - * 2 / 1000); - - // At this point all the pipes used by External have been - // marked as UNSET. - ctx->mDrawLock.lock(); - // Perform commit to unstage the pipes. - if (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) { - ALOGE("%s: display commit fail! for %d dpy", - __FUNCTION__, dpy); - } - ctx->mDrawLock.unlock(); - ctx->proc->invalidate(ctx->proc); - } - return; -} - -void handle_resume(hwc_context_t* ctx, int dpy) { - if(ctx->dpyAttr[dpy].connected) { - ctx->mDrawLock.lock(); - ctx->dpyAttr[dpy].isConfiguring = true; - ctx->dpyAttr[dpy].isActive = true; - ctx->mDrawLock.unlock(); - ctx->proc->invalidate(ctx->proc); - - usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period - * 2 / 1000); - - //At this point external has all the pipes it would need. - ctx->mDrawLock.lock(); - ctx->dpyAttr[dpy].isPause = false; - ctx->mDrawLock.unlock(); - ctx->proc->invalidate(ctx->proc); - } - return; -} - -void clearPipeResources(hwc_context_t* ctx, int dpy) { - if(ctx->mOverlay) { - ctx->mOverlay->configBegin(); - ctx->mOverlay->configDone(); - } - if(ctx->mRotMgr) { - ctx->mRotMgr->clear(); - } - // Call a display commit to ensure that pipes and associated - // fd's are cleaned up. - if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) { - ALOGE("%s: display commit failed for %d", __FUNCTION__, dpy); - } -} - -// Handles online events when HDMI is the primary display. In particular, -// online events for hdmi connected before AND after boot up and HWC init. -void handle_online(hwc_context_t* ctx, int dpy) { - // Close the current fd if it was opened earlier on when HWC - // was initialized. - if (ctx->dpyAttr[dpy].fd >= 0) { - close(ctx->dpyAttr[dpy].fd); - ctx->dpyAttr[dpy].fd = -1; - } - // TODO: If HDMI is connected after the display has booted up, - // and the best configuration is different from the default - // then we need to deal with this appropriately. - ctx->mHDMIDisplay->configure(); - updateDisplayInfo(ctx, dpy); - initCompositionResources(ctx, dpy); - ctx->dpyAttr[dpy].connected = true; -} - -// Handles offline events for HDMI. This can be used for offline events -// initiated by the HDMI driver and the CEC framework. -void handle_offline(hwc_context_t* ctx, int dpy) { - destroyCompositionResources(ctx, dpy); - // Clear all pipe resources and call a display commit to ensure - // that all the fd's are closed. This will ensure that the HDMI - // core turns off and that we receive an event the next time the - // cable is connected. - if (ctx->mHDMIDisplay->isHDMIPrimaryDisplay()) { - clearPipeResources(ctx, dpy); - } - ctx->mHDMIDisplay->teardown(); - resetDisplayInfo(ctx, dpy); - ctx->dpyAttr[dpy].connected = false; - ctx->dpyAttr[dpy].isActive = false; -} - -bool loadEglLib(hwc_context_t* ctx) { - bool success = false; -#ifdef QTI_BSP - dlerror(); - - ctx->mEglLib = dlopen("libEGL_adreno.so", RTLD_NOW); - if(ctx->mEglLib) { - *(void **)&(ctx->mpfn_eglGpuPerfHintQCOM) = dlsym(ctx->mEglLib, "eglGpuPerfHintQCOM"); - *(void **)&(ctx->mpfn_eglGetCurrentDisplay) = dlsym(ctx->mEglLib,"eglGetCurrentDisplay"); - *(void **)&(ctx->mpfn_eglGetCurrentContext) = dlsym(ctx->mEglLib,"eglGetCurrentContext"); - if (!ctx->mpfn_eglGpuPerfHintQCOM || - !ctx->mpfn_eglGetCurrentDisplay || - !ctx->mpfn_eglGetCurrentContext) { - ALOGE("Failed to load symbols from libEGL"); - dlclose(ctx->mEglLib); - ctx->mEglLib = NULL; - return false; - } - success = true; - ALOGI("Successfully Loaded GPUPerfHint APIs"); - } else { - ALOGE("Couldn't load libEGL: %s", dlerror()); - } -#else - (void) ctx; -#endif - return success; -} - -};//namespace qhwc diff --git a/msm8909/libhwcomposer/hwc_utils.h b/msm8909/libhwcomposer/hwc_utils.h deleted file mode 100644 index 0b824af4..00000000 --- a/msm8909/libhwcomposer/hwc_utils.h +++ /dev/null @@ -1,718 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C)2012-2016, The Linux Foundation. All rights reserved. - * - * Not a Contribution, Apache license notifications and license are retained - * for attribution purposes only. - * - * 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_UTILS_H -#define HWC_UTILS_H - -#define DEBUG_MDPDOWNSCALE 0 -#define HWC_REMOVE_DEPRECATED_VERSIONS 1 - -#include <fcntl.h> -#include <math.h> -#include <hardware/hwcomposer.h> -#include <gr.h> -#include <gralloc_priv.h> -#include <utils/String8.h> -#include "qdMetaData.h" -#include "mdp_version.h" -#include <overlayUtils.h> -#include <overlayRotator.h> -#include <EGL/egl.h> - - -#define ALIGN_TO(x, align) (((x) + ((align)-1)) & ~((align)-1)) -#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) -#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) -#define MAX_NUM_APP_LAYERS 32 -#define MIN_DISPLAY_XRES 200 -#define MIN_DISPLAY_YRES 200 -#define HWC_WFDDISPSYNC_LOG 0 -#define STR(f) #f; -// Max number of PTOR layers handled -#define MAX_PTOR_LAYERS 2 - -#ifdef QTI_BSP -#include <exhwcomposer_defs.h> -#endif - -//Fwrd decls -struct hwc_context_t; - -namespace ovutils = overlay::utils; - -namespace qmode { -class ModeManager; -} - -namespace overlay { -class Overlay; -class Rotator; -class RotMgr; -} - -namespace qhwc { -//fwrd decl -class QueuedBufferStore; -class HDMIDisplay; -class VirtualDisplay; -class IFBUpdate; -class IVideoOverlay; -class MDPComp; -class CopyBit; -class HwcDebug; -class AssertiveDisplay; -class HWCVirtualVDS; - - -struct MDPInfo { - int version; - char panel; - bool hasOverlay; -}; - -struct DisplayAttributes { - uint32_t refreshRate; - uint32_t dynRefreshRate; - uint32_t vsync_period; //nanos - uint32_t xres; - uint32_t yres; - uint32_t stride; - float xdpi; - float ydpi; - uint32_t fbformat; - int fd; - bool connected; //Applies only to pluggable disp. - //Connected does not mean it ready to use. - //It should be active also. (UNBLANKED) - bool isActive; - // In pause state, composition is bypassed - // used for WFD displays and in QDCM calibration mode - bool isPause; - // To trigger padding round to clean up mdp - // pipes - bool isConfiguring; - // Indicates whether external/virtual display is in MDP scaling mode - bool mMDPScalingMode; - // Ext dst Rect - hwc_rect_t mDstRect; - //Action safe attributes - // Flag to indicate the presence of action safe dimensions for external - bool mActionSafePresent; - int mAsWidthRatio; - int mAsHeightRatio; - - //If property fbsize set via adb shell debug.hwc.fbsize = XRESxYRES - //following fields are used. - bool customFBSize; - uint32_t xres_new; - uint32_t yres_new; - -}; - -struct ListStats { - int numAppLayers; //Total - 1, excluding FB layer. - int skipCount; - int fbLayerIndex; //Always last for now. = numAppLayers - //Video specific - int yuvCount; - int yuvIndices[MAX_NUM_APP_LAYERS]; - bool preMultipliedAlpha; - int yuv4k2kIndices[MAX_NUM_APP_LAYERS]; - int yuv4k2kCount; - // Notifies hwcomposer about the start and end of animation - // This will be set to true during animation, otherwise false. - bool isDisplayAnimating; - bool secureUI; // Secure display layer - bool isSecurePresent; - hwc_rect_t lRoi; //left ROI - hwc_rect_t rRoi; //right ROI. Unused in single DSI panels. - //App Buffer Composition index - int renderBufIndexforABC; - // Secure RGB specific - int secureRGBCount; - int secureRGBIndices[MAX_NUM_APP_LAYERS]; - //dyn refresh rate-Client requested refreshrate - uint32_t refreshRateRequest; - // Flag related to windowboxing feature - bool mAIVVideoMode; -}; - -//PTOR Comp info -struct PtorInfo { - int count; - int layerIndex[MAX_PTOR_LAYERS]; - hwc_rect_t displayFrame[MAX_PTOR_LAYERS]; - bool isActive() { return (count>0); } - int getPTORArrayIndex(int index) { - int idx = -1; - for(int i = 0; i < count; i++) { - if(index == layerIndex[i]) - idx = i; - } - return idx; - } -}; - -struct LayerProp { - uint32_t mFlags; //qcom specific layer flags - LayerProp():mFlags(0){}; -}; - -struct VsyncState { - bool enable; - bool fakevsync; - bool debug; -}; - -struct BwcPM { - static void setBwc(const hwc_rect_t& crop, const hwc_rect_t& dst, - const int& transform, const int& downscale, - ovutils::eMdpFlags& mdpFlags); -}; - -// LayerProp::flag values -enum { - HWC_MDPCOMP = 0x00000001, - HWC_COPYBIT = 0x00000002, -}; - -// AIV specific flags -enum { - HWC_AIV_VIDEO = 0x80000000, - HWC_AIV_CC = 0x40000000, -}; - -// HAL specific features -enum { - HWC_COLOR_FILL = 0x00000008, - HWC_FORMAT_RB_SWAP = 0x00000040, -}; - -/* External Display states */ -enum { - EXTERNAL_OFFLINE = 0, - EXTERNAL_ONLINE, - EXTERNAL_PAUSE, - EXTERNAL_RESUME, - EXTERNAL_MAXSTATES -}; - -class LayerRotMap { -public: - LayerRotMap() { reset(); } - void add(hwc_layer_1_t* layer, overlay::Rotator *rot); - //Resets the mapping of layer to rotator - void reset(); - //Clears mappings and existing rotator fences - //Intended to be used during errors - void clear(); - uint32_t getCount() const; - hwc_layer_1_t* getLayer(uint32_t index) const; - overlay::Rotator* getRot(uint32_t index) const; - bool isRotCached(uint32_t index) const; - void setReleaseFd(const int& fence); -private: - hwc_layer_1_t* mLayer[overlay::RotMgr::MAX_ROT_SESS]; - overlay::Rotator* mRot[overlay::RotMgr::MAX_ROT_SESS]; - uint32_t mCount; -}; - -inline uint32_t LayerRotMap::getCount() const { - return mCount; -} - -inline hwc_layer_1_t* LayerRotMap::getLayer(uint32_t index) const { - if(index >= mCount) return NULL; - return mLayer[index]; -} - -inline overlay::Rotator* LayerRotMap::getRot(uint32_t index) const { - if(index >= mCount) return NULL; - return mRot[index]; -} - -inline hwc_rect_t integerizeSourceCrop(const hwc_frect_t& cropF) { - hwc_rect_t cropI = {0,0,0,0}; - cropI.left = int(ceilf(cropF.left)); - cropI.top = int(ceilf(cropF.top)); - cropI.right = int(floorf(cropF.right)); - cropI.bottom = int(floorf(cropF.bottom)); - return cropI; -} - -inline bool isNonIntegralSourceCrop(const hwc_frect_t& cropF) { - if(cropF.left - roundf(cropF.left) || - cropF.top - roundf(cropF.top) || - cropF.right - roundf(cropF.right) || - cropF.bottom - roundf(cropF.bottom)) - return true; - else - return false; -} - -// ----------------------------------------------------------------------------- -// Utility functions - implemented in hwc_utils.cpp -void dumpLayer(hwc_layer_1_t const* l); -void setListStats(hwc_context_t *ctx, hwc_display_contents_1_t *list, - int dpy); -void initContext(hwc_context_t *ctx); -void closeContext(hwc_context_t *ctx); -//Crops source buffer against destination and FB boundaries -void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst, - const hwc_rect_t& scissor, int orient); -void getNonWormholeRegion(hwc_display_contents_1_t* list, - hwc_rect_t& nwr); -bool isSecuring(hwc_context_t* ctx, hwc_layer_1_t const* layer); -bool isSecureModePolicy(int mdpVersion); -// Returns true, if the input layer format is supported by rotator -bool isRotatorSupportedFormat(private_handle_t *hnd); -//Returns true, if the layer is YUV or the layer has been rendered by CPU -bool isRotationDoable(hwc_context_t *ctx, private_handle_t *hnd); -bool isExternalActive(hwc_context_t* ctx); -bool isAlphaScaled(hwc_layer_1_t const* layer); -bool needsScaling(hwc_layer_1_t const* layer); -bool isDownscaleRequired(hwc_layer_1_t const* layer); -bool needsScalingWithSplit(hwc_context_t* ctx, hwc_layer_1_t const* layer, - const int& dpy); -void sanitizeSourceCrop(hwc_rect_t& cropL, hwc_rect_t& cropR, - private_handle_t *hnd); -bool isAlphaPresent(hwc_layer_1_t const* layer); -bool isAlphaPresentinFB(hwc_context_t* ctx, int dpy); -int hwc_vsync_control(hwc_context_t* ctx, int dpy, int enable); -int getBlending(int blending); -bool isGLESOnlyComp(hwc_context_t *ctx, const int& dpy); -void reset_layer_prop(hwc_context_t* ctx, int dpy, int numAppLayers); -bool isAbcInUse(hwc_context_t *ctx); - -void dumpBuffer(private_handle_t *ohnd, char *bufferName); -void updateDisplayInfo(hwc_context_t* ctx, int dpy); -void resetDisplayInfo(hwc_context_t* ctx, int dpy); -void initCompositionResources(hwc_context_t* ctx, int dpy); -void destroyCompositionResources(hwc_context_t* ctx, int dpy); -void clearPipeResources(hwc_context_t* ctx, int dpy); - -//Helper function to dump logs -void dumpsys_log(android::String8& buf, const char* fmt, ...); - -int getExtOrientation(hwc_context_t* ctx); -bool isValidRect(const hwc_rect_t& rect); -hwc_rect_t deductRect(const hwc_rect_t& rect1, const hwc_rect_t& rect2); -bool isSameRect(const hwc_rect& rect1, const hwc_rect& rect2); -hwc_rect_t moveRect(const hwc_rect_t& rect, const int& x_off, const int& y_off); -hwc_rect_t getIntersection(const hwc_rect_t& rect1, const hwc_rect_t& rect2); -hwc_rect_t getUnion(const hwc_rect_t& rect1, const hwc_rect_t& rect2); -void optimizeLayerRects(const hwc_display_contents_1_t *list); -bool areLayersIntersecting(const hwc_layer_1_t* layer1, - const hwc_layer_1_t* layer2); -bool operator ==(const hwc_rect_t& lhs, const hwc_rect_t& rhs); -bool layerUpdating(const hwc_layer_1_t* layer); -/* Calculates the dirtyRegion for the given layer */ -hwc_rect_t calculateDirtyRect(const hwc_layer_1_t* layer, - hwc_rect_t& scissor); - - -// returns true if Action safe dimensions are set and target supports Actionsafe -bool isActionSafePresent(hwc_context_t *ctx, int dpy); - -/* Calculates the destination position based on the action safe rectangle */ -void getActionSafePosition(hwc_context_t *ctx, int dpy, hwc_rect_t& dst); - -void getAspectRatioPosition(hwc_context_t* ctx, int dpy, int extOrientation, - hwc_rect_t& inRect, hwc_rect_t& outRect); - -uint32_t getRefreshRate(hwc_context_t* ctx, uint32_t requestedRefreshRate); - -uint32_t roundOff(uint32_t refreshRate); - -void setRefreshRate(hwc_context_t *ctx, int dpy, uint32_t refreshRate); - -bool isPrimaryPortrait(hwc_context_t *ctx); - -bool isOrientationPortrait(hwc_context_t *ctx); - -void calcExtDisplayPosition(hwc_context_t *ctx, - private_handle_t *hnd, - int dpy, - hwc_rect_t& sourceCrop, - hwc_rect_t& displayFrame, - int& transform, - ovutils::eTransform& orient); - -// Returns the orientation that needs to be set on external for -// BufferMirrirMode(Sidesync) -int getMirrorModeOrientation(hwc_context_t *ctx); - -/* Get External State names */ -const char* getExternalDisplayState(uint32_t external_state); - -// Resets display ROI to full panel resoluion -void resetROI(hwc_context_t *ctx, const int dpy); - -// Aligns updating ROI to panel restrictions -hwc_rect_t getSanitizeROI(struct hwc_rect roi, hwc_rect boundary); - -// Handles wfd Pause and resume events -void handle_pause(hwc_context_t *ctx, int dpy); -void handle_resume(hwc_context_t *ctx, int dpy); - -// Handle ONLINE/OFFLINE for HDMI display -void handle_online(hwc_context_t* ctx, int dpy); -void handle_offline(hwc_context_t* ctx, int dpy); - -//Close acquireFenceFds of all layers of incoming list -void closeAcquireFds(hwc_display_contents_1_t* list); - -//Sync point impl. -int hwc_sync(hwc_context_t *ctx, hwc_display_contents_1_t* list, int dpy, - int fd); - -//Sets appropriate mdp flags for a layer. -void setMdpFlags(hwc_context_t *ctx, hwc_layer_1_t *layer, - ovutils::eMdpFlags &mdpFlags, - int rotDownscale, int transform); - -int configRotator(overlay::Rotator *rot, ovutils::Whf& whf, - hwc_rect_t& crop, const ovutils::eMdpFlags& mdpFlags, - const ovutils::eTransform& orient, const int& downscale); - -int configMdp(overlay::Overlay *ov, const ovutils::PipeArgs& parg, - const ovutils::eTransform& orient, const hwc_rect_t& crop, - const hwc_rect_t& pos, const MetaData_t *metadata, - const ovutils::eDest& dest); - -int configColorLayer(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy, - ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z, - const ovutils::eDest& dest); - -void updateSource(ovutils::eTransform& orient, ovutils::Whf& whf, - hwc_rect_t& crop, overlay::Rotator *rot); - -bool isZoomModeEnabled(hwc_rect_t crop); -void updateCropAIVVideoMode(hwc_context_t *ctx, hwc_rect_t& crop, int dpy); -void updateDestAIVVideoMode(hwc_context_t *ctx, hwc_rect_t& dst, int dpy); -void updateCoordinates(hwc_context_t *ctx, hwc_rect_t& crop, - hwc_rect_t& dst, int dpy); - -//Routine to configure low resolution panels (<= 2048 width) -int configureNonSplit(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy, - ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z, - const ovutils::eDest& dest, - overlay::Rotator **rot); - -//Routine to configure high resolution panels (> 2048 width) -int configureSplit(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy, - ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z, - const ovutils::eDest& lDest, - const ovutils::eDest& rDest, overlay::Rotator **rot); - -//Routine to split and configure high resolution YUV layer (> 2048 width) -int configureSourceSplit(hwc_context_t *ctx, hwc_layer_1_t *layer, - const int& dpy, - ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z, - const ovutils::eDest& lDest, - const ovutils::eDest& rDest, overlay::Rotator **rot); - -//On certain targets DMA pipes are used for rotation and they won't be available -//for line operations. On a per-target basis we can restrict certain use cases -//from using rotator, since we know before-hand that such scenarios can lead to -//extreme unavailability of pipes. This can also be done via hybrid calculations -//also involving many more variables like number of write-back interfaces etc, -//but the variety of scenarios is too high to warrant that. -bool canUseRotator(hwc_context_t *ctx, int dpy); - -int getLeftSplit(hwc_context_t *ctx, const int& dpy); - -bool isDisplaySplit(hwc_context_t* ctx, int dpy); - -int getRotDownscale(hwc_context_t *ctx, const hwc_layer_1_t *layer); - -// Set the GPU hint flag to high for MIXED/GPU composition only for -// first frame after MDP to GPU/MIXED mode transition. -// Set the GPU hint to default if the current composition type is GPU -// due to idle fallback or MDP composition. -void setGPUHint(hwc_context_t* ctx, hwc_display_contents_1_t* list); - -bool loadEglLib(hwc_context_t* ctx); - -// Returns true if rect1 is peripheral to rect2, false otherwise. -bool isPeripheral(const hwc_rect_t& rect1, const hwc_rect_t& rect2); - -// Checks if boot animation has completed and applies default mode -void processBootAnimCompleted(hwc_context_t *ctx); - -// Inline utility functions -static inline bool isSkipLayer(const hwc_layer_1_t* l) { - return (UNLIKELY(l && (l->flags & HWC_SKIP_LAYER))); -} - -static inline bool isAIVVideoLayer(const hwc_layer_1_t* l) { - return (UNLIKELY(l && (l->flags & HWC_AIV_VIDEO))); -} - -static inline bool isAIVCCLayer(const hwc_layer_1_t* l) { - return (UNLIKELY(l && (l->flags & HWC_AIV_CC))); -} - -// Returns true if the buffer is yuv -static inline bool isYuvBuffer(const private_handle_t* hnd) { - return (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO)); -} - -// Returns true if the buffer is yuv and exceeds the mixer width -static inline bool isYUVSplitNeeded(const private_handle_t* hnd) { - int maxMixerWidth = qdutils::MDPVersion::getInstance().getMaxMixerWidth(); - return (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO) && - (hnd->width > maxMixerWidth)); -} - -// Returns true if the buffer is secure -static inline bool isSecureBuffer(const private_handle_t* hnd) { - return (hnd && (private_handle_t::PRIV_FLAGS_SECURE_BUFFER & hnd->flags)); -} - -static inline bool isTileRendered(const private_handle_t* hnd) { - return (hnd && (private_handle_t::PRIV_FLAGS_TILE_RENDERED & hnd->flags)); -} - -static inline bool isCPURendered(const private_handle_t* hnd) { - return (hnd && (private_handle_t::PRIV_FLAGS_CPU_RENDERED & hnd->flags)); -} - -//Return true if the buffer is intended for Secure Display -static inline bool isSecureDisplayBuffer(const private_handle_t* hnd) { - return (hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY)); -} - -static inline int getWidth(const private_handle_t* hnd) { - MetaData_t *metadata = reinterpret_cast<MetaData_t*>(hnd->base_metadata); - if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) { - return metadata->bufferDim.sliceWidth; - } - return hnd->width; -} - -static inline int getHeight(const private_handle_t* hnd) { - MetaData_t *metadata = reinterpret_cast<MetaData_t*>(hnd->base_metadata); - if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) { - return metadata->bufferDim.sliceHeight; - } - return hnd->height; -} - -template<typename T> inline T max(T a, T b) { return (a > b) ? a : b; } -template<typename T> inline T min(T a, T b) { return (a < b) ? a : b; } - -// Initialize uevent thread -void init_uevent_thread(hwc_context_t* ctx); -// Initialize vsync thread -void init_vsync_thread(hwc_context_t* ctx); - -inline void getLayerResolution(const hwc_layer_1_t* layer, - int& width, int& height) { - hwc_rect_t displayFrame = layer->displayFrame; - width = displayFrame.right - displayFrame.left; - height = displayFrame.bottom - displayFrame.top; -} - -static inline int openFb(int dpy) { - int fd = -1; - const char *devtmpl = "/dev/graphics/fb%u"; - char name[64] = {0}; - snprintf(name, 64, devtmpl, dpy); - fd = open(name, O_RDWR); - return fd; -} - -template <class T> -inline void swap(T& a, T& b) { - T tmp = a; - a = b; - b = tmp; -} - -}; //qhwc namespace - -enum eAnimationState{ - ANIMATION_STOPPED, - ANIMATION_STARTED, -}; - -enum eCompositionState { - COMPOSITION_STATE_MDP = 0, // Set if composition type is MDP - COMPOSITION_STATE_GPU, // Set if composition type is GPU or MIXED - COMPOSITION_STATE_IDLE_FALLBACK, // Set if it is idlefallback -}; - -// Structure holds the information about the GPU hint. -struct gpu_hint_info { - // system level flag to enable gpu_perf_mode - bool mGpuPerfModeEnable; - // Stores the current GPU performance mode DEFAULT/HIGH - uint32_t mCurrGPUPerfMode; - // Stores the compositon state GPU, MDP or IDLE_FALLBACK - bool mCompositionState; - // Stores the EGLContext of current process - EGLContext mEGLContext; - // Stores the EGLDisplay of current process - EGLDisplay mEGLDisplay; -}; - -//struct holds the information about libmm-qdcm.so -struct qdcm_info { - qmode::ModeManager *mQdcmMode; - void *mQdcmLib; - bool mBootAnimCompleted; -}; - -// ----------------------------------------------------------------------------- -// HWC context -// This structure contains overall state -struct hwc_context_t { - hwc_composer_device_1_t device; - const hwc_procs_t* proc; - - //CopyBit objects - qhwc::CopyBit *mCopyBit[HWC_NUM_DISPLAY_TYPES]; - - //Overlay object - NULL for non overlay devices - overlay::Overlay *mOverlay; - //Holds a few rot objects - overlay::RotMgr *mRotMgr; - - //Primary and external FB updater - qhwc::IFBUpdate *mFBUpdate[HWC_NUM_DISPLAY_TYPES]; - // HDMI display related object. Used to configure/teardown - // HDMI when it is connected as primary or external. - qhwc::HDMIDisplay *mHDMIDisplay; - qhwc::MDPInfo mMDP; - qhwc::VsyncState vstate; - qhwc::DisplayAttributes dpyAttr[HWC_NUM_DISPLAY_TYPES]; - qhwc::ListStats listStats[HWC_NUM_DISPLAY_TYPES]; - qhwc::LayerProp *layerProp[HWC_NUM_DISPLAY_TYPES]; - qhwc::MDPComp *mMDPComp[HWC_NUM_DISPLAY_TYPES]; - qhwc::HwcDebug *mHwcDebug[HWC_NUM_DISPLAY_TYPES]; - hwc_rect_t mViewFrame[HWC_NUM_DISPLAY_TYPES]; - qhwc::AssertiveDisplay *mAD; - eAnimationState mAnimationState[HWC_NUM_DISPLAY_TYPES]; - qhwc::HWCVirtualVDS *mHWCVirtual; - - // stores the #numHwLayers of the previous frame - // for each display device - int mPrevHwLayerCount[HWC_NUM_DISPLAY_TYPES]; - - // stores the primary device orientation - int deviceOrientation; - //Securing in progress indicator - bool mSecuring; - //Display in secure mode indicator - bool mSecureMode; - //Lock to protect drawing data structures - mutable Locker mDrawLock; - //Drawing round when we use GPU - bool isPaddingRound; - // External Orientation - int mExtOrientation; - //Flags the transition of a video session - bool mVideoTransFlag; - //Used for SideSync feature - //which overrides the mExtOrientation - bool mBufferMirrorMode; - // Used to synchronize between WFD and Display modules - mutable Locker mWfdSyncLock; - - qhwc::LayerRotMap *mLayerRotMap[HWC_NUM_DISPLAY_TYPES]; - // Panel reset flag will be set if BTA check fails - bool mPanelResetStatus; - // number of active Displays - int numActiveDisplays; -#ifdef QTI_BSP - void *mEglLib; - EGLBoolean (*mpfn_eglGpuPerfHintQCOM)(EGLDisplay, EGLContext, EGLint *); - EGLDisplay (*mpfn_eglGetCurrentDisplay)(); - EGLContext (*mpfn_eglGetCurrentContext)(); - struct gpu_hint_info mGPUHintInfo; -#endif - //App Buffer Composition - bool enableABC; - // PTOR Info - qhwc::PtorInfo mPtorInfo; - //Running in Thermal burst mode - bool mThermalBurstMode; - //Layers out of ROI - bool copybitDrop[MAX_NUM_APP_LAYERS]; - // Flag related to windowboxing feature - bool mWindowboxFeature; - // This denotes the tolerance between video layer and external display - // aspect ratio - float mAspectRatioToleranceLevel; - //Used to notify that boot has completed - bool mBootAnimCompleted; - // Provides a way for OEM's to disable setting dynfps via metadata. - bool mUseMetaDataRefreshRate; - //struct holds the information about display tuning service library. - struct qdcm_info mQdcmInfo; -}; - -namespace qhwc { -static inline bool isSkipPresent (hwc_context_t *ctx, int dpy) { - return ctx->listStats[dpy].skipCount; -} - -static inline bool isYuvPresent (hwc_context_t *ctx, int dpy) { - return ctx->listStats[dpy].yuvCount; -} - -static inline bool has90Transform(hwc_layer_1_t const* layer) { - return ((layer->transform & HWC_TRANSFORM_ROT_90) && - !(layer->flags & HWC_COLOR_FILL)); -} - -inline bool isSecurePresent(hwc_context_t *ctx, int dpy) { - return ctx->listStats[dpy].isSecurePresent; -} - -static inline bool isSecondaryConfiguring(hwc_context_t* ctx) { - return (ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isConfiguring || - ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isConfiguring); -} - -static inline bool isSecondaryConnected(hwc_context_t* ctx) { - return (ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected || - ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected); -} - -static inline bool isSecondaryAnimating(hwc_context_t* ctx) { - return (ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected && - (!ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isPause) && - ctx->listStats[HWC_DISPLAY_EXTERNAL].isDisplayAnimating) - || - (ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected && - (!ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isPause) && - ctx->listStats[HWC_DISPLAY_VIRTUAL].isDisplayAnimating); -} - -/* Return Virtual Display connection status */ -static inline bool isVDConnected(hwc_context_t* ctx) { - return ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected; -} - -}; - -#endif //HWC_UTILS_H diff --git a/msm8909/libhwcomposer/hwc_virtual.cpp b/msm8909/libhwcomposer/hwc_virtual.cpp deleted file mode 100644 index 2bfb5e73..00000000 --- a/msm8909/libhwcomposer/hwc_virtual.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved. - * - * Not a Contribution, Apache license notifications and license are retained - * for attribution purposes only. - * - * 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 <fcntl.h> -#include <errno.h> - -#include <cutils/log.h> -#include <overlayWriteback.h> -#include "hwc_utils.h" -#include "hwc_fbupdate.h" -#include "hwc_mdpcomp.h" -#include "hwc_dump_layers.h" -#include "hwc_copybit.h" -#include "hwc_virtual.h" -#include "sync/sync.h" -#include <utils/Trace.h> - -#define HWCVIRTUAL_LOG 0 - -using namespace qhwc; -using namespace overlay; - -bool HWCVirtualVDS::sVDDumpEnabled = false; - -void HWCVirtualVDS::init(hwc_context_t *ctx) { - const int dpy = HWC_DISPLAY_VIRTUAL; - mScalingWidth = 0, mScalingHeight = 0; - initCompositionResources(ctx, dpy); - - if(ctx->mFBUpdate[dpy]) - ctx->mFBUpdate[dpy]->reset(); - if(ctx->mMDPComp[dpy]) - ctx->mMDPComp[dpy]->reset(); -} - -void HWCVirtualVDS::destroy(hwc_context_t *ctx, size_t /*numDisplays*/, - hwc_display_contents_1_t** displays) { - int dpy = HWC_DISPLAY_VIRTUAL; - - //Cleanup virtual display objs, since there is no explicit disconnect - if(ctx->dpyAttr[dpy].connected && (displays[dpy] == NULL)) { - ctx->dpyAttr[dpy].connected = false; - ctx->dpyAttr[dpy].isPause = false; - - destroyCompositionResources(ctx, dpy); - - // signal synclock to indicate successful wfd teardown - ctx->mWfdSyncLock.lock(); - ctx->mWfdSyncLock.signal(); - ctx->mWfdSyncLock.unlock(); - } -} - -int HWCVirtualVDS::prepare(hwc_composer_device_1 *dev, - hwc_display_contents_1_t *list) { - ATRACE_CALL(); - //XXX: Fix when framework support is added - hwc_context_t* ctx = (hwc_context_t*)(dev); - const int dpy = HWC_DISPLAY_VIRTUAL; - - if (list && list->outbuf && list->numHwLayers > 0) { - reset_layer_prop(ctx, dpy, (int)list->numHwLayers - 1); - uint32_t last = (uint32_t)list->numHwLayers - 1; - hwc_layer_1_t *fbLayer = &list->hwLayers[last]; - int fbWidth = 0, fbHeight = 0; - getLayerResolution(fbLayer, fbWidth, fbHeight); - ctx->dpyAttr[dpy].xres = fbWidth; - ctx->dpyAttr[dpy].yres = fbHeight; - - if(ctx->dpyAttr[dpy].connected == false) { - ctx->dpyAttr[dpy].connected = true; - ctx->dpyAttr[dpy].isPause = false; - // We set the vsync period to the primary refresh rate, leaving - // it up to the consumer to decide how fast to consume frames. - ctx->dpyAttr[dpy].vsync_period - = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period; - ctx->dpyAttr[dpy].fbformat = HAL_PIXEL_FORMAT_RGBA_8888; - init(ctx); - // Do one padding round for cases where primary has all pipes - // The virtual composition falls back to GPU in such cases. - ctx->isPaddingRound = true; - } - if(!ctx->dpyAttr[dpy].isPause) { - ctx->dpyAttr[dpy].isConfiguring = false; - ctx->dpyAttr[dpy].fd = Writeback::getInstance()->getFbFd(); - private_handle_t *ohnd = (private_handle_t *)list->outbuf; - - setMDPScalingMode(ctx, ohnd, dpy); - - mScalingWidth = getWidth(ohnd); - mScalingHeight = getHeight(ohnd); - - Writeback::getInstance()->configureDpyInfo(mScalingWidth, - mScalingHeight); - setListStats(ctx, list, dpy); - - if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) { - const int fbZ = 0; - if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ)) - { - ctx->mOverlay->clear(dpy); - ctx->mLayerRotMap[dpy]->clear(); - } - } - } else { - /* Virtual Display is in Pause state. - * Mark all application layers as OVERLAY so that - * GPU will not compose. - */ - Writeback::getInstance(); //Ensure that WB is active during pause - for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) { - hwc_layer_1_t *layer = &list->hwLayers[i]; - layer->compositionType = HWC_OVERLAY; - } - } - } - return 0; -} - -int HWCVirtualVDS::set(hwc_context_t *ctx, hwc_display_contents_1_t *list) { - ATRACE_CALL(); - int ret = 0; - const int dpy = HWC_DISPLAY_VIRTUAL; - - if (list && list->outbuf && list->numHwLayers > 0) { - uint32_t last = (uint32_t)list->numHwLayers - 1; - hwc_layer_1_t *fbLayer = &list->hwLayers[last]; - - if(ctx->dpyAttr[dpy].connected - && (!ctx->dpyAttr[dpy].isPause)) - { - private_handle_t *ohnd = (private_handle_t *)list->outbuf; - int format = ohnd->format; - if (format == HAL_PIXEL_FORMAT_RGBA_8888) - format = HAL_PIXEL_FORMAT_RGBX_8888; - Writeback::getInstance()->setOutputFormat( - utils::getMdpFormat(format)); - - // Configure WB secure mode based on output buffer handle - if(! Writeback::getInstance()->setSecure(isSecureBuffer(ohnd))) - { - ALOGE("Failed to set WB secure mode: %d for virtual display", - isSecureBuffer(ohnd)); - return false; - } - - int fd = -1; //FenceFD from the Copybit - hwc_sync(ctx, list, dpy, fd); - - // Dump the layers for virtual - if(ctx->mHwcDebug[dpy]) - ctx->mHwcDebug[dpy]->dumpLayers(list); - - if (!ctx->mMDPComp[dpy]->draw(ctx, list)) { - ALOGE("%s: MDPComp draw failed", __FUNCTION__); - ret = -1; - } - // We need an FB layer handle check to cater for this usecase: - // Video is playing in landscape on primary, then launch - // ScreenRecord app. - // In this scenario, the first VDS draw call will have HWC - // composition and VDS does nit involve GPU to get eglSwapBuffer - // to get valid fb handle. - if (fbLayer->handle && !ctx->mFBUpdate[dpy]->draw(ctx, - (private_handle_t *)fbLayer->handle)) { - ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__); - ret = -1; - } - - Writeback::getInstance()->queueBuffer(ohnd->fd, - (uint32_t)ohnd->offset); - if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) { - ALOGE("%s: display commit fail!", __FUNCTION__); - ret = -1; - } - - if(sVDDumpEnabled) { - char bufferName[128]; - // Dumping frame buffer - sync_wait(fbLayer->acquireFenceFd, 1000); - snprintf(bufferName, sizeof(bufferName), "vds.fb"); - dumpBuffer((private_handle_t *)fbLayer->handle, bufferName); - // Dumping WB output for non-secure session - if(!isSecureBuffer(ohnd)) { - sync_wait(list->retireFenceFd, 1000); - snprintf(bufferName, sizeof(bufferName), "vds.wb"); - dumpBuffer(ohnd, bufferName); - } - } - } else if(list->outbufAcquireFenceFd >= 0) { - //If we dont handle the frame, set retireFenceFd to outbufFenceFd, - //which will make sure, the framework waits on it and closes it. - //The other way is to wait on outbufFenceFd ourselves, close it and - //set retireFenceFd to -1. Since we want hwc to be async, choosing - //the former. - //Also dup because, the closeAcquireFds() will close the outbufFence - list->retireFenceFd = dup(list->outbufAcquireFenceFd); - } - } - - closeAcquireFds(list); - return ret; -} - -/* We set scaling mode on the VD if the output handle width and height - differs from the virtual frame buffer width and height. */ -void HWCVirtualVDS::setMDPScalingMode(hwc_context_t* ctx, - private_handle_t* ohnd, int dpy) { - bool scalingMode = false; - int fbWidth = ctx->dpyAttr[dpy].xres; - int fbHeight = ctx->dpyAttr[dpy].yres; - if((getWidth(ohnd) != fbWidth) || (getHeight(ohnd) != fbHeight)) { - scalingMode = true; - } - ctx->dpyAttr[dpy].mMDPScalingMode = scalingMode; - - ALOGD_IF(HWCVIRTUAL_LOG, "%s fb(%dx%d) outputBuffer(%dx%d) scalingMode=%d", - __FUNCTION__, fbWidth, fbHeight, - getWidth(ohnd), getHeight(ohnd), scalingMode); -} diff --git a/msm8909/libhwcomposer/hwc_virtual.h b/msm8909/libhwcomposer/hwc_virtual.h deleted file mode 100644 index bd1833c5..00000000 --- a/msm8909/libhwcomposer/hwc_virtual.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved. - * - * Not a Contribution, Apache license notifications and license are retained - * for attribution purposes only. - * - * 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_VIRTUAL -#define HWC_VIRTUAL - -#include <hwc_utils.h> - -namespace qhwc { - -class HWCVirtualVDS { -public: - HWCVirtualVDS(){}; - ~HWCVirtualVDS(){}; - // Chooses composition type and configures pipe for each layer in virtual - // display list - int prepare(hwc_composer_device_1 *dev, - hwc_display_contents_1_t* list); - // Queues the buffer for each layer in virtual display list and call display - // commit. - int set(hwc_context_t *ctx, hwc_display_contents_1_t *list); - // instantiates mdpcomp, copybit and fbupdate objects and initialize those - // objects for virtual display during virtual display connect. - void init(hwc_context_t *ctx); - // Destroys mdpcomp, copybit and fbupdate objects and for virtual display - // during virtual display disconnect. - void destroy(hwc_context_t *ctx, size_t numDisplays, - hwc_display_contents_1_t** displays); - int getScalingHeight() const { return mScalingHeight; }; - int getScalingWidth() const { return mScalingWidth; }; - // We can dump the frame buffer and WB - // output buffer by dynamically enabling - // dumping via a binder call: - // adb shell service call display.qservice 15 i32 3 i32 1 - static bool sVDDumpEnabled; - static void dynamicDebug(bool enable) {sVDDumpEnabled = enable;}; - -private: - // These variables store the resolution that WB is being configured to - // in the current draw cycle. - int mScalingWidth, mScalingHeight; - void setMDPScalingMode(hwc_context_t* ctx, - private_handle_t* ohnd, int dpy); -}; - -}; //namespace -#endif diff --git a/msm8909/libhwcomposer/hwc_vsync.cpp b/msm8909/libhwcomposer/hwc_vsync.cpp deleted file mode 100644 index ea3f672d..00000000 --- a/msm8909/libhwcomposer/hwc_vsync.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved. - * - * Not a Contribution, Apache license notifications and license are - * retained for attribution purposes only. - - * 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 <cutils/properties.h> -#include <utils/Log.h> -#include <fcntl.h> -#include <sys/ioctl.h> -#include <linux/msm_mdp.h> -#include <sys/resource.h> -#include <sys/prctl.h> -#include <poll.h> -#include "hwc_utils.h" -#include "hdmi.h" -#include "qd_utils.h" -#include "string.h" -#include "overlay.h" -#include <inttypes.h> - -using namespace qdutils; -namespace qhwc { - -#define HWC_VSYNC_THREAD_NAME "hwcVsyncThread" -#define PANEL_ON_STR "panel_power_on =" -#define ARRAY_LENGTH(array) (sizeof((array))/sizeof((array)[0])) -#define MAX_THERMAL_LEVEL 3 -const int MAX_DATA = 64; - -int hwc_vsync_control(hwc_context_t* ctx, int dpy, int enable) -{ - int ret = 0; - if(!ctx->vstate.fakevsync && - ioctl(ctx->dpyAttr[dpy].fd, MSMFB_OVERLAY_VSYNC_CTRL, - &enable) < 0) { - ALOGE("%s: vsync control failed. Dpy=%d, enable=%d : %s", - __FUNCTION__, dpy, enable, strerror(errno)); - ret = -errno; - } - return ret; -} - -static void handle_vsync_event(hwc_context_t* ctx, int dpy, char *data) -{ - // extract timestamp - uint64_t timestamp = 0; - if (!strncmp(data, "VSYNC=", strlen("VSYNC="))) { - timestamp = strtoull(data + strlen("VSYNC="), NULL, 0); - } - // send timestamp to SurfaceFlinger - ALOGD_IF (ctx->vstate.debug, "%s: timestamp %" PRIu64 " sent to SF for dpy=%d", - __FUNCTION__, timestamp, dpy); - ctx->proc->vsync(ctx->proc, dpy, timestamp); -} - -static void handle_blank_event(hwc_context_t* ctx, int dpy, char *data) -{ - if (!strncmp(data, PANEL_ON_STR, strlen(PANEL_ON_STR))) { - unsigned long int poweron = strtoul(data + strlen(PANEL_ON_STR), NULL, 0); - ALOGI("%s: dpy:%d panel power state: %ld", __FUNCTION__, dpy, poweron); - if (!ctx->mHDMIDisplay->isHDMIPrimaryDisplay()) { - ctx->dpyAttr[dpy].isActive = poweron ? true: false; - } - } -} - -static void handle_thermal_event(hwc_context_t* ctx, int dpy, char *data) -{ - // extract thermal level - uint64_t thermalLevel = 0; - if (!strncmp(data, "thermal_level=", strlen("thermal_level="))) { - thermalLevel = strtoull(data + strlen("thermal_level="), NULL, 0); - } - - if (thermalLevel >= MAX_THERMAL_LEVEL) { - ALOGD("%s: dpy:%d thermal_level=%" PRIu64 "",__FUNCTION__,dpy,thermalLevel); - ctx->mThermalBurstMode = true; - } else - ctx->mThermalBurstMode = false; -} - -struct event { - const char* name; - void (*callback)(hwc_context_t* ctx, int dpy, char *data); -}; - -struct event event_list[] = { - { "vsync_event", handle_vsync_event }, - { "show_blank_event", handle_blank_event }, - { "msm_fb_thermal_level", handle_thermal_event }, -}; - -#define num_events ARRAY_LENGTH(event_list) - -static void *vsync_loop(void *param) -{ - hwc_context_t * ctx = reinterpret_cast<hwc_context_t *>(param); - - char thread_name[64] = HWC_VSYNC_THREAD_NAME; - prctl(PR_SET_NAME, (unsigned long) &thread_name, 0, 0, 0); - struct sched_param sched_param = {0}; - sched_param.sched_priority = 5; - if (sched_setscheduler(gettid(), SCHED_FIFO, &sched_param) != 0) { - ALOGE("Couldn't set SCHED_FIFO for hwc_vsync"); - } - - char vdata[MAX_DATA]; - //Number of physical displays - //We poll on all the nodes. - int num_displays = HWC_NUM_DISPLAY_TYPES - 1; - struct pollfd pfd[num_displays][num_events]; - - char property[PROPERTY_VALUE_MAX]; - if(property_get("debug.hwc.fakevsync", property, NULL) > 0) { - if(atoi(property) == 1) - ctx->vstate.fakevsync = true; - } - - char node_path[MAX_SYSFS_FILE_PATH]; - - for (int dpy = HWC_DISPLAY_PRIMARY; dpy < num_displays; dpy++) { - for(size_t ev = 0; ev < num_events; ev++) { - snprintf(node_path, sizeof(node_path), - "/sys/class/graphics/fb%d/%s", - dpy == HWC_DISPLAY_PRIMARY ? 0 : - overlay::Overlay::getInstance()-> - getFbForDpy(HWC_DISPLAY_EXTERNAL), - event_list[ev].name); - - ALOGI("%s: Reading event %zu for dpy %d from %s", __FUNCTION__, - ev, dpy, node_path); - pfd[dpy][ev].fd = open(node_path, O_RDONLY); - - if (dpy == HWC_DISPLAY_PRIMARY && pfd[dpy][ev].fd < 0) { - // Make sure fb device is opened before starting - // this thread so this never happens. - ALOGE ("%s:unable to open event node for dpy=%d event=%zu, %s", - __FUNCTION__, dpy, ev, strerror(errno)); - if (ev == 0) { - ctx->vstate.fakevsync = true; - //XXX: Blank events don't work with fake vsync, - //but we shouldn't be running on fake vsync anyway. - break; - } - } - - memset(&vdata, '\0', sizeof(vdata)); - // Read once from the fds to clear the first notify - pread(pfd[dpy][ev].fd, vdata , MAX_DATA - 1, 0); - if (pfd[dpy][ev].fd >= 0) - pfd[dpy][ev].events = POLLPRI | POLLERR; - } - } - - if (LIKELY(!ctx->vstate.fakevsync)) { - do { - int err = poll(reinterpret_cast<struct pollfd *>(pfd), - (int)(num_displays * num_events), -1); - if(err > 0) { - for (int dpy = HWC_DISPLAY_PRIMARY; dpy < num_displays; dpy++) { - for(size_t ev = 0; ev < num_events; ev++) { - if (pfd[dpy][ev].revents & POLLPRI) { - // Clear vdata before writing into it - memset(&vdata, '\0', sizeof(vdata)); - ssize_t len = pread(pfd[dpy][ev].fd, vdata, - MAX_DATA - 1, 0); - if (UNLIKELY(len < 0)) { - // If the read was just interrupted - it is not - // a fatal error. Just continue in this case - ALOGE ("%s: Unable to read event:%zu for \ - dpy=%d : %s", - __FUNCTION__, ev, dpy, strerror(errno)); - continue; - } - vdata[len] = '\0'; - event_list[ev].callback(ctx, dpy, vdata); - } - } - } - } else { - ALOGE("%s: poll failed errno: %s", __FUNCTION__, - strerror(errno)); - continue; - } - } while (true); - - } else { - - //Fake vsync is used only when set explicitly through a property or when - //the vsync timestamp node cannot be opened at bootup. There is no - //fallback to fake vsync from the true vsync loop, ever, as the - //condition can easily escape detection. - //Also, fake vsync is delivered only for the primary display. - do { - usleep(16666); - uint64_t timestamp = systemTime(); - ctx->proc->vsync(ctx->proc, HWC_DISPLAY_PRIMARY, timestamp); - - } while (true); - } - - for (int dpy = HWC_DISPLAY_PRIMARY; dpy <= HWC_DISPLAY_EXTERNAL; dpy++ ) { - for( size_t event = 0; event < num_events; event++) { - if(pfd[dpy][event].fd >= 0) - close (pfd[dpy][event].fd); - } - } - - return NULL; -} - -void init_vsync_thread(hwc_context_t* ctx) -{ - int ret; - pthread_t vsync_thread; - ALOGI("Initializing VSYNC Thread"); - ret = pthread_create(&vsync_thread, NULL, vsync_loop, (void*) ctx); - if (ret) { - ALOGE("%s: failed to create %s: %s", __FUNCTION__, - HWC_VSYNC_THREAD_NAME, strerror(ret)); - } -} - -}; //namespace diff --git a/msm8909/liblight/Android.mk b/msm8909/liblight/Android.mk index 9458a51b..bbb076f0 100644 --- a/msm8909/liblight/Android.mk +++ b/msm8909/liblight/Android.mk @@ -13,19 +13,21 @@ # limitations under the License. LOCAL_PATH:= $(call my-dir) -include $(LOCAL_PATH)/../common.mk # HAL module implemenation stored in # hw/<COPYPIX_HARDWARE_MODULE_ID>.<ro.board.platform>.so include $(CLEAR_VARS) -LOCAL_SRC_FILES := lights.c +LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/common/inc +LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/qdcm/inc + +LOCAL_SRC_FILES := lights.c lights_prv.cpp LOCAL_MODULE_RELATIVE_PATH := hw -LOCAL_PROPRIETARY_MODULE := true -LOCAL_SHARED_LIBRARIES := liblog -LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdlights\" +LOCAL_SHARED_LIBRARIES := liblog libcutils libsdm-disp-vndapis +LOCAL_HEADER_LIBRARIES := libhardware_headers +LOCAL_CFLAGS := -DLOG_TAG=\"qdlights\" LOCAL_CLANG := true LOCAL_MODULE := lights.$(TARGET_BOARD_PLATFORM) LOCAL_MODULE_TAGS := optional -LOCAL_CFLAGS += -Wno-error +LOCAL_VENDOR_MODULE := true include $(BUILD_SHARED_LIBRARY) diff --git a/msm8909/liblight/lights.c b/msm8909/liblight/lights.c index cf24d501..eed6a250 100644 --- a/msm8909/liblight/lights.c +++ b/msm8909/liblight/lights.c @@ -1,6 +1,7 @@ /* + * Copyright (C) 2014, 2017 The Linux Foundation. All rights reserved. + * Not a contribution * Copyright (C) 2008 The Android Open Source Project - * Copyright (C) 2014 The Linux Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,8 +19,8 @@ // #define LOG_NDEBUG 0 -#include <cutils/log.h> - +#include <log/log.h> +#include <cutils/properties.h> #include <stdint.h> #include <stdlib.h> #include <string.h> @@ -32,6 +33,11 @@ #include <sys/types.h> #include <hardware/lights.h> +#include "lights_prv.h" + +#ifndef DEFAULT_LOW_PERSISTENCE_MODE_BRIGHTNESS +#define DEFAULT_LOW_PERSISTENCE_MODE_BRIGHTNESS 0x80 +#endif /******************************************************************************/ @@ -39,7 +45,9 @@ static pthread_once_t g_init = PTHREAD_ONCE_INIT; static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER; static struct light_state_t g_notification; static struct light_state_t g_battery; +static int g_last_backlight_mode = BRIGHTNESS_MODE_USER; static int g_attention = 0; +static int g_brightness_max = 0; char const*const RED_LED_FILE = "/sys/class/leds/red/brightness"; @@ -50,12 +58,12 @@ char const*const GREEN_LED_FILE char const*const BLUE_LED_FILE = "/sys/class/leds/blue/brightness"; -char const*const BLUETOOTH_LED_FILE - = "/sys/class/leds/bt/brightness"; - char const*const LCD_FILE = "/sys/class/leds/lcd-backlight/brightness"; +char const*const LCD_FILE2 + = "/sys/class/backlight/panel0-backlight/brightness"; + char const*const BUTTON_FILE = "/sys/class/leds/button-backlight/brightness"; @@ -68,6 +76,9 @@ char const*const GREEN_BLINK_FILE char const*const BLUE_BLINK_FILE = "/sys/class/leds/blue/blink"; +char const*const PERSISTENCE_FILE + = "/sys/class/graphics/fb0/msm_fb_persist_mode"; + /** * device methods */ @@ -120,12 +131,59 @@ set_light_backlight(struct light_device_t* dev, { int err = 0; int brightness = rgb_to_brightness(state); + unsigned int lpEnabled = + state->brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE; + if(!dev) { + return -1; + } + + pthread_mutex_lock(&g_lock); + // Toggle low persistence mode state + if ((g_last_backlight_mode != state->brightnessMode && lpEnabled) || + (!lpEnabled && + g_last_backlight_mode == BRIGHTNESS_MODE_LOW_PERSISTENCE)) { + if ((err = write_int(PERSISTENCE_FILE, lpEnabled)) != 0) { + ALOGE("%s: Failed to write to %s: %s\n", __FUNCTION__, + PERSISTENCE_FILE, strerror(errno)); + } + if (lpEnabled != 0) { + brightness = DEFAULT_LOW_PERSISTENCE_MODE_BRIGHTNESS; + } + } + + g_last_backlight_mode = state->brightnessMode; + + if (!err) { + if (!access(LCD_FILE, F_OK)) { + err = write_int(LCD_FILE, brightness); + } else { + err = write_int(LCD_FILE2, brightness); + } + } + + pthread_mutex_unlock(&g_lock); + return err; +} + +static int +set_light_backlight_ext(struct light_device_t* dev, + struct light_state_t const* state) +{ + int err = 0; + if(!dev) { return -1; } + + int brightness = state->color & 0x00ffffff; pthread_mutex_lock(&g_lock); - err = write_int(LCD_FILE, brightness); + + if (brightness >= 0 && brightness <= g_brightness_max) { + set_brightness_ext_level(brightness); + } + pthread_mutex_unlock(&g_lock); + return err; } @@ -184,15 +242,15 @@ set_speaker_light_locked(struct light_device_t* dev, if (red) { if (write_int(RED_BLINK_FILE, blink)) write_int(RED_LED_FILE, 0); - } + } if (green) { if (write_int(GREEN_BLINK_FILE, blink)) write_int(GREEN_LED_FILE, 0); - } + } if (blue) { if (write_int(BLUE_BLINK_FILE, blink)) write_int(BLUE_LED_FILE, 0); - } + } } else { write_int(RED_LED_FILE, red); write_int(GREEN_LED_FILE, green); @@ -263,20 +321,6 @@ set_light_buttons(struct light_device_t* dev, return err; } -static int -set_light_bluetooth(struct light_device_t* dev, - struct light_state_t const* state) -{ - int err = 0; - if(!dev) { - return -1; - } - pthread_mutex_lock(&g_lock); - err = write_int(BLUETOOTH_LED_FILE, state->color & 0xFF); - pthread_mutex_unlock(&g_lock); - return err; -} - /** Close the lights device */ static int close_lights(struct light_device_t *dev) @@ -301,18 +345,32 @@ static int open_lights(const struct hw_module_t* module, char const* name, int (*set_light)(struct light_device_t* dev, struct light_state_t const* state); - if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)) - set_light = set_light_backlight; - else if (0 == strcmp(LIGHT_ID_BATTERY, name)) + if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)) { + char property[PROPERTY_VALUE_MAX]; + property_get("persist.extend.brightness", property, "0"); + + if(!(strncmp(property, "1", PROPERTY_VALUE_MAX)) || + !(strncmp(property, "true", PROPERTY_VALUE_MAX))) { + property_get("persist.display.max_brightness", property, "255"); + g_brightness_max = atoi(property); + set_brightness_ext_init(); + set_light = set_light_backlight_ext; + } else + set_light = set_light_backlight; + } else if (0 == strcmp(LIGHT_ID_BATTERY, name)) set_light = set_light_battery; else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) set_light = set_light_notifications; - else if (0 == strcmp(LIGHT_ID_BUTTONS, name)) - set_light = set_light_buttons; + else if (0 == strcmp(LIGHT_ID_BUTTONS, name)) { + if (!access(BUTTON_FILE, F_OK)) { + // enable light button when the file is present + set_light = set_light_buttons; + } else { + return -EINVAL; + } + } else if (0 == strcmp(LIGHT_ID_ATTENTION, name)) set_light = set_light_attention; - else if (0 == strcmp(LIGHT_ID_BLUETOOTH, name)) - set_light = set_light_bluetooth; else return -EINVAL; @@ -326,7 +384,7 @@ static int open_lights(const struct hw_module_t* module, char const* name, memset(dev, 0, sizeof(*dev)); dev->common.tag = HARDWARE_DEVICE_TAG; - dev->common.version = 0; + dev->common.version = LIGHTS_DEVICE_API_VERSION_2_0; dev->common.module = (struct hw_module_t*)module; dev->common.close = (int (*)(struct hw_device_t*))close_lights; dev->set_light = set_light; diff --git a/msm8909/libhwcomposer/hwc_qclient.h b/msm8909/liblight/lights_prv.cpp index d9553773..f916ed2f 100644 --- a/msm8909/libhwcomposer/hwc_qclient.h +++ b/msm8909/liblight/lights_prv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2017, 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 @@ -20,48 +20,35 @@ * 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 CLIENTS; LOSS OF USE, DATA, OR PROFITS; OR + * 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 ANDROID_QCLIENT_H -#define ANDROID_QCLIENT_H -#include <utils/Errors.h> -#include <sys/types.h> -#include <cutils/log.h> -#include <binder/IServiceManager.h> -#include <media/IMediaDeathNotifier.h> -#include <IQClient.h> -struct hwc_context_t; +#include <hardware/hwcomposer_defs.h> +#include "disp_color_apis.h" +#include "lights_prv.h" -class Params; -namespace qClient { -// ---------------------------------------------------------------------------- +/******************************************************************************/ +static DISPAPI_HANDLE g_ctx; -class QClient : public BnQClient { -public: - QClient(hwc_context_t *ctx); - virtual ~QClient(); - virtual android::status_t notifyCallback(uint32_t command, - const android::Parcel* inParcel, - android::Parcel* outParcel); +/** + * device methods + */ + +void set_brightness_ext_init(void) +{ + disp_api_init((DISPAPI_HANDLE*) &g_ctx, 0); +} -private: - //Notifies of Media Player death - class MPDeathNotifier : public android::IMediaDeathNotifier { - public: - MPDeathNotifier(hwc_context_t* ctx) : mHwcContext(ctx){} - virtual void died(); - hwc_context_t *mHwcContext; - }; +int set_brightness_ext_level(int level) +{ + int err = disp_api_set_panel_brightness_level_ext(g_ctx, HWC_DISPLAY_PRIMARY, + level, 0); - hwc_context_t *mHwcContext; - const android::sp<android::IMediaDeathNotifier> mMPDeathNotifier; -}; -}; // namespace qClient -#endif // ANDROID_QCLIENT_H + return err; +} diff --git a/msm8909/libhwcomposer/hwc_qdcm_legacy.cpp b/msm8909/liblight/lights_prv.h index f9ce09fd..e0ec7362 100644 --- a/msm8909/libhwcomposer/hwc_qdcm_legacy.cpp +++ b/msm8909/liblight/lights_prv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014,2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2017, 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 @@ -27,53 +27,17 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <hwc_qdcm.h> -#include <hwc_utils.h> -#include <IQService.h> -#include <mdp_version.h> -#include <dlfcn.h> +#ifndef LIGHTS_PRV_H +#define LIGHTS_PRV_H -using namespace android; -using namespace qService; -using namespace qhwc; +#ifdef __cplusplus +extern "C" { +#endif -namespace qQdcm { -//---------------------------------------------------------------------------- -void qdcmInitContext(hwc_context_t* /*ctx*/) -{ -} +extern void set_brightness_ext_init(void); +extern int set_brightness_ext_level(int level); -void qdcmCloseContext(hwc_context_t* /*ctx*/) -{ +#ifdef __cplusplus } - -void qdcmApplyDefaultAfterBootAnimationDone(hwc_context_t* /*ctx*/) -{ - int ret = 0; - int (*applyMode)(int) = NULL; - void *modeHandle = NULL; - - modeHandle = dlopen("libmm-qdcm.so", RTLD_NOW); - if (modeHandle) { - *(void **)&applyMode = dlsym(modeHandle, "applyDefaults"); - if (applyMode) { - ret = applyMode(HWC_DISPLAY_PRIMARY); - if (ret) - ALOGE("%s: Not able to apply default mode", __FUNCTION__); - } else { - ALOGE("%s: No symbol applyDefaults found", __FUNCTION__); - } - dlclose(modeHandle); - } else { - ALOGE("%s: Not able to load libmm-qdcm.so", __FUNCTION__); - } -} - -//do nothing in case qdcm legacy implementation. -void qdcmCmdsHandler(hwc_context_t* /*ctx*/, const Parcel* /*in*/, Parcel* /*out*/) -{ -} - - -} //namespace qQdcm - +#endif +#endif diff --git a/msm8909/libmemtrack/Android.mk b/msm8909/libmemtrack/Android.mk index a73cfd75..10fd40a9 100644 --- a/msm8909/libmemtrack/Android.mk +++ b/msm8909/libmemtrack/Android.mk @@ -19,12 +19,12 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_RELATIVE_PATH := hw -LOCAL_PROPRIETARY_MODULE := true +LOCAL_VENDOR_MODULE := true LOCAL_C_INCLUDES += hardware/libhardware/include LOCAL_CFLAGS := -Wconversion -Wall -Werror -Wno-sign-conversion LOCAL_CLANG := true LOCAL_SHARED_LIBRARIES := liblog +LOCAL_HEADER_LIBRARIES := libhardware_headers LOCAL_SRC_FILES := memtrack_msm.c kgsl.c LOCAL_MODULE := memtrack.$(TARGET_BOARD_PLATFORM) -LOCAL_CFLAGS += -Wno-error include $(BUILD_SHARED_LIBRARY) diff --git a/msm8909/libmemtrack/kgsl.c b/msm8909/libmemtrack/kgsl.c index ce6a035f..69ee9018 100644 --- a/msm8909/libmemtrack/kgsl.c +++ b/msm8909/libmemtrack/kgsl.c @@ -74,7 +74,7 @@ int kgsl_memtrack_get_memory(pid_t pid, enum memtrack_type type, while (1) { unsigned long size, mapsize; char line_type[7]; - char flags[8]; + char flags[10]; char line_usage[19]; int ret, egl_surface_count = 0, egl_image_count = 0; @@ -83,12 +83,12 @@ int kgsl_memtrack_get_memory(pid_t pid, enum memtrack_type type, } /* Format: - * gpuaddr useraddr size id flags type usage sglen mapsize egLsrf egLimg - * 545ba000 545ba000 4096 1 -----pY gpumem arraybuffer 1 4096 0 0 + * gpuaddr useraddr size id flags type usage sglen mapsize eglsrf eglimg + * 545ba000 545ba000 4096 1 -----pY gpumem arraybuffer 1 4096 0 0 */ - ret = sscanf(line, "%*x %*x %lu %*d %6s %6s %18s %*d %lu %6d %6d\n", - &size, flags, line_type, line_usage, &mapsize, - &egl_surface_count, &egl_image_count); + ret = sscanf(line, "%*x %*x %lu %*d %9s %6s %18s %*d %lu %6d %6d\n", + &size, flags, line_type, line_usage, &mapsize, + &egl_surface_count, &egl_image_count); if (ret != 7) { continue; } @@ -110,6 +110,7 @@ int kgsl_memtrack_get_memory(pid_t pid, enum memtrack_type type, fclose(fp); return -ERANGE; } + accounted_size += mapsize; if (mapsize > size) { diff --git a/msm8909/liboverlay/Android.mk b/msm8909/liboverlay/Android.mk deleted file mode 100644 index 5c59d0f9..00000000 --- a/msm8909/liboverlay/Android.mk +++ /dev/null @@ -1,23 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(LOCAL_PATH)/../common.mk -include $(CLEAR_VARS) - -LOCAL_MODULE := liboverlay -LOCAL_MODULE_TAGS := optional -LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes) -LOCAL_SHARED_LIBRARIES := $(common_libs) libqdutils libmemalloc \ - libsync libdl -LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdoverlay\" -LOCAL_CLANG := $(common_clang_flags) -LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) -LOCAL_SRC_FILES := \ - overlay.cpp \ - overlayUtils.cpp \ - overlayMdp.cpp \ - overlayRotator.cpp \ - overlayMdpRot.cpp \ - overlayMdssRot.cpp \ - overlayWriteback.cpp \ - pipes/overlayGenPipe.cpp - -include $(BUILD_SHARED_LIBRARY) diff --git a/msm8909/liboverlay/mdpWrapper.h b/msm8909/liboverlay/mdpWrapper.h deleted file mode 100644 index f689e45f..00000000 --- a/msm8909/liboverlay/mdpWrapper.h +++ /dev/null @@ -1,388 +0,0 @@ -/* -* Copyright (c) 2011, 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 MDP_WRAPPER_H -#define MDP_WRAPPER_H - -#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL) - -/* -* In order to make overlay::mdp_wrapper shorter, please do something like: -* namespace mdpwrap = overlay::mdp_wrapper; -* */ - -#include <linux/msm_mdp.h> -#include <linux/msm_rotator.h> -#include <sys/ioctl.h> -#include <utils/Log.h> -#include <utils/Trace.h> -#include <errno.h> -#include "overlayUtils.h" -#include "overlay.h" - -#define IOCTL_DEBUG 0 -#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) -#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) - -namespace overlay{ - -namespace mdp_wrapper{ -/* FBIOGET_FSCREENINFO */ -bool getFScreenInfo(int fd, fb_fix_screeninfo& finfo); - -/* FBIOGET_VSCREENINFO */ -bool getVScreenInfo(int fd, fb_var_screeninfo& vinfo); - -/* FBIOPUT_VSCREENINFO */ -bool setVScreenInfo(int fd, fb_var_screeninfo& vinfo); - -/* MSM_ROTATOR_IOCTL_START */ -bool startRotator(int fd, msm_rotator_img_info& rot); - -/* MSM_ROTATOR_IOCTL_ROTATE */ -bool rotate(int fd, msm_rotator_data_info& rot); - -/* MSMFB_OVERLAY_SET */ -bool setOverlay(int fd, mdp_overlay& ov); - -/* MSMFB_OVERLAY_PREPARE */ -int validateAndSet(const int& fd, mdp_overlay_list& list); - -/* MSM_ROTATOR_IOCTL_FINISH */ -bool endRotator(int fd, int sessionId); - -/* MSMFB_OVERLAY_UNSET */ -bool unsetOverlay(int fd, int ovId); - -/* MSMFB_OVERLAY_GET */ -bool getOverlay(int fd, mdp_overlay& ov); - -/* MSMFB_OVERLAY_PLAY */ -bool play(int fd, msmfb_overlay_data& od); - -/* MSMFB_DISPLAY_COMMIT */ -bool displayCommit(int fd); - -/* MSMFB_WRITEBACK_INIT, MSMFB_WRITEBACK_START */ -bool wbInitStart(int fbfd); - -/* MSMFB_WRITEBACK_STOP, MSMFB_WRITEBACK_TERMINATE */ -bool wbStopTerminate(int fbfd); - -/* MSMFB_WRITEBACK_QUEUE_BUFFER */ -bool wbQueueBuffer(int fbfd, struct msmfb_data& fbData); - -/* MSMFB_WRITEBACK_DEQUEUE_BUFFER */ -bool wbDequeueBuffer(int fbfd, struct msmfb_data& fbData); - -/* the following are helper functions for dumping - * msm_mdp and friends*/ -void dump(const char* const s, const msmfb_overlay_data& ov); -void dump(const char* const s, const msmfb_data& ov); -void dump(const char* const s, const mdp_overlay& ov); -void dump(const char* const s, const uint32_t u[], uint32_t cnt); -void dump(const char* const s, const msmfb_img& ov); -void dump(const char* const s, const mdp_rect& ov); - -/* and rotator */ -void dump(const char* const s, const msm_rotator_img_info& rot); -void dump(const char* const s, const msm_rotator_data_info& rot); - -/* info */ -void dump(const char* const s, const fb_fix_screeninfo& finfo); -void dump(const char* const s, const fb_var_screeninfo& vinfo); - -//---------------Inlines ------------------------------------- - -inline bool getFScreenInfo(int fd, fb_fix_screeninfo& finfo) { - ATRACE_CALL(); - if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) < 0) { - ALOGE("Failed to call ioctl FBIOGET_FSCREENINFO err=%s", - strerror(errno)); - return false; - } - return true; -} - -inline bool getVScreenInfo(int fd, fb_var_screeninfo& vinfo) { - ATRACE_CALL(); - if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) < 0) { - ALOGE("Failed to call ioctl FBIOGET_VSCREENINFO err=%s", - strerror(errno)); - return false; - } - return true; -} - -inline bool setVScreenInfo(int fd, fb_var_screeninfo& vinfo) { - ATRACE_CALL(); - if (ioctl(fd, FBIOPUT_VSCREENINFO, &vinfo) < 0) { - ALOGE("Failed to call ioctl FBIOPUT_VSCREENINFO err=%s", - strerror(errno)); - return false; - } - return true; -} - -inline bool startRotator(int fd, msm_rotator_img_info& rot) { - ATRACE_CALL(); - if (ioctl(fd, MSM_ROTATOR_IOCTL_START, &rot) < 0){ - ALOGE("Failed to call ioctl MSM_ROTATOR_IOCTL_START err=%s", - strerror(errno)); - return false; - } - return true; -} - -inline bool rotate(int fd, msm_rotator_data_info& rot) { - ATRACE_CALL(); - if (ioctl(fd, MSM_ROTATOR_IOCTL_ROTATE, &rot) < 0) { - ALOGE("Failed to call ioctl MSM_ROTATOR_IOCTL_ROTATE err=%s", - strerror(errno)); - return false; - } - return true; -} - -inline bool setOverlay(int fd, mdp_overlay& ov) { - ATRACE_CALL(); - if (ioctl(fd, MSMFB_OVERLAY_SET, &ov) < 0) { - ALOGE("Failed to call ioctl MSMFB_OVERLAY_SET err=%s", - strerror(errno)); - return false; - } - return true; -} - -inline int validateAndSet(const int& fd, mdp_overlay_list& list) { - ATRACE_CALL(); - uint32_t id = 0; - if(UNLIKELY(Overlay::isDebugPipeLifecycle())) { - for(uint32_t i = 0; i < list.num_overlays; i++) { - if(list.overlay_list[i]->id != (uint32_t)MSMFB_NEW_REQUEST) { - id |= list.overlay_list[i]->id; - } - } - - ALOGD("%s Total pipes needed: %d, Exisiting pipe mask 0x%04x", - __FUNCTION__, list.num_overlays, id); - id = 0; - } - - if (ioctl(fd, MSMFB_OVERLAY_PREPARE, &list) < 0) { - ALOGD_IF(IOCTL_DEBUG, "Failed to call ioctl MSMFB_OVERLAY_PREPARE " - "err=%s", strerror(errno)); - return errno; - } - - if(UNLIKELY(Overlay::isDebugPipeLifecycle())) { - for(uint32_t i = 0; i < list.num_overlays; i++) { - id |= list.overlay_list[i]->id; - } - - ALOGD("%s Pipe mask after OVERLAY_PREPARE 0x%04x", __FUNCTION__, id); - } - - return 0; -} - -inline bool endRotator(int fd, uint32_t sessionId) { - ATRACE_CALL(); - if (ioctl(fd, MSM_ROTATOR_IOCTL_FINISH, &sessionId) < 0) { - ALOGE("Failed to call ioctl MSM_ROTATOR_IOCTL_FINISH err=%s", - strerror(errno)); - return false; - } - return true; -} - -inline bool unsetOverlay(int fd, int ovId) { - ATRACE_CALL(); - ALOGD_IF(Overlay::isDebugPipeLifecycle(), "%s Unsetting pipe 0x%04x", - __FUNCTION__, ovId); - - if (ioctl(fd, MSMFB_OVERLAY_UNSET, &ovId) < 0) { - ALOGE("Failed to call ioctl MSMFB_OVERLAY_UNSET err=%s", - strerror(errno)); - return false; - } - return true; -} - -inline bool getOverlay(int fd, mdp_overlay& ov) { - ATRACE_CALL(); - if (ioctl(fd, MSMFB_OVERLAY_GET, &ov) < 0) { - ALOGE("Failed to call ioctl MSMFB_OVERLAY_GET err=%s", - strerror(errno)); - return false; - } - return true; -} - -inline bool play(int fd, msmfb_overlay_data& od) { - ATRACE_CALL(); - if (ioctl(fd, MSMFB_OVERLAY_PLAY, &od) < 0) { - ALOGE("Failed to call ioctl MSMFB_OVERLAY_PLAY err=%s", - strerror(errno)); - return false; - } - return true; -} - -inline bool displayCommit(int fd, mdp_display_commit& info) { - ATRACE_CALL(); - ALOGD_IF(Overlay::isDebugPipeLifecycle(), "%s", __FUNCTION__); - - if(ioctl(fd, MSMFB_DISPLAY_COMMIT, &info) == -1) { - ALOGE("Failed to call ioctl MSMFB_DISPLAY_COMMIT err=%s", - strerror(errno)); - return false; - } - return true; -} - -inline bool wbInitStart(int fbfd) { - ATRACE_CALL(); - if(ioctl(fbfd, MSMFB_WRITEBACK_INIT, NULL) < 0) { - ALOGE("Failed to call ioctl MSMFB_WRITEBACK_INIT err=%s", - strerror(errno)); - return false; - } - if(ioctl(fbfd, MSMFB_WRITEBACK_START, NULL) < 0) { - ALOGE("Failed to call ioctl MSMFB_WRITEBACK_START err=%s", - strerror(errno)); - return false; - } - return true; -} - -inline bool wbStopTerminate(int fbfd) { - ATRACE_CALL(); - if(ioctl(fbfd, MSMFB_WRITEBACK_STOP, NULL) < 0) { - ALOGE("Failed to call ioctl MSMFB_WRITEBACK_STOP err=%s", - strerror(errno)); - return false; - } - if(ioctl(fbfd, MSMFB_WRITEBACK_TERMINATE, NULL) < 0) { - ALOGE("Failed to call ioctl MSMFB_WRITEBACK_TERMINATE err=%s", - strerror(errno)); - return false; - } - return true; -} - -inline bool wbQueueBuffer(int fbfd, struct msmfb_data& fbData) { - ATRACE_CALL(); - if(ioctl(fbfd, MSMFB_WRITEBACK_QUEUE_BUFFER, &fbData) < 0) { - ALOGE("Failed to call ioctl MSMFB_WRITEBACK_QUEUE_BUFFER err=%s", - strerror(errno)); - return false; - } - return true; -} - -inline bool wbDequeueBuffer(int fbfd, struct msmfb_data& fbData) { - ATRACE_CALL(); - if(ioctl(fbfd, MSMFB_WRITEBACK_DEQUEUE_BUFFER, &fbData) < 0) { - ALOGE("Failed to call ioctl MSMFB_WRITEBACK_DEQUEUE_BUFFER err=%s", - strerror(errno)); - return false; - } - return true; -} - -/* dump funcs */ -inline void dump(const char* const s, const msmfb_overlay_data& ov) { - ALOGE("%s msmfb_overlay_data id=%d", - s, ov.id); - dump("data", ov.data); -} -inline void dump(const char* const s, const msmfb_data& ov) { - ALOGE("%s msmfb_data offset=%d memid=%d id=%d flags=0x%x priv=%d", - s, ov.offset, ov.memory_id, ov.id, ov.flags, ov.priv); -} -inline void dump(const char* const s, const mdp_overlay& ov) { - ALOGE("%s mdp_overlay z=%d alpha=%d mask=%d flags=0x%x id=%d", - s, ov.z_order, ov.alpha, - ov.transp_mask, ov.flags, ov.id); - dump("src", ov.src); - dump("src_rect", ov.src_rect); - dump("dst_rect", ov.dst_rect); - /* - Commented off to prevent verbose logging, since user_data could have 8 or so - fields which are mostly 0 - dump("user_data", ov.user_data, - sizeof(ov.user_data)/sizeof(ov.user_data[0])); - */ -} -inline void dump(const char* const s, const msmfb_img& ov) { - ALOGE("%s msmfb_img w=%d h=%d format=%d %s", - s, ov.width, ov.height, ov.format, - overlay::utils::getFormatString(ov.format)); -} -inline void dump(const char* const s, const mdp_rect& ov) { - ALOGE("%s mdp_rect x=%d y=%d w=%d h=%d", - s, ov.x, ov.y, ov.w, ov.h); -} - -inline void dump(const char* const s, const uint32_t u[], uint32_t cnt) { - ALOGE("%s user_data cnt=%d", s, cnt); - for(uint32_t i=0; i < cnt; ++i) { - ALOGE("i=%d val=%d", i, u[i]); - } -} -inline void dump(const char* const s, const msm_rotator_img_info& rot) { - ALOGE("%s msm_rotator_img_info sessid=%u dstx=%d dsty=%d rot=%d, ena=%d scale=%d", - s, rot.session_id, rot.dst_x, rot.dst_y, - rot.rotations, rot.enable, rot.downscale_ratio); - dump("src", rot.src); - dump("dst", rot.dst); - dump("src_rect", rot.src_rect); -} -inline void dump(const char* const s, const msm_rotator_data_info& rot) { - ALOGE("%s msm_rotator_data_info sessid=%u verkey=%d", - s, rot.session_id, rot.version_key); - dump("src", rot.src); - dump("dst", rot.dst); - dump("src_chroma", rot.src_chroma); - dump("dst_chroma", rot.dst_chroma); -} -inline void dump(const char* const s, const fb_fix_screeninfo& finfo) { - ALOGE("%s fb_fix_screeninfo type=%d", s, finfo.type); -} -inline void dump(const char* const s, const fb_var_screeninfo& vinfo) { - ALOGE("%s fb_var_screeninfo xres=%d yres=%d", - s, vinfo.xres, vinfo.yres); -} - -} // mdp_wrapper - -} // overlay - -#endif // MDP_WRAPPER_H diff --git a/msm8909/liboverlay/overlay.cpp b/msm8909/liboverlay/overlay.cpp deleted file mode 100644 index 1a4bf03d..00000000 --- a/msm8909/liboverlay/overlay.cpp +++ /dev/null @@ -1,582 +0,0 @@ -/* -* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are -* met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above -* copyright notice, this list of conditions and the following -* disclaimer in the documentation and/or other materials provided -* with the distribution. -* * Neither the name of The Linux Foundation nor the names of its -* contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include <dlfcn.h> -#include "overlay.h" -#include "pipes/overlayGenPipe.h" -#include "mdp_version.h" -#include "qdMetaData.h" -#include "qd_utils.h" - -namespace overlay { -using namespace utils; -using namespace qdutils; - -Overlay::Overlay() { - int numPipes = qdutils::MDPVersion::getInstance().getTotalPipes(); - PipeBook::NUM_PIPES = (numPipes <= utils::OV_MAX)? numPipes : utils::OV_MAX; - for(int i = 0; i < PipeBook::NUM_PIPES; i++) { - mPipeBook[i].init(); - } - - initScalar(); - setDMAMultiplexingSupported(); -} - -Overlay::~Overlay() { - for(int i = 0; i < PipeBook::NUM_PIPES; i++) { - mPipeBook[i].destroy(); - } - destroyScalar(); -} - -void Overlay::configBegin() { - for(int i = 0; i < PipeBook::NUM_PIPES; i++) { - //Mark as available for this round. - PipeBook::resetUse(i); - PipeBook::resetAllocation(i); - } -} - -void Overlay::configDone() { - for(int i = 0; i < PipeBook::NUM_PIPES; i++) { - if((PipeBook::isNotUsed(i) && !sessionInProgress((eDest)i)) || - isSessionEnded((eDest)i)) { - //Forces UNSET on pipes, flushes rotator memory and session, closes - //fds - mPipeBook[i].destroy(); - } - } - PipeBook::save(); -} - -int Overlay::getPipeId(utils::eDest dest) { - return mPipeBook[(int)dest].mPipe->getPipeId(); -} - -eDest Overlay::getDest(int pipeid) { - eDest dest = OV_INVALID; - // finding the dest corresponding to the given pipe - for(int i=0; i < PipeBook::NUM_PIPES; ++i) { - if(mPipeBook[i].valid() && mPipeBook[i].mPipe->getPipeId() == pipeid) { - return (eDest)i; - } - } - return dest; -} - -eDest Overlay::reservePipe(int pipeid) { - eDest dest = getDest(pipeid); - PipeBook::setAllocation((int)dest); - return dest; -} - -eDest Overlay::nextPipe(eMdpPipeType type, const PipeSpecs& pipeSpecs) { - eDest dest = OV_INVALID; - int dpy = pipeSpecs.dpy; - int mixer = pipeSpecs.mixer; - int formatType = pipeSpecs.formatClass; - for(int i = 0; i < PipeBook::NUM_PIPES; i++) { - if( (type == OV_MDP_PIPE_ANY || //Pipe type match - type == PipeBook::getPipeType((eDest)i)) && - (mPipeBook[i].mDisplay == DPY_UNUSED || //Free or same display - mPipeBook[i].mDisplay == dpy) && - (mPipeBook[i].mMixer == MIXER_UNUSED || //Free or same mixer - mPipeBook[i].mMixer == mixer) && - (mPipeBook[i].mFormatType == FORMAT_NONE || //Free or same format - mPipeBook[i].mFormatType == formatType) && - PipeBook::isNotAllocated(i) && //Free pipe - ( (sDMAMultiplexingSupported && dpy) || - !(sDMAMode == DMA_BLOCK_MODE && //DMA pipe in Line mode - PipeBook::getPipeType((eDest)i) == OV_MDP_PIPE_DMA)) ){ - //DMA-Multiplexing is only supported for WB on 8x26 - dest = (eDest)i; - PipeBook::setAllocation(i); - break; - } - } - - if(dest != OV_INVALID) { - int index = (int)dest; - mPipeBook[index].mDisplay = dpy; - mPipeBook[index].mMixer = mixer; - mPipeBook[index].mFormatType = formatType; - if(not mPipeBook[index].valid()) { - mPipeBook[index].mPipe = new GenericPipe(dpy); - mPipeBook[index].mSession = PipeBook::NONE; - } - } - - return dest; -} - -utils::eDest Overlay::getPipe(const PipeSpecs& pipeSpecs) { - if(MDPVersion::getInstance().is8x26()) { - return getPipe_8x26(pipeSpecs); - } else if(MDPVersion::getInstance().is8x16()) { - return getPipe_8x16(pipeSpecs); - } else if(MDPVersion::getInstance().is8x39()) { - return getPipe_8x39(pipeSpecs); - } else if(MDPVersion::getInstance().is8994()) { - return getPipe_8994(pipeSpecs); - } - - eDest dest = OV_INVALID; - - //The default behavior is to assume RGB and VG pipes have scalars - if(pipeSpecs.formatClass == FORMAT_YUV) { - return nextPipe(OV_MDP_PIPE_VG, pipeSpecs); - } else if(pipeSpecs.fb == false) { //RGB App layers - if(not pipeSpecs.needsScaling) { - dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs); - } - if(dest == OV_INVALID) { - dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs); - } - if(dest == OV_INVALID) { - dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs); - } - } else { //FB layer - dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs); - if(dest == OV_INVALID) { - dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs); - } - //Some features can cause FB to have scaling as well. - //If we ever come to this block with FB needing scaling, - //the screen will be black for a frame, since the FB won't get a pipe - //but atleast this will prevent a hang - if(dest == OV_INVALID and (not pipeSpecs.needsScaling)) { - dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs); - } - } - return dest; -} - -utils::eDest Overlay::getPipe_8x26(const PipeSpecs& pipeSpecs) { - //Use this to hide all the 8x26 requirements that cannot be humanly - //described in a generic way - eDest dest = OV_INVALID; - if(pipeSpecs.formatClass == FORMAT_YUV) { //video - return nextPipe(OV_MDP_PIPE_VG, pipeSpecs); - } else if(pipeSpecs.fb == false) { //RGB app layers - if((not pipeSpecs.needsScaling) and - (not (pipeSpecs.numActiveDisplays > 1 && - pipeSpecs.dpy == DPY_PRIMARY))) { - dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs); - } - if(dest == OV_INVALID) { - dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs); - } - if(dest == OV_INVALID) { - dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs); - } - } else { //FB layer - //For 8x26 Secondary we use DMA always for FB for inline rotation - if(pipeSpecs.dpy == DPY_PRIMARY) { - dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs); - if(dest == OV_INVALID) { - dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs); - } - } - if(dest == OV_INVALID and (not pipeSpecs.needsScaling) and - (not (pipeSpecs.numActiveDisplays > 1 && - pipeSpecs.dpy == DPY_PRIMARY))) { - dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs); - } - } - return dest; -} - -utils::eDest Overlay::getPipe_8x16(const PipeSpecs& pipeSpecs) { - //Having such functions help keeping the interface generic but code specific - //and rife with assumptions - eDest dest = OV_INVALID; - if(pipeSpecs.formatClass == FORMAT_YUV or pipeSpecs.needsScaling) { - return nextPipe(OV_MDP_PIPE_VG, pipeSpecs); - } else { - //Since this is a specific func, we can assume stuff like RGB pipe not - //having scalar blocks - dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs); - if(dest == OV_INVALID) { - dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs); - } - if(dest == OV_INVALID) { - dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs); - } - } - return dest; -} - -utils::eDest Overlay::getPipe_8x39(const PipeSpecs& pipeSpecs) { - //8x16 & 8x36 has same number of pipes, pipe-types & scaling capabilities. - //Rely on 8x16 until we see a need to change. - return getPipe_8x16(pipeSpecs); -} - -utils::eDest Overlay::getPipe_8994(const PipeSpecs& pipeSpecs) { - //If DMA pipes need to be used in block mode for downscale, there could be - //cases where consecutive rounds need separate modes, which cannot be - //supported since we at least need 1 round in between where the DMA is - //unused - eDest dest = OV_INVALID; - if(pipeSpecs.formatClass == FORMAT_YUV) { - return nextPipe(OV_MDP_PIPE_VG, pipeSpecs); - } else { - dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs); - if(dest == OV_INVALID) { - dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs); - } - if(dest == OV_INVALID and not pipeSpecs.needsScaling) { - dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs); - } - } - return dest; -} - -void Overlay::endAllSessions() { - for(int i = 0; i < PipeBook::NUM_PIPES; i++) { - if(mPipeBook[i].valid() && mPipeBook[i].mSession==PipeBook::START) - mPipeBook[i].mSession = PipeBook::END; - } -} - -bool Overlay::isPipeTypeAttached(eMdpPipeType type) { - for(int i = 0; i < PipeBook::NUM_PIPES; i++) { - if(type == PipeBook::getPipeType((eDest)i) && - mPipeBook[i].mDisplay != DPY_UNUSED) { - return true; - } - } - return false; -} - -int Overlay::comparePipePriority(utils::eDest pipe1Index, - utils::eDest pipe2Index) { - validate((int)pipe1Index); - validate((int)pipe2Index); - uint8_t pipe1Prio = mPipeBook[(int)pipe1Index].mPipe->getPriority(); - uint8_t pipe2Prio = mPipeBook[(int)pipe2Index].mPipe->getPriority(); - if(pipe1Prio > pipe2Prio) - return -1; - if(pipe1Prio < pipe2Prio) - return 1; - return 0; -} - -bool Overlay::commit(utils::eDest dest) { - bool ret = false; - validate((int)dest); - - if(mPipeBook[dest].mPipe->commit()) { - ret = true; - PipeBook::setUse((int)dest); - } else { - clear(mPipeBook[dest].mDisplay); - } - return ret; -} - -bool Overlay::queueBuffer(int fd, uint32_t offset, - utils::eDest dest) { - bool ret = false; - validate((int)dest); - //Queue only if commit() has succeeded (and the bit set) - if(PipeBook::isUsed((int)dest)) { - ret = mPipeBook[dest].mPipe->queueBuffer(fd, offset); - } - return ret; -} - -void Overlay::setCrop(const utils::Dim& d, - utils::eDest dest) { - validate((int)dest); - mPipeBook[dest].mPipe->setCrop(d); -} - -void Overlay::setColor(const uint32_t color, - utils::eDest dest) { - validate((int)dest); - mPipeBook[dest].mPipe->setColor(color); -} - -void Overlay::setPosition(const utils::Dim& d, - utils::eDest dest) { - validate((int)dest); - mPipeBook[dest].mPipe->setPosition(d); -} - -void Overlay::setTransform(const int orient, - utils::eDest dest) { - validate((int)dest); - - utils::eTransform transform = - static_cast<utils::eTransform>(orient); - mPipeBook[dest].mPipe->setTransform(transform); - -} - -void Overlay::setSource(const utils::PipeArgs args, - utils::eDest dest) { - validate((int)dest); - - setPipeType(dest, PipeBook::getPipeType(dest)); - mPipeBook[dest].mPipe->setSource(args); -} - -void Overlay::setVisualParams(const MetaData_t& metadata, utils::eDest dest) { - validate((int)dest); - mPipeBook[dest].mPipe->setVisualParams(metadata); -} - -void Overlay::setPipeType(utils::eDest pipeIndex, - const utils::eMdpPipeType pType) { - mPipeBook[pipeIndex].mPipe->setPipeType(pType); -} - -Overlay* Overlay::getInstance() { - if(sInstance == NULL) { - sInstance = new Overlay(); - } - return sInstance; -} - -// Clears any VG pipes allocated to the fb devices -// Generates a LUT for pipe types. -int Overlay::initOverlay() { - int mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion(); - int numPipesXType[OV_MDP_PIPE_ANY] = {0}; - numPipesXType[OV_MDP_PIPE_RGB] = - qdutils::MDPVersion::getInstance().getRGBPipes(); - numPipesXType[OV_MDP_PIPE_VG] = - qdutils::MDPVersion::getInstance().getVGPipes(); - numPipesXType[OV_MDP_PIPE_DMA] = - qdutils::MDPVersion::getInstance().getDMAPipes(); - - int index = 0; - for(int X = 0; X < (int)OV_MDP_PIPE_ANY; X++) { //iterate over types - for(int j = 0; j < numPipesXType[X]; j++) { //iterate over num - PipeBook::pipeTypeLUT[index] = (utils::eMdpPipeType)X; - index++; - } - } - - if (mdpVersion < qdutils::MDSS_V5 && mdpVersion > qdutils::MDP_V3_0_5) { - msmfb_mixer_info_req req; - mdp_mixer_info *minfo = NULL; - char name[64]; - int fd = -1; - for(int i = 0; i < MAX_FB_DEVICES; i++) { - snprintf(name, 64, FB_DEVICE_TEMPLATE, i); - ALOGD("initoverlay:: opening the device:: %s", name); - fd = ::open(name, O_RDWR, 0); - if(fd < 0) { - ALOGE("cannot open framebuffer(%d)", i); - return -1; - } - //Get the mixer configuration */ - req.mixer_num = i; - if (ioctl(fd, MSMFB_MIXER_INFO, &req) == -1) { - ALOGE("ERROR: MSMFB_MIXER_INFO ioctl failed"); - close(fd); - return -1; - } - minfo = req.info; - for (int j = 0; j < req.cnt; j++) { - ALOGD("ndx=%d num=%d z_order=%d", minfo->pndx, minfo->pnum, - minfo->z_order); - // except the RGB base layer with z_order of -1, clear any - // other pipes connected to mixer. - if((minfo->z_order) != -1) { - int index = minfo->pndx; - ALOGD("Unset overlay with index: %d at mixer %d", index, i); - if(ioctl(fd, MSMFB_OVERLAY_UNSET, &index) == -1) { - ALOGE("ERROR: MSMFB_OVERLAY_UNSET failed"); - close(fd); - return -1; - } - } - minfo++; - } - close(fd); - fd = -1; - } - } - - FILE *displayDeviceFP = NULL; - char fbType[MAX_FRAME_BUFFER_NAME_SIZE]; - char msmFbTypePath[MAX_FRAME_BUFFER_NAME_SIZE]; - const char *strDtvPanel = "dtv panel"; - const char *strWbPanel = "writeback panel"; - - for(int num = 1; num < MAX_FB_DEVICES; num++) { - snprintf (msmFbTypePath, sizeof(msmFbTypePath), - "/sys/class/graphics/fb%d/msm_fb_type", num); - displayDeviceFP = fopen(msmFbTypePath, "r"); - - if(displayDeviceFP){ - fread(fbType, sizeof(char), MAX_FRAME_BUFFER_NAME_SIZE, - displayDeviceFP); - - if(strncmp(fbType, strDtvPanel, strlen(strDtvPanel)) == 0) { - sDpyFbMap[DPY_EXTERNAL] = num; - } else if(strncmp(fbType, strWbPanel, strlen(strWbPanel)) == 0) { - sDpyFbMap[DPY_WRITEBACK] = num; - } - - fclose(displayDeviceFP); - } - } - - return 0; -} - -bool Overlay::displayCommit(const int& fd) { - utils::Dim lRoi, rRoi; - return displayCommit(fd, lRoi, rRoi); -} - -bool Overlay::displayCommit(const int& fd, const utils::Dim& lRoi, - const utils::Dim& rRoi) { - //Commit - struct mdp_display_commit info; - memset(&info, 0, sizeof(struct mdp_display_commit)); - info.flags = MDP_DISPLAY_COMMIT_OVERLAY; - info.l_roi.x = lRoi.x; - info.l_roi.y = lRoi.y; - info.l_roi.w = lRoi.w; - info.l_roi.h = lRoi.h; - info.r_roi.x = rRoi.x; - info.r_roi.y = rRoi.y; - info.r_roi.w = rRoi.w; - info.r_roi.h = rRoi.h; - - if(!mdp_wrapper::displayCommit(fd, info)) { - ALOGE("%s: commit failed", __func__); - return false; - } - return true; -} - -void Overlay::getDump(char *buf, size_t len) { - int totalPipes = 0; - const char *str = "\nOverlay State\n\n"; - strlcat(buf, str, len); - for(int i = 0; i < PipeBook::NUM_PIPES; i++) { - if(mPipeBook[i].valid()) { - mPipeBook[i].mPipe->getDump(buf, len); - char str[64] = {'\0'}; - snprintf(str, 64, "Display=%d\n\n", mPipeBook[i].mDisplay); - strlcat(buf, str, len); - totalPipes++; - } - } - char str_pipes[64] = {'\0'}; - snprintf(str_pipes, 64, "Pipes=%d\n\n", totalPipes); - strlcat(buf, str_pipes, len); -} - -void Overlay::clear(int dpy) { - for(int i = 0; i < PipeBook::NUM_PIPES; i++) { - if (mPipeBook[i].mDisplay == dpy) { - // Mark as available for this round - PipeBook::resetUse(i); - PipeBook::resetAllocation(i); - if(getPipeId((utils::eDest)i) == -1) { - mPipeBook[i].destroy(); - } - } - } -} - -bool Overlay::validateAndSet(const int& dpy, const int& fbFd) { - GenericPipe* pipeArray[PipeBook::NUM_PIPES]; - memset(pipeArray, 0, sizeof(GenericPipe*)*(PipeBook::NUM_PIPES)); - - int num = 0; - for(int i = 0; i < PipeBook::NUM_PIPES; i++) { - if(PipeBook::isUsed(i) && mPipeBook[i].valid() && - mPipeBook[i].mDisplay == dpy) { - pipeArray[num++] = mPipeBook[i].mPipe; - } - } - - //Protect against misbehaving clients - return num ? GenericPipe::validateAndSet(pipeArray, num, fbFd) : true; -} - -void Overlay::initScalar() { - if(sLibScaleHandle == NULL) { - sLibScaleHandle = dlopen("libscale.so", RTLD_NOW); - if(sLibScaleHandle) { - *(void **) &sFnProgramScale = - dlsym(sLibScaleHandle, "programScale"); - } - } -} - -void Overlay::destroyScalar() { - if(sLibScaleHandle) { - dlclose(sLibScaleHandle); - sLibScaleHandle = NULL; - } -} - -void Overlay::PipeBook::init() { - mPipe = NULL; - mDisplay = DPY_UNUSED; - mMixer = MIXER_UNUSED; - mFormatType = FORMAT_NONE; -} - -void Overlay::PipeBook::destroy() { - if(mPipe) { - delete mPipe; - mPipe = NULL; - } - mDisplay = DPY_UNUSED; - mMixer = MIXER_UNUSED; - mFormatType = FORMAT_NONE; - mSession = NONE; -} - -Overlay* Overlay::sInstance = 0; -int Overlay::sDpyFbMap[DPY_MAX] = {0, -1, -1, -1}; -int Overlay::sDMAMode = DMA_LINE_MODE; -bool Overlay::sDMAMultiplexingSupported = false; -bool Overlay::sDebugPipeLifecycle = false; -int Overlay::PipeBook::NUM_PIPES = 0; -int Overlay::PipeBook::sPipeUsageBitmap = 0; -int Overlay::PipeBook::sLastUsageBitmap = 0; -int Overlay::PipeBook::sAllocatedBitmap = 0; -utils::eMdpPipeType Overlay::PipeBook::pipeTypeLUT[utils::OV_MAX] = - {utils::OV_MDP_PIPE_ANY}; -void *Overlay::sLibScaleHandle = NULL; -int (*Overlay::sFnProgramScale)(struct mdp_overlay_list *) = NULL; - -}; // namespace overlay diff --git a/msm8909/liboverlay/overlay.h b/msm8909/liboverlay/overlay.h deleted file mode 100644 index 5c93b232..00000000 --- a/msm8909/liboverlay/overlay.h +++ /dev/null @@ -1,428 +0,0 @@ -/* -* Copyright (c) 2011-2013, 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 OVERLAY_H -#define OVERLAY_H - -#include "overlayUtils.h" -#include "mdp_version.h" -#include "utils/threads.h" - -struct MetaData_t; - -namespace overlay { -class GenericPipe; - -class Overlay : utils::NoCopy { -public: - enum { DMA_BLOCK_MODE, DMA_LINE_MODE }; - //Abstract Display types. Each backed by a LayerMixer, - //represented by a fb node. - //High res panels can be backed by 2 layer mixers and a single fb node. - enum { DPY_PRIMARY, DPY_EXTERNAL, DPY_TERTIARY, DPY_WRITEBACK, DPY_UNUSED }; - enum { DPY_MAX = DPY_UNUSED }; - enum { MIXER_LEFT, MIXER_RIGHT, MIXER_UNUSED }; - enum { MIXER_DEFAULT = MIXER_LEFT, MIXER_MAX = MIXER_UNUSED }; - enum { MAX_FB_DEVICES = DPY_MAX }; - enum { FORMAT_YUV, FORMAT_RGB , FORMAT_NONE }; - - struct PipeSpecs { - PipeSpecs() : formatClass(FORMAT_RGB), needsScaling(false), fb(false), - dpy(DPY_PRIMARY), mixer(MIXER_DEFAULT), numActiveDisplays(1) {} - int formatClass; - bool needsScaling; - bool fb; - int dpy; - int mixer; - int numActiveDisplays; - }; - - /* dtor close */ - ~Overlay(); - - /* Marks the beginning of a drawing round, resets usage bits on pipes - * Should be called when drawing begins before any pipe config is done. - */ - void configBegin(); - - /* Marks the end of config for this drawing round - * Will do garbage collection of pipe objects and thus calling UNSETs, - * closing FDs, removing rotator objects and memory, if allocated. - * Should be called after all pipe configs are done. - */ - void configDone(); - - /* Get a pipe that supported the specified format class (yuv, rgb) and has - * scaling capabilities. - */ - utils::eDest getPipe(const PipeSpecs& pipeSpecs); - /* Returns the eDest corresponding to an already allocated pipeid. - * Useful for the reservation case, when libvpu reserves the pipe at its - * end, and expect the overlay to allocate a given pipe for a layer. - */ - utils::eDest reservePipe(int pipeid); - /* getting dest for the given pipeid */ - utils::eDest getDest(int pipeid); - /* getting overlay.pipeid for the given dest */ - int getPipeId(utils::eDest dest); - - void setSource(const utils::PipeArgs args, utils::eDest dest); - void setCrop(const utils::Dim& d, utils::eDest dest); - void setColor(const uint32_t color, utils::eDest dest); - void setTransform(const int orientation, utils::eDest dest); - void setPosition(const utils::Dim& dim, utils::eDest dest); - void setVisualParams(const MetaData_t& data, utils::eDest dest); - bool commit(utils::eDest dest); - bool queueBuffer(int fd, uint32_t offset, utils::eDest dest); - - /* pipe reservation session is running */ - bool sessionInProgress(utils::eDest dest); - /* pipe reservation session has ended*/ - bool isSessionEnded(utils::eDest dest); - /* start session for the pipe reservation */ - void startSession(utils::eDest dest); - /* end all started sesisons */ - void endAllSessions(); - /* Returns available ("unallocated") pipes for a display's mixer */ - int availablePipes(int dpy, int mixer); - /* Returns available ("unallocated") pipes for a display */ - int availablePipes(int dpy); - /* Returns available ("unallocated") pipe of given type for a display */ - int availablePipes(int dpy, utils::eMdpPipeType type); - /* Returns if any of the requested pipe type is attached to any of the - * displays - */ - bool isPipeTypeAttached(utils::eMdpPipeType type); - /* Compare pipe priorities and return - * 1 if 1st pipe has a higher priority - * 0 if both have the same priority - *-1 if 2nd pipe has a higher priority - */ - int comparePipePriority(utils::eDest pipe1Index, utils::eDest pipe2Index); - /* Returns pipe dump. Expects a NULL terminated buffer of big enough size - * to populate. - */ - /* Returns if DMA pipe multiplexing is supported by the mdss driver */ - static bool isDMAMultiplexingSupported(); - /* Returns if UI scaling on external is supported on the targets */ - static bool isUIScalingOnExternalSupported(); - void getDump(char *buf, size_t len); - /* Reset usage and allocation bits on all pipes for given display */ - void clear(int dpy); - /* Validate the set of pipes for a display and set them in driver */ - bool validateAndSet(const int& dpy, const int& fbFd); - - /* Closes open pipes, called during startup */ - static int initOverlay(); - /* Returns the singleton instance of overlay */ - static Overlay* getInstance(); - static void setDMAMode(const int& mode); - static int getDMAMode(); - /* Returns the framebuffer node backing up the display */ - static int getFbForDpy(const int& dpy); - - static bool displayCommit(const int& fd); - /* Overloads display commit with ROI's of each halves. - * Single interface panels will only update left ROI. */ - static bool displayCommit(const int& fd, const utils::Dim& lRoi, - const utils::Dim& rRoi); - /* Logs pipe lifecycle events like set, unset, commit when enabled */ - static void debugPipeLifecycle(const bool& enable); - /* Returns true if pipe life cycle logging is enabled */ - static bool isDebugPipeLifecycle(); - -private: - /* Ctor setup */ - explicit Overlay(); - /*Validate index range, abort if invalid */ - void validate(int index); - static void setDMAMultiplexingSupported(); - /* Returns an available pipe based on the type of pipe requested. When ANY - * is requested, the first available VG or RGB is returned. If no pipe is - * available for the display "dpy" then INV is returned. Note: If a pipe is - * assigned to a certain display, then it cannot be assigned to another - * display without being garbage-collected once. To add if a pipe is - * asisgned to a mixer within a display it cannot be reused for another - * mixer without being UNSET once*/ - utils::eDest nextPipe(utils::eMdpPipeType, const PipeSpecs& pipeSpecs); - /* Helpers that enfore target specific policies while returning pipes */ - utils::eDest getPipe_8x26(const PipeSpecs& pipeSpecs); - utils::eDest getPipe_8x16(const PipeSpecs& pipeSpecs); - utils::eDest getPipe_8x39(const PipeSpecs& pipeSpecs); - utils::eDest getPipe_8994(const PipeSpecs& pipeSpecs); - - /* Returns the handle to libscale.so's programScale function */ - static int (*getFnProgramScale())(struct mdp_overlay_list *); - /* Creates a scalar object using libscale.so */ - static void initScalar(); - /* Destroys the scalar object using libscale.so */ - static void destroyScalar(); - /* Sets the pipe type RGB/VG/DMA*/ - void setPipeType(utils::eDest pipeIndex, const utils::eMdpPipeType pType); - - /* Just like a Facebook for pipes, but much less profile info */ - struct PipeBook { - void init(); - void destroy(); - /* Check if pipe exists and return true, false otherwise */ - bool valid(); - - /* Hardware pipe wrapper */ - GenericPipe *mPipe; - /* Display using this pipe. Refer to enums above */ - int mDisplay; - /* Mixer within a split display this pipe is attached to */ - int mMixer; - /* Format for which this pipe is attached to the mixer*/ - int mFormatType; - - /* operations on bitmap */ - static bool pipeUsageUnchanged(); - static void setUse(int index); - static void resetUse(int index); - static bool isUsed(int index); - static bool isNotUsed(int index); - static void save(); - - static void setAllocation(int index); - static void resetAllocation(int index); - static bool isAllocated(int index); - static bool isNotAllocated(int index); - - static utils::eMdpPipeType getPipeType(utils::eDest dest); - static const char* getDestStr(utils::eDest dest); - - static int NUM_PIPES; - static utils::eMdpPipeType pipeTypeLUT[utils::OV_MAX]; - /* Session for reserved pipes */ - enum Session { - NONE, - START, - END - }; - Session mSession; - - private: - //usage tracks if a successful commit happened. So a pipe could be - //allocated to a display, but it may not end up using it for various - //reasons. If one display actually uses a pipe then it amy not be - //used by another display, without an UNSET in between. - static int sPipeUsageBitmap; - static int sLastUsageBitmap; - //Tracks which pipe objects are allocated. This does not imply that they - //will actually be used. For example, a display might choose to acquire - //3 pipe objects in one shot and proceed with config only if it gets all - //3. The bitmap helps allocate different pipe objects on each request. - static int sAllocatedBitmap; - }; - - PipeBook mPipeBook[utils::OV_INVALID]; //Used as max - - /* Singleton Instance*/ - static Overlay *sInstance; - static int sDpyFbMap[DPY_MAX]; - static int sDMAMode; - static bool sDMAMultiplexingSupported; - static void *sLibScaleHandle; - static int (*sFnProgramScale)(struct mdp_overlay_list *); - static bool sDebugPipeLifecycle; - - friend class MdpCtrl; -}; - -inline void Overlay::validate(int index) { - OVASSERT(index >=0 && index < PipeBook::NUM_PIPES, \ - "%s, Index out of bounds: %d", __FUNCTION__, index); - OVASSERT(mPipeBook[index].valid(), "Pipe does not exist %s", - PipeBook::getDestStr((utils::eDest)index)); -} - -inline int Overlay::availablePipes(int dpy, int mixer) { - int avail = 0; - for(int i = 0; i < PipeBook::NUM_PIPES; i++) { - if( (mPipeBook[i].mDisplay == DPY_UNUSED || - mPipeBook[i].mDisplay == dpy) && - (mPipeBook[i].mMixer == MIXER_UNUSED || - mPipeBook[i].mMixer == mixer) && - PipeBook::isNotAllocated(i) && - !(Overlay::getDMAMode() == Overlay::DMA_BLOCK_MODE && - PipeBook::getPipeType((utils::eDest)i) == - utils::OV_MDP_PIPE_DMA)) { - avail++; - } - } - return avail; -} - -inline int Overlay::availablePipes(int dpy) { - int avail = 0; - for(int i = 0; i < PipeBook::NUM_PIPES; i++) { - if( (mPipeBook[i].mDisplay == DPY_UNUSED || - mPipeBook[i].mDisplay == dpy) && - PipeBook::isNotAllocated(i) && - !(Overlay::getDMAMode() == Overlay::DMA_BLOCK_MODE && - PipeBook::getPipeType((utils::eDest)i) == - utils::OV_MDP_PIPE_DMA)) { - avail++; - } - } - return avail; -} - -inline int Overlay::availablePipes(int dpy, utils::eMdpPipeType type) { - int avail = 0; - for(int i = 0; i < PipeBook::NUM_PIPES; i++) { - if((mPipeBook[i].mDisplay == DPY_UNUSED || - mPipeBook[i].mDisplay == dpy) && - PipeBook::isNotAllocated(i) && - type == PipeBook::getPipeType((utils::eDest)i)) { - avail++; - } - } - return avail; -} - -inline void Overlay::setDMAMode(const int& mode) { - if(mode == DMA_LINE_MODE || mode == DMA_BLOCK_MODE) - sDMAMode = mode; -} - -inline void Overlay::setDMAMultiplexingSupported() { - sDMAMultiplexingSupported = false; - if(qdutils::MDPVersion::getInstance().is8x26()) - sDMAMultiplexingSupported = true; -} - -inline bool Overlay::isDMAMultiplexingSupported() { - return sDMAMultiplexingSupported; -} - -inline bool Overlay::isUIScalingOnExternalSupported() { - if(qdutils::MDPVersion::getInstance().is8x26() or - qdutils::MDPVersion::getInstance().is8x16() or - qdutils::MDPVersion::getInstance().is8x39()) { - return false; - } - return true; -} - -inline int Overlay::getDMAMode() { - return sDMAMode; -} - -inline int Overlay::getFbForDpy(const int& dpy) { - OVASSERT(dpy >= 0 && dpy < DPY_MAX, "Invalid dpy %d", dpy); - return sDpyFbMap[dpy]; -} - -inline int (*Overlay::getFnProgramScale())(struct mdp_overlay_list *) { - return sFnProgramScale; -} - -inline void Overlay::debugPipeLifecycle(const bool& enable) { - sDebugPipeLifecycle = enable; -} - -inline bool Overlay::isDebugPipeLifecycle() { - return sDebugPipeLifecycle; -} - -inline bool Overlay::PipeBook::valid() { - return (mPipe != NULL); -} - -inline bool Overlay::PipeBook::pipeUsageUnchanged() { - return (sPipeUsageBitmap == sLastUsageBitmap); -} - -inline void Overlay::PipeBook::setUse(int index) { - sPipeUsageBitmap |= (1 << index); -} - -inline void Overlay::PipeBook::resetUse(int index) { - sPipeUsageBitmap &= ~(1 << index); -} - -inline bool Overlay::PipeBook::isUsed(int index) { - return sPipeUsageBitmap & (1 << index); -} - -inline bool Overlay::PipeBook::isNotUsed(int index) { - return !isUsed(index); -} - -inline void Overlay::PipeBook::save() { - sLastUsageBitmap = sPipeUsageBitmap; -} - -inline void Overlay::PipeBook::setAllocation(int index) { - sAllocatedBitmap |= (1 << index); -} - -inline void Overlay::PipeBook::resetAllocation(int index) { - sAllocatedBitmap &= ~(1 << index); -} - -inline bool Overlay::PipeBook::isAllocated(int index) { - return sAllocatedBitmap & (1 << index); -} - -inline bool Overlay::PipeBook::isNotAllocated(int index) { - return !isAllocated(index); -} - -inline utils::eMdpPipeType Overlay::PipeBook::getPipeType(utils::eDest dest) { - return pipeTypeLUT[(int)dest]; -} - -inline void Overlay::startSession(utils::eDest dest) { - mPipeBook[(int)dest].mSession = PipeBook::START; -} - -inline bool Overlay::sessionInProgress(utils::eDest dest) { - return (mPipeBook[(int)dest].mSession == PipeBook::START); -} - -inline bool Overlay::isSessionEnded(utils::eDest dest) { - return (mPipeBook[(int)dest].mSession == PipeBook::END); -} - -inline const char* Overlay::PipeBook::getDestStr(utils::eDest dest) { - switch(getPipeType(dest)) { - case utils::OV_MDP_PIPE_RGB: return "RGB"; - case utils::OV_MDP_PIPE_VG: return "VG"; - case utils::OV_MDP_PIPE_DMA: return "DMA"; - default: return "Invalid"; - } - return "Invalid"; -} - -}; // overlay - -#endif // OVERLAY_H diff --git a/msm8909/liboverlay/overlayCtrlData.h b/msm8909/liboverlay/overlayCtrlData.h deleted file mode 100644 index 2eec98c9..00000000 --- a/msm8909/liboverlay/overlayCtrlData.h +++ /dev/null @@ -1,249 +0,0 @@ -/* -* Copyright (c) 2012-2013, 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 OVERLAY_CTRLDATA_H -#define OVERLAY_CTRLDATA_H - -#include "overlayUtils.h" -#include "overlayMdp.h" -#include "gralloc_priv.h" // INTERLACE_MASK - -namespace ovutils = overlay::utils; - -namespace overlay { - -/* -* Sequence to use: -* init -* start -* setXXX -* close -* */ -class Ctrl : utils::NoCopy { -public: - - /* ctor */ - explicit Ctrl(const int& dpy); - /* dtor close */ - ~Ctrl(); - - /* set source using whf, orient and wait flag */ - void setSource(const utils::PipeArgs& args); - /* set crop info and pass it down to mdp */ - void setCrop(const utils::Dim& d); - /* set color for mdp pipe */ - void setColor(const uint32_t color); - /* set orientation */ - void setTransform(const utils::eTransform& p); - /* set mdp position using dim */ - void setPosition(const utils::Dim& dim); - /* set mdp visual params using metadata */ - bool setVisualParams(const MetaData_t &metadata); - /* set pipe type RGB/DMA/VG */ - void setPipeType(const utils::eMdpPipeType& pType); - /* mdp set overlay/commit changes */ - bool commit(); - - /* ctrl id */ - int getPipeId() const; - /* ctrl fd */ - int getFd() const; - /* retrieve crop data */ - utils::Dim getCrop() const; - utils::Dim getPosition() const; - /* Update the src format based on rotator's dest */ - void updateSrcFormat(const uint32_t& rotDstFormat); - /* return pipe priority */ - uint8_t getPriority() const; - /* dump the state of the object */ - void dump() const; - /* Return the dump in the specified buffer */ - void getDump(char *buf, size_t len); - - static bool validateAndSet(Ctrl* ctrlArray[], const int& count, - const int& fbFd); -private: - // mdp ctrl struct(info e.g.) - MdpCtrl *mMdp; -}; - - -class Data : utils::NoCopy { -public: - /* init, reset */ - explicit Data(const int& dpy); - /* calls close */ - ~Data(); - /* set overlay pipe id in the mdp struct */ - void setPipeId(int id); - /* get overlay id in the mdp struct */ - int getPipeId() const; - /* queue buffer to the overlay */ - bool queueBuffer(int fd, uint32_t offset); - /* sump the state of the obj */ - void dump() const; - /* Return the dump in the specified buffer */ - void getDump(char *buf, size_t len); - -private: - // mdp data struct - MdpData *mMdp; -}; - -//-------------Inlines------------------------------- - -inline Ctrl::Ctrl(const int& dpy) : mMdp(new MdpCtrl(dpy)) { -} - -inline Ctrl::~Ctrl() { - delete mMdp; -} - -inline void Ctrl::setSource(const utils::PipeArgs& args) -{ - mMdp->setSource(args); -} - -inline void Ctrl::setPosition(const utils::Dim& dim) -{ - mMdp->setPosition(dim); -} - -inline void Ctrl::setTransform(const utils::eTransform& orient) -{ - mMdp->setTransform(orient); -} - -inline void Ctrl::setCrop(const utils::Dim& d) -{ - mMdp->setCrop(d); -} - -inline void Ctrl::setColor(const uint32_t color) -{ - mMdp->setColor(color); -} - -inline bool Ctrl::setVisualParams(const MetaData_t &metadata) -{ - if (!mMdp->setVisualParams(metadata)) { - ALOGE("Ctrl setVisualParams failed in MDP setVisualParams"); - return false; - } - return true; -} - -inline void Ctrl::setPipeType(const utils::eMdpPipeType& pType) -{ - mMdp->setPipeType(pType); -} - -inline void Ctrl::dump() const { - ALOGE("== Dump Ctrl start =="); - mMdp->dump(); - ALOGE("== Dump Ctrl end =="); -} - -inline bool Ctrl::commit() { - if(!mMdp->set()) { - ALOGE("Ctrl commit failed set overlay"); - return false; - } - return true; -} - -inline int Ctrl::getPipeId() const { - return mMdp->getPipeId(); -} - -inline int Ctrl::getFd() const { - return mMdp->getFd(); -} - -inline void Ctrl::updateSrcFormat(const uint32_t& rotDstFmt) { - mMdp->updateSrcFormat(rotDstFmt); -} - -inline bool Ctrl::validateAndSet(Ctrl* ctrlArray[], const int& count, - const int& fbFd) { - MdpCtrl* mdpCtrlArray[count]; - memset(&mdpCtrlArray, 0, sizeof(mdpCtrlArray)); - - for(int i = 0; i < count; i++) { - mdpCtrlArray[i] = ctrlArray[i]->mMdp; - } - - bool ret = MdpCtrl::validateAndSet(mdpCtrlArray, count, fbFd); - return ret; -} - -inline utils::Dim Ctrl::getCrop() const { - return mMdp->getSrcRectDim(); -} - -inline utils::Dim Ctrl::getPosition() const { - return mMdp->getDstRectDim(); -} - -inline uint8_t Ctrl::getPriority() const { - return mMdp->getPriority(); -} - -inline void Ctrl::getDump(char *buf, size_t len) { - mMdp->getDump(buf, len); -} - -inline Data::Data(const int& dpy) : mMdp(new MdpData(dpy)) { -} - -inline Data::~Data() { - delete mMdp; -} - -inline void Data::setPipeId(int id) { mMdp->setPipeId(id); } - -inline int Data::getPipeId() const { return mMdp->getPipeId(); } - -inline bool Data::queueBuffer(int fd, uint32_t offset) { - return mMdp->play(fd, offset); -} - -inline void Data::dump() const { - ALOGE("== Dump Data MDP start =="); - mMdp->dump(); - ALOGE("== Dump Data MDP end =="); -} - -inline void Data::getDump(char *buf, size_t len) { - mMdp->getDump(buf, len); -} - -} // overlay - -#endif diff --git a/msm8909/liboverlay/overlayMdp.cpp b/msm8909/liboverlay/overlayMdp.cpp deleted file mode 100644 index d52864e4..00000000 --- a/msm8909/liboverlay/overlayMdp.cpp +++ /dev/null @@ -1,393 +0,0 @@ -/* -* Copyright (C) 2008 The Android Open Source Project -* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. -* -* 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 <math.h> -#include <mdp_version.h> -#include "overlayUtils.h" -#include "overlayMdp.h" -#include "mdp_version.h" -#include <overlay.h> - -#define HSIC_SETTINGS_DEBUG 0 - -using namespace qdutils; - -namespace ovutils = overlay::utils; -namespace overlay { - -bool MdpCtrl::init(const int& dpy) { - int fbnum = Overlay::getFbForDpy(dpy); - if( fbnum < 0 ) { - ALOGE("%s: Invalid FB for the display: %d",__FUNCTION__, dpy); - return false; - } - - // FD init - if(!utils::openDev(mFd, fbnum, - Res::fbPath, O_RDWR)){ - ALOGE("Ctrl failed to init fbnum=%d", fbnum); - return false; - } - mDpy = dpy; - return true; -} - -void MdpCtrl::reset() { - utils::memset0(mOVInfo); - mOVInfo.id = MSMFB_NEW_REQUEST; - mOrientation = utils::OVERLAY_TRANSFORM_0; - mDpy = 0; -#ifdef USES_POST_PROCESSING - memset(&mParams, 0, sizeof(struct compute_params)); - mParams.params.conv_params.order = hsic_order_hsc_i; - mParams.params.conv_params.interface = interface_rec601; - mParams.params.conv_params.cc_matrix[0][0] = 1; - mParams.params.conv_params.cc_matrix[1][1] = 1; - mParams.params.conv_params.cc_matrix[2][2] = 1; -#endif -} - -bool MdpCtrl::close() { - bool result = true; - if(MSMFB_NEW_REQUEST != static_cast<int>(mOVInfo.id)) { - if(!mdp_wrapper::unsetOverlay(mFd.getFD(), mOVInfo.id)) { - ALOGE("MdpCtrl close error in unset"); - result = false; - } - } -#ifdef USES_POST_PROCESSING - /* free allocated memory in PP */ - if (mOVInfo.overlay_pp_cfg.igc_cfg.c0_c1_data) - free(mOVInfo.overlay_pp_cfg.igc_cfg.c0_c1_data); -#endif - reset(); - - if(!mFd.close()) { - result = false; - } - - return result; -} - -void MdpCtrl::setSource(const utils::PipeArgs& args) { - setSrcWhf(args.whf); - - //TODO These are hardcoded. Can be moved out of setSource. - mOVInfo.transp_mask = 0xffffffff; - - //TODO These calls should ideally be a part of setPipeParams API - setFlags(args.mdpFlags); - setZ(args.zorder); - setPlaneAlpha(args.planeAlpha); - setBlending(args.blending); -} - -void MdpCtrl::setCrop(const utils::Dim& d) { - setSrcRectDim(d); -} - -void MdpCtrl::setColor(const uint32_t color) { - mOVInfo.bg_color = color; -} - -void MdpCtrl::setPosition(const overlay::utils::Dim& d) { - setDstRectDim(d); -} - -void MdpCtrl::setTransform(const utils::eTransform& orient) { - int rot = utils::getMdpOrient(orient); - setUserData(rot); - mOrientation = static_cast<utils::eTransform>(rot); -} - -void MdpCtrl::setPipeType(const utils::eMdpPipeType& pType){ - switch((int) pType){ - case utils::OV_MDP_PIPE_RGB: - mOVInfo.pipe_type = PIPE_TYPE_RGB; - break; - case utils::OV_MDP_PIPE_VG: - mOVInfo.pipe_type = PIPE_TYPE_VIG; - break; - case utils::OV_MDP_PIPE_DMA: - mOVInfo.pipe_type = PIPE_TYPE_DMA; - break; - default: - mOVInfo.pipe_type = PIPE_TYPE_AUTO; - break; - } -} - -void MdpCtrl::doTransform() { - setRotationFlags(); - utils::Whf whf = getSrcWhf(); - utils::Dim dim = getSrcRectDim(); - utils::preRotateSource(mOrientation, whf, dim); - setSrcWhf(whf); - setSrcRectDim(dim); -} - -void MdpCtrl::doDownscale() { - if(MDPVersion::getInstance().supportsDecimation()) { - utils::getDecimationFactor(mOVInfo.src_rect.w, mOVInfo.src_rect.h, - mOVInfo.dst_rect.w, mOVInfo.dst_rect.h, mOVInfo.horz_deci, - mOVInfo.vert_deci); - } -} - -bool MdpCtrl::set() { - int mdpVersion = MDPVersion::getInstance().getMDPVersion(); - //deferred calcs, so APIs could be called in any order. - doTransform(); - utils::Whf whf = getSrcWhf(); - if(utils::isYuv(whf.format)) { - utils::normalizeCrop(mOVInfo.src_rect.x, mOVInfo.src_rect.w); - utils::normalizeCrop(mOVInfo.src_rect.y, mOVInfo.src_rect.h); - if(mdpVersion < MDSS_V5) { - utils::even_floor(mOVInfo.dst_rect.w); - utils::even_floor(mOVInfo.dst_rect.h); - } else if (mOVInfo.flags & MDP_DEINTERLACE) { - // For interlaced, crop.h should be 4-aligned - if (!(mOVInfo.flags & MDP_SOURCE_ROTATED_90) && - (mOVInfo.src_rect.h % 4)) - mOVInfo.src_rect.h = utils::aligndown(mOVInfo.src_rect.h, 4); - // For interlaced, width must be multiple of 4 when rotated 90deg. - else if ((mOVInfo.flags & MDP_SOURCE_ROTATED_90) && - (mOVInfo.src_rect.w % 4)) - mOVInfo.src_rect.w = utils::aligndown(mOVInfo.src_rect.w, 4); - } - } else { - // On 8974 and 8x26, there is a limitation of 1-pixel down-scaling - if (mdpVersion >= MDSS_V5) { - if(qdutils::MDPVersion::getInstance().is8x74v2() || - qdutils::MDPVersion::getInstance().is8x26()) { - if (mOVInfo.src_rect.w - mOVInfo.dst_rect.w == 1) - mOVInfo.src_rect.w -= 1; - if (mOVInfo.src_rect.h - mOVInfo.dst_rect.h == 1) - mOVInfo.src_rect.h -= 1; - } - } - } - - doDownscale(); - return true; -} - -//Update src format based on rotator's destination format. -void MdpCtrl::updateSrcFormat(const uint32_t& rotDestFmt) { - utils::Whf whf = getSrcWhf(); - whf.format = rotDestFmt; - setSrcWhf(whf); -} - -void MdpCtrl::dump() const { - ALOGE("== Dump MdpCtrl start =="); - mFd.dump(); - mdp_wrapper::dump("mOVInfo", mOVInfo); - ALOGE("== Dump MdpCtrl end =="); -} - -void MdpCtrl::getDump(char *buf, size_t len) { - ovutils::getDump(buf, len, "Ctrl", mOVInfo); -} - -void MdpData::dump() const { - ALOGE("== Dump MdpData start =="); - mFd.dump(); - mdp_wrapper::dump("mOvData", mOvData); - ALOGE("== Dump MdpData end =="); -} - -void MdpData::getDump(char *buf, size_t len) { - ovutils::getDump(buf, len, "Data", mOvData); -} - -bool MdpCtrl::setVisualParams(const MetaData_t& data) { - ALOGD_IF(0, "In %s: data.operation = %d", __FUNCTION__, data.operation); - - // Set Color Space for MDP to configure CSC matrix - mOVInfo.color_space = ITU_R_601; - if (data.operation & UPDATE_COLOR_SPACE) { - mOVInfo.color_space = data.colorSpace; - } - -#ifdef USES_POST_PROCESSING - bool needUpdate = false; - /* calculate the data */ - if (data.operation & PP_PARAM_HSIC) { - if (mParams.params.pa_params.hue != data.hsicData.hue) { - ALOGD_IF(HSIC_SETTINGS_DEBUG, - "Hue has changed from %d to %d", - mParams.params.pa_params.hue,data.hsicData.hue); - needUpdate = true; - } - - if (!isEqual(mParams.params.pa_params.sat, - data.hsicData.saturation)) { - ALOGD_IF(HSIC_SETTINGS_DEBUG, - "Saturation has changed from %f to %f", - mParams.params.pa_params.sat, - data.hsicData.saturation); - needUpdate = true; - } - - if (mParams.params.pa_params.intensity != data.hsicData.intensity) { - ALOGD_IF(HSIC_SETTINGS_DEBUG, - "Intensity has changed from %d to %d", - mParams.params.pa_params.intensity, - data.hsicData.intensity); - needUpdate = true; - } - - if (!isEqual(mParams.params.pa_params.contrast, - data.hsicData.contrast)) { - ALOGD_IF(HSIC_SETTINGS_DEBUG, - "Contrast has changed from %f to %f", - mParams.params.pa_params.contrast, - data.hsicData.contrast); - needUpdate = true; - } - - if (needUpdate) { - mParams.params.pa_params.hue = data.hsicData.hue; - mParams.params.pa_params.sat = data.hsicData.saturation; - mParams.params.pa_params.intensity = data.hsicData.intensity; - mParams.params.pa_params.contrast = data.hsicData.contrast; - mParams.params.pa_params.ops = MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE; - mParams.operation |= PP_OP_PA; - } - } - - if (data.operation & PP_PARAM_SHARP2) { - if (mParams.params.sharp_params.strength != data.Sharp2Data.strength) { - needUpdate = true; - } - if (mParams.params.sharp_params.edge_thr != data.Sharp2Data.edge_thr) { - needUpdate = true; - } - if (mParams.params.sharp_params.smooth_thr != - data.Sharp2Data.smooth_thr) { - needUpdate = true; - } - if (mParams.params.sharp_params.noise_thr != - data.Sharp2Data.noise_thr) { - needUpdate = true; - } - - if (needUpdate) { - mParams.params.sharp_params.strength = data.Sharp2Data.strength; - mParams.params.sharp_params.edge_thr = data.Sharp2Data.edge_thr; - mParams.params.sharp_params.smooth_thr = - data.Sharp2Data.smooth_thr; - mParams.params.sharp_params.noise_thr = data.Sharp2Data.noise_thr; - mParams.params.sharp_params.ops = - MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE; - mParams.operation |= PP_OP_SHARP; - } - } - - if (data.operation & PP_PARAM_IGC) { - if (mOVInfo.overlay_pp_cfg.igc_cfg.c0_c1_data == NULL){ - uint32_t *igcData - = (uint32_t *)malloc(2 * MAX_IGC_LUT_ENTRIES * sizeof(uint32_t)); - if (!igcData) { - ALOGE("IGC storage allocated failed"); - return false; - } - mOVInfo.overlay_pp_cfg.igc_cfg.c0_c1_data = igcData; - mOVInfo.overlay_pp_cfg.igc_cfg.c2_data - = igcData + MAX_IGC_LUT_ENTRIES; - } - - memcpy(mParams.params.igc_lut_params.c0, - data.igcData.c0, sizeof(uint16_t) * MAX_IGC_LUT_ENTRIES); - memcpy(mParams.params.igc_lut_params.c1, - data.igcData.c1, sizeof(uint16_t) * MAX_IGC_LUT_ENTRIES); - memcpy(mParams.params.igc_lut_params.c2, - data.igcData.c2, sizeof(uint16_t) * MAX_IGC_LUT_ENTRIES); - - mParams.params.igc_lut_params.ops - = MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE; - mParams.operation |= PP_OP_IGC; - needUpdate = true; - } - - if (data.operation & PP_PARAM_VID_INTFC) { - mParams.params.conv_params.interface = - (interface_type) data.video_interface; - needUpdate = true; - } - - if (needUpdate) { - display_pp_compute_params(&mParams, &mOVInfo.overlay_pp_cfg); - } -#endif - return true; -} - -bool MdpCtrl::validateAndSet(MdpCtrl* mdpCtrlArray[], const int& count, - const int& fbFd) { - mdp_overlay* ovArray[count]; - memset(&ovArray, 0, sizeof(ovArray)); - - for(int i = 0; i < count; i++) { - ovArray[i] = &mdpCtrlArray[i]->mOVInfo; - } - - struct mdp_overlay_list list; - memset(&list, 0, sizeof(struct mdp_overlay_list)); - list.num_overlays = count; - list.overlay_list = ovArray; - - int (*fnProgramScale)(struct mdp_overlay_list *) = - Overlay::getFnProgramScale(); - if(fnProgramScale) { - fnProgramScale(&list); - } - - // Error value is based on file errno-base.h - // 0 - indicates no error. - int errVal = mdp_wrapper::validateAndSet(fbFd, list); - if(errVal) { - /* No dump for failure due to insufficient resource */ - if(errVal != E2BIG) { - mdp_wrapper::dump("Bad ov dump: ", - *list.overlay_list[list.processed_overlays]); - } - return false; - } - - return true; -} - - -//// MdpData //////////// -bool MdpData::init(const int& dpy) { - int fbnum = Overlay::getFbForDpy(dpy); - if( fbnum < 0 ) { - ALOGE("%s: Invalid FB for the display: %d",__FUNCTION__, dpy); - return false; - } - - // FD init - if(!utils::openDev(mFd, fbnum, Res::fbPath, O_RDWR)){ - ALOGE("Ctrl failed to init fbnum=%d", fbnum); - return false; - } - return true; -} - -} // overlay diff --git a/msm8909/liboverlay/overlayMdp.h b/msm8909/liboverlay/overlayMdp.h deleted file mode 100644 index faed1ef0..00000000 --- a/msm8909/liboverlay/overlayMdp.h +++ /dev/null @@ -1,321 +0,0 @@ -/* -* Copyright (C) 2008 The Android Open Source Project -* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. -* -* 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 OVERLAY_MDP_H -#define OVERLAY_MDP_H - -#include <linux/msm_mdp.h> - -#include "overlayUtils.h" -#include "mdpWrapper.h" -#include "qdMetaData.h" -#ifdef USES_POST_PROCESSING -#include "lib-postproc.h" -#endif - -namespace overlay{ - -/* -* Mdp Ctrl holds corresponding fd and MDP related struct. -* It is simple wrapper to MDP services -* */ -class MdpCtrl { -public: - /* ctor reset */ - explicit MdpCtrl(const int& dpy); - /* dtor close */ - ~MdpCtrl(); - /* init underlying device using fbnum for dpy */ - bool init(const int& dpy); - /* unset overlay, reset and close fd */ - bool close(); - /* reset and set ov id to -1 / MSMFB_NEW_REQUEST */ - void reset(); - /* calls overlay set - * Set would always consult last good known ov instance. - * Only if it is different, set would actually exectue ioctl. - * On a sucess ioctl. last good known ov instance is updated */ - bool set(); - /* Sets the source total width, height, format */ - void setSource(const utils::PipeArgs& pargs); - /* - * Sets ROI, the unpadded region, for source buffer. - * Dim - ROI dimensions. - */ - void setCrop(const utils::Dim& d); - /* set color for mdp pipe */ - void setColor(const uint32_t color); - void setTransform(const utils::eTransform& orient); - /* given a dim and w/h, set overlay dim */ - void setPosition(const utils::Dim& dim); - /* using user_data, sets/unsets roationvalue in mdp flags */ - void setRotationFlags(); - /* Update the src format with rotator's dest*/ - void updateSrcFormat(const uint32_t& rotDstFormat); - /* dump state of the object */ - void dump() const; - /* Return the dump in the specified buffer */ - void getDump(char *buf, size_t len); - /* returns session id */ - int getPipeId() const; - /* returns the fd associated to ctrl*/ - int getFd() const; - /* returns a copy ro dst rect dim */ - utils::Dim getDstRectDim() const; - /* returns a copy to src rect dim */ - utils::Dim getSrcRectDim() const; - /* return pipe priority */ - uint8_t getPriority() const; - /* setVisualParam */ - bool setVisualParams(const MetaData_t& data); - /* sets pipe type RGB/DMA/VG */ - void setPipeType(const utils::eMdpPipeType& pType); - - static bool validateAndSet(MdpCtrl* mdpCtrlArray[], const int& count, - const int& fbFd); -private: - /* Perform transformation calculations */ - void doTransform(); - void doDownscale(); - /* get orient / user_data[0] */ - int getOrient() const; - /* returns flags from mdp structure */ - int getFlags() const; - /* set flags to mdp structure */ - void setFlags(int f); - /* set z order */ - void setZ(utils::eZorder z); - /* return a copy of src whf*/ - utils::Whf getSrcWhf() const; - /* set plane alpha */ - void setPlaneAlpha(int planeAlpha); - /* set blending method */ - void setBlending(overlay::utils::eBlending blending); - - /* set src whf */ - void setSrcWhf(const utils::Whf& whf); - /* set src/dst rect dim */ - void setSrcRectDim(const utils::Dim d); - void setDstRectDim(const utils::Dim d); - /* returns user_data[0]*/ - int getUserData() const; - /* sets user_data[0] */ - void setUserData(int v); - - utils::eTransform mOrientation; //Holds requested orientation - /* Actual overlay mdp structure */ - mdp_overlay mOVInfo; - /* FD for the mdp fbnum */ - OvFD mFd; - int mDpy; - -#ifdef USES_POST_PROCESSING - /* PP Compute Params */ - struct compute_params mParams; -#endif -}; - -/* MDP data */ -class MdpData { -public: - /* ctor reset data */ - explicit MdpData(const int& dpy); - /* dtor close*/ - ~MdpData(); - /* init FD */ - bool init(const int& dpy); - /* memset0 the underlying mdp object */ - void reset(); - /* close fd, and reset */ - bool close(); - /* set id of mdp data */ - void setPipeId(int id); - /* return ses id of data */ - int getPipeId() const; - /* get underlying fd*/ - int getFd() const; - /* get memory_id */ - int getSrcMemoryId() const; - /* calls wrapper play */ - bool play(int fd, uint32_t offset); - /* dump state of the object */ - void dump() const; - /* Return the dump in the specified buffer */ - void getDump(char *buf, size_t len); - -private: - - /* actual overlay mdp data */ - msmfb_overlay_data mOvData; - /* fd to mdp fbnum */ - OvFD mFd; -}; - -//--------------Inlines--------------------------------- - -///// MdpCtrl ////// - -inline MdpCtrl::MdpCtrl(const int& dpy) { - reset(); - init(dpy); -} - -inline MdpCtrl::~MdpCtrl() { - close(); -} - -inline int MdpCtrl::getOrient() const { - return getUserData(); -} - -inline int MdpCtrl::getPipeId() const { - return mOVInfo.id; -} - -inline int MdpCtrl::getFd() const { - return mFd.getFD(); -} - -inline int MdpCtrl::getFlags() const { - return mOVInfo.flags; -} - -inline void MdpCtrl::setFlags(int f) { - mOVInfo.flags = f; -} - -inline void MdpCtrl::setZ(overlay::utils::eZorder z) { - mOVInfo.z_order = z; -} - -inline void MdpCtrl::setPlaneAlpha(int planeAlpha) { - mOVInfo.alpha = planeAlpha; -} - -inline void MdpCtrl::setBlending(overlay::utils::eBlending blending) { - switch((int) blending) { - case utils::OVERLAY_BLENDING_OPAQUE: - mOVInfo.blend_op = BLEND_OP_OPAQUE; - break; - case utils::OVERLAY_BLENDING_PREMULT: - mOVInfo.blend_op = BLEND_OP_PREMULTIPLIED; - break; - case utils::OVERLAY_BLENDING_COVERAGE: - default: - mOVInfo.blend_op = BLEND_OP_COVERAGE; - } -} - -inline overlay::utils::Whf MdpCtrl::getSrcWhf() const { - return utils::Whf( mOVInfo.src.width, - mOVInfo.src.height, - mOVInfo.src.format); -} - -inline void MdpCtrl::setSrcWhf(const overlay::utils::Whf& whf) { - mOVInfo.src.width = whf.w; - mOVInfo.src.height = whf.h; - mOVInfo.src.format = whf.format; -} - -inline overlay::utils::Dim MdpCtrl::getSrcRectDim() const { - return utils::Dim( mOVInfo.src_rect.x, - mOVInfo.src_rect.y, - mOVInfo.src_rect.w, - mOVInfo.src_rect.h); -} - -inline void MdpCtrl::setSrcRectDim(const overlay::utils::Dim d) { - mOVInfo.src_rect.x = d.x; - mOVInfo.src_rect.y = d.y; - mOVInfo.src_rect.w = d.w; - mOVInfo.src_rect.h = d.h; -} - -inline overlay::utils::Dim MdpCtrl::getDstRectDim() const { - return utils::Dim( mOVInfo.dst_rect.x, - mOVInfo.dst_rect.y, - mOVInfo.dst_rect.w, - mOVInfo.dst_rect.h); -} - -inline void MdpCtrl::setDstRectDim(const overlay::utils::Dim d) { - mOVInfo.dst_rect.x = d.x; - mOVInfo.dst_rect.y = d.y; - mOVInfo.dst_rect.w = d.w; - mOVInfo.dst_rect.h = d.h; -} - -inline int MdpCtrl::getUserData() const { return mOVInfo.user_data[0]; } - -inline void MdpCtrl::setUserData(int v) { mOVInfo.user_data[0] = v; } - -inline void MdpCtrl::setRotationFlags() { - const int u = getUserData(); - if (u & MDP_ROT_90) - mOVInfo.flags |= MDP_SOURCE_ROTATED_90; -} - -inline uint8_t MdpCtrl::getPriority() const { - return mOVInfo.priority; -} - -/////// MdpData ////// - -inline MdpData::MdpData(const int& dpy) { - reset(); - init(dpy); -} - -inline MdpData::~MdpData() { close(); } - -inline void MdpData::reset() { - overlay::utils::memset0(mOvData); - mOvData.data.memory_id = -1; -} - -inline bool MdpData::close() { - reset(); - return mFd.close(); -} - -inline int MdpData::getSrcMemoryId() const { return mOvData.data.memory_id; } - -inline void MdpData::setPipeId(int id) { mOvData.id = id; } - -inline int MdpData::getPipeId() const { return mOvData.id; } - -inline int MdpData::getFd() const { return mFd.getFD(); } - -inline bool MdpData::play(int fd, uint32_t offset) { - mOvData.data.memory_id = fd; - mOvData.data.offset = offset; - if(!mdp_wrapper::play(mFd.getFD(), mOvData)){ - ALOGE("MdpData failed to play"); - dump(); - return false; - } - return true; -} - -} // overlay - -inline bool isEqual(float f1, float f2) { - return ((int)(f1*100) == (int)(f2*100)) ? true : false; -} - -#endif // OVERLAY_MDP_H diff --git a/msm8909/liboverlay/overlayMdpRot.cpp b/msm8909/liboverlay/overlayMdpRot.cpp deleted file mode 100755 index d3228976..00000000 --- a/msm8909/liboverlay/overlayMdpRot.cpp +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. - * Not a Contribution, Apache license notifications and license are retained - * for attribution purposes only. - * - * 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 <math.h> -#include "overlayUtils.h" -#include "overlayRotator.h" -#include "gr.h" - -namespace ovutils = overlay::utils; - -namespace overlay { - -MdpRot::MdpRot() { - reset(); - init(); -} - -MdpRot::~MdpRot() { close(); } - -bool MdpRot::enabled() const { return mRotImgInfo.enable; } - -void MdpRot::setRotations(uint32_t r) { mRotImgInfo.rotations = (uint8_t)r; } - -int MdpRot::getSrcMemId() const { - return mRotDataInfo.src.memory_id; -} - -int MdpRot::getDstMemId() const { - return mRotDataInfo.dst.memory_id; -} - -uint32_t MdpRot::getSrcOffset() const { - return mRotDataInfo.src.offset; -} - -uint32_t MdpRot::getDstOffset() const { - return mRotDataInfo.dst.offset; -} - -uint32_t MdpRot::getDstFormat() const { - return mRotImgInfo.dst.format; -} - -//Added for completeness. Not expected to be called. -utils::Whf MdpRot::getDstWhf() const { - int alW = 0, alH = 0; - int halFormat = ovutils::getHALFormat(mRotImgInfo.dst.format); - getBufferSizeAndDimensions(mRotImgInfo.dst.width, mRotImgInfo.dst.height, - halFormat, alW, alH); - return utils::Whf(alW, alH, mRotImgInfo.dst.format); -} - -//Added for completeness. Not expected to be called. -utils::Dim MdpRot::getDstDimensions() const { - int alW = 0, alH = 0; - int halFormat = ovutils::getHALFormat(mRotImgInfo.dst.format); - getBufferSizeAndDimensions(mRotImgInfo.dst.width, mRotImgInfo.dst.height, - halFormat, alW, alH); - return utils::Dim(0, 0, alW, alH); -} - -uint32_t MdpRot::getSessId() const { return mRotImgInfo.session_id; } - -void MdpRot::setDownscale(int ds) { - if ((utils::ROT_DS_EIGHTH == ds) && (mRotImgInfo.src_rect.h & 0xF)) { - // Ensure src_rect.h is a multiple of 16 for 1/8 downscaling. - // This is an undocumented MDP Rotator constraint. - mRotImgInfo.src_rect.h = utils::aligndown(mRotImgInfo.src_rect.h, 16); - } - mRotImgInfo.downscale_ratio = ds; -} - -void MdpRot::save() { - mLSRotImgInfo = mRotImgInfo; -} - -bool MdpRot::rotConfChanged() const { - // 0 means same - if(0 == ::memcmp(&mRotImgInfo, &mLSRotImgInfo, - sizeof (msm_rotator_img_info))) { - return false; - } - return true; -} - -bool MdpRot::init() -{ - if(!mFd.open(Res::rotPath, O_RDWR)){ - ALOGE("MdpRot failed to init %s", Res::rotPath); - return false; - } - return true; -} - -void MdpRot::setSource(const overlay::utils::Whf& awhf) { - utils::Whf whf(awhf); - mRotImgInfo.src.format = whf.format; - - mRotImgInfo.src.width = whf.w; - mRotImgInfo.src.height = whf.h; - - mRotImgInfo.src_rect.w = whf.w; - mRotImgInfo.src_rect.h = whf.h; - - mRotImgInfo.dst.width = whf.w; - mRotImgInfo.dst.height = whf.h; -} - -void MdpRot::setCrop(const utils::Dim& /*crop*/) { - // NO-OP for non-mdss rotator due to possible h/w limitations -} - -void MdpRot::setFlags(const utils::eMdpFlags& flags) { - mRotImgInfo.secure = 0; - if(flags & utils::OV_MDP_SECURE_OVERLAY_SESSION) - mRotImgInfo.secure = 1; -} - -void MdpRot::setTransform(const utils::eTransform& rot) -{ - int r = utils::getMdpOrient(rot); - setRotations(r); - mOrientation = static_cast<utils::eTransform>(r); - ALOGE_IF(DEBUG_OVERLAY, "%s: r=%d", __FUNCTION__, r); -} - -void MdpRot::doTransform() { - if(mOrientation & utils::OVERLAY_TRANSFORM_ROT_90) - utils::swap(mRotImgInfo.dst.width, mRotImgInfo.dst.height); -} - -bool MdpRot::commit() { - doTransform(); - if(rotConfChanged()) { - mRotImgInfo.enable = 1; - if(!overlay::mdp_wrapper::startRotator(mFd.getFD(), mRotImgInfo)) { - ALOGE("MdpRot commit failed"); - dump(); - mRotImgInfo.enable = 0; - return false; - } - mRotDataInfo.session_id = mRotImgInfo.session_id; - } - return true; -} - -uint32_t MdpRot::calcOutputBufSize() { - ovutils::Whf destWhf(mRotImgInfo.dst.width, - mRotImgInfo.dst.height, mRotImgInfo.dst.format); - return Rotator::calcOutputBufSize(destWhf); -} - -bool MdpRot::open_i(uint32_t numbufs, uint32_t bufsz) -{ - OvMem mem; - - OVASSERT(MAP_FAILED == mem.addr(), "MAP failed in open_i"); - - if(!mem.open(numbufs, bufsz, mRotImgInfo.secure)){ - ALOGE("%s: Failed to open", __func__); - mem.close(); - return false; - } - - OVASSERT(MAP_FAILED != mem.addr(), "MAP failed"); - OVASSERT(mem.getFD() != -1, "getFd is -1"); - - mRotDataInfo.dst.memory_id = mem.getFD(); - mRotDataInfo.dst.offset = 0; - mMem.mem = mem; - return true; -} - -bool MdpRot::close() { - bool success = true; - if(mFd.valid() && (getSessId() != 0)) { - if(!mdp_wrapper::endRotator(mFd.getFD(), getSessId())) { - ALOGE("Mdp Rot error endRotator, fd=%d sessId=%u", - mFd.getFD(), getSessId()); - success = false; - } - } - if (!mFd.close()) { - ALOGE("Mdp Rot error closing fd"); - success = false; - } - if (!mMem.close()) { - ALOGE("Mdp Rot error closing mem"); - success = false; - } - reset(); - return success; -} - -bool MdpRot::remap(uint32_t numbufs) { - // if current size changed, remap - uint32_t opBufSize = calcOutputBufSize(); - if(opBufSize == mMem.size()) { - ALOGE_IF(DEBUG_OVERLAY, "%s: same size %d", __FUNCTION__, opBufSize); - return true; - } - - if(!mMem.close()) { - ALOGE("%s error in closing prev rot mem", __FUNCTION__); - return false; - } - - ALOGE_IF(DEBUG_OVERLAY, "%s: size changed - remapping", __FUNCTION__); - - if(!open_i(numbufs, opBufSize)) { - ALOGE("%s Error could not open", __FUNCTION__); - return false; - } - - for (uint32_t i = 0; i < numbufs; ++i) { - mMem.mRotOffset[i] = i * opBufSize; - } - - return true; -} - -void MdpRot::reset() { - ovutils::memset0(mRotImgInfo); - ovutils::memset0(mLSRotImgInfo); - ovutils::memset0(mRotDataInfo); - ovutils::memset0(mMem.mRotOffset); - mMem.mCurrIndex = 0; - mOrientation = utils::OVERLAY_TRANSFORM_0; -} - -bool MdpRot::queueBuffer(int fd, uint32_t offset) { - if(enabled() and (not isRotCached(fd,offset))) { - int prev_fd = getSrcMemId(); - uint32_t prev_offset = getSrcOffset(); - - mRotDataInfo.src.memory_id = fd; - mRotDataInfo.src.offset = offset; - - if(false == remap(RotMem::ROT_NUM_BUFS)) { - ALOGE("%s Remap failed, not queueing", __FUNCTION__); - return false; - } - - mRotDataInfo.dst.offset = - mMem.mRotOffset[mMem.mCurrIndex]; - - if(!overlay::mdp_wrapper::rotate(mFd.getFD(), mRotDataInfo)) { - ALOGE("MdpRot failed rotate"); - dump(); - mRotDataInfo.src.memory_id = prev_fd; - mRotDataInfo.src.offset = prev_offset; - return false; - } - save(); - mMem.mCurrIndex = - (mMem.mCurrIndex + 1) % mMem.mem.numBufs(); - } - return true; -} - -void MdpRot::dump() const { - ALOGE("== Dump MdpRot start =="); - mFd.dump(); - mMem.mem.dump(); - mdp_wrapper::dump("mRotImgInfo", mRotImgInfo); - mdp_wrapper::dump("mRotDataInfo", mRotDataInfo); - ALOGE("== Dump MdpRot end =="); -} - -void MdpRot::getDump(char *buf, size_t len) const { - ovutils::getDump(buf, len, "MdpRotCtrl", mRotImgInfo); - ovutils::getDump(buf, len, "MdpRotData", mRotDataInfo); -} - -int MdpRot::getDownscaleFactor(const int& src_w, const int& src_h, - const int& dst_w, const int& dst_h, const uint32_t& /*mdpFormat*/, - const bool& /*isInterlaced*/) { - int dscale_factor = utils::ROT_DS_NONE; - // We need this check to engage the rotator whenever possible to assist MDP - // in performing video downscale. - // This saves bandwidth and avoids causing the driver to make too many panel - // -mode switches between BLT (writeback) and non-BLT (Direct) modes. - // Use-case: Video playback [with downscaling and rotation]. - if (dst_w && dst_h) - { - float fDscale = (float)(src_w * src_h) / (float)(dst_w * dst_h); - uint32_t dscale = (int)sqrtf(fDscale); - - if(dscale < 2) { - // Down-scale to > 50% of orig. - dscale_factor = utils::ROT_DS_NONE; - } else if(dscale < 4) { - // Down-scale to between > 25% to <= 50% of orig. - dscale_factor = utils::ROT_DS_HALF; - } else if(dscale < 8) { - // Down-scale to between > 12.5% to <= 25% of orig. - dscale_factor = utils::ROT_DS_FOURTH; - } else { - // Down-scale to <= 12.5% of orig. - dscale_factor = utils::ROT_DS_EIGHTH; - } - } - return dscale_factor; -} - -} // namespace overlay diff --git a/msm8909/liboverlay/overlayMdssRot.cpp b/msm8909/liboverlay/overlayMdssRot.cpp deleted file mode 100644 index 87e134a9..00000000 --- a/msm8909/liboverlay/overlayMdssRot.cpp +++ /dev/null @@ -1,430 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. - * Not a Contribution, Apache license notifications and license are retained - * for attribution purposes only. - * - * 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 <math.h> -#include "overlayUtils.h" -#include "overlayRotator.h" - -#define DEBUG_MDSS_ROT 0 - -#ifdef VENUS_COLOR_FORMAT -#include <media/msm_media_info.h> -#else -#define VENUS_BUFFER_SIZE(args...) 0 -#endif - -#ifndef MDSS_MDP_ROT_ONLY -#define MDSS_MDP_ROT_ONLY 0x80 -#endif - -#define MDSS_ROT_MASK (MDP_ROT_90 | MDP_FLIP_UD | MDP_FLIP_LR) - -namespace ovutils = overlay::utils; - -namespace overlay { -using namespace utils; - -MdssRot::MdssRot() { - reset(); - init(); -} - -MdssRot::~MdssRot() { close(); } - -bool MdssRot::enabled() const { return mEnabled; } - -void MdssRot::setRotations(uint32_t flags) { mRotInfo.flags |= flags; } - -int MdssRot::getSrcMemId() const { - return mRotData.data.memory_id; -} - -int MdssRot::getDstMemId() const { - return mRotData.dst_data.memory_id; -} - -uint32_t MdssRot::getSrcOffset() const { - return mRotData.data.offset; -} - -uint32_t MdssRot::getDstOffset() const { - return mRotData.dst_data.offset; -} - -uint32_t MdssRot::getDstFormat() const { - //For mdss src and dst formats are same - return mRotInfo.src.format; -} - -utils::Whf MdssRot::getDstWhf() const { - //For Mdss dst_rect itself represents buffer dimensions. We ignore actual - //aligned values during buffer allocation. Also the driver overwrites the - //src.format field if destination format is different. - //This implementation detail makes it possible to retrieve w,h even before - //buffer allocation, which happens in queueBuffer. - return utils::Whf(mRotInfo.dst_rect.w, mRotInfo.dst_rect.h, - mRotInfo.src.format); -} - -utils::Dim MdssRot::getDstDimensions() const { - return utils::Dim(mRotInfo.dst_rect.x, mRotInfo.dst_rect.y, - mRotInfo.dst_rect.w, mRotInfo.dst_rect.h); -} - -uint32_t MdssRot::getSessId() const { return mRotInfo.id; } - -void MdssRot::save() { - mLSRotInfo = mRotInfo; -} - -bool MdssRot::rotConfChanged() const { - // 0 means same - if(0 == ::memcmp(&mRotInfo, &mLSRotInfo, - sizeof (mdp_overlay))) { - return false; - } - return true; -} - -bool MdssRot::init() { - if(!utils::openDev(mFd, 0, Res::fbPath, O_RDWR)) { - ALOGE("MdssRot failed to init fb0"); - return false; - } - return true; -} - -void MdssRot::setSource(const overlay::utils::Whf& awhf) { - utils::Whf whf(awhf); - - mRotInfo.src.format = whf.format; - mRotInfo.src.width = whf.w; - mRotInfo.src.height = whf.h; -} - -void MdssRot::setCrop(const utils::Dim& crop) { - mRotInfo.src_rect.x = crop.x; - mRotInfo.src_rect.y = crop.y; - mRotInfo.src_rect.w = crop.w; - mRotInfo.src_rect.h = crop.h; -} - -void MdssRot::setDownscale(int downscale) { - mDownscale = downscale; -} - -void MdssRot::setFlags(const utils::eMdpFlags& flags) { - mRotInfo.flags = flags; -} - -void MdssRot::setTransform(const utils::eTransform& rot) -{ - // reset rotation flags to avoid stale orientation values - mRotInfo.flags &= ~MDSS_ROT_MASK; - int flags = utils::getMdpOrient(rot); - if (flags != -1) - setRotations(flags); - mOrientation = static_cast<utils::eTransform>(flags); - ALOGE_IF(DEBUG_OVERLAY, "%s: rot=%d", __FUNCTION__, flags); -} - -void MdssRot::doTransform() { - mRotInfo.flags |= mOrientation; - if(mOrientation & utils::OVERLAY_TRANSFORM_ROT_90) - utils::swap(mRotInfo.dst_rect.w, mRotInfo.dst_rect.h); -} - -bool MdssRot::commit() { - Dim adjCrop(mRotInfo.src_rect.x,mRotInfo.src_rect.y, - mRotInfo.src_rect.w,mRotInfo.src_rect.h); - adjCrop = getFormatAdjustedCrop(adjCrop, mRotInfo.src.format, - mRotInfo.flags & utils::OV_MDP_DEINTERLACE); - adjCrop = getDownscaleAdjustedCrop(adjCrop, mDownscale); - - mRotInfo.src_rect.x = adjCrop.x; - mRotInfo.src_rect.y = adjCrop.y; - mRotInfo.src_rect.w = adjCrop.w; - mRotInfo.src_rect.h = adjCrop.h; - - mRotInfo.dst_rect.x = 0; - mRotInfo.dst_rect.y = 0; - mRotInfo.dst_rect.w = mDownscale ? - mRotInfo.src_rect.w / mDownscale : mRotInfo.src_rect.w; - mRotInfo.dst_rect.h = mDownscale ? - mRotInfo.src_rect.h / mDownscale : mRotInfo.src_rect.h; - //Clear for next round - mDownscale = 0; - - doTransform(); - - mRotInfo.flags |= MDSS_MDP_ROT_ONLY; - mEnabled = true; - if(!overlay::mdp_wrapper::setOverlay(mFd.getFD(), mRotInfo)) { - ALOGE("MdssRot commit failed!"); - dump(); - return (mEnabled = false); - } - mRotData.id = mRotInfo.id; - return true; -} - -bool MdssRot::queueBuffer(int fd, uint32_t offset) { - if(enabled() and (not isRotCached(fd,offset))) { - int prev_fd = getSrcMemId(); - uint32_t prev_offset = getSrcOffset(); - - mRotData.data.memory_id = fd; - mRotData.data.offset = offset; - - if(false == remap(RotMem::ROT_NUM_BUFS)) { - ALOGE("%s Remap failed, not queuing", __FUNCTION__); - return false; - } - - mRotData.dst_data.offset = - mMem.mRotOffset[mMem.mCurrIndex]; - - if(!overlay::mdp_wrapper::play(mFd.getFD(), mRotData)) { - ALOGE("MdssRot play failed!"); - dump(); - mRotData.data.memory_id = prev_fd; - mRotData.data.offset = prev_offset; - return false; - } - save(); - mMem.mCurrIndex = - (mMem.mCurrIndex + 1) % mMem.mem.numBufs(); - } - return true; -} - -bool MdssRot::open_i(uint32_t numbufs, uint32_t bufsz) -{ - OvMem mem; - OVASSERT(MAP_FAILED == mem.addr(), "MAP failed in open_i"); - bool isSecure = mRotInfo.flags & utils::OV_MDP_SECURE_OVERLAY_SESSION; - - if(!mem.open(numbufs, bufsz, isSecure)){ - ALOGE("%s: Failed to open", __func__); - mem.close(); - return false; - } - - OVASSERT(MAP_FAILED != mem.addr(), "MAP failed"); - OVASSERT(mem.getFD() != -1, "getFd is -1"); - - mRotData.dst_data.memory_id = mem.getFD(); - mRotData.dst_data.offset = 0; - mMem.mem = mem; - return true; -} - -bool MdssRot::remap(uint32_t numbufs) { - // Calculate the size based on rotator's dst format, w and h. - uint32_t opBufSize = calcOutputBufSize(); - // If current size changed, remap - if(opBufSize == mMem.size()) { - ALOGE_IF(DEBUG_OVERLAY, "%s: same size %d", __FUNCTION__, opBufSize); - return true; - } - - ALOGE_IF(DEBUG_OVERLAY, "%s: size changed - remapping", __FUNCTION__); - - if(!mMem.close()) { - ALOGE("%s error in closing prev rot mem", __FUNCTION__); - return false; - } - - if(!open_i(numbufs, opBufSize)) { - ALOGE("%s Error could not open", __FUNCTION__); - return false; - } - - for (uint32_t i = 0; i < numbufs; ++i) { - mMem.mRotOffset[i] = i * opBufSize; - } - - return true; -} - -bool MdssRot::close() { - bool success = true; - if(mFd.valid() && (getSessId() != (uint32_t) MSMFB_NEW_REQUEST)) { - if(!mdp_wrapper::unsetOverlay(mFd.getFD(), getSessId())) { - ALOGE("MdssRot::close unsetOverlay failed, fd=%d sessId=%d", - mFd.getFD(), getSessId()); - success = false; - } - } - - if (!mFd.close()) { - ALOGE("Mdss Rot error closing fd"); - success = false; - } - if (!mMem.close()) { - ALOGE("Mdss Rot error closing mem"); - success = false; - } - reset(); - return success; -} - -void MdssRot::reset() { - ovutils::memset0(mRotInfo); - ovutils::memset0(mLSRotInfo); - ovutils::memset0(mRotData); - mRotData.data.memory_id = -1; - mRotInfo.id = MSMFB_NEW_REQUEST; - ovutils::memset0(mMem.mRotOffset); - mMem.mCurrIndex = 0; - mOrientation = utils::OVERLAY_TRANSFORM_0; - mDownscale = 0; -} - -void MdssRot::dump() const { - ALOGE("== Dump MdssRot start =="); - mFd.dump(); - mMem.mem.dump(); - mdp_wrapper::dump("mRotInfo", mRotInfo); - mdp_wrapper::dump("mRotData", mRotData); - ALOGE("== Dump MdssRot end =="); -} - -uint32_t MdssRot::calcOutputBufSize() { - uint32_t opBufSize = 0; - ovutils::Whf destWhf(mRotInfo.dst_rect.w, mRotInfo.dst_rect.h, - mRotInfo.src.format); //mdss src and dst formats are same. - - if (mRotInfo.flags & ovutils::OV_MDSS_MDP_BWC_EN) { - opBufSize = calcCompressedBufSize(destWhf); - } else { - opBufSize = Rotator::calcOutputBufSize(destWhf); - } - - return opBufSize; -} - -void MdssRot::getDump(char *buf, size_t len) const { - ovutils::getDump(buf, len, "MdssRotCtrl", mRotInfo); - ovutils::getDump(buf, len, "MdssRotData", mRotData); -} - -// Calculate the compressed o/p buffer size for BWC -uint32_t MdssRot::calcCompressedBufSize(const ovutils::Whf& destWhf) { - uint32_t bufSize = 0; - //Worst case alignments - int aWidth = ovutils::align(destWhf.w, 64); - int aHeight = ovutils::align(destWhf.h, 4); - /* - Format | RAU size (width x height) - ---------------------------------------------- - ARGB | 32 pixel x 4 line - RGB888 | 32 pixel x 4 line - Y (Luma) | 64 pixel x 4 line - CRCB 420 | 32 pixel x 2 line - CRCB 422 H2V1 | 32 pixel x 4 line - CRCB 422 H1V2 | 64 pixel x 2 line - - Metadata requirements:- - 1 byte meta data for every 8 RAUs - 2 byte meta data per RAU - */ - - //These blocks attempt to allocate for the worst case in each of the - //respective format classes, yuv/rgb. The table above is for reference - if(utils::isYuv(destWhf.format)) { - int yRauCount = aWidth / 64; //Y - int cRauCount = aWidth / 32; //C - int yStride = (64 * 4 * yRauCount) + alignup(yRauCount, 8) / 8; - int cStride = ((32 * 2 * cRauCount) + alignup(cRauCount, 8) / 8) * 2; - int yStrideOffset = (aHeight / 4); - int cStrideOffset = (aHeight / 2); - bufSize = (yStride * yStrideOffset + cStride * cStrideOffset) + - (yRauCount * yStrideOffset * 2) + - (cRauCount * cStrideOffset * 2) * 2; - ALOGD_IF(DEBUG_MDSS_ROT, "%s:YUV Y RAU Count = %d C RAU Count = %d", - __FUNCTION__, yRauCount, cRauCount); - } else { - int rauCount = aWidth / 32; - //Single plane - int stride = (32 * 4 * rauCount) + alignup(rauCount, 8) / 8; - int strideOffset = (aHeight / 4); - bufSize = (stride * strideOffset * 4 /*bpp*/) + - (rauCount * strideOffset * 2); - ALOGD_IF(DEBUG_MDSS_ROT, "%s:RGB RAU count = %d", __FUNCTION__, - rauCount); - } - - ALOGD_IF(DEBUG_MDSS_ROT, "%s: aligned width = %d, aligned height = %d " - "Buf Size = %d", __FUNCTION__, aWidth, aHeight, bufSize); - - return bufSize; -} - -int MdssRot::getDownscaleFactor(const int& srcW, const int& srcH, - const int& dstW, const int& dstH, const uint32_t& mdpFormat, - const bool& isInterlaced) { - if(not srcW or not srcH or not dstW or not dstH or isInterlaced) return 0; - - Dim crop(0, 0, srcW, srcH); - Dim adjCrop = getFormatAdjustedCrop(crop, mdpFormat, - false /*isInterlaced */); - - uint32_t downscale = min((adjCrop.w / dstW), (adjCrop.h / dstH)); - //Reduced to a power of 2 - downscale = (uint32_t) powf(2.0f, floorf(log2f((float)downscale))); - - if(downscale < 2 or downscale > 32) return 0; - - //Allow only 1 line or pixel to be chopped off since the source needs to - //be aligned to downscale. Progressively try with smaller downscale to see - //if we can satisfy the threshold - //For YUV the loop shouldnt be needed, unless in exceptional cases - Dim dsAdjCrop = getDownscaleAdjustedCrop(adjCrop, downscale); - while(downscale > 2 and (adjCrop.w > dsAdjCrop.w or - adjCrop.h > dsAdjCrop.h)) { - downscale /= 2; - dsAdjCrop = getDownscaleAdjustedCrop(adjCrop, downscale); - } - - if(not dsAdjCrop.w or not dsAdjCrop.h) return 0; - return downscale; -} - -Dim MdssRot::getFormatAdjustedCrop(const Dim& crop, - const uint32_t& mdpFormat, const bool& isInterlaced) { - Dim adjCrop = crop; - if (isYuv(mdpFormat)) { - normalizeCrop(adjCrop.x, adjCrop.w); - normalizeCrop(adjCrop.y, adjCrop.h); - // For interlaced, crop.h should be 4-aligned - if (isInterlaced and (adjCrop.h % 4)) - adjCrop.h = aligndown(adjCrop.h, 4); - } - return adjCrop; -} - -Dim MdssRot::getDownscaleAdjustedCrop(const Dim& crop, - const uint32_t& downscale) { - uint32_t alignedSrcW = aligndown(crop.w, downscale * 2); - uint32_t alignedSrcH = aligndown(crop.h, downscale * 2); - return Dim(crop.x, crop.y, alignedSrcW, alignedSrcH); -} - -} // namespace overlay diff --git a/msm8909/liboverlay/overlayMem.h b/msm8909/liboverlay/overlayMem.h deleted file mode 100644 index f0a19220..00000000 --- a/msm8909/liboverlay/overlayMem.h +++ /dev/null @@ -1,222 +0,0 @@ -/* -* Copyright (c) 2011, 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 OVERLAY_MEM_H -#define OVERLAY_MEM_H - -#include <sys/mman.h> -#include <fcntl.h> -#include <alloc_controller.h> -#include <memalloc.h> - -#include "gralloc_priv.h" -#include "overlayUtils.h" -#define SIZE_1M 0x00100000 - -namespace overlay { - -/* -* Holds base address, offset and the fd -* */ -class OvMem { -public: - /* ctor init*/ - explicit OvMem(); - - /* dtor DO NOT call close so it can be copied */ - ~OvMem(); - - /* Use libgralloc to retrieve fd, base addr, alloc type */ - bool open(uint32_t numbufs, - uint32_t bufSz, bool isSecure); - - /* close fd. assign base address to invalid*/ - bool close(); - - /* return underlying fd */ - int getFD() const; - - /* return true if fd is valid and base address is valid */ - bool valid() const; - - /* dump the state of the object */ - void dump() const; - - /* return underlying address */ - void* addr() const; - - /* return underlying offset */ - uint32_t bufSz() const; - - /* return number of bufs */ - uint32_t numBufs() const ; - -private: - /* actual os fd */ - int mFd; - - /* points to base addr (mmap)*/ - void* mBaseAddr; - - /* allocated buffer type determined by gralloc (ashmem, ion, etc) */ - int mAllocType; - - /* holds buf size sent down by the client */ - uint32_t mBufSz; - - /* num of bufs */ - uint32_t mNumBuffers; - - /* gralloc alloc controller */ - gralloc::IAllocController* mAlloc; - - /*Holds the aligned buffer size used for actual allocation*/ - uint32_t mBufSzAligned; -}; - -//-------------------Inlines----------------------------------- - -using gralloc::IMemAlloc; -using gralloc::alloc_data; - -inline OvMem::OvMem() { - mFd = -1; - mBaseAddr = MAP_FAILED; - mAllocType = 0; - mBufSz = 0; - mNumBuffers = 0; - mAlloc = gralloc::IAllocController::getInstance(); -} - -inline OvMem::~OvMem() { } - -inline bool OvMem::open(uint32_t numbufs, - uint32_t bufSz, bool isSecure) -{ - alloc_data data; - int allocFlags = GRALLOC_USAGE_PRIVATE_IOMMU_HEAP; - int err = 0; - OVASSERT(numbufs && bufSz, "numbufs=%d bufSz=%d", numbufs, bufSz); - mBufSz = bufSz; - - if(isSecure) { - allocFlags = GRALLOC_USAGE_PRIVATE_MM_HEAP; - allocFlags |= GRALLOC_USAGE_PROTECTED; - mBufSzAligned = utils::align(bufSz, SIZE_1M); - data.align = SIZE_1M; - } else { - mBufSzAligned = bufSz; - data.align = getpagesize(); - } - - // Allocate uncached rotator buffers - allocFlags |= GRALLOC_USAGE_PRIVATE_UNCACHED; - - mNumBuffers = numbufs; - - data.base = 0; - data.fd = -1; - data.offset = 0; - data.size = mBufSzAligned * mNumBuffers; - data.uncached = true; - - err = mAlloc->allocate(data, allocFlags); - if (err != 0) { - ALOGE("OvMem: Error allocating memory"); - return false; - } - - mFd = data.fd; - mBaseAddr = data.base; - mAllocType = data.allocType; - - return true; -} - -inline bool OvMem::close() -{ - int ret = 0; - - if(!valid()) { - return true; - } - - IMemAlloc* memalloc = mAlloc->getAllocator(mAllocType); - ret = memalloc->free_buffer(mBaseAddr, mBufSzAligned * mNumBuffers, 0, mFd); - if (ret != 0) { - ALOGE("OvMem: error freeing buffer"); - return false; - } - - mFd = -1; - mBaseAddr = MAP_FAILED; - mAllocType = 0; - mBufSz = 0; - mBufSzAligned = 0; - mNumBuffers = 0; - return true; -} - -inline bool OvMem::valid() const -{ - return (mFd != -1) && (mBaseAddr != MAP_FAILED); -} - -inline int OvMem::getFD() const -{ - return mFd; -} - -inline void* OvMem::addr() const -{ - return mBaseAddr; -} - -inline uint32_t OvMem::bufSz() const -{ - return mBufSz; -} - -inline uint32_t OvMem::numBufs() const -{ - return mNumBuffers; -} - -inline void OvMem::dump() const -{ - ALOGE("== Dump OvMem start =="); - ALOGE("fd=%d addr=%p type=%d bufsz=%u AlignedBufSz=%u", - mFd, mBaseAddr, mAllocType, mBufSz, mBufSzAligned); - ALOGE("== Dump OvMem end =="); -} - -} // overlay - -#endif // OVERLAY_MEM_H diff --git a/msm8909/liboverlay/overlayRotator.cpp b/msm8909/liboverlay/overlayRotator.cpp deleted file mode 100644 index b55f06ac..00000000 --- a/msm8909/liboverlay/overlayRotator.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. - * Not a Contribution, Apache license notifications and license are retained - * for attribution purposes only. - * - * 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 "overlayRotator.h" -#include "overlayUtils.h" -#include "mdp_version.h" -#include "sync/sync.h" -#include "gr.h" - -namespace ovutils = overlay::utils; - -namespace overlay { - -//============Rotator========================= - -Rotator::Rotator() { - char property[PROPERTY_VALUE_MAX]; - mRotCacheDisabled = false; - if((property_get("debug.rotcache.disable", property, NULL) > 0) && - (!strncmp(property, "1", PROPERTY_VALUE_MAX ) || - (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) { - /* Used in debugging to turnoff rotator caching */ - mRotCacheDisabled = true; - } -} - -Rotator::~Rotator() {} - -Rotator* Rotator::getRotator() { - int type = getRotatorHwType(); - if(type == TYPE_MDP) { - return new MdpRot(); //will do reset - } else if(type == TYPE_MDSS) { - return new MdssRot(); - } else { - ALOGE("%s Unknown h/w type %d", __FUNCTION__, type); - return NULL; - } -} - -int Rotator::getDownscaleFactor(const int& srcW, const int& srcH, - const int& dstW, const int& dstH, const uint32_t& mdpFormat, - const bool& isInterlaced) { - if(getRotatorHwType() == TYPE_MDSS) { - return MdssRot::getDownscaleFactor(srcW, srcH, dstW, dstH, - mdpFormat, isInterlaced); - } - return MdpRot::getDownscaleFactor(srcW, srcH, dstW, dstH, - mdpFormat, isInterlaced); -} - -uint32_t Rotator::calcOutputBufSize(const utils::Whf& destWhf) { - //dummy aligned w & h. - int alW = 0, alH = 0; - int halFormat = ovutils::getHALFormat(destWhf.format); - //A call into gralloc/memalloc - return getBufferSizeAndDimensions( - destWhf.w, destWhf.h, halFormat, alW, alH); -} - -int Rotator::getRotatorHwType() { - int mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion(); - if (mdpVersion == qdutils::MDSS_V5) - return TYPE_MDSS; - return TYPE_MDP; -} - -bool Rotator::isRotCached(int fd, uint32_t offset) const { - if(mRotCacheDisabled or rotConfChanged() or rotDataChanged(fd,offset)) - return false; - return true; -} - -bool Rotator::rotDataChanged(int fd, uint32_t offset) const { - /* fd and offset are the attributes of the current rotator input buffer. - * At this instance, getSrcMemId() and getSrcOffset() return the - * attributes of the previous rotator input buffer */ - if( (fd == getSrcMemId()) and (offset == getSrcOffset()) ) - return false; - return true; -} - -//============RotMem========================= - -bool RotMem::close() { - bool ret = true; - if(valid()) { - if(mem.close() == false) { - ALOGE("%s error in closing rot mem", __FUNCTION__); - ret = false; - } - } - return ret; -} - -RotMem::RotMem() : mCurrIndex(0) { - utils::memset0(mRotOffset); - for(int i = 0; i < ROT_NUM_BUFS; i++) { - mRelFence[i] = -1; - } -} - -RotMem::~RotMem() { - for(int i = 0; i < ROT_NUM_BUFS; i++) { - ::close(mRelFence[i]); - mRelFence[i] = -1; - } -} - -void RotMem::setCurrBufReleaseFd(const int& fence) { - int ret = 0; - - if(mRelFence[mCurrIndex] >= 0) { - //Wait for previous usage of this buffer to be over. - //Can happen if rotation takes > vsync and a fast producer. i.e queue - //happens in subsequent vsyncs either because content is 60fps or - //because the producer is hasty sometimes. - ret = sync_wait(mRelFence[mCurrIndex], 1000); - if(ret < 0) { - ALOGE("%s: sync_wait error!! error no = %d err str = %s", - __FUNCTION__, errno, strerror(errno)); - } - ::close(mRelFence[mCurrIndex]); - } - mRelFence[mCurrIndex] = fence; -} - -void RotMem::setPrevBufReleaseFd(const int& fence) { - uint32_t numRotBufs = mem.numBufs(); - uint32_t prevIndex = (mCurrIndex + numRotBufs - 1) % (numRotBufs); - - if(mRelFence[prevIndex] >= 0) { - /* No need of any wait as nothing will be written into this - * buffer by the rotator (this func is called when rotator is - * in cache mode) */ - ::close(mRelFence[prevIndex]); - } - - mRelFence[prevIndex] = fence; -} - -//============RotMgr========================= -RotMgr * RotMgr::sRotMgr = NULL; - -RotMgr* RotMgr::getInstance() { - if(sRotMgr == NULL) { - sRotMgr = new RotMgr(); - } - return sRotMgr; -} - -RotMgr::RotMgr() { - for(int i = 0; i < MAX_ROT_SESS; i++) { - mRot[i] = 0; - } - mUseCount = 0; - mRotDevFd = -1; -} - -RotMgr::~RotMgr() { - clear(); -} - -void RotMgr::configBegin() { - //Reset the number of objects used - mUseCount = 0; -} - -void RotMgr::configDone() { - //Remove the top most unused objects. Videos come and go. - for(int i = mUseCount; i < MAX_ROT_SESS; i++) { - if(mRot[i]) { - delete mRot[i]; - mRot[i] = 0; - } - } -} - -Rotator* RotMgr::getNext() { - //Return a rot object, creating one if necessary - overlay::Rotator *rot = NULL; - if(mUseCount >= MAX_ROT_SESS) { - ALOGW("%s, MAX rotator sessions reached, request rejected", __func__); - } else { - if(mRot[mUseCount] == NULL) - mRot[mUseCount] = overlay::Rotator::getRotator(); - rot = mRot[mUseCount++]; - } - return rot; -} - -void RotMgr::clear() { - //Brute force obj destruction, helpful in suspend. - for(int i = 0; i < MAX_ROT_SESS; i++) { - if(mRot[i]) { - delete mRot[i]; - mRot[i] = 0; - } - } - mUseCount = 0; - ::close(mRotDevFd); - mRotDevFd = -1; -} - -void RotMgr::getDump(char *buf, size_t len) { - for(int i = 0; i < MAX_ROT_SESS; i++) { - if(mRot[i]) { - mRot[i]->getDump(buf, len); - } - } - char str[4] = {'\0'}; - snprintf(str, 4, "\n"); - strlcat(buf, str, len); -} - -int RotMgr::getRotDevFd() { - if(mRotDevFd < 0 && Rotator::getRotatorHwType() == Rotator::TYPE_MDSS) { - mRotDevFd = ::open("/dev/graphics/fb0", O_RDWR, 0); - if(mRotDevFd < 0) { - ALOGE("%s failed to open fb0", __FUNCTION__); - } - } - return mRotDevFd; -} - -} diff --git a/msm8909/liboverlay/overlayRotator.h b/msm8909/liboverlay/overlayRotator.h deleted file mode 100644 index e045b440..00000000 --- a/msm8909/liboverlay/overlayRotator.h +++ /dev/null @@ -1,322 +0,0 @@ -/* -* Copyright (c) 2011,2013 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 OVERlAY_ROTATOR_H -#define OVERlAY_ROTATOR_H - -#include <stdlib.h> - -#include "mdpWrapper.h" -#include "overlayUtils.h" -#include "overlayMem.h" - -namespace overlay { - -/* - Manages the case where new rotator memory needs to be - allocated, before previous is freed, due to resolution change etc. If we make - rotator memory to be always max size, irrespctive of source resolution then - we don't need this RotMem wrapper. The inner class is sufficient. -*/ -struct RotMem { - // Max rotator buffers - enum { ROT_NUM_BUFS = 2 }; - RotMem(); - ~RotMem(); - bool close(); - bool valid() { return mem.valid(); } - uint32_t size() const { return mem.bufSz(); } - void setCurrBufReleaseFd(const int& fence); - void setPrevBufReleaseFd(const int& fence); - - // rotator data info dst offset - uint32_t mRotOffset[ROT_NUM_BUFS]; - int mRelFence[ROT_NUM_BUFS]; - // current slot being used - uint32_t mCurrIndex; - OvMem mem; -}; - -class Rotator -{ -public: - enum { TYPE_MDP, TYPE_MDSS }; - virtual ~Rotator(); - virtual void setSource(const utils::Whf& wfh) = 0; - virtual void setCrop(const utils::Dim& crop) = 0; - virtual void setFlags(const utils::eMdpFlags& flags) = 0; - virtual void setTransform(const utils::eTransform& rot) = 0; - virtual bool commit() = 0; - /* return true if the current rotator state is cached */ - virtual bool isRotCached(int fd, uint32_t offset) const; - /* return true if current rotator config is same as the last round*/ - virtual bool rotConfChanged() const = 0; - /* return true if the current rotator input buffer fd and offset - * are same as the last round */ - virtual bool rotDataChanged(int fd, uint32_t offset) const; - virtual void setDownscale(int ds) = 0; - /* returns the src buffer of the rotator for the previous/current round, - * depending on when it is called(before/after the queuebuffer)*/ - virtual int getSrcMemId() const = 0; - //Mem id and offset should be retrieved only after rotator kickoff - virtual int getDstMemId() const = 0; - virtual uint32_t getSrcOffset() const = 0; - virtual uint32_t getDstOffset() const = 0; - //Destination width, height, format, position should be retrieved only after - //rotator configuration is committed via commit API - virtual uint32_t getDstFormat() const = 0; - virtual utils::Whf getDstWhf() const = 0; - virtual utils::Dim getDstDimensions() const = 0; - virtual uint32_t getSessId() const = 0; - virtual bool queueBuffer(int fd, uint32_t offset) = 0; - virtual void dump() const = 0; - virtual void getDump(char *buf, size_t len) const = 0; - inline void setCurrBufReleaseFd(const int& fence) { - mMem.setCurrBufReleaseFd(fence); - } - inline void setPrevBufReleaseFd(const int& fence) { - mMem.setPrevBufReleaseFd(fence); - } - static Rotator *getRotator(); - /* Returns downscale by successfully applying constraints - * Returns 0 if target doesnt support rotator downscaling - * or if any of the constraints are not met - */ - static int getDownscaleFactor(const int& srcW, const int& srcH, - const int& dstW, const int& dstH, const uint32_t& mdpFormat, - const bool& isInterlaced); - -protected: - /* Rotator memory manager */ - RotMem mMem; - Rotator(); - static uint32_t calcOutputBufSize(const utils::Whf& destWhf); - -private: - bool mRotCacheDisabled; - /*Returns rotator h/w type */ - static int getRotatorHwType(); - friend class RotMgr; -}; - -/* -* MDP rot holds MDP's rotation related structures. -* -* */ -class MdpRot : public Rotator { -public: - virtual ~MdpRot(); - virtual void setSource(const utils::Whf& wfh); - virtual void setCrop(const utils::Dim& crop); - virtual void setFlags(const utils::eMdpFlags& flags); - virtual void setTransform(const utils::eTransform& rot); - virtual bool commit(); - virtual bool rotConfChanged() const; - virtual void setDownscale(int ds); - virtual int getSrcMemId() const; - virtual int getDstMemId() const; - virtual uint32_t getSrcOffset() const; - virtual uint32_t getDstOffset() const; - virtual uint32_t getDstFormat() const; - virtual utils::Whf getDstWhf() const; - virtual utils::Dim getDstDimensions() const; - virtual uint32_t getSessId() const; - virtual bool queueBuffer(int fd, uint32_t offset); - virtual void dump() const; - virtual void getDump(char *buf, size_t len) const; - -private: - explicit MdpRot(); - bool init(); - bool close(); - void setRotations(uint32_t r); - bool enabled () const; - /* remap rot buffers */ - bool remap(uint32_t numbufs); - bool open_i(uint32_t numbufs, uint32_t bufsz); - /* Deferred transform calculations */ - void doTransform(); - /* reset underlying data, basically memset 0 */ - void reset(); - /* save mRotImgInfo to be last known good config*/ - void save(); - /* Calculates the rotator's o/p buffer size post the transform calcs and - * knowing the o/p format depending on whether fastYuv is enabled or not */ - uint32_t calcOutputBufSize(); - - /* Applies downscale by taking areas - * Returns a log(downscale) - * Constraints applied: - * - downscale should be a power of 2 - * - Max downscale is 1/8 - */ - static int getDownscaleFactor(const int& srcW, const int& srcH, - const int& dstW, const int& dstH, const uint32_t& mdpFormat, - const bool& isInterlaced); - - /* rot info*/ - msm_rotator_img_info mRotImgInfo; - /* Last saved rot info*/ - msm_rotator_img_info mLSRotImgInfo; - /* rot data */ - msm_rotator_data_info mRotDataInfo; - /* Orientation */ - utils::eTransform mOrientation; - /* rotator fd */ - OvFD mFd; - - friend Rotator* Rotator::getRotator(); - friend int Rotator::getDownscaleFactor(const int& srcW, const int& srcH, - const int& dstW, const int& dstH, const uint32_t& mdpFormat, - const bool& isInterlaced); -}; - -/* -+* MDSS Rot holds MDSS's rotation related structures. -+* -+* */ -class MdssRot : public Rotator { -public: - virtual ~MdssRot(); - virtual void setSource(const utils::Whf& wfh); - virtual void setCrop(const utils::Dim& crop); - virtual void setFlags(const utils::eMdpFlags& flags); - virtual void setTransform(const utils::eTransform& rot); - virtual bool commit(); - virtual bool rotConfChanged() const; - virtual void setDownscale(int ds); - virtual int getSrcMemId() const; - virtual int getDstMemId() const; - virtual uint32_t getSrcOffset() const; - virtual uint32_t getDstOffset() const; - virtual uint32_t getDstFormat() const; - virtual utils::Whf getDstWhf() const; - virtual utils::Dim getDstDimensions() const; - virtual uint32_t getSessId() const; - virtual bool queueBuffer(int fd, uint32_t offset); - virtual void dump() const; - virtual void getDump(char *buf, size_t len) const; - -private: - explicit MdssRot(); - bool init(); - bool close(); - void setRotations(uint32_t r); - bool enabled () const; - /* remap rot buffers */ - bool remap(uint32_t numbufs); - bool open_i(uint32_t numbufs, uint32_t bufsz); - /* Deferred transform calculations */ - void doTransform(); - /* reset underlying data, basically memset 0 */ - void reset(); - /* save mRotInfo to be last known good config*/ - void save(); - /* Calculates the rotator's o/p buffer size post the transform calcs and - * knowing the o/p format depending on whether fastYuv is enabled or not */ - uint32_t calcOutputBufSize(); - // Calculate the compressed o/p buffer size for BWC - uint32_t calcCompressedBufSize(const utils::Whf& destWhf); - - /* Caller's responsibility to swap srcW, srcH if there is a 90 transform - * Returns actual downscale (not a log value) - * Constraints applied: - * - downscale should be a power of 2 - * - Max downscale is 1/32 - * - Equal downscale is applied in both directions - * - {srcW, srcH} mod downscale = 0 - * - Interlaced content is not supported - */ - static int getDownscaleFactor(const int& srcW, const int& srcH, - const int& dstW, const int& dstH, const uint32_t& mdpFormat, - const bool& isInterlaced); - - static utils::Dim getFormatAdjustedCrop(const utils::Dim& crop, - const uint32_t& mdpFormat, const bool& isInterlaced); - - static utils::Dim getDownscaleAdjustedCrop(const utils::Dim& crop, - const uint32_t& downscale); - - /* MdssRot info structure */ - mdp_overlay mRotInfo; - /* Last saved MdssRot info structure*/ - mdp_overlay mLSRotInfo; - /* MdssRot data structure */ - msmfb_overlay_data mRotData; - /* Orientation */ - utils::eTransform mOrientation; - /* rotator fd */ - OvFD mFd; - /* Enable/Disable Mdss Rot*/ - bool mEnabled; - int mDownscale; - - friend Rotator* Rotator::getRotator(); - friend int Rotator::getDownscaleFactor(const int& srcW, const int& srcH, - const int& dstW, const int& dstH, const uint32_t& mdpFormat, - const bool& isInterlaced); -}; - -// Holder of rotator objects. Manages lifetimes -class RotMgr { -public: - //Virtually we can support as many rotator sessions as possible, However - // more number of rotator sessions leads to performance issues, so - // restricting the max rotator session to 4 - enum { MAX_ROT_SESS = 4 }; - - ~RotMgr(); - void configBegin(); - void configDone(); - overlay::Rotator *getNext(); - void clear(); //Removes all instances - //Resets the usage of top count objects, making them available for reuse - void markUnusedTop(const uint32_t& count) { mUseCount -= count; } - /* Returns rot dump. - * Expects a NULL terminated buffer of big enough size. - */ - void getDump(char *buf, size_t len); - int getRotDevFd(); - int getNumActiveSessions() { return mUseCount; } - - static RotMgr *getInstance(); - -private: - RotMgr(); - static RotMgr *sRotMgr; - - overlay::Rotator *mRot[MAX_ROT_SESS]; - uint32_t mUseCount; - int mRotDevFd; -}; - - -} // overlay - -#endif // OVERlAY_ROTATOR_H diff --git a/msm8909/liboverlay/overlayUtils.cpp b/msm8909/liboverlay/overlayUtils.cpp deleted file mode 100644 index cbd52aed..00000000 --- a/msm8909/liboverlay/overlayUtils.cpp +++ /dev/null @@ -1,399 +0,0 @@ -/* -* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are -* met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above -* copyright notice, this list of conditions and the following -* disclaimer in the documentation and/or other materials provided -* with the distribution. -* * Neither the name of The Linux Foundation nor the names of its -* contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include <stdlib.h> -#include <math.h> -#include <utils/Log.h> -#include <linux/msm_mdp.h> -#include <cutils/properties.h> -#include "gralloc_priv.h" -#include "overlayUtils.h" -#include "mdpWrapper.h" -#include "mdp_version.h" -#include <hardware/hwcomposer_defs.h> - -// just a helper static thingy -namespace { -struct IOFile { - IOFile(const char* s, const char* mode) : fp(0) { - fp = ::fopen(s, mode); - if(!fp) { - ALOGE("Failed open %s", s); - } - } - template <class T> - size_t read(T& r, size_t elem) { - if(fp) { - return ::fread(&r, sizeof(T), elem, fp); - } - return 0; - } - size_t write(const char* s, uint32_t val) { - if(fp) { - return ::fprintf(fp, s, val); - } - return 0; - } - bool valid() const { return fp != 0; } - ~IOFile() { - if(fp) ::fclose(fp); - fp=0; - } - FILE* fp; -}; -} - -namespace overlay { - -//----------From class Res ------------------------------ -const char* const Res::fbPath = "/dev/graphics/fb%u"; -const char* const Res::rotPath = "/dev/msm_rotator"; -//-------------------------------------------------------- - - - -namespace utils { - -//-------------------------------------------------------- -//Refer to graphics.h, gralloc_priv.h, msm_mdp.h -int getMdpFormat(int format) { - switch (format) { - //From graphics.h - case HAL_PIXEL_FORMAT_RGBA_8888 : - return MDP_RGBA_8888; - case HAL_PIXEL_FORMAT_RGBX_8888: - return MDP_RGBX_8888; - case HAL_PIXEL_FORMAT_RGB_888: - return MDP_RGB_888; - case HAL_PIXEL_FORMAT_RGB_565: - return MDP_RGB_565; - case HAL_PIXEL_FORMAT_BGRA_8888: - return MDP_BGRA_8888; - case HAL_PIXEL_FORMAT_BGRX_8888: - return MDP_BGRX_8888; - case HAL_PIXEL_FORMAT_YV12: - return MDP_Y_CR_CB_GH2V2; - case HAL_PIXEL_FORMAT_YCbCr_422_SP: - return MDP_Y_CBCR_H2V1; - case HAL_PIXEL_FORMAT_YCrCb_420_SP: - return MDP_Y_CRCB_H2V2; - - //From gralloc_priv.h - case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: - return MDP_Y_CBCR_H2V2_TILE; - case HAL_PIXEL_FORMAT_YCbCr_420_SP: - return MDP_Y_CBCR_H2V2; - case HAL_PIXEL_FORMAT_YCrCb_422_SP: - return MDP_Y_CRCB_H2V1; - case HAL_PIXEL_FORMAT_YCbCr_422_I: - return MDP_YCBYCR_H2V1; - case HAL_PIXEL_FORMAT_YCrCb_422_I: - return MDP_YCRYCB_H2V1; - case HAL_PIXEL_FORMAT_YCbCr_444_SP: - return MDP_Y_CBCR_H1V1; - case HAL_PIXEL_FORMAT_YCrCb_444_SP: - return MDP_Y_CRCB_H1V1; - case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: - case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: - //NV12 encodeable format maps to the venus format on - //B-Family targets - return MDP_Y_CBCR_H2V2_VENUS; - default: - //Unsupported by MDP - //---graphics.h-------- - //HAL_PIXEL_FORMAT_RGBA_5551 - //HAL_PIXEL_FORMAT_RGBA_4444 - //---gralloc_priv.h----- - //HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO = 0x7FA30C01 - //HAL_PIXEL_FORMAT_R_8 = 0x10D - //HAL_PIXEL_FORMAT_RG_88 = 0x10E - ALOGE("%s: Unsupported HAL format = 0x%x", __func__, format); - return -1; - } - // not reached - return -1; -} - -// This function returns corresponding tile format -// MDSS support following RGB tile formats -// 32 bit formats -// 16 bit formats -int getMdpFormat(int format, bool tileEnabled) -{ - if(!tileEnabled) { - return getMdpFormat(format); - } - switch (format) { - case HAL_PIXEL_FORMAT_RGBA_8888 : - return MDP_RGBA_8888_TILE; - case HAL_PIXEL_FORMAT_RGBX_8888: - return MDP_RGBX_8888_TILE; - case HAL_PIXEL_FORMAT_RGB_565: - return MDP_RGB_565_TILE; - case HAL_PIXEL_FORMAT_BGRA_8888: - return MDP_BGRA_8888_TILE; - case HAL_PIXEL_FORMAT_BGRX_8888: - return MDP_BGRX_8888_TILE; - default: - return getMdpFormat(format); - } -} - - - -//Takes mdp format as input and translates to equivalent HAL format -//Refer to graphics.h, gralloc_priv.h, msm_mdp.h for formats. -int getHALFormat(int mdpFormat) { - switch (mdpFormat) { - //From graphics.h - case MDP_RGBA_8888: - return HAL_PIXEL_FORMAT_RGBA_8888; - case MDP_RGBX_8888: - return HAL_PIXEL_FORMAT_RGBX_8888; - case MDP_RGB_888: - return HAL_PIXEL_FORMAT_RGB_888; - case MDP_RGB_565: - return HAL_PIXEL_FORMAT_RGB_565; - case MDP_BGRA_8888: - return HAL_PIXEL_FORMAT_BGRA_8888; - case MDP_Y_CR_CB_GH2V2: - return HAL_PIXEL_FORMAT_YV12; - case MDP_Y_CBCR_H2V1: - return HAL_PIXEL_FORMAT_YCbCr_422_SP; - case MDP_Y_CRCB_H2V2: - return HAL_PIXEL_FORMAT_YCrCb_420_SP; - - //From gralloc_priv.h - case MDP_Y_CBCR_H2V2_TILE: - return HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED; - case MDP_Y_CBCR_H2V2: - return HAL_PIXEL_FORMAT_YCbCr_420_SP; - case MDP_Y_CRCB_H2V1: - return HAL_PIXEL_FORMAT_YCrCb_422_SP; - case MDP_YCBYCR_H2V1: - return HAL_PIXEL_FORMAT_YCbCr_422_I; - case MDP_YCRYCB_H2V1: - return HAL_PIXEL_FORMAT_YCrCb_422_I; - case MDP_Y_CBCR_H1V1: - return HAL_PIXEL_FORMAT_YCbCr_444_SP; - case MDP_Y_CRCB_H1V1: - return HAL_PIXEL_FORMAT_YCrCb_444_SP; - case MDP_Y_CBCR_H2V2_VENUS: - return HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS; - default: - ALOGE("%s: Unsupported MDP format = 0x%x", __func__, mdpFormat); - return -1; - } - // not reached - return -1; -} - -int getMdpOrient(eTransform rotation) { - int retTrans = 0; - bool trans90 = false; - int mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion(); - bool aFamily = (mdpVersion < qdutils::MDSS_V5); - - ALOGD_IF(DEBUG_OVERLAY, "%s: In rotation = %d", __FUNCTION__, rotation); - if(rotation & OVERLAY_TRANSFORM_ROT_90) { - retTrans |= MDP_ROT_90; - trans90 = true; - } - - if(rotation & OVERLAY_TRANSFORM_FLIP_H) { - if(trans90 && aFamily) { - //Swap for a-family, since its driver does 90 first - retTrans |= MDP_FLIP_UD; - } else { - retTrans |= MDP_FLIP_LR; - } - } - - if(rotation & OVERLAY_TRANSFORM_FLIP_V) { - if(trans90 && aFamily) { - //Swap for a-family, since its driver does 90 first - retTrans |= MDP_FLIP_LR; - } else { - retTrans |= MDP_FLIP_UD; - } - } - - ALOGD_IF(DEBUG_OVERLAY, "%s: Out rotation = %d", __FUNCTION__, retTrans); - return retTrans; -} - -void getDecimationFactor(const int& src_w, const int& src_h, - const int& dst_w, const int& dst_h, uint8_t& horzDeci, - uint8_t& vertDeci) { - horzDeci = 0; - vertDeci = 0; - float horDscale = ceilf((float)src_w / (float)dst_w); - float verDscale = ceilf((float)src_h / (float)dst_h); - qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance(); - - //Next power of 2, if not already - horDscale = powf(2.0f, ceilf(log2f(horDscale))); - verDscale = powf(2.0f, ceilf(log2f(verDscale))); - - //Since MDP can do downscale and has better quality, split the task - //between decimator and MDP downscale - horDscale /= (float)mdpHw.getMaxMDPDownscale(); - verDscale /= (float)mdpHw.getMaxMDPDownscale(); - - if((int)horDscale) - horzDeci = (uint8_t)log2f(horDscale); - - if((int)verDscale) - vertDeci = (uint8_t)log2f(verDscale); - - if(src_w > (int) mdpHw.getMaxMixerWidth()) { - //If the client sends us something > what a layer mixer supports - //then it means it doesn't want to use split-pipe but wants us to - //decimate. A minimum decimation of 2 will ensure that the width is - //always within layer mixer limits. - if(horzDeci < 2) - horzDeci = 2; - } -} - -static inline int compute(const uint32_t& x, const uint32_t& y, - const uint32_t& z) { - return x - ( y + z ); -} - -void preRotateSource(const eTransform& tr, Whf& whf, Dim& srcCrop) { - if(tr & OVERLAY_TRANSFORM_FLIP_H) { - srcCrop.x = compute(whf.w, srcCrop.x, srcCrop.w); - } - if(tr & OVERLAY_TRANSFORM_FLIP_V) { - srcCrop.y = compute(whf.h, srcCrop.y, srcCrop.h); - } - if(tr & OVERLAY_TRANSFORM_ROT_90) { - int tmp = srcCrop.x; - srcCrop.x = compute(whf.h, - srcCrop.y, - srcCrop.h); - srcCrop.y = tmp; - swap(whf.w, whf.h); - swap(srcCrop.w, srcCrop.h); - } -} - -void getDump(char *buf, size_t len, const char *prefix, - const mdp_overlay& ov) { - char str[256] = {'\0'}; - snprintf(str, 256, - "%s id=%d z=%d alpha=%d mask=%d flags=0x%x H.Deci=%d," - "V.Deci=%d\n", - prefix, ov.id, ov.z_order, ov.alpha, - ov.transp_mask, ov.flags, ov.horz_deci, ov.vert_deci); - strlcat(buf, str, len); - getDump(buf, len, "\tsrc", ov.src); - getDump(buf, len, "\tsrc_rect", ov.src_rect); - getDump(buf, len, "\tdst_rect", ov.dst_rect); -} - -void getDump(char *buf, size_t len, const char *prefix, - const msmfb_img& ov) { - char str_src[256] = {'\0'}; - snprintf(str_src, 256, - "%s w=%d h=%d format=%d %s\n", - prefix, ov.width, ov.height, ov.format, - overlay::utils::getFormatString(ov.format)); - strlcat(buf, str_src, len); -} - -void getDump(char *buf, size_t len, const char *prefix, - const mdp_rect& ov) { - char str_rect[256] = {'\0'}; - snprintf(str_rect, 256, - "%s x=%d y=%d w=%d h=%d\n", - prefix, ov.x, ov.y, ov.w, ov.h); - strlcat(buf, str_rect, len); -} - -void getDump(char *buf, size_t len, const char *prefix, - const msmfb_overlay_data& ov) { - char str[256] = {'\0'}; - snprintf(str, 256, - "%s id=%d\n", - prefix, ov.id); - strlcat(buf, str, len); - getDump(buf, len, "\tdata", ov.data); -} - -void getDump(char *buf, size_t len, const char *prefix, - const msmfb_data& ov) { - char str_data[256] = {'\0'}; - snprintf(str_data, 256, - "%s offset=%d memid=%d id=%d flags=0x%x\n", - prefix, ov.offset, ov.memory_id, ov.id, ov.flags); - strlcat(buf, str_data, len); -} - -void getDump(char *buf, size_t len, const char *prefix, - const msm_rotator_img_info& rot) { - char str[256] = {'\0'}; - snprintf(str, 256, "%s sessid=%u rot=%d, enable=%d downscale=%d\n", - prefix, rot.session_id, rot.rotations, rot.enable, - rot.downscale_ratio); - strlcat(buf, str, len); - getDump(buf, len, "\tsrc", rot.src); - getDump(buf, len, "\tdst", rot.dst); - getDump(buf, len, "\tsrc_rect", rot.src_rect); -} - -void getDump(char *buf, size_t len, const char *prefix, - const msm_rotator_data_info& rot) { - char str[256] = {'\0'}; - snprintf(str, 256, - "%s sessid=%u\n", - prefix, rot.session_id); - strlcat(buf, str, len); - getDump(buf, len, "\tsrc", rot.src); - getDump(buf, len, "\tdst", rot.dst); -} - -//Helper to even out x,w and y,h pairs -//x,y are always evened to ceil and w,h are evened to floor -void normalizeCrop(uint32_t& xy, uint32_t& wh) { - if(xy & 1) { - even_ceil(xy); - if(wh & 1) - even_floor(wh); - else - wh -= 2; - } else { - even_floor(wh); - } -} - -} // utils - -} // overlay diff --git a/msm8909/liboverlay/overlayUtils.h b/msm8909/liboverlay/overlayUtils.h deleted file mode 100644 index 2b8e3030..00000000 --- a/msm8909/liboverlay/overlayUtils.h +++ /dev/null @@ -1,683 +0,0 @@ -/* -* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are -* met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above -* copyright notice, this list of conditions and the following -* disclaimer in the documentation and/or other materials provided -* with the distribution. -* * Neither the name of The Linux Foundation nor the names of its -* contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef OVERLAY_UTILS_H -#define OVERLAY_UTILS_H - -#include <cutils/log.h> // ALOGE, etc -#include <errno.h> -#include <fcntl.h> // open, O_RDWR, etc -#include <hardware/hardware.h> -#include <hardware/gralloc.h> // buffer_handle_t -#include <linux/msm_mdp.h> // flags -#include <linux/msm_rotator.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <utils/Log.h> -#include "gralloc_priv.h" //for interlace - -// Older platforms do not support Venus -#ifndef VENUS_COLOR_FORMAT -#define MDP_Y_CBCR_H2V2_VENUS MDP_IMGTYPE_LIMIT -#endif - -/* -* -* Collection of utilities functions/structs/enums etc... -* -* */ - -// comment that out if you want to remove asserts -// or put it as -D in Android.mk. your choice. -#define OVERLAY_HAS_ASSERT - -#ifdef OVERLAY_HAS_ASSERT -# define OVASSERT(x, ...) if(!(x)) { ALOGE(__VA_ARGS__); abort(); } -#else -# define OVASSERT(x, ...) ALOGE_IF(!(x), __VA_ARGS__) -#endif // OVERLAY_HAS_ASSERT - -#define DEBUG_OVERLAY 0 -#define PROFILE_OVERLAY 0 - -#ifndef MDSS_MDP_RIGHT_MIXER -#define MDSS_MDP_RIGHT_MIXER 0x100 -#endif - -#ifndef MDP_OV_PIPE_FORCE_DMA -#define MDP_OV_PIPE_FORCE_DMA 0x4000 -#endif - -#ifndef MDSS_MDP_DUAL_PIPE -#define MDSS_MDP_DUAL_PIPE 0x200 -#endif - -#define FB_DEVICE_TEMPLATE "/dev/graphics/fb%u" - -namespace overlay { - -// fwd -class Overlay; -class OvFD; - -/* helper function to open by using fbnum */ -bool open(OvFD& fd, uint32_t fbnum, const char* const dev, - int flags = O_RDWR); - -namespace utils { -struct Whf; -struct Dim; - -inline uint32_t setBit(uint32_t x, uint32_t mask) { - return (x | mask); -} - -inline uint32_t clrBit(uint32_t x, uint32_t mask) { - return (x & ~mask); -} - -/* Utility class to help avoid copying instances by making the copy ctor -* and assignment operator private -* -* Usage: -* class SomeClass : utils::NoCopy {...}; -*/ -class NoCopy { -protected: - NoCopy(){} - ~NoCopy() {} -private: - NoCopy(const NoCopy&); - const NoCopy& operator=(const NoCopy&); -}; - -bool isMdssRotator(); -void normalizeCrop(uint32_t& xy, uint32_t& wh); - -template <class Type> -void swapWidthHeight(Type& width, Type& height); - -struct Dim { - Dim () : x(0), y(0), - w(0), h(0), - o(0) {} - Dim(uint32_t _x, uint32_t _y, uint32_t _w, uint32_t _h) : - x(_x), y(_y), - w(_w), h(_h) {} - Dim(uint32_t _x, uint32_t _y, uint32_t _w, uint32_t _h, uint32_t _o) : - x(_x), y(_y), - w(_w), h(_h), - o(_o) {} - bool check(uint32_t _w, uint32_t _h) const { - return (x+w <= _w && y+h <= _h); - - } - - bool operator==(const Dim& d) const { - return d.x == x && d.y == y && - d.w == w && d.h == h && - d.o == o; - } - - bool operator!=(const Dim& d) const { - return !operator==(d); - } - - void dump() const; - uint32_t x; - uint32_t y; - uint32_t w; - uint32_t h; - uint32_t o; -}; - -// TODO have Whfz - -struct Whf { - Whf() : w(0), h(0), format(0), size(0) {} - Whf(uint32_t wi, uint32_t he, uint32_t f) : - w(wi), h(he), format(f), size(0) {} - Whf(uint32_t wi, uint32_t he, uint32_t f, uint32_t s) : - w(wi), h(he), format(f), size(s) {} - // FIXME not comparing size at the moment - bool operator==(const Whf& whf) const { - return whf.w == w && whf.h == h && - whf.format == format; - } - bool operator!=(const Whf& whf) const { - return !operator==(whf); - } - void dump() const; - uint32_t w; - uint32_t h; - uint32_t format; - uint32_t size; -}; - -enum { MAX_PATH_LEN = 256 }; - -enum { DEFAULT_PLANE_ALPHA = 0xFF }; - -/** - * Rotator flags: not to be confused with orientation flags. - * Usually, you want to open the rotator to make sure it is - * ready for business. - * */ - enum eRotFlags { - ROT_FLAGS_NONE = 0, - //Use rotator for 0 rotation. It is used anyway for others. - ROT_0_ENABLED = 1 << 0, - //Enable rotator downscale optimization for hardware bugs not handled in - //driver. If downscale optimizatation is required, - //then rotator will be used even if its 0 rotation case. - ROT_DOWNSCALE_ENABLED = 1 << 1, - ROT_PREROTATED = 1 << 2, -}; - -enum eRotDownscale { - ROT_DS_NONE = 0, - ROT_DS_HALF = 1, - ROT_DS_FOURTH = 2, - ROT_DS_EIGHTH = 3, -}; - -/* - * Various mdp flags like PIPE SHARE, DEINTERLACE etc... - * kernel/common/linux/msm_mdp.h - * INTERLACE_MASK: hardware/qcom/display/libgralloc/badger/fb_priv.h - * */ -enum eMdpFlags { - OV_MDP_FLAGS_NONE = 0, - OV_MDP_PIPE_SHARE = MDP_OV_PIPE_SHARE, - OV_MDP_PIPE_FORCE_DMA = MDP_OV_PIPE_FORCE_DMA, - OV_MDP_DEINTERLACE = MDP_DEINTERLACE, - OV_MDP_SECURE_OVERLAY_SESSION = MDP_SECURE_OVERLAY_SESSION, - OV_MDP_SECURE_DISPLAY_OVERLAY_SESSION = MDP_SECURE_DISPLAY_OVERLAY_SESSION, - OV_MDP_SOURCE_ROTATED_90 = MDP_SOURCE_ROTATED_90, - OV_MDP_BACKEND_COMPOSITION = MDP_BACKEND_COMPOSITION, - OV_MDP_BLEND_FG_PREMULT = MDP_BLEND_FG_PREMULT, - OV_MDP_FLIP_H = MDP_FLIP_LR, - OV_MDP_FLIP_V = MDP_FLIP_UD, - OV_MDSS_MDP_RIGHT_MIXER = MDSS_MDP_RIGHT_MIXER, - OV_MDP_PP_EN = MDP_OVERLAY_PP_CFG_EN, - OV_MDSS_MDP_BWC_EN = MDP_BWC_EN, - OV_MDSS_MDP_DUAL_PIPE = MDSS_MDP_DUAL_PIPE, - OV_MDP_SOLID_FILL = MDP_SOLID_FILL, -}; - -enum eZorder { - ZORDER_0 = 0, - ZORDER_1, - ZORDER_2, - ZORDER_3, - Z_SYSTEM_ALLOC = 0xFFFF -}; - -enum eMdpPipeType { - OV_MDP_PIPE_RGB = 0, - OV_MDP_PIPE_VG, - OV_MDP_PIPE_DMA, - OV_MDP_PIPE_ANY, //Any -}; - -// Identify destination pipes -// TODO Names useless, replace with int and change all interfaces -enum eDest { - OV_P0 = 0, - OV_P1, - OV_P2, - OV_P3, - OV_P4, - OV_P5, - OV_P6, - OV_P7, - OV_P8, - OV_P9, - OV_INVALID, - OV_MAX = OV_INVALID, -}; - -/* Used when a buffer is split over 2 pipes and sent to display */ -enum { - OV_LEFT_SPLIT = 0, - OV_RIGHT_SPLIT, -}; - -/* values for copybit_set_parameter(OVERLAY_TRANSFORM) */ -enum eTransform { - /* No rot */ - OVERLAY_TRANSFORM_0 = 0x0, - /* flip source image horizontally 0x1 */ - OVERLAY_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H, - /* flip source image vertically 0x2 */ - OVERLAY_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V, - /* rotate source image 180 degrees - * It is basically bit-or-ed H | V == 0x3 */ - OVERLAY_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180, - /* rotate source image 90 degrees 0x4 */ - OVERLAY_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90, - /* rotate source image 90 degrees and flip horizontally 0x5 */ - OVERLAY_TRANSFORM_ROT_90_FLIP_H = HAL_TRANSFORM_ROT_90 | - HAL_TRANSFORM_FLIP_H, - /* rotate source image 90 degrees and flip vertically 0x6 */ - OVERLAY_TRANSFORM_ROT_90_FLIP_V = HAL_TRANSFORM_ROT_90 | - HAL_TRANSFORM_FLIP_V, - /* rotate source image 270 degrees - * Basically 180 | 90 == 0x7 */ - OVERLAY_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270, - /* rotate invalid like in Transform.h */ - OVERLAY_TRANSFORM_INV = 0x80 -}; - -enum eBlending { - OVERLAY_BLENDING_UNDEFINED = 0x0, - /* No blending */ - OVERLAY_BLENDING_OPAQUE, - /* src.rgb + dst.rgb*(1-src_alpha) */ - OVERLAY_BLENDING_PREMULT, - /* src.rgb * src_alpha + dst.rgb (1 - src_alpha) */ - OVERLAY_BLENDING_COVERAGE, -}; - -// Used to consolidate pipe params -struct PipeArgs { - PipeArgs() : mdpFlags(OV_MDP_FLAGS_NONE), - zorder(Z_SYSTEM_ALLOC), - rotFlags(ROT_FLAGS_NONE), - planeAlpha(DEFAULT_PLANE_ALPHA), - blending(OVERLAY_BLENDING_COVERAGE){ - } - - PipeArgs(eMdpFlags f, Whf _whf, - eZorder z, eRotFlags r, - int pA = DEFAULT_PLANE_ALPHA, eBlending b = OVERLAY_BLENDING_COVERAGE) : - mdpFlags(f), - whf(_whf), - zorder(z), - rotFlags(r), - planeAlpha(pA), - blending(b){ - } - - eMdpFlags mdpFlags; // for mdp_overlay flags - Whf whf; - eZorder zorder; // stage number - eRotFlags rotFlags; - int planeAlpha; - eBlending blending; -}; - -// Cannot use HW_OVERLAY_MAGNIFICATION_LIMIT, since at the time -// of integration, HW_OVERLAY_MAGNIFICATION_LIMIT was a define -enum { HW_OV_MAGNIFICATION_LIMIT = 20, - HW_OV_MINIFICATION_LIMIT = 8 -}; - -inline void setMdpFlags(eMdpFlags& f, eMdpFlags v) { - f = static_cast<eMdpFlags>(setBit(f, v)); -} - -inline void clearMdpFlags(eMdpFlags& f, eMdpFlags v) { - f = static_cast<eMdpFlags>(clrBit(f, v)); -} - -enum { FB0, FB1, FB2 }; - -struct ScreenInfo { - ScreenInfo() : mFBWidth(0), - mFBHeight(0), - mFBbpp(0), - mFBystride(0) {} - void dump(const char* const s) const; - uint32_t mFBWidth; - uint32_t mFBHeight; - uint32_t mFBbpp; - uint32_t mFBystride; -}; - -int getMdpFormat(int format); -int getMdpFormat(int format, bool tileEnabled); -int getHALFormat(int mdpFormat); -void getDecimationFactor(const int& src_w, const int& src_h, - const int& dst_w, const int& dst_h, uint8_t& horzDeci, - uint8_t& vertDeci); - -/* flip is upside down and such. V, H flip - * rotation is 90, 180 etc - * It returns MDP related enum/define that match rot+flip*/ -int getMdpOrient(eTransform rotation); -const char* getFormatString(int format); - -template <class T> -inline void memset0(T& t) { ::memset(&t, 0, sizeof(t)); } - -template <class T> inline void swap ( T& a, T& b ) -{ - T c(a); a=b; b=c; -} - -template<typename T> inline T max(T a, T b) { return (a > b) ? a : b; } - -template<typename T> inline T min(T a, T b) { return (a < b) ? a : b; } - -inline int alignup(int value, int a) { - //if align = 0, return the value. Else, do alignment. - return a ? ((((value - 1) / a) + 1) * a) : value; -} - -inline int aligndown(int value, int a) { - //if align = 0, return the value. Else, do alignment. - return a ? ((value) & ~(a-1)) : value; -} - -// FIXME that align should replace the upper one. -inline int align(int value, int a) { - //if align = 0, return the value. Else, do alignment. - return a ? ((value + (a-1)) & ~(a-1)) : value; -} - -inline bool isYuv(uint32_t format) { - switch(format){ - case MDP_Y_CBCR_H2V1: - case MDP_Y_CBCR_H2V2: - case MDP_Y_CRCB_H2V2: - case MDP_Y_CRCB_H1V1: - case MDP_Y_CRCB_H2V1: - case MDP_Y_CRCB_H2V2_TILE: - case MDP_Y_CBCR_H2V2_TILE: - case MDP_Y_CR_CB_H2V2: - case MDP_Y_CR_CB_GH2V2: - case MDP_Y_CBCR_H2V2_VENUS: - case MDP_YCBYCR_H2V1: - case MDP_YCRYCB_H2V1: - return true; - default: - return false; - } - return false; -} - -inline bool isRgb(uint32_t format) { - switch(format) { - case MDP_RGBA_8888: - case MDP_BGRA_8888: - case MDP_RGBX_8888: - case MDP_RGB_565: - return true; - default: - return false; - } - return false; -} - -inline const char* getFormatString(int format){ - #define STR(f) #f; - static const char* formats[MDP_IMGTYPE_LIMIT + 1] = {0}; - formats[MDP_RGB_565] = STR(MDP_RGB_565); - formats[MDP_XRGB_8888] = STR(MDP_XRGB_8888); - formats[MDP_Y_CBCR_H2V2] = STR(MDP_Y_CBCR_H2V2); - formats[MDP_Y_CBCR_H2V2_ADRENO] = STR(MDP_Y_CBCR_H2V2_ADRENO); - formats[MDP_ARGB_8888] = STR(MDP_ARGB_8888); - formats[MDP_RGB_888] = STR(MDP_RGB_888); - formats[MDP_Y_CRCB_H2V2] = STR(MDP_Y_CRCB_H2V2); - formats[MDP_YCBYCR_H2V1] = STR(MDP_YCBYCR_H2V1); - formats[MDP_YCRYCB_H2V1] = STR(MDP_YCRYCB_H2V1); - formats[MDP_CBYCRY_H2V1] = STR(MDP_CBYCRY_H2V1); - formats[MDP_Y_CRCB_H2V1] = STR(MDP_Y_CRCB_H2V1); - formats[MDP_Y_CBCR_H2V1] = STR(MDP_Y_CBCR_H2V1); - formats[MDP_Y_CRCB_H1V2] = STR(MDP_Y_CRCB_H1V2); - formats[MDP_Y_CBCR_H1V2] = STR(MDP_Y_CBCR_H1V2); - formats[MDP_RGBA_8888] = STR(MDP_RGBA_8888); - formats[MDP_BGRA_8888] = STR(MDP_BGRA_8888); - formats[MDP_RGBX_8888] = STR(MDP_RGBX_8888); - formats[MDP_Y_CRCB_H2V2_TILE] = STR(MDP_Y_CRCB_H2V2_TILE); - formats[MDP_Y_CBCR_H2V2_TILE] = STR(MDP_Y_CBCR_H2V2_TILE); - formats[MDP_Y_CR_CB_H2V2] = STR(MDP_Y_CR_CB_H2V2); - formats[MDP_Y_CR_CB_GH2V2] = STR(MDP_Y_CR_CB_GH2V2); - formats[MDP_Y_CB_CR_H2V2] = STR(MDP_Y_CB_CR_H2V2); - formats[MDP_Y_CRCB_H1V1] = STR(MDP_Y_CRCB_H1V1); - formats[MDP_Y_CBCR_H1V1] = STR(MDP_Y_CBCR_H1V1); - formats[MDP_YCRCB_H1V1] = STR(MDP_YCRCB_H1V1); - formats[MDP_YCBCR_H1V1] = STR(MDP_YCBCR_H1V1); - formats[MDP_BGR_565] = STR(MDP_BGR_565); - formats[MDP_BGR_888] = STR(MDP_BGR_888); - formats[MDP_Y_CBCR_H2V2_VENUS] = STR(MDP_Y_CBCR_H2V2_VENUS); - formats[MDP_BGRX_8888] = STR(MDP_BGRX_8888); - formats[MDP_RGBA_8888_TILE] = STR(MDP_RGBA_8888_TILE); - formats[MDP_ARGB_8888_TILE] = STR(MDP_ARGB_8888_TILE); - formats[MDP_ABGR_8888_TILE] = STR(MDP_ABGR_8888_TILE); - formats[MDP_BGRA_8888_TILE] = STR(MDP_BGRA_8888_TILE); - formats[MDP_RGBX_8888_TILE] = STR(MDP_RGBX_8888_TILE); - formats[MDP_XRGB_8888_TILE] = STR(MDP_XRGB_8888_TILE); - formats[MDP_XBGR_8888_TILE] = STR(MDP_XBGR_8888_TILE); - formats[MDP_BGRX_8888_TILE] = STR(MDP_BGRX_8888_TILE); - formats[MDP_RGB_565_TILE] = STR(MDP_RGB_565_TILE); - formats[MDP_IMGTYPE_LIMIT] = STR(MDP_IMGTYPE_LIMIT); - - if(format < 0 || format >= MDP_IMGTYPE_LIMIT) { - ALOGE("%s wrong fmt %d", __FUNCTION__, format); - return "Unsupported format"; - } - if(formats[format] == 0) { - ALOGE("%s: table missing format %d from header", __FUNCTION__, format); - return ""; - } - return formats[format]; -} - -inline void Whf::dump() const { - ALOGE("== Dump WHF w=%d h=%d f=%d s=%d start/end ==", - w, h, format, size); -} - -inline void Dim::dump() const { - ALOGE("== Dump Dim x=%d y=%d w=%d h=%d start/end ==", x, y, w, h); -} - -template <class Type> -void swapWidthHeight(Type& width, Type& height) { - Type tmp = width; - width = height; - height = tmp; -} - -inline void ScreenInfo::dump(const char* const s) const { - ALOGE("== Dump %s ScreenInfo w=%d h=%d" - " bpp=%d stride=%d start/end ==", - s, mFBWidth, mFBHeight, mFBbpp, mFBystride); -} - -inline bool openDev(OvFD& fd, int fbnum, - const char* const devpath, int flags) { - return overlay::open(fd, fbnum, devpath, flags); -} - -template <class T> -inline void even_ceil(T& value) { - if(value & 1) - value++; -} - -template <class T> -inline void even_floor(T& value) { - if(value & 1) - value--; -} - -/* Prerotation adjusts crop co-ordinates to the new transformed values within - * destination buffer. This is necessary only when the entire buffer is rotated - * irrespective of crop (A-family). If only the crop portion of the buffer is - * rotated into a destination buffer matching the size of crop, we don't need to - * use this helper (B-family). - * @Deprecated as of now, retained for the case where a full buffer needs - * transform and also as a reference. - */ -void preRotateSource(const eTransform& tr, Whf& whf, Dim& srcCrop); -void getDump(char *buf, size_t len, const char *prefix, const mdp_overlay& ov); -void getDump(char *buf, size_t len, const char *prefix, const msmfb_img& ov); -void getDump(char *buf, size_t len, const char *prefix, const mdp_rect& ov); -void getDump(char *buf, size_t len, const char *prefix, - const msmfb_overlay_data& ov); -void getDump(char *buf, size_t len, const char *prefix, const msmfb_data& ov); -void getDump(char *buf, size_t len, const char *prefix, - const msm_rotator_img_info& ov); -void getDump(char *buf, size_t len, const char *prefix, - const msm_rotator_data_info& ov); - -} // namespace utils ends - -//--------------------Class Res stuff (namespace overlay only) ----------- - -class Res { -public: - // /dev/graphics/fb%u - static const char* const fbPath; - // /dev/msm_rotator - static const char* const rotPath; -}; - - -//--------------------Class OvFD stuff (namespace overlay only) ----------- - -/* -* Holds one FD -* Dtor will NOT close the underlying FD. -* That enables us to copy that object around -* */ -class OvFD { -public: - /* Ctor */ - explicit OvFD(); - - /* dtor will NOT close the underlying FD */ - ~OvFD(); - - /* Open fd using the path given by dev. - * return false in failure */ - bool open(const char* const dev, - int flags = O_RDWR); - - /* populate path */ - void setPath(const char* const dev); - - /* Close fd if we have a valid fd. */ - bool close(); - - /* returns underlying fd.*/ - int getFD() const; - - /* returns true if fd is valid */ - bool valid() const; - - /* like operator= */ - void copy(int fd); - - /* dump the state of the instance */ - void dump() const; -private: - /* helper enum for determine valid/invalid fd */ - enum { INVAL = -1 }; - - /* actual os fd */ - int mFD; - - /* path, for debugging */ - char mPath[utils::MAX_PATH_LEN]; -}; - -//-------------------Inlines-------------------------- - -inline bool open(OvFD& fd, uint32_t fbnum, const char* const dev, int flags) -{ - char dev_name[64] = {0}; - snprintf(dev_name, sizeof(dev_name), dev, fbnum); - return fd.open(dev_name, flags); -} - -inline OvFD::OvFD() : mFD (INVAL) { - mPath[0] = 0; -} - -inline OvFD::~OvFD() { - //no op since copy() can be used to share fd, in 3d cases. -} - -inline bool OvFD::open(const char* const dev, int flags) -{ - mFD = ::open(dev, flags, 0); - if (mFD < 0) { - // FIXME errno, strerror in bionic? - ALOGE("Cant open device %s err=%d", dev, errno); - return false; - } - setPath(dev); - return true; -} - -inline void OvFD::setPath(const char* const dev) -{ - ::strlcpy(mPath, dev, sizeof(mPath)); -} - -inline bool OvFD::close() -{ - int ret = 0; - if(valid()) { - ret = ::close(mFD); - mFD = INVAL; - } - return (ret == 0); -} - -inline bool OvFD::valid() const -{ - return (mFD != INVAL); -} - -inline int OvFD::getFD() const { return mFD; } - -inline void OvFD::copy(int fd) { - mFD = fd; -} - -inline void OvFD::dump() const -{ - ALOGE("== Dump OvFD fd=%d path=%s start/end ==", - mFD, mPath); -} - -//--------------- class OvFD stuff ends --------------------- - -} // overlay - - -#endif // OVERLAY_UTILS_H diff --git a/msm8909/liboverlay/overlayWriteback.cpp b/msm8909/liboverlay/overlayWriteback.cpp deleted file mode 100644 index ed42a9f0..00000000 --- a/msm8909/liboverlay/overlayWriteback.cpp +++ /dev/null @@ -1,280 +0,0 @@ -/* -* Copyright (c) 2013 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 "overlay.h" -#include "overlayWriteback.h" -#include "mdpWrapper.h" - -#define SIZE_1M 0x00100000 - -namespace overlay { - -//=========== class WritebackMem ============================================== -bool WritebackMem::manageMem(uint32_t size, bool isSecure) { - if(mBuf.bufSz() == size) { - return true; - } - if(mBuf.valid()) { - if(!mBuf.close()) { - ALOGE("%s error closing mem", __func__); - return false; - } - } - return alloc(size, isSecure); -} - -bool WritebackMem::alloc(uint32_t size, bool isSecure) { - if(!mBuf.open(NUM_BUFS, size, isSecure)){ - ALOGE("%s: Failed to open", __func__); - mBuf.close(); - return false; - } - - OVASSERT(MAP_FAILED != mBuf.addr(), "MAP failed"); - OVASSERT(mBuf.getFD() != -1, "getFd is -1"); - - mCurrOffsetIndex = 0; - for (uint32_t i = 0; i < NUM_BUFS; i++) { - mOffsets[i] = i * size; - } - return true; -} - -bool WritebackMem::dealloc() { - bool ret = true; - if(mBuf.valid()) { - ret = mBuf.close(); - } - return ret; -} - -//=========== class Writeback ================================================= -Writeback::Writeback() : mXres(0), mYres(0), mOpFmt(-1), mSecure(false) { - int fbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK); - if(!utils::openDev(mFd, fbNum, Res::fbPath, O_RDWR)) { - ALOGE("%s failed to init %s", __func__, Res::fbPath); - return; - } - startSession(); -} - -Writeback::~Writeback() { - stopSession(); - if (!mFd.close()) { - ALOGE("%s error closing fd", __func__); - } -} - -bool Writeback::startSession() { - if(!mdp_wrapper::wbInitStart(mFd.getFD())) { - ALOGE("%s failed", __func__); - return false; - } - return true; -} - -bool Writeback::stopSession() { - if(mFd.valid()) { - if(!Overlay::displayCommit(mFd.getFD())) { - ALOGE("%s: displayCommit failed", __func__); - return false; - } - if(!mdp_wrapper::wbStopTerminate(mFd.getFD())) { - ALOGE("%s: wbStopTerminate failed", __func__); - return false; - } - } else { - ALOGE("%s Invalid fd", __func__); - return false; - } - return true; -} - -bool Writeback::configureDpyInfo(int xres, int yres) { - if(mXres != xres || mYres != yres) { - fb_var_screeninfo vinfo; - memset(&vinfo, 0, sizeof(fb_var_screeninfo)); - if(!mdp_wrapper::getVScreenInfo(mFd.getFD(), vinfo)) { - ALOGE("%s failed", __func__); - return false; - } - vinfo.xres = xres; - vinfo.yres = yres; - vinfo.xres_virtual = xres; - vinfo.yres_virtual = yres; - vinfo.xoffset = 0; - vinfo.yoffset = 0; - if(!mdp_wrapper::setVScreenInfo(mFd.getFD(), vinfo)) { - ALOGE("%s failed", __func__); - return false; - } - mXres = xres; - mYres = yres; - } - return true; -} - -bool Writeback::configureMemory(uint32_t size) { - if(!mWbMem.manageMem(size, mSecure)) { - ALOGE("%s failed, memory failure", __func__); - return false; - } - return true; -} - -bool Writeback::queueBuffer(int opFd, uint32_t opOffset) { - memset(&mFbData, 0, sizeof(struct msmfb_data)); - //Queue - mFbData.offset = opOffset; - mFbData.memory_id = opFd; - mFbData.id = 0; - mFbData.flags = 0; - if(!mdp_wrapper::wbQueueBuffer(mFd.getFD(), mFbData)) { - ALOGE("%s: queuebuffer failed", __func__); - return false; - } - return true; -} - -bool Writeback::dequeueBuffer() { - //Dequeue - mFbData.flags = MSMFB_WRITEBACK_DEQUEUE_BLOCKING; - if(!mdp_wrapper::wbDequeueBuffer(mFd.getFD(), mFbData)) { - ALOGE("%s: dequeuebuffer failed", __func__); - return false; - } - return true; -} - -bool Writeback::writeSync(int opFd, uint32_t opOffset) { - if(!queueBuffer(opFd, opOffset)) { - return false; - } - if(!Overlay::displayCommit(mFd.getFD())) { - return false; - } - if(!dequeueBuffer()) { - return false; - } - return true; -} - -bool Writeback::writeSync() { - mWbMem.useNextBuffer(); - return writeSync(mWbMem.getDstFd(), mWbMem.getOffset()); -} - -bool Writeback::setOutputFormat(int mdpFormat) { - if(mdpFormat != mOpFmt) { - struct msmfb_metadata metadata; - memset(&metadata, 0 , sizeof(metadata)); - metadata.op = metadata_op_wb_format; - metadata.data.mixer_cfg.writeback_format = mdpFormat; - if (ioctl(mFd.getFD(), MSMFB_METADATA_SET, &metadata) < 0) { - ALOGE("Error setting MDP Writeback format"); - return false; - } - mOpFmt = mdpFormat; - } - return true; -} - -int Writeback::getOutputFormat() { - if(mOpFmt < 0) { - struct msmfb_metadata metadata; - memset(&metadata, 0 , sizeof(metadata)); - metadata.op = metadata_op_wb_format; - if (ioctl(mFd.getFD(), MSMFB_METADATA_GET, &metadata) < 0) { - ALOGE("Error retrieving MDP Writeback format"); - return -1; - } - mOpFmt = metadata.data.mixer_cfg.writeback_format; - } - return mOpFmt; -} - -bool Writeback::setSecure(bool isSecure) { - if(isSecure != mSecure) { - // Call IOCTL to set WB interface as secure - struct msmfb_metadata metadata; - memset(&metadata, 0 , sizeof(metadata)); - metadata.op = metadata_op_wb_secure; - metadata.data.secure_en = isSecure; - if (ioctl(mFd.getFD(), MSMFB_METADATA_SET, &metadata) < 0) { - ALOGE("Error setting MDP WB secure"); - return false; - } - mSecure = isSecure; - } - return true; -} - -//static - -Writeback *Writeback::getInstance() { - if(sWb == NULL) { - sWb = new Writeback(); - } - sUsed = true; - return sWb; -} - -void Writeback::configDone() { - if(sUsed == false && sWb) { - delete sWb; - sWb = NULL; - } -} - -void Writeback::clear() { - sUsed = false; - if(sWb) { - delete sWb; - sWb = NULL; - } -} - -bool Writeback::getDump(char *buf, size_t len) { - if(sWb) { - utils::getDump(buf, len, "WBData", sWb->mFbData); - char outputBufferInfo[256]; - snprintf(outputBufferInfo, sizeof(outputBufferInfo), - "OutputBuffer xres=%d yres=%d format=%s\n\n", - sWb->getWidth(), sWb->getHeight(), - utils::getFormatString(sWb->getOutputFormat())); - strlcat(buf, outputBufferInfo, len); - return true; - } - return false; -} - -Writeback *Writeback::sWb = 0; -bool Writeback::sUsed = false; - -} //namespace overlay diff --git a/msm8909/liboverlay/overlayWriteback.h b/msm8909/liboverlay/overlayWriteback.h deleted file mode 100644 index 21186e6a..00000000 --- a/msm8909/liboverlay/overlayWriteback.h +++ /dev/null @@ -1,122 +0,0 @@ -/* -* Copyright (c) 2013 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 OVERLAY_WRITEBACK_H -#define OVERLAY_WRITEBACK_H - -#include "overlayMem.h" - -namespace overlay { - -class WritebackMgr; - -class WritebackMem { -public: - explicit WritebackMem() : mCurrOffsetIndex(0) { - memset(&mOffsets, 0, sizeof(mOffsets)); - } - ~WritebackMem() { dealloc(); } - bool manageMem(uint32_t size, bool isSecure); - void useNextBuffer() { - mCurrOffsetIndex = (mCurrOffsetIndex + 1) % NUM_BUFS; - } - uint32_t getOffset() const { return mOffsets[mCurrOffsetIndex]; } - int getDstFd() const { return mBuf.getFD(); } -private: - bool alloc(uint32_t size, bool isSecure); - bool dealloc(); - enum { NUM_BUFS = 2 }; - OvMem mBuf; - uint32_t mOffsets[NUM_BUFS]; - uint32_t mCurrOffsetIndex; -}; - -//Abstracts the WB2 interface of MDP -//Has modes to either manage memory or work with memory allocated elsewhere -class Writeback { -public: - ~Writeback(); - bool configureDpyInfo(int xres, int yres); - bool configureMemory(uint32_t size); - /* Blocking write. (queue, commit, dequeue) - * This class will do writeback memory management. - * This class will call display-commit on writeback mixer. - */ - bool writeSync(); - /* Blocking write. (queue, commit, dequeue) - * Client must do writeback memory management. - * Client must not call display-commit on writeback mixer. - */ - bool writeSync(int opFd, uint32_t opOffset); - /* Async queue. (Does not write) - * Client must do writeback memory management. - * Client must call display-commit on their own. - * Client must use sync mechanism e.g sync pt. - */ - bool queueBuffer(int opFd, uint32_t opOffset); - uint32_t getOffset() const { return mWbMem.getOffset(); } - int getDstFd() const { return mWbMem.getDstFd(); } - int getWidth() const { return mXres; } - int getHeight() const { return mYres; } - /* Subject to GC if writeback isnt used for a drawing round. - * Get always if caching the value. - */ - int getFbFd() const { return mFd.getFD(); } - int getOutputFormat(); - bool setOutputFormat(int mdpFormat); - bool setSecure(bool isSecure); - - static Writeback* getInstance(); - static void configBegin() { sUsed = false; } - static void configDone(); - static void clear(); - //Will take a dump of data structure only if there is an instance existing - //Returns true if dump is added to the input buffer, false otherwise - static bool getDump(char *buf, size_t len); - -private: - explicit Writeback(); - bool startSession(); - bool stopSession(); - //Actually block_until_write_done for the usage here. - bool dequeueBuffer(); - OvFD mFd; - WritebackMem mWbMem; - struct msmfb_data mFbData; - int mXres; - int mYres; - int mOpFmt; - bool mSecure; - - static bool sUsed; - static Writeback *sWb; -}; - -} - -#endif diff --git a/msm8909/liboverlay/pipes/overlayGenPipe.cpp b/msm8909/liboverlay/pipes/overlayGenPipe.cpp deleted file mode 100644 index aebaebfb..00000000 --- a/msm8909/liboverlay/pipes/overlayGenPipe.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* -* Copyright (c) 2012-2013, 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 "overlayGenPipe.h" -#include "mdp_version.h" - -namespace overlay { - -GenericPipe::GenericPipe(const int& dpy) : mDpy(dpy), - mCtrl(new Ctrl(dpy)), mData(new Data(dpy)) { -} - -GenericPipe::~GenericPipe() { - delete mCtrl; - delete mData; -} - -void GenericPipe::setSource(const utils::PipeArgs& args) { - mCtrl->setSource(args); -} - -void GenericPipe::setCrop(const overlay::utils::Dim& d) { - mCtrl->setCrop(d); -} - -void GenericPipe::setColor(const uint32_t color) { - mCtrl->setColor(color); -} - -void GenericPipe::setTransform(const utils::eTransform& orient) { - mCtrl->setTransform(orient); -} - -void GenericPipe::setPosition(const utils::Dim& d) { - mCtrl->setPosition(d); -} - -bool GenericPipe::setVisualParams(const MetaData_t &metadata) -{ - return mCtrl->setVisualParams(metadata); -} - -void GenericPipe::setPipeType(const utils::eMdpPipeType& pType) { - mCtrl->setPipeType(pType); -} - -bool GenericPipe::commit() { - return mCtrl->commit(); -} - -bool GenericPipe::queueBuffer(int fd, uint32_t offset) { - int pipeId = mCtrl->getPipeId(); - OVASSERT(-1 != pipeId, "Ctrl ID should not be -1"); - // set pipe id from ctrl to data - mData->setPipeId(pipeId); - - return mData->queueBuffer(fd, offset); -} - -utils::Dim GenericPipe::getCrop() const -{ - return mCtrl->getCrop(); -} - -uint8_t GenericPipe::getPriority() const { - return mCtrl->getPriority(); -} - -void GenericPipe::dump() const -{ - ALOGE("== Dump Generic pipe start =="); - mCtrl->dump(); - mData->dump(); - ALOGE("== Dump Generic pipe end =="); -} - -void GenericPipe::getDump(char *buf, size_t len) { - mCtrl->getDump(buf, len); - mData->getDump(buf, len); -} - -int GenericPipe::getPipeId() { - return mCtrl->getPipeId(); -} - -bool GenericPipe::validateAndSet(GenericPipe* pipeArray[], const int& count, - const int& fbFd) { - Ctrl* ctrlArray[count]; - memset(&ctrlArray, 0, sizeof(ctrlArray)); - - for(int i = 0; i < count; i++) { - ctrlArray[i] = pipeArray[i]->mCtrl; - } - - return Ctrl::validateAndSet(ctrlArray, count, fbFd); -} - -} //namespace overlay diff --git a/msm8909/liboverlay/pipes/overlayGenPipe.h b/msm8909/liboverlay/pipes/overlayGenPipe.h deleted file mode 100644 index 0a2639a1..00000000 --- a/msm8909/liboverlay/pipes/overlayGenPipe.h +++ /dev/null @@ -1,86 +0,0 @@ -/* -* Copyright (c) 2011-2013, 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 OVERLAY_GENERIC_PIPE_H -#define OVERLAY_GENERIC_PIPE_H - -#include "overlayUtils.h" -#include "overlayCtrlData.h" - -namespace overlay { - -class GenericPipe : utils::NoCopy { -public: - /* ctor */ - explicit GenericPipe(const int& dpy); - /* dtor */ - ~GenericPipe(); - /* Control APIs */ - /* set source using whf, orient and wait flag */ - void setSource(const utils::PipeArgs& args); - /* set crop a.k.a the region of interest */ - void setCrop(const utils::Dim& d); - /* set color for mdp pipe */ - void setColor(const uint32_t color); - /* set orientation*/ - void setTransform(const utils::eTransform& param); - /* set mdp posision using dim */ - void setPosition(const utils::Dim& dim); - /* set visual param */ - bool setVisualParams(const MetaData_t &metadata); - /* set pipe type RGB/DMA/VG */ - void setPipeType(const utils::eMdpPipeType& pType); - /* commit changes to the overlay "set"*/ - bool commit(); - /* Data APIs */ - /* queue buffer to the overlay */ - bool queueBuffer(int fd, uint32_t offset); - /* return cached startup args */ - const utils::PipeArgs& getArgs() const; - /* retrieve cached crop data */ - utils::Dim getCrop() const; - /* return pipe priority */ - uint8_t getPriority() const; - /* dump the state of the object */ - void dump() const; - /* Return the dump in the specified buffer */ - void getDump(char *buf, size_t len); - int getPipeId(); - - static bool validateAndSet(GenericPipe* pipeArray[], const int& count, - const int& fbFd); -private: - int mDpy; - Ctrl *mCtrl; - Data *mData; -}; - -} //namespace overlay - -#endif // OVERLAY_GENERIC_PIPE_H diff --git a/msm8909/libqdutils/Android.bp b/msm8909/libqdutils/Android.bp new file mode 100644 index 00000000..3166e8d0 --- /dev/null +++ b/msm8909/libqdutils/Android.bp @@ -0,0 +1,42 @@ +cc_library_shared { + name: "libqdutils", + vendor: true, + defaults: ["display_defaults"], + header_libs: ["libhardware_headers", "libutils_headers"], + shared_libs: [ + "libbinder", + "libqservice", + ], + cflags: [ + "-DDEBUG_CALC_FPS", + "-DLOG_TAG=\"qdutils\"", + "-Wno-sign-conversion", + ], + srcs: [ + "qd_utils.cpp", + "display_config.cpp", + "profiler.cpp" + ], +} + +cc_library_shared { + name: "libqdMetaData", + vendor: true, + defaults: ["display_defaults"], + cflags: [ + "-Wno-sign-conversion", + "-DLOG_TAG=\"qdmetadata\"", + ], + srcs: ["qdMetaData.cpp","qd_utils.cpp"], +} + +// Remove after WFD moves to use libqdMetaData directly +cc_library_shared { + name: "libqdMetaData.system", + defaults: ["display_defaults"], + cflags: [ + "-Wno-sign-conversion", + "-DLOG_TAG=\"qdmetadata\"", + ], + srcs: ["qdMetaData.cpp","qd_utils.cpp"], +} diff --git a/msm8909/libqdutils/Android.mk b/msm8909/libqdutils/Android.mk deleted file mode 100644 index 444ca32e..00000000 --- a/msm8909/libqdutils/Android.mk +++ /dev/null @@ -1,40 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(LOCAL_PATH)/../common.mk -include $(CLEAR_VARS) - -LOCAL_MODULE := libqdutils -LOCAL_MODULE_TAGS := optional -LOCAL_SHARED_LIBRARIES := $(common_libs) libui libbinder libqservice -LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes) -LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdutils\" -Wno-float-conversion -LOCAL_CLANG := $(common_clang_flags) - -ifeq ($(TARGET_SUPPORTS_WEARABLES),true) -LOCAL_CFLAGS += -DHDMI_STUB -endif - -LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) -LOCAL_COPY_HEADERS_TO := $(common_header_export_path) -LOCAL_COPY_HEADERS := display_config.h mdp_version.h -LOCAL_SRC_FILES := profiler.cpp mdp_version.cpp \ - idle_invalidator.cpp \ - comptype.cpp qd_utils.cpp \ - cb_utils.cpp display_config.cpp \ - cb_swap_rect.cpp -include $(BUILD_SHARED_LIBRARY) - -include $(CLEAR_VARS) - -LOCAL_COPY_HEADERS_TO := $(common_header_export_path) -LOCAL_COPY_HEADERS := qdMetaData.h -LOCAL_SHARED_LIBRARIES := liblog libcutils -LOCAL_C_INCLUDES := $(common_includes) -LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) -LOCAL_SRC_FILES := qdMetaData.cpp -LOCAL_CFLAGS := $(common_flags) -LOCAL_CFLAGS += -DLOG_TAG=\"DisplayMetaData\" -LOCAL_CLANG := $(common_clang_flags) -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE := libqdMetaData -include $(BUILD_SHARED_LIBRARY) - diff --git a/msm8909/libqdutils/Makefile.am b/msm8909/libqdutils/Makefile.am new file mode 100644 index 00000000..01fbf199 --- /dev/null +++ b/msm8909/libqdutils/Makefile.am @@ -0,0 +1,32 @@ +h_sources = qdMetaData.h + +cpp_sources = qdMetaData.cpp + +library_includedir = $(includedir) +library_include_HEADERS = $(h_sources) + +lib_LTLIBRARIES = libqdMetaData.la +libqdMetaData_la_CC = @CC@ +libqdMetaData_la_SOURCES = $(cpp_sources) +libqdMetaData_la_CFLAGS = $(AM_CFLAGS) -DLOG_TAG=\"DisplayMetaData\" +libqdMetaData_la_CPPFLAGS = $(AM_CPPFLAGS) +libqdMetaData_LDADD = -lcutils -llog +libqdMetaData_la_LDFLAGS = -shared -avoid-version + +header_sources = display_config.h + +c_sources = profiler.cpp \ + qd_utils.cpp \ + display_config.cpp + +library_includedir = $(includedir) +library_include_HEADERS = $(header_sources) + +lib_LTLIBRARIES += libqdutils.la +libqdutils_la_CC = @CC@ +libqdutils_la_SOURCES = $(c_sources) +libqdutils_la_CFLAGS = $(COMMON_CFLAGS) -DLOG_TAG=\"qdutils\" +libqdutils_la_CPPFLAGS = $(AM_CPPFLAGS) +libqdutils_LDADD = -lhardware -lcutils -llog -lbinder +libqdutils_la_LIBADD = ../libqservice/libqservice.la +libqdutils_la_LDFLAGS = -shared -avoid-version
\ No newline at end of file diff --git a/msm8909/libqdutils/cb_swap_rect.cpp b/msm8909/libqdutils/cb_swap_rect.cpp deleted file mode 100644 index 8c8efec9..00000000 --- a/msm8909/libqdutils/cb_swap_rect.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2014, The Linux Foundation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of The Linux Foundation or 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 "cb_swap_rect.h" - -ANDROID_SINGLETON_STATIC_INSTANCE(qdutils::cb_swap_rect); - -namespace qdutils { - -cb_swap_rect:: cb_swap_rect(){ - swap_rect_feature_on = false ; -} -void cb_swap_rect::setSwapRectFeature_on( bool value){ - swap_rect_feature_on = value ; -} -bool cb_swap_rect::checkSwapRectFeature_on(){ - return swap_rect_feature_on; -} - -}; diff --git a/msm8909/libqdutils/cb_utils.cpp b/msm8909/libqdutils/cb_utils.cpp deleted file mode 100644 index ddad35d5..00000000 --- a/msm8909/libqdutils/cb_utils.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* Copyright (c) 2013, 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 copyrigh -* 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 "cb_utils.h" -#include "cb_swap_rect.h" -#include <ui/Region.h> -/* get union of two rects into 3rd rect */ -void getUnion(hwc_rect_t& rect1,hwc_rect_t& rect2, hwc_rect_t& irect) { - - irect.left = min(rect1.left, rect2.left); - irect.top = min(rect1.top, rect2.top); - irect.right = max(rect1.right, rect2.right); - irect.bottom = max(rect1.bottom, rect2.bottom); -} - -int clear (copybit_device_t *copybit, private_handle_t* hnd, hwc_rect_t& rect) -{ - int ret = 0; - copybit_rect_t clear_rect = {rect.left, rect.top,rect.right,rect.bottom}; - - copybit_image_t buf; - buf.w = ALIGN(getWidth(hnd),32); - buf.h = getHeight(hnd); - buf.format = hnd->format; - buf.base = (void *)hnd->base; - buf.handle = (native_handle_t *)hnd; - - ret = copybit->clear(copybit, &buf, &clear_rect); - return ret; -} -using namespace android; -using namespace qhwc; -namespace qdutils { - -int CBUtils::uiClearRegion(hwc_display_contents_1_t* list, - int version, LayerProp *layerProp, hwc_rect_t dirtyRect, - copybit_device_t *copybit, private_handle_t *renderBuffer) { - - size_t last = list->numHwLayers - 1; - hwc_rect_t fbFrame = list->hwLayers[last].displayFrame; - Rect fbFrameRect(fbFrame.left,fbFrame.top,fbFrame.right,fbFrame.bottom); - Region wormholeRegion(fbFrameRect); - - if ((dirtyRect.right - dirtyRect.left > 0) && - (dirtyRect.bottom - dirtyRect.top > 0)) { -#ifdef QTI_BSP - Rect tmpRect(dirtyRect.left,dirtyRect.top,dirtyRect.right, - dirtyRect.bottom); - Region tmpRegion(tmpRect); - wormholeRegion = wormholeRegion.intersect(tmpRegion); -#endif - } - if(cb_swap_rect::getInstance().checkSwapRectFeature_on() == true){ - wormholeRegion.set(0,0); - for(size_t i = 0 ; i < last; i++) { - if(((list->hwLayers[i].blending == HWC_BLENDING_NONE) && - (list->hwLayers[i].planeAlpha == 0xFF)) || - !(layerProp[i].mFlags & HWC_COPYBIT) || - (list->hwLayers[i].flags & HWC_SKIP_HWC_COMPOSITION)) - continue ; - hwc_rect_t displayFrame = list->hwLayers[i].displayFrame; - Rect tmpRect(displayFrame.left,displayFrame.top, - displayFrame.right,displayFrame.bottom); - wormholeRegion.set(tmpRect); - } - }else{ - for (size_t i = 0 ; i < last; i++) { - // need to take care only in per pixel blending. - // Restrict calculation only for copybit layers. - if((list->hwLayers[i].blending != HWC_BLENDING_NONE) || - (list->hwLayers[i].planeAlpha != 0xFF) || - !(layerProp[i].mFlags & HWC_COPYBIT)) - continue ; - hwc_rect_t displayFrame = list->hwLayers[i].displayFrame; - Rect tmpRect(displayFrame.left,displayFrame.top,displayFrame.right, - displayFrame.bottom); - Region tmpRegion(tmpRect); - wormholeRegion.subtractSelf(wormholeRegion.intersect(tmpRegion)); - } - } - if(wormholeRegion.isEmpty()){ - return 1; - } - //TO DO :- 1. remove union and call clear for each rect. - Region::const_iterator it = wormholeRegion.begin(); - Region::const_iterator const end = wormholeRegion.end(); - while (it != end) { - const Rect& r = *it++; - hwc_rect_t tmpWormRect = {r.left,r.top,r.right,r.bottom}; - if (version == qdutils::MDP_V3_0_4 || - version == qdutils::MDP_V3_0_5) { - int clear_w = tmpWormRect.right - tmpWormRect.left; - int clear_h = tmpWormRect.bottom - tmpWormRect.top; - //mdp can't handle solid fill for one line - //making solid fill as full in this case - //disable swap rect if presents - if ((clear_w == 1) || (clear_h ==1)) { - clear(copybit, renderBuffer, fbFrame); - return 0; - } else { - clear(copybit, renderBuffer, tmpWormRect); - } - } else { - clear(copybit, renderBuffer, tmpWormRect); - } - } - return 1; -} - -}//namespace qdutils diff --git a/msm8909/libqdutils/comptype.cpp b/msm8909/libqdutils/comptype.cpp deleted file mode 100644 index a29158a6..00000000 --- a/msm8909/libqdutils/comptype.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2013, 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 or 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<comptype.h> - -//Instanticate the QCCompositionType Singleton -ANDROID_SINGLETON_STATIC_INSTANCE(qdutils::QCCompositionType); diff --git a/msm8909/libqdutils/comptype.h b/msm8909/libqdutils/comptype.h deleted file mode 100644 index bbadaae3..00000000 --- a/msm8909/libqdutils/comptype.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2012-2013, 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 or 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 INCLUDE_LIBQCOM_COMPTYPES -#define INCLUDE_LIBQCOM_COMPTYPES - -#include <stdint.h> -#include <string.h> -#include <utils/Singleton.h> -#include <cutils/properties.h> - -using namespace android; -namespace qdutils { -// Enum containing the supported composition types -enum { - COMPOSITION_TYPE_GPU = 0, - COMPOSITION_TYPE_MDP = 0x1, - COMPOSITION_TYPE_C2D = 0x2, - COMPOSITION_TYPE_CPU = 0x4, - COMPOSITION_TYPE_DYN = 0x8 -}; - -/* This class caches the composition type - */ -class QCCompositionType : public Singleton <QCCompositionType> -{ - public: - QCCompositionType(); - ~QCCompositionType() { } - int getCompositionType() {return mCompositionType;} - private: - int mCompositionType; - -}; - -inline QCCompositionType::QCCompositionType() -{ - char property[PROPERTY_VALUE_MAX]; - mCompositionType = COMPOSITION_TYPE_GPU; - if (property_get("debug.composition.type", property, "gpu") > 0) { - if ((strncmp(property, "mdp", 3)) == 0) { - mCompositionType = COMPOSITION_TYPE_MDP; - } else if ((strncmp(property, "c2d", 3)) == 0) { - mCompositionType = COMPOSITION_TYPE_C2D; - } else if ((strncmp(property, "dyn", 3)) == 0) { -#ifdef USE_MDP3 - mCompositionType = COMPOSITION_TYPE_DYN | COMPOSITION_TYPE_MDP; -#else - mCompositionType = COMPOSITION_TYPE_DYN | COMPOSITION_TYPE_C2D; -#endif - } - } -} - -}; //namespace qdutils -#endif //INCLUDE_LIBQCOM_COMPTYPES diff --git a/msm8909/libqdutils/display_config.cpp b/msm8909/libqdutils/display_config.cpp index 62422fed..83d912e2 100644 --- a/msm8909/libqdutils/display_config.cpp +++ b/msm8909/libqdutils/display_config.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. +* Copyright (c) 2013-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 @@ -27,14 +27,24 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <fcntl.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> #include <display_config.h> #include <QServiceUtils.h> +#include <qd_utils.h> using namespace android; using namespace qService; namespace qdutils { +//============================================================================= +// The functions below run in the client process and wherever necessary +// do a binder call to HWC to get/set data. + int isExternalConnected(void) { int ret; status_t err = (status_t) FAILED_TRANSACTION; @@ -68,9 +78,9 @@ int getDisplayAttributes(int dpy, DisplayAttributes_t& dpyattr) { dpyattr.yres = outParcel.readInt32(); dpyattr.xdpi = outParcel.readFloat(); dpyattr.ydpi = outParcel.readFloat(); - dpyattr.panel_type = (char) outParcel.readInt32(); + dpyattr.panel_type = outParcel.readInt32(); } else { - ALOGE("%s: Failed to get display attributes err=%d", __FUNCTION__, err); + ALOGE("%s() failed with err %d", __FUNCTION__, err); } return err; } @@ -170,22 +180,189 @@ int configureDynRefreshRate(uint32_t op, uint32_t refreshRate) { return err; } -}; //namespace +int getConfigCount(int /*dpy*/) { + int numConfigs = -1; + sp<IQService> binder = getBinder(); + if(binder != NULL) { + Parcel inParcel, outParcel; + inParcel.writeInt32(DISPLAY_PRIMARY); + status_t err = binder->dispatch(IQService::GET_CONFIG_COUNT, + &inParcel, &outParcel); + if(!err) { + numConfigs = outParcel.readInt32(); + ALOGI("%s() Received num configs %d", __FUNCTION__, numConfigs); + } else { + ALOGE("%s() failed with err %d", __FUNCTION__, err); + } + } + return numConfigs; +} + +int getActiveConfig(int dpy) { + int configIndex = -1; + sp<IQService> binder = getBinder(); + if(binder != NULL) { + Parcel inParcel, outParcel; + inParcel.writeInt32(dpy); + status_t err = binder->dispatch(IQService::GET_ACTIVE_CONFIG, + &inParcel, &outParcel); + if(!err) { + configIndex = outParcel.readInt32(); + ALOGI("%s() Received active config index %d", __FUNCTION__, + configIndex); + } else { + ALOGE("%s() failed with err %d", __FUNCTION__, err); + } + } + return configIndex; +} + +int setActiveConfig(int configIndex, int /*dpy*/) { + status_t err = (status_t) FAILED_TRANSACTION; + sp<IQService> binder = getBinder(); + if(binder != NULL) { + Parcel inParcel, outParcel; + inParcel.writeInt32(configIndex); + inParcel.writeInt32(DISPLAY_PRIMARY); + err = binder->dispatch(IQService::SET_ACTIVE_CONFIG, + &inParcel, &outParcel); + if(!err) { + ALOGI("%s() Successfully set active config index %d", __FUNCTION__, + configIndex); + } else { + ALOGE("%s() failed with err %d", __FUNCTION__, err); + } + } + return err; +} + +DisplayAttributes getDisplayAttributes(int configIndex, int dpy) { + DisplayAttributes dpyattr = {}; + sp<IQService> binder = getBinder(); + if(binder != NULL) { + Parcel inParcel, outParcel; + inParcel.writeInt32(configIndex); + inParcel.writeInt32(dpy); + status_t err = binder->dispatch( + IQService::GET_DISPLAY_ATTRIBUTES_FOR_CONFIG, &inParcel, + &outParcel); + if(!err) { + dpyattr.vsync_period = outParcel.readInt32(); + dpyattr.xres = outParcel.readInt32(); + dpyattr.yres = outParcel.readInt32(); + dpyattr.xdpi = outParcel.readFloat(); + dpyattr.ydpi = outParcel.readFloat(); + dpyattr.panel_type = outParcel.readInt32(); + dpyattr.is_yuv = outParcel.readInt32(); + ALOGI("%s() Received attrs for index %d: xres %d, yres %d", + __FUNCTION__, configIndex, dpyattr.xres, dpyattr.yres); + } else { + ALOGE("%s() failed with err %d", __FUNCTION__, err); + } + } + return dpyattr; +} + +int setPanelMode(int mode) { + status_t err = (status_t) FAILED_TRANSACTION; + sp<IQService> binder = getBinder(); + if(binder != NULL) { + Parcel inParcel, outParcel; + inParcel.writeInt32(mode); + err = binder->dispatch(IQService::SET_DISPLAY_MODE, + &inParcel, &outParcel); + if(!err) { + ALOGI("%s() Successfully set the display mode to %d", __FUNCTION__, + mode); + } else { + ALOGE("%s() failed with err %d", __FUNCTION__, err); + } + } + return err; +} + +int setPanelBrightness(int level) { + status_t err = (status_t) FAILED_TRANSACTION; + sp<IQService> binder = getBinder(); + Parcel inParcel, outParcel; + + if(binder != NULL) { + inParcel.writeInt32(level); + status_t err = binder->dispatch(IQService::SET_PANEL_BRIGHTNESS, + &inParcel, &outParcel); + if(err) { + ALOGE("%s() failed with err %d", __FUNCTION__, err); + } + } + return err; +} + +int getPanelBrightness() { + int panel_brightness = -1; + sp<IQService> binder = getBinder(); + Parcel inParcel, outParcel; + + if(binder != NULL) { + status_t err = binder->dispatch(IQService::GET_PANEL_BRIGHTNESS, + &inParcel, &outParcel); + if(!err) { + panel_brightness = outParcel.readInt32(); + ALOGI("%s() Current panel brightness value %d", __FUNCTION__, + panel_brightness); + } else { + ALOGE("%s() failed with err %d", __FUNCTION__, err); + } + } + return panel_brightness; +} + +}// namespace // ---------------------------------------------------------------------------- -// Screen refresh for native daemons linking dynamically to libqdutils +// Functions for linking dynamically to libqdutils // ---------------------------------------------------------------------------- +extern "C" int minHdcpEncryptionLevelChanged(int dpy, int min_enc_level) { + status_t err = (status_t) FAILED_TRANSACTION; + sp<IQService> binder = getBinder(); + Parcel inParcel, outParcel; + inParcel.writeInt32(dpy); + inParcel.writeInt32(min_enc_level); + + if(binder != NULL) { + err = binder->dispatch(IQService::MIN_HDCP_ENCRYPTION_LEVEL_CHANGED, + &inParcel, &outParcel); + } + + if(err) { + ALOGE("%s: Failed for dpy %d err=%d", __FUNCTION__, dpy, err); + } else { + err = outParcel.readInt32(); + } + + return err; +} + extern "C" int refreshScreen() { int ret = 0; ret = screenRefresh(); return ret; } -// ---------------------------------------------------------------------------- -// Native daemons needs to send enable partial update ack for PU to enable -// ---------------------------------------------------------------------------- -extern "C" int setPartialUpdateState() { - int ret = 0; - ret = setPartialUpdate(IQService::ENABLE_PARTIAL_UPDATE); - return ret; +extern "C" int controlPartialUpdate(int dpy, int mode) { + status_t err = (status_t) FAILED_TRANSACTION; + sp<IQService> binder = getBinder(); + if(binder != NULL) { + Parcel inParcel, outParcel; + inParcel.writeInt32(dpy); + inParcel.writeInt32(mode); + err = binder->dispatch(IQService::CONTROL_PARTIAL_UPDATE, &inParcel, &outParcel); + if(err != 0) { + ALOGE_IF(getBinder(), "%s() failed with err %d", __FUNCTION__, err); + } else { + return outParcel.readInt32(); + } + } + + return err; } + diff --git a/msm8909/libqdutils/display_config.h b/msm8909/libqdutils/display_config.h index e9b2fc3c..6512bf53 100644 --- a/msm8909/libqdutils/display_config.h +++ b/msm8909/libqdutils/display_config.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 The Linux Foundation. All rights reserved. + * Copyright (c) 2013 - 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 @@ -26,24 +26,33 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +#ifndef _DISPLAY_CONFIG_H +#define _DISPLAY_CONFIG_H + #include <gralloc_priv.h> #include <qdMetaData.h> -#include <mdp_version.h> #include <hardware/hwcomposer.h> -// This header is for clients to use to set/get global display configuration -// The functions in this header run in the client process and wherever necessary -// do a binder call to HWC to get/set data. +// This header is for clients to use to set/get global display configuration. // Only primary and external displays are supported here. -// WiFi/virtual displays are not supported. namespace qdutils { + +/* TODO: Have all the common enums that need be exposed to clients and which + * are also needed in hwc defined here. Remove such definitions we have in + * hwc_utils.h + */ + // Use this enum to specify the dpy parameters where needed enum { - DISPLAY_PRIMARY = HWC_DISPLAY_PRIMARY, + DISPLAY_PRIMARY = HWC_DISPLAY_PRIMARY, DISPLAY_EXTERNAL = HWC_DISPLAY_EXTERNAL, - DISPLAY_VIRTUAL = HWC_DISPLAY_VIRTUAL, +#ifdef QTI_BSP + DISPLAY_TERTIARY = HWC_DISPLAY_TERTIARY, +#endif + DISPLAY_VIRTUAL = HWC_DISPLAY_VIRTUAL, }; // External Display states - used in setSecondaryDisplayStatus() @@ -61,16 +70,37 @@ enum { SET_BINDER_DYN_REFRESH_RATE, }; +enum { + DEFAULT_MODE = 0, + VIDEO_MODE, + COMMAND_MODE, +}; + +enum { + DISPLAY_PORT_DEFAULT = 0, + DISPLAY_PORT_DSI, + DISPLAY_PORT_DTV, + DISPLAY_PORT_WRITEBACK, + DISPLAY_PORT_LVDS, + DISPLAY_PORT_EDP, + DISPLAY_PORT_DP, +}; + // Display Attributes that are available to clients of this library // Not to be confused with a similar struct in hwc_utils (in the hwc namespace) -struct DisplayAttributes_t { - uint32_t vsync_period; //nanoseconds - uint32_t xres; - uint32_t yres; - float xdpi; - float ydpi; - char panel_type; -}; +typedef struct DisplayAttributes { + uint32_t vsync_period = 0; //nanoseconds + uint32_t xres = 0; + uint32_t yres = 0; + float xdpi = 0.0f; + float ydpi = 0.0f; + int panel_type = DISPLAY_PORT_DEFAULT; + bool is_yuv = false; +} DisplayAttributes_t; + +//============================================================================= +// The functions below run in the client process and wherever necessary +// do a binder call to HWC to get/set data. // Check if external display is connected. Useful to check before making // calls for external displays @@ -98,4 +128,36 @@ int setSecondaryDisplayStatus(int dpy, uint32_t status); // Enable/Disable/Set refresh rate dynamically int configureDynRefreshRate(uint32_t op, uint32_t refreshRate); + +// Returns the number of configs supported for the display on success. +// Returns -1 on error. +// Only primary display supported for now, value of dpy ignored. +int getConfigCount(int dpy); + +// Returns the index of config that is current set for the display on success. +// Returns -1 on error. +// Only primary display supported for now, value of dpy ignored. +int getActiveConfig(int dpy); + +// Sets the config for the display on success and returns 0. +// Returns -1 on error. +// Only primary display supported for now, value of dpy ignored +int setActiveConfig(int configIndex, int dpy); + +// Returns the attributes for the specified config for the display on success. +// Returns xres and yres as 0 on error. +// Only primary display supported for now, value of dpy ignored +DisplayAttributes getDisplayAttributes(int configIndex, int dpy); + +// Set the primary display mode to command or video mode +int setDisplayMode(int mode); + +// Sets the panel brightness of the primary display +int setPanelBrightness(int level); + +// Retrieves the current panel brightness value +int getPanelBrightness(); + }; //namespace + +#endif diff --git a/msm8909/libqdutils/idle_invalidator.cpp b/msm8909/libqdutils/idle_invalidator.cpp deleted file mode 100644 index b8db0bf2..00000000 --- a/msm8909/libqdutils/idle_invalidator.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2012, 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 "idle_invalidator.h" -#include <unistd.h> -#include <poll.h> -#include <string.h> -#include <fcntl.h> -#include <cutils/properties.h> - -#define II_DEBUG 0 -#define IDLE_NOTIFY_PATH "/sys/devices/virtual/graphics/fb0/idle_notify" -#define IDLE_TIME_PATH "/sys/devices/virtual/graphics/fb0/idle_time" - - -static const char *threadName = "IdleInvalidator"; -InvalidatorHandler IdleInvalidator::mHandler = NULL; -android::sp<IdleInvalidator> IdleInvalidator::sInstance(0); - -IdleInvalidator::IdleInvalidator(): Thread(false), mHwcContext(0), - mTimeoutEventFd(-1) { - ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__); -} - -IdleInvalidator::~IdleInvalidator() { - if(mTimeoutEventFd >= 0) { - close(mTimeoutEventFd); - } -} - -int IdleInvalidator::init(InvalidatorHandler reg_handler, void* user_data) { - mHandler = reg_handler; - mHwcContext = user_data; - - // Open a sysfs node to receive the timeout notification from driver. - mTimeoutEventFd = open(IDLE_NOTIFY_PATH, O_RDONLY); - if (mTimeoutEventFd < 0) { - ALOGE ("%s:not able to open %s node %s", - __FUNCTION__, IDLE_NOTIFY_PATH, strerror(errno)); - return -1; - } - - int defaultIdleTime = 70; //ms - char property[PROPERTY_VALUE_MAX] = {0}; - if((property_get("debug.mdpcomp.idletime", property, NULL) > 0)) { - defaultIdleTime = atoi(property); - } - if(not setIdleTimeout(defaultIdleTime)) { - close(mTimeoutEventFd); - mTimeoutEventFd = -1; - return -1; - } - - //Triggers the threadLoop to run, if not already running. - run(threadName, android::PRIORITY_LOWEST); - return 0; -} - -bool IdleInvalidator::setIdleTimeout(const uint32_t& timeout) { - ALOGD_IF(II_DEBUG, "IdleInvalidator::%s timeout %d", - __FUNCTION__, timeout); - - // Open a sysfs node to send the timeout value to driver. - int fd = open(IDLE_TIME_PATH, O_WRONLY); - - if (fd < 0) { - ALOGE ("%s:Unable to open %s node %s", - __FUNCTION__, IDLE_TIME_PATH, strerror(errno)); - return false; - } - - char strSleepTime[64]; - snprintf(strSleepTime, sizeof(strSleepTime), "%d", timeout); - - // Notify driver about the timeout value - ssize_t len = pwrite(fd, strSleepTime, strlen(strSleepTime), 0); - if(len < -1) { - ALOGE ("%s:Unable to write into %s node %s", - __FUNCTION__, IDLE_TIME_PATH, strerror(errno)); - close(fd); - return false; - } - - close(fd); - return true; -} - -bool IdleInvalidator::threadLoop() { - ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__); - struct pollfd pFd; - pFd.fd = mTimeoutEventFd; - if (pFd.fd >= 0) - pFd.events = POLLPRI | POLLERR; - // Poll for an timeout event from driver - int err = poll(&pFd, 1, -1); - if(err > 0) { - if (pFd.revents & POLLPRI) { - char data[64]; - // Consume the node by reading it - ssize_t len = pread(pFd.fd, data, 64, 0); - ALOGD_IF(II_DEBUG, "IdleInvalidator::%s Idle Timeout fired len %zd", - __FUNCTION__, len); - mHandler((void*)mHwcContext); - } - } - return true; -} - -int IdleInvalidator::readyToRun() { - ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__); - return 0; /*NO_ERROR*/ -} - -void IdleInvalidator::onFirstRef() { - ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__); -} - -IdleInvalidator *IdleInvalidator::getInstance() { - ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__); - if(sInstance.get() == NULL) - sInstance = new IdleInvalidator(); - return sInstance.get(); -} diff --git a/msm8909/libqdutils/idle_invalidator.h b/msm8909/libqdutils/idle_invalidator.h deleted file mode 100644 index 52334a02..00000000 --- a/msm8909/libqdutils/idle_invalidator.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2012, 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 INCLUDE_IDLEINVALIDATOR -#define INCLUDE_IDLEINVALIDATOR - -#include <cutils/log.h> -#include <utils/threads.h> -#include <gr.h> - -typedef void (*InvalidatorHandler)(void*); - -class IdleInvalidator : public android::Thread { - IdleInvalidator(); - void *mHwcContext; - int mTimeoutEventFd; - static InvalidatorHandler mHandler; - static android::sp<IdleInvalidator> sInstance; - -public: - ~IdleInvalidator(); - /* init timer obj */ - int init(InvalidatorHandler reg_handler, void* user_data); - bool setIdleTimeout(const uint32_t& timeout); - - /*Overrides*/ - virtual bool threadLoop(); - virtual int readyToRun(); - virtual void onFirstRef(); - static IdleInvalidator *getInstance(); -}; - -#endif // INCLUDE_IDLEINVALIDATOR diff --git a/msm8909/libqdutils/mdp_version.cpp b/msm8909/libqdutils/mdp_version.cpp deleted file mode 100644 index 088f82b6..00000000 --- a/msm8909/libqdutils/mdp_version.cpp +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of The Linux Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include <cutils/log.h> -#include <linux/msm_mdp.h> -#include "mdp_version.h" -#include "qd_utils.h" - -#define DEBUG 0 - -ANDROID_SINGLETON_STATIC_INSTANCE(qdutils::MDPVersion); -namespace qdutils { - -#define TOKEN_PARAMS_DELIM "=" - -// chip variants have same major number and minor numbers usually vary -// for e.g., MDSS_MDP_HW_REV_101 is 0x10010000 -// 1001 - major number -// 0000 - minor number -// 8x26 v1 minor number is 0000 -// v2 minor number is 0001 etc.. -#ifndef MDSS_MDP_HW_REV_100 -#define MDSS_MDP_HW_REV_100 0x10000000 //8974 v1 -#endif -#ifndef MDSS_MDP_HW_REV_101 -#define MDSS_MDP_HW_REV_101 0x10010000 //8x26 -#endif -#ifndef MDSS_MDP_HW_REV_102 -#define MDSS_MDP_HW_REV_102 0x10020000 //8974 v2 -#endif -#ifndef MDSS_MDP_HW_REV_103 -#define MDSS_MDP_HW_REV_103 0x10030000 //8084 -#endif -#ifndef MDSS_MDP_HW_REV_104 -#define MDSS_MDP_HW_REV_104 0x10040000 //Next version -#endif -#ifndef MDSS_MDP_HW_REV_105 -#define MDSS_MDP_HW_REV_105 0x10050000 //8994 -#endif -#ifndef MDSS_MDP_HW_REV_106 -#define MDSS_MDP_HW_REV_106 0x10060000 //8x16 -#endif -#ifndef MDSS_MDP_HW_REV_107 -#define MDSS_MDP_HW_REV_107 0x10070000 //Next version -#endif -#ifndef MDSS_MDP_HW_REV_108 -#define MDSS_MDP_HW_REV_108 0x10080000 //8x39 & 8x36 -#endif -#ifndef MDSS_MDP_HW_REV_109 -#define MDSS_MDP_HW_REV_109 0x10090000 //Next version -#endif -#ifndef MDSS_MDP_HW_REV_200 -#define MDSS_MDP_HW_REV_200 0x20000000 //8092 -#endif -#ifndef MDSS_MDP_HW_REV_206 -#define MDSS_MDP_HW_REV_206 0x20060000 //Future -#endif - -MDPVersion::MDPVersion() -{ - mMDPVersion = MDSS_V5; - mMdpRev = 0; - mRGBPipes = 0; - mVGPipes = 0; - mDMAPipes = 0; - mFeatures = 0; - mMDPUpscale = 1; - mMDPDownscale = 1; - mMacroTileEnabled = false; - mLowBw = 0; - mHighBw = 0; - mSourceSplit = false; - mSourceSplitAlways = false; - mRGBHasNoScalar = false; - mRotDownscale = false; - - // this is the default limit of mixer unless driver reports it. - // For resolutions beyond this, we use dual/split overlay pipes. - mMaxMixerWidth = 2048; - - updatePanelInfo(); - - if(!updateSysFsInfo()) { - ALOGE("Unable to read display sysfs node"); - } - if (mMdpRev == MDP_V3_0_4){ - mMDPVersion = MDP_V3_0_4; - } - else if (mMdpRev == MDP_V3_0_5){ - mMDPVersion = MDP_V3_0_5; - } - - mHasOverlay = false; - if((mMDPVersion >= MDP_V4_0) || - (mMDPVersion == MDP_V_UNKNOWN) || - (mMDPVersion == MDP_V3_0_4) || - (mMDPVersion == MDP_V3_0_5)) - mHasOverlay = true; - if(!updateSplitInfo()) { - ALOGE("Unable to read display split node"); - } -} - -MDPVersion::~MDPVersion() { - close(mFd); -} - -int MDPVersion::tokenizeParams(char *inputParams, const char *delim, - char* tokenStr[], int *idx) { - char *tmp_token = NULL; - char *temp_ptr; - int index = 0; - if (!inputParams) { - return -1; - } - tmp_token = strtok_r(inputParams, delim, &temp_ptr); - while (tmp_token != NULL) { - tokenStr[index++] = tmp_token; - tmp_token = strtok_r(NULL, " ", &temp_ptr); - } - *idx = index; - return 0; -} -// This function reads the sysfs node to read the primary panel type -// and updates information accordingly -void MDPVersion::updatePanelInfo() { - FILE *displayDeviceFP = NULL; - FILE *panelInfoNodeFP = NULL; - char fbType[MAX_FRAME_BUFFER_NAME_SIZE]; - const char *strCmdPanel = "mipi dsi cmd panel"; - const char *strVideoPanel = "mipi dsi video panel"; - const char *strLVDSPanel = "lvds panel"; - const char *strEDPPanel = "edp panel"; - - displayDeviceFP = fopen("/sys/class/graphics/fb0/msm_fb_type", "r"); - if(displayDeviceFP){ - fread(fbType, sizeof(char), MAX_FRAME_BUFFER_NAME_SIZE, - displayDeviceFP); - if(strncmp(fbType, strCmdPanel, strlen(strCmdPanel)) == 0) { - mPanelInfo.mType = MIPI_CMD_PANEL; - } - else if(strncmp(fbType, strVideoPanel, strlen(strVideoPanel)) == 0) { - mPanelInfo.mType = MIPI_VIDEO_PANEL; - } - else if(strncmp(fbType, strLVDSPanel, strlen(strLVDSPanel)) == 0) { - mPanelInfo.mType = LVDS_PANEL; - } - else if(strncmp(fbType, strEDPPanel, strlen(strEDPPanel)) == 0) { - mPanelInfo.mType = EDP_PANEL; - } - fclose(displayDeviceFP); - } else { - ALOGE("Unable to read Primary Panel Information"); - } - - panelInfoNodeFP = fopen("/sys/class/graphics/fb0/msm_fb_panel_info", "r"); - if(panelInfoNodeFP){ - size_t len = PAGE_SIZE; - ssize_t read; - char *readLine = (char *) malloc (len); - char property[PROPERTY_VALUE_MAX]; - while((read = getline((char **)&readLine, &len, - panelInfoNodeFP)) != -1) { - int token_ct=0; - char *tokens[10]; - memset(tokens, 0, sizeof(tokens)); - - if(!tokenizeParams(readLine, TOKEN_PARAMS_DELIM, tokens, - &token_ct)) { - if(!strncmp(tokens[0], "pu_en", strlen("pu_en"))) { - mPanelInfo.mPartialUpdateEnable = atoi(tokens[1]); - ALOGI("PartialUpdate status: %s", - mPanelInfo.mPartialUpdateEnable? "Enabled" : - "Disabled"); - } - if(!strncmp(tokens[0], "xstart", strlen("xstart"))) { - mPanelInfo.mLeftAlign = atoi(tokens[1]); - ALOGI("Left Align: %d", mPanelInfo.mLeftAlign); - } - if(!strncmp(tokens[0], "walign", strlen("walign"))) { - mPanelInfo.mWidthAlign = atoi(tokens[1]); - ALOGI("Width Align: %d", mPanelInfo.mWidthAlign); - } - if(!strncmp(tokens[0], "ystart", strlen("ystart"))) { - mPanelInfo.mTopAlign = atoi(tokens[1]); - ALOGI("Top Align: %d", mPanelInfo.mTopAlign); - } - if(!strncmp(tokens[0], "halign", strlen("halign"))) { - mPanelInfo.mHeightAlign = atoi(tokens[1]); - ALOGI("Height Align: %d", mPanelInfo.mHeightAlign); - } - if(!strncmp(tokens[0], "min_w", strlen("min_w"))) { - mPanelInfo.mMinROIWidth = atoi(tokens[1]); - ALOGI("Min ROI Width: %d", mPanelInfo.mMinROIWidth); - } - if(!strncmp(tokens[0], "min_h", strlen("min_h"))) { - mPanelInfo.mMinROIHeight = atoi(tokens[1]); - ALOGI("Min ROI Height: %d", mPanelInfo.mMinROIHeight); - } - if(!strncmp(tokens[0], "roi_merge", strlen("roi_merge"))) { - mPanelInfo.mNeedsROIMerge = atoi(tokens[1]); - ALOGI("Needs ROI Merge: %d", mPanelInfo.mNeedsROIMerge); - } - if(!strncmp(tokens[0], "dyn_fps_en", strlen("dyn_fps_en"))) { - mPanelInfo.mDynFpsSupported = atoi(tokens[1]); - ALOGI("Dynamic Fps: %s", mPanelInfo.mDynFpsSupported ? - "Enabled" : "Disabled"); - } - if(!strncmp(tokens[0], "min_fps", strlen("min_fps"))) { - mPanelInfo.mMinFps = atoi(tokens[1]); - ALOGI("Min Panel fps: %d", mPanelInfo.mMinFps); - } - if(!strncmp(tokens[0], "max_fps", strlen("max_fps"))) { - mPanelInfo.mMaxFps = atoi(tokens[1]); - ALOGI("Max Panel fps: %d", mPanelInfo.mMaxFps); - } - } - } - if((property_get("persist.hwc.pubypass", property, 0) > 0) && - (!strncmp(property, "1", PROPERTY_VALUE_MAX ) || - (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) { - mPanelInfo.mPartialUpdateEnable = 0; - ALOGI("PartialUpdate disabled by property"); - } - fclose(panelInfoNodeFP); - } else { - ALOGE("Failed to open msm_fb_panel_info node"); - } -} - -// This function reads the sysfs node to read MDP capabilities -// and parses and updates information accordingly. -bool MDPVersion::updateSysFsInfo() { - FILE *sysfsFd; - size_t len = PAGE_SIZE; - ssize_t read; - char *line = NULL; - char sysfsPath[255]; - memset(sysfsPath, 0, sizeof(sysfsPath)); - snprintf(sysfsPath , sizeof(sysfsPath), - "/sys/class/graphics/fb0/mdp/caps"); - char property[PROPERTY_VALUE_MAX]; - bool enableMacroTile = false; - - if((property_get("persist.hwc.macro_tile_enable", property, NULL) > 0) && - (!strncmp(property, "1", PROPERTY_VALUE_MAX ) || - (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) { - enableMacroTile = true; - } - - sysfsFd = fopen(sysfsPath, "rb"); - - if (sysfsFd == NULL) { - ALOGE("%s: sysFsFile file '%s' not found", - __FUNCTION__, sysfsPath); - return false; - } else { - line = (char *) malloc(len); - while((read = getline(&line, &len, sysfsFd)) != -1) { - int index=0; - char *tokens[10]; - memset(tokens, 0, sizeof(tokens)); - - // parse the line and update information accordingly - if(!tokenizeParams(line, TOKEN_PARAMS_DELIM, tokens, &index)) { - if(!strncmp(tokens[0], "hw_rev", strlen("hw_rev"))) { - mMdpRev = atoi(tokens[1]); - } - else if(!strncmp(tokens[0], "rgb_pipes", strlen("rgb_pipes"))) { - mRGBPipes = (uint8_t)atoi(tokens[1]); - } - else if(!strncmp(tokens[0], "vig_pipes", strlen("vig_pipes"))) { - mVGPipes = (uint8_t)atoi(tokens[1]); - } - else if(!strncmp(tokens[0], "dma_pipes", strlen("dma_pipes"))) { - mDMAPipes = (uint8_t)atoi(tokens[1]); - } - else if(!strncmp(tokens[0], "max_downscale_ratio", - strlen("max_downscale_ratio"))) { - mMDPDownscale = atoi(tokens[1]); - } - else if(!strncmp(tokens[0], "max_upscale_ratio", - strlen("max_upscale_ratio"))) { - mMDPUpscale = atoi(tokens[1]); - } else if(!strncmp(tokens[0], "max_bandwidth_low", - strlen("max_bandwidth_low"))) { - mLowBw = atol(tokens[1]); - } else if(!strncmp(tokens[0], "max_bandwidth_high", - strlen("max_bandwidth_high"))) { - mHighBw = atol(tokens[1]); - } else if(!strncmp(tokens[0], "max_mixer_width", - strlen("max_mixer_width"))) { - mMaxMixerWidth = atoi(tokens[1]); - } else if(!strncmp(tokens[0], "features", strlen("features"))) { - for(int i=1; i<index;i++) { - if(!strncmp(tokens[i], "bwc", strlen("bwc"))) { - mFeatures |= MDP_BWC_EN; - } else if(!strncmp(tokens[i], "decimation", - strlen("decimation"))) { - mFeatures |= MDP_DECIMATION_EN; - } else if(!strncmp(tokens[i], "tile_format", - strlen("tile_format"))) { - if(enableMacroTile) - mMacroTileEnabled = true; - } else if(!strncmp(tokens[i], "src_split", - strlen("src_split"))) { - mSourceSplit = true; - } else if(!strncmp(tokens[i], "non_scalar_rgb", - strlen("non_scalar_rgb"))) { - mRGBHasNoScalar = true; - } else if(!strncmp(tokens[i], "rotator_downscale", - strlen("rotator_downscale"))) { - mRotDownscale = true; - } - } - } - } - } - free(line); - fclose(sysfsFd); - } - - if(mMDPVersion >= qdutils::MDP_V4_2 and mMDPVersion < qdutils::MDSS_V5) { - mRotDownscale = true; - } - - if(mSourceSplit) { - memset(sysfsPath, 0, sizeof(sysfsPath)); - snprintf(sysfsPath , sizeof(sysfsPath), - "/sys/class/graphics/fb0/msm_fb_src_split_info"); - - sysfsFd = fopen(sysfsPath, "rb"); - if (sysfsFd == NULL) { - ALOGE("%s: Opening file %s failed with error %s", __FUNCTION__, - sysfsPath, strerror(errno)); - return false; - } else { - line = (char *) malloc(len); - if((read = getline(&line, &len, sysfsFd)) != -1) { - if(!strncmp(line, "src_split_always", - strlen("src_split_always"))) { - mSourceSplitAlways = true; - } - } - free(line); - fclose(sysfsFd); - } - } - - ALOGD_IF(DEBUG, "%s: mMDPVersion: %d mMdpRev: %x mRGBPipes:%d," - "mVGPipes:%d", __FUNCTION__, mMDPVersion, mMdpRev, - mRGBPipes, mVGPipes); - ALOGD_IF(DEBUG, "%s:mDMAPipes:%d \t mMDPDownscale:%d, mFeatures:%d", - __FUNCTION__, mDMAPipes, mMDPDownscale, mFeatures); - ALOGD_IF(DEBUG, "%s:mLowBw: %lu mHighBw: %lu", __FUNCTION__, mLowBw, - mHighBw); - - return true; -} - -// This function reads the sysfs node to read MDP capabilities -// and parses and updates information accordingly. -bool MDPVersion::updateSplitInfo() { - if(mMDPVersion >= MDSS_V5) { - char split[64] = {0}; - FILE* fp = fopen("/sys/class/graphics/fb0/msm_fb_split", "r"); - if(fp){ - //Format "left right" space as delimiter - if(fread(split, sizeof(char), 64, fp)) { - split[sizeof(split) - 1] = '\0'; - mSplit.mLeft = atoi(split); - ALOGI_IF(mSplit.mLeft, "Left Split=%d", mSplit.mLeft); - char *rght = strpbrk(split, " "); - if(rght) - mSplit.mRight = atoi(rght + 1); - ALOGI_IF(mSplit.mRight, "Right Split=%d", mSplit.mRight); - } - } else { - ALOGE("Failed to open mdss_fb_split node"); - return false; - } - if(fp) - fclose(fp); - } - return true; -} - - -bool MDPVersion::hasMinCropWidthLimitation() const { - return mMdpRev <= MDSS_MDP_HW_REV_102; -} - -bool MDPVersion::supportsDecimation() { - return mFeatures & MDP_DECIMATION_EN; -} - -uint32_t MDPVersion::getMaxMDPDownscale() { - return mMDPDownscale; -} - -uint32_t MDPVersion::getMaxMDPUpscale() { - return mMDPUpscale; -} - -bool MDPVersion::supportsBWC() { - // BWC - Bandwidth Compression - return (mFeatures & MDP_BWC_EN); -} - -bool MDPVersion::supportsMacroTile() { - // MACRO TILE support - return mMacroTileEnabled; -} - -bool MDPVersion::isSrcSplit() const { - return mSourceSplit; -} - -bool MDPVersion::isSrcSplitAlways() const { - return mSourceSplitAlways; -} - -bool MDPVersion::isRGBScalarSupported() const { - return (!mRGBHasNoScalar); -} - -bool MDPVersion::is8x26() { - return (mMdpRev >= MDSS_MDP_HW_REV_101 and - mMdpRev < MDSS_MDP_HW_REV_102); -} - -bool MDPVersion::is8x74v2() { - return (mMdpRev >= MDSS_MDP_HW_REV_102 and - mMdpRev < MDSS_MDP_HW_REV_103); -} - -bool MDPVersion::is8084() { - return (mMdpRev >= MDSS_MDP_HW_REV_103 and - mMdpRev < MDSS_MDP_HW_REV_104); -} - -bool MDPVersion::is8092() { - return (mMdpRev >= MDSS_MDP_HW_REV_200 and - mMdpRev < MDSS_MDP_HW_REV_206); -} - -bool MDPVersion::is8994() { - return (mMdpRev >= MDSS_MDP_HW_REV_105 and - mMdpRev < MDSS_MDP_HW_REV_106); -} - -bool MDPVersion::is8x16() { - return (mMdpRev >= MDSS_MDP_HW_REV_106 and - mMdpRev < MDSS_MDP_HW_REV_107); -} - -bool MDPVersion::is8x39() { - return (mMdpRev >= MDSS_MDP_HW_REV_108 and - mMdpRev < MDSS_MDP_HW_REV_109); -} - - -}; //namespace qdutils - diff --git a/msm8909/libqdutils/mdp_version.h b/msm8909/libqdutils/mdp_version.h deleted file mode 100644 index 3c7f6a30..00000000 --- a/msm8909/libqdutils/mdp_version.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (c) 2012-2013, 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 INCLUDE_LIBQCOMUTILS_MDPVER -#define INCLUDE_LIBQCOMUTILS_MDPVER - -#include <stdint.h> -#include <utils/Singleton.h> -#include <cutils/properties.h> - -/* This class gets the MSM type from the soc info -*/ -using namespace android; -namespace qdutils { -// These panel definitions are available at mdss_mdp.h which is internal header -// file and is not available at <linux/mdss_mdp.h>. -// ToDo: once it is available at linux/mdss_mdp.h, these below definitions can -// be removed. -enum mdp_version { - MDP_V_UNKNOWN = 0, - MDP_V2_2 = 220, - MDP_V3_0 = 300, - MDP_V3_0_3 = 303, - MDP_V3_0_4 = 304, - MDP_V3_0_5 = 305, - MDP_V3_1 = 310, - MDP_V4_0 = 400, - MDP_V4_1 = 410, - MDP_V4_2 = 420, - MDP_V4_3 = 430, - MDP_V4_4 = 440, - MDSS_V5 = 500, -}; - -#define NO_PANEL '0' -#define MDDI_PANEL '1' -#define EBI2_PANEL '2' -#define LCDC_PANEL '3' -#define EXT_MDDI_PANEL '4' -#define TV_PANEL '5' -#define DTV_PANEL '7' -#define MIPI_VIDEO_PANEL '8' -#define MIPI_CMD_PANEL '9' -#define WRITEBACK_PANEL 'a' -#define LVDS_PANEL 'b' -#define EDP_PANEL 'c' - -class MDPVersion; - -struct Split { - int mLeft; - int mRight; - Split() : mLeft(0), mRight(0){} - int left() { return mLeft; } - int right() { return mRight; } - friend class MDPVersion; -}; - -struct PanelInfo { - char mType; // Smart or Dumb - int mPartialUpdateEnable; // Partial update feature - int mLeftAlign; // ROI left alignment restriction - int mWidthAlign; // ROI width alignment restriction - int mTopAlign; // ROI top alignment restriction - int mHeightAlign; // ROI height alignment restriction - int mMinROIWidth; // Min width needed for ROI - int mMinROIHeight; // Min height needed for ROI - bool mNeedsROIMerge; // Merge ROI's of both the DSI's - bool mDynFpsSupported; // Panel Supports dyn fps - uint32_t mMinFps; // Min fps supported by panel - uint32_t mMaxFps; // Max fps supported by panel - PanelInfo() : mType(NO_PANEL), mPartialUpdateEnable(0), - mLeftAlign(0), mWidthAlign(0), mTopAlign(0), mHeightAlign(0), - mMinROIWidth(0), mMinROIHeight(0), mNeedsROIMerge(false), - mDynFpsSupported(0), mMinFps(0), mMaxFps(0) {} - friend class MDPVersion; -}; - -class MDPVersion : public Singleton <MDPVersion> -{ -public: - MDPVersion(); - ~MDPVersion(); - int getMDPVersion() {return mMDPVersion;} - char getPanelType() {return mPanelInfo.mType;} - bool hasOverlay() {return mHasOverlay;} - uint8_t getTotalPipes() { - return (uint8_t)(mRGBPipes + mVGPipes + mDMAPipes); - } - uint8_t getRGBPipes() { return mRGBPipes; } - uint8_t getVGPipes() { return mVGPipes; } - uint8_t getDMAPipes() { return mDMAPipes; } - bool supportsDecimation(); - uint32_t getMaxMDPDownscale(); - uint32_t getMaxMDPUpscale(); - bool supportsBWC(); - bool supportsMacroTile(); - int getLeftSplit() { return mSplit.left(); } - int getRightSplit() { return mSplit.right(); } - bool isPartialUpdateEnabled() { return mPanelInfo.mPartialUpdateEnable; } - int getLeftAlign() { return mPanelInfo.mLeftAlign; } - int getWidthAlign() { return mPanelInfo.mWidthAlign; } - int getTopAlign() { return mPanelInfo.mTopAlign; } - int getHeightAlign() { return mPanelInfo.mHeightAlign; } - int getMinROIWidth() { return mPanelInfo.mMinROIWidth; } - int getMinROIHeight() { return mPanelInfo.mMinROIHeight; } - bool needsROIMerge() { return mPanelInfo.mNeedsROIMerge; } - unsigned long getLowBw() { return mLowBw; } - unsigned long getHighBw() { return mHighBw; } - bool isRotDownscaleEnabled() { return mRotDownscale; } - bool isDynFpsSupported() { return mPanelInfo.mDynFpsSupported; } - uint32_t getMinFpsSupported() { return mPanelInfo.mMinFps; } - uint32_t getMaxFpsSupported() { return mPanelInfo.mMaxFps; } - uint32_t getMaxMixerWidth() const { return mMaxMixerWidth; } - bool hasMinCropWidthLimitation() const; - bool isSrcSplit() const; - bool isSrcSplitAlways() const; - bool isRGBScalarSupported() const; - bool is8x26(); - bool is8x74v2(); - bool is8084(); - bool is8092(); - bool is8994(); - bool is8x16(); - bool is8x39(); - -private: - bool updateSysFsInfo(); - void updatePanelInfo(); - bool updateSplitInfo(); - int tokenizeParams(char *inputParams, const char *delim, - char* tokenStr[], int *idx); - int mFd; - int mMDPVersion; - bool mHasOverlay; - uint32_t mMdpRev; - uint8_t mRGBPipes; - uint8_t mVGPipes; - uint8_t mDMAPipes; - uint32_t mFeatures; - uint32_t mMDPDownscale; - uint32_t mMDPUpscale; - bool mMacroTileEnabled; - Split mSplit; - PanelInfo mPanelInfo; - unsigned long mLowBw; //kbps - unsigned long mHighBw; //kbps - bool mSourceSplit; - //Additional property on top of source split - bool mSourceSplitAlways; - bool mRGBHasNoScalar; - bool mRotDownscale; - uint32_t mMaxMixerWidth; //maximum x-res of a given mdss mixer. -}; -}; //namespace qdutils -#endif //INCLUDE_LIBQCOMUTILS_MDPVER diff --git a/msm8909/libqdutils/profiler.cpp b/msm8909/libqdutils/profiler.cpp index b183e6dd..810b0198 100644 --- a/msm8909/libqdutils/profiler.cpp +++ b/msm8909/libqdutils/profiler.cpp @@ -28,6 +28,7 @@ */ #define LOG_NDDEBUG 0 +#define __STDC_FORMAT_MACROS 1 #include <inttypes.h> #include "profiler.h" diff --git a/msm8909/libqdutils/profiler.h b/msm8909/libqdutils/profiler.h index 5f270b02..9ac8157e 100644 --- a/msm8909/libqdutils/profiler.h +++ b/msm8909/libqdutils/profiler.h @@ -33,7 +33,7 @@ #include <stdio.h> #include <utils/Singleton.h> #include <cutils/properties.h> -#include <cutils/log.h> +#include <log/log.h> #ifndef DEBUG_CALC_FPS #define CALC_FPS() ((void)0) diff --git a/msm8909/libqdutils/qdMetaData.cpp b/msm8909/libqdutils/qdMetaData.cpp index 9f8a3248..9f73e443 100644 --- a/msm8909/libqdutils/qdMetaData.cpp +++ b/msm8909/libqdutils/qdMetaData.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018, 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 @@ -30,61 +30,71 @@ #include <errno.h> #include <string.h> #include <sys/mman.h> -#include <cutils/log.h> +#include <log/log.h> +#include <cinttypes> #include <gralloc_priv.h> -#include <inttypes.h> #include "qdMetaData.h" -int setMetaData(private_handle_t *handle, DispParamType paramType, - void *param) { - if (!handle) { - ALOGE("%s: Private handle is null!", __func__); +unsigned long getMetaDataSize() { + return static_cast<unsigned long>(ROUND_UP_PAGESIZE(sizeof(MetaData_t))); +} + +static int validateAndMap(private_handle_t* handle) { + if (private_handle_t::validate(handle)) { + ALOGE("%s: Private handle is invalid - handle:%p", __func__, handle); return -1; } if (handle->fd_metadata == -1) { - ALOGE("%s: Bad fd for extra data!", __func__); + ALOGE("%s: Invalid metadata fd - handle:%p fd: %d", + __func__, handle, handle->fd_metadata); return -1; } - if (!param) { - ALOGE("%s: input param is null!", __func__); - return -1; + + if (!handle->base_metadata) { + auto size = getMetaDataSize(); + void *base = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, + handle->fd_metadata, 0); + if (base == reinterpret_cast<void*>(MAP_FAILED)) { + ALOGE("%s: metadata mmap failed - handle:%p fd: %d err: %s", + __func__, handle, handle->fd_metadata, strerror(errno)); + + return -1; + } + handle->base_metadata = (uintptr_t) base; } - unsigned long size = ROUND_UP_PAGESIZE(sizeof(MetaData_t)); - void *base = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, - handle->fd_metadata, 0); - if (base == reinterpret_cast<void*>(MAP_FAILED)) { - ALOGE("%s: mmap() failed: error is %s!", __func__, strerror(errno)); - return -1; + return 0; +} + +int setMetaData(private_handle_t *handle, DispParamType paramType, + void *param) { + auto err = validateAndMap(handle); + if (err != 0) + return err; + return setMetaDataVa(reinterpret_cast<MetaData_t*>(handle->base_metadata), + paramType, param); +} + +int setMetaDataVa(MetaData_t *data, DispParamType paramType, + void *param) { + if (data == nullptr) + return -EINVAL; + // If parameter is NULL reset the specific MetaData Key + if (!param) { + data->operation &= ~paramType; + // param unset + return 0; } - MetaData_t *data = reinterpret_cast <MetaData_t *>(base); + data->operation |= paramType; switch (paramType) { - case PP_PARAM_HSIC: - memcpy((void *)&data->hsicData, param, sizeof(HSICData_t)); - break; - case PP_PARAM_SHARPNESS: - data->sharpness = *((int32_t *)param); - break; - case PP_PARAM_VID_INTFC: - data->video_interface = *((int32_t *)param); - break; case PP_PARAM_INTERLACED: data->interlaced = *((int32_t *)param); break; - case PP_PARAM_IGC: - memcpy((void *)&data->igcData, param, sizeof(IGCData_t)); - break; - case PP_PARAM_SHARP2: - memcpy((void *)&data->Sharp2Data, param, sizeof(Sharp2Data_t)); - break; - case PP_PARAM_TIMESTAMP: - data->timestamp = *((int64_t *)param); - break; case UPDATE_BUFFER_GEOMETRY: - memcpy((void *)&data->bufferDim, param, sizeof(BufferDim_t)); + data->bufferDim = *((BufferDim_t *)param); break; case UPDATE_REFRESH_RATE: - data->refreshrate = *((uint32_t *)param); + data->refreshrate = *((float *)param); break; case UPDATE_COLOR_SPACE: data->colorSpace = *((ColorSpace_t *)param); @@ -92,12 +102,206 @@ int setMetaData(private_handle_t *handle, DispParamType paramType, case MAP_SECURE_BUFFER: data->mapSecureBuffer = *((int32_t *)param); break; + case S3D_FORMAT: + data->s3dFormat = *((uint32_t *)param); + break; + case LINEAR_FORMAT: + data->linearFormat = *((uint32_t *)param); + break; + case SET_IGC: + data->igc = *((IGC_t *)param); + break; + case SET_SINGLE_BUFFER_MODE: + data->isSingleBufferMode = *((uint32_t *)param); + break; + case SET_S3D_COMP: + data->s3dComp = *((S3DGpuComp_t *)param); + break; + case SET_VT_TIMESTAMP: + data->vtTimeStamp = *((uint64_t *)param); + break; + case COLOR_METADATA: + data->color = *((ColorMetaData *)param); + break; default: ALOGE("Unknown paramType %d", paramType); break; } - if(munmap(base, size)) - ALOGE("%s: failed to unmap ptr %p, err %d", __func__, (void*)base, - errno); return 0; } + +int clearMetaData(private_handle_t *handle, DispParamType paramType) { + auto err = validateAndMap(handle); + if (err != 0) + return err; + return clearMetaDataVa(reinterpret_cast<MetaData_t *>(handle->base_metadata), + paramType); +} + +int clearMetaDataVa(MetaData_t *data, DispParamType paramType) { + if (data == nullptr) + return -EINVAL; + data->operation &= ~paramType; + switch (paramType) { + case SET_S3D_COMP: + data->s3dComp.displayId = -1; + data->s3dComp.s3dMode = 0; + break; + default: + ALOGE("Unknown paramType %d", paramType); + break; + } + return 0; +} + +int getMetaData(private_handle_t *handle, DispFetchParamType paramType, + void *param) { + int ret = validateAndMap(handle); + if (ret != 0) + return ret; + return getMetaDataVa(reinterpret_cast<MetaData_t *>(handle->base_metadata), + paramType, param); +} + +int getMetaDataVa(MetaData_t *data, DispFetchParamType paramType, + void *param) { + // Make sure we send 0 only if the operation queried is present + int ret = -EINVAL; + if (data == nullptr) + return ret; + + switch (paramType) { + case GET_PP_PARAM_INTERLACED: + if (data->operation & PP_PARAM_INTERLACED) { + *((int32_t *)param) = data->interlaced; + ret = 0; + } + break; + case GET_BUFFER_GEOMETRY: + if (data->operation & UPDATE_BUFFER_GEOMETRY) { + *((BufferDim_t *)param) = data->bufferDim; + ret = 0; + } + break; + case GET_REFRESH_RATE: + if (data->operation & UPDATE_REFRESH_RATE) { + *((float *)param) = data->refreshrate; + ret = 0; + } + break; + case GET_COLOR_SPACE: + if (data->operation & UPDATE_COLOR_SPACE) { + *((ColorSpace_t *)param) = data->colorSpace; + ret = 0; + } + break; + case GET_MAP_SECURE_BUFFER: + if (data->operation & MAP_SECURE_BUFFER) { + *((int32_t *)param) = data->mapSecureBuffer; + ret = 0; + } + break; + case GET_S3D_FORMAT: + if (data->operation & S3D_FORMAT) { + *((uint32_t *)param) = data->s3dFormat; + ret = 0; + } + break; + case GET_LINEAR_FORMAT: + if (data->operation & LINEAR_FORMAT) { + *((uint32_t *)param) = data->linearFormat; + ret = 0; + } + break; + case GET_IGC: + if (data->operation & SET_IGC) { + *((IGC_t *)param) = data->igc; + ret = 0; + } + break; + case GET_SINGLE_BUFFER_MODE: + if (data->operation & SET_SINGLE_BUFFER_MODE) { + *((uint32_t *)param) = data->isSingleBufferMode; + ret = 0; + } + break; + case GET_S3D_COMP: + if (data->operation & SET_S3D_COMP) { + *((S3DGpuComp_t *)param) = data->s3dComp; + ret = 0; + } + break; + case GET_VT_TIMESTAMP: + if (data->operation & SET_VT_TIMESTAMP) { + *((uint64_t *)param) = data->vtTimeStamp; + ret = 0; + } + break; + case GET_COLOR_METADATA: + if (data->operation & COLOR_METADATA) { + *((ColorMetaData *)param) = data->color; + ret = 0; + } + break; + default: + ALOGE("Unknown paramType %d", paramType); + break; + } + return ret; +} + +int copyMetaData(struct private_handle_t *src, struct private_handle_t *dst) { + auto err = validateAndMap(src); + if (err != 0) + return err; + + err = validateAndMap(dst); + if (err != 0) + return err; + + MetaData_t *src_data = reinterpret_cast <MetaData_t *>(src->base_metadata); + MetaData_t *dst_data = reinterpret_cast <MetaData_t *>(dst->base_metadata); + *dst_data = *src_data; + return 0; +} + +int copyMetaDataVaToHandle(MetaData_t *src_data, struct private_handle_t *dst) { + int err = -EINVAL; + if (src_data == nullptr) + return err; + + err = validateAndMap(dst); + if (err != 0) + return err; + + MetaData_t *dst_data = reinterpret_cast <MetaData_t *>(dst->base_metadata); + *dst_data = *src_data; + return 0; +} + +int copyMetaDataHandleToVa(struct private_handle_t *src, MetaData_t *dst_data) { + int err = -EINVAL; + if (dst_data == nullptr) + return err; + + err = validateAndMap(src); + if (err != 0) + return err; + + MetaData_t *src_data = reinterpret_cast <MetaData_t *>(src->base_metadata); + *dst_data = *src_data; + return 0; +} + +int copyMetaDataVaToVa(MetaData_t *src_data, MetaData_t *dst_data) { + int err = -EINVAL; + if (src_data == nullptr) + return err; + + if (dst_data == nullptr) + return err; + + *dst_data = *src_data; + return 0; +} + diff --git a/msm8909/libqdutils/qdMetaData.h b/msm8909/libqdutils/qdMetaData.h index 32d788e6..afe86d31 100644 --- a/msm8909/libqdutils/qdMetaData.h +++ b/msm8909/libqdutils/qdMetaData.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018, 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 @@ -30,16 +30,25 @@ #ifndef _QDMETADATA_H #define _QDMETADATA_H +#include <color_metadata.h> + #ifdef __cplusplus extern "C" { #endif -#define MAX_IGC_LUT_ENTRIES 256 +#define MAX_UBWC_STATS_LENGTH 32 enum ColorSpace_t{ ITU_R_601, ITU_R_601_FR, ITU_R_709, + ITU_R_2020, + ITU_R_2020_FR, +}; + +enum IGC_t { + IGC_NotSpecified, + IGC_sRGB, }; struct HSICData_t { @@ -49,36 +58,52 @@ struct HSICData_t { float contrast; }; -struct Sharp2Data_t { - int32_t strength; - uint32_t edge_thr; - uint32_t smooth_thr; - uint32_t noise_thr; +struct BufferDim_t { + int32_t sliceWidth; + int32_t sliceHeight; }; -struct IGCData_t{ - uint16_t c0[MAX_IGC_LUT_ENTRIES]; - uint16_t c1[MAX_IGC_LUT_ENTRIES]; - uint16_t c2[MAX_IGC_LUT_ENTRIES]; +enum UBWC_Version { + UBWC_UNUSED = 0, + UBWC_1_0 = 0x1, + UBWC_2_0 = 0x2, + UBWC_MAX_VERSION = 0xFF, }; -struct BufferDim_t { - int32_t sliceWidth; - int32_t sliceHeight; +struct UBWC_2_0_Stats { + uint32_t nCRStatsTile32; /**< UBWC Stats info for 32 Byte Tile */ + uint32_t nCRStatsTile64; /**< UBWC Stats info for 64 Byte Tile */ + uint32_t nCRStatsTile96; /**< UBWC Stats info for 96 Byte Tile */ + uint32_t nCRStatsTile128; /**< UBWC Stats info for 128 Byte Tile */ + uint32_t nCRStatsTile160; /**< UBWC Stats info for 160 Byte Tile */ + uint32_t nCRStatsTile192; /**< UBWC Stats info for 192 Byte Tile */ + uint32_t nCRStatsTile256; /**< UBWC Stats info for 256 Byte Tile */ +}; + +struct UBWCStats { + enum UBWC_Version version; /* Union depends on this version. */ + uint8_t bDataValid; /* If [non-zero], CR Stats data is valid. + * Consumers may use stats data. + * If [zero], CR Stats data is invalid. + * Consumers *Shall* not use stats data */ + union { + struct UBWC_2_0_Stats ubwc_stats; + uint32_t reserved[MAX_UBWC_STATS_LENGTH]; /* This is for future */ + }; +}; + +struct S3DGpuComp_t { + int32_t displayId; /* on which display S3D is composed by client */ + uint32_t s3dMode; /* the S3D format of this layer to be accessed by client */ }; struct MetaData_t { int32_t operation; int32_t interlaced; struct BufferDim_t bufferDim; - struct HSICData_t hsicData; - int32_t sharpness; - int32_t video_interface; - struct IGCData_t igcData; - struct Sharp2Data_t Sharp2Data; - int64_t timestamp; - uint32_t refreshrate; + float refreshrate; enum ColorSpace_t colorSpace; + enum IGC_t igc; /* Gralloc sets PRIV_SECURE_BUFFER flag to inform that the buffers are from * ION_SECURE. which should not be mapped. However, for GPU post proc * feature, GFX needs to map this buffer, in the client context and in SF @@ -86,25 +111,87 @@ struct MetaData_t { * for clients to set, and GPU will to read and know when to map the * SECURE_BUFFER(ION) */ int32_t mapSecureBuffer; + /* The supported formats are defined in gralloc_priv.h to + * support legacy code*/ + uint32_t s3dFormat; + /* VENUS output buffer is linear for UBWC Interlaced video */ + uint32_t linearFormat; + /* Set by graphics to indicate that this buffer will be written to but not + * swapped out */ + uint32_t isSingleBufferMode; + /* Indicate GPU to draw S3D layer on dedicate display device */ + struct S3DGpuComp_t s3dComp; + + /* Set by camera to program the VT Timestamp */ + uint64_t vtTimeStamp; + /* Color Aspects + HDR info */ + ColorMetaData color; + /* Consumer should read this data as follows based on + * Gralloc flag "interlaced" listed above. + * [0] : If it is progressive. + * [0] : Top field, if it is interlaced. + * [1] : Do not read, if it is progressive. + * [1] : Bottom field, if it is interlaced. + */ + struct UBWCStats ubwcCRStats[2]; }; enum DispParamType { - PP_PARAM_HSIC = 0x0001, - PP_PARAM_SHARPNESS = 0x0002, - PP_PARAM_INTERLACED = 0x0004, - PP_PARAM_VID_INTFC = 0x0008, - PP_PARAM_IGC = 0x0010, - PP_PARAM_SHARP2 = 0x0020, - PP_PARAM_TIMESTAMP = 0x0040, - UPDATE_BUFFER_GEOMETRY = 0x0080, - UPDATE_REFRESH_RATE = 0x0100, - UPDATE_COLOR_SPACE = 0x0200, - MAP_SECURE_BUFFER = 0x400, + SET_VT_TIMESTAMP = 0x0001, + COLOR_METADATA = 0x0002, + PP_PARAM_INTERLACED = 0x0004, + UNUSED2 = 0x0008, + UNUSED3 = 0x0010, + UNUSED4 = 0x0020, + SET_UBWC_CR_STATS_INFO = 0x0040, + UPDATE_BUFFER_GEOMETRY = 0x0080, + UPDATE_REFRESH_RATE = 0x0100, + UPDATE_COLOR_SPACE = 0x0200, + MAP_SECURE_BUFFER = 0x0400, + S3D_FORMAT = 0x0800, + LINEAR_FORMAT = 0x1000, + SET_IGC = 0x2000, + SET_SINGLE_BUFFER_MODE = 0x4000, + SET_S3D_COMP = 0x8000, +}; + +enum DispFetchParamType { + GET_VT_TIMESTAMP = 0x0001, + GET_COLOR_METADATA = 0x0002, + GET_PP_PARAM_INTERLACED = 0x0004, + GET_UBWC_CR_STATS_INFO = 0x0040, + GET_BUFFER_GEOMETRY = 0x0080, + GET_REFRESH_RATE = 0x0100, + GET_COLOR_SPACE = 0x0200, + GET_MAP_SECURE_BUFFER = 0x0400, + GET_S3D_FORMAT = 0x0800, + GET_LINEAR_FORMAT = 0x1000, + GET_IGC = 0x2000, + GET_SINGLE_BUFFER_MODE = 0x4000, + GET_S3D_COMP = 0x8000, }; struct private_handle_t; int setMetaData(struct private_handle_t *handle, enum DispParamType paramType, - void *param); + void *param); +int setMetaDataVa(struct MetaData_t* data, enum DispParamType paramType, + void *param); + +int getMetaData(struct private_handle_t *handle, + enum DispFetchParamType paramType, + void *param); +int getMetaDataVa(struct MetaData_t* data, enum DispFetchParamType paramType, + void *param); + +int copyMetaData(struct private_handle_t *src, struct private_handle_t *dst); +int copyMetaDataVaToHandle(struct MetaData_t *src, struct private_handle_t *dst); +int copyMetaDataHandleToVa(struct private_handle_t* src, struct MetaData_t *dst); +int copyMetaDataVaToVa(struct MetaData_t *src, struct MetaData_t *dst); + +int clearMetaData(struct private_handle_t *handle, enum DispParamType paramType); +int clearMetaDataVa(struct MetaData_t *data, enum DispParamType paramType); + +unsigned long getMetaDataSize(); #ifdef __cplusplus } diff --git a/msm8909/libqdutils/qd_utils.cpp b/msm8909/libqdutils/qd_utils.cpp index 05842167..fc01eab0 100644 --- a/msm8909/libqdutils/qd_utils.cpp +++ b/msm8909/libqdutils/qd_utils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013, 2018 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 @@ -27,57 +27,152 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <unistd.h> +#include <gralloc_priv.h> #include "qd_utils.h" -#define QD_UTILS_DEBUG 0 namespace qdutils { -#ifdef HDMI_STUB -int getHDMINode(void) -{ - ALOGD_IF(QD_UTILS_DEBUG, "%s: HDMI_STUB\n", __func__); - return -1; -} -int getEdidRawData(char *buffer) -{ - ALOGD_IF(QD_UTILS_DEBUG, "%s: HDMI_STUB\n", __func__); - (void) buffer; +static int parseLine(char *input, char *tokens[], const uint32_t maxToken, uint32_t *count) { + char *tmpToken = NULL; + char *tmpPtr; + uint32_t index = 0; + const char *delim = ", =\n"; + if (!input) { + return -1; + } + tmpToken = strtok_r(input, delim, &tmpPtr); + while (tmpToken && index < maxToken) { + tokens[index++] = tmpToken; + tmpToken = strtok_r(NULL, delim, &tmpPtr); + } + *count = index; + return 0; } -#else -int getHDMINode(void) -{ + +static int getExternalNode(const char *type) { FILE *displayDeviceFP = NULL; char fbType[MAX_FRAME_BUFFER_NAME_SIZE]; char msmFbTypePath[MAX_FRAME_BUFFER_NAME_SIZE]; int j = 0; - for(j = 0; j < HWC_NUM_DISPLAY_TYPES; j++) { + for(j = 0; j < kFBNodeMax; j++) { snprintf (msmFbTypePath, sizeof(msmFbTypePath), - "/sys/class/graphics/fb%d/msm_fb_type", j); + "/sys/devices/virtual/graphics/fb%d/msm_fb_type", j); displayDeviceFP = fopen(msmFbTypePath, "r"); if(displayDeviceFP) { fread(fbType, sizeof(char), MAX_FRAME_BUFFER_NAME_SIZE, displayDeviceFP); - if(strncmp(fbType, "dtv panel", strlen("dtv panel")) == 0) { - ALOGD("%s: HDMI is at fb%d", __func__, j); + if(strncmp(fbType, type, strlen(type)) == 0) { + ALOGD("%s: %s is at fb%d", __func__, type, j); fclose(displayDeviceFP); break; } fclose(displayDeviceFP); } else { - ALOGE("%s: Failed to open fb node %d", __func__, j); + ALOGE("%s: Failed to open fb node %s", __func__, msmFbTypePath); } } - if (j < HWC_NUM_DISPLAY_TYPES) + if (j < kFBNodeMax) return j; else - ALOGE("%s: Failed to find HDMI node", __func__); + ALOGE("%s: Failed to find %s node", __func__, type); return -1; } +static int querySDEInfoDRM(HWQueryType type, int *value) { + char property[PROPERTY_VALUE_MAX] = {0}; + + // TODO(user): If future targets don't support WB UBWC, add separate + // properties in target specific system.prop and have clients like WFD + // directly rely on those. + switch(type) { + case HAS_UBWC: + case HAS_WB_UBWC: // WFD stack still uses this + *value = 1; + property_get(DISABLE_UBWC_PROP, property, "0"); + if(!(strncmp(property, "1", PROPERTY_VALUE_MAX)) || + !(strncmp(property, "true", PROPERTY_VALUE_MAX))) { + *value = 0; + } + break; + default: + ALOGE("Invalid query type %d", type); + return -EINVAL; + } + + return 0; +} + +static int querySDEInfoFB(HWQueryType type, int *value) { + FILE *fileptr = NULL; + const char *featureName; + char stringBuffer[MAX_STRING_LENGTH]; + uint32_t tokenCount = 0; + const uint32_t maxCount = 10; + char *tokens[maxCount] = { NULL }; + + switch(type) { + case HAS_UBWC: + featureName = "ubwc"; + break; + case HAS_WB_UBWC: + featureName = "wb_ubwc"; + break; + default: + ALOGE("Invalid query type %d", type); + return -EINVAL; + } + + fileptr = fopen("/sys/devices/virtual/graphics/fb0/mdp/caps", "rb"); + if (!fileptr) { + ALOGE("File '%s' not found", stringBuffer); + return -EINVAL; + } + + size_t len = MAX_STRING_LENGTH; + ssize_t read; + char *line = stringBuffer; + while ((read = getline(&line, &len, fileptr)) != -1) { + // parse the line and update information accordingly + if (parseLine(line, tokens, maxCount, &tokenCount)) { + continue; + } + + if (strncmp(tokens[0], "features", strlen("features"))) { + continue; + } + + for (uint32_t i = 0; i < tokenCount; i++) { + if (!strncmp(tokens[i], featureName, strlen(featureName))) { + *value = 1; + } + } + } + fclose(fileptr); + + return 0; +} + +int querySDEInfo(HWQueryType type, int *value) { + if (!value) { + return -EINVAL; + } + + if (getDriverType() == DriverType::DRM) { + return querySDEInfoDRM(type, value); + } + + return querySDEInfoFB(type, value); +} + +int getHDMINode(void) { + return getExternalNode("dtv panel"); +} + int getEdidRawData(char *buffer) { int size; @@ -91,12 +186,12 @@ int getEdidRawData(char *buffer) } snprintf(msmFbTypePath, sizeof(msmFbTypePath), - "/sys/class/graphics/fb%d/edid_raw_data", node_id); + "/sys/devices/virtual/graphics/fb%d/edid_raw_data", node_id); - edidFile = open(msmFbTypePath, O_RDONLY, 0); + edidFile = open(msmFbTypePath, O_RDONLY, 0); if (edidFile < 0) { - ALOGE("%s no edid raw data found", __func__); + ALOGE("%s no edid raw data found %s", __func__,msmFbTypePath); return 0; } @@ -104,34 +199,162 @@ int getEdidRawData(char *buffer) close(edidFile); return size; } -#endif - -/* Calculates the aspect ratio for based on src & dest */ -void getAspectRatioPosition(int destWidth, int destHeight, int srcWidth, - int srcHeight, hwc_rect_t& rect) { - int x =0, y =0; - - if (srcWidth * destHeight > destWidth * srcHeight) { - srcHeight = destWidth * srcHeight / srcWidth; - srcWidth = destWidth; - } else if (srcWidth * destHeight < destWidth * srcHeight) { - srcWidth = destHeight * srcWidth / srcHeight; - srcHeight = destHeight; - } else { - srcWidth = destWidth; - srcHeight = destHeight; - } - if (srcWidth > destWidth) srcWidth = destWidth; - if (srcHeight > destHeight) srcHeight = destHeight; - x = (destWidth - srcWidth) / 2; - y = (destHeight - srcHeight) / 2; - ALOGD_IF(QD_UTILS_DEBUG, "%s: AS Position: x = %d, y = %d w = %d h = %d", - __FUNCTION__, x, y, srcWidth , srcHeight); - // Convert it back to hwc_rect_t - rect.left = x; - rect.top = y; - rect.right = srcWidth + rect.left; - rect.bottom = srcHeight + rect.top; + +bool isDPConnected() { + char connectPath[MAX_FRAME_BUFFER_NAME_SIZE]; + FILE *connectFile = NULL; + size_t len = MAX_STRING_LENGTH; + char stringBuffer[MAX_STRING_LENGTH]; + char *line = stringBuffer; + + int nodeId = getExternalNode("dp panel"); + if (nodeId < 0) { + ALOGE("%s no DP node found", __func__); + return false; + } + + snprintf(connectPath, sizeof(connectPath), + "/sys/devices/virtual/graphics/fb%d/connected", nodeId); + + connectFile = fopen(connectPath, "rb"); + if (!connectFile) { + ALOGW("Failed to open connect node for device node %s", connectPath); + return false; + } + + if (getline(&line, &len, connectFile) < 0) { + fclose(connectFile); + return false; + } + + fclose(connectFile); + + return atoi(line); +} + +int getDPTestConfig(uint32_t *panelBpp, uint32_t *patternType) { + if (!panelBpp || !patternType) { + return -1; + } + + char configPath[MAX_FRAME_BUFFER_NAME_SIZE]; + FILE *configFile = NULL; + uint32_t tokenCount = 0; + const uint32_t maxCount = 10; + char *tokens[maxCount] = { NULL }; + size_t len = MAX_STRING_LENGTH; + char stringBuffer[MAX_STRING_LENGTH]; + char *line = stringBuffer; + + int nodeId = getExternalNode("dp panel"); + if (nodeId < 0) { + ALOGE("%s no DP node found", __func__); + return -EINVAL; + } + + snprintf(configPath, sizeof(configPath), + "/sys/devices/virtual/graphics/fb%d/config", nodeId); + + configFile = fopen(configPath, "rb"); + if (!configFile) { + ALOGW("Failed to open config node for device node %s", configPath); + return -EINVAL; + } + + while (getline(&line, &len, configFile) != -1) { + if (!parseLine(line, tokens, maxCount, &tokenCount)) { + if (!strncmp(tokens[0], "bpp", strlen("bpp"))) { + *panelBpp = static_cast<uint32_t>(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "pattern", strlen("pattern"))) { + *patternType = static_cast<uint32_t>(atoi(tokens[1])); + } + } + } + + fclose(configFile); + + return 0; +} + +DriverType getDriverType() { + const char *fb_caps = "/sys/devices/virtual/graphics/fb0/mdp/caps"; + // 0 - File exists + return access(fb_caps, F_OK) ? DriverType::DRM : DriverType::FB; +} + +const char *GetHALPixelFormatString(int format) { + switch (format) { + case HAL_PIXEL_FORMAT_RGBA_8888: + return "RGBA_8888"; + case HAL_PIXEL_FORMAT_RGBX_8888: + return "RGBX_8888"; + case HAL_PIXEL_FORMAT_RGB_888: + return "RGB_888"; + case HAL_PIXEL_FORMAT_RGB_565: + return "RGB_565"; + case HAL_PIXEL_FORMAT_BGR_565: + return "BGR_565"; + case HAL_PIXEL_FORMAT_BGRA_8888: + return "BGRA_8888"; + case HAL_PIXEL_FORMAT_RGBA_5551: + return "RGBA_5551"; + case HAL_PIXEL_FORMAT_RGBA_4444: + return "RGBA_4444"; + case HAL_PIXEL_FORMAT_YV12: + return "YV12"; + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + return "YCbCr_422_SP_NV16"; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + return "YCrCb_420_SP_NV21"; + case HAL_PIXEL_FORMAT_YCbCr_422_I: + return "YCbCr_422_I_YUY2"; + case HAL_PIXEL_FORMAT_YCrCb_422_I: + return "YCrCb_422_I_YVYU"; + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + return "NV12_ENCODEABLE"; + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: + return "YCbCr_420_SP_TILED_TILE_4x2"; + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + return "YCbCr_420_SP"; + case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: + return "YCrCb_420_SP_ADRENO"; + case HAL_PIXEL_FORMAT_YCrCb_422_SP: + return "YCrCb_422_SP"; + case HAL_PIXEL_FORMAT_R_8: + return "R_8"; + case HAL_PIXEL_FORMAT_RG_88: + return "RG_88"; + case HAL_PIXEL_FORMAT_INTERLACE: + return "INTERLACE"; + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: + return "YCbCr_420_SP_VENUS"; + case HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS: + return "YCrCb_420_SP_VENUS"; + case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC: + return "YCbCr_420_SP_VENUS_UBWC"; + case HAL_PIXEL_FORMAT_RGBA_1010102: + return "RGBA_1010102"; + case HAL_PIXEL_FORMAT_ARGB_2101010: + return "ARGB_2101010"; + case HAL_PIXEL_FORMAT_RGBX_1010102: + return "RGBX_1010102"; + case HAL_PIXEL_FORMAT_XRGB_2101010: + return "XRGB_2101010"; + case HAL_PIXEL_FORMAT_BGRA_1010102: + return "BGRA_1010102"; + case HAL_PIXEL_FORMAT_ABGR_2101010: + return "ABGR_2101010"; + case HAL_PIXEL_FORMAT_BGRX_1010102: + return "BGRX_1010102"; + case HAL_PIXEL_FORMAT_XBGR_2101010: + return "XBGR_2101010"; + case HAL_PIXEL_FORMAT_YCbCr_420_P010: + return "YCbCr_420_P010"; + case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC: + return "YCbCr_420_TP10_UBWC"; + default: + return "Unknown_format"; + } } }; //namespace qdutils diff --git a/msm8909/libqdutils/qd_utils.h b/msm8909/libqdutils/qd_utils.h index 1d4bc19e..eed8661f 100644 --- a/msm8909/libqdutils/qd_utils.h +++ b/msm8909/libqdutils/qd_utils.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, The Linux Foundation. All rights reserved. + * Copyright (C) 2013, 2017 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 @@ -35,7 +35,7 @@ #include <ctype.h> #include <fcntl.h> #include <utils/Errors.h> -#include <utils/Log.h> +#include <log/log.h> #include <linux/fb.h> #include <sys/ioctl.h> @@ -45,18 +45,31 @@ #include <hardware/hwcomposer.h> namespace qdutils { -#define EDID_RAW_DATA_SIZE 640 -enum qd_utils { +enum HWQueryType { + HAS_UBWC = 1, + HAS_WB_UBWC = 2 +}; + +enum { + EDID_RAW_DATA_SIZE = 640, MAX_FRAME_BUFFER_NAME_SIZE = 128, MAX_SYSFS_FILE_PATH = 255, - SUPPORTED_DOWNSCALE_AREA = (1920*1080) + MAX_STRING_LENGTH = 1024, }; -int getHDMINode(void); +int querySDEInfo(HWQueryType type, int *value); int getEdidRawData(char *buffer); +int getHDMINode(void); +bool isDPConnected(); +int getDPTestConfig(uint32_t *panelBpp, uint32_t *patternType); -void getAspectRatioPosition(int destWidth, int destHeight, int srcWidth, - int srcHeight, hwc_rect_t& rect); +enum class DriverType { + FB = 0, + DRM, +}; +DriverType getDriverType(); +const char *GetHALPixelFormatString(int format); +static const int kFBNodeMax = 4; }; //namespace qdutils #endif diff --git a/msm8909/libqservice/Android.bp b/msm8909/libqservice/Android.bp new file mode 100644 index 00000000..fe69d393 --- /dev/null +++ b/msm8909/libqservice/Android.bp @@ -0,0 +1,16 @@ +cc_library_shared { + name: "libqservice", + vendor: true, + defaults: ["display_defaults"], + shared_libs: ["libbinder"], + cflags: [ + "-DLOG_TAG=\"qdqservice\"", + "-Wno-sign-conversion", + ], + srcs: [ + "QService.cpp", + "IQService.cpp", + "IQClient.cpp", + "IQHDMIClient.cpp", + ], +} diff --git a/msm8909/libqservice/Android.mk b/msm8909/libqservice/Android.mk deleted file mode 100644 index e2a82550..00000000 --- a/msm8909/libqservice/Android.mk +++ /dev/null @@ -1,21 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(LOCAL_PATH)/../common.mk -include $(CLEAR_VARS) - -LOCAL_MODULE := libqservice -LOCAL_MODULE_TAGS := optional -LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes) -LOCAL_SHARED_LIBRARIES := $(common_libs) libbinder -LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdqservice\" -LOCAL_CFLAGS += -Wno-error -LOCAL_CLANG := $(common_clang_flags) -LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) -LOCAL_SRC_FILES := QService.cpp \ - IQService.cpp \ - IQClient.cpp -LOCAL_COPY_HEADERS_TO := $(common_header_export_path) -LOCAL_COPY_HEADERS := IQService.h \ - IQClient.h - - -include $(BUILD_SHARED_LIBRARY) diff --git a/msm8909/libqservice/IQHDMIClient.cpp b/msm8909/libqservice/IQHDMIClient.cpp new file mode 100644 index 00000000..6379e574 --- /dev/null +++ b/msm8909/libqservice/IQHDMIClient.cpp @@ -0,0 +1,103 @@ +/* +* Copyright (c) 2014 The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation. nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include <log/log.h> +#include <binder/Parcel.h> +#include "IQHDMIClient.h" + +using namespace android; +namespace qClient { + +enum { + HDMI_CONNECTED = IBinder::FIRST_CALL_TRANSACTION, + CEC_MESSAGE_RECEIVED +}; + +class BpQHDMIClient : public BpInterface<IQHDMIClient> +{ +public: + BpQHDMIClient(const sp<IBinder>& impl) + :BpInterface<IQHDMIClient>(impl) + { + } + + void onHdmiHotplug(int connected) + { + Parcel data, reply; + data.writeInterfaceToken(IQHDMIClient::getInterfaceDescriptor()); + data.writeInt32(connected); + remote()->transact(HDMI_CONNECTED, data, &reply, IBinder::FLAG_ONEWAY); + } + + void onCECMessageRecieved(char *msg, ssize_t len) + { + Parcel data, reply; + data.writeInterfaceToken(IQHDMIClient::getInterfaceDescriptor()); + data.writeInt32((int32_t)len); + void *buf = data.writeInplace(len); + if (buf != NULL) + memcpy(buf, msg, len); + remote()->transact(CEC_MESSAGE_RECEIVED, data, &reply, + IBinder::FLAG_ONEWAY); + } +}; + +IMPLEMENT_META_INTERFACE(QHDMIClient, + "android.display.IQHDMIClient"); + +status_t BnQHDMIClient::onTransact(uint32_t code, const Parcel& data, + Parcel* reply, uint32_t flags) +{ + switch(code) { + case HDMI_CONNECTED: { + CHECK_INTERFACE(IQHDMIClient, data, reply); + int connected = data.readInt32(); + onHdmiHotplug(connected); + return NO_ERROR; + } + case CEC_MESSAGE_RECEIVED: { + CHECK_INTERFACE(IQHDMIClient, data, reply); + ssize_t len = data.readInt32(); + const void* msg; + if(len >= 0 && len <= (ssize_t) data.dataAvail()) { + msg = data.readInplace(len); + } else { + msg = NULL; + len = 0; + } + if (msg != NULL) + onCECMessageRecieved((char*) msg, len); + return NO_ERROR; + } + default: { + return BBinder::onTransact(code, data, reply, flags); + } + } +} + +}; //namespace qClient diff --git a/msm8909/libhwcomposer/hwc_ad.h b/msm8909/libqservice/IQHDMIClient.h index 0be5f5df..c3d012a4 100644 --- a/msm8909/libhwcomposer/hwc_ad.h +++ b/msm8909/libqservice/IQHDMIClient.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013 The Linux Foundation. All rights reserved. +* Copyright (c) 2014 The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -27,40 +27,31 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef HWC_AD_H -#define HWC_AD_H +#ifndef HDMI_EVENTS_LISTENER_H_ +#define HDMI_EVENTS_LISTENER_H_ -#include <overlayUtils.h> -#include <hwc_utils.h> +#include <utils/RefBase.h> +#include <binder/IInterface.h> -struct hwc_context_t; +namespace qClient { -namespace qhwc { - -class AssertiveDisplay { +class IQHDMIClient : public android::IInterface +{ public: - AssertiveDisplay(hwc_context_t *ctx); - void markDoable(hwc_context_t *ctx, const hwc_display_contents_1_t* list); - bool prepare(hwc_context_t *ctx, const hwc_rect_t& crop, - const overlay::utils::Whf& whf, - const private_handle_t *hnd); - bool draw(hwc_context_t *ctx, int fd, uint32_t offset); - //Resets a few members on each draw round - void reset() { mDoable = false; - mDest = overlay::utils::OV_INVALID; - } - bool isDoable() const { return mDoable; } - int getDstFd() const; - uint32_t getDstOffset() const; + DECLARE_META_INTERFACE(QHDMIClient); + virtual void onHdmiHotplug(int connected) = 0; + virtual void onCECMessageRecieved(char *msg, ssize_t len) = 0; +}; -private: - bool mDoable; - bool mTurnedOff; - //State of feature existence on certain devices and configs. - bool mFeatureEnabled; - overlay::utils::eDest mDest; - void turnOffAD(); +class BnQHDMIClient : public android::BnInterface<IQHDMIClient> +{ +public: + virtual android::status_t onTransact( uint32_t code, + const android::Parcel& data, + android::Parcel* reply, uint32_t flags = 0); }; -} -#endif +}; //namespace qhdmi + +#endif // HDMI_EVENTS_LISTENER_H_ + diff --git a/msm8909/libqservice/IQService.cpp b/msm8909/libqservice/IQService.cpp index 9e2b0f52..d45a141c 100644 --- a/msm8909/libqservice/IQService.cpp +++ b/msm8909/libqservice/IQService.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved. + * Copyright (C) 2012-2016, The Linux Foundation. All rights reserved. * * Not a Contribution, Apache license notifications and license are * retained for attribution purposes only. @@ -25,8 +25,8 @@ #include <binder/IBinder.h> #include <binder/IInterface.h> #include <binder/IPCThreadState.h> +#include <cutils/android_filesystem_config.h> #include <utils/Errors.h> -#include <private/android_filesystem_config.h> #include <IQService.h> #define QSERVICE_DEBUG 0 @@ -45,13 +45,22 @@ public: : BpInterface<IQService>(impl) {} virtual void connect(const sp<IQClient>& client) { - ALOGD_IF(QSERVICE_DEBUG, "%s: connect client", __FUNCTION__); + ALOGD_IF(QSERVICE_DEBUG, "%s: connect HWC client", __FUNCTION__); Parcel data, reply; data.writeInterfaceToken(IQService::getInterfaceDescriptor()); data.writeStrongBinder(IInterface::asBinder(client)); - remote()->transact(CONNECT, data, &reply); + remote()->transact(CONNECT_HWC_CLIENT, data, &reply); } + virtual void connect(const sp<IQHDMIClient>& client) { + ALOGD_IF(QSERVICE_DEBUG, "%s: connect HDMI client", __FUNCTION__); + Parcel data, reply; + data.writeInterfaceToken(IQService::getInterfaceDescriptor()); + data.writeStrongBinder(IInterface::asBinder(client)); + remote()->transact(CONNECT_HDMI_CLIENT, data, &reply); + } + + virtual android::status_t dispatch(uint32_t command, const Parcel* inParcel, Parcel* outParcel) { ALOGD_IF(QSERVICE_DEBUG, "%s: dispatch in:%p", __FUNCTION__, inParcel); @@ -70,8 +79,6 @@ IMPLEMENT_META_INTERFACE(QService, "android.display.IQService"); // ---------------------------------------------------------------------- -static void getProcName(int pid, char *buf, int size); - status_t BnQService::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { @@ -80,33 +87,41 @@ status_t BnQService::onTransact( IPCThreadState* ipc = IPCThreadState::self(); const int callerPid = ipc->getCallingPid(); const int callerUid = ipc->getCallingUid(); - const int MAX_BUF_SIZE = 1024; - char callingProcName[MAX_BUF_SIZE] = {0}; - - getProcName(callerPid, callingProcName, MAX_BUF_SIZE); const bool permission = (callerUid == AID_MEDIA || callerUid == AID_GRAPHICS || callerUid == AID_ROOT || - callerUid == AID_SYSTEM); + callerUid == AID_CAMERASERVER || + callerUid == AID_AUDIO || + callerUid == AID_SYSTEM || + callerUid == AID_MEDIA_CODEC); - if (code == CONNECT) { + if (code == CONNECT_HWC_CLIENT) { CHECK_INTERFACE(IQService, data, reply); if(callerUid != AID_GRAPHICS) { - ALOGE("display.qservice CONNECT access denied: \ - pid=%d uid=%d process=%s", - callerPid, callerUid, callingProcName); + ALOGE("display.qservice CONNECT_HWC_CLIENT access denied: pid=%d uid=%d", + callerPid, callerUid); return PERMISSION_DENIED; } sp<IQClient> client = interface_cast<IQClient>(data.readStrongBinder()); connect(client); return NO_ERROR; + } else if(code == CONNECT_HDMI_CLIENT) { + CHECK_INTERFACE(IQService, data, reply); + if(callerUid != AID_SYSTEM && callerUid != AID_ROOT) { + ALOGE("display.qservice CONNECT_HDMI_CLIENT access denied: pid=%d uid=%d", + callerPid, callerUid); + return PERMISSION_DENIED; + } + sp<IQHDMIClient> client = + interface_cast<IQHDMIClient>(data.readStrongBinder()); + connect(client); + return NO_ERROR; } else if (code > COMMAND_LIST_START && code < COMMAND_LIST_END) { if(!permission) { - ALOGE("display.qservice access denied: command=%d\ - pid=%d uid=%d process=%s", code, callerPid, - callerUid, callingProcName); + ALOGE("display.qservice access denied: command=%d pid=%d uid=%d", + code, callerPid, callerUid); return PERMISSION_DENIED; } CHECK_INTERFACE(IQService, data, reply); @@ -117,20 +132,4 @@ status_t BnQService::onTransact( } } -//Helper -static void getProcName(int pid, char *buf, int size) { - int fd = -1; - snprintf(buf, size, "/proc/%d/cmdline", pid); - fd = open(buf, O_RDONLY); - if (fd < 0) { - strlcpy(buf, "Unknown", size); - } else { - ssize_t len = read(fd, buf, size - 1); - if (len >= 0) - buf[len] = 0; - - close(fd); - } -} - }; // namespace qService diff --git a/msm8909/libqservice/IQService.h b/msm8909/libqservice/IQService.h index 0f0dc4c1..f9aa7fde 100644 --- a/msm8909/libqservice/IQService.h +++ b/msm8909/libqservice/IQService.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012-2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2012-2014, 2016-2017 The Linux Foundation. All rights reserved. * * Not a Contribution, Apache license notifications and license are * retained for attribution purposes only. @@ -28,6 +28,7 @@ #include <binder/IInterface.h> #include <binder/IBinder.h> #include <IQClient.h> +#include <IQHDMIClient.h> namespace qService { @@ -39,25 +40,41 @@ public: DECLARE_META_INTERFACE(QService); enum { COMMAND_LIST_START = android::IBinder::FIRST_CALL_TRANSACTION, - SECURING, // Hardware securing start/end notification - UNSECURING, // Hardware unsecuring start/end notification - CONNECT, // Connect to qservice - SCREEN_REFRESH, // Refresh screen through SF invalidate - EXTERNAL_ORIENTATION, // Set external orientation - BUFFER_MIRRORMODE, // Buffer mirrormode - CHECK_EXTERNAL_STATUS, // Check status of external display - GET_DISPLAY_ATTRIBUTES, // Get display attributes - SET_HSIC_DATA, // Set HSIC on dspp - GET_DISPLAY_VISIBLE_REGION, // Get the visibleRegion for dpy - SET_SECONDARY_DISPLAY_STATUS, // Sets secondary display status - SET_PARTIAL_UPDATE, // Preference on partial update feature - SET_VIEW_FRAME, // Set view frame of display - DYNAMIC_DEBUG, // Enable more logging on the fly - SET_IDLE_TIMEOUT, // Set idle timeout for GPU fallback + GET_PANEL_BRIGHTNESS = 2, // Provides ability to set the panel brightness + SET_PANEL_BRIGHTNESS = 3, // Provides ability to get the panel brightness + CONNECT_HWC_CLIENT = 4, // Connect to qservice + SCREEN_REFRESH = 5, // Refresh screen through SF invalidate + EXTERNAL_ORIENTATION = 6,// Set external orientation + BUFFER_MIRRORMODE = 7, // Buffer mirrormode + CHECK_EXTERNAL_STATUS = 8,// Check status of external display + GET_DISPLAY_ATTRIBUTES = 9,// Get display attributes + SET_HSIC_DATA = 10, // Set HSIC on dspp + GET_DISPLAY_VISIBLE_REGION = 11,// Get the visibleRegion for dpy + SET_SECONDARY_DISPLAY_STATUS = 12,// Sets secondary display status + SET_MAX_PIPES_PER_MIXER = 13,// Set max pipes per mixer for MDPComp + SET_VIEW_FRAME = 14, // Set view frame of display + DYNAMIC_DEBUG = 15, // Enable more logging on the fly + SET_IDLE_TIMEOUT = 16, // Set idle timeout for GPU fallback + TOGGLE_BWC = 17, // Toggle BWC On/Off on targets that support /* Enable/Disable/Set refresh rate dynamically */ - CONFIGURE_DYN_REFRESH_RATE, - QDCM_SVC_CMDS, // request QDCM services. - TOGGLE_SCREEN_UPDATE, // Provides ability to disable screen updates + CONFIGURE_DYN_REFRESH_RATE = 18, + CONTROL_PARTIAL_UPDATE = 19, // Provides ability to enable/disable partial update + TOGGLE_SCREEN_UPDATES = 20, // Provides ability to set the panel brightness + SET_FRAME_DUMP_CONFIG = 21, // Provides ability to set the frame dump config + SET_S3D_MODE = 22, // Set the 3D mode as specified in msm_hdmi_modes.h + CONNECT_HDMI_CLIENT = 23, // Connect HDMI CEC HAL Client + QDCM_SVC_CMDS = 24, // request QDCM services. + SET_ACTIVE_CONFIG = 25, //Set a specified display config + GET_ACTIVE_CONFIG = 26, //Get the current config index + GET_CONFIG_COUNT = 27, //Get the number of supported display configs + GET_DISPLAY_ATTRIBUTES_FOR_CONFIG = 28, //Get attr for specified config + SET_DISPLAY_MODE = 29, // Set display mode to command or video mode + SET_CAMERA_STATUS = 30, // To notify display when camera is on and off + MIN_HDCP_ENCRYPTION_LEVEL_CHANGED = 31, + GET_BW_TRANSACTION_STATUS = 32, //Client can query BW transaction status. + SET_LAYER_MIXER_RESOLUTION = 33, // Enables client to set layer mixer resolution. + SET_COLOR_MODE = 34, // Overrides the QDCM mode on the display + GET_HDR_CAPABILITIES = 35, // Get HDR capabilities for legacy HWC interface COMMAND_LIST_END = 400, }; @@ -72,6 +89,14 @@ public: DEBUG_VSYNC, DEBUG_VD, DEBUG_PIPE_LIFECYCLE, + DEBUG_DRIVER_CONFIG, + DEBUG_ROTATOR, + DEBUG_QDCM, + DEBUG_SCALAR, + DEBUG_CLIENT, + DEBUG_DISPLAY, + DEBUG_MAX_VAL = DEBUG_DISPLAY, // Used to check each bit of the debug command paramater. + // Update DEBUG_MAX_VAL when adding new debug tag. }; enum { @@ -80,8 +105,13 @@ public: ENABLE_PARTIAL_UPDATE, }; - // Register a client that can be notified + // Register a HWC client that can be notified + // This client is generic and is intended to get + // dispatches of all events calling into QService virtual void connect(const android::sp<qClient::IQClient>& client) = 0; + // Register an HDMI client. This client gets notification of HDMI events + // such as plug/unplug and CEC messages + virtual void connect(const android::sp<qClient::IQHDMIClient>& client) = 0; // Generic function to dispatch binder commands // The type of command decides how the data is parceled virtual android::status_t dispatch(uint32_t command, diff --git a/msm8909/libqservice/Makefile.am b/msm8909/libqservice/Makefile.am new file mode 100644 index 00000000..79935b8b --- /dev/null +++ b/msm8909/libqservice/Makefile.am @@ -0,0 +1,18 @@ +h_sources = IQService.h \ + IQClient.h + +cpp_sources = QService.cpp \ + IQService.cpp \ + IQClient.cpp \ + IQHDMIClient.cpp + +library_includedir = $(includedir) +library_include_HEADERS = $(h_sources) + +lib_LTLIBRARIES = libqservice.la +libqservice_la_CC = @CC@ +libqservice_la_SOURCES = $(cpp_sources) +libqservice_la_CFLAGS = $(COMMON_CFLAGS) -DLOG_TAG=\"qdqservice\" +libqservice_la_CPPFLAGS = $(AM_CPPFLAGS) +libqservice_LDADD = -lhardware -lcutils -llog -lbinder +libqservice_la_LDFLAGS = -shared -avoid-version
\ No newline at end of file diff --git a/msm8909/libqservice/QService.cpp b/msm8909/libqservice/QService.cpp index 12dd9956..546ad7ee 100644 --- a/msm8909/libqservice/QService.cpp +++ b/msm8909/libqservice/QService.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-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 @@ -50,24 +50,52 @@ QService::~QService() } void QService::connect(const sp<qClient::IQClient>& client) { - ALOGD_IF(QSERVICE_DEBUG,"client connected"); + ALOGD_IF(QSERVICE_DEBUG,"HWC client connected"); mClient = client; } +void QService::connect(const sp<qClient::IQHDMIClient>& client) { + ALOGD_IF(QSERVICE_DEBUG,"HDMI client connected"); + mHDMIClient = client; +} + status_t QService::dispatch(uint32_t command, const Parcel* inParcel, Parcel* outParcel) { status_t err = (status_t) FAILED_TRANSACTION; IPCThreadState* ipc = IPCThreadState::self(); //Rewind parcel in case we're calling from the same process - if (ipc->getCallingPid() == getpid()) + bool sameProcess = (ipc->getCallingPid() == getpid()); + if(sameProcess) inParcel->setDataPosition(0); if (mClient.get()) { ALOGD_IF(QSERVICE_DEBUG, "Dispatching command: %d", command); err = mClient->notifyCallback(command, inParcel, outParcel); + //Rewind parcel in case we're calling from the same process + if (sameProcess) + outParcel->setDataPosition(0); } return err; } +void QService::onHdmiHotplug(int connected) { + if(mHDMIClient.get()) { + ALOGD_IF(QSERVICE_DEBUG, "%s: HDMI hotplug", __FUNCTION__); + mHDMIClient->onHdmiHotplug(connected); + } else { + ALOGW("%s: Failed to get a valid HDMI client", __FUNCTION__); + } +} + +void QService::onCECMessageReceived(char *msg, ssize_t len) { + if(mHDMIClient.get()) { + ALOGD_IF(QSERVICE_DEBUG, "%s: CEC message received", __FUNCTION__); + mHDMIClient->onCECMessageRecieved(msg, len); + } else { + ALOGW("%s: Failed to get a valid HDMI client", __FUNCTION__); + } +} + + void QService::init() { if(!sQService) { diff --git a/msm8909/libqservice/QService.h b/msm8909/libqservice/QService.h index a8e4cdba..6bb4d7d5 100644 --- a/msm8909/libqservice/QService.h +++ b/msm8909/libqservice/QService.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 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 @@ -32,7 +32,7 @@ #include <utils/Errors.h> #include <sys/types.h> -#include <cutils/log.h> +#include <log/log.h> #include <binder/IServiceManager.h> #include <IQService.h> #include <IQClient.h> @@ -46,13 +46,17 @@ class QService : public BnQService { public: virtual ~QService(); virtual void connect(const android::sp<qClient::IQClient>& client); + virtual void connect(const android::sp<qClient::IQHDMIClient>& client); virtual android::status_t dispatch(uint32_t command, const android::Parcel* data, android::Parcel* reply); + virtual void onHdmiHotplug(int connected); + virtual void onCECMessageReceived(char *msg, ssize_t len); static void init(); private: QService(); android::sp<qClient::IQClient> mClient; + android::sp<qClient::IQHDMIClient> mHDMIClient; static QService *sQService; }; }; // namespace qService diff --git a/msm8909/libqservice/QServiceUtils.h b/msm8909/libqservice/QServiceUtils.h index ff09aa97..8f25253c 100644 --- a/msm8909/libqservice/QServiceUtils.h +++ b/msm8909/libqservice/QServiceUtils.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-15 The Linux Foundation. All rights reserved. +* Copyright (c) 2013-14 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 @@ -62,24 +62,12 @@ inline android::status_t sendSingleParam(uint32_t command, uint32_t value) { // ---------------------------------------------------------------------------- // Convenience wrappers that clients can call // ---------------------------------------------------------------------------- -inline android::status_t securing(uint32_t startEnd) { - return sendSingleParam(qService::IQService::SECURING, startEnd); -} - -inline android::status_t unsecuring(uint32_t startEnd) { - return sendSingleParam(qService::IQService::UNSECURING, startEnd); -} - inline android::status_t screenRefresh() { return sendSingleParam(qService::IQService::SCREEN_REFRESH, 1); } -inline android::status_t setPartialUpdate(uint32_t enable) { - return sendSingleParam(qService::IQService::SET_PARTIAL_UPDATE, enable); -} - inline android::status_t toggleScreenUpdate(uint32_t on) { - return sendSingleParam(qService::IQService::TOGGLE_SCREEN_UPDATE, on); + return sendSingleParam(qService::IQService::TOGGLE_SCREEN_UPDATES, on); } inline android::status_t setExtOrientation(uint32_t orientation) { @@ -91,4 +79,24 @@ inline android::status_t setBufferMirrorMode(uint32_t enable) { return sendSingleParam(qService::IQService::BUFFER_MIRRORMODE, enable); } +inline android::status_t setCameraLaunchStatus(uint32_t on) { + return sendSingleParam(qService::IQService::SET_CAMERA_STATUS, on); +} + +inline bool displayBWTransactionPending() { + android::status_t err = (android::status_t) android::FAILED_TRANSACTION; + bool ret = false; + android::sp<qService::IQService> binder = getBinder(); + android::Parcel inParcel, outParcel; + if(binder != NULL) { + err = binder->dispatch(qService::IQService::GET_BW_TRANSACTION_STATUS, + &inParcel , &outParcel); + if(err != android::NO_ERROR){ + ALOGE("GET_BW_TRANSACTION_STATUS binder call failed err=%d", err); + return ret; + } + } + ret = outParcel.readInt32(); + return ret; +} #endif /* end of include guard: QSERVICEUTILS_H */ diff --git a/msm8909/sdm/include/core/buffer_allocator.h b/msm8909/sdm/include/core/buffer_allocator.h new file mode 100644 index 00000000..6d77bcde --- /dev/null +++ b/msm8909/sdm/include/core/buffer_allocator.h @@ -0,0 +1,159 @@ +/* +* Copyright (c) 2015 - 2017, 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. +*/ + +/*! @file buffer_allocator.h + @brief Interface file for platform specific buffer allocator. + + @details This interface is used by SDM to allocate internal buffers. +*/ + +#ifndef __BUFFER_ALLOCATOR_H__ +#define __BUFFER_ALLOCATOR_H__ + +#include "layer_buffer.h" + +namespace sdm { +/*! @brief Input configuration set by the client for buffer allocation. + + @sa BufferInfo::BufferConfig +*/ + +struct BufferConfig { + uint32_t width = 0; //!< Specifies buffer width for buffer allocation. + uint32_t height = 0; //!< Specifies buffer height for buffer allocation. + LayerBufferFormat format = kFormatInvalid; //!< Specifies buffer format for buffer allocation. + uint32_t buffer_count = 0; //!< Specifies number of buffers to be allocated. + bool secure = false; //!< Specifies buffer to be allocated from + //!< secure region. + bool cache = false; //!< Specifies whether the buffer needs to be cache. + bool secure_camera = false; //!< Specifies buffer to be allocated from specific + //!< secure heap and with a specific alignment. + bool gfx_client = false; //!< Specifies whether buffer is used by gfx. +}; + +/*! @brief Holds the information about the allocated buffer. + + @sa BufferAllocator::AllocateBuffer + @sa BufferAllocator::FreeBuffer + @sa BufferAllocator::GetAllocatedBufferInfo +*/ +struct AllocatedBufferInfo { + int fd = -1; //!< Specifies the fd of the allocated buffer. + uint32_t stride = 0; //!< Specifies allocated buffer stride in bytes. + uint32_t aligned_width = 0; //!< Specifies aligned allocated buffer width in pixels. + uint32_t aligned_height = 0; //!< Specifies aligned allocated buffer height in pixels. + LayerBufferFormat format = kFormatInvalid; // Specifies buffer format for allocated buffer. + uint32_t size = 0; //!< Specifies the size of the allocated buffer. +}; + +/*! @brief Holds the information about the input/output configuration of an output buffer. + + @sa BufferAllocator::AllocateBuffer + @sa BufferAllocator::FreeBuffer +*/ +struct BufferInfo { + BufferConfig buffer_config; //!< Specifies configuration of a buffer to be allocated. + AllocatedBufferInfo alloc_buffer_info; //!< Specifies buffer information of allocated buffer. + + void *private_data = NULL; //!< Pointer to private data. +}; + +/*! @brief Buffer allocator implemented by the client + + @details This class declares prototype for BufferAllocator methods which must be + implemented by the client. Buffer manager in display manager will use these methods to + allocate/deallocate buffers for display manager. + + @sa CoreInterface::CreateCore +*/ +class BufferAllocator { + public: + /*! @brief Method to allocate ouput buffer for the given input configuration. + + @details This method allocates memory based on input configuration. + + @param[in] buffer_info \link BufferInfo \endlink + + @return \link DisplayError \endlink + */ + virtual DisplayError AllocateBuffer(BufferInfo *buffer_info) = 0; + + + /*! @brief Method to deallocate the ouput buffer. + + @details This method deallocates the memory allocated using AllocateBuffer method. + + @param[in] buffer_info \link BufferInfo \endlink + + @return \link DisplayError \endlink + */ + virtual DisplayError FreeBuffer(BufferInfo *buffer_info) = 0; + + + /*! @brief Method to get the buffer size. + + @details This method returns buffer size for a specific configuration mentioned in buffer info. + + @param[in] buffer_info \link BufferInfo \endlink + + @return \link unsigned int \endlink + */ + virtual uint32_t GetBufferSize(BufferInfo *buffer_info) = 0; + + /*! @brief Method to Get the AllocatedBufferInfo only. + + @details This method populates the AllocatedBufferInfo as per the configuration in BufferInfo, + but fd will be invalid. + + @param[in] buffer_info \link BufferInfo \endlink + + @param[out] allocated_buffer_info \link AllocatedBufferInfo \endlink + + @return \link DisplayError \endlink + */ + virtual DisplayError GetAllocatedBufferInfo(const BufferConfig &buffer_config, + AllocatedBufferInfo *allocated_buffer_info) = 0; + + /* + * Retuns a buffer's layout in terms of number of planes, stride and offset of each plane + * Input: AllocatedBufferInfo with a valid aligned width, aligned height, SDM format + * Output: stride for each plane, offset of each plane from base, number of planes + */ + virtual DisplayError GetBufferLayout(const AllocatedBufferInfo &buf_info, + uint32_t stride[4], uint32_t offset[4], + uint32_t *num_planes) { return kErrorNotSupported; } + + protected: + virtual ~BufferAllocator() { } +}; + +} // namespace sdm + +#endif // __BUFFER_ALLOCATOR_H__ + diff --git a/msm8909/sdm/include/core/buffer_sync_handler.h b/msm8909/sdm/include/core/buffer_sync_handler.h new file mode 100644 index 00000000..1dc54138 --- /dev/null +++ b/msm8909/sdm/include/core/buffer_sync_handler.h @@ -0,0 +1,99 @@ +/* +* Copyright (c) 2015, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/*! @file buffer_sync_handler.h + @brief Interface file for platform specific buffer allocator. + + @details SDM will use this interface to wait for buffer sync fd to be signaled/merge + the two buffer sync fds into one. +*/ + +#ifndef __BUFFER_SYNC_HANDLER_H__ +#define __BUFFER_SYNC_HANDLER_H__ + +#include "sdm_types.h" + +namespace sdm { + +/*! @brief Buffer sync handler implemented by the client + + @details This class declares prototype for BufferSyncHandler methods which must be + implemented by the client. SDM will use these methods to wait for buffer sync fd to be + signaled/merge two buffer sync fds into one. + + @sa CoreInterface::CreateCore +*/ +class BufferSyncHandler { + public: + /*! @brief Method to wait for ouput buffer to be released. + + @details This method waits for fd to be signaled by the producer/consumer. + It is responsibility of the caller to close file descriptor. + + @param[in] fd + + @return \link DisplayError \endlink + */ + + virtual DisplayError SyncWait(int fd) = 0; + + /*! @brief Method to merge two sync fds into one sync fd + + @details This method merges two buffer sync fds into one sync fd, if a producer/consumer + requires to wait for more than one sync fds. It is responsibility of the caller to close file + descriptor. + + @param[in] fd1 + @param[in] fd2 + @param[out] merged_fd + + @return \link DisplayError \endlink + */ + + virtual DisplayError SyncMerge(int fd1, int fd2, int *merged_fd) = 0; + + /*! @brief Method to detect if sync fd is signaled + + @details This method detects if sync fd is signaled. It is responsibility of the caller to + close file descriptor. + + @param[in] fd + + @return \link Tue if fd has been signaled \endlink + */ + virtual bool IsSyncSignaled(int fd) = 0; + + protected: + virtual ~BufferSyncHandler() { } +}; + +} // namespace sdm + +#endif // __BUFFER_SYNC_HANDLER_H__ + diff --git a/msm8909/sdm/include/core/core_interface.h b/msm8909/sdm/include/core/core_interface.h new file mode 100644 index 00000000..88cbf75c --- /dev/null +++ b/msm8909/sdm/include/core/core_interface.h @@ -0,0 +1,240 @@ +/* +* Copyright (c) 2014 - 2016, 2018 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. +*/ + +/*! @file core_interface.h + @brief Interface file for core of the display subsystem. + + @details Display core is primarily used for loading and unloading different display device + components viz primary, external and virtual. Display core is a statically linked library which + runs in caller's process context. +*/ +#ifndef __CORE_INTERFACE_H__ +#define __CORE_INTERFACE_H__ + +#include <stdint.h> + +#include "display_interface.h" +#include "sdm_types.h" +#include "buffer_allocator.h" +#include "buffer_sync_handler.h" +#include "socket_handler.h" + +/*! @brief Display manager interface version. + + @details Display manager interfaces are version tagged to maintain backward compatibility. This + version is supplied as a default argument during display core initialization. + + Client may use an older version of interfaces and link to a higher version of display manager + library, but vice versa is not allowed. + + A 32-bit client must use 32-bit display core library and a 64-bit client must use 64-bit display + core library. + + Display manager interfaces follow default data structures alignment. Client must not override the + default padding rules while using these interfaces. + + @warning It is assumed that client upgrades or downgrades display core interface all at once + and recompile all binaries which use these interfaces. Mix and match of these interfaces can + lead to unpredictable behaviour. + + @sa CoreInterface::CreateCore +*/ +#define SDM_REVISION_MAJOR (1) +#define SDM_REVISION_MINOR (0) + +#define SDM_VERSION_TAG ((uint32_t) ((SDM_REVISION_MAJOR << 24) | (SDM_REVISION_MINOR << 16) | \ + (sizeof(SDMCompatibility) << 8) | sizeof(int *))) + +namespace sdm { + +/*! @brief Forward declaration for debug handler. +*/ +class DebugHandler; + +/*! @brief This enum represents max bandwidth limit mode. + + @sa DisplayInterface::SetMaxBandwidthMode +*/ +enum HWBwModes { + kBwDefault, //!< Default state. No change in device bandwidth limit. + kBwCamera, //!< Camera is on. Bandwidth limit should be reduced accordingly. + kBwVFlip, //!< VFlip is required. Reduce bandwidth limit accordingly. + kBwHFlip, //!< HFlip is required. Reduce bandwidth limit accordingly. + kBwModeMax, //!< Limiter for maximum available bandwidth modes. +}; + + +/*! @brief Information on hardware for the first display + + @details This structure returns the display type of the first display on the device + (internal display or HDMI etc) and whether it is currently connected, + +*/ +struct HWDisplayInterfaceInfo { + DisplayType type; + bool is_connected; +}; + +/*! @brief Display core interface. + + @details This class defines display core interfaces. It contains methods which client shall use + to create/destroy different display devices. This interface is created during display core + CreateCore() and remains valid until DestroyCore(). + + @sa CoreInterface::CreateCore + @sa CoreInterface::DestroyCore +*/ +class CoreInterface { + public: + /*! @brief Method to create and get handle to display core interface. + + @details This method is the entry point into the display core. Client can create and operate on + different display devices only through a valid interface handle obtained using this method. An + object of display core is created and handle to this object is returned via output parameter. + This interface shall be called only once. + + @param[in] debug_handler \link DebugHandler \endlink + @param[in] buffer_allocator \link BufferAllocator \endlink + @param[in] buffer_sync_handler \link BufferSyncHandler \endlink + @param[out] interface \link CoreInterface \endlink + @param[in] version \link SDM_VERSION_TAG \endlink. Client must not override this argument. + + @return \link DisplayError \endlink + + @sa DestroyCore + */ + static DisplayError CreateCore(DebugHandler *debug_handler, BufferAllocator *buffer_allocator, + BufferSyncHandler *buffer_sync_handler, CoreInterface **interface, + uint32_t version = SDM_VERSION_TAG); + + /*! @brief Method to create and get handle to display core interface. + + @details This method is the entry point into the display core. Client can create and operate on + different display devices only through a valid interface handle obtained using this method. An + object of display core is created and handle to this object is returned via output parameter. + This interface shall be called only once. + + @param[in] debug_handler \link DebugHandler \endlink + @param[in] buffer_allocator \link BufferAllocator \endlink + @param[in] buffer_sync_handler \link BufferSyncHandler \endlink + @param[in] socket_handler \link SocketHandler \endlink + @param[out] interface \link CoreInterface \endlink + @param[in] version \link SDM_VERSION_TAG \endlink. Client must not override this argument. + + @return \link DisplayError \endlink + + @sa DestroyCore + */ + static DisplayError CreateCore(DebugHandler *debug_handler, BufferAllocator *buffer_allocator, + BufferSyncHandler *buffer_sync_handler, + SocketHandler *socket_handler, CoreInterface **interface, + uint32_t version = SDM_VERSION_TAG); + + /*! @brief Method to release handle to display core interface. + + @details The object of corresponding display core is destroyed when this method is invoked. + Client must explicitly destroy all created display device objects associated with this handle + before invoking this method. + + @param[in] interface \link CoreInterface \endlink + + @return \link DisplayError \endlink + + @sa CreateCore + */ + static DisplayError DestroyCore(); + + /*! @brief Method to create a display device for a given type. + + @details Client shall use this method to create each of the connected display type. A handle to + interface associated with this object is returned via output parameter which can be used to + interact further with the display device. + + @param[in] type \link DisplayType \endlink + @param[in] event_handler \link DisplayEventHandler \endlink + @param[out] interface \link DisplayInterface \endlink + + @return \link DisplayError \endlink + + @sa DestroyDisplay + */ + virtual DisplayError CreateDisplay(DisplayType type, DisplayEventHandler *event_handler, + DisplayInterface **interface) = 0; + + /*! @brief Method to destroy a display device. + + @details Client shall use this method to destroy each of the created display device objects. + + @param[in] interface \link DisplayInterface \endlink + + @return \link DisplayError \endlink + + @sa CreateDisplay + */ + virtual DisplayError DestroyDisplay(DisplayInterface *interface) = 0; + + /*! @brief Method to update the bandwidth limit as per given mode. + + @param[in] mode indicate the mode or use case + + @return \link DisplayError \endlink + + */ + virtual DisplayError SetMaxBandwidthMode(HWBwModes mode) = 0; + + /*! @brief Method to get characteristics of the first display. + + @details Client shall use this method to determine if the first display is HDMI, and whether + it is currently connected. + + @param[in] hw_disp_info structure that this method will fill up with info. + + @return \link DisplayError \endlink + + */ + virtual DisplayError GetFirstDisplayInterfaceType(HWDisplayInterfaceInfo *hw_disp_info) = 0; + + /*! @brief Method to check color transform supported or not. + + @details Client shall use this method to determine if target supports color transform or not + + @return bool + + */ + virtual bool IsColorTransformSupported() = 0; + + + protected: + virtual ~CoreInterface() { } +}; + +} // namespace sdm + +#endif // __CORE_INTERFACE_H__ + diff --git a/msm8909/sdm/include/core/debug_interface.h b/msm8909/sdm/include/core/debug_interface.h new file mode 100644 index 00000000..08f65eae --- /dev/null +++ b/msm8909/sdm/include/core/debug_interface.h @@ -0,0 +1,165 @@ +/* +* 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. +*/ + +/*! @file debug_interface.h + @brief This file provides the debug interface for display manager. +*/ +#ifndef __DEBUG_INTERFACE_H__ +#define __DEBUG_INTERFACE_H__ + +namespace sdm { + +/*! @brief This enum represents different modules/logical unit tags that a log message may + be associated with. Client may use this to filter messages for dynamic logging. + + @sa DebugHandler +*/ +enum DebugTag { + kTagNone, //!< Debug log is not tagged. This type of logs should always be printed. + kTagResources, //!< Debug log is tagged for resource management. + kTagStrategy, //!< Debug log is tagged for strategy decisions. + kTagCompManager, //!< Debug log is tagged for composition manager. + kTagDriverConfig, //!< Debug log is tagged for driver config. + kTagRotator, //!< Debug log is tagged for rotator. + kTagScalar, //!< Debug log is tagged for Scalar Helper. + kTagQDCM, //!< Debug log is tagged for display QDCM color managing. + kTagDisplay, //!< Debug log is tagged for display core logs. + kTagClient, //!< Debug log is tagged for SDM client. +}; + +/*! @brief Display debug handler class. + + @details This class defines display debug handler. The handle contains methods which client + should implement to get different levels of logging/tracing from display manager. Display manager + will call into these methods at appropriate times to send logging/tracing information. + + @sa CoreInterface::CreateCore +*/ +class DebugHandler { + public: + /*! @brief Method to handle error messages. + + @param[in] tag \link DebugTag \endlink + @param[in] format \link message format with variable argument list \endlink + */ + virtual void Error(DebugTag tag, const char *format, ...) = 0; + + /*! @brief Method to handle warning messages. + + @param[in] tag \link DebugTag \endlink + @param[in] format \link message format with variable argument list \endlink + */ + virtual void Warning(DebugTag tag, const char *format, ...) = 0; + + /*! @brief Method to handle informative messages. + + @param[in] tag \link DebugTag \endlink + @param[in] format \link message format with variable argument list \endlink + */ + virtual void Info(DebugTag tag, const char *format, ...) = 0; + + /*! @brief Method to handle debug messages. + + @param[in] tag \link DebugTag \endlink + @param[in] format \link message format with variable argument list \endlink + */ + virtual void Debug(DebugTag tag, const char *format, ...) = 0; + + /*! @brief Method to handle verbose messages. + + @param[in] tag \link DebugTag \endlink + @param[in] format \link message format with variable argument list \endlink + */ + virtual void Verbose(DebugTag tag, const char *format, ...) = 0; + + /*! @brief Method to begin trace for a module/logical unit. + + @param[in] class_name \link name of the class that the function belongs to \endlink + @param[in] function_name \link name of the function to be traced \endlink + @param[in] custom_string \link custom string for multiple traces within a function \endlink + */ + virtual void BeginTrace(const char *class_name, const char *function_name, + const char *custom_string) = 0; + + /*! @brief Method to end trace for a module/logical unit. + */ + virtual void EndTrace() = 0; + + /*! @brief Method to get property value corresponding to give string. + + @param[in] property_name name of the property + @param[out] integer converted value corresponding to the property name + + @return \link DisplayError \endlink + */ + virtual DisplayError GetProperty(const char *property_name, int *value) = 0; + + /*! @brief Method to get property value corresponding to give string. + + @param[in] property_name name of the property + @param[out] string value corresponding to the property name + + @return \link DisplayError \endlink + */ + virtual DisplayError GetProperty(const char *property_name, char *value) = 0; + + /*! @brief Method to set a property to a given string value. + + @param[in] property_name name of the property + @param[in] value new value of the property name + + @return \link DisplayError \endlink + */ + virtual DisplayError SetProperty(const char *property_name, const char *value) = 0; + + protected: + virtual ~DebugHandler() { } +}; + +/*! @brief Scope tracer template class. + + @details This class template implements the funtionality to capture the trace for function/ + module. It starts the trace upon object creation and ends the trace upon object destruction. +*/ +template <class T> +class ScopeTracer { + public: + ScopeTracer(const char *class_name, const char *function_name) { + T::Get()->BeginTrace(class_name, function_name, ""); + } + + ~ScopeTracer() { T::Get()->EndTrace(); } +}; + +} // namespace sdm + +#endif // __DEBUG_INTERFACE_H__ + + + diff --git a/msm8909/sdm/include/core/display_interface.h b/msm8909/sdm/include/core/display_interface.h new file mode 100644 index 00000000..3101eec6 --- /dev/null +++ b/msm8909/sdm/include/core/display_interface.h @@ -0,0 +1,694 @@ +/* +* Copyright (c) 2014 - 2017, 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. +*/ + +/*! @file display_interface.h + @brief Interface file for display device which represents a physical panel or an output buffer + where contents can be rendered. + + @details Display device is used to send layer buffers for composition and get them rendered onto + the target device. Each display device represents a unique display target which may be either a + physical panel or an output buffer.. +*/ +#ifndef __DISPLAY_INTERFACE_H__ +#define __DISPLAY_INTERFACE_H__ + +#include <stdint.h> +#include <string> +#include <vector> +#include <utility> + +#include "layer_stack.h" +#include "sdm_types.h" + +namespace sdm { + +typedef std::vector<std::pair<std::string, std::string>> AttrVal; + +/*! @brief This enum represents display device types where contents can be rendered. + + @sa CoreInterface::CreateDisplay + @sa CoreInterface::IsDisplaySupported +*/ +enum DisplayType { + kPrimary, //!< Main physical display which is attached to the handheld device. + kHDMI, //!< HDMI physical display which is generally detachable. + kVirtual, //!< Contents would be rendered into the output buffer provided by the client + //!< e.g. wireless display. + kDisplayMax, +}; + +/*! @brief This enum represents states of a display device. + + @sa DisplayInterface::GetDisplayState + @sa DisplayInterface::SetDisplayState +*/ +enum DisplayState { + kStateOff, //!< Display is OFF. Contents are not rendered in this state. Client will not + //!< receive VSync events in this state. This is default state as well. + + kStateOn, //!< Display is ON. Contents are rendered in this state. + + kStateDoze, //!< Display is ON and it is configured in a low power state. + + kStateDozeSuspend, + //!< Display is ON in a low power state and continue showing its current + //!< contents indefinitely until the mode changes. + + kStateStandby, //!< Display is OFF. Client will continue to receive VSync events in this state + //!< if VSync is enabled. Contents are not rendered in this state. +}; + +/*! @brief This enum represents flags to override detail enhancer parameters. + + @sa DisplayInterface::SetDetailEnhancerData +*/ +enum DetailEnhancerOverrideFlags { + kOverrideDEEnable = 0x1, // Specifies to enable detail enhancer + kOverrideDESharpen1 = 0x2, // Specifies user defined Sharpening/smooth for noise + kOverrideDESharpen2 = 0x4, // Specifies user defined Sharpening/smooth for signal + kOverrideDEClip = 0x8, // Specifies user defined DE clip shift + kOverrideDELimit = 0x10, // Specifies user defined DE limit value + kOverrideDEThrQuiet = 0x20, // Specifies user defined DE quiet threshold + kOverrideDEThrDieout = 0x40, // Specifies user defined DE dieout threshold + kOverrideDEThrLow = 0x80, // Specifies user defined DE low threshold + kOverrideDEThrHigh = 0x100, // Specifies user defined DE high threshold + kOverrideDEFilterConfig = 0x200, // Specifies user defined scaling filter config + kOverrideDEMax = 0xFFFFFFFF, +}; + +/*! @brief This enum represents Y/RGB scaling filter configuration. + + @sa DisplayInterface::SetDetailEnhancerData +*/ +enum ScalingFilterConfig { + kFilterEdgeDirected, + kFilterCircular, + kFilterSeparable, + kFilterBilinear, + kFilterMax, +}; + +/*! @brief This enum represents the quality level of the content. + + @sa DisplayInterface::SetDetailEnhancerData +*/ +enum ContentQuality { + kContentQualityUnknown, // Default: high artifact and noise + kContentQualityLow, // Low quality content, high artifact and noise, + kContentQualityMedium, // Medium quality, medium artifact and noise, + kContentQualityHigh, // High quality content, low artifact and noise + kContentQualityMax, +}; + +/*! @brief This enum represents the display port. + + @sa DisplayInterface::GetDisplayPort +*/ +enum DisplayPort { + kPortDefault, + kPortDSI, // Display is connected to DSI port. + kPortDTV, // Display is connected to DTV port + kPortWriteBack, // Display is connected to writeback port + kPortLVDS, // Display is connected to LVDS port + kPortEDP, // Display is connected to EDP port + kPortDP, // Display is connected to DP port. +}; + +/*! @brief This enum represents the events received by Display HAL. */ +enum DisplayEvent { + kIdleTimeout, // Event triggered by Idle Timer. + kThermalEvent, // Event triggered by Thermal. +}; + +/*! @brief This structure defines configuration for fixed properties of a display device. + + @sa DisplayInterface::GetConfig + @sa DisplayInterface::SetConfig +*/ +struct DisplayConfigFixedInfo { + bool underscan = false; //!< If display support CE underscan. + bool secure = false; //!< If this display is capable of handling secure content. + bool is_cmdmode = false; //!< If panel is command mode panel. + bool hdr_supported = false; //!< if HDR is enabled + uint32_t max_luminance = 0; //!< From Panel's peak luminance + uint32_t average_luminance = 0; //!< From Panel's average luminance + uint32_t min_luminance = 0; //!< From Panel's blackness level +}; + +/*! @brief This structure defines configuration for variable properties of a display device. + + @sa DisplayInterface::GetConfig + @sa DisplayInterface::SetConfig +*/ +struct DisplayConfigVariableInfo { + uint32_t x_pixels = 0; //!< Total number of pixels in X-direction on the display panel. + uint32_t y_pixels = 0; //!< Total number of pixels in Y-direction on the display panel. + float x_dpi = 0.0f; //!< Dots per inch in X-direction. + float y_dpi = 0.0f; //!< Dots per inch in Y-direction. + uint32_t fps = 0; //!< Frame rate per second. + uint32_t vsync_period_ns = 0; //!< VSync period in nanoseconds. + bool is_yuv = false; //!< If the display output is in YUV format. +}; + +/*! @brief Event data associated with VSync event. + + @sa DisplayEventHandler::VSync +*/ +struct DisplayEventVSync { + int64_t timestamp = 0; //!< System monotonic clock timestamp in nanoseconds. +}; + +/*! @brief The structure defines the user input for detail enhancer module. + + @sa DisplayInterface::SetDetailEnhancerData +*/ +struct DisplayDetailEnhancerData { + uint32_t override_flags = 0; // flags to specify which data to be set. + uint16_t enable = 0; // Detail enchancer enable + int16_t sharpen_level1 = 0; // Sharpening/smooth strenght for noise + int16_t sharpen_level2 = 0; // Sharpening/smooth strenght for signal + uint16_t clip = 0; // DE clip shift + uint16_t limit = 0; // DE limit value + uint16_t thr_quiet = 0; // DE quiet threshold + uint16_t thr_dieout = 0; // DE dieout threshold + uint16_t thr_low = 0; // DE low threshold + uint16_t thr_high = 0; // DE high threshold + int32_t sharp_factor = 50; // sharp_factor specifies sharpness/smoothness level, + // range -100..100 positive for sharpness and negative for + // smoothness + ContentQuality quality_level = kContentQualityUnknown; + // Specifies context quality level + ScalingFilterConfig filter_config = kFilterEdgeDirected; + // Y/RGB filter configuration +}; + +/*! @brief Display device event handler implemented by the client. + + @details This class declares prototype for display device event handler methods which must be + implemented by the client. Display device will use these methods to notify events to the client. + Client must post heavy-weight event handling to a separate thread and unblock display manager + thread instantly. + + @sa CoreInterface::CreateDisplay +*/ +class DisplayEventHandler { + public: + /*! @brief Event handler for VSync event. + + @details This event is dispatched on every vertical synchronization. The event is disabled by + default. + + @param[in] vsync \link DisplayEventVSync \endlink + + @return \link DisplayError \endlink + + @sa DisplayInterface::GetDisplayState + @sa DisplayInterface::SetDisplayState + */ + virtual DisplayError VSync(const DisplayEventVSync &vsync) = 0; + + /*! @brief Event handler for Refresh event. + + @details This event is dispatched to trigger a screen refresh. Client must call Prepare() and + Commit() in response to it from a separate thread. There is no data associated with this + event. + + @return \link DisplayError \endlink + + @sa DisplayInterface::Prepare + @sa DisplayInterface::Commit + */ + virtual DisplayError Refresh() = 0; + + /*! @brief Event handler for CEC messages. + + @details This event is dispatched to send CEC messages to the CEC HAL. + + @param[in] message message to be sent + + @return \link DisplayError \endlink + */ + virtual DisplayError CECMessage(char *message) = 0; + + /*! @brief Event handler for events received by Display HAL. */ + virtual DisplayError HandleEvent(DisplayEvent event) = 0; + + protected: + virtual ~DisplayEventHandler() { } +}; + +struct PPDisplayAPIPayload; +struct PPPendingParams; + +/*! @brief Display device interface. + + @details This class defines display device interface. It contains methods which client shall use + to configure or submit layers for composition on the display device. This interface is created + during display device creation and remains valid until destroyed. + + @sa CoreInterface::CreateDisplay + @sa CoreInterface::DestroyDisplay +*/ +class DisplayInterface { + public: + /*! @brief Method to determine hardware capability to compose layers associated with given frame. + + @details Client shall send all layers associated with a frame targeted for current display + using this method and check the layers which can be handled completely in display manager. + + Client shall mark composition type for one of the layer as kCompositionGPUTarget; the GPU + composed output would be rendered at the specified layer if some of the layers are not handled + by SDM. + + Display manager will set each layer as kCompositionGPU or kCompositionSDE upon return. Client + shall render all the layers marked as kCompositionGPU using GPU. + + This method can be called multiple times but only last call prevails. This method must be + followed by Commit(). + + @param[inout] layer_stack \link LayerStack \endlink + + @return \link DisplayError \endlink + + @sa Commit + */ + virtual DisplayError Prepare(LayerStack *layer_stack) = 0; + + /*! @brief Method to commit layers of a frame submitted in a former call to Prepare(). + + @details Client shall call this method to submit layers for final composition. The composed + output would be displayed on the panel or written in output buffer. + + Client must ensure that layer stack is same as previous call to Prepare. + + This method shall be called only once for each frame. + + In the event of an error as well, this call will cause any fences returned in the previous call + to Commit() to eventually become signaled, so the client's wait on fences can be released to + prevent deadlocks. + + @param[in] layer_stack \link LayerStack \endlink + + @return \link DisplayError \endlink + + @sa Prepare + */ + virtual DisplayError Commit(LayerStack *layer_stack) = 0; + + /*! @brief Method to flush any pending buffers/fences submitted previously via Commit() call. + + @details Client shall call this method to request the Display manager to release all buffers and + respective fences currently in use. This operation may result in a blank display on the panel + until a new frame is submitted for composition. + + @return \link DisplayError \endlink + + @sa Prepare + @sa Commit + */ + virtual DisplayError Flush() = 0; + + /*! @brief Method to get current state of the display device. + + @param[out] state \link DisplayState \endlink + + @return \link DisplayError \endlink + + @sa SetDisplayState + */ + virtual DisplayError GetDisplayState(DisplayState *state) = 0; + + /*! @brief Method to get number of configurations(variable properties) supported on the display + device. + + @param[out] count Number of modes supported; mode index starts with 0. + + @return \link DisplayError \endlink + */ + virtual DisplayError GetNumVariableInfoConfigs(uint32_t *count) = 0; + + /*! @brief Method to get configuration for fixed properties of the display device. + + @param[out] fixed_info \link DisplayConfigFixedInfo \endlink + + @return \link DisplayError \endlink + */ + virtual DisplayError GetConfig(DisplayConfigFixedInfo *fixed_info) = 0; + + /*! @brief Method to get configuration for variable properties of the display device. + + @param[in] index index of the mode + @param[out] variable_info \link DisplayConfigVariableInfo \endlink + + @return \link DisplayError \endlink + */ + virtual DisplayError GetConfig(uint32_t index, DisplayConfigVariableInfo *variable_info) = 0; + + /*! @brief Method to get index of active configuration of the display device. + + @param[out] index index of the mode corresponding to variable properties. + + @return \link DisplayError \endlink + */ + virtual DisplayError GetActiveConfig(uint32_t *index) = 0; + + /*! @brief Method to get VSync event state. Default event state is disabled. + + @param[out] enabled vsync state + + @return \link DisplayError \endlink + */ + virtual DisplayError GetVSyncState(bool *enabled) = 0; + + /*! @brief Method to set current state of the display device. + + @param[in] state \link DisplayState \endlink + + @return \link DisplayError \endlink + + @sa SetDisplayState + */ + virtual DisplayError SetDisplayState(DisplayState state) = 0; + + /*! @brief Method to set active configuration for variable properties of the display device. + + @param[in] variable_info \link DisplayConfigVariableInfo \endlink + + @return \link DisplayError \endlink + */ + virtual DisplayError SetActiveConfig(DisplayConfigVariableInfo *variable_info) = 0; + + /*! @brief Method to set active configuration for variable properties of the display device. + + @param[in] index index of the mode corresponding to variable properties. + + @return \link DisplayError \endlink + */ + virtual DisplayError SetActiveConfig(uint32_t index) = 0; + + /*! @brief Method to set VSync event state. Default event state is disabled. + + @param[out] enabled vsync state + + @return \link DisplayError \endlink + */ + virtual DisplayError SetVSyncState(bool enable) = 0; + + /*! @brief Method to set idle timeout value. Idle fallback is disabled with timeout value 0. + + @param[in] active_ms value in milliseconds. + + @return \link void \endlink + */ + virtual void SetIdleTimeoutMs(uint32_t active_ms) = 0; + + /*! @brief Method to set maximum number of mixer stages for each display. + + @param[in] max_mixer_stages maximum number of mixer stages. + + @return \link DisplayError \endlink + */ + virtual DisplayError SetMaxMixerStages(uint32_t max_mixer_stages) = 0; + + /*! @brief Method to control partial update feature for each display. + + @param[in] enable partial update feature control flag + @param[out] pending whether the operation is completed or pending for completion + + @return \link DisplayError \endlink + */ + virtual DisplayError ControlPartialUpdate(bool enable, uint32_t *pending) = 0; + + /*! @brief Method to disable partial update for at least 1 frame. + @return \link DisplayError \endlink + */ + virtual DisplayError DisablePartialUpdateOneFrame() = 0; + + /*! @brief Method to set the mode of the primary display. + + @param[in] mode the new display mode. + + @return \link DisplayError \endlink + */ + virtual DisplayError SetDisplayMode(uint32_t mode) = 0; + + /*! @brief Method to get the min and max refresh rate of a display. + + @param[out] min and max refresh rate. + + @return \link DisplayError \endlink + */ + virtual DisplayError GetRefreshRateRange(uint32_t *min_refresh_rate, + uint32_t *max_refresh_rate) = 0; + + /*! @brief Method to set the refresh rate of a display. + + @param[in] new refresh rate of the display. + + @return \link DisplayError \endlink + */ + virtual DisplayError SetRefreshRate(uint32_t refresh_rate) = 0; + + /*! @brief Method to query whether scanning is support for the HDMI display. + + @return \link DisplayError \endlink + */ + virtual bool IsUnderscanSupported() = 0; + + /*! @brief Method to set brightness of the primary display. + + @param[in] level the new backlight level. + + @return \link DisplayError \endlink + */ + virtual DisplayError SetPanelBrightness(int level) = 0; + + /*! @brief Method to cache brightness of the primary display. + + @param[in] level the new backlight level. + + @return \link DisplayError \endlink + */ + virtual DisplayError CachePanelBrightness(int level) = 0; + + /*! @brief Method to notify display about change in min HDCP encryption level. + + @param[in] min_enc_level minimum encryption level value. + + @return \link DisplayError \endlink + */ + virtual DisplayError OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level) = 0; + + /*! @brief Method to route display API requests to color service. + + @param[in] in_payload \link PPDisplayAPIPayload \endlink + @param[out] out_payload \link PPDisplayPayload \endlink + @param[out] pending_action \link PPPendingParams \endlink + + @return \link DisplayError \endlink + */ + virtual DisplayError ColorSVCRequestRoute(const PPDisplayAPIPayload &in_payload, + PPDisplayAPIPayload *out_payload, + PPPendingParams *pending_action) = 0; + + /*! @brief Method to request the number of color modes supported. + + @param[out] mode_count Number of modes + + @return \link DisplayError \endlink + */ + virtual DisplayError GetColorModeCount(uint32_t *mode_count) = 0; + + /*! @brief Method to request the information of supported color modes. + + @param[inout] mode_count Number of updated modes + @param[out] vector of mode strings + + @return \link DisplayError \endlink + */ + virtual DisplayError GetColorModes(uint32_t *mode_count, + std::vector<std::string> *color_modes) = 0; + + /*! @brief Method to request the attributes of color mode. + + @param[in] mode name + @param[out] vector of mode attributes + + @return \link DisplayError \endlink + */ + virtual DisplayError GetColorModeAttr(const std::string &color_mode, + AttrVal *attr_map) = 0; + + /*! @brief Method to set the color mode + + @param[in] mode_name Mode name which needs to be set + + @return \link DisplayError \endlink + */ + virtual DisplayError SetColorMode(const std::string &color_mode) = 0; + + /*! @brief Method to set the color transform + + @param[in] length Mode name which needs to be set + @param[in] color_transform 4x4 Matrix for color transform + + @return \link DisplayError \endlink + */ + virtual DisplayError SetColorTransform(const uint32_t length, const double *color_transform) = 0; + + /*! @brief Method to get the default color mode. + + @param[out] default mode name + + @return \link DisplayError \endlink + */ + virtual DisplayError GetDefaultColorMode(std::string *color_mode) = 0; + + /*! @brief Method to request applying default display mode. + + @return \link DisplayError \endlink + */ + virtual DisplayError ApplyDefaultDisplayMode() = 0; + + /*! @brief Method to set the position of the hw cursor. + + @param[in] x \link x position \endlink + @param[in] y \link y position \endlink + + @return \link DisplayError \endlink + */ + virtual DisplayError SetCursorPosition(int x, int y) = 0; + + /*! @brief Method to get the brightness level of the display + + @param[out] level brightness level + + @return \link DisplayError \endlink + */ + virtual DisplayError GetPanelBrightness(int *level) = 0; + + /*! @brief Method to set layer mixer resolution. + + @param[in] width layer mixer width + @param[in] height layer mixer height + + @return \link DisplayError \endlink + */ + virtual DisplayError SetMixerResolution(uint32_t width, uint32_t height) = 0; + + /*! @brief Method to get layer mixer resolution. + + @param[out] width layer mixer width + @param[out] height layer mixer height + + @return \link DisplayError \endlink + */ + virtual DisplayError GetMixerResolution(uint32_t *width, uint32_t *height) = 0; + + /*! @brief Method to set frame buffer configuration. + + @param[in] variable_info \link DisplayConfigVariableInfo \endlink + + @return \link DisplayError \endlink + */ + virtual DisplayError SetFrameBufferConfig(const DisplayConfigVariableInfo &variable_info) = 0; + + /*! @brief Method to get frame buffer configuration. + + @param[out] variable_info \link DisplayConfigVariableInfo \endlink + + @return \link DisplayError \endlink + */ + virtual DisplayError GetFrameBufferConfig(DisplayConfigVariableInfo *variable_info) = 0; + + /*! @brief Method to set detail enhancement data. + + @param[in] de_data \link DisplayDetailEnhancerData \endlink + + @return \link DisplayError \endlink + */ + virtual DisplayError SetDetailEnhancerData(const DisplayDetailEnhancerData &de_data) = 0; + + /*! @brief Method to get display port information. + + @param[out] port \link DisplayPort \endlink + + @return \link DisplayError \endlink + */ + virtual DisplayError GetDisplayPort(DisplayPort *port) = 0; + + /*! @brief Method to query whether it is Primrary device. + + @return true if this interface is primary. + */ + virtual bool IsPrimaryDisplay() = 0; + + /*! @brief Method to toggle composition types handling by SDM. + + @details Client shall call this method to request SDM to enable/disable a specific type of + layer composition. If client disables a composition type, SDM will not handle any of the layer + composition using the disabled method in a draw cycle. On lack of resources to handle all + layers using other enabled composition methods, Prepare() will return an error. + + Request to toggle composition type is applied from subsequent draw cycles. + + Default state of all defined composition types is enabled. + + @param[in] composition_type \link LayerComposition \endlink + @param[in] enable \link enable composition type \endlink + + @return \link DisplayError \endlink + + @sa Prepare + */ + virtual DisplayError SetCompositionState(LayerComposition composition_type, bool enable) = 0; + + /*! @brief Method to check whether a client target with the given properties + can be supported/handled by hardware. + + @param[in] width client target width + @param[in] height client target height + @param[in] format client target format + @param[in] colorMetaData client target colorMetaData + + @return \link DisplayError \endlink + */ + virtual DisplayError GetClientTargetSupport(uint32_t width, uint32_t height, + LayerBufferFormat format, + const ColorMetaData &color_metadata) = 0; + + /* + * Returns a string consisting of a dump of SDM's display and layer related state + * as programmed to driver + */ + virtual std::string Dump() = 0; + + protected: + virtual ~DisplayInterface() { } +}; + +} // namespace sdm + +#endif // __DISPLAY_INTERFACE_H__ + diff --git a/msm8909/sdm/include/core/layer_buffer.h b/msm8909/sdm/include/core/layer_buffer.h new file mode 100644 index 00000000..c86e0202 --- /dev/null +++ b/msm8909/sdm/include/core/layer_buffer.h @@ -0,0 +1,283 @@ +/* +* Copyright (c) 2014, 2016-2017, 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. +*/ + +/*! @file layer_buffer.h + @brief File for layer buffer structure. + +*/ +#ifndef __LAYER_BUFFER_H__ +#define __LAYER_BUFFER_H__ + +#include <stdint.h> +#include <color_metadata.h> + +#include "sdm_types.h" + +namespace sdm { + +/*! @brief This enum represents display layer inverse gamma correction (IGC) types. + + @sa Layer +*/ +enum LayerIGC { + kIGCNotSpecified, //!< IGC is not specified. + kIGCsRGB, //!< sRGB IGC type. +}; + +/*! @brief This enum represents different buffer formats supported by display manager. + + @sa LayerBuffer +*/ +enum LayerBufferFormat { + /* All RGB formats, Any new format will be added towards end of this group to maintain backward + compatibility. + */ + kFormatARGB8888, //!< 8-bits Alpha, Red, Green, Blue interleaved in ARGB order. + kFormatRGBA8888, //!< 8-bits Red, Green, Blue, Alpha interleaved in RGBA order. + kFormatBGRA8888, //!< 8-bits Blue, Green, Red, Alpha interleaved in BGRA order. + kFormatXRGB8888, //!< 8-bits Padding, Red, Green, Blue interleaved in XRGB order. No Alpha. + kFormatRGBX8888, //!< 8-bits Red, Green, Blue, Padding interleaved in RGBX order. No Alpha. + kFormatBGRX8888, //!< 8-bits Blue, Green, Red, Padding interleaved in BGRX order. No Alpha. + kFormatRGBA5551, //!< 5-bits Red, Green, Blue, and 1 bit Alpha interleaved in RGBA order. + kFormatRGBA4444, //!< 4-bits Red, Green, Blue, Alpha interleaved in RGBA order. + kFormatRGB888, //!< 8-bits Red, Green, Blue interleaved in RGB order. No Alpha. + kFormatBGR888, //!< 8-bits Blue, Green, Red interleaved in BGR order. No Alpha. + kFormatRGB565, //!< 5-bit Red, 6-bit Green, 5-bit Blue interleaved in RGB order. No Alpha. + kFormatBGR565, //!< 5-bit Blue, 6-bit Green, 5-bit Red interleaved in BGR order. No Alpha. + kFormatRGBA8888Ubwc, //!< UBWC aligned RGBA8888 format + kFormatRGBX8888Ubwc, //!< UBWC aligned RGBX8888 format + kFormatBGR565Ubwc, //!< UBWC aligned BGR565 format + kFormatRGBA1010102, //!< 10-bits Red, Green, Blue, Alpha interleaved in RGBA order. + kFormatARGB2101010, //!< 10-bits Alpha, Red, Green, Blue interleaved in ARGB order. + kFormatRGBX1010102, //!< 10-bits Red, Green, Blue, Padding interleaved in RGBX order. No Alpha. + kFormatXRGB2101010, //!< 10-bits Padding, Red, Green, Blue interleaved in XRGB order. No Alpha. + kFormatBGRA1010102, //!< 10-bits Blue, Green, Red, Alpha interleaved in BGRA order. + kFormatABGR2101010, //!< 10-bits Alpha, Blue, Green, Red interleaved in ABGR order. + kFormatBGRX1010102, //!< 10-bits Blue, Green, Red, Padding interleaved in BGRX order. No Alpha. + kFormatXBGR2101010, //!< 10-bits Padding, Blue, Green, Red interleaved in XBGR order. No Alpha. + kFormatRGBA1010102Ubwc, //!< UBWC aligned RGBA1010102 format + kFormatRGBX1010102Ubwc, //!< UBWC aligned RGBX1010102 format + kFormatRGB101010, // 10-bits Red, Green, Blue, interleaved in RGB order. No Alpha. + + /* All YUV-Planar formats, Any new format will be added towards end of this group to maintain + backward compatibility. + */ + kFormatYCbCr420Planar = 0x100, //!< Y-plane: y(0), y(1), y(2) ... y(n) + //!< 2x2 subsampled U-plane: u(0), u(2) ... u(n-1) + //!< 2x2 subsampled V-plane: v(0), v(2) ... v(n-1) + + kFormatYCrCb420Planar, //!< Y-plane: y(0), y(1), y(2) ... y(n) + //!< 2x2 subsampled V-plane: v(0), v(2) ... v(n-1) + //!< 2x2 subsampled U-plane: u(0), u(2) ... u(n-1) + + kFormatYCrCb420PlanarStride16, //!< kFormatYCrCb420Planar with stride aligned to 16 bytes + + /* All YUV-Semiplanar formats, Any new format will be added towards end of this group to + maintain backward compatibility. + */ + kFormatYCbCr420SemiPlanar = 0x200, //!< Y-plane: y(0), y(1), y(2) ... y(n) + //!< 2x2 subsampled interleaved UV-plane: + //!< u(0), v(0), u(2), v(2) ... u(n-1), v(n-1) + //!< aka NV12. + + kFormatYCrCb420SemiPlanar, //!< Y-plane: y(0), y(1), y(2) ... y(n) + //!< 2x2 subsampled interleaved VU-plane: + //!< v(0), u(0), v(2), u(2) ... v(n-1), u(n-1) + //!< aka NV21. + + kFormatYCbCr420SemiPlanarVenus, //!< Y-plane: y(0), y(1), y(2) ... y(n) + //!< 2x2 subsampled interleaved UV-plane: + //!< u(0), v(0), u(2), v(2) ... u(n-1), v(n-1) + + kFormatYCbCr422H1V2SemiPlanar, //!< Y-plane: y(0), y(1), y(2) ... y(n) + //!< vertically subsampled interleaved UV-plane: + //!< u(0), v(1), u(2), v(3) ... u(n-1), v(n) + + kFormatYCrCb422H1V2SemiPlanar, //!< Y-plane: y(0), y(1), y(2) ... y(n) + //!< vertically subsampled interleaved VU-plane: + //!< v(0), u(1), v(2), u(3) ... v(n-1), u(n) + + kFormatYCbCr422H2V1SemiPlanar, //!< Y-plane: y(0), y(1), y(2) ... y(n) + //!< horizontally subsampled interleaved UV-plane: + //!< u(0), v(1), u(2), v(3) ... u(n-1), v(n) + + kFormatYCrCb422H2V1SemiPlanar, //!< Y-plane: y(0), y(1), y(2) ... y(n) + //!< horizontally subsampled interleaved VU-plane: + //!< v(0), u(1), v(2), u(3) ... v(n-1), u(n) + + kFormatYCbCr420SPVenusUbwc, //!< UBWC aligned YCbCr420SemiPlanarVenus format + + kFormatYCrCb420SemiPlanarVenus, //!< Y-plane: y(0), y(1), y(2) ... y(n) + //!< 2x2 subsampled interleaved UV-plane: + //!< v(0), u(0), v(2), u(2) ... v(n-1), u(n-1) + + kFormatYCbCr420P010, //!< 16 bit Y-plane with 5 MSB bits set to 0: + //!< y(0), y(1), y(2) ... y(n) + //!< 2x2 subsampled interleaved 10 bit UV-plane with + //!< 5 MSB bits set to 0: + //!< u(0), v(0), u(2), v(2) ... u(n-1), v(n-1) + //!< aka P010. + + kFormatYCbCr420TP10Ubwc, //!< UBWC aligned YCbCr420TP10 format. + + kFormatYCbCr420P010Ubwc, //!< UBWC aligned YCbCr420P010 format. + + /* All YUV-Packed formats, Any new format will be added towards end of this group to maintain + backward compatibility. + */ + kFormatYCbCr422H2V1Packed = 0x300, //!< Y-plane interleaved with horizontally subsampled U/V by + //!< factor of 2 + //!< y(0), u(0), y(1), v(0), y(2), u(2), y(3), v(2) + //!< y(n-1), u(n-1), y(n), v(n-1) + + kFormatCbYCrY422H2V1Packed, + kFormatInvalid = 0xFFFFFFFF, +}; + + +/*! @brief This enum represents different types of 3D formats supported. + + @sa LayerBufferS3DFormat +*/ +enum LayerBufferS3DFormat { + kS3dFormatNone, //!< Layer buffer content is not 3D content. + kS3dFormatLeftRight, //!< Left and Right view of a 3D content stitched left and right. + kS3dFormatRightLeft, //!< Right and Left view of a 3D content stitched left and right. + kS3dFormatTopBottom, //!< Left and RightView of a 3D content stitched top and bottom. + kS3dFormatFramePacking //!< Left and right view of 3D content coded in consecutive frames. +}; + +/*! @brief This structure defines a color sample plane belonging to a buffer format. RGB buffer + formats have 1 plane whereas YUV buffer formats may have upto 4 planes. + + @sa LayerBuffer +*/ +struct LayerBufferPlane { + int fd = -1; //!< File descriptor referring to the buffer associated with this plane. + uint32_t offset = 0; //!< Offset of the plane in bytes from beginning of the buffer. + uint32_t stride = 0; //!< Stride in bytes i.e. length of a scanline including padding. +}; + +/*! @brief This structure defines flags associated with a layer buffer. The 1-bit flag can be set + to ON(1) or OFF(0). + + @sa LayerBuffer +*/ +struct LayerBufferFlags { + union { + struct { + uint32_t secure : 1; //!< This flag shall be set by client to indicate that the + //!< buffer need to be handled securely. + + uint32_t video : 1; //!< This flag shall be set by client to indicate that the + //!< buffer is video/ui buffer. + + uint32_t macro_tile : 1; //!< This flag shall be set by client to indicate that the + //!< buffer format is macro tiled. + + uint32_t interlace : 1; //!< This flag shall be set by the client to indicate that + //!< the buffer has interlaced content. + + uint32_t secure_display : 1; //!< This flag shall be set by the client to indicate that the + //!< secure display session is in progress. Secure display + //!< session can not coexist with non-secure session. + + uint32_t secure_camera : 1; //!< This flag shall be set by the client to indicate that the + //!< buffer is associated with secure camera session. A secure + //!< camera layer can co-exist with non-secure layer(s). + + uint32_t hdr : 1; //!< This flag shall be set by the client to indicate that the + //!< the content is HDR. + }; + + uint32_t flags = 0; //!< For initialization purpose only. + //!< Client shall not refer to it directly. + }; +}; + +/*! @brief This structure defines a layer buffer handle which contains raw buffer and its associated + properties. + + @sa LayerBuffer + @sa LayerStack +*/ +struct LayerBuffer { + uint32_t width = 0; //!< Aligned width of the Layer that this buffer is for. + uint32_t height = 0; //!< Aligned height of the Layer that this buffer is for. + uint32_t unaligned_width = 0; + //!< Unaligned width of the Layer that this buffer is for. + uint32_t unaligned_height = 0; + //!< Unaligned height of the Layer that this buffer is for. + uint32_t size = 0; //!< Size of a single buffer (even if multiple clubbed together) + LayerBufferFormat format = kFormatRGBA8888; //!< Format of the buffer content. + ColorMetaData color_metadata = {}; //!< CSC + Range + Transfer + Matrix + HDR Info + LayerIGC igc = kIGCNotSpecified; //!< IGC that will be applied on this layer. + LayerBufferPlane planes[4] = {}; + //!< Array of planes that this buffer contains. RGB buffer formats + //!< have 1 plane whereas YUV buffer formats may have upto 4 planes + //!< Total number of planes for the buffer will be interpreted based + //!< on the buffer format specified. + + int acquire_fence_fd = -1; //!< File descriptor referring to a sync fence object which will be + //!< signaled when buffer can be read/write by display manager. + //!< This fence object is set by the client during Commit(). For + //!< input buffers client shall signal this fence when buffer + //!< content is available and can be read by display manager. For + //!< output buffers, client shall signal fence when buffer is ready + //!< to be written by display manager. + + //!< This field is used only during Commit() and shall be set to -1 + //!< by the client when buffer is already available for read/write. + + int release_fence_fd = -1; //!< File descriptor referring to a sync fence object which will be + //!< signaled when buffer has been read/written by display manager. + //!< This fence object is set by display manager during Commit(). + //!< For input buffers display manager will signal this fence when + //!< buffer has been consumed. For output buffers, display manager + //!< will signal this fence when buffer is produced. + + //!< This field is used only during Commit() and will be set to -1 + //!< by display manager when buffer is already available for + //!< read/write. + + LayerBufferFlags flags; //!< Flags associated with this buffer. + + LayerBufferS3DFormat s3d_format = kS3dFormatNone; + //!< Represents the format of the buffer content in 3D. This field + //!< could be modified by both client and SDM. + uint64_t buffer_id __attribute__((aligned(8))) = 0; + //!< Specifies the buffer id. +}; + +// This enum represents buffer layout types. +enum BufferLayout { + kLinear, //!< Linear data + kUBWC, //!< UBWC aligned data + kTPTiled //!< Tightly Packed data +}; + +} // namespace sdm + +#endif // __LAYER_BUFFER_H__ + diff --git a/msm8909/sdm/include/core/layer_stack.h b/msm8909/sdm/include/core/layer_stack.h new file mode 100644 index 00000000..f12e5c17 --- /dev/null +++ b/msm8909/sdm/include/core/layer_stack.h @@ -0,0 +1,392 @@ +/* +* Copyright (c) 2014 - 2017, 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. +*/ + +/*! @file layer_stack.h + @brief File for display layer stack structure which represents a drawing buffer. + + @details Display layer is a drawing buffer object which will be blended with other drawing buffers + under blending rules. +*/ +#ifndef __LAYER_STACK_H__ +#define __LAYER_STACK_H__ + +#include <stdint.h> +#include <utils/constants.h> + +#include <vector> + +#include "layer_buffer.h" +#include "sdm_types.h" + +namespace sdm { + +/*! @brief This enum represents display layer blending types. + + @sa Layer +*/ +enum LayerBlending { + kBlendingPremultiplied, //!< Pixel color is expressed using premultiplied alpha in RGBA tuples. + //!< If plane alpha is less than 0xFF, apply modulation as well. + //!< pixel.rgb = src.rgb + dest.rgb x (1 - src.a) + + kBlendingOpaque, //!< Pixel color is expressed using straight alpha in color tuples. It + //!< is constant blend operation. The layer would appear opaque if plane + //!< alpha is 0xFF. + + kBlendingCoverage, //!< Pixel color is expressed using straight alpha in color tuples. If + //!< plane alpha is less than 0xff, apply modulation as well. + //!< pixel.rgb = src.rgb x src.a + dest.rgb x (1 - src.a) +}; + +/*! @brief This enum represents display layer composition types. + + @sa Layer +*/ +enum LayerComposition { + /* ==== List of composition types set by SDM === */ + /* These composition types represent SDM composition decision for the layers which need to + be blended. Composition types are set during Prepare() by SDM. + Client can set default composition type to any of the below before calling into Prepare(), + however client's input value is ignored and does not play any role in composition decision. + */ + kCompositionGPU, //!< This layer will be drawn onto the target buffer by GPU. Display + //!< device will mark the layer for GPU composition if it can not + //!< handle composition for it. + //!< This composition type is used only if GPUTarget layer is provided + //!< in a composition cycle. + + kCompositionGPUS3D, //!< This layer will be drawn onto the target buffer in s3d mode by GPU. + //!< Display device will mark the layer for GPU composition if it can + //!< not handle composition for it. + //!< This composition type is used only if GPUTarget layer is provided + //!< in a composition cycle. + + kCompositionSDE, //!< This layer will be composed by SDE. It must not be composed by + //!< GPU or Blit. + + kCompositionHWCursor, //!< This layer will be composed by SDE using HW Cursor. It must not be + //!< composed by GPU or Blit. + + kCompositionHybrid, //!< This layer will be drawn by a blit engine and SDE together. + //!< Display device will split the layer, update the blit rectangle + //!< that need to be composed by a blit engine and update original + //!< source rectangle that will be composed by SDE. + //!< This composition type is used only if GPUTarget and BlitTarget + //!< layers are provided in a composition cycle. + + kCompositionBlit, //!< This layer will be composed using Blit Engine. + //!< This composition type is used only if BlitTarget layer is provided + //!< in a composition cycle. + + /* === List of composition types set by Client === */ + /* These composition types represent target buffer layers onto which GPU or Blit will draw if SDM + decide to have some or all layers drawn by respective composition engine. + Client must provide a target buffer layer, if respective composition type is not disabled by + an explicit call to SetCompositionState() method. If a composition type is not disabled, + providing a target buffer layer is optional. If SDM is unable to handle layers without support + of such a composition engine, Prepare() call will return failure. + */ + kCompositionGPUTarget, //!< This layer will hold result of composition for layers marked for + //!< GPU composition. + //!< If display device does not set any layer for GPU composition then + //!< this layer would be ignored. Else, this layer will be composed + //!< with other layers marked for SDE composition by SDE. + //!< Only one layer shall be marked as target buffer by the caller. + //!< GPU target layer shall be placed after all application layers + //!< in the layer stack. + + kCompositionBlitTarget, //!< This layer will hold result of composition for blit rectangles + //!< from the layers marked for hybrid composition. Nth blit rectangle + //!< in a layer shall be composed onto Nth blit target. + //!< If display device does not set any layer for hybrid composition + //!< then this would be ignored. + //!< Blit target layers shall be placed after GPUTarget in the layer + //!< stack. +}; + +/*! @brief This structure defines rotation and flip values for a display layer. + + @sa Layer +*/ +struct LayerTransform { + float rotation = 0.0f; //!< Left most pixel coordinate. + bool flip_horizontal = false; //!< Mirror reversal of the layer across a horizontal axis. + bool flip_vertical = false; //!< Mirror reversal of the layer across a vertical axis. + + bool operator==(const LayerTransform& transform) const { + return (rotation == transform.rotation && flip_horizontal == transform.flip_horizontal && + flip_vertical == transform.flip_vertical); + } + + bool operator!=(const LayerTransform& transform) const { + return !operator==(transform); + } +}; + +/*! @brief This structure defines flags associated with a layer. The 1-bit flag can be set to ON(1) + or OFF(0). + + @sa LayerBuffer +*/ +struct LayerFlags { + union { + struct { + uint32_t skip : 1; //!< This flag shall be set by client to indicate that this layer + //!< will be handled by GPU. Display Device will not consider it + //!< for composition. + + uint32_t updating : 1; //!< This flag shall be set by client to indicate that this is + //!< updating non-updating. so strategy manager will mark them for + //!< SDE/GPU composition respectively when the layer stack qualifies + //!< for cache based composition. + + uint32_t solid_fill : 1; + //!< This flag shall be set by client to indicate that this layer + //!< is for solid fill without input buffer. Display Device will + //!< use SDE HW feature to achieve it. + + uint32_t cursor : 1; //!< This flag shall be set by client to indicate that this layer + //!< is a cursor + //!< Display Device may handle this layer using HWCursor + + uint32_t single_buffer : 1; //!< This flag shall be set by client to indicate that the layer + //!< uses only a single buffer that will not be swapped out + }; + + uint32_t flags = 0; //!< For initialization purpose only. + //!< Client shall not refer it directly. + }; +}; + +/*! @brief This structure defines flags associated with the layer requests. The 1-bit flag can be + set to ON(1) or OFF(0). + + @sa Layer +*/ +struct LayerRequestFlags { + union { + struct { + uint32_t tone_map : 1; //!< This flag will be set by SDM when the layer needs tone map + uint32_t secure: 1; //!< This flag will be set by SDM when the layer must be secure + uint32_t flip_buffer: 1; //!< This flag will be set by SDM when the layer needs FBT flip + }; + uint32_t request_flags = 0; //!< For initialization purpose only. + //!< Shall not be refered directly. + }; +}; + +/*! @brief This structure defines LayerRequest. + Includes width/height/format of the LayerRequest. + + SDM shall set the properties of LayerRequest to be used by the client + + @sa LayerRequest +*/ +struct LayerRequest { + LayerRequestFlags flags; // Flags associated with this request + LayerBufferFormat format = kFormatRGBA8888; // Requested format + uint32_t width = 0; // Requested unaligned width. + uint32_t height = 0; // Requested unalighed height +}; + +/*! @brief This structure defines flags associated with a layer stack. The 1-bit flag can be set to + ON(1) or OFF(0). + + @sa LayerBuffer +*/ +struct LayerStackFlags { + union { + struct { + uint32_t geometry_changed : 1; //!< This flag shall be set by client to indicate that the + //!< layer set passed to Prepare() has changed by more than + //!< just the buffer handles and acquire fences. + + uint32_t skip_present : 1; //!< This flag will be set to true, if the current layer + //!< stack contains skip layers. + + uint32_t video_present : 1; //!< This flag will be set to true, if current layer stack + //!< contains video. + + uint32_t secure_present : 1; //!< This flag will be set to true, if the current layer + //!< stack contains secure layers. + + uint32_t animating : 1; //!< This flag shall be set by client to indicate that the + //!< current frame is animating.i + + uint32_t attributes_changed : 1; + //!< This flag shall be set by client to indicate that the + //!< current frame has some properties changed and + //!< needs re-config. + + uint32_t cursor_present : 1; //!< This flag will be set to true if the current layer + //!< stack contains cursor layer. + + uint32_t single_buffered_layer_present : 1; //!< Set if stack has single buffered layer + + uint32_t s3d_mode_present : 1; //!< This flag will be set to true, if the current layer + //!< stack contains s3d layer, and the layer stack can enter + //!< s3d mode. + + uint32_t post_processed_output : 1; // If output_buffer should contain post processed output + // This applies only to primary displays currently + + uint32_t hdr_present : 1; //!< Set if stack has HDR content + }; + + uint32_t flags = 0; //!< For initialization purpose only. + //!< Client shall not refer it directly. + }; +}; + +/*! @brief This structure defines a rectanglular area inside a display layer. + + @sa LayerRectArray +*/ +struct LayerRect { + float left = 0.0f; //!< Left-most pixel coordinate. + float top = 0.0f; //!< Top-most pixel coordinate. + float right = 0.0f; //!< Right-most pixel coordinate. + float bottom = 0.0f; //!< Bottom-most pixel coordinate. + + LayerRect() = default; + + LayerRect(float l, float t, float r, float b) : left(l), top(t), right(r), bottom(b) { } + + bool operator==(const LayerRect& rect) const { + return left == rect.left && right == rect.right && top == rect.top && bottom == rect.bottom; + } + + bool operator!=(const LayerRect& rect) const { + return !operator==(rect); + } +}; + +/*! @brief This structure defines an array of display layer rectangles. + + @sa LayerRect +*/ +struct LayerRectArray { + LayerRect *rect = NULL; //!< Pointer to first element of array. + uint32_t count = 0; //!< Number of elements in the array. +}; + +/*! @brief This structure defines display layer object which contains layer properties and a drawing + buffer. + + @sa LayerArray +*/ +struct Layer { + LayerBuffer input_buffer = {}; //!< Buffer to be composed. + //!< If this remains unchanged between two + //!< consecutive Prepare() calls and + //!< geometry_changed flag is not set for the + //!< second call, then the display device will + //!< assume that buffer content has not + //!< changed. + + LayerComposition composition = kCompositionGPU; //!< Composition type which can be set by either + //!< the client or the display device. This value + //!< should be preserved between Prepare() and + //!< Commit() calls. + + LayerRect src_rect = {}; //!< Rectangular area of the layer buffer to + //!< consider for composition. + + LayerRect dst_rect = {}; //!< The target position where the frame will be + //!< displayed. Cropping rectangle is scaled to + //!< fit into this rectangle. The origin is the + //!< top-left corner of the screen. + + std::vector<LayerRect> visible_regions = {}; //!< Visible rectangular areas in screen space. + //!< The visible region includes areas overlapped + //!< by a translucent layer. + + std::vector<LayerRect> dirty_regions = {}; //!< Rectangular areas in the current frames + //!< that have changed in comparison to + //!< previous frame. + + std::vector<LayerRect> blit_regions = {}; //!< Rectangular areas of this layer which need + //!< to be composed to blit target. Display + //!< device will update blit rectangles if a + //!< layer composition is set as hybrid. Nth blit + //!< rectangle shall be composed onto Nth blit + //!< target. + + LayerBlending blending = kBlendingPremultiplied; //!< Blending operation which need to be + //!< applied on the layer buffer during + //!< composition. + + LayerTransform transform = {}; //!< Rotation/Flip operations which need to be + //!< applied to the layer buffer during + //!< composition. + + uint8_t plane_alpha = 0xff; //!< Alpha value applied to the whole layer. + //!< Value of each pixel is computed as: + //!< if(kBlendingPremultiplied) { + //!< pixel.RGB = pixel.RGB * planeAlpha/255 + //!< } + //!< pixel.a = pixel.a * planeAlpha + + uint32_t frame_rate = 0; //!< Rate at which frames are being updated for + //!< this layer. + + uint32_t solid_fill_color = 0; //!< Solid color used to fill the layer when + //!< no content is associated with the layer. + + LayerFlags flags; //!< Flags associated with this layer. + + LayerRequest request = {}; //!< o/p - request on this Layer by SDM. + + Lut3d lut_3d = {}; //!< o/p - Populated by SDM when tone mapping is + //!< needed on this layer. +}; + +/*! @brief This structure defines a layer stack that contains layers which need to be composed and + rendered onto the target. + + @sa DisplayInterface::Prepare + @sa DisplayInterface::Commit +*/ +struct LayerStack { + std::vector<Layer *> layers = {}; //!< Vector of layer pointers. + + int retire_fence_fd = -1; //!< File descriptor referring to a sync fence object which + //!< will be signaled when this composited frame has been + //!< replaced on screen by a subsequent frame on a physical + //!< display. The fence object is created and returned during + //!< Commit(). Client shall close the returned file + //!< descriptor. + //!< NOTE: This field applies to a physical display only. + + LayerBuffer *output_buffer = NULL; //!< Pointer to the buffer where composed buffer would be + //!< rendered for virtual displays. + //!< NOTE: This field applies to a virtual display only. + + LayerStackFlags flags; //!< Flags associated with this layer set. +}; + +} // namespace sdm + +#endif // __LAYER_STACK_H__ + diff --git a/msm8909/sdm/include/core/sdm_types.h b/msm8909/sdm/include/core/sdm_types.h new file mode 100644 index 00000000..f8bb4e39 --- /dev/null +++ b/msm8909/sdm/include/core/sdm_types.h @@ -0,0 +1,75 @@ +/* +* Copyright (c) 2014 - 2017, 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. +*/ + +/*! @file sdm_types.h + @brief This file contains miscellaneous data types used across display interfaces. +*/ +#ifndef __SDM_TYPES_H__ +#define __SDM_TYPES_H__ + +namespace sdm { + +/*! @brief This enum represents different error codes that display interfaces may return. +*/ +enum DisplayError { + kErrorNone, //!< Call executed successfully. + kErrorUndefined, //!< An unspecified error has occured. + kErrorNotSupported, //!< Requested operation is not supported. + kErrorPermission, //!< Operation is not permitted in current state. + kErrorVersion, //!< Client is using advanced version of interfaces and calling into an + //!< older version of display library. + kErrorDataAlignment, //!< Client data structures are not aligned on naturual boundaries. + kErrorInstructionSet, //!< 32-bit client is calling into 64-bit library or vice versa. + kErrorParameters, //!< Invalid parameters passed to a method. + kErrorFileDescriptor, //!< Invalid file descriptor. + kErrorMemory, //!< System is running low on memory. + kErrorResources, //!< Not enough hardware resources available to execute call. + kErrorHardware, //!< A hardware error has occured. + kErrorTimeOut, //!< The operation has timed out to prevent client from waiting forever. + kErrorShutDown, //!< Driver is processing shutdown sequence + kErrorPerfValidation, //!< Bandwidth or Clock requirement validation failure. + kErrorNoAppLayers, //!< No App layer(s) in the draw cycle. + kErrorNotValidated, //!< Draw cycle has not been validated. +}; + +/*! @brief This structure is defined for client and library compatibility check purpose only. This + structure is used in SDM_VERSION_TAG definition only. Client should not refer it directly for + any purpose. +*/ +struct SDMCompatibility { + char c1; + int i1; + char c2; + int i2; +}; + +} // namespace sdm + +#endif // __SDM_TYPES_H__ + diff --git a/msm8909/sdm/include/core/socket_handler.h b/msm8909/sdm/include/core/socket_handler.h new file mode 100644 index 00000000..e7fe00e4 --- /dev/null +++ b/msm8909/sdm/include/core/socket_handler.h @@ -0,0 +1,75 @@ +/* +* 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. +*/ + +/*! @file socket_handler.h + @brief Interface file for platform specific Socket Handler. + + @details SDM will use this interface to get the platform specific Socket fd. +*/ + +#ifndef __SOCKET_HANDLER_H__ +#define __SOCKET_HANDLER_H__ + +namespace sdm { + +/*! @brief This enum represents Socket types, for which SDM can request the fd. + +*/ +enum SocketType { + kDpps, //!< Socket for Dpps +}; + +/*! @brief Socket handler implemented by the client + + @details This class declares prototype for SocketHandler methods which must be + implemented by client. SDM will use these methods to get the platform specific Socket fd. + + @sa CoreInterface::CreateCore +*/ +class SocketHandler { + public: + /*! @brief Method to get the platform specific Socket fd for a given socket type. + + @details This method returns the platform specific Socket fd for a given socket type. + It is the responsibility of the caller to close the file descriptor. + + @param[in] socket_type + + @return \link int \endlink + */ + + virtual int GetSocketFd(SocketType socket_type) = 0; + + protected: + virtual ~SocketHandler() { } +}; + +} // namespace sdm + +#endif // __SOCKET_HANDLER_H__ diff --git a/msm8909/sdm/include/private/color_interface.h b/msm8909/sdm/include/private/color_interface.h new file mode 100644 index 00000000..94be13d3 --- /dev/null +++ b/msm8909/sdm/include/private/color_interface.h @@ -0,0 +1,88 @@ +/* Copyright (c) 2015-2017, The Linux Foundataion. 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 __COLOR_INTERFACE_H__ +#define __COLOR_INTERFACE_H__ + +#include "core/sdm_types.h" +#include "color_params.h" + +namespace sdm { + +#define COLORMGR_LIBRARY_NAME "libsdm-color.so" +#define CREATE_COLOR_INTERFACE_NAME "CreateColorInterface" +#define DESTROY_COLOR_INTERFACE_NAME "DestroyColorInterface" +#define COLOR_REVISION_MAJOR (1) +#define COLOR_REVISION_MINOR (0) + +#define COLOR_VERSION_TAG ((uint16_t)((COLOR_REVISION_MAJOR << 8) | COLOR_REVISION_MINOR)) + +class ColorInterface; + +typedef DisplayError (*CreateColorInterface)(uint16_t version, DisplayType type, + const PPHWAttributes &attributes, + ColorInterface **interface); + +typedef DisplayError (*DestroyColorInterface)(DisplayType type); + +class ColorInterface { + public: + virtual DisplayError ColorSVCRequestRoute(const PPDisplayAPIPayload &in_payload, + PPDisplayAPIPayload *out_payload, + PPFeaturesConfig *out_features, + PPPendingParams *pending_action) = 0; + + virtual DisplayError ApplyDefaultDisplayMode(PPFeaturesConfig *out_features) = 0; + + virtual DisplayError ColorIntfSetColorTransform(PPFeaturesConfig *out_features, + uint32_t disp_id, uint32_t length, + const double *trans_data) = 0; + + virtual DisplayError ColorIntfSetDisplayMode(PPFeaturesConfig *out_features, + uint32_t disp_id, int32_t mode_id) = 0; + + virtual DisplayError ColorIntfGetNumDisplayModes(PPFeaturesConfig *out_features, + uint32_t disp_id, uint32_t *mode_cnt) = 0; + + virtual DisplayError ColorIntfEnumerateDisplayModes(PPFeaturesConfig *out_features, + uint32_t disp_id, SDEDisplayMode *modes, + uint32_t *mode_cnt) = 0; + virtual DisplayError ColorIntfGetModeInfo(PPFeaturesConfig *out_features, + uint32_t disp_id, int32_t mode_id, + AttrVal *query) = 0; + virtual DisplayError ColorIntfGetDefaultModeID(PPFeaturesConfig *out_features, + uint32_t disp_id, int32_t *mode_id) = 0; + + protected: + virtual ~ColorInterface() {} +}; + +} // namespace sdm + +#endif // __COLOR_INTERFACE_H__ diff --git a/msm8909/sdm/include/private/color_params.h b/msm8909/sdm/include/private/color_params.h new file mode 100644 index 00000000..897b2347 --- /dev/null +++ b/msm8909/sdm/include/private/color_params.h @@ -0,0 +1,636 @@ +/* Copyright (c) 2015-2017, The Linux Foundataion. 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 __COLOR_PARAMS_H__ +#define __COLOR_PARAMS_H__ + +#include <stdio.h> +#include <string.h> +#include <utils/locker.h> +#include <utils/constants.h> +#include <core/sdm_types.h> +#include <core/display_interface.h> + +#include <utility> +#include <string> +#include <vector> + +#include "hw_info_types.h" + +namespace sdm { + +typedef std::vector<std::pair<std::string, std::string>> AttrVal; + +// Bitmap Pending action to indicate to the caller what's pending to be taken care of. +enum PendingAction { + kInvalidating = BITMAP(0), + kApplySolidFill = BITMAP(1), + kDisableSolidFill = BITMAP(2), + kEnterQDCMMode = BITMAP(3), + kExitQDCMMode = BITMAP(4), + kSetPanelBrightness = BITMAP(5), + kEnableFrameCapture = BITMAP(6), + kDisableFrameCapture = BITMAP(7), + kConfigureDetailedEnhancer = BITMAP(8), + kInvalidatingAndkSetPanelBrightness = BITMAP(9), + kModeSet = BITMAP(10), + kGetDetailedEnhancerData = BITMAP(21), + kNoAction = BITMAP(31), +}; + +static const uint32_t kOpsEnable = BITMAP(0); +static const uint32_t kOpsRead = BITMAP(1); +static const uint32_t kOpsWrite = BITMAP(2); +static const uint32_t kOpsDisable = BITMAP(3); + +static const uint32_t kOpsGc8BitRoundEnable = BITMAP(4); + +static const uint32_t kPaHueEnable = BITMAP(4); +static const uint32_t kPaSatEnable = BITMAP(5); +static const uint32_t kPaValEnable = BITMAP(6); +static const uint32_t kPaContEnable = BITMAP(7); + +static const uint32_t kPaSixZoneEnable = BITMAP(8); +static const uint32_t kPaSkinEnable = BITMAP(9); +static const uint32_t kPaSkyEnable = BITMAP(10); +static const uint32_t kPaFoliageEnable = BITMAP(11); + +static const uint32_t kLeftSplitMode = BITMAP(28); // 0x10000000 +static const uint32_t kRightSplitMode = BITMAP(29); // 0x20000000 + +static const int32_t kInvalidModeId = -1; + +static const std::string kDynamicRangeAttribute = "DynamicRange"; +static const std::string kColorGamutAttribute = "ColorGamut"; +static const std::string kPictureQualityAttribute = "PictureQuality"; + +static const std::string kHdr = "hdr"; +static const std::string kSdr = "sdr"; + +static const std::string kNative = "native"; +static const std::string kDcip3 = "dcip3"; +static const std::string kSrgb = "srgb"; +static const std::string kDisplayP3 = "display_p3"; + +static const std::string kVivid = "vivid"; +static const std::string kSharp = "sharp"; +static const std::string kStandard = "standard"; + +// Enum to identify type of dynamic range of color mode. +enum DynamicRangeType { + kSdrType, + kHdrType, +}; + +// ENUM to identify different Postprocessing feature block to program. +// Note: For each new entry added here, also need update hw_interface::GetPPFeaturesVersion<> +// AND HWPrimary::SetPPFeatures<>. +enum PPGlobalColorFeatureID { + kGlobalColorFeaturePcc, + kGlobalColorFeatureIgc, + kGlobalColorFeaturePgc, + kMixerColorFeatureGc, + kGlobalColorFeaturePaV2, + kGlobalColorFeatureDither, + kGlobalColorFeatureGamut, + kGlobalColorFeaturePADither, + kGlobalColorFeatureCsc, + kMaxNumPPFeatures, +}; + +struct PPPendingParams { + int32_t action = kNoAction; + void *params = NULL; +}; + +struct PPColorInfo { + uint32_t r_bitdepth = 0; + uint32_t r = 0; + uint32_t g_bitdepth = 0; + uint32_t g = 0; + uint32_t b_bitdepth = 0; + uint32_t b = 0; +}; + +struct PPColorFillParams { + uint32_t flags = 0; + struct { + uint32_t width = 0; + uint32_t height = 0; + int32_t x = 0; + int32_t y = 0; + } rect; + + PPColorInfo color; +}; + +struct PPFeatureVersion { + // SDE ASIC versioning its PP block at each specific feature level. + static const uint32_t kSDEPpVersionInvalid = 0; + static const uint32_t kSDEIgcV17 = 1; + static const uint32_t kSDEPgcV17 = 5; + static const uint32_t kSDEDitherV17 = 7; + static const uint32_t kSDEGamutV17 = 9; + static const uint32_t kSDEPaV17 = 11; + static const uint32_t kSDEPccV17 = 13; + static const uint32_t kSDELegacyPP = 15; + static const uint32_t kSDEPADitherV17 = 16; + static const uint32_t kSDEIgcV30 = 17; + static const uint32_t kSDEGamutV4 = 18; + + uint32_t version[kMaxNumPPFeatures]; + PPFeatureVersion() { memset(version, 0, sizeof(version)); } +}; + +struct PPHWAttributes : HWResourceInfo, HWPanelInfo, DisplayConfigVariableInfo { + char panel_name[256] = "generic_panel"; + PPFeatureVersion version; + int panel_max_brightness = 0; + + void Set(const HWResourceInfo &hw_res, const HWPanelInfo &panel_info, + const DisplayConfigVariableInfo &attr, const PPFeatureVersion &feature_ver); +}; + +struct PPDisplayAPIPayload { + bool own_payload = false; // to indicate if *payload is owned by this or just a reference. + uint32_t size = 0; + uint8_t *payload = NULL; + + PPDisplayAPIPayload() = default; + PPDisplayAPIPayload(uint32_t size, uint8_t *param) + : size(size), payload(param) {} + + template <typename T> + DisplayError CreatePayload(T *&output) { + DisplayError ret = kErrorNone; + + payload = new uint8_t[sizeof(T)](); + if (!payload) { + ret = kErrorMemory; + output = NULL; + } else { + this->size = sizeof(T); + output = reinterpret_cast<T *>(payload); + own_payload = true; + } + return ret; + } + + DisplayError CreatePayloadBytes(uint32_t size_in_bytes, uint8_t **output) { + DisplayError ret = kErrorNone; + + payload = new uint8_t[size_in_bytes](); + if (!payload) { + ret = kErrorMemory; + *output = NULL; + } else { + this->size = size_in_bytes; + *output = payload; + own_payload = true; + } + return ret; + } + + inline void DestroyPayload() { + if (payload && own_payload) { + delete[] payload; + payload = NULL; + size = 0; + } else { + payload = NULL; + size = 0; + } + } +}; + +struct PPRectInfo { + uint32_t width; + uint32_t height; + int32_t x; + int32_t y; +}; + +typedef enum { + PP_PIXEL_FORMAT_NONE = 0, + PP_PIXEL_FORMAT_RGB_888, + PP_PIXEL_FORMAT_RGB_2101010, + PP_PIXEL_FORMAT_MAX, + PP_PIXEL_FORMAT_FORCE32BIT = 0x7FFFFFFF, +} PPPixelFormats; + +struct PPFrameCaptureInputParams { + PPRectInfo rect; + PPPixelFormats out_pix_format; + uint32_t flags; +}; + +struct PPFrameCaptureData { + PPFrameCaptureInputParams input_params; + uint8_t *buffer; + uint32_t buffer_stride; + uint32_t buffer_size; +}; + +static const uint32_t kDeTuningFlagSharpFactor = 0x01; +static const uint32_t kDeTuningFlagClip = 0x02; +static const uint32_t kDeTuningFlagThrQuiet = 0x04; +static const uint32_t kDeTuningFlagThrDieout = 0x08; +static const uint32_t kDeTuningFlagThrLow = 0x10; +static const uint32_t kDeTuningFlagThrHigh = 0x20; +static const uint32_t kDeTuningFlagContentQualLevel = 0x40; + +typedef enum { + kDeContentQualUnknown, + kDeContentQualLow, + kDeContentQualMedium, + kDeContentQualHigh, + kDeContentQualMax, +} PPDEContentQualLevel; + +typedef enum { + kDeContentTypeUnknown, + kDeContentTypeVideo, + kDeContentTypeGraphics, + kDeContentTypeMax, +} PPDEContentType; + +struct PPDETuningCfg { + uint32_t flags = 0; + int32_t sharp_factor = 0; + uint16_t thr_quiet = 0; + uint16_t thr_dieout = 0; + uint16_t thr_low = 0; + uint16_t thr_high = 0; + uint16_t clip = 0; + PPDEContentQualLevel quality = kDeContentQualUnknown; + PPDEContentType content_type = kDeContentTypeUnknown; +}; + +struct PPDETuningCfgData { + uint32_t cfg_en = 0; + PPDETuningCfg params; + bool cfg_pending = false; +}; + +struct SDEGamutCfg { + static const int kGamutTableNum = 4; + static const int kGamutScaleoffTableNum = 3; + static const int kGamutTableSize = 1229; + static const int kGamutTableCoarseSize = 32; + static const int kGamutScaleoffSize = 16; + uint32_t mode; + uint32_t map_en; + uint32_t tbl_size[kGamutTableNum]; + uint32_t *c0_data[kGamutTableNum]; + uint32_t *c1_c2_data[kGamutTableNum]; + uint32_t tbl_scale_off_sz[kGamutScaleoffTableNum]; + uint32_t *scale_off_data[kGamutScaleoffTableNum]; +}; + +struct SDEPccCoeff { + uint32_t c = 0; + uint32_t r = 0; + uint32_t g = 0; + uint32_t b = 0; + uint32_t rg = 0; + uint32_t gb = 0; + uint32_t rb = 0; + uint32_t rgb = 0; +}; + +struct SDEPccCfg { + SDEPccCoeff red; + SDEPccCoeff green; + SDEPccCoeff blue; + + static SDEPccCfg *Init(uint32_t arg __attribute__((__unused__))); + SDEPccCfg *GetConfig() { return this; } +}; + +struct SDECscCfg { + static const uint32_t kCscMVSize = 9; + static const uint32_t kCscBVSize = 3; + static const uint32_t kCscLVSize = 6; + uint32_t flags; + uint32_t csc_mv[kCscMVSize]; + uint32_t csc_pre_bv[kCscBVSize]; + uint32_t csc_post_bv[kCscBVSize]; + uint32_t csc_pre_lv[kCscLVSize]; + uint32_t csc_post_lv[kCscLVSize]; + + static SDECscCfg *Init(uint32_t arg __attribute__((__unused__))); + SDECscCfg *GetConfig() { return this; } +}; + +struct SDEDitherCfg { + uint32_t g_y_depth; + uint32_t r_cr_depth; + uint32_t b_cb_depth; + uint32_t length; + uint32_t dither_matrix[16]; + uint32_t temporal_en; + + static SDEDitherCfg *Init(uint32_t arg __attribute__((__unused__))); + SDEDitherCfg *GetConfig() { return this; } +}; + +struct SDEPADitherData { + uint64_t data_flags; + uint32_t matrix_size; + uint64_t matrix_data_addr; + uint32_t strength; + uint32_t offset_en; +}; + +class SDEPADitherWrapper : private SDEPADitherData { + public: + static SDEPADitherWrapper *Init(uint32_t arg __attribute__((__unused__))); + ~SDEPADitherWrapper() { + if (buffer_) + delete[] buffer_; + } + inline SDEPADitherData *GetConfig(void) { return this; } + + private: + SDEPADitherWrapper() {} + uint32_t *buffer_ = NULL; +}; + +struct SDEPaMemColorData { + uint32_t adjust_p0 = 0; + uint32_t adjust_p1 = 0; + uint32_t adjust_p2 = 0; + uint32_t blend_gain = 0; + uint8_t sat_hold = 0; + uint8_t val_hold = 0; + uint32_t hue_region = 0; + uint32_t sat_region = 0; + uint32_t val_region = 0; +}; + +struct SDEPaData { + static const int kSixZoneLUTSize = 384; + uint32_t mode = 0; + uint32_t hue_adj = 0; + uint32_t sat_adj = 0; + uint32_t val_adj = 0; + uint32_t cont_adj; + SDEPaMemColorData skin; + SDEPaMemColorData sky; + SDEPaMemColorData foliage; + uint32_t six_zone_thresh = 0; + uint32_t six_zone_adj_p0 = 0; + uint32_t six_zone_adj_p1 = 0; + uint8_t six_zone_sat_hold = 0; + uint8_t six_zone_val_hold = 0; + uint32_t six_zone_len = 0; + uint32_t *six_zone_curve_p0 = NULL; + uint32_t *six_zone_curve_p1 = NULL; +}; + +struct SDEIgcLUTData { + static const int kMaxIgcLUTEntries = 256; + uint32_t table_fmt = 0; + uint32_t len = 0; + uint32_t *c0_c1_data = NULL; + uint32_t *c2_data = NULL; +}; + +struct SDEIgcV30LUTData { + static const int kMaxIgcLUTEntries = 256; + uint32_t table_fmt = 0; + uint32_t len = 0; + uint64_t c0_c1_data = 0; + uint64_t c2_data = 0; + uint32_t strength = 0; +}; + +struct SDEPgcLUTData { + static const int kPgcLUTEntries = 1024; + uint32_t len = 0; + uint32_t *c0_data = NULL; + uint32_t *c1_data = NULL; + uint32_t *c2_data = NULL; +}; + +struct SDEDisplayMode { + static const int kMaxModeNameSize = 256; + int32_t id = -1; + uint32_t type = 0; + char name[kMaxModeNameSize] = {0}; +}; + +// Wrapper on HW block config data structure to encapsulate the details of allocating +// and destroying from the caller. +class SDEGamutCfgWrapper : private SDEGamutCfg { + public: + enum GamutMode { + GAMUT_FINE_MODE = 0x01, + GAMUT_COARSE_MODE, + GAMUT_COARSE_MODE_13, + }; + + // This factory method will be used by libsdm-color.so data producer to be populated with + // converted config values for SDE feature blocks. + static SDEGamutCfgWrapper *Init(uint32_t arg); + + // Data consumer<Commit thread> will be responsible to destroy it once the feature is commited. + ~SDEGamutCfgWrapper() { + if (buffer_) + delete[] buffer_; + } + + // Data consumer will use this method to retrieve contained feature configuration. + inline SDEGamutCfg *GetConfig(void) { return this; } + + private: + SDEGamutCfgWrapper() {} + uint32_t *buffer_ = NULL; +}; + +class SDEPaCfgWrapper : private SDEPaData { + public: + static SDEPaCfgWrapper *Init(uint32_t arg = 0); + ~SDEPaCfgWrapper() { + if (buffer_) + delete[] buffer_; + } + inline SDEPaData *GetConfig(void) { return this; } + + private: + SDEPaCfgWrapper() {} + uint32_t *buffer_ = NULL; +}; + +class SDEIgcLUTWrapper : private SDEIgcLUTData { + public: + static SDEIgcLUTWrapper *Init(uint32_t arg __attribute__((__unused__))); + ~SDEIgcLUTWrapper() { + if (buffer_) + delete[] buffer_; + } + inline SDEIgcLUTData *GetConfig(void) { return this; } + + private: + SDEIgcLUTWrapper() {} + uint32_t *buffer_ = NULL; +}; + +class SDEIgcV30LUTWrapper : private SDEIgcV30LUTData { + public: + static SDEIgcV30LUTWrapper *Init(uint32_t arg __attribute__((__unused__))); + ~SDEIgcV30LUTWrapper() { + if (buffer_) + delete[] buffer_; + } + inline SDEIgcV30LUTData *GetConfig(void) { return this; } + + private: + SDEIgcV30LUTWrapper(const SDEIgcV30LUTWrapper& src) { /* do not create copies */ } + SDEIgcV30LUTWrapper& operator=(const SDEIgcV30LUTWrapper&) { return *this; } + SDEIgcV30LUTWrapper() {} + uint32_t *buffer_ = NULL; +}; + +class SDEPgcLUTWrapper : private SDEPgcLUTData { + public: + static SDEPgcLUTWrapper *Init(uint32_t arg __attribute__((__unused__))); + ~SDEPgcLUTWrapper() { + if (buffer_) + delete[] buffer_; + } + inline SDEPgcLUTData *GetConfig(void) { return this; } + + private: + SDEPgcLUTWrapper() {} + uint32_t *buffer_ = NULL; +}; + +// Base Postprocessing features information. +class PPFeatureInfo { + public: + uint32_t enable_flags_ = 0; // bitmap to indicate subset of parameters enabling or not. + uint32_t feature_version_ = 0; + uint32_t feature_id_ = 0; + uint32_t disp_id_ = 0; + uint32_t pipe_id_ = 0; + + virtual ~PPFeatureInfo() {} + virtual void *GetConfigData(void) const = 0; +}; + +// Individual Postprocessing feature representing physical attributes and information +// This template class wrapping around abstract data type representing different +// post-processing features. It will take output from ColorManager converting from raw metadata. +// The configuration will directly pass into HWInterface to program the hardware accordingly. +template <typename T> +class TPPFeatureInfo : public PPFeatureInfo { + public: + virtual ~TPPFeatureInfo() { + if (params_) + delete params_; + } + + // API for data consumer to get underlying data configs to program into pp hardware block. + virtual void *GetConfigData(void) const { return params_->GetConfig(); } + + // API for data producer to get access to underlying data configs to populate it. + T *GetParamsReference(void) { return params_; } + + // API for create this template object. + static TPPFeatureInfo *Init(uint32_t arg = 0) { + TPPFeatureInfo *info = new TPPFeatureInfo(); + if (info) { + info->params_ = T::Init(arg); + if (!info->params_) { + delete info; + info = NULL; + } + } + + return info; + } + + protected: + TPPFeatureInfo() = default; + + private: + T *params_ = NULL; +}; + +// This singleton class serves as data exchanging central between data producer +// <libsdm-color.so> and data consumer<SDM and HWC.> +// This class defines PP pending features to be programmed, which generated from +// ColorManager. Dirty flag indicates some features are available to be programmed. +// () Lock is needed since the object wil be accessed from 2 tasks. +// All API exposed are not threadsafe, it's caller's responsiblity to acquire the locker. +class PPFeaturesConfig { + public: + PPFeaturesConfig() { memset(feature_, 0, sizeof(feature_)); } + ~PPFeaturesConfig() { Reset(); } + + // ColorManager installs one TFeatureInfo<T> to take the output configs computed + // from ColorManager, containing all physical features to be programmed and also compute + // metadata/populate into T. + inline DisplayError AddFeature(uint32_t feature_id, PPFeatureInfo *feature) { + if (feature_id < kMaxNumPPFeatures) { + if (feature_[feature_id]) { + delete feature_[feature_id]; + feature_[feature_id] = NULL; + } + feature_[feature_id] = feature; + } + return kErrorNone; + } + + inline Locker &GetLocker(void) { return locker_; } + inline PPFrameCaptureData *GetFrameCaptureData(void) { return &frame_capture_data; } + inline PPDETuningCfgData *GetDETuningCfgData(void) { return &de_tuning_data_; } + // Once all features are consumed, destroy/release all TFeatureInfo<T> on the list, + // then clear dirty_ flag and return the lock to the TFeatureInfo<T> producer. + void Reset(); + + // Consumer to call this to retrieve all the TFeatureInfo<T> on the list to be programmed. + DisplayError RetrieveNextFeature(PPFeatureInfo **feature); + + inline bool IsDirty() { return dirty_; } + inline void MarkAsDirty() { dirty_ = true; } + + private: + bool dirty_ = 0; + Locker locker_; + PPFeatureInfo *feature_[kMaxNumPPFeatures]; // reference to TFeatureInfo<T>. + uint32_t next_idx_ = 0; + PPFrameCaptureData frame_capture_data; + PPDETuningCfgData de_tuning_data_; +}; + +} // namespace sdm + +#endif // __COLOR_PARAMS_H__ diff --git a/msm8909/sdm/include/private/dpps_control_interface.h b/msm8909/sdm/include/private/dpps_control_interface.h new file mode 100644 index 00000000..8a449079 --- /dev/null +++ b/msm8909/sdm/include/private/dpps_control_interface.h @@ -0,0 +1,40 @@ +/* +* 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 __DPPS_CONTROL_INTERFACE_H__ +#define __DPPS_CONTROL_INTERFACE_H__ + +namespace sdm { + +class DppsControlInterface { + public: + virtual ~DppsControlInterface() { } + virtual DisplayError On() = 0; + virtual DisplayError Off() = 0; +}; + +} // namespace sdm + +#endif // __DPPS_CONTROL_INTERFACE_H__ + diff --git a/msm8909/sdm/include/private/extension_interface.h b/msm8909/sdm/include/private/extension_interface.h new file mode 100644 index 00000000..2e5bd49c --- /dev/null +++ b/msm8909/sdm/include/private/extension_interface.h @@ -0,0 +1,87 @@ +/* +* Copyright (c) 2015 - 2017, 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 __EXTENSION_INTERFACE_H__ +#define __EXTENSION_INTERFACE_H__ + +#include <core/sdm_types.h> +#include <core/display_interface.h> + +#include "partial_update_interface.h" +#include "strategy_interface.h" +#include "resource_interface.h" +#include "dpps_control_interface.h" + +namespace sdm { + +#define EXTENSION_LIBRARY_NAME "libsdmextension.so" +#define CREATE_EXTENSION_INTERFACE_NAME "CreateExtensionInterface" +#define DESTROY_EXTENSION_INTERFACE_NAME "DestroyExtensionInterface" + +#define EXTENSION_REVISION_MAJOR (1) +#define EXTENSION_REVISION_MINOR (0) + +#define EXTENSION_VERSION_TAG ((uint16_t) ((EXTENSION_REVISION_MAJOR << 8) \ + | EXTENSION_REVISION_MINOR)) + +class ExtensionInterface; + +typedef DisplayError (*CreateExtensionInterface)(uint16_t version, ExtensionInterface **interface); +typedef DisplayError (*DestroyExtensionInterface)(ExtensionInterface *interface); + +class ExtensionInterface { + public: + virtual DisplayError CreatePartialUpdate(DisplayType type, const HWResourceInfo &hw_resource_info, + const HWPanelInfo &hw_panel_info, + const HWMixerAttributes &mixer_attributes, + const HWDisplayAttributes &display_attributes, + const DisplayConfigVariableInfo &fb_config, + PartialUpdateInterface **interface) = 0; + virtual DisplayError DestroyPartialUpdate(PartialUpdateInterface *interface) = 0; + + virtual DisplayError CreateStrategyExtn(DisplayType type, BufferAllocator *buffer_allocator, + const HWResourceInfo &hw_resource_info, + const HWPanelInfo &hw_panel_info, + const HWMixerAttributes &mixer_attributes, + const DisplayConfigVariableInfo &fb_config, + StrategyInterface **interface) = 0; + virtual DisplayError DestroyStrategyExtn(StrategyInterface *interface) = 0; + + virtual DisplayError CreateResourceExtn(const HWResourceInfo &hw_resource_info, + BufferAllocator *buffer_allocator, + BufferSyncHandler *buffer_sync_handler, + ResourceInterface **interface) = 0; + virtual DisplayError DestroyResourceExtn(ResourceInterface *interface) = 0; + virtual DisplayError CreateDppsControlExtn(DppsControlInterface **dpps_control_interface, + SocketHandler *socket_handler) = 0; + virtual DisplayError DestroyDppsControlExtn(DppsControlInterface *interface) = 0; + + protected: + virtual ~ExtensionInterface() { } +}; + +} // namespace sdm + +#endif // __EXTENSION_INTERFACE_H__ + diff --git a/msm8909/sdm/include/private/hw_info_types.h b/msm8909/sdm/include/private/hw_info_types.h new file mode 100644 index 00000000..d4f8d728 --- /dev/null +++ b/msm8909/sdm/include/private/hw_info_types.h @@ -0,0 +1,561 @@ +/* +* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __HW_INFO_TYPES_H__ +#define __HW_INFO_TYPES_H__ + +#include <stdint.h> +#include <core/display_interface.h> +#include <core/core_interface.h> +#include <vector> +#include <map> +#include <string> +#include <bitset> + +namespace sdm { +using std::string; + +const int kMaxSDELayers = 16; // Maximum number of layers that can be handled by MDP5 hardware + // in a given layer stack. +#define MAX_PLANES 4 + +#define MAX_DETAIL_ENHANCE_CURVE 3 + +enum HWDeviceType { + kDevicePrimary, + kDeviceHDMI, + kDeviceVirtual, + kDeviceRotator, + kDeviceMax, +}; + +enum HWBlockType { + kHWPrimary, + kHWHDMI, + kHWWriteback0, + kHWWriteback1, + kHWWriteback2, + kHWBlockMax +}; + +enum HWDisplayMode { + kModeDefault, + kModeVideo, + kModeCommand, +}; + +enum PipeType { + kPipeTypeUnused, + kPipeTypeVIG, + kPipeTypeRGB, + kPipeTypeDMA, + kPipeTypeCursor, +}; + +enum HWSubBlockType { + kHWVIGPipe, + kHWRGBPipe, + kHWDMAPipe, + kHWCursorPipe, + kHWRotatorInput, + kHWRotatorOutput, + kHWWBIntfOutput, + kHWDestinationScalar, + kHWSubBlockMax, +}; + +enum HWAlphaInterpolation { + kInterpolationPixelRepeat, + kInterpolationBilinear, + kInterpolationMax, +}; + +enum HWBlendingFilter { + kBlendFilterCircular, + kBlendFilterSeparable, + kBlendFilterMax, +}; + +enum HWPipeFlags { + kIGC = 0x01, + kMultiRect = 0x02, + kMultiRectParallelMode = 0x04, +}; + +enum HWAVRModes { + kContinuousMode, // Mode to enable AVR feature for every frame. + kOneShotMode, // Mode to enable AVR feature for particular frame. +}; + +typedef std::map<HWSubBlockType, std::vector<LayerBufferFormat>> FormatsMap; + +struct HWDynBwLimitInfo { + uint32_t cur_mode = kBwDefault; + uint32_t total_bw_limit[kBwModeMax] = { 0 }; + uint32_t pipe_bw_limit[kBwModeMax] = { 0 }; +}; + +struct HWPipeCaps { + PipeType type = kPipeTypeUnused; + uint32_t id = 0; + uint32_t master_pipe_id = 0; + uint32_t max_rects = 1; +}; + +struct HWRotatorInfo { + enum { ROT_TYPE_MDSS, ROT_TYPE_V4L2 }; + uint32_t type = ROT_TYPE_MDSS; + uint32_t num_rotator = 0; + bool has_downscale = false; + std::string device_path = ""; + float min_downscale = 2.0f; + bool downscale_compression = false; + + void Reset() { *this = HWRotatorInfo(); } +}; + +struct HWDestScalarInfo { + uint32_t count = 0; + uint32_t max_input_width = 0; + uint32_t max_output_width = 0; + uint32_t max_scale_up = 1; +}; + +enum SmartDMARevision { + V1, + V2, +}; + +struct HWResourceInfo { + uint32_t hw_version = 0; + uint32_t hw_revision = 0; + uint32_t num_dma_pipe = 0; + uint32_t num_vig_pipe = 0; + uint32_t num_rgb_pipe = 0; + uint32_t num_cursor_pipe = 0; + uint32_t num_blending_stages = 0; + uint32_t num_control = 0; + uint32_t num_mixer_to_disp = 0; + uint32_t smp_total = 0; + uint32_t smp_size = 0; + uint32_t num_smp_per_pipe = 0; + uint32_t max_scale_up = 1; + uint32_t max_scale_down = 1; + float rot_downscale_max = 0.0f; + uint64_t max_bandwidth_low = 0; + uint64_t max_bandwidth_high = 0; + uint32_t max_mixer_width = 2048; + uint32_t max_pipe_width = 2048; + uint32_t max_cursor_size = 0; + uint32_t max_pipe_bw = 0; + uint32_t max_sde_clk = 0; + float clk_fudge_factor = 1.0f; + uint32_t macrotile_nv12_factor = 0; + uint32_t macrotile_factor = 0; + uint32_t linear_factor = 0; + uint32_t scale_factor = 0; + uint32_t extra_fudge_factor = 0; + uint32_t amortizable_threshold = 0; + uint32_t system_overhead_lines = 0; + bool has_bwc = false; + bool has_ubwc = false; + bool has_decimation = false; + bool has_macrotile = false; + bool has_non_scalar_rgb = false; + bool is_src_split = false; + bool perf_calc = false; + bool has_dyn_bw_support = false; + bool separate_rotator = false; + bool has_qseed3 = false; + bool has_concurrent_writeback = false; + bool has_ppp = false; + uint32_t writeback_index = kHWBlockMax; + HWDynBwLimitInfo dyn_bw_info; + std::vector<HWPipeCaps> hw_pipes; + FormatsMap supported_formats_map; + HWRotatorInfo hw_rot_info; + HWDestScalarInfo hw_dest_scalar_info; + bool has_avr = false; + bool has_hdr = false; + SmartDMARevision smart_dma_rev = SmartDMARevision::V1; + void Reset() { *this = HWResourceInfo(); } +}; + +struct HWSplitInfo { + uint32_t left_split = 0; + uint32_t right_split = 0; + + bool operator !=(const HWSplitInfo &split_info) { + return ((left_split != split_info.left_split) || (right_split != split_info.right_split)); + } + + bool operator ==(const HWSplitInfo &split_info) { + return !(operator !=(split_info)); + } +}; + +enum HWS3DMode { + kS3DModeNone, + kS3DModeLR, + kS3DModeRL, + kS3DModeTB, + kS3DModeFP, + kS3DModeMax, +}; + +struct HWColorPrimaries { + uint32_t white_point[2] = {}; // White point + uint32_t red[2] = {}; // Red color primary + uint32_t green[2] = {}; // Green color primary + uint32_t blue[2] = {}; // Blue color primary +}; + +struct HWPanelOrientation { + bool rotation = false; + bool flip_horizontal = false; + bool flip_vertical = false; +}; + +struct HWPanelInfo { + DisplayPort port = kPortDefault; // Display port + HWDisplayMode mode = kModeDefault; // Display mode + bool partial_update = false; // Partial update feature + int left_align = 1; // ROI left alignment restriction + int width_align = 1; // ROI width alignment restriction + int top_align = 1; // ROI top alignment restriction + int height_align = 1; // ROI height alignment restriction + int min_roi_width = 1; // Min width needed for ROI + int min_roi_height = 1; // Min height needed for ROI + bool needs_roi_merge = false; // Merge ROI's of both the DSI's + bool dynamic_fps = false; // Panel Supports dynamic fps + bool dfps_porch_mode = false; // dynamic fps VFP or HFP mode + bool ping_pong_split = false; // Supports Ping pong split + uint32_t min_fps = 0; // Min fps supported by panel + uint32_t max_fps = 0; // Max fps supported by panel + bool is_primary_panel = false; // Panel is primary display + bool is_pluggable = false; // Panel is pluggable + HWSplitInfo split_info; // Panel split configuration + char panel_name[256] = {0}; // Panel name + HWS3DMode s3d_mode = kS3DModeNone; // Panel's current s3d mode. + int panel_max_brightness = 0; // Max panel brightness + uint32_t left_roi_count = 1; // Number if ROI supported on left panel + uint32_t right_roi_count = 1; // Number if ROI supported on right panel + bool hdr_enabled = false; // HDR feature supported + uint32_t peak_luminance = 0; // Panel's peak luminance level + uint32_t average_luminance = 0; // Panel's average luminance level + uint32_t blackness_level = 0; // Panel's blackness level + HWColorPrimaries primaries = {}; // WRGB color primaries + HWPanelOrientation panel_orientation = {}; // Panel Orientation + + bool operator !=(const HWPanelInfo &panel_info) { + return ((port != panel_info.port) || (mode != panel_info.mode) || + (partial_update != panel_info.partial_update) || + (left_align != panel_info.left_align) || (width_align != panel_info.width_align) || + (top_align != panel_info.top_align) || (height_align != panel_info.height_align) || + (min_roi_width != panel_info.min_roi_width) || + (min_roi_height != panel_info.min_roi_height) || + (needs_roi_merge != panel_info.needs_roi_merge) || + (dynamic_fps != panel_info.dynamic_fps) || (min_fps != panel_info.min_fps) || + (dfps_porch_mode != panel_info.dfps_porch_mode) || + (ping_pong_split != panel_info.ping_pong_split) || + (max_fps != panel_info.max_fps) || (is_primary_panel != panel_info.is_primary_panel) || + (split_info != panel_info.split_info) || (s3d_mode != panel_info.s3d_mode) || + (left_roi_count != panel_info.left_roi_count) || + (right_roi_count != panel_info.right_roi_count)); + } + + bool operator ==(const HWPanelInfo &panel_info) { + return !(operator !=(panel_info)); + } +}; + +struct HWSessionConfig { + LayerRect src_rect; + LayerRect dst_rect; + uint32_t buffer_count = 0; + bool secure = false; + uint32_t frame_rate = 0; + LayerTransform transform; + bool secure_camera = false; + + bool operator==(const HWSessionConfig& config) const { + return (src_rect == config.src_rect && + dst_rect == config.dst_rect && + buffer_count == config.buffer_count && + secure == config.secure && + frame_rate == config.frame_rate && + transform == config.transform && + secure_camera == config.secure_camera); + } + + bool operator!=(const HWSessionConfig& config) const { + return !operator==(config); + } +}; + +struct HWRotateInfo { + int pipe_id = -1; // Not actual pipe id, but the relative DMA id + int writeback_id = -1; // Writeback block id, but this is the same as DMA id + LayerRect src_roi; // Source crop of each split + LayerRect dst_roi; // Destination crop of each split + bool valid = false; + int rotate_id = -1; // Actual rotator session id with driver + + void Reset() { *this = HWRotateInfo(); } +}; + +struct HWRotatorSession { + HWRotateInfo hw_rotate_info[kMaxRotatePerLayer]; + uint32_t hw_block_count = 0; // number of rotator hw blocks used by rotator session + int session_id = -1; // A handle with Session Manager + HWSessionConfig hw_session_config; + LayerBuffer input_buffer; // Input to rotator + LayerBuffer output_buffer; // Output of rotator, crop width and stride are same + float input_compression = 1.0f; + float output_compression = 1.0f; + bool is_buffer_cached = false; +}; + +struct HWScaleLutInfo { + uint32_t dir_lut_size = 0; + uint32_t cir_lut_size = 0; + uint32_t sep_lut_size = 0; + uint64_t dir_lut = 0; + uint64_t cir_lut = 0; + uint64_t sep_lut = 0; +}; + +struct HWDetailEnhanceData : DisplayDetailEnhancerData { + uint16_t prec_shift = 0; + int16_t adjust_a[MAX_DETAIL_ENHANCE_CURVE] = {0}; + int16_t adjust_b[MAX_DETAIL_ENHANCE_CURVE] = {0}; + int16_t adjust_c[MAX_DETAIL_ENHANCE_CURVE] = {0}; +}; + +struct HWPixelExtension { + int32_t extension = 0; // Number of pixels extension in left, right, top and bottom directions + // for all color components. This pixel value for each color component + // should be sum of fetch and repeat pixels. + + int32_t overfetch = 0; // Number of pixels need to be overfetched in left, right, top and bottom + // directions from source image for scaling. + + int32_t repeat = 0; // Number of pixels need to be repeated in left, right, top and bottom + // directions for scaling. +}; + +struct HWPlane { + int32_t init_phase_x = 0; + int32_t phase_step_x = 0; + int32_t init_phase_y = 0; + int32_t phase_step_y = 0; + HWPixelExtension left; + HWPixelExtension top; + HWPixelExtension right; + HWPixelExtension bottom; + uint32_t roi_width = 0; + int32_t preload_x = 0; + int32_t preload_y = 0; + uint32_t src_width = 0; + uint32_t src_height = 0; +}; + +struct HWScaleData { + struct enable { + uint8_t scale = 0; + uint8_t direction_detection = 0; + uint8_t detail_enhance = 0; + } enable; + uint32_t dst_width = 0; + uint32_t dst_height = 0; + HWPlane plane[MAX_PLANES]; + // scale_v2_data fields + ScalingFilterConfig y_rgb_filter_cfg = kFilterEdgeDirected; + ScalingFilterConfig uv_filter_cfg = kFilterEdgeDirected; + HWAlphaInterpolation alpha_filter_cfg = kInterpolationPixelRepeat; + HWBlendingFilter blend_cfg = kBlendFilterCircular; + + struct lut_flags { + uint8_t lut_swap = 0; + uint8_t lut_dir_wr = 0; + uint8_t lut_y_cir_wr = 0; + uint8_t lut_uv_cir_wr = 0; + uint8_t lut_y_sep_wr = 0; + uint8_t lut_uv_sep_wr = 0; + } lut_flag; + + uint32_t dir_lut_idx = 0; + /* for Y(RGB) and UV planes*/ + uint32_t y_rgb_cir_lut_idx = 0; + uint32_t uv_cir_lut_idx = 0; + uint32_t y_rgb_sep_lut_idx = 0; + uint32_t uv_sep_lut_idx = 0; + + HWDetailEnhanceData detail_enhance; +}; + +struct HWDestScaleInfo { + uint32_t mixer_width = 0; + uint32_t mixer_height = 0; + bool scale_update = false; + HWScaleData scale_data = {}; + LayerRect panel_roi = {}; +}; + +typedef std::map<uint32_t, HWDestScaleInfo *> DestScaleInfoMap; + +struct HWAVRInfo { + bool enable = false; // Flag to Enable AVR feature + HWAVRModes mode = kContinuousMode; // Specifies the AVR mode +}; + +struct HWPipeInfo { + uint8_t rect = 255; + uint32_t pipe_id = 0; + HWSubBlockType sub_block_type = kHWSubBlockMax; + LayerRect src_roi; + LayerRect dst_roi; + uint8_t horizontal_decimation = 0; + uint8_t vertical_decimation = 0; + HWScaleData scale_data; + uint32_t z_order = 0; + uint8_t flags = 0; + bool valid = false; + + void Reset() { *this = HWPipeInfo(); } +}; + +struct HWLayerConfig { + HWPipeInfo left_pipe; // pipe for left side of output + HWPipeInfo right_pipe; // pipe for right side of output + HWRotatorSession hw_rotator_session; + float compression = 1.0f; + + void Reset() { *this = HWLayerConfig(); } +}; + +struct HWHDRLayerInfo { + enum HDROperation { + kNoOp, // No-op. + kSet, // Sets the HDR MetaData - Start of HDR + kReset, // resets the previously set HDR Metadata, End of HDR + }; + + int32_t layer_index = -1; + HDROperation operation = kNoOp; +}; + +struct HWLayersInfo { + LayerStack *stack = NULL; // Input layer stack. Set by the caller. + uint32_t app_layer_count = 0; // Total number of app layers. Must not be 0. + uint32_t gpu_target_index = 0; // GPU target layer index. 0 if not present. + + std::vector<Layer> hw_layers = {}; // Layers which need to be programmed on the HW + + uint32_t index[kMaxSDELayers] = {}; // Indexes of the layers from the layer stack which need to + // be programmed on hardware. + uint32_t roi_index[kMaxSDELayers] = {0}; // Stores the ROI index where the layers are visible. + + int sync_handle = -1; // Release fence id for current draw cycle. + int set_idle_time_ms = -1; // Set idle time to the new specified value. + // -1 indicates no change in idle time since last set value. + + std::vector<LayerRect> left_frame_roi = {}; // Left ROI. + std::vector<LayerRect> right_frame_roi = {}; // Right ROI. + LayerRect partial_fb_roi = {}; // Damaged area in framebuffer. + + bool roi_split = false; // Indicates separated left and right ROI + + bool use_hw_cursor = false; // Indicates that HWCursor pipe needs to be used for cursor layer + DestScaleInfoMap dest_scale_info_map = {}; + HWHDRLayerInfo hdr_layer_info = {}; + Handle pvt_data = NULL; // Private data used by sdm extension only. +}; + +struct HWLayers { + HWLayersInfo info; + HWLayerConfig config[kMaxSDELayers]; + float output_compression = 1.0f; + uint32_t bandwidth = 0; + uint32_t clock = 0; + HWAVRInfo hw_avr_info = {}; +}; + +struct HWDisplayAttributes : DisplayConfigVariableInfo { + bool is_device_split = false; + uint32_t v_front_porch = 0; //!< Vertical front porch of panel + uint32_t v_back_porch = 0; //!< Vertical back porch of panel + uint32_t v_pulse_width = 0; //!< Vertical pulse width of panel + uint32_t h_total = 0; //!< Total width of panel (hActive + hFP + hBP + hPulseWidth) + uint32_t v_total = 0; //!< Total height of panel (vActive + vFP + vBP + vPulseWidth) + std::bitset<32> s3d_config; //!< Stores the bit mask of S3D modes + + void Reset() { *this = HWDisplayAttributes(); } + + bool operator !=(const HWDisplayAttributes &display_attributes) { + return ((is_device_split != display_attributes.is_device_split) || + (x_pixels != display_attributes.x_pixels) || + (y_pixels != display_attributes.y_pixels) || + (x_dpi != display_attributes.x_dpi) || + (y_dpi != display_attributes.y_dpi) || + (fps != display_attributes.fps) || + (vsync_period_ns != display_attributes.vsync_period_ns) || + (v_front_porch != display_attributes.v_front_porch) || + (v_back_porch != display_attributes.v_back_porch) || + (v_pulse_width != display_attributes.v_pulse_width) || + (h_total != display_attributes.h_total) || + (is_yuv != display_attributes.is_yuv)); + } + + bool operator ==(const HWDisplayAttributes &display_attributes) { + return !(operator !=(display_attributes)); + } +}; + +struct HWMixerAttributes { + uint32_t width = 0; // Layer mixer width + uint32_t height = 0; // Layer mixer height + uint32_t split_left = 0; + LayerBufferFormat output_format = kFormatRGB101010; // Layer mixer output format + + bool operator !=(const HWMixerAttributes &mixer_attributes) { + return ((width != mixer_attributes.width) || + (height != mixer_attributes.height) || + (output_format != mixer_attributes.output_format) || + (split_left != mixer_attributes.split_left)); + } + + bool operator ==(const HWMixerAttributes &mixer_attributes) { + return !(operator !=(mixer_attributes)); + } + + bool IsValid() { + return (width > 0 && height > 0); + } +}; + +} // namespace sdm + +#endif // __HW_INFO_TYPES_H__ + diff --git a/msm8909/sdm/include/private/partial_update_interface.h b/msm8909/sdm/include/private/partial_update_interface.h new file mode 100644 index 00000000..b753587a --- /dev/null +++ b/msm8909/sdm/include/private/partial_update_interface.h @@ -0,0 +1,55 @@ +/* +* Copyright (c) 2015, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __PARTIAL_UPDATE_INTERFACE_H__ +#define __PARTIAL_UPDATE_INTERFACE_H__ + +#include <core/display_interface.h> +#include <core/buffer_allocator.h> +#include <core/buffer_sync_handler.h> + +#include "hw_info_types.h" + +namespace sdm { + +struct PUConstraints { + bool enable = true; //!< If this is set, PU will be enabled or it will be disabled + bool enable_cursor_pu = false; //!< If this is set, PU will consider cursor layer in the layer + //!< stack for cursor partial update +}; + +class PartialUpdateInterface { + public: + virtual DisplayError Start(const PUConstraints &pu_constraints) = 0; + virtual DisplayError GenerateROI(HWLayersInfo *hw_layers_info) = 0; + virtual DisplayError Stop() = 0; + + protected: + virtual ~PartialUpdateInterface() { } +}; + +} // namespace sdm + +#endif // __PARTIAL_UPDATE_INTERFACE_H__ + diff --git a/msm8909/sdm/include/private/resource_interface.h b/msm8909/sdm/include/private/resource_interface.h new file mode 100644 index 00000000..356c5662 --- /dev/null +++ b/msm8909/sdm/include/private/resource_interface.h @@ -0,0 +1,77 @@ +/* +* Copyright (c) 2015 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __RESOURCE_INTERFACE_H__ +#define __RESOURCE_INTERFACE_H__ + +#include <core/display_interface.h> +#include "hw_info_types.h" + +namespace sdm { + +class ResourceInterface { + public: + enum ResourceCmd { + kCmdResetScalarLUT, + kCmdMax, + }; + + virtual DisplayError RegisterDisplay(DisplayType type, + const HWDisplayAttributes &display_attributes, + const HWPanelInfo &hw_panel_info, + const HWMixerAttributes &mixer_attributes, + Handle *display_ctx) = 0; + virtual DisplayError UnregisterDisplay(Handle display_ctx) = 0; + virtual DisplayError ReconfigureDisplay(Handle display_ctx, + const HWDisplayAttributes &display_attributes, + const HWPanelInfo &hw_panel_info, + const HWMixerAttributes &mixer_attributes) = 0; + virtual DisplayError Start(Handle display_ctx) = 0; + virtual DisplayError Stop(Handle display_ctx, HWLayers *hw_layers) = 0; + virtual DisplayError Prepare(Handle display_ctx, HWLayers *hw_layers) = 0; + virtual DisplayError PostPrepare(Handle display_ctx, HWLayers *hw_layers) = 0; + virtual DisplayError Commit(Handle display_ctx, HWLayers *hw_layers) = 0; + virtual DisplayError PostCommit(Handle display_ctx, HWLayers *hw_layers) = 0; + virtual void Purge(Handle display_ctx) = 0; + virtual DisplayError SetMaxMixerStages(Handle display_ctx, uint32_t max_mixer_stages) = 0; + virtual DisplayError ValidateScaling(const LayerRect &crop, const LayerRect &dst, + bool rotate90, BufferLayout layout, + bool use_rotator_downscale) = 0; + virtual DisplayError ValidateCursorConfig(Handle display_ctx, const Layer *layer, + bool is_top) = 0; + virtual DisplayError ValidateAndSetCursorPosition(Handle display_ctx, HWLayers *hw_layers, + int x, int y, + DisplayConfigVariableInfo *fb_config) = 0; + virtual DisplayError SetMaxBandwidthMode(HWBwModes mode) = 0; + virtual DisplayError GetScaleLutConfig(HWScaleLutInfo *lut_info) = 0; + virtual DisplayError SetDetailEnhancerData(Handle display_ctx, + const DisplayDetailEnhancerData &de_data) = 0; + virtual DisplayError Perform(int cmd, ...) = 0; + virtual ~ResourceInterface() { } +}; + +} // namespace sdm + +#endif // __RESOURCE_INTERFACE_H__ + diff --git a/msm8909/sdm/include/private/strategy_interface.h b/msm8909/sdm/include/private/strategy_interface.h new file mode 100644 index 00000000..f903d5f0 --- /dev/null +++ b/msm8909/sdm/include/private/strategy_interface.h @@ -0,0 +1,65 @@ +/* +* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __STRATEGY_INTERFACE_H__ +#define __STRATEGY_INTERFACE_H__ + +#include <core/sdm_types.h> +#include <core/display_interface.h> +#include "hw_info_types.h" + +namespace sdm { + +struct StrategyConstraints { + bool safe_mode = false; //!< In this mode, strategy manager chooses the composition strategy + //!< that requires minimum number of pipe for the current frame. i.e., + //!< video only composition, secure only composition or GPU composition + + bool use_cursor = false; //!< If this is set, strategy manager will configure cursor layer in the + //!< layer stack as hw cursor else it will be treated as a normal layer + + uint32_t max_layers = kMaxSDELayers; //!< Maximum number of layers that shall be programmed + //!< on hardware for the given layer stack. +}; + +class StrategyInterface { + public: + virtual DisplayError Start(HWLayersInfo *hw_layers_info, uint32_t *max_attempts) = 0; + virtual DisplayError GetNextStrategy(StrategyConstraints *constraints) = 0; + virtual DisplayError Stop() = 0; + virtual DisplayError Reconfigure(const HWPanelInfo &hw_panel_info, + const HWResourceInfo &hw_res_info, + const HWMixerAttributes &mixer_attributes, + const DisplayConfigVariableInfo &fb_config) = 0; + virtual DisplayError SetCompositionState(LayerComposition composition_type, bool enable) = 0; + virtual DisplayError Purge() = 0; + virtual DisplayError SetIdleTimeoutMs(uint32_t active_ms) = 0; + + virtual ~StrategyInterface() { } +}; + +} // namespace sdm + +#endif // __STRATEGY_INTERFACE_H__ + diff --git a/msm8909/sdm/include/utils/constants.h b/msm8909/sdm/include/utils/constants.h new file mode 100644 index 00000000..5efe3571 --- /dev/null +++ b/msm8909/sdm/include/utils/constants.h @@ -0,0 +1,84 @@ +/* +* Copyright (c) 2014 - 2017, 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 __CONSTANTS_H__ +#define __CONSTANTS_H__ + +#include <stdlib.h> +#include <inttypes.h> + +#ifndef PRIu64 +#define PRIu64 "llu" +#endif + +#define INT(exp) static_cast<int>(exp) +#define FLOAT(exp) static_cast<float>(exp) +#define UINT8(exp) static_cast<uint8_t>(exp) +#define UINT16(exp) static_cast<uint16_t>(exp) +#define UINT32(exp) static_cast<uint32_t>(exp) +#define INT32(exp) static_cast<int32_t>(exp) +#define UINT64(exp) static_cast<uint64_t>(exp) + +#define ROUND_UP(number, step) ((((number) + ((step) - 1)) / (step)) * (step)) + +#define BITMAP(bit) (1 << (bit)) + +#define ROUND_UP_ALIGN_DOWN(value, a) FLOAT(FloorToMultipleOf(UINT32(value + 0.5f), UINT32(a))) +#define ROUND_UP_ALIGN_UP(value, a) FLOAT(CeilToMultipleOf(UINT32(value + 0.5f), UINT32(a))) + +#define IDLE_TIMEOUT_DEFAULT_MS 70 +#define IDLE_TIMEOUT_ACTIVE_MS IDLE_TIMEOUT_DEFAULT_MS +#define IDLE_TIMEOUT_INACTIVE_MS 520 + +#define IS_RGB_FORMAT(format) (((format) < kFormatYCbCr420Planar) ? true: false) + +#define BITS_PER_BYTE 8 +#define BITS_TO_BYTES(x) (((x) + (BITS_PER_BYTE - 1)) / (BITS_PER_BYTE)) + +// factor value should be in powers of 2(eg: 1, 2, 4, 8) +template <class T1, class T2> +inline T1 FloorToMultipleOf(const T1 &value, const T2 &factor) { + return (T1)(value & (~(factor - 1))); +} + +template <class T1, class T2> +inline T1 CeilToMultipleOf(const T1 &value, const T2 &factor) { + return (T1)((value + (factor - 1)) & (~(factor - 1))); +} + +namespace sdm { + + const int kThreadPriorityUrgent = -9; + const int kMaxRotatePerLayer = 2; + const uint32_t kMaxBlitTargetLayers = 2; + const int kPageSize = 4096; + const uint32_t kGridSize = 129; // size used for non-linear transformation before Tone-mapping + const uint32_t kLutDim = 17; // Dim of the 3d LUT for tone-mapping. + + typedef void * Handle; + +} // namespace sdm + +#endif // __CONSTANTS_H__ + diff --git a/msm8909/sdm/include/utils/debug.h b/msm8909/sdm/include/utils/debug.h new file mode 100644 index 00000000..af23a922 --- /dev/null +++ b/msm8909/sdm/include/utils/debug.h @@ -0,0 +1,121 @@ +/* +* Copyright (c) 2014 - 2018, 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 __DEBUG_H__ +#define __DEBUG_H__ + +#include <stdint.h> +#include <core/sdm_types.h> +#include <core/debug_interface.h> +#include <core/display_interface.h> +#include <display_properties.h> + +#define DLOG(tag, method, format, ...) Debug::Get()->method(tag, __CLASS__ "::%s: " format, \ + __FUNCTION__, ##__VA_ARGS__) + +#define DLOGE_IF(tag, format, ...) DLOG(tag, Error, format, ##__VA_ARGS__) +#define DLOGW_IF(tag, format, ...) DLOG(tag, Warning, format, ##__VA_ARGS__) +#define DLOGI_IF(tag, format, ...) DLOG(tag, Info, format, ##__VA_ARGS__) +#define DLOGD_IF(tag, format, ...) DLOG(tag, Debug, format, ##__VA_ARGS__) +#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__) + +#define DTRACE_BEGIN(custom_string) Debug::Get()->BeginTrace(__CLASS__, __FUNCTION__, custom_string) +#define DTRACE_END() Debug::Get()->EndTrace() +#define DTRACE_SCOPED() ScopeTracer <Debug> scope_tracer(__CLASS__, __FUNCTION__) + +namespace sdm { + +class Debug { + public: + static inline void SetDebugHandler(DebugHandler *debug_handler) { + debug_.debug_handler_ = debug_handler; + } + static inline DebugHandler* Get() { return debug_.debug_handler_; } + static int GetSimulationFlag(); + static int GetHDMIResolution(); + static void GetIdleTimeoutMs(uint32_t *active_ms, uint32_t *inactive_ms); + static int GetBootAnimLayerCount(); + static bool IsRotatorDownScaleDisabled(); + static bool IsDecimationDisabled(); + static int GetMaxPipesPerMixer(DisplayType display_type); + static int GetMaxUpscale(); + static bool IsVideoModeEnabled(); + static bool IsRotatorUbwcDisabled(); + static bool IsRotatorSplitDisabled(); + static bool IsScalarDisabled(); + static bool IsUbwcTiledFrameBuffer(); + static bool IsAVRDisabled(); + static bool IsExtAnimDisabled(); + static bool IsPartialSplitDisabled(); + static DisplayError GetMixerResolution(uint32_t *width, uint32_t *height); + static int GetExtMaxlayers(); + static bool GetProperty(const char *property_name, char *value); + static bool SetProperty(const char *property_name, const char *value); + + private: + Debug(); + + // By default, drop any log messages/traces coming from Display manager. It will be overriden by + // Display manager client when core is successfully initialized. + class DefaultDebugHandler : public DebugHandler { + public: + virtual void Error(DebugTag /*tag*/, const char */*format*/, ...) { } + virtual void Warning(DebugTag /*tag*/, const char */*format*/, ...) { } + virtual void Info(DebugTag /*tag*/, const char */*format*/, ...) { } + virtual void Debug(DebugTag /*tag*/, const char */*format*/, ...) { } + virtual void Verbose(DebugTag /*tag*/, const char */*format*/, ...) { } + virtual void BeginTrace(const char */*class_name*/, const char */*function_name*/, + const char */*custom_string*/) { } + virtual void EndTrace() { } + virtual DisplayError GetProperty(const char */*property_name*/, int */*value*/) { + return kErrorNotSupported; + } + virtual DisplayError GetProperty(const char */*property_name*/, char */*value*/) { + return kErrorNotSupported; + } + virtual DisplayError SetProperty(const char */*property_name*/, const char */*value*/) { + return kErrorNotSupported; + } + }; + + DefaultDebugHandler default_debug_handler_; + DebugHandler *debug_handler_; + static Debug debug_; +}; + +} // namespace sdm + +#endif // __DEBUG_H__ + diff --git a/msm8909/sdm/include/utils/factory.h b/msm8909/sdm/include/utils/factory.h new file mode 100644 index 00000000..f77a2999 --- /dev/null +++ b/msm8909/sdm/include/utils/factory.h @@ -0,0 +1,63 @@ +/* +* Copyright (c) 2017, 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 __FACTORY_H__ +#define __FACTORY_H__ + +#include <utility> +#include <map> +#include <string> + +namespace sdm { + +template <class Creator> +class Factory { + public: + int Add(const std::string &name, const Creator &creator) { + map_.insert(std::pair<std::string, Creator>(name, creator)); + + return 0; + } + + Creator Get(const std::string &name) { + typename std::map<std::string, Creator>::iterator it = map_.find(name); + if (it != map_.end()) { + return it->second; + } + + return nullptr; + } + + private: + std::map<std::string, Creator> map_; +}; + +} // namespace sdm + +#endif // __FACTORY_H__ diff --git a/msm8909/libqdutils/cb_swap_rect.h b/msm8909/sdm/include/utils/formats.h index daaeb37f..dd819dcd 100644 --- a/msm8909/libqdutils/cb_swap_rect.h +++ b/msm8909/sdm/include/utils/formats.h @@ -1,9 +1,11 @@ -/* Copyright (c) 2014, The Linux Foundation. All rights reserved. +/* +* 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 +* modification, are permitted provided that the following conditions are * met: -* * Redistributions of source code must retain the above copyrigh -* notice, this list of conditions and the following disclaimer +* * 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 @@ -20,32 +22,24 @@ * 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 +* 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 __FORMATS_H__ +#define __FORMATS_H__ + +#include <core/layer_stack.h> + +namespace sdm { -#ifndef CB_SWAP_RECT -#define CB_SWAP_RECT +bool IsUBWCFormat(LayerBufferFormat format); +bool Is10BitFormat(LayerBufferFormat format); +const char *GetFormatString(const LayerBufferFormat &format); +BufferLayout GetBufferLayout(LayerBufferFormat format); -#include <stdint.h> -#include <utils/Singleton.h> -#include <cutils/log.h> +} // namespace sdm -using namespace android; -namespace qdutils { -enum { -HWC_SKIP_HWC_COMPOSITION = 0x00040000, -}; +#endif // __FORMATS_H__ -class cb_swap_rect : public Singleton <cb_swap_rect> -{ - bool swap_rect_feature_on; - public : - cb_swap_rect(); - void setSwapRectFeature_on( bool value); - bool checkSwapRectFeature_on(); -}; -} // namespace qdutils -#endif diff --git a/msm8909/sdm/include/utils/locker.h b/msm8909/sdm/include/utils/locker.h new file mode 100644 index 00000000..0096098d --- /dev/null +++ b/msm8909/sdm/include/utils/locker.h @@ -0,0 +1,166 @@ +/* +* 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 __LOCKER_H__ +#define __LOCKER_H__ + +#include <stdint.h> +#include <pthread.h> +#include <sys/time.h> + +#define SCOPE_LOCK(locker) Locker::ScopeLock lock(locker) +#define SEQUENCE_ENTRY_SCOPE_LOCK(locker) Locker::SequenceEntryScopeLock lock(locker) +#define SEQUENCE_EXIT_SCOPE_LOCK(locker) Locker::SequenceExitScopeLock lock(locker) +#define SEQUENCE_WAIT_SCOPE_LOCK(locker) Locker::SequenceWaitScopeLock lock(locker) +#define SEQUENCE_CANCEL_SCOPE_LOCK(locker) Locker::SequenceCancelScopeLock lock(locker) + +namespace sdm { + +class Locker { + public: + class ScopeLock { + public: + explicit ScopeLock(Locker& locker) : locker_(locker) { + locker_.Lock(); + } + + ~ScopeLock() { + locker_.Unlock(); + } + + private: + Locker &locker_; + }; + + class SequenceEntryScopeLock { + public: + explicit SequenceEntryScopeLock(Locker& locker) : locker_(locker) { + locker_.Lock(); + locker_.sequence_wait_ = 1; + } + + ~SequenceEntryScopeLock() { + locker_.Unlock(); + } + + private: + Locker &locker_; + }; + + class SequenceExitScopeLock { + public: + explicit SequenceExitScopeLock(Locker& locker) : locker_(locker) { + locker_.Lock(); + locker_.sequence_wait_ = 0; + } + + ~SequenceExitScopeLock() { + locker_.Broadcast(); + locker_.Unlock(); + } + + private: + Locker &locker_; + }; + + class SequenceWaitScopeLock { + public: + explicit SequenceWaitScopeLock(Locker& locker) : locker_(locker), error_(false) { + locker_.Lock(); + + while (locker_.sequence_wait_ == 1) { + locker_.Wait(); + error_ = (locker_.sequence_wait_ == -1); + } + } + + ~SequenceWaitScopeLock() { + locker_.Unlock(); + } + + bool IsError() { + return error_; + } + + private: + Locker &locker_; + bool error_; + }; + + class SequenceCancelScopeLock { + public: + explicit SequenceCancelScopeLock(Locker& locker) : locker_(locker) { + locker_.Lock(); + locker_.sequence_wait_ = -1; + } + + ~SequenceCancelScopeLock() { + locker_.Broadcast(); + locker_.Unlock(); + } + + private: + Locker &locker_; + }; + + Locker() : sequence_wait_(0) { + pthread_mutex_init(&mutex_, 0); + pthread_cond_init(&condition_, 0); + } + + ~Locker() { + pthread_mutex_destroy(&mutex_); + pthread_cond_destroy(&condition_); + } + + void Lock() { pthread_mutex_lock(&mutex_); } + void Unlock() { pthread_mutex_unlock(&mutex_); } + void Signal() { pthread_cond_signal(&condition_); } + void Broadcast() { pthread_cond_broadcast(&condition_); } + void Wait() { pthread_cond_wait(&condition_, &mutex_); } + int WaitFinite(int ms) { + struct timespec ts; + struct timeval tv; + gettimeofday(&tv, NULL); + ts.tv_sec = tv.tv_sec + ms/1000; + ts.tv_nsec = tv.tv_usec*1000 + (ms%1000)*1000000; + ts.tv_sec += ts.tv_nsec/1000000000L; + ts.tv_nsec %= 1000000000L; + return pthread_cond_timedwait(&condition_, &mutex_, &ts); + } + + private: + pthread_mutex_t mutex_; + pthread_cond_t condition_; + int sequence_wait_; // This flag is set to 1 on sequence entry, 0 on exit, and -1 on cancel. + // Some routines will wait for sequence of function calls to finish + // so that capturing a transitionary snapshot of context is prevented. + // If flag is set to -1, these routines will exit without doing any + // further processing. +}; + +} // namespace sdm + +#endif // __LOCKER_H__ + diff --git a/msm8909/sdm/include/utils/rect.h b/msm8909/sdm/include/utils/rect.h new file mode 100644 index 00000000..00273e17 --- /dev/null +++ b/msm8909/sdm/include/utils/rect.h @@ -0,0 +1,67 @@ +/* +* Copyright (c) 2015-2017, 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 __RECT_H__ +#define __RECT_H__ + +#include <stdint.h> +#include <core/sdm_types.h> +#include <core/layer_stack.h> +#include <utils/debug.h> + +namespace sdm { + + enum RectOrientation { + kOrientationPortrait, + kOrientationLandscape, + kOrientationUnknown, + }; + + bool IsValid(const LayerRect &rect); + bool IsCongruent(const LayerRect &rect1, const LayerRect &rect2); + void LogI(DebugTag debug_tag, const char *prefix, const LayerRect &roi); + void Log(DebugTag debug_tag, const char *prefix, const LayerRect &roi); + void Normalize(const uint32_t &align_x, const uint32_t &align_y, LayerRect *rect); + LayerRect Union(const LayerRect &rect1, const LayerRect &rect2); + LayerRect Intersection(const LayerRect &rect1, const LayerRect &rect2); + LayerRect Subtract(const LayerRect &rect1, const LayerRect &rect2); + LayerRect Reposition(const LayerRect &rect1, const int &x_offset, const int &y_offset); + void SplitLeftRight(const LayerRect &in_rect, uint32_t split_count, uint32_t align_x, + bool flip_horizontal, LayerRect *out_rects); + void SplitTopBottom(const LayerRect &in_rect, uint32_t split_count, uint32_t align_y, + bool flip_horizontal, LayerRect *out_rects); + void MapRect(const LayerRect &src_domain, const LayerRect &dst_domain, const LayerRect &in_rect, + LayerRect *out_rect); + void TransformHV(const LayerRect &src_domain, const LayerRect &in_rect, + const LayerTransform &transform, LayerRect *out_rect); + RectOrientation GetOrientation(const LayerRect &in_rect); +} // namespace sdm + +#endif // __RECT_H__ + diff --git a/msm8909/sdm/include/utils/sync_task.h b/msm8909/sdm/include/utils/sync_task.h new file mode 100644 index 00000000..725460a1 --- /dev/null +++ b/msm8909/sdm/include/utils/sync_task.h @@ -0,0 +1,143 @@ +/* +* Copyright (c) 2017, 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 __SYNC_TASK_H__ +#define __SYNC_TASK_H__ + +#include <thread> +#include <mutex> +#include <condition_variable> // NOLINT + +namespace sdm { + +template <class TaskCode> +class SyncTask { + public: + // This class need to be overridden by caller to pass on a task context. + class TaskContext { + public: + virtual ~TaskContext() { } + }; + + // Methods to callback into caller for command codes executions in worker thread. + class TaskHandler { + public: + virtual ~TaskHandler() { } + virtual void OnTask(const TaskCode &task_code, TaskContext *task_context) = 0; + }; + + explicit SyncTask(TaskHandler &task_handler) : task_handler_(task_handler) { + // Block caller thread until worker thread has started and ready to listen to task commands. + // Worker thread will signal as soon as callback is received in the new thread. + std::unique_lock<std::mutex> caller_lock(caller_mutex_); + std::thread worker_thread(SyncTaskThread, this); + worker_thread_.swap(worker_thread); + caller_cv_.wait(caller_lock); + } + + ~SyncTask() { + // Task code does not matter here. + PerformTask(task_code_, nullptr, true); + worker_thread_.join(); + } + + void PerformTask(const TaskCode &task_code, TaskContext *task_context) { + PerformTask(task_code, task_context, false); + } + + private: + void PerformTask(const TaskCode &task_code, TaskContext *task_context, bool terminate) { + std::unique_lock<std::mutex> caller_lock(caller_mutex_); + + // New scope to limit scope of worker lock to this block. + { + // Set task command code and notify worker thread. + std::unique_lock<std::mutex> worker_lock(worker_mutex_); + task_code_ = task_code; + task_context_ = task_context; + worker_thread_exit_ = terminate; + pending_code_ = true; + worker_cv_.notify_one(); + } + + // Wait for worker thread to finish and signal. + caller_cv_.wait(caller_lock); + } + + static void SyncTaskThread(SyncTask *sync_task) { + if (sync_task) { + sync_task->OnThreadCallback(); + } + } + + void OnThreadCallback() { + // Acquire worker lock and start waiting for events. + // Wait must start before caller thread can post events, otherwise posted events will be lost. + // Caller thread will be blocked until worker thread signals readiness. + std::unique_lock<std::mutex> worker_lock(worker_mutex_); + + // New scope to limit scope of caller lock to this block. + { + // Signal caller thread that worker thread is ready to listen to events. + std::unique_lock<std::mutex> caller_lock(caller_mutex_); + caller_cv_.notify_one(); + } + + while (!worker_thread_exit_) { + // Add predicate to handle spurious interrupts. + // Wait for caller thread to signal new command codes. + worker_cv_.wait(worker_lock, [this] { return pending_code_; }); + + // Call task handler which is implemented by the caller. + if (!worker_thread_exit_) { + task_handler_.OnTask(task_code_, task_context_); + } + + pending_code_ = false; + // Notify completion of current task to the caller thread which is blocked. + std::unique_lock<std::mutex> caller_lock(caller_mutex_); + caller_cv_.notify_one(); + } + } + + TaskHandler &task_handler_; + TaskCode task_code_; + TaskContext *task_context_ = nullptr; + std::thread worker_thread_; + std::mutex caller_mutex_; + std::mutex worker_mutex_; + std::condition_variable caller_cv_; + std::condition_variable worker_cv_; + bool worker_thread_exit_ = false; + bool pending_code_ = false; +}; + +} // namespace sdm + +#endif // __SYNC_TASK_H__ diff --git a/msm8909/sdm/include/utils/sys.h b/msm8909/sdm/include/utils/sys.h new file mode 100644 index 00000000..6b40df45 --- /dev/null +++ b/msm8909/sdm/include/utils/sys.h @@ -0,0 +1,101 @@ +/* +* Copyright (c) 2015, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __SYS_H__ +#define __SYS_H__ + +#include <sys/eventfd.h> +#include <dlfcn.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <poll.h> +#include <pthread.h> +#include <fstream> + +#ifdef SDM_VIRTUAL_DRIVER +#include <virtual_driver.h> +#endif + +namespace sdm { + +class Sys { + public: +#ifndef SDM_VIRTUAL_DRIVER + typedef std::fstream fstream; +#else + typedef VirtualFStream fstream; +#endif + + // Pointers to system calls which are either mapped to actual system call or virtual driver. +#ifdef TARGET_HEADLESS + typedef int (*ioctl)(int, unsigned long int, ...); // NOLINT +#else + typedef int (*ioctl)(int, int, ...); +#endif + typedef int (*access)(const char *, int); + typedef int (*open)(const char *, int, ...); + typedef int (*close)(int); + typedef int (*poll)(struct pollfd *, nfds_t, int); + typedef ssize_t (*pread)(int, void *, size_t, off_t); + typedef ssize_t (*pwrite)(int, const void *, size_t, off_t); + typedef int (*pthread_cancel)(pthread_t thread); + typedef int (*dup)(int fd); + typedef ssize_t (*read)(int, void *, size_t); + typedef ssize_t (*write)(int, const void *, size_t); + typedef int (*eventfd)(unsigned int, int); + + static bool getline_(fstream &fs, std::string &line); // NOLINT + + static ioctl ioctl_; + static access access_; + static open open_; + static close close_; + static poll poll_; + static pread pread_; + static pwrite pwrite_; + static pthread_cancel pthread_cancel_; + static dup dup_; + static read read_; + static write write_; + static eventfd eventfd_; +}; + +class DynLib { + public: + ~DynLib(); + bool Open(const char *lib_name); + bool Sym(const char *func_name, void **func_ptr); + const char * Error() { return ::dlerror(); } + operator bool() const { return lib_ != NULL; } + + private: + void Close(); + + void *lib_ = NULL; +}; + +} // namespace sdm + +#endif // __SYS_H__ diff --git a/msm8909/libqdutils/cb_utils.h b/msm8909/sdm/include/utils/utils.h index 8d26b8e5..b1c55c41 100644 --- a/msm8909/libqdutils/cb_utils.h +++ b/msm8909/sdm/include/utils/utils.h @@ -1,9 +1,11 @@ -/* Copyright (c) 2013, The Linux Foundation. All rights reserved. +/* +* Copyright (c) 2016 - 2017, 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 +* modification, are permitted provided that the following conditions are * met: -* * Redistributions of source code must retain the above copyrigh -* notice, this list of conditions and the following disclaimer +* * 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 @@ -20,26 +22,28 @@ * 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 +* 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 __UTILS_H__ +#define __UTILS_H__ -#ifndef CB_UTIL_H -#define CB_UTIL_H +namespace sdm { -#include "hwc_utils.h" -#include "copybit.h" +float gcd(float a, float b); +float lcm(float a, float b); +void CloseFd(int *fd); -using namespace qhwc; -namespace qdutils { -class CBUtils { -public: - static int uiClearRegion(hwc_display_contents_1_t* list, - int version, LayerProp *layerProp, hwc_rect_t dirtyIndex, - copybit_device_t *copybit, private_handle_t *renderBuffer); +enum class DriverType { + FB = 0, + DRM, }; -}//namespace qdutils -#endif /* end of include guard: CB_UTIL_H*/ + +DriverType GetDriverType(); + +} // namespace sdm + +#endif // __UTILS_H__ diff --git a/msm8909/sdm/libs/core/Android.mk b/msm8909/sdm/libs/core/Android.mk new file mode 100644 index 00000000..7aab09c6 --- /dev/null +++ b/msm8909/sdm/libs/core/Android.mk @@ -0,0 +1,82 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +include $(LOCAL_PATH)/../../../common.mk + +LOCAL_MODULE := libsdmcore +LOCAL_VENDOR_MODULE := true +LOCAL_MODULE_TAGS := optional +LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes) +LOCAL_HEADER_LIBRARIES := display_headers +LOCAL_CFLAGS := -Wno-unused-parameter -DLOG_TAG=\"SDM\" \ + $(common_flags) +LOCAL_HW_INTF_PATH_1 := fb +LOCAL_SHARED_LIBRARIES := libdl libsdmutils + +ifneq ($(TARGET_IS_HEADLESS), true) + LOCAL_CFLAGS += -DCOMPILE_DRM -isystem external/libdrm + LOCAL_SHARED_LIBRARIES += libdrm libdrmutils + LOCAL_HW_INTF_PATH_2 := drm +endif + +ifeq ($(TARGET_USES_DRM_PP),true) + LOCAL_CFLAGS += -DPP_DRM_ENABLE +endif + +LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps) +LOCAL_SRC_FILES := core_interface.cpp \ + core_impl.cpp \ + display_base.cpp \ + display_primary.cpp \ + display_hdmi.cpp \ + display_virtual.cpp \ + comp_manager.cpp \ + strategy.cpp \ + resource_default.cpp \ + color_manager.cpp \ + hw_events_interface.cpp \ + hw_info_interface.cpp \ + hw_interface.cpp \ + $(LOCAL_HW_INTF_PATH_1)/hw_info.cpp \ + $(LOCAL_HW_INTF_PATH_1)/hw_device.cpp \ + $(LOCAL_HW_INTF_PATH_1)/hw_primary.cpp \ + $(LOCAL_HW_INTF_PATH_1)/hw_hdmi.cpp \ + $(LOCAL_HW_INTF_PATH_1)/hw_virtual.cpp \ + $(LOCAL_HW_INTF_PATH_1)/hw_color_manager.cpp \ + $(LOCAL_HW_INTF_PATH_1)/hw_scale.cpp \ + $(LOCAL_HW_INTF_PATH_1)/hw_events.cpp + +ifneq ($(TARGET_IS_HEADLESS), true) + LOCAL_SRC_FILES += $(LOCAL_HW_INTF_PATH_2)/hw_info_drm.cpp \ + $(LOCAL_HW_INTF_PATH_2)/hw_device_drm.cpp \ + $(LOCAL_HW_INTF_PATH_2)/hw_events_drm.cpp \ + $(LOCAL_HW_INTF_PATH_2)/hw_scale_drm.cpp \ + $(LOCAL_HW_INTF_PATH_2)/hw_color_manager_drm.cpp +endif + +include $(BUILD_SHARED_LIBRARY) + +SDM_HEADER_PATH := ../../include +include $(CLEAR_VARS) +LOCAL_COPY_HEADERS_TO := $(common_header_export_path)/sdm/core +LOCAL_COPY_HEADERS = $(SDM_HEADER_PATH)/core/buffer_allocator.h \ + $(SDM_HEADER_PATH)/core/buffer_sync_handler.h \ + $(SDM_HEADER_PATH)/core/core_interface.h \ + $(SDM_HEADER_PATH)/core/debug_interface.h \ + $(SDM_HEADER_PATH)/core/display_interface.h \ + $(SDM_HEADER_PATH)/core/layer_buffer.h \ + $(SDM_HEADER_PATH)/core/layer_stack.h \ + $(SDM_HEADER_PATH)/core/sdm_types.h \ + $(SDM_HEADER_PATH)/core/socket_handler.h +include $(BUILD_COPY_HEADERS) + +include $(CLEAR_VARS) +LOCAL_COPY_HEADERS_TO := $(common_header_export_path)/sdm/private +LOCAL_COPY_HEADERS = $(SDM_HEADER_PATH)/private/color_interface.h \ + $(SDM_HEADER_PATH)/private/color_params.h \ + $(SDM_HEADER_PATH)/private/extension_interface.h \ + $(SDM_HEADER_PATH)/private/hw_info_types.h \ + $(SDM_HEADER_PATH)/private/partial_update_interface.h \ + $(SDM_HEADER_PATH)/private/resource_interface.h \ + $(SDM_HEADER_PATH)/private/strategy_interface.h \ + $(SDM_HEADER_PATH)/private/dpps_control_interface.h +include $(BUILD_COPY_HEADERS) diff --git a/msm8909/sdm/libs/core/Makefile.am b/msm8909/sdm/libs/core/Makefile.am new file mode 100644 index 00000000..2b45d8e3 --- /dev/null +++ b/msm8909/sdm/libs/core/Makefile.am @@ -0,0 +1,47 @@ +HEADER_PATH := ${WORKSPACE}/display/display-hal/sdm/include + +c_sources = core_interface.cpp \ + core_impl.cpp \ + display_base.cpp \ + display_primary.cpp \ + display_hdmi.cpp \ + display_virtual.cpp \ + comp_manager.cpp \ + strategy.cpp \ + resource_default.cpp \ + dump_impl.cpp \ + color_manager.cpp \ + hw_interface.cpp \ + hw_info_interface.cpp \ + hw_events_interface.cpp \ + fb/hw_info.cpp \ + fb/hw_device.cpp \ + fb/hw_primary.cpp \ + fb/hw_hdmi.cpp \ + fb/hw_virtual.cpp \ + fb/hw_color_manager.cpp \ + fb/hw_scale.cpp \ + fb/hw_events.cpp + +core_h_sources = $(HEADER_PATH)/core/*.h + +core_includedir = $(includedir)/sdm/core +core_include_HEADERS = $(core_h_sources) + +private_h_sources = $(HEADER_PATH)/private/*.h + +private_includedir = $(includedir)/sdm/private +private_include_HEADERS = $(private_h_sources) + +utils_h_sources = $(HEADER_PATH)/utils/*.h + +utils_includedir = $(includedir)/sdm/utils +utils_include_HEADERS = $(utils_h_sources) + +lib_LTLIBRARIES = libsdmcore.la +libsdmcore_la_CC = @CC@ +libsdmcore_la_SOURCES = $(c_sources) +libsdmcore_la_CFLAGS = $(COMMON_CFLAGS) -DLOG_TAG=\"SDM\" +libsdmcore_la_CPPFLAGS = $(AM_CPPFLAGS) +libsdmcore_la_LIBADD = ../utils/libsdmutils.la +libsdmcore_la_LDFLAGS = -shared -avoid-version diff --git a/msm8909/sdm/libs/core/color_manager.cpp b/msm8909/sdm/libs/core/color_manager.cpp new file mode 100644 index 00000000..938ab991 --- /dev/null +++ b/msm8909/sdm/libs/core/color_manager.cpp @@ -0,0 +1,243 @@ +/* Copyright (c) 2015 - 2017, The Linux Foundataion. 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 <private/color_interface.h> +#include <utils/constants.h> +#include <utils/debug.h> +#include "color_manager.h" + +#define __CLASS__ "ColorManager" + +namespace sdm { + +DynLib ColorManagerProxy::color_lib_; +CreateColorInterface ColorManagerProxy::create_intf_ = NULL; +DestroyColorInterface ColorManagerProxy::destroy_intf_ = NULL; +HWResourceInfo ColorManagerProxy::hw_res_info_; + +// Below two functions are part of concrete implementation for SDM core private +// color_params.h +void PPFeaturesConfig::Reset() { + for (int i = 0; i < kMaxNumPPFeatures; i++) { + if (feature_[i]) { + delete feature_[i]; + feature_[i] = NULL; + } + } + dirty_ = false; + next_idx_ = 0; +} + +DisplayError PPFeaturesConfig::RetrieveNextFeature(PPFeatureInfo **feature) { + DisplayError ret = kErrorNone; + uint32_t i(0); + + for (i = next_idx_; i < kMaxNumPPFeatures; i++) { + if (feature_[i]) { + *feature = feature_[i]; + next_idx_ = i + 1; + break; + } + } + + if (i == kMaxNumPPFeatures) { + ret = kErrorParameters; + next_idx_ = 0; + } + + return ret; +} + +DisplayError ColorManagerProxy::Init(const HWResourceInfo &hw_res_info) { + DisplayError error = kErrorNone; + + // Load color service library and retrieve its entry points. + if (color_lib_.Open(COLORMGR_LIBRARY_NAME)) { + if (!color_lib_.Sym(CREATE_COLOR_INTERFACE_NAME, reinterpret_cast<void **>(&create_intf_)) || + !color_lib_.Sym(DESTROY_COLOR_INTERFACE_NAME, reinterpret_cast<void **>(&destroy_intf_))) { + DLOGW("Fail to retrieve = %s from %s", CREATE_COLOR_INTERFACE_NAME, COLORMGR_LIBRARY_NAME); + error = kErrorResources; + } + } else { + DLOGW("Fail to load = %s", COLORMGR_LIBRARY_NAME); + error = kErrorResources; + } + + hw_res_info_ = hw_res_info; + + return error; +} + +void ColorManagerProxy::Deinit() { + color_lib_.~DynLib(); +} + +ColorManagerProxy::ColorManagerProxy(DisplayType type, HWInterface *intf, + const HWDisplayAttributes &attr, + const HWPanelInfo &info) + : device_type_(type), pp_hw_attributes_(), hw_intf_(intf), color_intf_(NULL), pp_features_() {} + +ColorManagerProxy *ColorManagerProxy::CreateColorManagerProxy(DisplayType type, + HWInterface *hw_intf, + const HWDisplayAttributes &attribute, + const HWPanelInfo &panel_info) { + DisplayError error = kErrorNone; + PPFeatureVersion versions; + + // check if all resources are available before invoking factory method from libsdm-color.so. + if (!color_lib_ || !create_intf_ || !destroy_intf_) { + DLOGW("Information for %s isn't available!", COLORMGR_LIBRARY_NAME); + return NULL; + } + + ColorManagerProxy *color_manager_proxy = + new ColorManagerProxy(type, hw_intf, attribute, panel_info); + if (color_manager_proxy) { + // 1. need query post-processing feature version from HWInterface. + error = color_manager_proxy->hw_intf_->GetPPFeaturesVersion(&versions); + PPHWAttributes &hw_attr = color_manager_proxy->pp_hw_attributes_; + if (error != kErrorNone) { + DLOGW("Fail to get DSPP feature versions"); + } else { + hw_attr.Set(hw_res_info_, panel_info, attribute, versions); + DLOGW("PAV2 version is versions = %d, version = %d ", + hw_attr.version.version[kGlobalColorFeaturePaV2], + versions.version[kGlobalColorFeaturePaV2]); + } + + // 2. instantiate concrete ColorInterface from libsdm-color.so, pass all hardware info in. + error = create_intf_(COLOR_VERSION_TAG, color_manager_proxy->device_type_, hw_attr, + &color_manager_proxy->color_intf_); + if (error != kErrorNone) { + DLOGW("Unable to instantiate concrete ColorInterface from %s", COLORMGR_LIBRARY_NAME); + delete color_manager_proxy; + color_manager_proxy = NULL; + } + } + + return color_manager_proxy; +} + +ColorManagerProxy::~ColorManagerProxy() { + if (destroy_intf_) + destroy_intf_(device_type_); + color_intf_ = NULL; +} + +DisplayError ColorManagerProxy::ColorSVCRequestRoute(const PPDisplayAPIPayload &in_payload, + PPDisplayAPIPayload *out_payload, + PPPendingParams *pending_action) { + DisplayError ret = kErrorNone; + + // On completion, dspp_features_ will be populated and mark dirty with all resolved dspp + // feature list with paramaters being transformed into target requirement. + ret = color_intf_->ColorSVCRequestRoute(in_payload, out_payload, &pp_features_, pending_action); + + return ret; +} + +DisplayError ColorManagerProxy::ApplyDefaultDisplayMode(void) { + DisplayError ret = kErrorNone; + + // On POR, will be invoked from prepare<> request once bootanimation is done. + ret = color_intf_->ApplyDefaultDisplayMode(&pp_features_); + + return ret; +} + +bool ColorManagerProxy::NeedsPartialUpdateDisable() { + Locker &locker(pp_features_.GetLocker()); + SCOPE_LOCK(locker); + + return pp_features_.IsDirty(); +} + +DisplayError ColorManagerProxy::Commit() { + Locker &locker(pp_features_.GetLocker()); + SCOPE_LOCK(locker); + + DisplayError ret = kErrorNone; + if (pp_features_.IsDirty()) { + ret = hw_intf_->SetPPFeatures(&pp_features_); + } + + return ret; +} + +void PPHWAttributes::Set(const HWResourceInfo &hw_res, + const HWPanelInfo &panel_info, + const DisplayConfigVariableInfo &attr, + const PPFeatureVersion &feature_ver) { + HWResourceInfo &res = *this; + res = hw_res; + HWPanelInfo &panel = *this; + panel = panel_info; + DisplayConfigVariableInfo &attributes = *this; + attributes = attr; + version = feature_ver; + panel_max_brightness = panel_info.panel_max_brightness; + + if (strlen(panel_info.panel_name)) { + snprintf(&panel_name[0], sizeof(panel_name), "%s", &panel_info.panel_name[0]); + char *tmp = panel_name; + while ((tmp = strstr(tmp, " ")) != NULL) + *tmp = '_'; + if ((tmp = strstr(panel_name, "\n")) != NULL) + *tmp = '\0'; + } +} + +DisplayError ColorManagerProxy::ColorMgrGetNumOfModes(uint32_t *mode_cnt) { + return color_intf_->ColorIntfGetNumDisplayModes(&pp_features_, 0, mode_cnt); +} + +DisplayError ColorManagerProxy::ColorMgrGetModes(uint32_t *mode_cnt, + SDEDisplayMode *modes) { + return color_intf_->ColorIntfEnumerateDisplayModes(&pp_features_, 0, modes, mode_cnt); +} + +DisplayError ColorManagerProxy::ColorMgrSetMode(int32_t color_mode_id) { + return color_intf_->ColorIntfSetDisplayMode(&pp_features_, 0, color_mode_id); +} + +DisplayError ColorManagerProxy::ColorMgrGetModeInfo(int32_t mode_id, AttrVal *query) { + return color_intf_->ColorIntfGetModeInfo(&pp_features_, 0, mode_id, query); +} + +DisplayError ColorManagerProxy::ColorMgrSetColorTransform(uint32_t length, + const double *trans_data) { + return color_intf_->ColorIntfSetColorTransform(&pp_features_, 0, length, trans_data); +} + +DisplayError ColorManagerProxy::ColorMgrGetDefaultModeID(int32_t *mode_id) { + return color_intf_->ColorIntfGetDefaultModeID(&pp_features_, 0, mode_id); +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/core/color_manager.h b/msm8909/sdm/libs/core/color_manager.h new file mode 100644 index 00000000..db050afd --- /dev/null +++ b/msm8909/sdm/libs/core/color_manager.h @@ -0,0 +1,98 @@ +/* Copyright (c) 2015-2017, The Linux Foundataion. 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 __COLOR_MANAGER_H__ +#define __COLOR_MANAGER_H__ + +#include <stdlib.h> +#include <core/sdm_types.h> +#include <utils/locker.h> +#include <private/color_interface.h> +#include <utils/sys.h> +#include <utils/debug.h> +#include "hw_interface.h" + +namespace sdm { + +/* + * ColorManager proxy to maintain necessary information to interact with underlying color service. + * Each display object has its own proxy. + */ +class ColorManagerProxy { + public: + static DisplayError Init(const HWResourceInfo &hw_res_info); + static void Deinit(); + + /* Create ColorManagerProxy for this display object, following things need to be happening + * 1. Instantiates concrete ColorInerface implementation. + * 2. Pass all display object specific informations into it. + * 3. Populate necessary resources. + * 4. Need get panel name for hw_panel_info_. + */ + static ColorManagerProxy *CreateColorManagerProxy(DisplayType type, HWInterface *hw_intf, + const HWDisplayAttributes &attribute, + const HWPanelInfo &panel_info); + + /* need reverse the effect of CreateColorManagerProxy. */ + ~ColorManagerProxy(); + + DisplayError ColorSVCRequestRoute(const PPDisplayAPIPayload &in_payload, + PPDisplayAPIPayload *out_payload, + PPPendingParams *pending_action); + DisplayError ApplyDefaultDisplayMode(); + DisplayError ColorMgrGetNumOfModes(uint32_t *mode_cnt); + DisplayError ColorMgrGetModes(uint32_t *mode_cnt, SDEDisplayMode *modes); + DisplayError ColorMgrSetMode(int32_t color_mode_id); + DisplayError ColorMgrGetModeInfo(int32_t mode_id, AttrVal *query); + DisplayError ColorMgrSetColorTransform(uint32_t length, const double *trans_data); + DisplayError ColorMgrGetDefaultModeID(int32_t *mode_id); + bool NeedsPartialUpdateDisable(); + DisplayError Commit(); + + protected: + ColorManagerProxy() {} + ColorManagerProxy(DisplayType type, HWInterface *intf, const HWDisplayAttributes &attr, + const HWPanelInfo &info); + + private: + static DynLib color_lib_; + static CreateColorInterface create_intf_; + static DestroyColorInterface destroy_intf_; + static HWResourceInfo hw_res_info_; + + DisplayType device_type_; + PPHWAttributes pp_hw_attributes_; + HWInterface *hw_intf_; + ColorInterface *color_intf_; + PPFeaturesConfig pp_features_; +}; + +} // namespace sdm + +#endif // __COLOR_MANAGER_H__ diff --git a/msm8909/sdm/libs/core/comp_manager.cpp b/msm8909/sdm/libs/core/comp_manager.cpp new file mode 100644 index 00000000..5488e460 --- /dev/null +++ b/msm8909/sdm/libs/core/comp_manager.cpp @@ -0,0 +1,605 @@ +/* +* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <utils/constants.h> +#include <utils/debug.h> +#include <core/buffer_allocator.h> + +#include "comp_manager.h" +#include "strategy.h" + +#define __CLASS__ "CompManager" + +namespace sdm { + +static bool NeedsScaledComposition(const DisplayConfigVariableInfo &fb_config, + const HWMixerAttributes &mixer_attributes) { + return ((fb_config.x_pixels != mixer_attributes.width) || + (fb_config.y_pixels != mixer_attributes.height)); +} + +DisplayError CompManager::Init(const HWResourceInfo &hw_res_info, + ExtensionInterface *extension_intf, + BufferAllocator *buffer_allocator, + BufferSyncHandler *buffer_sync_handler, + SocketHandler *socket_handler) { + SCOPE_LOCK(locker_); + + DisplayError error = kErrorNone; + + if (extension_intf) { + error = extension_intf->CreateResourceExtn(hw_res_info, buffer_allocator, buffer_sync_handler, + &resource_intf_); + extension_intf->CreateDppsControlExtn(&dpps_ctrl_intf_, socket_handler); + } else { + error = ResourceDefault::CreateResourceDefault(hw_res_info, &resource_intf_); + } + + if (error != kErrorNone) { + if (extension_intf) { + extension_intf->DestroyDppsControlExtn(dpps_ctrl_intf_); + } + return error; + } + + hw_res_info_ = hw_res_info; + buffer_allocator_ = buffer_allocator; + extension_intf_ = extension_intf; + + return error; +} + +DisplayError CompManager::Deinit() { + SCOPE_LOCK(locker_); + + if (extension_intf_) { + extension_intf_->DestroyResourceExtn(resource_intf_); + extension_intf_->DestroyDppsControlExtn(dpps_ctrl_intf_); + } else { + ResourceDefault::DestroyResourceDefault(resource_intf_); + } + + return kErrorNone; +} + +DisplayError CompManager::RegisterDisplay(DisplayType type, + const HWDisplayAttributes &display_attributes, + const HWPanelInfo &hw_panel_info, + const HWMixerAttributes &mixer_attributes, + const DisplayConfigVariableInfo &fb_config, + Handle *display_ctx) { + SCOPE_LOCK(locker_); + + DisplayError error = kErrorNone; + + DisplayCompositionContext *display_comp_ctx = new DisplayCompositionContext(); + if (!display_comp_ctx) { + return kErrorMemory; + } + + Strategy *&strategy = display_comp_ctx->strategy; + strategy = new Strategy(extension_intf_, buffer_allocator_, type, hw_res_info_, hw_panel_info, + mixer_attributes, display_attributes, fb_config); + if (!strategy) { + DLOGE("Unable to create strategy"); + delete display_comp_ctx; + return kErrorMemory; + } + + error = strategy->Init(); + if (error != kErrorNone) { + delete strategy; + delete display_comp_ctx; + return error; + } + + error = resource_intf_->RegisterDisplay(type, display_attributes, hw_panel_info, mixer_attributes, + &display_comp_ctx->display_resource_ctx); + if (error != kErrorNone) { + strategy->Deinit(); + delete strategy; + delete display_comp_ctx; + display_comp_ctx = NULL; + return error; + } + + registered_displays_[type] = 1; + display_comp_ctx->is_primary_panel = hw_panel_info.is_primary_panel; + display_comp_ctx->display_type = type; + display_comp_ctx->fb_config = fb_config; + *display_ctx = display_comp_ctx; + // New non-primary display device has been added, so move the composition mode to safe mode until + // resources for the added display is configured properly. + if (!display_comp_ctx->is_primary_panel) { + safe_mode_ = true; + max_sde_ext_layers_ = UINT32(Debug::GetExtMaxlayers()); + } + + display_comp_ctx->scaled_composition = NeedsScaledComposition(fb_config, mixer_attributes); + DLOGV_IF(kTagCompManager, "registered display bit mask 0x%x, configured display bit mask 0x%x, " \ + "display type %d", registered_displays_.to_ulong(), configured_displays_.to_ulong(), + display_comp_ctx->display_type); + + return kErrorNone; +} + +DisplayError CompManager::UnregisterDisplay(Handle display_ctx) { + SCOPE_LOCK(locker_); + + DisplayCompositionContext *display_comp_ctx = + reinterpret_cast<DisplayCompositionContext *>(display_ctx); + + if (!display_comp_ctx) { + return kErrorParameters; + } + + resource_intf_->UnregisterDisplay(display_comp_ctx->display_resource_ctx); + + Strategy *&strategy = display_comp_ctx->strategy; + strategy->Deinit(); + delete strategy; + + registered_displays_[display_comp_ctx->display_type] = 0; + configured_displays_[display_comp_ctx->display_type] = 0; + + if (display_comp_ctx->display_type == kHDMI) { + max_layers_ = kMaxSDELayers; + } + + DLOGV_IF(kTagCompManager, "registered display bit mask 0x%x, configured display bit mask 0x%x, " \ + "display type %d", registered_displays_.to_ulong(), configured_displays_.to_ulong(), + display_comp_ctx->display_type); + + delete display_comp_ctx; + display_comp_ctx = NULL; + return kErrorNone; +} + +DisplayError CompManager::ReconfigureDisplay(Handle comp_handle, + const HWDisplayAttributes &display_attributes, + const HWPanelInfo &hw_panel_info, + const HWMixerAttributes &mixer_attributes, + const DisplayConfigVariableInfo &fb_config) { + SCOPE_LOCK(locker_); + + DisplayError error = kErrorNone; + DisplayCompositionContext *display_comp_ctx = + reinterpret_cast<DisplayCompositionContext *>(comp_handle); + + error = resource_intf_->ReconfigureDisplay(display_comp_ctx->display_resource_ctx, + display_attributes, hw_panel_info, mixer_attributes); + if (error != kErrorNone) { + return error; + } + + if (display_comp_ctx->strategy) { + error = display_comp_ctx->strategy->Reconfigure(hw_panel_info, display_attributes, + mixer_attributes, fb_config); + if (error != kErrorNone) { + DLOGE("Unable to Reconfigure strategy."); + display_comp_ctx->strategy->Deinit(); + delete display_comp_ctx->strategy; + display_comp_ctx->strategy = NULL; + return error; + } + } + + // For HDMI S3D mode, set max_layers_ to 0 so that primary display would fall back + // to GPU composition to release pipes for HDMI. + if (display_comp_ctx->display_type == kHDMI) { + if (hw_panel_info.s3d_mode != kS3DModeNone) { + max_layers_ = 0; + } else { + max_layers_ = kMaxSDELayers; + } + } + + display_comp_ctx->scaled_composition = NeedsScaledComposition(fb_config, mixer_attributes); + // Update new resolution. + display_comp_ctx->fb_config = fb_config; + + return error; +} + +void CompManager::PrepareStrategyConstraints(Handle comp_handle, HWLayers *hw_layers) { + DisplayCompositionContext *display_comp_ctx = + reinterpret_cast<DisplayCompositionContext *>(comp_handle); + StrategyConstraints *constraints = &display_comp_ctx->constraints; + bool low_end_hw = ((hw_res_info_.num_vig_pipe + hw_res_info_.num_rgb_pipe + + hw_res_info_.num_dma_pipe) <= kSafeModeThreshold); + + constraints->safe_mode = safe_mode_; + constraints->use_cursor = false; + constraints->max_layers = max_layers_; + + // Limit 2 layer SDE Comp if its not a Primary Display. + // Safe mode is the policy for External display on a low end device. + if (!display_comp_ctx->is_primary_panel) { + constraints->max_layers = max_sde_ext_layers_; + constraints->safe_mode = (low_end_hw && !hw_res_info_.separate_rotator) ? true : safe_mode_; + if(hw_layers->info.stack->flags.secure_present) + secure_external_layer_ = true; + else + secure_external_layer_ = false; + } + + // When Secure layer is present on external, GPU composition should be policy + // for Primary on low end devices + if(display_comp_ctx->is_primary_panel && (registered_displays_.count() > 1) + && low_end_hw && secure_external_layer_) { + DLOGV_IF(kTagCompManager,"Secure layer present for LET. Fallingback to GPU"); + hw_layers->info.stack->flags.skip_present = 1; + for(auto &layer : hw_layers->info.stack->layers) { + if(layer->composition != kCompositionGPUTarget) { + layer->flags.skip = 1; + } + } + } + + // If a strategy fails after successfully allocating resources, then set safe mode + if (display_comp_ctx->remaining_strategies != display_comp_ctx->max_strategies) { + constraints->safe_mode = true; + } + + // Set use_cursor constraint to Strategy + constraints->use_cursor = display_comp_ctx->valid_cursor; + + // TODO(user): App layer count will change for hybrid composition + uint32_t app_layer_count = UINT32(hw_layers->info.stack->layers.size()) - 1; + if (display_comp_ctx->idle_fallback || display_comp_ctx->thermal_fallback_) { + // Handle the idle timeout by falling back + constraints->safe_mode = true; + } + + // Avoid safe mode, if there is only one app layer. + if (app_layer_count == 1) { + constraints->safe_mode = false; + } +} + +void CompManager::PrePrepare(Handle display_ctx, HWLayers *hw_layers) { + SCOPE_LOCK(locker_); + DisplayCompositionContext *display_comp_ctx = + reinterpret_cast<DisplayCompositionContext *>(display_ctx); + display_comp_ctx->valid_cursor = SupportLayerAsCursor(display_comp_ctx, hw_layers); + + // pu constraints + display_comp_ctx->pu_constraints.enable_cursor_pu = display_comp_ctx->valid_cursor; + + display_comp_ctx->strategy->Start(&hw_layers->info, &display_comp_ctx->max_strategies, + display_comp_ctx->pu_constraints); + display_comp_ctx->remaining_strategies = display_comp_ctx->max_strategies; +} + +DisplayError CompManager::Prepare(Handle display_ctx, HWLayers *hw_layers) { + SCOPE_LOCK(locker_); + + DisplayCompositionContext *display_comp_ctx = + reinterpret_cast<DisplayCompositionContext *>(display_ctx); + Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx; + + DisplayError error = kErrorUndefined; + + PrepareStrategyConstraints(display_ctx, hw_layers); + + // Select a composition strategy, and try to allocate resources for it. + resource_intf_->Start(display_resource_ctx); + + bool exit = false; + uint32_t &count = display_comp_ctx->remaining_strategies; + for (; !exit && count > 0; count--) { + error = display_comp_ctx->strategy->GetNextStrategy(&display_comp_ctx->constraints); + if (error != kErrorNone) { + // Composition strategies exhausted. Resource Manager could not allocate resources even for + // GPU composition. This will never happen. + exit = true; + } + + if (!exit) { + error = resource_intf_->Prepare(display_resource_ctx, hw_layers); + // Exit if successfully prepared resource, else try next strategy. + exit = (error == kErrorNone); + } + } + + if (error != kErrorNone) { + resource_intf_->Stop(display_resource_ctx, hw_layers); + DLOGE("Composition strategies exhausted for display = %d", display_comp_ctx->display_type); + return error; + } + + error = resource_intf_->Stop(display_resource_ctx, hw_layers); + + return error; +} + +DisplayError CompManager::PostPrepare(Handle display_ctx, HWLayers *hw_layers) { + SCOPE_LOCK(locker_); + DisplayCompositionContext *display_comp_ctx = + reinterpret_cast<DisplayCompositionContext *>(display_ctx); + Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx; + + DisplayError error = kErrorNone; + error = resource_intf_->PostPrepare(display_resource_ctx, hw_layers); + if (error != kErrorNone) { + return error; + } + + display_comp_ctx->strategy->Stop(); + + return kErrorNone; +} + +DisplayError CompManager::Commit(Handle display_ctx, HWLayers *hw_layers) { + SCOPE_LOCK(locker_); + + DisplayCompositionContext *display_comp_ctx = + reinterpret_cast<DisplayCompositionContext *>(display_ctx); + + return resource_intf_->Commit(display_comp_ctx->display_resource_ctx, hw_layers); +} + +DisplayError CompManager::ReConfigure(Handle display_ctx, HWLayers *hw_layers) { + SCOPE_LOCK(locker_); + + DisplayCompositionContext *display_comp_ctx = + reinterpret_cast<DisplayCompositionContext *>(display_ctx); + Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx; + + DisplayError error = kErrorUndefined; + resource_intf_->Start(display_resource_ctx); + error = resource_intf_->Prepare(display_resource_ctx, hw_layers); + + if (error != kErrorNone) { + DLOGE("Reconfigure failed for display = %d", display_comp_ctx->display_type); + } + + resource_intf_->Stop(display_resource_ctx, hw_layers); + if (error != kErrorNone) { + error = resource_intf_->PostPrepare(display_resource_ctx, hw_layers); + } + + return error; +} + +DisplayError CompManager::PostCommit(Handle display_ctx, HWLayers *hw_layers) { + SCOPE_LOCK(locker_); + + DisplayError error = kErrorNone; + DisplayCompositionContext *display_comp_ctx = + reinterpret_cast<DisplayCompositionContext *>(display_ctx); + configured_displays_[display_comp_ctx->display_type] = 1; + if (configured_displays_ == registered_displays_) { + safe_mode_ = false; + } + + error = resource_intf_->PostCommit(display_comp_ctx->display_resource_ctx, hw_layers); + if (error != kErrorNone) { + return error; + } + + display_comp_ctx->idle_fallback = false; + + DLOGV_IF(kTagCompManager, "registered display bit mask 0x%x, configured display bit mask 0x%x, " \ + "display type %d", registered_displays_, configured_displays_, + display_comp_ctx->display_type); + + return kErrorNone; +} + +void CompManager::Purge(Handle display_ctx) { + SCOPE_LOCK(locker_); + + DisplayCompositionContext *display_comp_ctx = + reinterpret_cast<DisplayCompositionContext *>(display_ctx); + + resource_intf_->Purge(display_comp_ctx->display_resource_ctx); + + display_comp_ctx->strategy->Purge(); +} + +DisplayError CompManager::SetIdleTimeoutMs(Handle display_ctx, uint32_t active_ms) { + SCOPE_LOCK(locker_); + + DisplayCompositionContext *display_comp_ctx = + reinterpret_cast<DisplayCompositionContext *>(display_ctx); + + return display_comp_ctx->strategy->SetIdleTimeoutMs(active_ms); +} + +void CompManager::ProcessIdleTimeout(Handle display_ctx) { + SCOPE_LOCK(locker_); + + DisplayCompositionContext *display_comp_ctx = + reinterpret_cast<DisplayCompositionContext *>(display_ctx); + + if (!display_comp_ctx) { + return; + } + + display_comp_ctx->idle_fallback = true; +} + +void CompManager::ProcessThermalEvent(Handle display_ctx, int64_t thermal_level) { + SCOPE_LOCK(locker_); + + DisplayCompositionContext *display_comp_ctx = + reinterpret_cast<DisplayCompositionContext *>(display_ctx); + + if (thermal_level >= kMaxThermalLevel) { + display_comp_ctx->thermal_fallback_ = true; + } else { + display_comp_ctx->thermal_fallback_ = false; + } +} + +void CompManager::ProcessIdlePowerCollapse(Handle display_ctx) { + SCOPE_LOCK(locker_); + + DisplayCompositionContext *display_comp_ctx = + reinterpret_cast<DisplayCompositionContext *>(display_ctx); + + if (display_comp_ctx) { + resource_intf_->Perform(ResourceInterface::kCmdResetScalarLUT, + display_comp_ctx->display_resource_ctx); + } +} + +DisplayError CompManager::SetMaxMixerStages(Handle display_ctx, uint32_t max_mixer_stages) { + SCOPE_LOCK(locker_); + + DisplayError error = kErrorNone; + DisplayCompositionContext *display_comp_ctx = + reinterpret_cast<DisplayCompositionContext *>(display_ctx); + + if (display_comp_ctx) { + error = resource_intf_->SetMaxMixerStages(display_comp_ctx->display_resource_ctx, + max_mixer_stages); + } + + return error; +} + +void CompManager::ControlPartialUpdate(Handle display_ctx, bool enable) { + SCOPE_LOCK(locker_); + + DisplayCompositionContext *display_comp_ctx = + reinterpret_cast<DisplayCompositionContext *>(display_ctx); + display_comp_ctx->pu_constraints.enable = enable; +} + +DisplayError CompManager::ValidateScaling(const LayerRect &crop, const LayerRect &dst, + bool rotate90) { + BufferLayout layout = Debug::IsUbwcTiledFrameBuffer() ? kUBWC : kLinear; + return resource_intf_->ValidateScaling(crop, dst, rotate90, layout, true); +} + +DisplayError CompManager::ValidateAndSetCursorPosition(Handle display_ctx, HWLayers *hw_layers, + int x, int y) { + DisplayCompositionContext *display_comp_ctx = + reinterpret_cast<DisplayCompositionContext *>(display_ctx); + Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx; + return resource_intf_->ValidateAndSetCursorPosition(display_resource_ctx, hw_layers, x, y, + &display_comp_ctx->fb_config); +} + +bool CompManager::SupportLayerAsCursor(Handle comp_handle, HWLayers *hw_layers) { + DisplayCompositionContext *display_comp_ctx = + reinterpret_cast<DisplayCompositionContext *>(comp_handle); + Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx; + LayerStack *layer_stack = hw_layers->info.stack; + bool supported = false; + int32_t gpu_index = -1; + + // HW Cursor cannot be used, if Display configuration needs scaled composition. + if (display_comp_ctx->scaled_composition || !layer_stack->flags.cursor_present) { + return supported; + } + + for (int32_t i = INT32(layer_stack->layers.size() - 1); i >= 0; i--) { + Layer *layer = layer_stack->layers.at(UINT32(i)); + if (layer->composition == kCompositionGPUTarget) { + gpu_index = i; + break; + } + } + if (gpu_index <= 0) { + return supported; + } + Layer *cursor_layer = layer_stack->layers.at(UINT32(gpu_index) - 1); + if (cursor_layer->flags.cursor && !cursor_layer->flags.skip && + resource_intf_->ValidateCursorConfig(display_resource_ctx, + cursor_layer, true) == kErrorNone) { + supported = true; + } + + return supported; +} + +DisplayError CompManager::SetMaxBandwidthMode(HWBwModes mode) { + if ((hw_res_info_.has_dyn_bw_support == false) || (mode >= kBwModeMax)) { + return kErrorNotSupported; + } + + return resource_intf_->SetMaxBandwidthMode(mode); +} + +DisplayError CompManager::GetScaleLutConfig(HWScaleLutInfo *lut_info) { + return resource_intf_->GetScaleLutConfig(lut_info); +} + +DisplayError CompManager::SetDetailEnhancerData(Handle display_ctx, + const DisplayDetailEnhancerData &de_data) { + SCOPE_LOCK(locker_); + + DisplayCompositionContext *display_comp_ctx = + reinterpret_cast<DisplayCompositionContext *>(display_ctx); + + return resource_intf_->SetDetailEnhancerData(display_comp_ctx->display_resource_ctx, de_data); +} + +DisplayError CompManager::SetCompositionState(Handle display_ctx, + LayerComposition composition_type, bool enable) { + SCOPE_LOCK(locker_); + + DisplayCompositionContext *display_comp_ctx = + reinterpret_cast<DisplayCompositionContext *>(display_ctx); + + return display_comp_ctx->strategy->SetCompositionState(composition_type, enable); +} + +DisplayError CompManager::ControlDpps(bool enable) { + if (dpps_ctrl_intf_) { + return enable ? dpps_ctrl_intf_->On() : dpps_ctrl_intf_->Off(); + } + + return kErrorNone; +} + +bool CompManager::SetDisplayState(Handle display_ctx, + DisplayState state, DisplayType display_type) { + display_state_[display_type] = state; + + switch (state) { + case kStateOff: + Purge(display_ctx); + configured_displays_.reset(display_type); + DLOGV_IF(kTagCompManager, "configured_displays_ = 0x%x", configured_displays_); + break; + + case kStateOn: + if (registered_displays_.count() > 1) { + safe_mode_ = true; + DLOGV_IF(kTagCompManager, "safe_mode = %d", safe_mode_); + } + break; + + default: + break; + } + + return true; +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/core/comp_manager.h b/msm8909/sdm/libs/core/comp_manager.h new file mode 100644 index 00000000..d1351aeb --- /dev/null +++ b/msm8909/sdm/libs/core/comp_manager.h @@ -0,0 +1,123 @@ +/* +* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __COMP_MANAGER_H__ +#define __COMP_MANAGER_H__ + +#include <core/display_interface.h> +#include <private/extension_interface.h> +#include <utils/locker.h> +#include <bitset> + +#include "strategy.h" +#include "resource_default.h" +#include "hw_interface.h" + +namespace sdm { + +class CompManager { + public: + DisplayError Init(const HWResourceInfo &hw_res_info_, ExtensionInterface *extension_intf, + BufferAllocator *buffer_allocator, BufferSyncHandler *buffer_sync_handler, + SocketHandler *socket_handler); + DisplayError Deinit(); + DisplayError RegisterDisplay(DisplayType type, const HWDisplayAttributes &display_attributes, + const HWPanelInfo &hw_panel_info, + const HWMixerAttributes &mixer_attributes, + const DisplayConfigVariableInfo &fb_config, Handle *display_ctx); + DisplayError UnregisterDisplay(Handle display_ctx); + DisplayError ReconfigureDisplay(Handle display_ctx, const HWDisplayAttributes &display_attributes, + const HWPanelInfo &hw_panel_info, + const HWMixerAttributes &mixer_attributes, + const DisplayConfigVariableInfo &fb_config); + void PrePrepare(Handle display_ctx, HWLayers *hw_layers); + DisplayError Prepare(Handle display_ctx, HWLayers *hw_layers); + DisplayError Commit(Handle display_ctx, HWLayers *hw_layers); + DisplayError PostPrepare(Handle display_ctx, HWLayers *hw_layers); + DisplayError ReConfigure(Handle display_ctx, HWLayers *hw_layers); + DisplayError PostCommit(Handle display_ctx, HWLayers *hw_layers); + void Purge(Handle display_ctx); + DisplayError SetIdleTimeoutMs(Handle display_ctx, uint32_t active_ms); + void ProcessIdleTimeout(Handle display_ctx); + void ProcessThermalEvent(Handle display_ctx, int64_t thermal_level); + void ProcessIdlePowerCollapse(Handle display_ctx); + DisplayError SetMaxMixerStages(Handle display_ctx, uint32_t max_mixer_stages); + void ControlPartialUpdate(Handle display_ctx, bool enable); + DisplayError ValidateScaling(const LayerRect &crop, const LayerRect &dst, bool rotate90); + DisplayError ValidateCursorPosition(Handle display_ctx, HWLayers *hw_layers, int x, int y); + bool SupportLayerAsCursor(Handle display_ctx, HWLayers *hw_layers); + DisplayError ValidateAndSetCursorPosition(Handle display_ctx, HWLayers *hw_layers, int x, int y); + bool SetDisplayState(Handle display_ctx, DisplayState state, DisplayType display_type); + DisplayError SetMaxBandwidthMode(HWBwModes mode); + DisplayError GetScaleLutConfig(HWScaleLutInfo *lut_info); + DisplayError SetDetailEnhancerData(Handle display_ctx, const DisplayDetailEnhancerData &de_data); + DisplayError SetCompositionState(Handle display_ctx, LayerComposition composition_type, + bool enable); + DisplayError ControlDpps(bool enable); + + private: + static const int kMaxThermalLevel = 3; + static const int kSafeModeThreshold = 4; + + void PrepareStrategyConstraints(Handle display_ctx, HWLayers *hw_layers); + + struct DisplayCompositionContext { + Strategy *strategy = NULL; + StrategyConstraints constraints; + Handle display_resource_ctx = NULL; + DisplayType display_type = kPrimary; + uint32_t max_strategies = 0; + uint32_t remaining_strategies = 0; + bool idle_fallback = false; + bool thermal_fallback_ = false; + // Using primary panel flag of hw panel to configure Constraints. We do not need other hw + // panel parameters for now. + bool is_primary_panel = false; + bool valid_cursor = false; + PUConstraints pu_constraints = {}; + bool scaled_composition = false; + DisplayConfigVariableInfo fb_config = {}; + }; + + Locker locker_; + ResourceInterface *resource_intf_ = NULL; + std::bitset<kDisplayMax> registered_displays_; // Bit mask of registered displays + std::bitset<kDisplayMax> configured_displays_; // Bit mask of sucessfully configured displays + uint32_t display_state_[kDisplayMax] = {}; + bool safe_mode_ = false; // Flag to notify all displays to be in resource crunch + // mode, where strategy manager chooses the best strategy + // that uses optimal number of pipes for each display + bool secure_external_layer_ = false; + HWResourceInfo hw_res_info_; + BufferAllocator *buffer_allocator_ = NULL; + ExtensionInterface *extension_intf_ = NULL; + uint32_t max_layers_ = kMaxSDELayers; + uint32_t max_sde_ext_layers_ = 0; + DppsControlInterface *dpps_ctrl_intf_ = NULL; +}; + +} // namespace sdm + +#endif // __COMP_MANAGER_H__ + diff --git a/msm8909/sdm/libs/core/core_impl.cpp b/msm8909/sdm/libs/core/core_impl.cpp new file mode 100644 index 00000000..212612c2 --- /dev/null +++ b/msm8909/sdm/libs/core/core_impl.cpp @@ -0,0 +1,188 @@ +/* +* Copyright (c) 2014 - 2018, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <dlfcn.h> +#include <utils/locker.h> +#include <utils/constants.h> +#include <utils/debug.h> + +#include "core_impl.h" +#include "display_primary.h" +#include "display_hdmi.h" +#include "display_virtual.h" +#include "hw_info_interface.h" +#include "color_manager.h" + +#define __CLASS__ "CoreImpl" + +namespace sdm { + +CoreImpl::CoreImpl(BufferAllocator *buffer_allocator, + BufferSyncHandler *buffer_sync_handler, + SocketHandler *socket_handler) + : buffer_allocator_(buffer_allocator), buffer_sync_handler_(buffer_sync_handler), + socket_handler_(socket_handler) { +} + +DisplayError CoreImpl::Init() { + SCOPE_LOCK(locker_); + DisplayError error = kErrorNone; + + // Try to load extension library & get handle to its interface. + if (extension_lib_.Open(EXTENSION_LIBRARY_NAME)) { + if (!extension_lib_.Sym(CREATE_EXTENSION_INTERFACE_NAME, + reinterpret_cast<void **>(&create_extension_intf_)) || + !extension_lib_.Sym(DESTROY_EXTENSION_INTERFACE_NAME, + reinterpret_cast<void **>(&destroy_extension_intf_))) { + DLOGE("Unable to load symbols, error = %s", extension_lib_.Error()); + return kErrorUndefined; + } + + error = create_extension_intf_(EXTENSION_VERSION_TAG, &extension_intf_); + if (error != kErrorNone) { + DLOGE("Unable to create interface"); + return error; + } + } else { + DLOGW("Unable to load = %s, error = %s", EXTENSION_LIBRARY_NAME, extension_lib_.Error()); + } + + error = HWInfoInterface::Create(&hw_info_intf_); + if (error != kErrorNone) { + goto CleanupOnError; + } + + if (hw_info_intf_ == NULL) { + return kErrorResources; + } + error = hw_info_intf_->GetHWResourceInfo(&hw_resource_); + if (error != kErrorNone) { + goto CleanupOnError; + } + + error = comp_mgr_.Init(hw_resource_, extension_intf_, buffer_allocator_, + buffer_sync_handler_, socket_handler_); + + if (error != kErrorNone) { + goto CleanupOnError; + } + + error = ColorManagerProxy::Init(hw_resource_); + // if failed, doesn't affect display core functionalities. + if (error != kErrorNone) { + DLOGW("Unable creating color manager and continue without it."); + } + + return kErrorNone; + +CleanupOnError: + if (hw_info_intf_) { + HWInfoInterface::Destroy(hw_info_intf_); + } + + return error; +} + +DisplayError CoreImpl::Deinit() { + SCOPE_LOCK(locker_); + + ColorManagerProxy::Deinit(); + + comp_mgr_.Deinit(); + HWInfoInterface::Destroy(hw_info_intf_); + + return kErrorNone; +} + +DisplayError CoreImpl::CreateDisplay(DisplayType type, DisplayEventHandler *event_handler, + DisplayInterface **intf) { + SCOPE_LOCK(locker_); + + if (!event_handler || !intf) { + return kErrorParameters; + } + + DisplayBase *display_base = NULL; + + switch (type) { + case kPrimary: + display_base = new DisplayPrimary(event_handler, hw_info_intf_, buffer_sync_handler_, + buffer_allocator_, &comp_mgr_); + break; + case kHDMI: + display_base = new DisplayHDMI(event_handler, hw_info_intf_, buffer_sync_handler_, + buffer_allocator_, &comp_mgr_); + break; + case kVirtual: + display_base = new DisplayVirtual(event_handler, hw_info_intf_, buffer_sync_handler_, + buffer_allocator_, &comp_mgr_); + break; + default: + DLOGE("Spurious display type %d", type); + return kErrorParameters; + } + + if (!display_base) { + return kErrorMemory; + } + + DisplayError error = display_base->Init(); + if (error != kErrorNone) { + delete display_base; + return error; + } + + *intf = display_base; + return kErrorNone; +} + +DisplayError CoreImpl::DestroyDisplay(DisplayInterface *intf) { + SCOPE_LOCK(locker_); + + if (!intf) { + return kErrorParameters; + } + + DisplayBase *display_base = static_cast<DisplayBase *>(intf); + display_base->Deinit(); + delete display_base; + + return kErrorNone; +} + +DisplayError CoreImpl::SetMaxBandwidthMode(HWBwModes mode) { + SCOPE_LOCK(locker_); + + return comp_mgr_.SetMaxBandwidthMode(mode); +} + +DisplayError CoreImpl::GetFirstDisplayInterfaceType(HWDisplayInterfaceInfo *hw_disp_info) { + return hw_info_intf_->GetFirstDisplayInterfaceType(hw_disp_info); +} + +bool CoreImpl::IsColorTransformSupported() { + return (hw_resource_.has_ppp) ? false : true; +} +} // namespace sdm + diff --git a/msm8909/sdm/libs/core/core_impl.h b/msm8909/sdm/libs/core/core_impl.h new file mode 100644 index 00000000..e5156aae --- /dev/null +++ b/msm8909/sdm/libs/core/core_impl.h @@ -0,0 +1,80 @@ +/* +* Copyright (c) 2014 - 2016, 2018 The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __CORE_IMPL_H__ +#define __CORE_IMPL_H__ + +#include <core/core_interface.h> +#include <private/extension_interface.h> +#include <private/color_interface.h> +#include <utils/locker.h> +#include <utils/sys.h> + +#include "hw_interface.h" +#include "comp_manager.h" + +#define SET_REVISION(major, minor) ((major << 8) | minor) + +namespace sdm { + +class CoreImpl : public CoreInterface { + public: + // This class implements display core interface revision 1.0. + static const uint16_t kRevision = SET_REVISION(1, 0); + CoreImpl(BufferAllocator *buffer_allocator, BufferSyncHandler *buffer_sync_handler, + SocketHandler *socket_handler); + virtual ~CoreImpl() { } + + // This method returns the interface revision for the current display core object. + // Future revisions will override this method and return the appropriate revision upon query. + virtual uint16_t GetRevision() { return kRevision; } + virtual DisplayError Init(); + virtual DisplayError Deinit(); + + // Methods from core interface + virtual DisplayError CreateDisplay(DisplayType type, DisplayEventHandler *event_handler, + DisplayInterface **intf); + virtual DisplayError DestroyDisplay(DisplayInterface *intf); + virtual DisplayError SetMaxBandwidthMode(HWBwModes mode); + virtual DisplayError GetFirstDisplayInterfaceType(HWDisplayInterfaceInfo *hw_disp_info); + virtual bool IsColorTransformSupported(); + + protected: + Locker locker_; + BufferAllocator *buffer_allocator_ = NULL; + BufferSyncHandler *buffer_sync_handler_ = NULL; + HWResourceInfo hw_resource_; + CompManager comp_mgr_; + HWInfoInterface *hw_info_intf_ = NULL; + DynLib extension_lib_; + ExtensionInterface *extension_intf_ = NULL; + CreateExtensionInterface create_extension_intf_ = NULL; + DestroyExtensionInterface destroy_extension_intf_ = NULL; + SocketHandler *socket_handler_ = NULL; +}; + +} // namespace sdm + +#endif // __CORE_IMPL_H__ + diff --git a/msm8909/sdm/libs/core/core_interface.cpp b/msm8909/sdm/libs/core/core_interface.cpp new file mode 100644 index 00000000..911ad014 --- /dev/null +++ b/msm8909/sdm/libs/core/core_interface.cpp @@ -0,0 +1,133 @@ +/* +* Copyright (c) 2014 - 2015, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <utils/locker.h> +#include <utils/constants.h> +#include <utils/debug.h> +#include <core/buffer_sync_handler.h> + +#include "core_impl.h" + +#define __CLASS__ "CoreInterface" + +#define GET_REVISION(version) (version >> 16) +#define GET_DATA_ALIGNMENT(version) ((version >> 8) & 0xFF) +#define GET_INSTRUCTION_SET(version) (version & 0xFF) + +namespace sdm { + +// Currently, we support only one client and one session for display core. So, create a global +// singleton core object. +struct CoreSingleton { + CoreSingleton() : core_impl(NULL) { } + + CoreImpl *core_impl; + Locker locker; +} g_core; + +// TODO(user): Have a single structure handle carries all the interface pointers. +DisplayError CoreInterface::CreateCore(DebugHandler *debug_handler, + BufferAllocator *buffer_allocator, + BufferSyncHandler *buffer_sync_handler, + CoreInterface **interface, uint32_t client_version) { + return CreateCore(debug_handler, buffer_allocator, buffer_sync_handler, NULL, + interface, client_version); +} + +DisplayError CoreInterface::CreateCore(DebugHandler *debug_handler, + BufferAllocator *buffer_allocator, + BufferSyncHandler *buffer_sync_handler, + SocketHandler *socket_handler, + CoreInterface **interface, uint32_t client_version) { + SCOPE_LOCK(g_core.locker); + + if (!debug_handler || !buffer_allocator || !buffer_sync_handler || !interface) { + return kErrorParameters; + } + + // Check compatibility of client and core. + uint32_t lib_version = SDM_VERSION_TAG; + if (GET_REVISION(client_version) > GET_REVISION(lib_version)) { + return kErrorVersion; + } else if (GET_DATA_ALIGNMENT(client_version) != GET_DATA_ALIGNMENT(lib_version)) { + return kErrorDataAlignment; + } else if (GET_INSTRUCTION_SET(client_version) != GET_INSTRUCTION_SET(lib_version)) { + return kErrorInstructionSet; + } + + CoreImpl *&core_impl = g_core.core_impl; + if (core_impl) { + return kErrorUndefined; + } + + Debug::SetDebugHandler(debug_handler); + + // Create appropriate CoreImpl object based on client version. + if (GET_REVISION(client_version) == CoreImpl::kRevision) { + core_impl = new CoreImpl(buffer_allocator, buffer_sync_handler, socket_handler); + } else { + return kErrorNotSupported; + } + + if (!core_impl) { + return kErrorMemory; + } + + DisplayError error = core_impl->Init(); + if (error != kErrorNone) { + delete core_impl; + core_impl = NULL; + return error; + } + + *interface = core_impl; + DLOGI("Open interface handle = %p", *interface); + + return kErrorNone; +} + +DisplayError CoreInterface::DestroyCore() { + SCOPE_LOCK(g_core.locker); + + DLOGI("Close handle"); + + CoreImpl *&core_impl = g_core.core_impl; + if (!core_impl) { + return kErrorUndefined; + } + + core_impl->Deinit(); + delete core_impl; + core_impl = NULL; + + return kErrorNone; +} + +} // namespace sdm + diff --git a/msm8909/sdm/libs/core/display_base.cpp b/msm8909/sdm/libs/core/display_base.cpp new file mode 100644 index 00000000..82467379 --- /dev/null +++ b/msm8909/sdm/libs/core/display_base.cpp @@ -0,0 +1,1536 @@ +/* +* Copyright (c) 2014 - 2018, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <utils/constants.h> +#include <utils/debug.h> +#include <utils/formats.h> +#include <utils/rect.h> +#include <utils/utils.h> + +#include <iomanip> +#include <map> +#include <sstream> +#include <string> +#include <vector> +#include <algorithm> + +#include "display_base.h" +#include "hw_info_interface.h" + +#define __CLASS__ "DisplayBase" + +namespace sdm { + +// TODO(user): Have a single structure handle carries all the interface pointers and variables. +DisplayBase::DisplayBase(DisplayType display_type, DisplayEventHandler *event_handler, + HWDeviceType hw_device_type, BufferSyncHandler *buffer_sync_handler, + BufferAllocator *buffer_allocator, CompManager *comp_manager, + HWInfoInterface *hw_info_intf) + : display_type_(display_type), event_handler_(event_handler), hw_device_type_(hw_device_type), + buffer_sync_handler_(buffer_sync_handler), buffer_allocator_(buffer_allocator), + comp_manager_(comp_manager), hw_info_intf_(hw_info_intf) { +} + +DisplayError DisplayBase::Init() { + lock_guard<recursive_mutex> obj(recursive_mutex_); + DisplayError error = kErrorNone; + hw_panel_info_ = HWPanelInfo(); + hw_intf_->GetHWPanelInfo(&hw_panel_info_); + + uint32_t active_index = 0; + hw_intf_->GetActiveConfig(&active_index); + hw_intf_->GetDisplayAttributes(active_index, &display_attributes_); + fb_config_ = display_attributes_; + + error = Debug::GetMixerResolution(&mixer_attributes_.width, &mixer_attributes_.height); + if (error == kErrorNone) { + hw_intf_->SetMixerAttributes(mixer_attributes_); + } + + error = hw_intf_->GetMixerAttributes(&mixer_attributes_); + if (error != kErrorNone) { + return error; + } + + // Override x_pixels and y_pixels of frame buffer with mixer width and height + fb_config_.x_pixels = mixer_attributes_.width; + fb_config_.y_pixels = mixer_attributes_.height; + + HWScaleLutInfo lut_info = {}; + error = comp_manager_->GetScaleLutConfig(&lut_info); + if (error == kErrorNone) { + error = hw_intf_->SetScaleLutConfig(&lut_info); + if (error != kErrorNone) { + goto CleanupOnError; + } + } + + error = comp_manager_->RegisterDisplay(display_type_, display_attributes_, hw_panel_info_, + mixer_attributes_, fb_config_, &display_comp_ctx_); + if (error != kErrorNone) { + goto CleanupOnError; + } + + if (hw_info_intf_) { + HWResourceInfo hw_resource_info = HWResourceInfo(); + hw_info_intf_->GetHWResourceInfo(&hw_resource_info); + auto max_mixer_stages = hw_resource_info.num_blending_stages; + int property_value = Debug::GetMaxPipesPerMixer(display_type_); + if (property_value >= 0) { + max_mixer_stages = std::min(UINT32(property_value), hw_resource_info.num_blending_stages); + } + DisplayBase::SetMaxMixerStages(max_mixer_stages); + } + + color_mgr_ = ColorManagerProxy::CreateColorManagerProxy(display_type_, hw_intf_, + display_attributes_, hw_panel_info_); + if (!color_mgr_) { + DLOGW("Unable to create ColorManagerProxy for display = %d", display_type_); + } else if (InitializeColorModes() != kErrorNone) { + DLOGW("InitColorModes failed for display = %d", display_type_); + } + + Debug::Get()->GetProperty(DISABLE_HDR_LUT_GEN, &disable_hdr_lut_gen_); + + return kErrorNone; + +CleanupOnError: + if (display_comp_ctx_) { + comp_manager_->UnregisterDisplay(display_comp_ctx_); + } + + return error; +} + +DisplayError DisplayBase::Deinit() { + { // Scope for lock + lock_guard<recursive_mutex> obj(recursive_mutex_); + color_modes_.clear(); + color_mode_map_.clear(); + color_mode_attr_map_.clear(); + + if (color_mgr_) { + delete color_mgr_; + color_mgr_ = NULL; + } + + comp_manager_->UnregisterDisplay(display_comp_ctx_); + } + HWEventsInterface::Destroy(hw_events_intf_); + HWInterface::Destroy(hw_intf_); + + return kErrorNone; +} + +DisplayError DisplayBase::BuildLayerStackStats(LayerStack *layer_stack) { + std::vector<Layer *> &layers = layer_stack->layers; + HWLayersInfo &hw_layers_info = hw_layers_.info; + + hw_layers_info.stack = layer_stack; + + for (auto &layer : layers) { + if (layer->composition == kCompositionGPUTarget) { + hw_layers_info.gpu_target_index = hw_layers_info.app_layer_count; + break; + } + hw_layers_info.app_layer_count++; + } + + DLOGD_IF(kTagNone, "LayerStack layer_count: %d, app_layer_count: %d, gpu_target_index: %d, " + "display type: %d", layers.size(), hw_layers_info.app_layer_count, + hw_layers_info.gpu_target_index, display_type_); + + if (!hw_layers_info.app_layer_count) { + DLOGW("Layer count is zero"); + return kErrorNoAppLayers; + } + + if (hw_layers_info.gpu_target_index) { + return ValidateGPUTargetParams(); + } + + return kErrorNone; +} + +DisplayError DisplayBase::ValidateGPUTargetParams() { + HWLayersInfo &hw_layers_info = hw_layers_.info; + Layer *gpu_target_layer = hw_layers_info.stack->layers.at(hw_layers_info.gpu_target_index); + + if (!IsValid(gpu_target_layer->src_rect)) { + DLOGE("Invalid src rect for GPU target layer"); + return kErrorParameters; + } + + if (!IsValid(gpu_target_layer->dst_rect)) { + DLOGE("Invalid dst rect for GPU target layer"); + return kErrorParameters; + } + + float layer_mixer_width = FLOAT(mixer_attributes_.width); + float layer_mixer_height = FLOAT(mixer_attributes_.height); + float fb_width = FLOAT(fb_config_.x_pixels); + float fb_height = FLOAT(fb_config_.y_pixels); + LayerRect src_domain = (LayerRect){0.0f, 0.0f, fb_width, fb_height}; + LayerRect dst_domain = (LayerRect){0.0f, 0.0f, layer_mixer_width, layer_mixer_height}; + LayerRect out_rect = gpu_target_layer->dst_rect; + + MapRect(src_domain, dst_domain, gpu_target_layer->dst_rect, &out_rect); + Normalize(1, 1, &out_rect); + + auto gpu_target_layer_dst_xpixels = out_rect.right - out_rect.left; + auto gpu_target_layer_dst_ypixels = out_rect.bottom - out_rect.top; + + if (gpu_target_layer_dst_xpixels > mixer_attributes_.width || + gpu_target_layer_dst_ypixels > mixer_attributes_.height) { + DLOGE("GPU target layer dst rect is not with in limits gpu wxh %fx%f, mixer wxh %dx%d", + gpu_target_layer_dst_xpixels, gpu_target_layer_dst_ypixels, + mixer_attributes_.width, mixer_attributes_.height); + return kErrorParameters; + } + + return kErrorNone; +} + +DisplayError DisplayBase::Prepare(LayerStack *layer_stack) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + DisplayError error = kErrorNone; + needs_validate_ = true; + + if (!active_) { + return kErrorPermission; + } + + if (!layer_stack) { + return kErrorParameters; + } + + DLOGI_IF(kTagDisplay, "Entering Prepare for display type : %d", display_type_); + error = BuildLayerStackStats(layer_stack); + if (error != kErrorNone) { + return error; + } + + error = HandleHDR(layer_stack); + if (error != kErrorNone) { + DLOGW("HandleHDR failed"); + return error; + } + + if (color_mgr_ && color_mgr_->NeedsPartialUpdateDisable()) { + DisablePartialUpdateOneFrame(); + } + + if (partial_update_control_ == false || disable_pu_one_frame_) { + comp_manager_->ControlPartialUpdate(display_comp_ctx_, false /* enable */); + disable_pu_one_frame_ = false; + } + + comp_manager_->PrePrepare(display_comp_ctx_, &hw_layers_); + while (true) { + error = comp_manager_->Prepare(display_comp_ctx_, &hw_layers_); + if (error != kErrorNone) { + break; + } + + error = hw_intf_->Validate(&hw_layers_); + if (error == kErrorNone) { + // Strategy is successful now, wait for Commit(). + needs_validate_ = false; + break; + } + if (error == kErrorShutDown) { + comp_manager_->PostPrepare(display_comp_ctx_, &hw_layers_); + return error; + } + } + + comp_manager_->PostPrepare(display_comp_ctx_, &hw_layers_); + + DLOGI_IF(kTagDisplay, "Exiting Prepare for display type : %d", display_type_); + return error; +} + +DisplayError DisplayBase::Commit(LayerStack *layer_stack) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + DisplayError error = kErrorNone; + + if (!active_) { + needs_validate_ = true; + return kErrorPermission; + } + + if (!layer_stack) { + return kErrorParameters; + } + + if (needs_validate_) { + DLOGE("Commit: Corresponding Prepare() is not called for display = %d", display_type_); + return kErrorNotValidated; + } + + // Layer stack attributes has changed, need to Reconfigure, currently in use for Hybrid Comp + if (layer_stack->flags.attributes_changed) { + error = comp_manager_->ReConfigure(display_comp_ctx_, &hw_layers_); + if (error != kErrorNone) { + return error; + } + + error = hw_intf_->Validate(&hw_layers_); + if (error != kErrorNone) { + return error; + } + } + + DLOGI_IF(kTagDisplay, "Entering commit for display type : %d", display_type_); + CommitLayerParams(layer_stack); + + error = comp_manager_->Commit(display_comp_ctx_, &hw_layers_); + if (error != kErrorNone) { + return error; + } + + // check if feature list cache is dirty and pending. + // If dirty, need program to hardware blocks. + if (color_mgr_) + error = color_mgr_->Commit(); + if (error != kErrorNone) { // won't affect this execution path. + DLOGW("ColorManager::Commit(...) isn't working"); + } + + error = hw_intf_->Commit(&hw_layers_); + if (error != kErrorNone) { + return error; + } + + PostCommitLayerParams(layer_stack); + + if (partial_update_control_) { + comp_manager_->ControlPartialUpdate(display_comp_ctx_, true /* enable */); + } + + error = comp_manager_->PostCommit(display_comp_ctx_, &hw_layers_); + if (error != kErrorNone) { + return error; + } + + DLOGI_IF(kTagDisplay, "Exiting commit for display type : %d", display_type_); + return kErrorNone; +} + +DisplayError DisplayBase::Flush() { + lock_guard<recursive_mutex> obj(recursive_mutex_); + DisplayError error = kErrorNone; + + if (!active_) { + return kErrorPermission; + } + hw_layers_.info.hw_layers.clear(); + error = hw_intf_->Flush(); + if (error == kErrorNone) { + comp_manager_->Purge(display_comp_ctx_); + needs_validate_ = true; + } else { + DLOGW("Unable to flush display = %d", display_type_); + } + + return error; +} + +DisplayError DisplayBase::GetDisplayState(DisplayState *state) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + if (!state) { + return kErrorParameters; + } + + *state = state_; + return kErrorNone; +} + +DisplayError DisplayBase::GetNumVariableInfoConfigs(uint32_t *count) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + return hw_intf_->GetNumDisplayAttributes(count); +} + +DisplayError DisplayBase::GetConfig(uint32_t index, DisplayConfigVariableInfo *variable_info) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + HWDisplayAttributes attrib; + if (hw_intf_->GetDisplayAttributes(index, &attrib) == kErrorNone) { + *variable_info = attrib; + return kErrorNone; + } + + return kErrorNotSupported; +} + +DisplayError DisplayBase::GetConfig(DisplayConfigFixedInfo *fixed_info) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + fixed_info->is_cmdmode = (hw_panel_info_.mode == kModeCommand); + + HWResourceInfo hw_resource_info = HWResourceInfo(); + hw_info_intf_->GetHWResourceInfo(&hw_resource_info); + // hdr can be supported by display when target and panel supports HDR. + fixed_info->hdr_supported = (hw_resource_info.has_hdr && hw_panel_info_.hdr_enabled); + // Populate luminance values only if hdr will be supported on that display + fixed_info->max_luminance = fixed_info->hdr_supported ? hw_panel_info_.peak_luminance: 0; + fixed_info->average_luminance = fixed_info->hdr_supported ? hw_panel_info_.average_luminance : 0; + fixed_info->min_luminance = fixed_info->hdr_supported ? hw_panel_info_.blackness_level: 0; + + return kErrorNone; +} + +DisplayError DisplayBase::GetActiveConfig(uint32_t *index) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + return hw_intf_->GetActiveConfig(index); +} + +DisplayError DisplayBase::GetVSyncState(bool *enabled) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + if (!enabled) { + return kErrorParameters; + } + + *enabled = vsync_enable_; + + return kErrorNone; +} + +DisplayError DisplayBase::SetDisplayState(DisplayState state) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + DisplayError error = kErrorNone; + bool active = false; + + DLOGI("Set state = %d, display %d", state, display_type_); + + if (state == state_) { + DLOGI("Same state transition is requested."); + return kErrorNone; + } + + switch (state) { + case kStateOff: + hw_layers_.info.hw_layers.clear(); + error = hw_intf_->Flush(); + if (error == kErrorNone) { + error = hw_intf_->PowerOff(); + } + break; + + case kStateOn: + error = hw_intf_->PowerOn(); + if (error != kErrorNone) { + return error; + } + + error = comp_manager_->ReconfigureDisplay(display_comp_ctx_, display_attributes_, + hw_panel_info_, mixer_attributes_, fb_config_); + if (error != kErrorNone) { + return error; + } + + active = true; + break; + + case kStateDoze: + error = hw_intf_->Doze(); + active = true; + break; + + case kStateDozeSuspend: + error = hw_intf_->DozeSuspend(); + if (display_type_ != kPrimary) { + active = true; + } + + break; + + case kStateStandby: + error = hw_intf_->Standby(); + break; + + default: + DLOGE("Spurious state = %d transition requested.", state); + break; + } + + if (error == kErrorNone) { + active_ = active; + state_ = state; + comp_manager_->SetDisplayState(display_comp_ctx_, state, display_type_); + } + + return error; +} + +DisplayError DisplayBase::SetActiveConfig(uint32_t index) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + DisplayError error = kErrorNone; + uint32_t active_index = 0; + + hw_intf_->GetActiveConfig(&active_index); + + if (active_index == index) { + return kErrorNone; + } + + error = hw_intf_->SetDisplayAttributes(index); + if (error != kErrorNone) { + return error; + } + + return ReconfigureDisplay(); +} + +DisplayError DisplayBase::SetMaxMixerStages(uint32_t max_mixer_stages) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + DisplayError error = kErrorNone; + + error = comp_manager_->SetMaxMixerStages(display_comp_ctx_, max_mixer_stages); + + if (error == kErrorNone) { + max_mixer_stages_ = max_mixer_stages; + } + + return error; +} + +std::string DisplayBase::Dump() { + lock_guard<recursive_mutex> obj(recursive_mutex_); + HWDisplayAttributes attrib; + uint32_t active_index = 0; + uint32_t num_modes = 0; + std::ostringstream os; + + hw_intf_->GetNumDisplayAttributes(&num_modes); + hw_intf_->GetActiveConfig(&active_index); + hw_intf_->GetDisplayAttributes(active_index, &attrib); + + os << "device type:" << display_type_; + os << "\nstate: " << state_ << " vsync on: " << vsync_enable_ << " max. mixer stages: " + << max_mixer_stages_; + os << "\nnum configs: " << num_modes << " active config index: " << active_index; + + DisplayConfigVariableInfo &info = attrib; + + uint32_t num_hw_layers = UINT32(hw_layers_.info.hw_layers.size()); + + if (num_hw_layers == 0) { + os << "\nNo hardware layers programmed"; + return os.str(); + } + + LayerBuffer *out_buffer = nullptr; + if (hw_layers_.info.stack) { + out_buffer = hw_layers_.info.stack->output_buffer; + } + if (out_buffer != nullptr) { + os << "\nres: " << out_buffer->width << "x" << out_buffer->height << " format: " + << GetFormatString(out_buffer->format); + } else { + os.precision(2); + os << "\nres: " << info.x_pixels << "x" << info.y_pixels << " dpi: " << std::fixed << + info.x_dpi << "x" << std::fixed << info.y_dpi << " fps: " << info.fps << + " vsync period: " << info.vsync_period_ns; + } + + HWLayersInfo &layer_info = hw_layers_.info; + for (uint32_t i = 0; i < layer_info.left_frame_roi.size(); i++) { + LayerRect &l_roi = layer_info.left_frame_roi.at(i); + LayerRect &r_roi = layer_info.right_frame_roi.at(i); + + os << "\nROI(LTRB)#" << i << " LEFT(" << INT(l_roi.left) << " " << INT(l_roi.top) << " " << + INT(l_roi.right) << " " << INT(l_roi.bottom) << ")"; + if (IsValid(r_roi)) { + os << " RIGHT(" << INT(r_roi.left) << " " << INT(r_roi.top) << " " << INT(r_roi.right) << " " + << INT(r_roi.bottom) << ")"; + } + } + + LayerRect &fb_roi = layer_info.partial_fb_roi; + if (IsValid(fb_roi)) { + os << "\nPartial FB ROI(LTRB):(" << INT(fb_roi.left) << " " << INT(fb_roi.top) << " " << + INT(fb_roi.right) << " " << INT(fb_roi.bottom) << ")"; + } + + const char *header = "\n| Idx | Comp Type | Split | WB | Pipe | W x H | Format | Src Rect (L T R B) | Dst Rect (L T R B) | Z | Flags | Deci(HxV) | CS | Rng |"; //NOLINT + const char *newline = "\n|-----|-------------|--------|----|--------|-------------|--------------------------|---------------------|---------------------|----|------------|-----------|----|-----|"; //NOLINT + const char *format = "\n| %3s | %11s " "| %6s " "| %2s | 0x%04x | %4d x %4d | %24s " "| %4d %4d %4d %4d " "| %4d %4d %4d %4d " "| %2s | %10s " "| %9s | %2s | %3s |"; //NOLINT + + + os << "\n"; + os << newline; + os << header; + os << newline; + + for (uint32_t i = 0; i < num_hw_layers; i++) { + uint32_t layer_index = hw_layers_.info.index[i]; + // hw-layer from hw layers info + Layer &hw_layer = hw_layers_.info.hw_layers.at(i); + LayerBuffer *input_buffer = &hw_layer.input_buffer; + HWLayerConfig &layer_config = hw_layers_.config[i]; + HWRotatorSession &hw_rotator_session = layer_config.hw_rotator_session; + + char idx[8] = { 0 }; + const char *comp_type = GetName(hw_layer.composition); + const char *buffer_format = GetFormatString(input_buffer->format); + const char *rotate_split[2] = { "Rot-1", "Rot-2" }; + const char *comp_split[2] = { "Comp-1", "Comp-2" }; + + snprintf(idx, sizeof(idx), "%d", layer_index); + + for (uint32_t count = 0; count < hw_rotator_session.hw_block_count; count++) { + char writeback_id[8] = { 0 }; + char row[1024]; + HWRotateInfo &rotate = hw_rotator_session.hw_rotate_info[count]; + LayerRect &src_roi = rotate.src_roi; + LayerRect &dst_roi = rotate.dst_roi; + + snprintf(writeback_id, sizeof(writeback_id), "%d", rotate.writeback_id); + + snprintf(row, sizeof(row), format, idx, comp_type, rotate_split[count], + writeback_id, rotate.pipe_id, input_buffer->width, + input_buffer->height, buffer_format, INT(src_roi.left), + INT(src_roi.top), INT(src_roi.right), INT(src_roi.bottom), + INT(dst_roi.left), INT(dst_roi.top), INT(dst_roi.right), + INT(dst_roi.bottom), "-", "- ", "- ", "-", "-"); + os << row; + // print the below only once per layer block, fill with spaces for rest. + idx[0] = 0; + comp_type = ""; + } + + if (hw_rotator_session.hw_block_count > 0) { + input_buffer = &hw_rotator_session.output_buffer; + buffer_format = GetFormatString(input_buffer->format); + } + + for (uint32_t count = 0; count < 2; count++) { + char decimation[16] = { 0 }; + char flags[16] = { 0 }; + char z_order[8] = { 0 }; + char color_primary[8] = { 0 }; + char range[8] = { 0 }; + + HWPipeInfo &pipe = (count == 0) ? layer_config.left_pipe : layer_config.right_pipe; + + if (!pipe.valid) { + continue; + } + + LayerRect &src_roi = pipe.src_roi; + LayerRect &dst_roi = pipe.dst_roi; + + snprintf(z_order, sizeof(z_order), "%d", pipe.z_order); + snprintf(flags, sizeof(flags), "0x%08x", hw_layer.flags.flags); + snprintf(decimation, sizeof(decimation), "%3d x %3d", pipe.horizontal_decimation, + pipe.vertical_decimation); + ColorMetaData &color_metadata = hw_layer.input_buffer.color_metadata; + snprintf(color_primary, sizeof(color_primary), "%d", color_metadata.colorPrimaries); + snprintf(range, sizeof(range), "%d", color_metadata.range); + + char row[1024]; + snprintf(row, sizeof(row), format, idx, comp_type, comp_split[count], + "-", pipe.pipe_id, input_buffer->width, input_buffer->height, + buffer_format, INT(src_roi.left), INT(src_roi.top), + INT(src_roi.right), INT(src_roi.bottom), INT(dst_roi.left), + INT(dst_roi.top), INT(dst_roi.right), INT(dst_roi.bottom), + z_order, flags, decimation, color_primary, range); + + os << row; + // print the below only once per layer block, fill with spaces for rest. + idx[0] = 0; + comp_type = ""; + } + } + + os << newline << "\n"; + + return os.str(); +} + +const char * DisplayBase::GetName(const LayerComposition &composition) { + switch (composition) { + case kCompositionGPU: return "GPU"; + case kCompositionSDE: return "SDE"; + case kCompositionHWCursor: return "CURSOR"; + case kCompositionHybrid: return "HYBRID"; + case kCompositionBlit: return "BLIT"; + case kCompositionGPUTarget: return "GPU_TARGET"; + case kCompositionBlitTarget: return "BLIT_TARGET"; + default: return "UNKNOWN"; + } +} + +DisplayError DisplayBase::ColorSVCRequestRoute(const PPDisplayAPIPayload &in_payload, + PPDisplayAPIPayload *out_payload, + PPPendingParams *pending_action) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + if (color_mgr_) + return color_mgr_->ColorSVCRequestRoute(in_payload, out_payload, pending_action); + else + return kErrorParameters; +} + +DisplayError DisplayBase::GetColorModeCount(uint32_t *mode_count) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + if (!mode_count) { + return kErrorParameters; + } + + if (!color_mgr_) { + return kErrorNotSupported; + } + + DLOGV_IF(kTagQDCM, "Number of modes from color manager = %d", num_color_modes_); + *mode_count = num_color_modes_; + + return kErrorNone; +} + +DisplayError DisplayBase::GetColorModes(uint32_t *mode_count, + std::vector<std::string> *color_modes) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + if (!mode_count || !color_modes) { + return kErrorParameters; + } + + if (!color_mgr_) { + return kErrorNotSupported; + } + + for (uint32_t i = 0; i < num_color_modes_; i++) { + DLOGV_IF(kTagQDCM, "Color Mode[%d]: Name = %s mode_id = %d", i, color_modes_[i].name, + color_modes_[i].id); + color_modes->at(i) = color_modes_[i].name; + } + + return kErrorNone; +} + +DisplayError DisplayBase::GetColorModeAttr(const std::string &color_mode, AttrVal *attr) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + if (!attr) { + return kErrorParameters; + } + + if (!color_mgr_) { + return kErrorNotSupported; + } + + auto it = color_mode_attr_map_.find(color_mode); + if (it == color_mode_attr_map_.end()) { + DLOGE("Failed: Mode %s without attribute", color_mode.c_str()); + return kErrorNotSupported; + } + *attr = it->second; + + return kErrorNone; +} + +DisplayError DisplayBase::SetColorMode(const std::string &color_mode) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + if (!color_mgr_) { + return kErrorNotSupported; + } + + DynamicRangeType dynamic_range_type; + if (IsSupportColorModeAttribute(color_mode)) { + auto it_mode = color_mode_attr_map_.find(color_mode); + std::string dynamic_range; + GetValueOfModeAttribute(it_mode->second, kDynamicRangeAttribute, &dynamic_range); + if (dynamic_range == kHdr) { + dynamic_range_type = kHdrType; + } else { + dynamic_range_type = kSdrType; + } + } else { + if (color_mode.find("hal_hdr") != std::string::npos) { + dynamic_range_type = kHdrType; + } else { + dynamic_range_type = kSdrType; + } + } + + DisplayError error = kErrorNone; + if (disable_hdr_lut_gen_) { + error = SetColorModeInternal(color_mode); + if (error != kErrorNone) { + return error; + } + // Store the new SDR color mode request by client + if (dynamic_range_type == kSdrType) { + current_color_mode_ = color_mode; + } + return error; + } + + if (hdr_playback_mode_) { + // HDR playback on, If incoming mode is SDR mode, + // cache the mode and apply it after HDR playback stop. + if (dynamic_range_type == kHdrType) { + error = SetColorModeInternal(color_mode); + if (error != kErrorNone) { + return error; + } + } else if (dynamic_range_type == kSdrType) { + current_color_mode_ = color_mode; + } + } else { + // HDR playback off, do not apply HDR mode + if (dynamic_range_type == kHdrType) { + DLOGE("Failed: Forbid setting HDR Mode : %s when HDR playback off", color_mode.c_str()); + return kErrorNotSupported; + } + error = SetColorModeInternal(color_mode); + if (error != kErrorNone) { + return error; + } + current_color_mode_ = color_mode; + } + + return error; +} + +DisplayError DisplayBase::SetColorModeInternal(const std::string &color_mode) { + DLOGV_IF(kTagQDCM, "Color Mode = %s", color_mode.c_str()); + + ColorModeMap::iterator it = color_mode_map_.find(color_mode); + if (it == color_mode_map_.end()) { + DLOGE("Failed: Unknown Mode : %s", color_mode.c_str()); + return kErrorNotSupported; + } + + SDEDisplayMode *sde_display_mode = it->second; + + DLOGV_IF(kTagQDCM, "Color Mode Name = %s corresponding mode_id = %d", sde_display_mode->name, + sde_display_mode->id); + DisplayError error = kErrorNone; + error = color_mgr_->ColorMgrSetMode(sde_display_mode->id); + if (error != kErrorNone) { + DLOGE("Failed for mode id = %d", sde_display_mode->id); + return error; + } + + return error; +} + +DisplayError DisplayBase::GetValueOfModeAttribute(const AttrVal &attr,const std::string &type, + std::string *value) { + if (!value) { + return kErrorParameters; + } + for (auto &it : attr) { + if (it.first.find(type) != std::string::npos) { + *value = it.second; + } + } + + return kErrorNone; +} + +bool DisplayBase::IsSupportColorModeAttribute(const std::string &color_mode) { + auto it = color_mode_attr_map_.find(color_mode); + if (it == color_mode_attr_map_.end()) { + return false; + } + return true; +} + +DisplayError DisplayBase::GetHdrColorMode(std::string *color_mode, bool *found_hdr) { + if (!found_hdr || !color_mode) { + return kErrorParameters; + } + auto it_mode = color_mode_attr_map_.find(current_color_mode_); + if (it_mode == color_mode_attr_map_.end()) { + DLOGE("Failed: Unknown Mode : %s", current_color_mode_.c_str()); + return kErrorNotSupported; + } + + *found_hdr = false; + std::string cur_color_gamut, cur_pic_quality; + // get the attributes of current color mode + GetValueOfModeAttribute(it_mode->second, kColorGamutAttribute, &cur_color_gamut); + GetValueOfModeAttribute(it_mode->second, kPictureQualityAttribute, &cur_pic_quality); + + // found the corresponding HDR mode id which + // has the same attributes with current SDR mode. + for (auto &it_hdr : color_mode_attr_map_) { + std::string dynamic_range, color_gamut, pic_quality; + GetValueOfModeAttribute(it_hdr.second, kDynamicRangeAttribute, &dynamic_range); + GetValueOfModeAttribute(it_hdr.second, kColorGamutAttribute, &color_gamut); + GetValueOfModeAttribute(it_hdr.second, kPictureQualityAttribute, &pic_quality); + if (dynamic_range == kHdr && cur_color_gamut == color_gamut && + cur_pic_quality == pic_quality) { + *color_mode = it_hdr.first; + *found_hdr = true; + DLOGV_IF(kTagQDCM, "corresponding hdr mode = %s", color_mode->c_str()); + return kErrorNone; + } + } + + // The corresponding HDR mode was not be found, + // apply the first HDR mode that we encouter. + for (auto &it_hdr : color_mode_attr_map_) { + std::string dynamic_range; + GetValueOfModeAttribute(it_hdr.second, kDynamicRangeAttribute, &dynamic_range); + if (dynamic_range == kHdr) { + *color_mode = it_hdr.first; + *found_hdr = true; + DLOGV_IF(kTagQDCM, "First hdr mode = %s", color_mode->c_str()); + return kErrorNone; + } + } + + return kErrorNone; +} + +DisplayError DisplayBase::SetColorTransform(const uint32_t length, const double *color_transform) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + if (!color_mgr_) { + return kErrorNotSupported; + } + + if (!color_transform) { + return kErrorParameters; + } + + return color_mgr_->ColorMgrSetColorTransform(length, color_transform); +} + +DisplayError DisplayBase::GetDefaultColorMode(std::string *color_mode) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + if (!color_mode) { + return kErrorParameters; + } + + if (!color_mgr_) { + return kErrorNotSupported; + } + + int32_t default_id = kInvalidModeId; + DisplayError error = color_mgr_->ColorMgrGetDefaultModeID(&default_id); + if (error != kErrorNone) { + DLOGE("Failed for get default color mode id"); + return error; + } + + for (uint32_t i = 0; i < num_color_modes_; i++) { + if (color_modes_[i].id == default_id) { + *color_mode = color_modes_[i].name; + return kErrorNone; + } + } + + return kErrorNotSupported; +} + +DisplayError DisplayBase::ApplyDefaultDisplayMode() { + lock_guard<recursive_mutex> obj(recursive_mutex_); + if (color_mgr_) + return color_mgr_->ApplyDefaultDisplayMode(); + else + return kErrorParameters; +} + +DisplayError DisplayBase::SetCursorPosition(int x, int y) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + if (state_ != kStateOn) { + return kErrorNotSupported; + } + + DisplayError error = comp_manager_->ValidateAndSetCursorPosition(display_comp_ctx_, &hw_layers_, + x, y); + if (error == kErrorNone) { + return hw_intf_->SetCursorPosition(&hw_layers_, x, y); + } + + return kErrorNone; +} + +DisplayError DisplayBase::GetRefreshRateRange(uint32_t *min_refresh_rate, + uint32_t *max_refresh_rate) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + // The min and max refresh rates will be same when the HWPanelInfo does not contain valid rates. + // Usually for secondary displays, command mode panels + HWDisplayAttributes display_attributes; + uint32_t active_index = 0; + hw_intf_->GetActiveConfig(&active_index); + DisplayError error = hw_intf_->GetDisplayAttributes(active_index, &display_attributes); + if (error) { + return error; + } + + *min_refresh_rate = display_attributes.fps; + *max_refresh_rate = display_attributes.fps; + + return error; +} + +DisplayError DisplayBase::SetVSyncState(bool enable) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + DisplayError error = kErrorNone; + if (vsync_enable_ != enable) { + error = hw_intf_->SetVSyncState(enable); + if (error == kErrorNone) { + vsync_enable_ = enable; + } + } + return error; +} + +DisplayError DisplayBase::ReconfigureDisplay() { + lock_guard<recursive_mutex> obj(recursive_mutex_); + DisplayError error = kErrorNone; + HWDisplayAttributes display_attributes; + HWMixerAttributes mixer_attributes; + HWPanelInfo hw_panel_info; + uint32_t active_index = 0; + + error = hw_intf_->GetActiveConfig(&active_index); + if (error != kErrorNone) { + return error; + } + + error = hw_intf_->GetDisplayAttributes(active_index, &display_attributes); + if (error != kErrorNone) { + return error; + } + + error = hw_intf_->GetMixerAttributes(&mixer_attributes); + if (error != kErrorNone) { + return error; + } + + error = hw_intf_->GetHWPanelInfo(&hw_panel_info); + if (error != kErrorNone) { + return error; + } + + if (display_attributes == display_attributes_ && mixer_attributes == mixer_attributes_ && + hw_panel_info == hw_panel_info_) { + return kErrorNone; + } + + error = comp_manager_->ReconfigureDisplay(display_comp_ctx_, display_attributes, hw_panel_info, + mixer_attributes, fb_config_); + if (error != kErrorNone) { + return error; + } + + if (mixer_attributes != mixer_attributes_) { + DisablePartialUpdateOneFrame(); + } + + display_attributes_ = display_attributes; + mixer_attributes_ = mixer_attributes; + hw_panel_info_ = hw_panel_info; + + return kErrorNone; +} + +DisplayError DisplayBase::SetMixerResolution(uint32_t width, uint32_t height) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + + DisplayError error = ReconfigureMixer(width, height); + if (error != kErrorNone) { + return error; + } + + req_mixer_width_ = width; + req_mixer_height_ = height; + + return kErrorNone; +} + +DisplayError DisplayBase::GetMixerResolution(uint32_t *width, uint32_t *height) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + if (!width || !height) { + return kErrorParameters; + } + + *width = mixer_attributes_.width; + *height = mixer_attributes_.height; + + return kErrorNone; +} + +DisplayError DisplayBase::ReconfigureMixer(uint32_t width, uint32_t height) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + DisplayError error = kErrorNone; + + if (!width || !height) { + return kErrorParameters; + } + + DLOGD_IF(kTagQDCM, "Reconfiguring mixer with width : %d, height : %d", width, height); + HWMixerAttributes mixer_attributes; + mixer_attributes.width = width; + mixer_attributes.height = height; + + error = hw_intf_->SetMixerAttributes(mixer_attributes); + if (error != kErrorNone) { + return error; + } + + return ReconfigureDisplay(); +} + +bool DisplayBase::NeedsDownScale(const LayerRect &src_rect, const LayerRect &dst_rect, + bool needs_rotation) { + float src_width = FLOAT(src_rect.right - src_rect.left); + float src_height = FLOAT(src_rect.bottom - src_rect.top); + float dst_width = FLOAT(dst_rect.right - dst_rect.left); + float dst_height = FLOAT(dst_rect.bottom - dst_rect.top); + + if (needs_rotation) { + std::swap(src_width, src_height); + } + + if ((src_width > dst_width) || (src_height > dst_height)) { + return true; + } + + return false; +} + +bool DisplayBase::NeedsMixerReconfiguration(LayerStack *layer_stack, uint32_t *new_mixer_width, + uint32_t *new_mixer_height) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + uint32_t layer_count = UINT32(layer_stack->layers.size()); + + uint32_t fb_width = fb_config_.x_pixels; + uint32_t fb_height = fb_config_.y_pixels; + uint32_t fb_area = fb_width * fb_height; + LayerRect fb_rect = (LayerRect) {0.0f, 0.0f, FLOAT(fb_width), FLOAT(fb_height)}; + uint32_t mixer_width = mixer_attributes_.width; + uint32_t mixer_height = mixer_attributes_.height; + uint32_t display_width = display_attributes_.x_pixels; + uint32_t display_height = display_attributes_.y_pixels; + + RectOrientation fb_orientation = GetOrientation(fb_rect); + uint32_t max_layer_area = 0; + uint32_t max_area_layer_index = 0; + std::vector<Layer *> layers = layer_stack->layers; + uint32_t align_x = display_attributes_.is_device_split ? 4 : 2; + uint32_t align_y = 2; + + if (req_mixer_width_ && req_mixer_height_) { + DLOGD_IF(kTagDisplay, "Required mixer width : %d, height : %d", + req_mixer_width_, req_mixer_height_); + *new_mixer_width = req_mixer_width_; + *new_mixer_height = req_mixer_height_; + return (req_mixer_width_ != mixer_width || req_mixer_height_ != mixer_height); + } + + for (uint32_t i = 0; i < layer_count; i++) { + Layer *layer = layers.at(i); + + uint32_t layer_width = UINT32(layer->src_rect.right - layer->src_rect.left); + uint32_t layer_height = UINT32(layer->src_rect.bottom - layer->src_rect.top); + uint32_t layer_area = layer_width * layer_height; + + if (layer_area > max_layer_area) { + max_layer_area = layer_area; + max_area_layer_index = i; + } + } + DLOGV_IF(kTagDisplay, "Max area layer at index : %d", max_area_layer_index); + + // TODO(user): Mark layer which needs downscaling on GPU fallback as priority layer and use MDP + // for composition to avoid quality mismatch between GPU and MDP switch(idle timeout usecase). + if (max_layer_area >= fb_area) { + Layer *layer = layers.at(max_area_layer_index); + bool needs_rotation = (layer->transform.rotation == 90.0f); + + uint32_t layer_width = UINT32(layer->src_rect.right - layer->src_rect.left); + uint32_t layer_height = UINT32(layer->src_rect.bottom - layer->src_rect.top); + LayerRect layer_dst_rect = {}; + + RectOrientation layer_orientation = GetOrientation(layer->src_rect); + if (layer_orientation != kOrientationUnknown && + fb_orientation != kOrientationUnknown) { + if (layer_orientation != fb_orientation) { + std::swap(layer_width, layer_height); + } + } + + // Align the width and height according to fb's aspect ratio + *new_mixer_width = FloorToMultipleOf(UINT32((FLOAT(fb_width) / FLOAT(fb_height)) * + layer_height), align_x); + *new_mixer_height = FloorToMultipleOf(layer_height, align_y); + + LayerRect dst_domain = {0.0f, 0.0f, FLOAT(*new_mixer_width), FLOAT(*new_mixer_height)}; + + MapRect(fb_rect, dst_domain, layer->dst_rect, &layer_dst_rect); + if (NeedsDownScale(layer->src_rect, layer_dst_rect, needs_rotation)) { + *new_mixer_width = display_width; + *new_mixer_height = display_height; + } + + return true; + } + + return false; +} + +DisplayError DisplayBase::SetFrameBufferConfig(const DisplayConfigVariableInfo &variable_info) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + uint32_t width = variable_info.x_pixels; + uint32_t height = variable_info.y_pixels; + + if (width == 0 || height == 0) { + DLOGE("Unsupported resolution: (%dx%d)", width, height); + return kErrorParameters; + } + + // Create rects to represent the new source and destination crops + LayerRect crop = LayerRect(0, 0, FLOAT(width), FLOAT(height)); + LayerRect dst = LayerRect(0, 0, FLOAT(mixer_attributes_.width), FLOAT(mixer_attributes_.height)); + // Set rotate90 to false since this is taken care of during regular composition. + bool rotate90 = false; + + DisplayError error = comp_manager_->ValidateScaling(crop, dst, rotate90); + if (error != kErrorNone) { + DLOGE("Unsupported resolution: (%dx%d)", width, height); + return kErrorParameters; + } + + error = comp_manager_->ReconfigureDisplay(display_comp_ctx_, display_attributes_, hw_panel_info_, + mixer_attributes_, variable_info); + if (error != kErrorNone) { + return error; + } + + fb_config_.x_pixels = width; + fb_config_.y_pixels = height; + + DLOGI("New framebuffer resolution (%dx%d)", fb_config_.x_pixels, fb_config_.y_pixels); + + return kErrorNone; +} + +DisplayError DisplayBase::GetFrameBufferConfig(DisplayConfigVariableInfo *variable_info) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + if (!variable_info) { + return kErrorParameters; + } + + *variable_info = fb_config_; + + return kErrorNone; +} + +DisplayError DisplayBase::SetDetailEnhancerData(const DisplayDetailEnhancerData &de_data) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + DisplayError error = comp_manager_->SetDetailEnhancerData(display_comp_ctx_, de_data); + if (error != kErrorNone) { + return error; + } + + DisablePartialUpdateOneFrame(); + + return kErrorNone; +} + +DisplayError DisplayBase::GetDisplayPort(DisplayPort *port) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + + if (!port) { + return kErrorParameters; + } + + *port = hw_panel_info_.port; + + return kErrorNone; +} + +bool DisplayBase::IsPrimaryDisplay() { + lock_guard<recursive_mutex> obj(recursive_mutex_); + + return hw_panel_info_.is_primary_panel; +} + +DisplayError DisplayBase::SetCompositionState(LayerComposition composition_type, bool enable) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + + return comp_manager_->SetCompositionState(display_comp_ctx_, composition_type, enable); +} + +void DisplayBase::CommitLayerParams(LayerStack *layer_stack) { + // Copy the acquire fence from clients layers to HWLayers + uint32_t hw_layers_count = UINT32(hw_layers_.info.hw_layers.size()); + + for (uint32_t i = 0; i < hw_layers_count; i++) { + Layer *sdm_layer = layer_stack->layers.at(hw_layers_.info.index[i]); + Layer &hw_layer = hw_layers_.info.hw_layers.at(i); + + hw_layer.input_buffer.planes[0].fd = sdm_layer->input_buffer.planes[0].fd; + hw_layer.input_buffer.planes[0].offset = sdm_layer->input_buffer.planes[0].offset; + hw_layer.input_buffer.planes[0].stride = sdm_layer->input_buffer.planes[0].stride; + hw_layer.input_buffer.size = sdm_layer->input_buffer.size; + hw_layer.input_buffer.acquire_fence_fd = sdm_layer->input_buffer.acquire_fence_fd; + } + + return; +} + +void DisplayBase::PostCommitLayerParams(LayerStack *layer_stack) { + // Copy the release fence from HWLayers to clients layers + uint32_t hw_layers_count = UINT32(hw_layers_.info.hw_layers.size()); + + std::vector<uint32_t> fence_dup_flag; + + for (uint32_t i = 0; i < hw_layers_count; i++) { + uint32_t sdm_layer_index = hw_layers_.info.index[i]; + Layer *sdm_layer = layer_stack->layers.at(sdm_layer_index); + Layer &hw_layer = hw_layers_.info.hw_layers.at(i); + + // Copy the release fence only once for a SDM Layer. + // In S3D use case, two hw layers can share the same input buffer, So make sure to merge the + // output fence fd and assign it to layer's input buffer release fence fd. + if (std::find(fence_dup_flag.begin(), fence_dup_flag.end(), sdm_layer_index) == + fence_dup_flag.end()) { + sdm_layer->input_buffer.release_fence_fd = hw_layer.input_buffer.release_fence_fd; + fence_dup_flag.push_back(sdm_layer_index); + } else { + int temp = -1; + buffer_sync_handler_->SyncMerge(hw_layer.input_buffer.release_fence_fd, + sdm_layer->input_buffer.release_fence_fd, &temp); + + if (hw_layer.input_buffer.release_fence_fd >= 0) { + Sys::close_(hw_layer.input_buffer.release_fence_fd); + hw_layer.input_buffer.release_fence_fd = -1; + } + + if (sdm_layer->input_buffer.release_fence_fd >= 0) { + Sys::close_(sdm_layer->input_buffer.release_fence_fd); + sdm_layer->input_buffer.release_fence_fd = -1; + } + + sdm_layer->input_buffer.release_fence_fd = temp; + } + } + + return; +} + +DisplayError DisplayBase::InitializeColorModes() { + if (!color_mgr_) { + return kErrorNotSupported; + } + + DisplayError error = color_mgr_->ColorMgrGetNumOfModes(&num_color_modes_); + if (error != kErrorNone || !num_color_modes_) { + DLOGV_IF(kTagQDCM, "GetNumModes failed = %d count = %d", error, num_color_modes_); + return kErrorNotSupported; + } + DLOGI("Number of Color Modes = %d", num_color_modes_); + + if (!color_modes_.size()) { + color_modes_.resize(num_color_modes_); + + DisplayError error = color_mgr_->ColorMgrGetModes(&num_color_modes_, color_modes_.data()); + if (error != kErrorNone) { + color_modes_.clear(); + DLOGE("Failed"); + return error; + } + int32_t default_id = kInvalidModeId; + error = color_mgr_->ColorMgrGetDefaultModeID(&default_id); + + AttrVal var; + for (uint32_t i = 0; i < num_color_modes_; i++) { + DLOGV_IF(kTagQDCM, "Color Mode[%d]: Name = %s mode_id = %d", i, color_modes_[i].name, + color_modes_[i].id); + // get the name of default color mode + if (color_modes_[i].id == default_id) { + current_color_mode_ = color_modes_[i].name; + } + auto it = color_mode_map_.find(color_modes_[i].name); + if (it != color_mode_map_.end()) { + if (it->second->id < color_modes_[i].id) { + color_mode_map_.erase(it); + color_mode_map_.insert(std::make_pair(color_modes_[i].name, &color_modes_[i])); + } + } else { + color_mode_map_.insert(std::make_pair(color_modes_[i].name, &color_modes_[i])); + } + + var.clear(); + error = color_mgr_->ColorMgrGetModeInfo(color_modes_[i].id, &var); + if (error != kErrorNone) { + DLOGE("Failed for get attributes of mode_id = %d", color_modes_[i].id); + continue; + } + if (!var.empty()) { + auto it = color_mode_attr_map_.find(color_modes_[i].name); + if (it == color_mode_attr_map_.end()) { + color_mode_attr_map_.insert(std::make_pair(color_modes_[i].name, var)); + } + } + } + } + + return kErrorNone; +} + +DisplayError DisplayBase::HandleHDR(LayerStack *layer_stack) { + DisplayError error = kErrorNone; + + if (display_type_ != kPrimary) { + // Handling is needed for only primary displays + return kErrorNone; + } + + if (!layer_stack->flags.hdr_present) { + // HDR playback off - set prev mode + if (hdr_playback_mode_) { + hdr_playback_mode_ = false; + if (color_mgr_ && !disable_hdr_lut_gen_) { + // Do not apply HDR Mode when hdr lut generation is disabled + DLOGI("Setting color mode = %s", current_color_mode_.c_str()); + // HDR playback off - set prev mode + error = SetColorModeInternal(current_color_mode_); + } + comp_manager_->ControlDpps(true); // Enable Dpps + } + } else { + // hdr is present + if (!hdr_playback_mode_ && !layer_stack->flags.animating) { + // hdr is starting + hdr_playback_mode_ = true; + if (color_mgr_ && !disable_hdr_lut_gen_) { + std::string hdr_color_mode; + if (IsSupportColorModeAttribute(current_color_mode_)) { + bool found_hdr = false; + error = GetHdrColorMode(&hdr_color_mode, &found_hdr); + // try to set "hal-hdr" mode if did not found that + // the dynamic range of mode is hdr + if (!found_hdr) { + hdr_color_mode = "hal_hdr"; + } + } else { + hdr_color_mode = "hal_hdr"; + } + DLOGI("Setting color mode = %s", hdr_color_mode.c_str()); + error = SetColorModeInternal(hdr_color_mode); + } + comp_manager_->ControlDpps(false); // Disable Dpps + } + } + + return error; +} + + +DisplayError DisplayBase::GetClientTargetSupport(uint32_t width, uint32_t height, + LayerBufferFormat format, + const ColorMetaData &color_metadata) { + if (format != kFormatRGBA8888 && format != kFormatRGBA1010102) { + DLOGW("Unsupported format = %d", format); + return kErrorNotSupported; + } else if (ValidateScaling(width, height) != kErrorNone) { + DLOGW("Unsupported width = %d height = %d", width, height); + return kErrorNotSupported; + } else if (color_metadata.transfer && color_metadata.colorPrimaries) { + DisplayError error = ValidateDataspace(color_metadata); + if (error != kErrorNone) { + DLOGW("Unsupported Transfer Request = %d Color Primary = %d", + color_metadata.transfer, color_metadata.colorPrimaries); + return error; + } + + // Check for BT2020 support + if (color_metadata.colorPrimaries == ColorPrimaries_BT2020) { + DLOGW("Unsupported Color Primary = %d", color_metadata.colorPrimaries); + return kErrorNotSupported; + } + } + + return kErrorNone; +} + +DisplayError DisplayBase::ValidateScaling(uint32_t width, uint32_t height) { + uint32_t display_width = display_attributes_.x_pixels; + uint32_t display_height = display_attributes_.y_pixels; + + HWResourceInfo hw_resource_info = HWResourceInfo(); + hw_info_intf_->GetHWResourceInfo(&hw_resource_info); + float max_scale_down = FLOAT(hw_resource_info.max_scale_down); + float max_scale_up = FLOAT(hw_resource_info.max_scale_up); + + float scale_x = FLOAT(width / display_width); + float scale_y = FLOAT(height / display_height); + + if (scale_x > max_scale_down || scale_y > max_scale_down) { + return kErrorNotSupported; + } + + if (UINT32(scale_x) < 1 && scale_x > 0.0f) { + if ((1.0f / scale_x) > max_scale_up) { + return kErrorNotSupported; + } + } + + if (UINT32(scale_y) < 1 && scale_y > 0.0f) { + if ((1.0f / scale_y) > max_scale_up) { + return kErrorNotSupported; + } + } + + return kErrorNone; +} + +DisplayError DisplayBase::ValidateDataspace(const ColorMetaData &color_metadata) { + // Handle transfer + switch (color_metadata.transfer) { + case Transfer_sRGB: + case Transfer_SMPTE_170M: + case Transfer_SMPTE_ST2084: + case Transfer_HLG: + case Transfer_Linear: + case Transfer_Gamma2_2: + break; + default: + DLOGW("Unsupported Transfer Request = %d", color_metadata.transfer); + return kErrorNotSupported; + } + + // Handle colorPrimaries + switch (color_metadata.colorPrimaries) { + case ColorPrimaries_BT709_5: + case ColorPrimaries_BT601_6_525: + case ColorPrimaries_BT601_6_625: + case ColorPrimaries_DCIP3: + case ColorPrimaries_BT2020: + break; + default: + DLOGW("Unsupported Color Primary = %d", color_metadata.colorPrimaries); + return kErrorNotSupported; + } + + return kErrorNone; +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/core/display_base.h b/msm8909/sdm/libs/core/display_base.h new file mode 100644 index 00000000..e511dac1 --- /dev/null +++ b/msm8909/sdm/libs/core/display_base.h @@ -0,0 +1,184 @@ +/* +* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __DISPLAY_BASE_H__ +#define __DISPLAY_BASE_H__ + +#include <core/display_interface.h> +#include <private/strategy_interface.h> +#include <private/color_interface.h> + +#include <map> +#include <mutex> +#include <string> +#include <vector> + +#include "hw_interface.h" +#include "comp_manager.h" +#include "color_manager.h" +#include "hw_events_interface.h" + +namespace sdm { + +using std::recursive_mutex; +using std::lock_guard; + +class DisplayBase : public DisplayInterface { + public: + DisplayBase(DisplayType display_type, DisplayEventHandler *event_handler, + HWDeviceType hw_device_type, BufferSyncHandler *buffer_sync_handler, + BufferAllocator *buffer_allocator, CompManager *comp_manager, + HWInfoInterface *hw_info_intf); + virtual ~DisplayBase() { } + virtual DisplayError Init(); + virtual DisplayError Deinit(); + DisplayError Prepare(LayerStack *layer_stack); + DisplayError Commit(LayerStack *layer_stack); + virtual DisplayError Flush(); + virtual DisplayError GetDisplayState(DisplayState *state); + virtual DisplayError GetNumVariableInfoConfigs(uint32_t *count); + virtual DisplayError GetConfig(uint32_t index, DisplayConfigVariableInfo *variable_info); + virtual DisplayError GetConfig(DisplayConfigFixedInfo *variable_info); + virtual DisplayError GetActiveConfig(uint32_t *index); + virtual DisplayError GetVSyncState(bool *enabled); + virtual DisplayError SetDisplayState(DisplayState state); + virtual DisplayError SetActiveConfig(uint32_t index); + virtual DisplayError SetActiveConfig(DisplayConfigVariableInfo *variable_info) { + return kErrorNotSupported; + } + virtual DisplayError SetMaxMixerStages(uint32_t max_mixer_stages); + virtual DisplayError ControlPartialUpdate(bool enable, uint32_t *pending) { + return kErrorNotSupported; + } + virtual DisplayError DisablePartialUpdateOneFrame() { + return kErrorNotSupported; + } + virtual DisplayError SetDisplayMode(uint32_t mode) { + return kErrorNotSupported; + } + virtual bool IsUnderscanSupported() { + return false; + } + virtual DisplayError SetPanelBrightness(int level) { + return kErrorNotSupported; + } + virtual DisplayError CachePanelBrightness(int level) { + return kErrorNotSupported; + } + virtual DisplayError OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level) { + return kErrorNotSupported; + } + virtual DisplayError ColorSVCRequestRoute(const PPDisplayAPIPayload &in_payload, + PPDisplayAPIPayload *out_payload, + PPPendingParams *pending_action); + virtual DisplayError GetColorModeCount(uint32_t *mode_count); + virtual DisplayError GetColorModes(uint32_t *mode_count, std::vector<std::string> *color_modes); + virtual DisplayError GetColorModeAttr(const std::string &color_mode, AttrVal *attr); + virtual DisplayError SetColorMode(const std::string &color_mode); + virtual DisplayError SetColorTransform(const uint32_t length, const double *color_transform); + virtual DisplayError GetDefaultColorMode(std::string *color_mode); + virtual DisplayError ApplyDefaultDisplayMode(void); + virtual DisplayError SetCursorPosition(int x, int y); + virtual DisplayError GetRefreshRateRange(uint32_t *min_refresh_rate, uint32_t *max_refresh_rate); + virtual DisplayError GetPanelBrightness(int *level) { + return kErrorNotSupported; + } + virtual DisplayError SetVSyncState(bool enable); + virtual void SetIdleTimeoutMs(uint32_t active_ms) {} + virtual DisplayError SetMixerResolution(uint32_t width, uint32_t height); + virtual DisplayError GetMixerResolution(uint32_t *width, uint32_t *height); + virtual DisplayError SetFrameBufferConfig(const DisplayConfigVariableInfo &variable_info); + virtual DisplayError GetFrameBufferConfig(DisplayConfigVariableInfo *variable_info); + virtual DisplayError SetDetailEnhancerData(const DisplayDetailEnhancerData &de_data); + virtual DisplayError GetDisplayPort(DisplayPort *port); + virtual bool IsPrimaryDisplay(); + virtual DisplayError SetCompositionState(LayerComposition composition_type, bool enable); + virtual DisplayError GetClientTargetSupport(uint32_t width, uint32_t height, + LayerBufferFormat format, + const ColorMetaData &color_metadata); + virtual std::string Dump(); + + protected: + DisplayError BuildLayerStackStats(LayerStack *layer_stack); + virtual DisplayError ValidateGPUTargetParams(); + void CommitLayerParams(LayerStack *layer_stack); + void PostCommitLayerParams(LayerStack *layer_stack); + DisplayError HandleHDR(LayerStack *layer_stack); + DisplayError ValidateScaling(uint32_t width, uint32_t height); + DisplayError ValidateDataspace(const ColorMetaData &color_metadata); + + const char *GetName(const LayerComposition &composition); + DisplayError ReconfigureDisplay(); + bool NeedsMixerReconfiguration(LayerStack *layer_stack, uint32_t *new_mixer_width, + uint32_t *new_mixer_height); + DisplayError ReconfigureMixer(uint32_t width, uint32_t height); + bool NeedsDownScale(const LayerRect &src_rect, const LayerRect &dst_rect, bool needs_rotation); + DisplayError InitializeColorModes(); + DisplayError SetColorModeInternal(const std::string &color_mode); + DisplayError GetValueOfModeAttribute(const AttrVal &attr, const std::string &type, + std::string *value); + DisplayError GetHdrColorMode(std::string *color_mode, bool *found_hdr); + bool IsSupportColorModeAttribute(const std::string &color_mode); + + recursive_mutex recursive_mutex_; + DisplayType display_type_; + DisplayEventHandler *event_handler_ = NULL; + HWDeviceType hw_device_type_; + HWInterface *hw_intf_ = NULL; + HWPanelInfo hw_panel_info_; + BufferSyncHandler *buffer_sync_handler_ = NULL; + BufferAllocator *buffer_allocator_ {}; + CompManager *comp_manager_ = NULL; + DisplayState state_ = kStateOff; + bool active_ = false; + Handle hw_device_ = 0; + Handle display_comp_ctx_ = 0; + HWLayers hw_layers_; + bool needs_validate_ = true; + bool vsync_enable_ = false; + uint32_t max_mixer_stages_ = 0; + HWInfoInterface *hw_info_intf_ = NULL; + ColorManagerProxy *color_mgr_ = NULL; // each display object owns its ColorManagerProxy + bool partial_update_control_ = true; + HWEventsInterface *hw_events_intf_ = NULL; + bool disable_pu_one_frame_ = false; + uint32_t num_color_modes_ = 0; + std::vector<SDEDisplayMode> color_modes_; + typedef std::map<std::string, SDEDisplayMode *> ColorModeMap; + ColorModeMap color_mode_map_ = {}; + typedef std::map<std::string, AttrVal> ColorModeAttrMap; + ColorModeAttrMap color_mode_attr_map_ = {}; + HWDisplayAttributes display_attributes_ = {}; + HWMixerAttributes mixer_attributes_ = {}; + DisplayConfigVariableInfo fb_config_ = {}; + uint32_t req_mixer_width_ = 0; + uint32_t req_mixer_height_ = 0; + std::string current_color_mode_ = "hal_native"; + bool hdr_playback_mode_ = false; + int disable_hdr_lut_gen_ = 0; +}; + +} // namespace sdm + +#endif // __DISPLAY_BASE_H__ diff --git a/msm8909/sdm/libs/core/display_hdmi.cpp b/msm8909/sdm/libs/core/display_hdmi.cpp new file mode 100644 index 00000000..5f8eeb4d --- /dev/null +++ b/msm8909/sdm/libs/core/display_hdmi.cpp @@ -0,0 +1,303 @@ +/* +* Copyright (c) 2014 - 2018, 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 <map> +#include <utility> +#include <vector> + +#include "display_hdmi.h" +#include "hw_interface.h" +#include "hw_info_interface.h" + +#define __CLASS__ "DisplayHDMI" + +namespace sdm { + +DisplayHDMI::DisplayHDMI(DisplayEventHandler *event_handler, HWInfoInterface *hw_info_intf, + BufferSyncHandler *buffer_sync_handler, BufferAllocator *buffer_allocator, + CompManager *comp_manager) + : DisplayBase(kHDMI, event_handler, kDeviceHDMI, buffer_sync_handler, buffer_allocator, + comp_manager, hw_info_intf) { +} + +DisplayError DisplayHDMI::Init() { + lock_guard<recursive_mutex> obj(recursive_mutex_); + + DisplayError error = HWInterface::Create(kHDMI, hw_info_intf_, buffer_sync_handler_, + buffer_allocator_, &hw_intf_); + if (error != kErrorNone) { + return error; + } + + uint32_t active_mode_index; + char value[64] = "0"; + Debug::GetProperty(HDMI_S3D_MODE_PROP, value); + HWS3DMode mode = (HWS3DMode)atoi(value); + if (mode > kS3DModeNone && mode < kS3DModeMax) { + active_mode_index = GetBestConfig(mode); + } else { + active_mode_index = GetBestConfig(kS3DModeNone); + } + + error = hw_intf_->SetDisplayAttributes(active_mode_index); + if (error != kErrorNone) { + HWInterface::Destroy(hw_intf_); + } + + error = DisplayBase::Init(); + if (error != kErrorNone) { + HWInterface::Destroy(hw_intf_); + return error; + } + + GetScanSupport(); + underscan_supported_ = (scan_support_ == kScanAlwaysUnderscanned) || (scan_support_ == kScanBoth); + + s3d_format_to_mode_.insert(std::pair<LayerBufferS3DFormat, HWS3DMode> + (kS3dFormatNone, kS3DModeNone)); + s3d_format_to_mode_.insert(std::pair<LayerBufferS3DFormat, HWS3DMode> + (kS3dFormatLeftRight, kS3DModeLR)); + s3d_format_to_mode_.insert(std::pair<LayerBufferS3DFormat, HWS3DMode> + (kS3dFormatRightLeft, kS3DModeRL)); + s3d_format_to_mode_.insert(std::pair<LayerBufferS3DFormat, HWS3DMode> + (kS3dFormatTopBottom, kS3DModeTB)); + s3d_format_to_mode_.insert(std::pair<LayerBufferS3DFormat, HWS3DMode> + (kS3dFormatFramePacking, kS3DModeFP)); + + error = HWEventsInterface::Create(INT(display_type_), this, event_list_, &hw_events_intf_); + if (error != kErrorNone) { + DisplayBase::Deinit(); + HWInterface::Destroy(hw_intf_); + DLOGE("Failed to create hardware events interface. Error = %d", error); + } + + return error; +} + +DisplayError DisplayHDMI::Prepare(LayerStack *layer_stack) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + DisplayError error = kErrorNone; + uint32_t new_mixer_width = 0; + uint32_t new_mixer_height = 0; + uint32_t display_width = display_attributes_.x_pixels; + uint32_t display_height = display_attributes_.y_pixels; + + if (NeedsMixerReconfiguration(layer_stack, &new_mixer_width, &new_mixer_height)) { + error = ReconfigureMixer(new_mixer_width, new_mixer_height); + if (error != kErrorNone) { + ReconfigureMixer(display_width, display_height); + } + } + + SetS3DMode(layer_stack); + + // Clean hw layers for reuse. + hw_layers_ = HWLayers(); + + return DisplayBase::Prepare(layer_stack); +} + +DisplayError DisplayHDMI::GetRefreshRateRange(uint32_t *min_refresh_rate, + uint32_t *max_refresh_rate) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + DisplayError error = kErrorNone; + + if (hw_panel_info_.min_fps && hw_panel_info_.max_fps) { + *min_refresh_rate = hw_panel_info_.min_fps; + *max_refresh_rate = hw_panel_info_.max_fps; + } else { + error = DisplayBase::GetRefreshRateRange(min_refresh_rate, max_refresh_rate); + } + + return error; +} + +DisplayError DisplayHDMI::SetRefreshRate(uint32_t refresh_rate) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + + if (!active_) { + return kErrorPermission; + } + + DisplayError error = hw_intf_->SetRefreshRate(refresh_rate); + if (error != kErrorNone) { + return error; + } + + return DisplayBase::ReconfigureDisplay(); +} + +bool DisplayHDMI::IsUnderscanSupported() { + lock_guard<recursive_mutex> obj(recursive_mutex_); + return underscan_supported_; +} + +DisplayError DisplayHDMI::OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + return hw_intf_->OnMinHdcpEncryptionLevelChange(min_enc_level); +} + +uint32_t DisplayHDMI::GetBestConfig(HWS3DMode s3d_mode) { + uint32_t best_index = 0, index; + uint32_t num_modes = 0; + + hw_intf_->GetNumDisplayAttributes(&num_modes); + + // Get display attribute for each mode + std::vector<HWDisplayAttributes> attrib(num_modes); + for (index = 0; index < num_modes; index++) { + hw_intf_->GetDisplayAttributes(index, &attrib[index]); + } + + // Select best config for s3d_mode. If s3d is not enabled, s3d_mode is kS3DModeNone + for (index = 0; index < num_modes; index ++) { + if (attrib[index].s3d_config[s3d_mode]) { + break; + } + } + if (index < num_modes) { + best_index = UINT32(index); + for (size_t index = best_index + 1; index < num_modes; index ++) { + if (!attrib[index].s3d_config[s3d_mode]) + continue; + + // From the available configs, select the best + // Ex: 1920x1080@60Hz is better than 1920x1080@30 and 1920x1080@30 is better than 1280x720@60 + if (attrib[index].y_pixels > attrib[best_index].y_pixels) { + best_index = UINT32(index); + } else if (attrib[index].y_pixels == attrib[best_index].y_pixels) { + if (attrib[index].x_pixels > attrib[best_index].x_pixels) { + best_index = UINT32(index); + } else if (attrib[index].x_pixels == attrib[best_index].x_pixels) { + if (attrib[index].vsync_period_ns < attrib[best_index].vsync_period_ns) { + best_index = UINT32(index); + } + } + } + } + } else { + DLOGW("%s, could not support S3D mode from EDID info. S3D mode is %d", + __FUNCTION__, s3d_mode); + } + + // Used for changing HDMI Resolution - override the best with user set config + uint32_t user_config = UINT32(Debug::GetHDMIResolution()); + if (user_config) { + uint32_t config_index = 0; + // For the config, get the corresponding index + DisplayError error = hw_intf_->GetConfigIndex(user_config, &config_index); + if (error == kErrorNone) + return config_index; + } + + return best_index; +} + +void DisplayHDMI::GetScanSupport() { + DisplayError error = kErrorNone; + uint32_t video_format = 0; + uint32_t max_cea_format = 0; + HWScanInfo scan_info = HWScanInfo(); + hw_intf_->GetHWScanInfo(&scan_info); + + uint32_t active_mode_index = 0; + hw_intf_->GetActiveConfig(&active_mode_index); + + error = hw_intf_->GetVideoFormat(active_mode_index, &video_format); + if (error != kErrorNone) { + return; + } + + error = hw_intf_->GetMaxCEAFormat(&max_cea_format); + if (error != kErrorNone) { + return; + } + + // The scan support for a given HDMI TV must be read from scan info corresponding to + // Preferred Timing if the preferred timing of the display is currently active, and if it is + // valid. In all other cases, we must read the scan support from CEA scan info if + // the resolution is a CEA resolution, or from IT scan info for all other resolutions. + if (active_mode_index == 0 && scan_info.pt_scan_support != kScanNotSupported) { + scan_support_ = scan_info.pt_scan_support; + } else if (video_format < max_cea_format) { + scan_support_ = scan_info.cea_scan_support; + } else { + scan_support_ = scan_info.it_scan_support; + } +} + +void DisplayHDMI::SetS3DMode(LayerStack *layer_stack) { + uint32_t s3d_layer_count = 0; + HWS3DMode s3d_mode = kS3DModeNone; + uint32_t layer_count = UINT32(layer_stack->layers.size()); + + // S3D mode is supported for the following scenarios: + // 1. Layer stack containing only one s3d layer which is not skip + // 2. Layer stack containing only one secure layer along with one s3d layer + for (uint32_t i = 0; i < layer_count; i++) { + Layer *layer = layer_stack->layers.at(i); + LayerBuffer &layer_buffer = layer->input_buffer; + + if (layer_buffer.s3d_format != kS3dFormatNone) { + s3d_layer_count++; + if (s3d_layer_count > 1 || layer->flags.skip) { + s3d_mode = kS3DModeNone; + break; + } + + std::map<LayerBufferS3DFormat, HWS3DMode>::iterator it = + s3d_format_to_mode_.find(layer_buffer.s3d_format); + if (it != s3d_format_to_mode_.end()) { + s3d_mode = it->second; + } + } else if (layer_buffer.flags.secure && layer_count > 2) { + s3d_mode = kS3DModeNone; + break; + } + } + + if (hw_intf_->SetS3DMode(s3d_mode) != kErrorNone) { + hw_intf_->SetS3DMode(kS3DModeNone); + layer_stack->flags.s3d_mode_present = false; + } else if (s3d_mode != kS3DModeNone) { + layer_stack->flags.s3d_mode_present = true; + } + + DisplayBase::ReconfigureDisplay(); +} + +DisplayError DisplayHDMI::VSync(int64_t timestamp) { + if (vsync_enable_) { + DisplayEventVSync vsync; + vsync.timestamp = timestamp; + event_handler_->VSync(vsync); + } + + return kErrorNone; +} + +} // namespace sdm + diff --git a/msm8909/sdm/libs/core/display_hdmi.h b/msm8909/sdm/libs/core/display_hdmi.h new file mode 100644 index 00000000..4758b043 --- /dev/null +++ b/msm8909/sdm/libs/core/display_hdmi.h @@ -0,0 +1,71 @@ +/* +* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __DISPLAY_HDMI_H__ +#define __DISPLAY_HDMI_H__ + +#include <vector> +#include <map> + +#include "display_base.h" +#include "hw_events_interface.h" + +namespace sdm { + +class HWHDMIInterface; + +class DisplayHDMI : public DisplayBase, HWEventHandler { + public: + DisplayHDMI(DisplayEventHandler *event_handler, HWInfoInterface *hw_info_intf, + BufferSyncHandler *buffer_sync_handler, BufferAllocator *buffer_allocator, + CompManager *comp_manager); + virtual DisplayError Init(); + virtual DisplayError Prepare(LayerStack *layer_stack); + virtual DisplayError GetRefreshRateRange(uint32_t *min_refresh_rate, uint32_t *max_refresh_rate); + virtual DisplayError SetRefreshRate(uint32_t refresh_rate); + virtual bool IsUnderscanSupported(); + virtual DisplayError OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level); + + // Implement the HWEventHandlers + virtual DisplayError VSync(int64_t timestamp); + virtual DisplayError Blank(bool blank) { return kErrorNone; } + virtual void IdleTimeout() { } + virtual void ThermalEvent(int64_t thermal_level) { } + virtual void IdlePowerCollapse() { } + + private: + uint32_t GetBestConfig(HWS3DMode s3d_mode); + void GetScanSupport(); + void SetS3DMode(LayerStack *layer_stack); + + bool underscan_supported_ = false; + HWScanSupport scan_support_; + std::map<LayerBufferS3DFormat, HWS3DMode> s3d_format_to_mode_; + std::vector<HWEvent> event_list_ = { HWEvent::VSYNC, HWEvent::IDLE_NOTIFY, HWEvent::EXIT + }; +}; + +} // namespace sdm + +#endif // __DISPLAY_HDMI_H__ diff --git a/msm8909/sdm/libs/core/display_primary.cpp b/msm8909/sdm/libs/core/display_primary.cpp new file mode 100644 index 00000000..af212975 --- /dev/null +++ b/msm8909/sdm/libs/core/display_primary.cpp @@ -0,0 +1,338 @@ +/* +* Copyright (c) 2014 - 2017, 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 <utils/rect.h> +#include <map> +#include <algorithm> +#include <functional> +#include <vector> + +#include "display_primary.h" +#include "hw_interface.h" +#include "hw_info_interface.h" + +#define __CLASS__ "DisplayPrimary" + +namespace sdm { + +DisplayPrimary::DisplayPrimary(DisplayEventHandler *event_handler, HWInfoInterface *hw_info_intf, + BufferSyncHandler *buffer_sync_handler, + BufferAllocator *buffer_allocator, CompManager *comp_manager) + : DisplayBase(kPrimary, event_handler, kDevicePrimary, buffer_sync_handler, buffer_allocator, + comp_manager, hw_info_intf) { +} + +DisplayError DisplayPrimary::Init() { + lock_guard<recursive_mutex> obj(recursive_mutex_); + + DisplayError error = HWInterface::Create(kPrimary, hw_info_intf_, buffer_sync_handler_, + buffer_allocator_, &hw_intf_); + if (error != kErrorNone) { + return error; + } + + error = DisplayBase::Init(); + if (error != kErrorNone) { + HWInterface::Destroy(hw_intf_); + return error; + } + + if (hw_panel_info_.mode == kModeCommand && Debug::IsVideoModeEnabled()) { + error = hw_intf_->SetDisplayMode(kModeVideo); + if (error != kErrorNone) { + DLOGW("Retaining current display mode. Current = %d, Requested = %d", hw_panel_info_.mode, + kModeVideo); + } + } + + avr_prop_disabled_ = Debug::IsAVRDisabled(); + + error = HWEventsInterface::Create(INT(display_type_), this, event_list_, &hw_events_intf_); + if (error != kErrorNone) { + DLOGE("Failed to create hardware events interface. Error = %d", error); + DisplayBase::Deinit(); + HWInterface::Destroy(hw_intf_); + } + + return error; +} + +DisplayError DisplayPrimary::Prepare(LayerStack *layer_stack) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + DisplayError error = kErrorNone; + uint32_t new_mixer_width = 0; + uint32_t new_mixer_height = 0; + uint32_t display_width = display_attributes_.x_pixels; + uint32_t display_height = display_attributes_.y_pixels; + + if (NeedsMixerReconfiguration(layer_stack, &new_mixer_width, &new_mixer_height)) { + error = ReconfigureMixer(new_mixer_width, new_mixer_height); + if (error != kErrorNone) { + ReconfigureMixer(display_width, display_height); + } + } + + // Clean hw layers for reuse. + hw_layers_ = HWLayers(); + hw_layers_.hw_avr_info.enable = NeedsAVREnable(); + + return DisplayBase::Prepare(layer_stack); +} + +DisplayError DisplayPrimary::Commit(LayerStack *layer_stack) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + DisplayError error = kErrorNone; + uint32_t app_layer_count = hw_layers_.info.app_layer_count; + + // Enabling auto refresh is async and needs to happen before commit ioctl + if (hw_panel_info_.mode == kModeCommand) { + bool enable = (app_layer_count == 1) && layer_stack->flags.single_buffered_layer_present; + bool need_refresh = layer_stack->flags.single_buffered_layer_present && (app_layer_count > 1); + + hw_intf_->SetAutoRefresh(enable); + if (need_refresh) { + event_handler_->Refresh(); + } + } + + error = DisplayBase::Commit(layer_stack); + if (error != kErrorNone) { + return error; + } + + DisplayBase::ReconfigureDisplay(); + + int idle_time_ms = hw_layers_.info.set_idle_time_ms; + if (idle_time_ms >= 0) { + hw_intf_->SetIdleTimeoutMs(UINT32(idle_time_ms)); + } + + if (switch_to_cmd_) { + uint32_t pending; + switch_to_cmd_ = false; + ControlPartialUpdate(true /* enable */, &pending); + } + + return error; +} + +DisplayError DisplayPrimary::SetDisplayState(DisplayState state) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + DisplayError error = kErrorNone; + error = DisplayBase::SetDisplayState(state); + if (error != kErrorNone) { + return error; + } + + // Set vsync enable state to false, as driver disables vsync during display power off. + if (state == kStateOff) { + vsync_enable_ = false; + } + + return kErrorNone; +} + +void DisplayPrimary::SetIdleTimeoutMs(uint32_t active_ms) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + + if (comp_manager_->SetIdleTimeoutMs(display_comp_ctx_, active_ms) == kErrorNone) { + hw_intf_->SetIdleTimeoutMs(active_ms); + } +} + +DisplayError DisplayPrimary::SetDisplayMode(uint32_t mode) { + DisplayError error = kErrorNone; + + // Limit scope of mutex to this block + { + lock_guard<recursive_mutex> obj(recursive_mutex_); + HWDisplayMode hw_display_mode = static_cast<HWDisplayMode>(mode); + uint32_t pending = 0; + + if (!active_) { + DLOGW("Invalid display state = %d. Panel must be on.", state_); + return kErrorNotSupported; + } + + if (hw_display_mode != kModeCommand && hw_display_mode != kModeVideo) { + DLOGW("Invalid panel mode parameters. Requested = %d", hw_display_mode); + return kErrorParameters; + } + + if (hw_display_mode == hw_panel_info_.mode) { + DLOGW("Same display mode requested. Current = %d, Requested = %d", hw_panel_info_.mode, + hw_display_mode); + return kErrorNone; + } + + error = hw_intf_->SetDisplayMode(hw_display_mode); + if (error != kErrorNone) { + DLOGW("Retaining current display mode. Current = %d, Requested = %d", hw_panel_info_.mode, + hw_display_mode); + return error; + } + + if (mode == kModeVideo) { + ControlPartialUpdate(false /* enable */, &pending); + } else if (mode == kModeCommand) { + // Flush idle timeout value currently set. + hw_intf_->SetIdleTimeoutMs(0); + switch_to_cmd_ = true; + } + } + + // Request for a new draw cycle. New display mode will get applied on next draw cycle. + // New idle time will get configured as part of this. + event_handler_->Refresh(); + + return error; +} + +DisplayError DisplayPrimary::SetPanelBrightness(int level) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + return hw_intf_->SetPanelBrightness(level); +} + +DisplayError DisplayPrimary::CachePanelBrightness(int level) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + return hw_intf_->CachePanelBrightness(level); +} + +DisplayError DisplayPrimary::GetRefreshRateRange(uint32_t *min_refresh_rate, + uint32_t *max_refresh_rate) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + DisplayError error = kErrorNone; + + if (hw_panel_info_.min_fps && hw_panel_info_.max_fps) { + *min_refresh_rate = hw_panel_info_.min_fps; + *max_refresh_rate = hw_panel_info_.max_fps; + } else { + error = DisplayBase::GetRefreshRateRange(min_refresh_rate, max_refresh_rate); + } + + return error; +} + +DisplayError DisplayPrimary::SetRefreshRate(uint32_t refresh_rate) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + + if (!active_ || !hw_panel_info_.dynamic_fps) { + return kErrorNotSupported; + } + + if (refresh_rate < hw_panel_info_.min_fps || refresh_rate > hw_panel_info_.max_fps) { + DLOGE("Invalid Fps = %d request", refresh_rate); + return kErrorParameters; + } + + DisplayError error = hw_intf_->SetRefreshRate(refresh_rate); + if (error != kErrorNone) { + return error; + } + + return DisplayBase::ReconfigureDisplay(); +} + +DisplayError DisplayPrimary::VSync(int64_t timestamp) { + if (vsync_enable_) { + DisplayEventVSync vsync; + vsync.timestamp = timestamp; + event_handler_->VSync(vsync); + } + + return kErrorNone; +} + +void DisplayPrimary::IdleTimeout() { + event_handler_->Refresh(); + comp_manager_->ProcessIdleTimeout(display_comp_ctx_); + event_handler_->HandleEvent(kIdleTimeout); +} + +void DisplayPrimary::ThermalEvent(int64_t thermal_level) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + comp_manager_->ProcessThermalEvent(display_comp_ctx_, thermal_level); + event_handler_->HandleEvent(kThermalEvent); +} + +void DisplayPrimary::IdlePowerCollapse() { + lock_guard<recursive_mutex> obj(recursive_mutex_); + comp_manager_->ProcessIdlePowerCollapse(display_comp_ctx_); +} + +DisplayError DisplayPrimary::GetPanelBrightness(int *level) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + return hw_intf_->GetPanelBrightness(level); +} + +DisplayError DisplayPrimary::ControlPartialUpdate(bool enable, uint32_t *pending) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + if (!pending) { + return kErrorParameters; + } + + if (!hw_panel_info_.partial_update) { + // Nothing to be done. + DLOGI("partial update is not applicable for display=%d", display_type_); + return kErrorNotSupported; + } + + *pending = 0; + if (enable == partial_update_control_) { + DLOGI("Same state transition is requested."); + return kErrorNone; + } + + partial_update_control_ = enable; + + if (!enable) { + // If the request is to turn off feature, new draw call is required to have + // the new setting into effect. + *pending = 1; + } + + return kErrorNone; +} + +DisplayError DisplayPrimary::DisablePartialUpdateOneFrame() { + lock_guard<recursive_mutex> obj(recursive_mutex_); + disable_pu_one_frame_ = true; + + return kErrorNone; +} + +bool DisplayPrimary::NeedsAVREnable() { + if (avr_prop_disabled_) { + return false; + } + + return (hw_panel_info_.mode == kModeVideo && ((hw_panel_info_.dynamic_fps && + hw_panel_info_.dfps_porch_mode) || (!hw_panel_info_.dynamic_fps && + hw_panel_info_.min_fps != hw_panel_info_.max_fps))); +} + +} // namespace sdm + diff --git a/msm8909/sdm/libs/core/display_primary.h b/msm8909/sdm/libs/core/display_primary.h new file mode 100644 index 00000000..7cb20e54 --- /dev/null +++ b/msm8909/sdm/libs/core/display_primary.h @@ -0,0 +1,75 @@ +/* +* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __DISPLAY_PRIMARY_H__ +#define __DISPLAY_PRIMARY_H__ + +#include <vector> + +#include "display_base.h" +#include "hw_events_interface.h" + +namespace sdm { + +class HWPrimaryInterface; + +class DisplayPrimary : public DisplayBase, HWEventHandler { + public: + DisplayPrimary(DisplayEventHandler *event_handler, HWInfoInterface *hw_info_intf, + BufferSyncHandler *buffer_sync_handler, BufferAllocator *buffer_allocator, + CompManager *comp_manager); + virtual DisplayError Init(); + virtual DisplayError Prepare(LayerStack *layer_stack); + virtual DisplayError Commit(LayerStack *layer_stack); + virtual DisplayError ControlPartialUpdate(bool enable, uint32_t *pending); + virtual DisplayError DisablePartialUpdateOneFrame(); + virtual DisplayError SetDisplayState(DisplayState state); + virtual void SetIdleTimeoutMs(uint32_t active_ms); + virtual DisplayError SetDisplayMode(uint32_t mode); + virtual DisplayError GetRefreshRateRange(uint32_t *min_refresh_rate, uint32_t *max_refresh_rate); + virtual DisplayError SetRefreshRate(uint32_t refresh_rate); + virtual DisplayError SetPanelBrightness(int level); + virtual DisplayError GetPanelBrightness(int *level); + virtual DisplayError CachePanelBrightness(int level); + + // Implement the HWEventHandlers + virtual DisplayError VSync(int64_t timestamp); + virtual DisplayError Blank(bool blank) { return kErrorNone; } + virtual void IdleTimeout(); + virtual void ThermalEvent(int64_t thermal_level); + virtual void IdlePowerCollapse(); + + private: + bool NeedsAVREnable(); + + std::vector<HWEvent> event_list_ = { HWEvent::VSYNC, HWEvent::EXIT, HWEvent::IDLE_NOTIFY, + HWEvent::SHOW_BLANK_EVENT, HWEvent::THERMAL_LEVEL, HWEvent::IDLE_POWER_COLLAPSE }; + bool avr_prop_disabled_ = false; + bool switch_to_cmd_ = false; +}; + +} // namespace sdm + +#endif // __DISPLAY_PRIMARY_H__ + diff --git a/msm8909/sdm/libs/core/display_virtual.cpp b/msm8909/sdm/libs/core/display_virtual.cpp new file mode 100644 index 00000000..fcdc152b --- /dev/null +++ b/msm8909/sdm/libs/core/display_virtual.cpp @@ -0,0 +1,141 @@ +/* +* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <utils/constants.h> +#include <utils/debug.h> + +#include "display_virtual.h" +#include "hw_interface.h" +#include "hw_info_interface.h" + +#define __CLASS__ "DisplayVirtual" + +namespace sdm { + +DisplayVirtual::DisplayVirtual(DisplayEventHandler *event_handler, HWInfoInterface *hw_info_intf, + BufferSyncHandler *buffer_sync_handler, + BufferAllocator *buffer_allocator, CompManager *comp_manager) + : DisplayBase(kVirtual, event_handler, kDeviceVirtual, buffer_sync_handler, buffer_allocator, + comp_manager, hw_info_intf) { +} + +DisplayError DisplayVirtual::Init() { + lock_guard<recursive_mutex> obj(recursive_mutex_); + + DisplayError error = HWInterface::Create(kVirtual, hw_info_intf_, buffer_sync_handler_, + buffer_allocator_, &hw_intf_); + if (error != kErrorNone) { + return error; + } + + hw_intf_->GetDisplayAttributes(0 /* active_index */, &display_attributes_); + + error = DisplayBase::Init(); + if (error != kErrorNone) { + HWInterface::Destroy(hw_intf_); + } + + return error; +} + +DisplayError DisplayVirtual::GetNumVariableInfoConfigs(uint32_t *count) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + *count = 1; + return kErrorNone; +} + +DisplayError DisplayVirtual::GetConfig(uint32_t index, DisplayConfigVariableInfo *variable_info) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + *variable_info = display_attributes_; + return kErrorNone; +} + +DisplayError DisplayVirtual::GetActiveConfig(uint32_t *index) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + *index = 0; + return kErrorNone; +} + +DisplayError DisplayVirtual::SetActiveConfig(DisplayConfigVariableInfo *variable_info) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + + if (!variable_info) { + return kErrorParameters; + } + + DisplayError error = kErrorNone; + HWDisplayAttributes display_attributes; + HWMixerAttributes mixer_attributes; + + display_attributes.x_pixels = variable_info->x_pixels; + display_attributes.y_pixels = variable_info->y_pixels; + display_attributes.fps = variable_info->fps; + + if (display_attributes == display_attributes_) { + return kErrorNone; + } + + error = hw_intf_->SetDisplayAttributes(display_attributes); + if (error != kErrorNone) { + return error; + } + + error = hw_intf_->GetMixerAttributes(&mixer_attributes); + if (error != kErrorNone) { + return error; + } + + // if display is already connected, unregister display from composition manager and register + // the display with new configuration. + if (display_comp_ctx_) { + comp_manager_->UnregisterDisplay(display_comp_ctx_); + } + + error = comp_manager_->RegisterDisplay(display_type_, display_attributes, hw_panel_info_, + mixer_attributes, fb_config_, &display_comp_ctx_); + if (error != kErrorNone) { + return error; + } + + display_attributes_ = display_attributes; + mixer_attributes_ = mixer_attributes; + + DLOGI("Virtual display resolution changed to[%dx%d]", display_attributes_.x_pixels, + display_attributes_.y_pixels); + + return kErrorNone; +} + +DisplayError DisplayVirtual::Prepare(LayerStack *layer_stack) { + lock_guard<recursive_mutex> obj(recursive_mutex_); + + // Clean hw layers for reuse. + hw_layers_ = HWLayers(); + + return DisplayBase::Prepare(layer_stack); +} + + +} // namespace sdm + diff --git a/msm8909/sdm/libs/core/display_virtual.h b/msm8909/sdm/libs/core/display_virtual.h new file mode 100644 index 00000000..ad0aecb3 --- /dev/null +++ b/msm8909/sdm/libs/core/display_virtual.h @@ -0,0 +1,74 @@ +/* +* 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 __DISPLAY_VIRTUAL_H__ +#define __DISPLAY_VIRTUAL_H__ + +#include <private/hw_info_types.h> +#include "display_base.h" + +namespace sdm { + +class HWVirtualInterface; + +class DisplayVirtual : public DisplayBase { + public: + DisplayVirtual(DisplayEventHandler *event_handler, HWInfoInterface *hw_info_intf, + BufferSyncHandler *buffer_sync_handler, BufferAllocator *buffer_allocator, + CompManager *comp_manager); + virtual DisplayError Init(); + virtual DisplayError Prepare(LayerStack *layer_stack); + virtual DisplayError GetNumVariableInfoConfigs(uint32_t *count); + virtual DisplayError GetConfig(uint32_t index, DisplayConfigVariableInfo *variable_info); + virtual DisplayError GetActiveConfig(uint32_t *index); + virtual DisplayError SetActiveConfig(uint32_t index) { + return kErrorNotSupported; + } + virtual DisplayError SetActiveConfig(DisplayConfigVariableInfo *variable_info); + virtual DisplayError SetMixerResolution(uint32_t width, uint32_t height) { + return kErrorNotSupported; + } + virtual DisplayError SetVSyncState(bool enable) { + return kErrorNotSupported; + } + virtual DisplayError SetRefreshRate(uint32_t refresh_rate) { + return kErrorNotSupported; + } + virtual DisplayError GetMixerResolution(uint32_t *width, uint32_t *height) { + return kErrorNotSupported; + } + virtual DisplayError SetDetailEnhancerData(const DisplayDetailEnhancerData &de_data) { + return kErrorNotSupported; + } + virtual DisplayError ValidateGPUTargetParams() { + // TODO(user): Validate GPU target for virtual display when query display attributes + // on virtual display is functional. + return kErrorNone; + } +}; + +} // namespace sdm + +#endif // __DISPLAY_VIRTUAL_H__ + diff --git a/msm8909/sdm/libs/core/drm/hw_color_manager_drm.cpp b/msm8909/sdm/libs/core/drm/hw_color_manager_drm.cpp new file mode 100644 index 00000000..640a8432 --- /dev/null +++ b/msm8909/sdm/libs/core/drm/hw_color_manager_drm.cpp @@ -0,0 +1,294 @@ +/* +* Copyright (c) 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define __CLASS__ "HWColorManagerDRM" + +#ifdef PP_DRM_ENABLE +#include <drm/msm_drm_pp.h> +#endif +#include <utils/debug.h> +#include "hw_color_manager_drm.h" + +using sde_drm::kFeaturePcc; +using sde_drm::kFeatureIgc; +using sde_drm::kFeaturePgc; +using sde_drm::kFeatureMixerGc; +using sde_drm::kFeaturePaV2; +using sde_drm::kFeatureDither; +using sde_drm::kFeatureGamut; +using sde_drm::kFeaturePADither; +using sde_drm::kPPFeaturesMax; + +#ifdef PP_DRM_ENABLE +static const uint32_t kPgcDataMask = 0x3FF; +static const uint32_t kPgcShift = 16; +#endif + +namespace sdm { + +DisplayError (*HWColorManagerDrm::GetDrmFeature[])(const PPFeatureInfo &, DRMPPFeatureInfo *) = { + [kGlobalColorFeaturePcc] = &HWColorManagerDrm::GetDrmPCC, + [kGlobalColorFeatureIgc] = &HWColorManagerDrm::GetDrmIGC, + [kGlobalColorFeaturePgc] = &HWColorManagerDrm::GetDrmPGC, + [kMixerColorFeatureGc] = &HWColorManagerDrm::GetDrmMixerGC, + [kGlobalColorFeaturePaV2] = &HWColorManagerDrm::GetDrmPAV2, + [kGlobalColorFeatureDither] = &HWColorManagerDrm::GetDrmDither, + [kGlobalColorFeatureGamut] = &HWColorManagerDrm::GetDrmGamut, + [kGlobalColorFeaturePADither] = &HWColorManagerDrm::GetDrmPADither, +}; + +void HWColorManagerDrm::FreeDrmFeatureData(DRMPPFeatureInfo *feature) { + if (feature->payload) + free(feature->payload); +} + +uint32_t HWColorManagerDrm::GetFeatureVersion(const DRMPPFeatureInfo &feature) { + uint32_t version = PPFeatureVersion::kSDEPpVersionInvalid; + + switch (feature.id) { + case kFeaturePcc: + break; + case kFeatureIgc: + break; + case kFeaturePgc: + if (feature.version == 1) + version = PPFeatureVersion::kSDEPgcV17; + break; + case kFeatureMixerGc: + break; + case kFeaturePaV2: + break; + case kFeatureDither: + break; + case kFeatureGamut: + if (feature.version == 1) + version = PPFeatureVersion::kSDEGamutV17; + else if (feature.version == 4) + version = PPFeatureVersion::kSDEGamutV4; + break; + case kFeaturePADither: + break; + default: + break; + } + return version; +} + +DRMPPFeatureID HWColorManagerDrm::ToDrmFeatureId(uint32_t id) { + DRMPPFeatureID ret = kPPFeaturesMax; + + switch (id) { + case kGlobalColorFeaturePcc: + ret = kFeaturePcc; + break; + case kGlobalColorFeatureIgc: + ret = kFeatureIgc; + break; + case kGlobalColorFeaturePgc: + ret = kFeaturePgc; + break; + case kMixerColorFeatureGc: + ret = kFeatureMixerGc; + break; + case kGlobalColorFeaturePaV2: + ret = kFeaturePaV2; + break; + case kGlobalColorFeatureDither: + ret = kFeatureDither; + break; + case kGlobalColorFeatureGamut: + ret = kFeatureGamut; + break; + case kGlobalColorFeaturePADither: + ret = kFeaturePADither; + break; + default: + break; + } + return ret; +} + +DisplayError HWColorManagerDrm::GetDrmPCC(const PPFeatureInfo &in_data, + DRMPPFeatureInfo *out_data) { + DisplayError ret = kErrorNone; + return ret; +} + +DisplayError HWColorManagerDrm::GetDrmIGC(const PPFeatureInfo &in_data, + DRMPPFeatureInfo *out_data) { + DisplayError ret = kErrorNone; + return ret; +} + +DisplayError HWColorManagerDrm::GetDrmPGC(const PPFeatureInfo &in_data, + DRMPPFeatureInfo *out_data) { + DisplayError ret = kErrorNone; +#ifdef PP_DRM_ENABLE + struct SDEPgcLUTData *sde_pgc; + struct drm_msm_pgc_lut *mdp_pgc; + + if (!out_data) { + DLOGE("Invalid input parameter for gamut"); + return kErrorParameters; + } + sde_pgc = (struct SDEPgcLUTData *)in_data.GetConfigData(); + out_data->id = kFeaturePgc; + out_data->type = sde_drm::kPropBlob; + out_data->version = in_data.feature_version_; + out_data->payload_size = sizeof(struct drm_msm_pgc_lut); + + if (in_data.enable_flags_ & kOpsDisable) { + /* feature disable case */ + out_data->payload = NULL; + return ret; + } else if (!(in_data.enable_flags_ & kOpsEnable)) { + out_data->payload = NULL; + return kErrorParameters; + } + + mdp_pgc = new drm_msm_pgc_lut(); + if (!mdp_pgc) { + DLOGE("Failed to allocate memory for pgc"); + return kErrorMemory; + } + + if (in_data.enable_flags_ & kOpsEnable) + mdp_pgc->flags = PGC_8B_ROUND; + else + mdp_pgc->flags = 0; + + for (int i = 0, j = 0; i < PGC_TBL_LEN; i++, j += 2) { + mdp_pgc->c0[i] = (sde_pgc->c0_data[j] & kPgcDataMask) | + (sde_pgc->c0_data[j + 1] & kPgcDataMask) << kPgcShift; + mdp_pgc->c1[i] = (sde_pgc->c1_data[j] & kPgcDataMask) | + (sde_pgc->c1_data[j + 1] & kPgcDataMask) << kPgcShift; + mdp_pgc->c2[i] = (sde_pgc->c2_data[j] & kPgcDataMask) | + (sde_pgc->c2_data[j + 1] & kPgcDataMask) << kPgcShift; + } + out_data->payload = mdp_pgc; +#endif + return ret; +} + +DisplayError HWColorManagerDrm::GetDrmMixerGC(const PPFeatureInfo &in_data, + DRMPPFeatureInfo *out_data) { + DisplayError ret = kErrorNone; + return ret; +} + +DisplayError HWColorManagerDrm::GetDrmPAV2(const PPFeatureInfo &in_data, + DRMPPFeatureInfo *out_data) { + DisplayError ret = kErrorNone; + return ret; +} + +DisplayError HWColorManagerDrm::GetDrmDither(const PPFeatureInfo &in_data, + DRMPPFeatureInfo *out_data) { + DisplayError ret = kErrorNone; + return ret; +} + +DisplayError HWColorManagerDrm::GetDrmGamut(const PPFeatureInfo &in_data, + DRMPPFeatureInfo *out_data) { + DisplayError ret = kErrorNone; +#ifdef PP_DRM_ENABLE + struct SDEGamutCfg *sde_gamut = NULL; + struct drm_msm_3d_gamut *mdp_gamut = NULL; + uint32_t size = 0; + + if (!out_data) { + DLOGE("Invalid input parameter for gamut"); + return kErrorParameters; + } + sde_gamut = (struct SDEGamutCfg *)in_data.GetConfigData(); + out_data->id = kFeatureGamut; + out_data->type = sde_drm::kPropBlob; + out_data->version = in_data.feature_version_; + out_data->payload_size = sizeof(struct drm_msm_3d_gamut); + if (in_data.enable_flags_ & kOpsDisable) { + /* feature disable case */ + out_data->payload = NULL; + return ret; + } else if (!(in_data.enable_flags_ & kOpsEnable)) { + out_data->payload = NULL; + return kErrorParameters; + } + + mdp_gamut = new drm_msm_3d_gamut(); + if (!mdp_gamut) { + DLOGE("Failed to allocate memory for gamut"); + return kErrorMemory; + } + + if (sde_gamut->map_en) + mdp_gamut->flags = GAMUT_3D_MAP_EN; + else + mdp_gamut->flags = 0; + + switch (sde_gamut->mode) { + case SDEGamutCfgWrapper::GAMUT_FINE_MODE: + mdp_gamut->mode = GAMUT_3D_MODE_17; + size = GAMUT_3D_MODE17_TBL_SZ; + break; + case SDEGamutCfgWrapper::GAMUT_COARSE_MODE: + mdp_gamut->mode = GAMUT_3D_MODE_5; + size = GAMUT_3D_MODE5_TBL_SZ; + break; + case SDEGamutCfgWrapper::GAMUT_COARSE_MODE_13: + mdp_gamut->mode = GAMUT_3D_MODE_13; + size = GAMUT_3D_MODE13_TBL_SZ; + break; + default: + DLOGE("Invalid gamut mode %d", sde_gamut->mode); + free(mdp_gamut); + return kErrorParameters; + } + + if (sde_gamut->map_en) + std::memcpy(mdp_gamut->scale_off, sde_gamut->scale_off_data, + sizeof(uint32_t) * GAMUT_3D_SCALE_OFF_SZ * GAMUT_3D_SCALE_OFF_TBL_NUM); + + for (uint32_t row = 0; row < GAMUT_3D_TBL_NUM; row++) { + for (uint32_t col = 0; col < size; col++) { + mdp_gamut->col[row][col].c0 = sde_gamut->c0_data[row][col]; + mdp_gamut->col[row][col].c2_c1 = sde_gamut->c1_c2_data[row][col]; + } + } + out_data->payload = mdp_gamut; +#endif + return ret; +} + +DisplayError HWColorManagerDrm::GetDrmPADither(const PPFeatureInfo &in_data, + DRMPPFeatureInfo *out_data) { + DisplayError ret = kErrorNone; + return ret; +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/core/drm/hw_color_manager_drm.h b/msm8909/sdm/libs/core/drm/hw_color_manager_drm.h new file mode 100644 index 00000000..a10d00bb --- /dev/null +++ b/msm8909/sdm/libs/core/drm/hw_color_manager_drm.h @@ -0,0 +1,64 @@ +/* +* Copyright (c) 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __HW_COLOR_MANAGER_DRM_H__ +#define __HW_COLOR_MANAGER_DRM_H__ + +#include <drm_interface.h> +#include <private/color_params.h> + +using sde_drm::DRMPPFeatureID; +using sde_drm::DRMPPFeatureInfo; + +namespace sdm { + +class HWColorManagerDrm { + public: + static DisplayError (*GetDrmFeature[kMaxNumPPFeatures])(const PPFeatureInfo &in_data, + DRMPPFeatureInfo *out_data); + static void FreeDrmFeatureData(DRMPPFeatureInfo *feature); + static uint32_t GetFeatureVersion(const DRMPPFeatureInfo &feature); + static DRMPPFeatureID ToDrmFeatureId(uint32_t id); + protected: + HWColorManagerDrm() {} + + private: + static DisplayError GetDrmPCC(const PPFeatureInfo &in_data, DRMPPFeatureInfo *out_data); + static DisplayError GetDrmIGC(const PPFeatureInfo &in_data, DRMPPFeatureInfo *out_data); + static DisplayError GetDrmPGC(const PPFeatureInfo &in_data, DRMPPFeatureInfo *out_data); + static DisplayError GetDrmMixerGC(const PPFeatureInfo &in_data, DRMPPFeatureInfo *out_data); + static DisplayError GetDrmPAV2(const PPFeatureInfo &in_data, DRMPPFeatureInfo *out_data); + static DisplayError GetDrmDither(const PPFeatureInfo &in_data, DRMPPFeatureInfo *out_data); + static DisplayError GetDrmGamut(const PPFeatureInfo &in_data, DRMPPFeatureInfo *out_data); + static DisplayError GetDrmPADither(const PPFeatureInfo &in_data, DRMPPFeatureInfo *out_data); +}; + +} // namespace sdm + +#endif // __HW_COLOR_MANAGER_DRM_H__ diff --git a/msm8909/sdm/libs/core/drm/hw_device_drm.cpp b/msm8909/sdm/libs/core/drm/hw_device_drm.cpp new file mode 100644 index 00000000..400856ca --- /dev/null +++ b/msm8909/sdm/libs/core/drm/hw_device_drm.cpp @@ -0,0 +1,1061 @@ +/* +* Copyright (c) 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define __STDC_FORMAT_MACROS + +#include <ctype.h> +#include <drm/drm_fourcc.h> +#include <drm_lib_loader.h> +#include <drm_master.h> +#include <drm_res_mgr.h> +#include <fcntl.h> +#include <inttypes.h> +#include <linux/fb.h> +#include <math.h> +#include <stdio.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <utils/constants.h> +#include <utils/debug.h> +#include <utils/formats.h> +#include <utils/sys.h> +#include <private/color_params.h> + +#include <algorithm> +#include <string> +#include <unordered_map> +#include <utility> +#include <vector> + +#include "hw_device_drm.h" +#include "hw_info_interface.h" +#include "hw_color_manager_drm.h" + +#define __CLASS__ "HWDeviceDRM" + +#ifndef DRM_FORMAT_MOD_QCOM_COMPRESSED +#define DRM_FORMAT_MOD_QCOM_COMPRESSED fourcc_mod_code(QCOM, 1) +#endif +#ifndef DRM_FORMAT_MOD_QCOM_DX +#define DRM_FORMAT_MOD_QCOM_DX fourcc_mod_code(QCOM, 0x2) +#endif +#ifndef DRM_FORMAT_MOD_QCOM_TIGHT +#define DRM_FORMAT_MOD_QCOM_TIGHT fourcc_mod_code(QCOM, 0x4) +#endif + +using std::string; +using std::to_string; +using std::fstream; +using std::unordered_map; +using drm_utils::DRMMaster; +using drm_utils::DRMResMgr; +using drm_utils::DRMLibLoader; +using drm_utils::DRMBuffer; +using sde_drm::GetDRMManager; +using sde_drm::DestroyDRMManager; +using sde_drm::DRMDisplayType; +using sde_drm::DRMDisplayToken; +using sde_drm::DRMConnectorInfo; +using sde_drm::DRMPPFeatureInfo; +using sde_drm::DRMRect; +using sde_drm::DRMRotation; +using sde_drm::DRMBlendType; +using sde_drm::DRMSrcConfig; +using sde_drm::DRMOps; +using sde_drm::DRMTopology; + +namespace sdm { + +static void GetDRMFormat(LayerBufferFormat format, uint32_t *drm_format, + uint64_t *drm_format_modifier) { + switch (format) { + case kFormatRGBA8888: + *drm_format = DRM_FORMAT_ABGR8888; + break; + case kFormatRGBA8888Ubwc: + *drm_format = DRM_FORMAT_ABGR8888; + *drm_format_modifier = DRM_FORMAT_MOD_QCOM_COMPRESSED; + break; + case kFormatRGBA5551: + *drm_format = DRM_FORMAT_ABGR1555; + break; + case kFormatRGBA4444: + *drm_format = DRM_FORMAT_ABGR4444; + break; + case kFormatBGRA8888: + *drm_format = DRM_FORMAT_ARGB8888; + break; + case kFormatRGBX8888: + *drm_format = DRM_FORMAT_XBGR8888; + break; + case kFormatRGBX8888Ubwc: + *drm_format = DRM_FORMAT_XBGR8888; + *drm_format_modifier = DRM_FORMAT_MOD_QCOM_COMPRESSED; + break; + case kFormatBGRX8888: + *drm_format = DRM_FORMAT_XRGB8888; + break; + case kFormatRGB888: + *drm_format = DRM_FORMAT_BGR888; + break; + case kFormatRGB565: + *drm_format = DRM_FORMAT_BGR565; + break; + case kFormatBGR565: + *drm_format = DRM_FORMAT_RGB565; + break; + case kFormatBGR565Ubwc: + *drm_format = DRM_FORMAT_BGR565; + *drm_format_modifier = DRM_FORMAT_MOD_QCOM_COMPRESSED; + break; + case kFormatRGBA1010102: + *drm_format = DRM_FORMAT_ABGR2101010; + break; + case kFormatRGBA1010102Ubwc: + *drm_format = DRM_FORMAT_ABGR2101010; + *drm_format_modifier = DRM_FORMAT_MOD_QCOM_COMPRESSED; + break; + case kFormatARGB2101010: + *drm_format = DRM_FORMAT_BGRA1010102; + break; + case kFormatRGBX1010102: + *drm_format = DRM_FORMAT_XBGR2101010; + break; + case kFormatRGBX1010102Ubwc: + *drm_format = DRM_FORMAT_XBGR2101010; + *drm_format_modifier = DRM_FORMAT_MOD_QCOM_COMPRESSED; + break; + case kFormatXRGB2101010: + *drm_format = DRM_FORMAT_BGRX1010102; + break; + case kFormatBGRA1010102: + *drm_format = DRM_FORMAT_ARGB2101010; + break; + case kFormatABGR2101010: + *drm_format = DRM_FORMAT_RGBA1010102; + break; + case kFormatBGRX1010102: + *drm_format = DRM_FORMAT_XRGB2101010; + break; + case kFormatXBGR2101010: + *drm_format = DRM_FORMAT_RGBX1010102; + break; + case kFormatYCbCr420SemiPlanar: + *drm_format = DRM_FORMAT_NV12; + break; + case kFormatYCbCr420SemiPlanarVenus: + *drm_format = DRM_FORMAT_NV12; + break; + case kFormatYCbCr420SPVenusUbwc: + *drm_format = DRM_FORMAT_NV12; + *drm_format_modifier = DRM_FORMAT_MOD_QCOM_COMPRESSED; + break; + case kFormatYCrCb420SemiPlanar: + *drm_format = DRM_FORMAT_NV21; + break; + case kFormatYCrCb420SemiPlanarVenus: + *drm_format = DRM_FORMAT_NV21; + break; + case kFormatYCbCr420P010: + *drm_format = DRM_FORMAT_NV12; + *drm_format_modifier = DRM_FORMAT_MOD_QCOM_DX; + break; + case kFormatYCbCr420P010Ubwc: + *drm_format = DRM_FORMAT_NV12; + *drm_format_modifier = DRM_FORMAT_MOD_QCOM_COMPRESSED | + DRM_FORMAT_MOD_QCOM_DX; + break; + case kFormatYCbCr420TP10Ubwc: + *drm_format = DRM_FORMAT_NV12; + *drm_format_modifier = DRM_FORMAT_MOD_QCOM_COMPRESSED | + DRM_FORMAT_MOD_QCOM_DX | DRM_FORMAT_MOD_QCOM_TIGHT; + break; + case kFormatYCbCr422H2V1SemiPlanar: + *drm_format = DRM_FORMAT_NV16; + break; + case kFormatYCrCb422H2V1SemiPlanar: + *drm_format = DRM_FORMAT_NV61; + break; + case kFormatYCrCb420PlanarStride16: + *drm_format = DRM_FORMAT_YVU420; + break; + default: + DLOGW("Unsupported format %s", GetFormatString(format)); + } +} + +void HWDeviceDRM::Registry::RegisterCurrent(HWLayers *hw_layers) { + DRMMaster *master = nullptr; + DRMMaster::GetInstance(&master); + + if (!master) { + DLOGE("Failed to acquire DRM Master instance"); + return; + } + + HWLayersInfo &hw_layer_info = hw_layers->info; + uint32_t hw_layer_count = UINT32(hw_layer_info.hw_layers.size()); + + for (uint32_t i = 0; i < hw_layer_count; i++) { + Layer &layer = hw_layer_info.hw_layers.at(i); + LayerBuffer *input_buffer = &layer.input_buffer; + HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session; + HWRotateInfo *hw_rotate_info = &hw_rotator_session->hw_rotate_info[0]; + + if (hw_rotate_info->valid) { + input_buffer = &hw_rotator_session->output_buffer; + } + + int fd = input_buffer->planes[0].fd; + if (fd >= 0 && hashmap_[current_index_].find(fd) == hashmap_[current_index_].end()) { + AllocatedBufferInfo buf_info {}; + DRMBuffer layout {}; + buf_info.fd = layout.fd = fd; + buf_info.aligned_width = layout.width = input_buffer->width; + buf_info.aligned_height = layout.height = input_buffer->height; + buf_info.format = input_buffer->format; + GetDRMFormat(buf_info.format, &layout.drm_format, &layout.drm_format_modifier); + buffer_allocator_->GetBufferLayout(buf_info, layout.stride, layout.offset, + &layout.num_planes); + uint32_t fb_id = 0; + int ret = master->CreateFbId(layout, &fb_id); + if (ret < 0) { + DLOGE("CreateFbId failed. width %d, height %d, format: %s, stride %u, error %d", + layout.width, layout.height, GetFormatString(buf_info.format), layout.stride[0], + errno); + } else { + hashmap_[current_index_][fd] = fb_id; + } + } + } +} + +void HWDeviceDRM::Registry::UnregisterNext() { + DRMMaster *master = nullptr; + DRMMaster::GetInstance(&master); + + if (!master) { + DLOGE("Failed to acquire DRM Master instance"); + return; + } + + current_index_ = (current_index_ + 1) % kCycleDelay; + auto &curr_map = hashmap_[current_index_]; + for (auto &pair : curr_map) { + uint32_t fb_id = pair.second; + int ret = master->RemoveFbId(fb_id); + if (ret < 0) { + DLOGE("Removing fb_id %d failed with error %d", fb_id, errno); + } + } + + curr_map.clear(); +} + +void HWDeviceDRM::Registry::Clear() { + for (int i = 0; i < kCycleDelay; i++) { + UnregisterNext(); + } + current_index_ = 0; +} + +uint32_t HWDeviceDRM::Registry::GetFbId(int fd) { + auto it = hashmap_[current_index_].find(fd); + return (it == hashmap_[current_index_].end()) ? 0 : it->second; +} + +HWDeviceDRM::HWDeviceDRM(BufferSyncHandler *buffer_sync_handler, BufferAllocator *buffer_allocator, + HWInfoInterface *hw_info_intf) + : hw_info_intf_(hw_info_intf), buffer_sync_handler_(buffer_sync_handler), + registry_(buffer_allocator) { + device_type_ = kDevicePrimary; + device_name_ = "Peripheral Display"; + hw_info_intf_ = hw_info_intf; +} + +DisplayError HWDeviceDRM::Init() { + DRMLibLoader *drm_lib = DRMLibLoader::GetInstance(); + if (drm_lib == nullptr) { + DLOGE("Failed to load DRM Lib"); + return kErrorResources; + } + default_mode_ = (drm_lib->IsLoaded() == false); + + if (!default_mode_) { + DRMMaster *drm_master = {}; + int dev_fd = -1; + DRMMaster::GetInstance(&drm_master); + drm_master->GetHandle(&dev_fd); + drm_lib->FuncGetDRMManager()(dev_fd, &drm_mgr_intf_); + if (drm_mgr_intf_->RegisterDisplay(DRMDisplayType::PERIPHERAL, &token_)) { + DLOGE("RegisterDisplay failed"); + return kErrorResources; + } + + drm_mgr_intf_->CreateAtomicReq(token_, &drm_atomic_intf_); + drm_mgr_intf_->GetConnectorInfo(token_.conn_id, &connector_info_); + InitializeConfigs(); + drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id, ¤t_mode_); + + drm_atomic_intf_->Perform(DRMOps::CRTC_SET_OUTPUT_FENCE_OFFSET, token_.crtc_id, 1); + + // TODO(user): Enable this and remove the one in SetupAtomic() onces underruns are fixed + // drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1); + // Commit to setup pipeline with mode, which then tells us the topology etc + if (drm_atomic_intf_->Commit(true /* synchronous */)) { + DLOGE("Setting up CRTC %d, Connector %d for %s failed", token_.crtc_id, token_.conn_id, + device_name_); + return kErrorResources; + } + + // Reload connector info for updated info after 1st commit + drm_mgr_intf_->GetConnectorInfo(token_.conn_id, &connector_info_); + DLOGI("Setup CRTC %d, Connector %d for %s", token_.crtc_id, token_.conn_id, device_name_); + } + + PopulateDisplayAttributes(); + PopulateHWPanelInfo(); + UpdateMixerAttributes(); + hw_info_intf_->GetHWResourceInfo(&hw_resource_); + + // TODO(user): In future, remove has_qseed3 member, add version and pass version to constructor + if (hw_resource_.has_qseed3) { + hw_scale_ = new HWScaleDRM(HWScaleDRM::Version::V2); + } + + return kErrorNone; +} + +DisplayError HWDeviceDRM::Deinit() { + delete hw_scale_; + registry_.Clear(); + drm_mgr_intf_->DestroyAtomicReq(drm_atomic_intf_); + drm_atomic_intf_ = {}; + drm_mgr_intf_->UnregisterDisplay(token_); + return kErrorNone; +} + +void HWDeviceDRM::InitializeConfigs() { + // TODO(user): Update modes + current_mode_ = connector_info_.modes[0]; +} + +DisplayError HWDeviceDRM::PopulateDisplayAttributes() { + drmModeModeInfo mode = {}; + uint32_t mm_width = 0; + uint32_t mm_height = 0; + DRMTopology topology = DRMTopology::SINGLE_LM; + + if (default_mode_) { + DRMResMgr *res_mgr = nullptr; + int ret = DRMResMgr::GetInstance(&res_mgr); + if (ret < 0) { + DLOGE("Failed to acquire DRMResMgr instance"); + return kErrorResources; + } + + res_mgr->GetMode(&mode); + res_mgr->GetDisplayDimInMM(&mm_width, &mm_height); + } else { + mode = current_mode_; + mm_width = connector_info_.mmWidth; + mm_height = connector_info_.mmHeight; + topology = connector_info_.topology; + } + + display_attributes_.x_pixels = mode.hdisplay; + display_attributes_.y_pixels = mode.vdisplay; + display_attributes_.fps = mode.vrefresh; + display_attributes_.vsync_period_ns = UINT32(1000000000L / display_attributes_.fps); + + /* + Active Front Sync Back + Region Porch Porch + <-----------------------><----------------><-------------><--------------> + <----- [hv]display -----> + <------------- [hv]sync_start ------------> + <--------------------- [hv]sync_end ---------------------> + <-------------------------------- [hv]total -----------------------------> + */ + + display_attributes_.v_front_porch = mode.vsync_start - mode.vdisplay; + display_attributes_.v_pulse_width = mode.vsync_end - mode.vsync_start; + display_attributes_.v_back_porch = mode.vtotal - mode.vsync_end; + display_attributes_.v_total = mode.vtotal; + + display_attributes_.h_total = mode.htotal; + uint32_t h_blanking = mode.htotal - mode.hdisplay; + display_attributes_.is_device_split = + (topology == DRMTopology::DUAL_LM || topology == DRMTopology::DUAL_LM_MERGE); + display_attributes_.h_total += display_attributes_.is_device_split ? h_blanking : 0; + + display_attributes_.x_dpi = (FLOAT(mode.hdisplay) * 25.4f) / FLOAT(mm_width); + display_attributes_.y_dpi = (FLOAT(mode.vdisplay) * 25.4f) / FLOAT(mm_height); + + return kErrorNone; +} + +void HWDeviceDRM::PopulateHWPanelInfo() { + hw_panel_info_ = {}; + + snprintf(hw_panel_info_.panel_name, sizeof(hw_panel_info_.panel_name), "%s", + connector_info_.panel_name.c_str()); + hw_panel_info_.split_info.left_split = display_attributes_.x_pixels; + if (display_attributes_.is_device_split) { + hw_panel_info_.split_info.left_split = hw_panel_info_.split_info.right_split = + display_attributes_.x_pixels / 2; + } + + hw_panel_info_.partial_update = 0; + hw_panel_info_.left_align = 0; + hw_panel_info_.width_align = 0; + hw_panel_info_.top_align = 0; + hw_panel_info_.height_align = 0; + hw_panel_info_.min_roi_width = 0; + hw_panel_info_.min_roi_height = 0; + hw_panel_info_.needs_roi_merge = 0; + hw_panel_info_.dynamic_fps = connector_info_.dynamic_fps; + hw_panel_info_.min_fps = 60; + hw_panel_info_.max_fps = 60; + hw_panel_info_.is_primary_panel = connector_info_.is_primary; + hw_panel_info_.is_pluggable = 0; + + if (!default_mode_) { + hw_panel_info_.needs_roi_merge = (connector_info_.topology == DRMTopology::DUAL_LM_MERGE); + } + + GetHWDisplayPortAndMode(); + GetHWPanelMaxBrightness(); + + DLOGI("%s, Panel Interface = %s, Panel Mode = %s, Is Primary = %d", device_name_, + interface_str_.c_str(), hw_panel_info_.mode == kModeVideo ? "Video" : "Command", + hw_panel_info_.is_primary_panel); + DLOGI("Partial Update = %d, Dynamic FPS = %d", hw_panel_info_.partial_update, + hw_panel_info_.dynamic_fps); + DLOGI("Align: left = %d, width = %d, top = %d, height = %d", hw_panel_info_.left_align, + hw_panel_info_.width_align, hw_panel_info_.top_align, hw_panel_info_.height_align); + DLOGI("ROI: min_width = %d, min_height = %d, need_merge = %d", hw_panel_info_.min_roi_width, + hw_panel_info_.min_roi_height, hw_panel_info_.needs_roi_merge); + DLOGI("FPS: min = %d, max =%d", hw_panel_info_.min_fps, hw_panel_info_.max_fps); + DLOGI("Left Split = %d, Right Split = %d", hw_panel_info_.split_info.left_split, + hw_panel_info_.split_info.right_split); +} + +void HWDeviceDRM::GetHWDisplayPortAndMode() { + hw_panel_info_.port = kPortDefault; + hw_panel_info_.mode = + (connector_info_.panel_mode == sde_drm::DRMPanelMode::VIDEO) ? kModeVideo : kModeCommand; + + if (default_mode_) { + return; + } + + switch (connector_info_.type) { + case DRM_MODE_CONNECTOR_DSI: + hw_panel_info_.port = kPortDSI; + interface_str_ = "DSI"; + break; + case DRM_MODE_CONNECTOR_LVDS: + hw_panel_info_.port = kPortLVDS; + interface_str_ = "LVDS"; + break; + case DRM_MODE_CONNECTOR_eDP: + hw_panel_info_.port = kPortEDP; + interface_str_ = "EDP"; + break; + case DRM_MODE_CONNECTOR_TV: + case DRM_MODE_CONNECTOR_HDMIA: + case DRM_MODE_CONNECTOR_HDMIB: + hw_panel_info_.port = kPortDTV; + interface_str_ = "HDMI"; + break; + case DRM_MODE_CONNECTOR_VIRTUAL: + hw_panel_info_.port = kPortWriteBack; + interface_str_ = "Virtual"; + break; + case DRM_MODE_CONNECTOR_DisplayPort: + // TODO(user): Add when available + interface_str_ = "DisplayPort"; + break; + } + + return; +} + +void HWDeviceDRM::GetHWPanelMaxBrightness() { + char brightness[kMaxStringLength] = {0}; + string kMaxBrightnessNode = "/sys/class/backlight/panel0-backlight/max_brightness"; + + hw_panel_info_.panel_max_brightness = 255; + int fd = Sys::open_(kMaxBrightnessNode.c_str(), O_RDONLY); + if (fd < 0) { + DLOGW("Failed to open max brightness node = %s, error = %s", kMaxBrightnessNode.c_str(), + strerror(errno)); + return; + } + + if (Sys::pread_(fd, brightness, sizeof(brightness), 0) > 0) { + hw_panel_info_.panel_max_brightness = atoi(brightness); + DLOGI("Max brightness level = %d", hw_panel_info_.panel_max_brightness); + } else { + DLOGW("Failed to read max brightness level. error = %s", strerror(errno)); + } + + Sys::close_(fd); +} + +DisplayError HWDeviceDRM::GetActiveConfig(uint32_t *active_config) { + *active_config = 0; + return kErrorNone; +} + +DisplayError HWDeviceDRM::GetNumDisplayAttributes(uint32_t *count) { + *count = 1; + return kErrorNone; +} + +DisplayError HWDeviceDRM::GetDisplayAttributes(uint32_t index, + HWDisplayAttributes *display_attributes) { + *display_attributes = display_attributes_; + return kErrorNone; +} + +DisplayError HWDeviceDRM::GetHWPanelInfo(HWPanelInfo *panel_info) { + *panel_info = hw_panel_info_; + return kErrorNone; +} + +DisplayError HWDeviceDRM::SetDisplayAttributes(uint32_t index) { + return kErrorNone; +} + +DisplayError HWDeviceDRM::SetDisplayAttributes(const HWDisplayAttributes &display_attributes) { + return kErrorNotSupported; +} + +DisplayError HWDeviceDRM::GetConfigIndex(uint32_t mode, uint32_t *index) { + return kErrorNone; +} + +DisplayError HWDeviceDRM::PowerOn() { + DTRACE_SCOPED(); + return kErrorNone; +} + +DisplayError HWDeviceDRM::PowerOff() { + return kErrorNone; +} + +DisplayError HWDeviceDRM::Doze() { + return kErrorNone; +} + +DisplayError HWDeviceDRM::DozeSuspend() { + return kErrorNone; +} + +DisplayError HWDeviceDRM::Standby() { + return kErrorNone; +} + +void HWDeviceDRM::SetupAtomic(HWLayers *hw_layers, bool validate) { + if (default_mode_) { + return; + } + + HWLayersInfo &hw_layer_info = hw_layers->info; + uint32_t hw_layer_count = UINT32(hw_layer_info.hw_layers.size()); + + for (uint32_t i = 0; i < hw_layer_count; i++) { + Layer &layer = hw_layer_info.hw_layers.at(i); + LayerBuffer *input_buffer = &layer.input_buffer; + HWPipeInfo *left_pipe = &hw_layers->config[i].left_pipe; + HWPipeInfo *right_pipe = &hw_layers->config[i].right_pipe; + HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session; + bool needs_rotation = false; + + for (uint32_t count = 0; count < 2; count++) { + HWPipeInfo *pipe_info = (count == 0) ? left_pipe : right_pipe; + HWRotateInfo *hw_rotate_info = &hw_rotator_session->hw_rotate_info[count]; + + if (hw_rotate_info->valid) { + input_buffer = &hw_rotator_session->output_buffer; + needs_rotation = true; + } + + uint32_t fb_id = registry_.GetFbId(input_buffer->planes[0].fd); + if (pipe_info->valid && fb_id) { + uint32_t pipe_id = pipe_info->pipe_id; + drm_atomic_intf_->Perform(DRMOps::PLANE_SET_ALPHA, pipe_id, layer.plane_alpha); + drm_atomic_intf_->Perform(DRMOps::PLANE_SET_ZORDER, pipe_id, pipe_info->z_order); + DRMBlendType blending = {}; + SetBlending(layer.blending, &blending); + drm_atomic_intf_->Perform(DRMOps::PLANE_SET_BLEND_TYPE, pipe_id, blending); + DRMRect src = {}; + SetRect(pipe_info->src_roi, &src); + drm_atomic_intf_->Perform(DRMOps::PLANE_SET_SRC_RECT, pipe_id, src); + DRMRect dst = {}; + SetRect(pipe_info->dst_roi, &dst); + drm_atomic_intf_->Perform(DRMOps::PLANE_SET_DST_RECT, pipe_id, dst); + + uint32_t rot_bit_mask = 0; + // In case of rotation, rotator handles flips + if (!needs_rotation) { + if (layer.transform.flip_horizontal) { + rot_bit_mask |= UINT32(DRMRotation::FLIP_H); + } + if (layer.transform.flip_vertical) { + rot_bit_mask |= UINT32(DRMRotation::FLIP_V); + } + } + + drm_atomic_intf_->Perform(DRMOps::PLANE_SET_ROTATION, pipe_id, rot_bit_mask); + drm_atomic_intf_->Perform(DRMOps::PLANE_SET_H_DECIMATION, pipe_id, + pipe_info->horizontal_decimation); + drm_atomic_intf_->Perform(DRMOps::PLANE_SET_V_DECIMATION, pipe_id, + pipe_info->vertical_decimation); + uint32_t config = 0; + SetSrcConfig(layer.input_buffer, &config); + drm_atomic_intf_->Perform(DRMOps::PLANE_SET_SRC_CONFIG, pipe_id, config);; + drm_atomic_intf_->Perform(DRMOps::PLANE_SET_FB_ID, pipe_id, fb_id); + drm_atomic_intf_->Perform(DRMOps::PLANE_SET_CRTC, pipe_id, token_.crtc_id); + if (!validate && input_buffer->acquire_fence_fd >= 0) { + drm_atomic_intf_->Perform(DRMOps::PLANE_SET_INPUT_FENCE, pipe_id, + input_buffer->acquire_fence_fd); + } + if (hw_scale_) { + SDEScaler scaler_output = {}; + hw_scale_->SetPlaneScaler(pipe_info->scale_data, &scaler_output); + // TODO(user): Remove qseed3 and add version check, then send appropriate scaler object + if (hw_resource_.has_qseed3) { + drm_atomic_intf_->Perform(DRMOps::PLANE_SET_SCALER_CONFIG, pipe_id, + reinterpret_cast<uint64_t>(&scaler_output.scaler_v2)); + } + } + } + } + + // TODO(user): Remove this and enable the one in Init() onces underruns are fixed + drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1); + } +} + +DisplayError HWDeviceDRM::Validate(HWLayers *hw_layers) { + DTRACE_SCOPED(); + + registry_.RegisterCurrent(hw_layers); + SetupAtomic(hw_layers, true /* validate */); + + int ret = drm_atomic_intf_->Validate(); + if (ret) { + DLOGE("%s failed with error %d", __FUNCTION__, ret); + return kErrorHardware; + } + + return kErrorNone; +} + +DisplayError HWDeviceDRM::Commit(HWLayers *hw_layers) { + DTRACE_SCOPED(); + + DisplayError err = kErrorNone; + registry_.RegisterCurrent(hw_layers); + + if (default_mode_) { + err = DefaultCommit(hw_layers); + } else { + err = AtomicCommit(hw_layers); + } + + registry_.UnregisterNext(); + + return err; +} + +DisplayError HWDeviceDRM::DefaultCommit(HWLayers *hw_layers) { + DTRACE_SCOPED(); + + HWLayersInfo &hw_layer_info = hw_layers->info; + LayerStack *stack = hw_layer_info.stack; + + stack->retire_fence_fd = -1; + for (Layer &layer : hw_layer_info.hw_layers) { + layer.input_buffer.release_fence_fd = -1; + } + + DRMMaster *master = nullptr; + int ret = DRMMaster::GetInstance(&master); + if (ret < 0) { + DLOGE("Failed to acquire DRMMaster instance"); + return kErrorResources; + } + + DRMResMgr *res_mgr = nullptr; + ret = DRMResMgr::GetInstance(&res_mgr); + if (ret < 0) { + DLOGE("Failed to acquire DRMResMgr instance"); + return kErrorResources; + } + + int dev_fd = -1; + master->GetHandle(&dev_fd); + + uint32_t connector_id = 0; + res_mgr->GetConnectorId(&connector_id); + + uint32_t crtc_id = 0; + res_mgr->GetCrtcId(&crtc_id); + + drmModeModeInfo mode; + res_mgr->GetMode(&mode); + + uint32_t fb_id = registry_.GetFbId(hw_layer_info.hw_layers.at(0).input_buffer.planes[0].fd); + ret = drmModeSetCrtc(dev_fd, crtc_id, fb_id, 0 /* x */, 0 /* y */, &connector_id, + 1 /* num_connectors */, &mode); + if (ret < 0) { + DLOGE("drmModeSetCrtc failed dev fd %d, fb_id %d, crtc id %d, connector id %d, %s", dev_fd, + fb_id, crtc_id, connector_id, strerror(errno)); + return kErrorHardware; + } + + return kErrorNone; +} + +DisplayError HWDeviceDRM::AtomicCommit(HWLayers *hw_layers) { + DTRACE_SCOPED(); + SetupAtomic(hw_layers, false /* validate */); + + int ret = drm_atomic_intf_->Commit(false /* synchronous */); + if (ret) { + DLOGE("%s failed with error %d", __FUNCTION__, ret); + return kErrorHardware; + } + + int release_fence = -1; + int retire_fence = -1; + + drm_atomic_intf_->Perform(DRMOps::CRTC_GET_RELEASE_FENCE, token_.crtc_id, &release_fence); + drm_atomic_intf_->Perform(DRMOps::CONNECTOR_GET_RETIRE_FENCE, token_.conn_id, &retire_fence); + + HWLayersInfo &hw_layer_info = hw_layers->info; + LayerStack *stack = hw_layer_info.stack; + stack->retire_fence_fd = retire_fence; + + for (uint32_t i = 0; i < hw_layer_info.hw_layers.size(); i++) { + Layer &layer = hw_layer_info.hw_layers.at(i); + HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session; + if (hw_rotator_session->hw_block_count) { + hw_rotator_session->output_buffer.release_fence_fd = Sys::dup_(release_fence); + } else { + layer.input_buffer.release_fence_fd = Sys::dup_(release_fence); + } + } + + hw_layer_info.sync_handle = release_fence; + + return kErrorNone; +} + +DisplayError HWDeviceDRM::Flush() { + return kErrorNone; +} + +void HWDeviceDRM::SetBlending(const LayerBlending &source, DRMBlendType *target) { + switch (source) { + case kBlendingPremultiplied: + *target = DRMBlendType::PREMULTIPLIED; + break; + case kBlendingOpaque: + *target = DRMBlendType::OPAQUE; + break; + case kBlendingCoverage: + *target = DRMBlendType::COVERAGE; + break; + default: + *target = DRMBlendType::UNDEFINED; + } +} + + +void HWDeviceDRM::SetSrcConfig(const LayerBuffer &input_buffer, uint32_t *config) { + if (input_buffer.flags.interlace) { + *config |= (0x01 << UINT32(DRMSrcConfig::DEINTERLACE)); + } +} + +void HWDeviceDRM::SetRect(const LayerRect &source, DRMRect *target) { + target->left = UINT32(source.left); + target->top = UINT32(source.top); + target->right = UINT32(source.right); + target->bottom = UINT32(source.bottom); +} + +bool HWDeviceDRM::EnableHotPlugDetection(int enable) { + return true; +} + +void HWDeviceDRM::ResetDisplayParams() {} + +DisplayError HWDeviceDRM::SetCursorPosition(HWLayers *hw_layers, int x, int y) { + DTRACE_SCOPED(); + return kErrorNone; +} + +DisplayError HWDeviceDRM::GetPPFeaturesVersion(PPFeatureVersion *vers) { + struct DRMPPFeatureInfo info = {}; + + for (uint32_t i = 0; i < kMaxNumPPFeatures; i++) { + memset(&info, 0, sizeof(struct DRMPPFeatureInfo)); + info.id = HWColorManagerDrm::ToDrmFeatureId(i); + if (info.id >= sde_drm::kPPFeaturesMax) + continue; + // use crtc_id_ = 0 since PP features are same across all CRTCs + drm_mgr_intf_->GetCrtcPPInfo(0, info); + vers->version[i] = HWColorManagerDrm::GetFeatureVersion(info); + } + return kErrorNone; +} + +DisplayError HWDeviceDRM::SetPPFeatures(PPFeaturesConfig *feature_list) { + int ret = 0; + PPFeatureInfo *feature = NULL; + DRMPPFeatureInfo kernel_params = {}; + + while (true) { + ret = feature_list->RetrieveNextFeature(&feature); + if (ret) + break; + + if (feature) { + DLOGV_IF(kTagDriverConfig, "feature_id = %d", feature->feature_id_); + if (!HWColorManagerDrm::GetDrmFeature[feature->feature_id_]) { + DLOGE("GetDrmFeature is not valid for feature %d", feature->feature_id_); + continue; + } + ret = HWColorManagerDrm::GetDrmFeature[feature->feature_id_](*feature, &kernel_params); + if (!ret) + drm_atomic_intf_->Perform(DRMOps::CRTC_SET_POST_PROC, token_.crtc_id, &kernel_params); + HWColorManagerDrm::FreeDrmFeatureData(&kernel_params); + } + } + + // Once all features were consumed, then destroy all feature instance from feature_list, + feature_list->Reset(); + + return kErrorNone; +} + +DisplayError HWDeviceDRM::SetVSyncState(bool enable) { + return kErrorNone; +} + +void HWDeviceDRM::SetIdleTimeoutMs(uint32_t timeout_ms) {} + +DisplayError HWDeviceDRM::SetDisplayMode(const HWDisplayMode hw_display_mode) { + return kErrorNotSupported; +} + +DisplayError HWDeviceDRM::SetRefreshRate(uint32_t refresh_rate) { + return kErrorNotSupported; +} + +DisplayError HWDeviceDRM::SetPanelBrightness(int level) { + DisplayError err = kErrorNone; + char buffer[kMaxSysfsCommandLength] = {0}; + + DLOGV_IF(kTagDriverConfig, "Set brightness level to %d", level); + int fd = Sys::open_(kBrightnessNode, O_RDWR); + if (fd < 0) { + DLOGV_IF(kTagDriverConfig, "Failed to open node = %s, error = %s ", kBrightnessNode, + strerror(errno)); + return kErrorFileDescriptor; + } + + int32_t bytes = snprintf(buffer, kMaxSysfsCommandLength, "%d\n", level); + ssize_t ret = Sys::pwrite_(fd, buffer, static_cast<size_t>(bytes), 0); + if (ret <= 0) { + DLOGV_IF(kTagDriverConfig, "Failed to write to node = %s, error = %s ", kBrightnessNode, + strerror(errno)); + err = kErrorHardware; + } + + Sys::close_(fd); + + return err; +} + +DisplayError HWDeviceDRM::GetPanelBrightness(int *level) { + DisplayError err = kErrorNone; + char brightness[kMaxStringLength] = {0}; + + if (!level) { + DLOGV_IF(kTagDriverConfig, "Invalid input, null pointer."); + return kErrorParameters; + } + + int fd = Sys::open_(kBrightnessNode, O_RDWR); + if (fd < 0) { + DLOGV_IF(kTagDriverConfig, "Failed to open brightness node = %s, error = %s", kBrightnessNode, + strerror(errno)); + return kErrorFileDescriptor; + } + + if (Sys::pread_(fd, brightness, sizeof(brightness), 0) > 0) { + *level = atoi(brightness); + DLOGV_IF(kTagDriverConfig, "Brightness level = %d", *level); + } else { + DLOGV_IF(kTagDriverConfig, "Failed to read panel brightness"); + err = kErrorHardware; + } + + Sys::close_(fd); + + return err; +} + +DisplayError HWDeviceDRM::CachePanelBrightness(int level) { + return kErrorNotSupported; +} + +DisplayError HWDeviceDRM::GetHWScanInfo(HWScanInfo *scan_info) { + return kErrorNotSupported; +} + +DisplayError HWDeviceDRM::GetVideoFormat(uint32_t config_index, uint32_t *video_format) { + return kErrorNotSupported; +} + +DisplayError HWDeviceDRM::GetMaxCEAFormat(uint32_t *max_cea_format) { + return kErrorNotSupported; +} + +DisplayError HWDeviceDRM::OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level) { + return kErrorNotSupported; +} + +DisplayError HWDeviceDRM::SetS3DMode(HWS3DMode s3d_mode) { + return kErrorNotSupported; +} + +DisplayError HWDeviceDRM::SetScaleLutConfig(HWScaleLutInfo *lut_info) { + sde_drm::DRMScalerLUTInfo drm_lut_info = {}; + drm_lut_info.cir_lut = lut_info->cir_lut; + drm_lut_info.dir_lut = lut_info->dir_lut; + drm_lut_info.sep_lut = lut_info->sep_lut; + drm_lut_info.cir_lut_size = lut_info->cir_lut_size; + drm_lut_info.dir_lut_size = lut_info->dir_lut_size; + drm_lut_info.sep_lut_size = lut_info->sep_lut_size; + drm_mgr_intf_->SetScalerLUT(drm_lut_info); + + return kErrorNone; +} + +DisplayError HWDeviceDRM::SetMixerAttributes(const HWMixerAttributes &mixer_attributes) { + if (!hw_resource_.hw_dest_scalar_info.count) { + return kErrorNotSupported; + } + + if (mixer_attributes.width > display_attributes_.x_pixels || + mixer_attributes.height > display_attributes_.y_pixels) { + DLOGW("Input resolution exceeds display resolution! input: res %dx%d display: res %dx%d", + mixer_attributes.width, mixer_attributes.height, display_attributes_.x_pixels, + display_attributes_.y_pixels); + return kErrorNotSupported; + } + + uint32_t max_input_width = hw_resource_.hw_dest_scalar_info.max_input_width; + if (display_attributes_.is_device_split) { + max_input_width *= 2; + } + + if (mixer_attributes.width > max_input_width) { + DLOGW("Input width exceeds width limit! input_width %d width_limit %d", mixer_attributes.width, + max_input_width); + return kErrorNotSupported; + } + + float mixer_aspect_ratio = FLOAT(mixer_attributes.width) / FLOAT(mixer_attributes.height); + float display_aspect_ratio = + FLOAT(display_attributes_.x_pixels) / FLOAT(display_attributes_.y_pixels); + + if (display_aspect_ratio != mixer_aspect_ratio) { + DLOGW("Aspect ratio mismatch! input: res %dx%d display: res %dx%d", mixer_attributes.width, + mixer_attributes.height, display_attributes_.x_pixels, display_attributes_.y_pixels); + return kErrorNotSupported; + } + + float scale_x = FLOAT(display_attributes_.x_pixels) / FLOAT(mixer_attributes.width); + float scale_y = FLOAT(display_attributes_.y_pixels) / FLOAT(mixer_attributes.height); + float max_scale_up = hw_resource_.hw_dest_scalar_info.max_scale_up; + if (scale_x > max_scale_up || scale_y > max_scale_up) { + DLOGW( + "Up scaling ratio exceeds for destination scalar upscale limit scale_x %f scale_y %f " + "max_scale_up %f", + scale_x, scale_y, max_scale_up); + return kErrorNotSupported; + } + + float mixer_split_ratio = FLOAT(mixer_attributes_.split_left) / FLOAT(mixer_attributes_.width); + + mixer_attributes_ = mixer_attributes; + mixer_attributes_.split_left = mixer_attributes_.width; + if (display_attributes_.is_device_split) { + mixer_attributes_.split_left = UINT32(FLOAT(mixer_attributes.width) * mixer_split_ratio); + } + + return kErrorNone; +} + +DisplayError HWDeviceDRM::GetMixerAttributes(HWMixerAttributes *mixer_attributes) { + if (!mixer_attributes) { + return kErrorParameters; + } + + mixer_attributes_.width = display_attributes_.x_pixels; + mixer_attributes_.height = display_attributes_.y_pixels; + mixer_attributes_.split_left = display_attributes_.is_device_split + ? hw_panel_info_.split_info.left_split + : mixer_attributes_.width; + *mixer_attributes = mixer_attributes_; + + return kErrorNone; +} + +void HWDeviceDRM::UpdateMixerAttributes() { + mixer_attributes_.width = display_attributes_.x_pixels; + mixer_attributes_.height = display_attributes_.y_pixels; + mixer_attributes_.split_left = display_attributes_.is_device_split + ? hw_panel_info_.split_info.left_split + : mixer_attributes_.width; +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/core/drm/hw_device_drm.h b/msm8909/sdm/libs/core/drm/hw_device_drm.h new file mode 100644 index 00000000..cc2ae7bc --- /dev/null +++ b/msm8909/sdm/libs/core/drm/hw_device_drm.h @@ -0,0 +1,168 @@ +/* +* Copyright (c) 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __HW_DEVICE_DRM_H__ +#define __HW_DEVICE_DRM_H__ + +#include <drm_interface.h> +#include <errno.h> +#include <pthread.h> +#include <xf86drmMode.h> +#include <string> +#include <unordered_map> +#include <vector> + +#include "hw_interface.h" +#include "hw_scale_drm.h" + +#define IOCTL_LOGE(ioctl, type) \ + DLOGE("ioctl %s, device = %d errno = %d, desc = %s", #ioctl, type, errno, strerror(errno)) + +namespace sdm { +class HWInfoInterface; + +class HWDeviceDRM : public HWInterface { + public: + explicit HWDeviceDRM(BufferSyncHandler *buffer_sync_handler, BufferAllocator *buffer_allocator, + HWInfoInterface *hw_info_intf); + virtual ~HWDeviceDRM() {} + virtual DisplayError Init(); + virtual DisplayError Deinit(); + + protected: + // From HWInterface + virtual DisplayError GetActiveConfig(uint32_t *active_config); + virtual DisplayError GetNumDisplayAttributes(uint32_t *count); + virtual DisplayError GetDisplayAttributes(uint32_t index, + HWDisplayAttributes *display_attributes); + virtual DisplayError GetHWPanelInfo(HWPanelInfo *panel_info); + virtual DisplayError SetDisplayAttributes(uint32_t index); + virtual DisplayError SetDisplayAttributes(const HWDisplayAttributes &display_attributes); + virtual DisplayError GetConfigIndex(uint32_t mode, uint32_t *index); + virtual DisplayError PowerOn(); + virtual DisplayError PowerOff(); + virtual DisplayError Doze(); + virtual DisplayError DozeSuspend(); + virtual DisplayError Standby(); + virtual DisplayError Validate(HWLayers *hw_layers); + virtual DisplayError Commit(HWLayers *hw_layers); + virtual DisplayError Flush(); + virtual DisplayError GetPPFeaturesVersion(PPFeatureVersion *vers); + virtual DisplayError SetPPFeatures(PPFeaturesConfig *feature_list); + virtual DisplayError SetVSyncState(bool enable); + virtual void SetIdleTimeoutMs(uint32_t timeout_ms); + virtual DisplayError SetDisplayMode(const HWDisplayMode hw_display_mode); + virtual DisplayError SetRefreshRate(uint32_t refresh_rate); + virtual DisplayError SetPanelBrightness(int level); + virtual DisplayError CachePanelBrightness(int level); + virtual DisplayError GetHWScanInfo(HWScanInfo *scan_info); + virtual DisplayError GetVideoFormat(uint32_t config_index, uint32_t *video_format); + virtual DisplayError GetMaxCEAFormat(uint32_t *max_cea_format); + virtual DisplayError SetCursorPosition(HWLayers *hw_layers, int x, int y); + virtual DisplayError OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level); + virtual DisplayError GetPanelBrightness(int *level); + virtual DisplayError SetAutoRefresh(bool enable) { return kErrorNone; } + virtual DisplayError SetS3DMode(HWS3DMode s3d_mode); + virtual DisplayError SetScaleLutConfig(HWScaleLutInfo *lut_info); + virtual DisplayError SetMixerAttributes(const HWMixerAttributes &mixer_attributes); + virtual DisplayError GetMixerAttributes(HWMixerAttributes *mixer_attributes); + + enum { + kHWEventVSync, + kHWEventBlank, + }; + + static const int kMaxStringLength = 1024; + static const int kNumPhysicalDisplays = 2; + static const int kMaxSysfsCommandLength = 12; + static constexpr const char *kBrightnessNode = + "/sys/class/backlight/panel0-backlight/brightness"; + + DisplayError SetFormat(const LayerBufferFormat &source, uint32_t *target); + DisplayError SetStride(HWDeviceType device_type, LayerBufferFormat format, uint32_t width, + uint32_t *target); + DisplayError PopulateDisplayAttributes(); + void PopulateHWPanelInfo(); + void GetHWDisplayPortAndMode(); + void GetHWPanelMaxBrightness(); + void ResetDisplayParams(); + bool EnableHotPlugDetection(int enable); + void UpdateMixerAttributes(); + void InitializeConfigs(); + void SetBlending(const LayerBlending &source, sde_drm::DRMBlendType *target); + void SetSrcConfig(const LayerBuffer &input_buffer, uint32_t *config); + void SetRect(const LayerRect &source, sde_drm::DRMRect *target); + DisplayError DefaultCommit(HWLayers *hw_layers); + DisplayError AtomicCommit(HWLayers *hw_layers); + void SetupAtomic(HWLayers *hw_layers, bool validate); + + class Registry { + public: + explicit Registry(BufferAllocator *buffer_allocator) : buffer_allocator_(buffer_allocator) {} + // Call on each validate and commit to register layer buffers + void RegisterCurrent(HWLayers *hw_layers); + // Call at the end of draw cycle to clear the next slot for business + void UnregisterNext(); + // Call on display disconnect to release all gem handles and fb_ids + void Clear(); + // Finds an fb_id corresponding to an fd in current map + uint32_t GetFbId(int fd); + + private: + static const int kCycleDelay = 1; // N cycle delay before destroy + // fd to fb_id map. fd is used as key only for a single draw cycle between + // prepare and commit. It should not be used for caching in future due to fd recycling + std::unordered_map<int, uint32_t> hashmap_[kCycleDelay] {}; + int current_index_ = 0; + BufferAllocator *buffer_allocator_ = {}; + }; + + HWResourceInfo hw_resource_ = {}; + HWPanelInfo hw_panel_info_ = {}; + HWInfoInterface *hw_info_intf_ = {}; + BufferSyncHandler *buffer_sync_handler_ = {}; + HWDeviceType device_type_ = {}; + const char *device_name_ = {}; + bool synchronous_commit_ = false; + HWDisplayAttributes display_attributes_ = {}; + HWMixerAttributes mixer_attributes_ = {}; + sde_drm::DRMManagerInterface *drm_mgr_intf_ = {}; + sde_drm::DRMAtomicReqInterface *drm_atomic_intf_ = {}; + sde_drm::DRMDisplayToken token_ = {}; + drmModeModeInfo current_mode_ = {}; + bool default_mode_ = false; + sde_drm::DRMConnectorInfo connector_info_ = {}; + std::string interface_str_ = "DSI"; + HWScaleDRM *hw_scale_ = {}; + Registry registry_; +}; + +} // namespace sdm + +#endif // __HW_DEVICE_DRM_H__ diff --git a/msm8909/sdm/libs/core/drm/hw_events_drm.cpp b/msm8909/sdm/libs/core/drm/hw_events_drm.cpp new file mode 100644 index 00000000..9c9023a9 --- /dev/null +++ b/msm8909/sdm/libs/core/drm/hw_events_drm.cpp @@ -0,0 +1,298 @@ +/* +* Copyright (c) 2017, 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 <drm_master.h> +#include <errno.h> +#include <fcntl.h> +#include <math.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/prctl.h> +#include <sys/resource.h> +#include <sys/types.h> +#include <utils/debug.h> +#include <utils/sys.h> +#include <xf86drm.h> + +#include <algorithm> +#include <map> +#include <utility> +#include <vector> + +#include "hw_events_drm.h" + +#define __CLASS__ "HWEventsDRM" + +namespace sdm { + +using drm_utils::DRMMaster; + +DisplayError HWEventsDRM::InitializePollFd() { + for (uint32_t i = 0; i < event_data_list_.size(); i++) { + char data[kMaxStringLength]{}; + HWEventData &event_data = event_data_list_[i]; + poll_fds_[i].fd = -1; + + switch (event_data.event_type) { + case HWEvent::VSYNC: { + poll_fds_[i].events = POLLIN | POLLPRI | POLLERR; + DRMMaster *master = nullptr; + int ret = DRMMaster::GetInstance(&master); + if (ret < 0) { + DLOGE("Failed to acquire DRMMaster instance"); + return kErrorNotSupported; + } + master->GetHandle(&poll_fds_[i].fd); + vsync_index_ = i; + } break; + case HWEvent::EXIT: { + // Create an eventfd to be used to unblock the poll system call when + // a thread is exiting. + poll_fds_[i].fd = Sys::eventfd_(0, 0); + poll_fds_[i].events |= POLLIN; + // Clear any existing data + Sys::pread_(poll_fds_[i].fd, data, kMaxStringLength, 0); + } break; + case HWEvent::IDLE_NOTIFY: + case HWEvent::SHOW_BLANK_EVENT: + case HWEvent::THERMAL_LEVEL: + case HWEvent::IDLE_POWER_COLLAPSE: + break; + } + } + + return kErrorNone; +} + +DisplayError HWEventsDRM::SetEventParser() { + DisplayError error = kErrorNone; + + for (auto &event_data : event_data_list_) { + switch (event_data.event_type) { + case HWEvent::VSYNC: + event_data.event_parser = &HWEventsDRM::HandleVSync; + break; + case HWEvent::IDLE_NOTIFY: + event_data.event_parser = &HWEventsDRM::HandleIdleTimeout; + break; + case HWEvent::EXIT: + event_data.event_parser = &HWEventsDRM::HandleThreadExit; + break; + case HWEvent::SHOW_BLANK_EVENT: + event_data.event_parser = &HWEventsDRM::HandleBlank; + break; + case HWEvent::THERMAL_LEVEL: + event_data.event_parser = &HWEventsDRM::HandleThermal; + break; + case HWEvent::IDLE_POWER_COLLAPSE: + event_data.event_parser = &HWEventsDRM::HandleIdlePowerCollapse; + break; + default: + error = kErrorParameters; + break; + } + } + + return error; +} + +void HWEventsDRM::PopulateHWEventData(const vector<HWEvent> &event_list) { + for (auto &event : event_list) { + HWEventData event_data; + event_data.event_type = event; + event_data_list_.push_back(std::move(event_data)); + } + + SetEventParser(); + InitializePollFd(); +} + +DisplayError HWEventsDRM::Init(int display_type, HWEventHandler *event_handler, + const vector<HWEvent> &event_list) { + if (!event_handler) + return kErrorParameters; + + event_handler_ = event_handler; + poll_fds_.resize(event_list.size()); + event_thread_name_ += " - " + std::to_string(display_type); + + PopulateHWEventData(event_list); + + if (pthread_create(&event_thread_, NULL, &DisplayEventThread, this) < 0) { + DLOGE("Failed to start %s, error = %s", event_thread_name_.c_str()); + return kErrorResources; + } + + return kErrorNone; +} + +DisplayError HWEventsDRM::Deinit() { + exit_threads_ = true; + Sys::pthread_cancel_(event_thread_); + + for (uint32_t i = 0; i < event_data_list_.size(); i++) { + if (event_data_list_[i].event_type == HWEvent::EXIT) { + uint64_t exit_value = 1; + ssize_t write_size = Sys::write_(poll_fds_[i].fd, &exit_value, sizeof(uint64_t)); + if (write_size != sizeof(uint64_t)) { + DLOGW("Error triggering exit fd (%d). write size = %d, error = %s", poll_fds_[i].fd, + write_size, strerror(errno)); + } + } + } + + pthread_join(event_thread_, NULL); + CloseFds(); + + return kErrorNone; +} + +DisplayError HWEventsDRM::CloseFds() { + for (uint32_t i = 0; i < event_data_list_.size(); i++) { + switch (event_data_list_[i].event_type) { + case HWEvent::VSYNC: + poll_fds_[i].fd = -1; + break; + case HWEvent::EXIT: + Sys::close_(poll_fds_[i].fd); + poll_fds_[i].fd = -1; + break; + case HWEvent::IDLE_NOTIFY: + case HWEvent::SHOW_BLANK_EVENT: + case HWEvent::THERMAL_LEVEL: + case HWEvent::IDLE_POWER_COLLAPSE: + break; + default: + return kErrorNotSupported; + } + } + + return kErrorNone; +} + +void *HWEventsDRM::DisplayEventThread(void *context) { + if (context) { + return reinterpret_cast<HWEventsDRM *>(context)->DisplayEventHandler(); + } + + return NULL; +} + +void *HWEventsDRM::DisplayEventHandler() { + char data[kMaxStringLength]{}; + + prctl(PR_SET_NAME, event_thread_name_.c_str(), 0, 0, 0); + setpriority(PRIO_PROCESS, 0, kThreadPriorityUrgent); + + while (!exit_threads_) { + if (RegisterVSync() != kErrorNone) { + pthread_exit(0); + return nullptr; + } + + int error = Sys::poll_(poll_fds_.data(), UINT32(poll_fds_.size()), -1); + if (error <= 0) { + DLOGW("poll failed. error = %s", strerror(errno)); + continue; + } + + for (uint32_t i = 0; i < event_data_list_.size(); i++) { + pollfd &poll_fd = poll_fds_[i]; + switch (event_data_list_[i].event_type) { + case HWEvent::VSYNC: + (this->*(event_data_list_[i]).event_parser)(nullptr); + break; + case HWEvent::EXIT: + if ((poll_fd.revents & POLLIN) && + (Sys::read_(poll_fd.fd, data, kMaxStringLength) > 0)) { + (this->*(event_data_list_[i]).event_parser)(data); + } + break; + case HWEvent::IDLE_NOTIFY: + case HWEvent::SHOW_BLANK_EVENT: + case HWEvent::THERMAL_LEVEL: + case HWEvent::IDLE_POWER_COLLAPSE: + if (poll_fd.fd >= 0 && (poll_fd.revents & POLLPRI) && + (Sys::pread_(poll_fd.fd, data, kMaxStringLength, 0) > 0)) { + (this->*(event_data_list_[i]).event_parser)(data); + } + break; + } + } + } + + pthread_exit(0); + + return nullptr; +} + +DisplayError HWEventsDRM::RegisterVSync() { + drmVBlank vblank{}; + vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT); + vblank.request.sequence = 1; + // DRM hack to pass in context to unused field signal. Driver will write this to the node being + // polled on, and will be read as part of drm event handling and sent to handler + vblank.request.signal = reinterpret_cast<unsigned long>(this); // NOLINT + int error = drmWaitVBlank(poll_fds_[vsync_index_].fd, &vblank); + if (error < 0) { + DLOGE("drmWaitVBlank failed with err %d", errno); + return kErrorResources; + } + + return kErrorNone; +} + +void HWEventsDRM::HandleVSync(char *data) { + if (poll_fds_[vsync_index_].revents & (POLLIN | POLLPRI)) { + drmEventContext event = {}; + event.version = DRM_EVENT_CONTEXT_VERSION; + event.vblank_handler = &HWEventsDRM::VSyncHandlerCallback; + int error = drmHandleEvent(poll_fds_[vsync_index_].fd, &event); + if (error != 0) { + DLOGE("drmHandleEvent failed: %i", error); + } + } +} + +void HWEventsDRM::VSyncHandlerCallback(int fd, unsigned int sequence, unsigned int tv_sec, + unsigned int tv_usec, void *data) { + int64_t timestamp = (int64_t)(tv_sec)*1000000000 + (int64_t)(tv_usec)*1000; + reinterpret_cast<HWEventsDRM *>(data)->event_handler_->VSync(timestamp); +} + +void HWEventsDRM::HandleIdleTimeout(char *data) { + event_handler_->IdleTimeout(); +} + +void HWEventsDRM::HandleIdlePowerCollapse(char *data) { + event_handler_->IdlePowerCollapse(); +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/core/drm/hw_events_drm.h b/msm8909/sdm/libs/core/drm/hw_events_drm.h new file mode 100644 index 00000000..f114b1fa --- /dev/null +++ b/msm8909/sdm/libs/core/drm/hw_events_drm.h @@ -0,0 +1,90 @@ +/* +* Copyright (c) 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __HW_EVENTS_DRM_H__ +#define __HW_EVENTS_DRM_H__ + +#include <sys/poll.h> +#include <map> +#include <string> +#include <utility> +#include <vector> + +#include "hw_events_interface.h" +#include "hw_interface.h" + +namespace sdm { + +using std::vector; + +class HWEventsDRM : public HWEventsInterface { + public: + virtual DisplayError Init(int display_type, HWEventHandler *event_handler, + const vector<HWEvent> &event_list); + virtual DisplayError Deinit(); + + private: + static const int kMaxStringLength = 1024; + + typedef void (HWEventsDRM::*EventParser)(char *); + + struct HWEventData { + HWEvent event_type {}; + EventParser event_parser {}; + }; + + static void *DisplayEventThread(void *context); + static void VSyncHandlerCallback(int fd, unsigned int sequence, unsigned int tv_sec, + unsigned int tv_usec, void *data); + + void *DisplayEventHandler(); + void HandleVSync(char *data); + void HandleIdleTimeout(char *data); + void HandleThreadExit(char *data) {} + void HandleThermal(char *data) {} + void HandleBlank(char *data) {} + void HandleIdlePowerCollapse(char *data); + void PopulateHWEventData(const vector<HWEvent> &event_list); + DisplayError SetEventParser(); + DisplayError InitializePollFd(); + DisplayError CloseFds(); + DisplayError RegisterVSync(); + + HWEventHandler *event_handler_{}; + vector<HWEventData> event_data_list_{}; + vector<pollfd> poll_fds_{}; + pthread_t event_thread_{}; + std::string event_thread_name_ = "SDM_EventThread"; + bool exit_threads_ = false; + uint32_t vsync_index_ = 0; +}; + +} // namespace sdm + +#endif // __HW_EVENTS_DRM_H__ diff --git a/msm8909/sdm/libs/core/drm/hw_info_drm.cpp b/msm8909/sdm/libs/core/drm/hw_info_drm.cpp new file mode 100644 index 00000000..c59d9db6 --- /dev/null +++ b/msm8909/sdm/libs/core/drm/hw_info_drm.cpp @@ -0,0 +1,594 @@ +/* +* Copyright (c) 2017, 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 <drm/drm_fourcc.h> +#include <drm_lib_loader.h> +#include <drm_master.h> +#include <drm_res_mgr.h> +#include <fcntl.h> +#include <media/msm_sde_rotator.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <utils/constants.h> +#include <utils/debug.h> +#include <utils/sys.h> + +#include <algorithm> +#include <fstream> +#include <iostream> +#include <map> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "hw_info_drm.h" + +#ifndef DRM_FORMAT_MOD_QCOM_COMPRESSED +#define DRM_FORMAT_MOD_QCOM_COMPRESSED fourcc_mod_code(QCOM, 1) +#endif +#ifndef DRM_FORMAT_MOD_QCOM_DX +#define DRM_FORMAT_MOD_QCOM_DX fourcc_mod_code(QCOM, 0x2) +#endif +#ifndef DRM_FORMAT_MOD_QCOM_TIGHT +#define DRM_FORMAT_MOD_QCOM_TIGHT fourcc_mod_code(QCOM, 0x4) +#endif + +#define __CLASS__ "HWInfoDRM" + +using drm_utils::DRMMaster; +using drm_utils::DRMResMgr; +using drm_utils::DRMLogger; +using drm_utils::DRMLibLoader; +using sde_drm::GetDRMManager; +using sde_drm::DRMPlanesInfo; +using sde_drm::DRMCrtcInfo; +using sde_drm::DRMPlaneType; + +using std::vector; +using std::map; +using std::string; +using std::fstream; +using std::to_string; + +namespace sdm { + +class DRMLoggerImpl : public DRMLogger { + public: +#define PRINTLOG(tag, method, format, buf) \ + va_list list; \ + va_start(list, format); \ + vsnprintf(buf, sizeof(buf), format, list); \ + va_end(list); \ + Debug::Get()->method(tag, "%s", buf); + + void Error(const char *format, ...) { PRINTLOG(kTagNone, Error, format, buf_); } + void Warning(const char *format, ...) { PRINTLOG(kTagDriverConfig, Warning, format, buf_); } + void Info(const char *format, ...) { PRINTLOG(kTagDriverConfig, Info, format, buf_); } + void Debug(const char *format, ...) { PRINTLOG(kTagDriverConfig, Debug, format, buf_); } + void Verbose(const char *format, ...) { PRINTLOG(kTagDriverConfig, Verbose, format, buf_); } + + private: + char buf_[1024] = {}; +}; + +HWResourceInfo *HWInfoDRM::hw_resource_ = nullptr; + +HWInfoDRM::HWInfoDRM() { + DRMLogger::Set(new DRMLoggerImpl()); + drm_lib = DRMLibLoader::GetInstance(); + if (drm_lib == nullptr) { + DLOGE("Failed to load DRM Library"); + return; + } + default_mode_ = (drm_lib->IsLoaded() == false); + if (!default_mode_) { + DRMMaster *drm_master = {}; + int dev_fd = -1; + DRMMaster::GetInstance(&drm_master); + if (!drm_master) { + DLOGE("Failed to acquire DRMMaster instance"); + return; + } + drm_master->GetHandle(&dev_fd); + drm_lib->FuncGetDRMManager()(dev_fd, &drm_mgr_intf_); + } +} + +HWInfoDRM::~HWInfoDRM() { + if (hw_resource_ != nullptr) { + delete hw_resource_; + hw_resource_ = nullptr; + } + + if (drm_mgr_intf_) { + if (drm_lib != nullptr) { + drm_lib->FuncDestroyDRMManager()(); + } + drm_mgr_intf_ = nullptr; + } + + drm_lib->Destroy(); + drm_lib = nullptr; + DRMMaster::DestroyInstance(); +} + +DisplayError HWInfoDRM::GetDynamicBWLimits(HWResourceInfo *hw_resource) { + HWDynBwLimitInfo* bw_info = &hw_resource->dyn_bw_info; + for (int index = 0; index < kBwModeMax; index++) { + bw_info->total_bw_limit[index] = UINT32(hw_resource->max_bandwidth_low); + bw_info->pipe_bw_limit[index] = hw_resource->max_pipe_bw; + } + + return kErrorNone; +} + +DisplayError HWInfoDRM::GetHWResourceInfo(HWResourceInfo *hw_resource) { + if (hw_resource_) { + *hw_resource = *hw_resource_; + return kErrorNone; + } + + hw_resource->num_blending_stages = 1; + hw_resource->max_pipe_width = 2560; + hw_resource->max_cursor_size = 128; + hw_resource->max_scale_down = 1; + hw_resource->max_scale_up = 1; + hw_resource->has_decimation = false; + hw_resource->max_bandwidth_low = 9600000; + hw_resource->max_bandwidth_high = 9600000; + hw_resource->max_pipe_bw = 4500000; + hw_resource->max_sde_clk = 412500000; + hw_resource->clk_fudge_factor = FLOAT(105) / FLOAT(100); + hw_resource->macrotile_nv12_factor = 8; + hw_resource->macrotile_factor = 4; + hw_resource->linear_factor = 1; + hw_resource->scale_factor = 1; + hw_resource->extra_fudge_factor = 2; + hw_resource->amortizable_threshold = 0; + hw_resource->system_overhead_lines = 0; + hw_resource->hw_dest_scalar_info.count = 0; + hw_resource->hw_dest_scalar_info.max_scale_up = 0; + hw_resource->hw_dest_scalar_info.max_input_width = 0; + hw_resource->hw_dest_scalar_info.max_output_width = 0; + hw_resource->is_src_split = true; + hw_resource->perf_calc = false; + hw_resource->has_dyn_bw_support = false; + hw_resource->has_qseed3 = false; + hw_resource->has_concurrent_writeback = false; + + // TODO(user): Deprecate + hw_resource->hw_version = kHWMdssVersion5; + hw_resource->hw_revision = 0; + hw_resource->max_mixer_width = 0; + hw_resource->writeback_index = 0; + hw_resource->has_bwc = false; + hw_resource->has_ubwc = true; + hw_resource->has_macrotile = true; + hw_resource->separate_rotator = true; + hw_resource->has_non_scalar_rgb = false; + + GetSystemInfo(hw_resource); + GetHWPlanesInfo(hw_resource); + GetWBInfo(hw_resource); + + // Disable destination scalar count to 0 if extension library is not present + DynLib extension_lib; + if (!extension_lib.Open("libsdmextension.so")) { + hw_resource->hw_dest_scalar_info.count = 0; + } + + DLOGI("Max plane width = %d", hw_resource->max_pipe_width); + DLOGI("Max cursor width = %d", hw_resource->max_cursor_size); + DLOGI("Max plane upscale = %d", hw_resource->max_scale_up); + DLOGI("Max plane downscale = %d", hw_resource->max_scale_down); + DLOGI("Has Decimation = %d", hw_resource->has_decimation); + DLOGI("Max Blending Stages = %d", hw_resource->num_blending_stages); + DLOGI("Has Source Split = %d", hw_resource->is_src_split); + DLOGI("Has QSEED3 = %d", hw_resource->has_qseed3); + DLOGI("Has UBWC = %d", hw_resource->has_ubwc); + DLOGI("Has Concurrent Writeback = %d", hw_resource->has_concurrent_writeback); + DLOGI("Max Low Bw = %" PRIu64 "", hw_resource->max_bandwidth_low); + DLOGI("Max High Bw = % " PRIu64 "", hw_resource->max_bandwidth_high); + DLOGI("Max Pipe Bw = %" PRIu64 " KBps", hw_resource->max_pipe_bw); + DLOGI("MaxSDEClock = % " PRIu64 " Hz", hw_resource->max_sde_clk); + DLOGI("Clock Fudge Factor = %f", hw_resource->clk_fudge_factor); + DLOGI("Prefill factors:"); + DLOGI("\tTiled_NV12 = %d", hw_resource->macrotile_nv12_factor); + DLOGI("\tTiled = %d", hw_resource->macrotile_factor); + DLOGI("\tLinear = %d", hw_resource->linear_factor); + DLOGI("\tScale = %d", hw_resource->scale_factor); + DLOGI("\tFudge_factor = %d", hw_resource->extra_fudge_factor); + + if (hw_resource->separate_rotator || hw_resource->num_dma_pipe) { + GetHWRotatorInfo(hw_resource); + } + + if (hw_resource->has_dyn_bw_support) { + DisplayError ret = GetDynamicBWLimits(hw_resource); + if (ret != kErrorNone) { + DLOGE("Failed to read dynamic band width info"); + return ret; + } + + DLOGI("Has Support for multiple bw limits shown below"); + for (int index = 0; index < kBwModeMax; index++) { + DLOGI("Mode-index=%d total_bw_limit=%d and pipe_bw_limit=%d", index, + hw_resource->dyn_bw_info.total_bw_limit[index], + hw_resource->dyn_bw_info.pipe_bw_limit[index]); + } + } + + if (!hw_resource_) { + hw_resource_ = new HWResourceInfo(); + *hw_resource_ = *hw_resource; + } + + return kErrorNone; +} + +void HWInfoDRM::GetSystemInfo(HWResourceInfo *hw_resource) { + DRMCrtcInfo info; + drm_mgr_intf_->GetCrtcInfo(0 /* system_info */, &info); + hw_resource->is_src_split = info.has_src_split; + hw_resource->has_qseed3 = (info.qseed_version == sde_drm::QSEEDVersion::V3); + hw_resource->num_blending_stages = info.max_blend_stages; + hw_resource->smart_dma_rev = (info.smart_dma_rev == sde_drm::SmartDMARevision::V2) ? + SmartDMARevision::V2 : SmartDMARevision::V1; +} + +void HWInfoDRM::GetHWPlanesInfo(HWResourceInfo *hw_resource) { + DRMPlanesInfo planes; + drm_mgr_intf_->GetPlanesInfo(&planes); + for (auto &pipe_obj : planes) { + HWPipeCaps pipe_caps; + string name = {}; + switch (pipe_obj.second.type) { + case DRMPlaneType::DMA: + name = "DMA"; + pipe_caps.type = kPipeTypeDMA; + if (!hw_resource->num_dma_pipe) { + PopulateSupportedFmts(kHWDMAPipe, pipe_obj.second, hw_resource); + } + hw_resource->num_dma_pipe++; + break; + case DRMPlaneType::VIG: + name = "VIG"; + pipe_caps.type = kPipeTypeVIG; + if (!hw_resource->num_vig_pipe) { + PopulatePipeCaps(pipe_obj.second, hw_resource); + PopulateSupportedFmts(kHWVIGPipe, pipe_obj.second, hw_resource); + } + hw_resource->num_vig_pipe++; + break; + case DRMPlaneType::CURSOR: + name = "CURSOR"; + pipe_caps.type = kPipeTypeCursor; + if (!hw_resource->num_cursor_pipe) { + PopulateSupportedFmts(kHWCursorPipe, pipe_obj.second, hw_resource); + hw_resource->max_cursor_size = pipe_obj.second.max_linewidth; + } + hw_resource->num_cursor_pipe++; + break; + default: + continue; // Not adding any other pipe type + } + pipe_caps.id = pipe_obj.first; + pipe_caps.master_pipe_id = pipe_obj.second.master_plane_id; + DLOGI("Adding %s Pipe : Id %d", name.c_str(), pipe_obj.first); + hw_resource->hw_pipes.push_back(std::move(pipe_caps)); + } +} + +void HWInfoDRM::PopulatePipeCaps(const sde_drm::DRMPlaneTypeInfo &info, + HWResourceInfo *hw_resource) { + hw_resource->max_pipe_width = info.max_linewidth; + hw_resource->max_scale_down = info.max_downscale; + hw_resource->max_scale_up = info.max_upscale; + hw_resource->has_decimation = info.max_horizontal_deci > 1 && info.max_vertical_deci > 1; +} + +void HWInfoDRM::PopulateSupportedFmts(HWSubBlockType sub_blk_type, + const sde_drm::DRMPlaneTypeInfo &info, + HWResourceInfo *hw_resource) { + vector<LayerBufferFormat> sdm_formats; + FormatsMap &fmts_map = hw_resource->supported_formats_map; + + if (fmts_map.find(sub_blk_type) == fmts_map.end()) { + for (auto &fmts : info.formats_supported) { + GetSDMFormat(fmts.first, fmts.second, &sdm_formats); + } + + fmts_map.insert(make_pair(sub_blk_type, sdm_formats)); + } +} + +void HWInfoDRM::GetWBInfo(HWResourceInfo *hw_resource) { + HWSubBlockType sub_blk_type = kHWWBIntfOutput; + vector<LayerBufferFormat> supported_sdm_formats; + sde_drm::DRMDisplayToken token; + + // Fake register + if (drm_mgr_intf_->RegisterDisplay(sde_drm::DRMDisplayType::VIRTUAL, &token)) { + return; + } + + sde_drm::DRMConnectorInfo connector_info; + drm_mgr_intf_->GetConnectorInfo(token.conn_id, &connector_info); + for (auto &fmts : connector_info.formats_supported) { + GetSDMFormat(fmts.first, fmts.second, &supported_sdm_formats); + } + + hw_resource->supported_formats_map.erase(sub_blk_type); + hw_resource->supported_formats_map.insert(make_pair(sub_blk_type, supported_sdm_formats)); + + drm_mgr_intf_->UnregisterDisplay(token); +} + +void HWInfoDRM::GetSDMFormat(uint32_t v4l2_format, LayerBufferFormat *sdm_format) { + switch (v4l2_format) { + case SDE_PIX_FMT_ARGB_8888: *sdm_format = kFormatARGB8888; break; + case SDE_PIX_FMT_RGBA_8888: *sdm_format = kFormatRGBA8888; break; + case SDE_PIX_FMT_BGRA_8888: *sdm_format = kFormatBGRA8888; break; + case SDE_PIX_FMT_RGBX_8888: *sdm_format = kFormatRGBX8888; break; + case SDE_PIX_FMT_BGRX_8888: *sdm_format = kFormatBGRX8888; break; + case SDE_PIX_FMT_RGBA_5551: *sdm_format = kFormatRGBA5551; break; + case SDE_PIX_FMT_RGBA_4444: *sdm_format = kFormatRGBA4444; break; + case SDE_PIX_FMT_RGB_888: *sdm_format = kFormatRGB888; break; + case SDE_PIX_FMT_BGR_888: *sdm_format = kFormatBGR888; break; + case SDE_PIX_FMT_RGB_565: *sdm_format = kFormatRGB565; break; + case SDE_PIX_FMT_BGR_565: *sdm_format = kFormatBGR565; break; + case SDE_PIX_FMT_Y_CB_CR_H2V2: *sdm_format = kFormatYCbCr420Planar; break; + case SDE_PIX_FMT_Y_CR_CB_H2V2: *sdm_format = kFormatYCrCb420Planar; break; + case SDE_PIX_FMT_Y_CR_CB_GH2V2: *sdm_format = kFormatYCrCb420PlanarStride16; break; + case SDE_PIX_FMT_Y_CBCR_H2V2: *sdm_format = kFormatYCbCr420SemiPlanar; break; + case SDE_PIX_FMT_Y_CRCB_H2V2: *sdm_format = kFormatYCrCb420SemiPlanar; break; + case SDE_PIX_FMT_Y_CBCR_H1V2: *sdm_format = kFormatYCbCr422H1V2SemiPlanar; break; + case SDE_PIX_FMT_Y_CRCB_H1V2: *sdm_format = kFormatYCrCb422H1V2SemiPlanar; break; + case SDE_PIX_FMT_Y_CBCR_H2V1: *sdm_format = kFormatYCbCr422H2V1SemiPlanar; break; + case SDE_PIX_FMT_Y_CRCB_H2V1: *sdm_format = kFormatYCrCb422H2V1SemiPlanar; break; + case SDE_PIX_FMT_YCBYCR_H2V1: *sdm_format = kFormatYCbCr422H2V1Packed; break; + case SDE_PIX_FMT_Y_CBCR_H2V2_VENUS: *sdm_format = kFormatYCbCr420SemiPlanarVenus; break; + case SDE_PIX_FMT_Y_CRCB_H2V2_VENUS: *sdm_format = kFormatYCrCb420SemiPlanarVenus; break; + case SDE_PIX_FMT_RGBA_8888_UBWC: *sdm_format = kFormatRGBA8888Ubwc; break; + case SDE_PIX_FMT_RGBX_8888_UBWC: *sdm_format = kFormatRGBX8888Ubwc; break; + case SDE_PIX_FMT_RGB_565_UBWC: *sdm_format = kFormatBGR565Ubwc; break; + case SDE_PIX_FMT_Y_CBCR_H2V2_UBWC: *sdm_format = kFormatYCbCr420SPVenusUbwc; break; + case SDE_PIX_FMT_RGBA_1010102: *sdm_format = kFormatRGBA1010102; break; + case SDE_PIX_FMT_ARGB_2101010: *sdm_format = kFormatARGB2101010; break; + case SDE_PIX_FMT_RGBX_1010102: *sdm_format = kFormatRGBX1010102; break; + case SDE_PIX_FMT_XRGB_2101010: *sdm_format = kFormatXRGB2101010; break; + case SDE_PIX_FMT_BGRA_1010102: *sdm_format = kFormatBGRA1010102; break; + case SDE_PIX_FMT_ABGR_2101010: *sdm_format = kFormatABGR2101010; break; + case SDE_PIX_FMT_BGRX_1010102: *sdm_format = kFormatBGRX1010102; break; + case SDE_PIX_FMT_XBGR_2101010: *sdm_format = kFormatXBGR2101010; break; + case SDE_PIX_FMT_RGBA_1010102_UBWC: *sdm_format = kFormatRGBA1010102Ubwc; break; + case SDE_PIX_FMT_RGBX_1010102_UBWC: *sdm_format = kFormatRGBX1010102Ubwc; break; + case SDE_PIX_FMT_Y_CBCR_H2V2_P010: *sdm_format = kFormatYCbCr420P010; break; + case SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC: *sdm_format = kFormatYCbCr420TP10Ubwc; break; + /* TODO(user) : enable when defined in uapi + case SDE_PIX_FMT_Y_CBCR_H2V2_P010_UBWC: *sdm_format = kFormatYCbCr420P010Ubwc; break; */ + default: *sdm_format = kFormatInvalid; + } +} + +void HWInfoDRM::GetRotatorFormatsForType(int fd, uint32_t type, + vector<LayerBufferFormat> *supported_formats) { + struct v4l2_fmtdesc fmtdesc = {}; + fmtdesc.type = type; + while (!Sys::ioctl_(fd, static_cast<int>(VIDIOC_ENUM_FMT), &fmtdesc)) { + LayerBufferFormat sdm_format = kFormatInvalid; + GetSDMFormat(fmtdesc.pixelformat, &sdm_format); + if (sdm_format != kFormatInvalid) { + supported_formats->push_back(sdm_format); + } + fmtdesc.index++; + } +} + +DisplayError HWInfoDRM::GetRotatorSupportedFormats(uint32_t v4l2_index, + HWResourceInfo *hw_resource) { + string path = "/dev/video" + to_string(v4l2_index); + int fd = Sys::open_(path.c_str(), O_RDONLY); + if (fd < 0) { + DLOGE("Failed to open %s with error %d", path.c_str(), errno); + return kErrorNotSupported; + } + + vector<LayerBufferFormat> supported_formats = {}; + GetRotatorFormatsForType(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT, &supported_formats); + hw_resource->supported_formats_map.erase(kHWRotatorInput); + hw_resource->supported_formats_map.insert(make_pair(kHWRotatorInput, supported_formats)); + + supported_formats = {}; + GetRotatorFormatsForType(fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, &supported_formats); + hw_resource->supported_formats_map.erase(kHWRotatorOutput); + hw_resource->supported_formats_map.insert(make_pair(kHWRotatorOutput, supported_formats)); + + Sys::close_(fd); + + return kErrorNone; +} + +DisplayError HWInfoDRM::GetHWRotatorInfo(HWResourceInfo *hw_resource) { + string v4l2_path = "/sys/class/video4linux/video"; + const uint32_t kMaxV4L2Nodes = 64; + + for (uint32_t i = 0; i < kMaxV4L2Nodes; i++) { + string path = v4l2_path + to_string(i) + "/name"; + Sys::fstream fs(path, fstream::in); + if (!fs.is_open()) { + continue; + } + + string line; + if (Sys::getline_(fs, line) && (!strncmp(line.c_str(), "sde_rotator", strlen("sde_rotator")))) { + hw_resource->hw_rot_info.device_path = string("/dev/video" + to_string(i)); + hw_resource->hw_rot_info.num_rotator++; + hw_resource->hw_rot_info.type = HWRotatorInfo::ROT_TYPE_V4L2; + hw_resource->hw_rot_info.has_downscale = true; + GetRotatorSupportedFormats(i, hw_resource); + + string caps_path = v4l2_path + to_string(i) + "/device/caps"; + Sys::fstream caps_fs(caps_path, fstream::in); + + if (caps_fs.is_open()) { + string caps; + while (Sys::getline_(caps_fs, caps)) { + const string downscale_compression = "downscale_compression="; + const string min_downscale = "min_downscale="; + if (caps.find(downscale_compression) != string::npos) { + hw_resource->hw_rot_info.downscale_compression = + std::stoi(string(caps, downscale_compression.length())); + } else if (caps.find(min_downscale) != string::npos) { + hw_resource->hw_rot_info.min_downscale = + std::stof(string(caps, min_downscale.length())); + } + } + } + + // We support only 1 rotator + break; + } + } + + DLOGI("V4L2 Rotator: Count = %d, Downscale = %d, Min_downscale = %f, Downscale_compression = %d", + hw_resource->hw_rot_info.num_rotator, hw_resource->hw_rot_info.has_downscale, + hw_resource->hw_rot_info.min_downscale, hw_resource->hw_rot_info.downscale_compression); + + return kErrorNone; +} + +void HWInfoDRM::GetSDMFormat(uint32_t drm_format, uint64_t drm_format_modifier, + vector<LayerBufferFormat> *sdm_formats) { + vector<LayerBufferFormat> &fmts(*sdm_formats); + switch (drm_format) { + case DRM_FORMAT_BGRA8888: + fmts.push_back(kFormatARGB8888); + break; + case DRM_FORMAT_ABGR8888: + fmts.push_back(drm_format_modifier ? kFormatRGBA8888Ubwc : kFormatRGBA8888); + break; + case DRM_FORMAT_ARGB8888: + fmts.push_back(kFormatBGRA8888); + break; + case DRM_FORMAT_BGRX8888: + fmts.push_back(kFormatXRGB8888); + break; + case DRM_FORMAT_XBGR8888: + fmts.push_back(drm_format_modifier ? kFormatRGBX8888Ubwc : kFormatRGBX8888); + break; + case DRM_FORMAT_XRGB8888: + fmts.push_back(kFormatBGRX8888); + break; + case DRM_FORMAT_ABGR1555: + fmts.push_back(kFormatRGBA5551); + break; + case DRM_FORMAT_ABGR4444: + fmts.push_back(kFormatRGBA4444); + break; + case DRM_FORMAT_BGR888: + fmts.push_back(kFormatRGB888); + break; + case DRM_FORMAT_RGB888: + fmts.push_back(kFormatBGR888); + break; + case DRM_FORMAT_BGR565: + fmts.push_back(drm_format_modifier ? kFormatBGR565Ubwc : kFormatRGB565); + break; + case DRM_FORMAT_RGB565: + fmts.push_back(kFormatBGR565); + break; + case DRM_FORMAT_ABGR2101010: + fmts.push_back(drm_format_modifier ? kFormatRGBA1010102Ubwc : kFormatRGBA1010102); + break; + case DRM_FORMAT_BGRA1010102: + fmts.push_back(kFormatARGB2101010); + break; + case DRM_FORMAT_XBGR2101010: + fmts.push_back(drm_format_modifier ? kFormatRGBX1010102Ubwc : kFormatRGBX1010102); + break; + case DRM_FORMAT_BGRX1010102: + fmts.push_back(kFormatXRGB2101010); + break; + case DRM_FORMAT_ARGB2101010: + fmts.push_back(kFormatBGRA1010102); + break; + case DRM_FORMAT_RGBA1010102: + fmts.push_back(kFormatABGR2101010); + break; + case DRM_FORMAT_XRGB2101010: + fmts.push_back(kFormatBGRX1010102); + break; + case DRM_FORMAT_RGBX1010102: + fmts.push_back(kFormatXBGR2101010); + break; + case DRM_FORMAT_YVU420: + fmts.push_back(kFormatYCrCb420PlanarStride16); + break; + case DRM_FORMAT_NV12: + if (drm_format_modifier == (DRM_FORMAT_MOD_QCOM_COMPRESSED | + DRM_FORMAT_MOD_QCOM_DX | DRM_FORMAT_MOD_QCOM_TIGHT)) { + fmts.push_back(kFormatYCbCr420TP10Ubwc); + } else if (drm_format_modifier == (DRM_FORMAT_MOD_QCOM_COMPRESSED | + DRM_FORMAT_MOD_QCOM_DX)) { + fmts.push_back(kFormatYCbCr420P010Ubwc); + } else if (drm_format_modifier == DRM_FORMAT_MOD_QCOM_COMPRESSED) { + fmts.push_back(kFormatYCbCr420SPVenusUbwc); + } else if (drm_format_modifier == DRM_FORMAT_MOD_QCOM_DX) { + fmts.push_back(kFormatYCbCr420P010); + } else { + fmts.push_back(kFormatYCbCr420SemiPlanarVenus); + fmts.push_back(kFormatYCbCr420SemiPlanar); + } + break; + case DRM_FORMAT_NV21: + fmts.push_back(kFormatYCrCb420SemiPlanarVenus); + fmts.push_back(kFormatYCrCb420SemiPlanar); + break; + case DRM_FORMAT_NV16: + fmts.push_back(kFormatYCbCr422H2V1SemiPlanar); + break; + default: + break; + } +} + +DisplayError HWInfoDRM::GetFirstDisplayInterfaceType(HWDisplayInterfaceInfo *hw_disp_info) { + hw_disp_info->type = kPrimary; + hw_disp_info->is_connected = true; + + return kErrorNone; +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/core/drm/hw_info_drm.h b/msm8909/sdm/libs/core/drm/hw_info_drm.h new file mode 100644 index 00000000..6194a4bf --- /dev/null +++ b/msm8909/sdm/libs/core/drm/hw_info_drm.h @@ -0,0 +1,82 @@ +/* +* Copyright (c) 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __HW_INFO_DRM_H__ +#define __HW_INFO_DRM_H__ + +#include <core/core_interface.h> +#include <core/sdm_types.h> +#include <drm_interface.h> +#include <private/hw_info_types.h> +#include <bitset> +#include <vector> +#include <drm_lib_loader.h> + +#include "hw_info_interface.h" + +namespace sdm { + +class HWInfoDRM: public HWInfoInterface { + public: + HWInfoDRM(); + virtual ~HWInfoDRM(); + virtual DisplayError GetHWResourceInfo(HWResourceInfo *hw_resource); + virtual DisplayError GetFirstDisplayInterfaceType(HWDisplayInterfaceInfo *hw_disp_info); + + private: + DisplayError GetHWRotatorInfo(HWResourceInfo *hw_resource); + void GetSystemInfo(HWResourceInfo *hw_resource); + void GetHWPlanesInfo(HWResourceInfo *hw_resource); + void GetWBInfo(HWResourceInfo *hw_resource); + DisplayError GetDynamicBWLimits(HWResourceInfo *hw_resource); + void GetSDMFormat(uint32_t drm_format, uint64_t drm_format_modifier, + std::vector<LayerBufferFormat> *sdm_formats); + void GetSDMFormat(uint32_t v4l2_format, LayerBufferFormat *sdm_format); + void GetRotatorFormatsForType(int fd, uint32_t type, + std::vector<LayerBufferFormat> *supported_formats); + DisplayError GetRotatorSupportedFormats(uint32_t v4l2_index, HWResourceInfo *hw_resource); + void PopulateSupportedFmts(HWSubBlockType sub_blk_type, const sde_drm::DRMPlaneTypeInfo &info, + HWResourceInfo *hw_resource); + void PopulatePipeCaps(const sde_drm::DRMPlaneTypeInfo &info, HWResourceInfo *hw_resource); + + + sde_drm::DRMManagerInterface *drm_mgr_intf_ = {}; + bool default_mode_ = false; + + // TODO(user): Read Mdss version from the driver + static const int kHWMdssVersion5 = 500; // MDSS_V5 + static const int kMaxStringLength = 1024; + static HWResourceInfo *hw_resource_; + + drm_utils::DRMLibLoader *drm_lib = nullptr; +}; + +} // namespace sdm + +#endif // __HW_INFO_DRM_H__ diff --git a/msm8909/sdm/libs/core/drm/hw_scale_drm.cpp b/msm8909/sdm/libs/core/drm/hw_scale_drm.cpp new file mode 100644 index 00000000..96f084e0 --- /dev/null +++ b/msm8909/sdm/libs/core/drm/hw_scale_drm.cpp @@ -0,0 +1,157 @@ +/* +* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <utils/debug.h> + +#include "hw_scale_drm.h" + +#define __CLASS__ "HWScaleDRM" + +namespace sdm { + +static uint32_t GetScalingFilter(ScalingFilterConfig filter_cfg) { + switch (filter_cfg) { + case kFilterEdgeDirected: + return FILTER_EDGE_DIRECTED_2D; + case kFilterCircular: + return FILTER_CIRCULAR_2D; + case kFilterSeparable: + return FILTER_SEPARABLE_1D; + case kFilterBilinear: + return FILTER_BILINEAR; + default: + DLOGE("Invalid Scaling Filter"); + return kFilterMax; + } +} + +static uint32_t GetAlphaInterpolation(HWAlphaInterpolation alpha_filter_cfg) { + switch (alpha_filter_cfg) { + case kInterpolationPixelRepeat: + return FILTER_ALPHA_DROP_REPEAT; + case kInterpolationBilinear: + return FILTER_ALPHA_BILINEAR; + default: + DLOGE("Invalid Alpha Interpolation"); + return kInterpolationMax; + } +} + +void HWScaleDRM::SetPlaneScaler(const HWScaleData &scale_data, SDEScaler *scaler) { + if (version_ == Version::V2) { + SetPlaneScalerV2(scale_data, &scaler->scaler_v2); + } +} + +void HWScaleDRM::SetPlaneScalerV2(const HWScaleData &scale_data, sde_drm_scaler_v2 *scaler) { + if (!scale_data.enable.scale && !scale_data.enable.direction_detection && + !scale_data.enable.detail_enhance) { + return; + } + + scaler->enable = scale_data.enable.scale; + scaler->dir_en = scale_data.enable.direction_detection; + scaler->de.enable = scale_data.detail_enhance.enable; + + for (int i = 0; i < SDE_MAX_PLANES; i++) { + const HWPlane &plane = scale_data.plane[i]; + scaler->init_phase_x[i] = plane.init_phase_x; + scaler->phase_step_x[i] = plane.phase_step_x; + scaler->init_phase_y[i] = plane.init_phase_y; + scaler->phase_step_y[i] = plane.phase_step_y; + + // TODO(user): Remove right, bottom from HWPlane and rename to LR, TB similar to qseed3 + // Also remove roi_width which is unused. + scaler->pe.num_ext_pxls_lr[i] = plane.left.extension; + scaler->pe.num_ext_pxls_tb[i] = plane.top.extension; + + scaler->pe.left_ftch[i] = plane.left.overfetch; + scaler->pe.top_ftch[i] = plane.top.overfetch; + scaler->pe.right_ftch[i] = plane.right.overfetch; + scaler->pe.btm_ftch[i] = plane.bottom.overfetch; + + scaler->pe.left_rpt[i] = plane.left.repeat; + scaler->pe.top_rpt[i] = plane.top.repeat; + scaler->pe.right_rpt[i] = plane.right.repeat; + scaler->pe.btm_rpt[i] = plane.bottom.repeat; + + scaler->preload_x[i] = UINT32(plane.preload_x); + scaler->preload_y[i] = UINT32(plane.preload_y); + + scaler->src_width[i] = plane.src_width; + scaler->src_height[i] = plane.src_height; + } + + scaler->dst_width = scale_data.dst_width; + scaler->dst_height = scale_data.dst_height; + + scaler->y_rgb_filter_cfg = GetScalingFilter(scale_data.y_rgb_filter_cfg); + scaler->uv_filter_cfg = GetScalingFilter(scale_data.uv_filter_cfg); + scaler->alpha_filter_cfg = GetAlphaInterpolation(scale_data.alpha_filter_cfg); + scaler->blend_cfg = scale_data.blend_cfg; + + scaler->lut_flag = (scale_data.lut_flag.lut_swap ? SCALER_LUT_SWAP : 0) | + (scale_data.lut_flag.lut_dir_wr ? SCALER_LUT_DIR_WR : 0) | + (scale_data.lut_flag.lut_y_cir_wr ? SCALER_LUT_Y_CIR_WR : 0) | + (scale_data.lut_flag.lut_uv_cir_wr ? SCALER_LUT_UV_CIR_WR : 0) | + (scale_data.lut_flag.lut_y_sep_wr ? SCALER_LUT_Y_SEP_WR : 0) | + (scale_data.lut_flag.lut_uv_sep_wr ? SCALER_LUT_UV_SEP_WR : 0); + + scaler->dir_lut_idx = scale_data.dir_lut_idx; + scaler->y_rgb_cir_lut_idx = scale_data.y_rgb_cir_lut_idx; + scaler->uv_cir_lut_idx = scale_data.uv_cir_lut_idx; + scaler->y_rgb_sep_lut_idx = scale_data.y_rgb_sep_lut_idx; + scaler->uv_sep_lut_idx = scale_data.uv_sep_lut_idx; + + /* TODO(user): Uncomment when de support is added + if (scaler->de.enable) { + sde_drm_de_v1 *det_enhance = &scaler->de; + det_enhance->sharpen_level1 = scale_data.detail_enhance.sharpen_level1; + det_enhance->sharpen_level2 = scale_data.detail_enhance.sharpen_level2; + det_enhance->clip = scale_data.detail_enhance.clip; + det_enhance->limit = scale_data.detail_enhance.limit; + det_enhance->thr_quiet = scale_data.detail_enhance.thr_quiet; + det_enhance->thr_dieout = scale_data.detail_enhance.thr_dieout; + det_enhance->thr_low = scale_data.detail_enhance.thr_low; + det_enhance->thr_high = scale_data.detail_enhance.thr_high; + det_enhance->prec_shift = scale_data.detail_enhance.prec_shift; + + for (int i = 0; i < SDE_MAX_DE_CURVES; i++) { + det_enhance->adjust_a[i] = scale_data.detail_enhance.adjust_a[i]; + det_enhance->adjust_b[i] = scale_data.detail_enhance.adjust_b[i]; + det_enhance->adjust_c[i] = scale_data.detail_enhance.adjust_c[i]; + } + } + */ + + return; +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/core/drm/hw_scale_drm.h b/msm8909/sdm/libs/core/drm/hw_scale_drm.h new file mode 100644 index 00000000..8a4be70b --- /dev/null +++ b/msm8909/sdm/libs/core/drm/hw_scale_drm.h @@ -0,0 +1,63 @@ +/* +* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __HW_SCALE_DRM_H__ +#define __HW_SCALE_DRM_H__ + +#include <stdint.h> +#include <stdlib.h> +#include <drm.h> +// The 3 headers above are a workaround to prevent kernel drm.h from being used that has the +// "virtual" keyword used for a variable. In future replace libdrm version drm.h with kernel +// version drm/drm.h +#include <drm/sde_drm.h> +#include <private/hw_info_types.h> + +namespace sdm { + +struct SDEScaler { + struct sde_drm_scaler_v2 scaler_v2 = {}; + // More here, maybe in a union +}; + +class HWScaleDRM { + public: + enum class Version { V2 }; + explicit HWScaleDRM(Version v) : version_(v) {} + void SetPlaneScaler(const HWScaleData &scale, SDEScaler *scaler); + + private: + void SetPlaneScalerV2(const HWScaleData &scale, sde_drm_scaler_v2 *scaler_v2); + + Version version_ = Version::V2; +}; + +} // namespace sdm + +#endif // __HW_SCALE_DRM_H__ diff --git a/msm8909/sdm/libs/core/fb/hw_color_manager.cpp b/msm8909/sdm/libs/core/fb/hw_color_manager.cpp new file mode 100644 index 00000000..051d5cb7 --- /dev/null +++ b/msm8909/sdm/libs/core/fb/hw_color_manager.cpp @@ -0,0 +1,188 @@ +/* +* Copyright (c) 2015-2017, 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 <ctype.h> +#include <math.h> +#include <fcntl.h> +#include <inttypes.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/resource.h> +#include <sys/prctl.h> +#include <linux/msm_mdp.h> +#include <utils/constants.h> +#include <utils/debug.h> +#include "hw_color_manager.h" + +#define __CLASS__ "HWColorManager" + +namespace sdm { + +DisplayError (*HWColorManager::SetFeature[])(const PPFeatureInfo &, msmfb_mdp_pp *) = { + [kGlobalColorFeaturePcc] = &HWColorManager::SetPCC, + [kGlobalColorFeatureIgc] = &HWColorManager::SetIGC, + [kGlobalColorFeaturePgc] = &HWColorManager::SetPGC, + [kMixerColorFeatureGc] = &HWColorManager::SetMixerGC, + [kGlobalColorFeaturePaV2] = &HWColorManager::SetPAV2, + [kGlobalColorFeatureDither] = &HWColorManager::SetDither, + [kGlobalColorFeatureGamut] = &HWColorManager::SetGamut, + [kGlobalColorFeaturePADither] = &HWColorManager::SetPADither, + [kGlobalColorFeatureCsc] = &HWColorManager::SetCSCLegacy, +}; + +DisplayError HWColorManager::SetPCC(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params) { + DisplayError ret = kErrorNone; + + kernel_params->op = mdp_op_pcc_cfg; + kernel_params->data.pcc_cfg_data.version = feature.feature_version_; + kernel_params->data.pcc_cfg_data.block = MDP_LOGICAL_BLOCK_DISP_0 + feature.disp_id_; + kernel_params->data.pcc_cfg_data.ops = feature.enable_flags_; + kernel_params->data.pcc_cfg_data.cfg_payload = feature.GetConfigData(); + DLOGV_IF(kTagQDCM, "kernel params version = %d, block = %d, flags = %d", + kernel_params->data.pcc_cfg_data.version, kernel_params->data.pcc_cfg_data.block, + kernel_params->data.pcc_cfg_data.ops); + + return ret; +} + +DisplayError HWColorManager::SetIGC(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params) { + DisplayError ret = kErrorNone; + + kernel_params->op = mdp_op_lut_cfg; + kernel_params->data.lut_cfg_data.lut_type = mdp_lut_igc; + kernel_params->data.lut_cfg_data.data.igc_lut_data.block = + MDP_LOGICAL_BLOCK_DISP_0 + feature.disp_id_; + kernel_params->data.lut_cfg_data.data.igc_lut_data.version = feature.feature_version_; + kernel_params->data.lut_cfg_data.data.igc_lut_data.ops = feature.enable_flags_; + kernel_params->data.lut_cfg_data.data.igc_lut_data.cfg_payload = feature.GetConfigData(); + + return ret; +} + +DisplayError HWColorManager::SetPGC(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params) { + DisplayError ret = kErrorNone; + + kernel_params->op = mdp_op_lut_cfg; + kernel_params->data.lut_cfg_data.lut_type = mdp_lut_pgc; + kernel_params->data.lut_cfg_data.data.pgc_lut_data.version = feature.feature_version_; + kernel_params->data.lut_cfg_data.data.pgc_lut_data.block = + MDP_LOGICAL_BLOCK_DISP_0 + feature.disp_id_; + kernel_params->data.lut_cfg_data.data.pgc_lut_data.flags = feature.enable_flags_; + kernel_params->data.lut_cfg_data.data.pgc_lut_data.cfg_payload = feature.GetConfigData(); + + return ret; +} + +DisplayError HWColorManager::SetMixerGC(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params) { + DisplayError ret = kErrorNone; + + kernel_params->op = mdp_op_lut_cfg; + kernel_params->data.lut_cfg_data.lut_type = mdp_lut_pgc; + kernel_params->data.lut_cfg_data.data.pgc_lut_data.version = feature.feature_version_; + kernel_params->data.lut_cfg_data.data.pgc_lut_data.block = + (MDP_LOGICAL_BLOCK_DISP_0 + feature.disp_id_) | MDSS_PP_LM_CFG; + kernel_params->data.lut_cfg_data.data.pgc_lut_data.flags = feature.enable_flags_; + kernel_params->data.lut_cfg_data.data.pgc_lut_data.cfg_payload = feature.GetConfigData(); + return ret; +} + +DisplayError HWColorManager::SetPAV2(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params) { + DisplayError ret = kErrorNone; + + kernel_params->op = mdp_op_pa_v2_cfg; + kernel_params->data.pa_v2_cfg_data.version = feature.feature_version_; + kernel_params->data.pa_v2_cfg_data.block = MDP_LOGICAL_BLOCK_DISP_0 + feature.disp_id_; + kernel_params->data.pa_v2_cfg_data.flags = feature.enable_flags_; + kernel_params->data.pa_v2_cfg_data.cfg_payload = feature.GetConfigData(); + DLOGV_IF(kTagQDCM, "kernel params version = %d, block = %d, flags = %d", + kernel_params->data.pa_v2_cfg_data.version, kernel_params->data.pa_v2_cfg_data.block, + kernel_params->data.pa_v2_cfg_data.flags); + + return ret; +} + +DisplayError HWColorManager::SetDither(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params) { + DisplayError ret = kErrorNone; + + kernel_params->op = mdp_op_dither_cfg; + kernel_params->data.dither_cfg_data.version = feature.feature_version_; + kernel_params->data.dither_cfg_data.block = MDP_LOGICAL_BLOCK_DISP_0 + feature.disp_id_; + kernel_params->data.dither_cfg_data.flags = feature.enable_flags_; + kernel_params->data.dither_cfg_data.cfg_payload = feature.GetConfigData(); + + return ret; +} + +DisplayError HWColorManager::SetGamut(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params) { + DisplayError ret = kErrorNone; + + kernel_params->op = mdp_op_gamut_cfg; + kernel_params->data.gamut_cfg_data.version = feature.feature_version_; + kernel_params->data.gamut_cfg_data.block = MDP_LOGICAL_BLOCK_DISP_0 + feature.disp_id_; + kernel_params->data.gamut_cfg_data.flags = feature.enable_flags_; + kernel_params->data.gamut_cfg_data.cfg_payload = feature.GetConfigData(); + + return ret; +} + +DisplayError HWColorManager::SetPADither(const PPFeatureInfo &feature, + msmfb_mdp_pp *kernel_params) { + DisplayError ret = kErrorNone; +#ifdef PA_DITHER + kernel_params->op = mdp_op_pa_dither_cfg; + kernel_params->data.dither_cfg_data.version = feature.feature_version_; + kernel_params->data.dither_cfg_data.block = MDP_LOGICAL_BLOCK_DISP_0 + feature.disp_id_; + kernel_params->data.dither_cfg_data.flags = feature.enable_flags_; + kernel_params->data.dither_cfg_data.cfg_payload = feature.GetConfigData(); +#endif + return ret; +} + +DisplayError HWColorManager::SetCSCLegacy(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params) { + DisplayError ret = kErrorNone; + + kernel_params->op = mdp_op_csc_cfg; + kernel_params->data.csc_cfg_data.block = MDP_BLOCK_DMA_P; + std::memcpy(&kernel_params->data.csc_cfg_data.csc_data, feature.GetConfigData(), + sizeof(mdp_csc_cfg)); + + for( int row = 0; row < 3; row++) { + DLOGV_IF(kTagQDCM, "kernel mv[%d][0]=0x%x mv[%d][1]=0x%x mv[%d][2]=0x%x\n", + row, kernel_params->data.csc_cfg_data.csc_data.csc_mv[row*3 + 0], + row, kernel_params->data.csc_cfg_data.csc_data.csc_mv[row*3 + 1], + row, kernel_params->data.csc_cfg_data.csc_data.csc_mv[row*3 + 2]); + DLOGV_IF(kTagQDCM, "kernel pre_bv[%d]=%x\n", row, + kernel_params->data.csc_cfg_data.csc_data.csc_pre_bv[row]); + DLOGV_IF(kTagQDCM, "kernel post_bv[%d]=%x\n", row, + kernel_params->data.csc_cfg_data.csc_data.csc_post_bv[row]); + } + return ret; +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/core/fb/hw_color_manager.h b/msm8909/sdm/libs/core/fb/hw_color_manager.h new file mode 100644 index 00000000..46e41f51 --- /dev/null +++ b/msm8909/sdm/libs/core/fb/hw_color_manager.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2015-2017, The Linux Foundataion. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#ifndef __HW_COLOR_MANAGER_H__ +#define __HW_COLOR_MANAGER_H__ + +#include <linux/msm_mdp_ext.h> +#include <linux/msm_mdp.h> + +#include <private/color_params.h> + +namespace sdm { + +class HWColorManager { + public: + static DisplayError SetPCC(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params); + static DisplayError SetIGC(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params); + static DisplayError SetPGC(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params); + static DisplayError SetMixerGC(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params); + static DisplayError SetPAV2(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params); + static DisplayError SetDither(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params); + static DisplayError SetGamut(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params); + static DisplayError SetPADither(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params); + static DisplayError SetCSCLegacy(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params); + static DisplayError (*SetFeature[kMaxNumPPFeatures])(const PPFeatureInfo &feature, + msmfb_mdp_pp *kernel_params); + + protected: + HWColorManager() {} +}; + +} // namespace sdm + +#endif // __HW_COLOR_MANAGER_H__ diff --git a/msm8909/sdm/libs/core/fb/hw_device.cpp b/msm8909/sdm/libs/core/fb/hw_device.cpp new file mode 100644 index 00000000..491c6cfd --- /dev/null +++ b/msm8909/sdm/libs/core/fb/hw_device.cpp @@ -0,0 +1,1368 @@ +/* +* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define __STDC_FORMAT_MACROS + +#include <stdio.h> +#include <ctype.h> +#include <math.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <inttypes.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <linux/fb.h> +#include <utils/constants.h> +#include <utils/debug.h> +#include <utils/sys.h> +#include <vector> +#include <algorithm> +#include <string> + +#include "hw_device.h" +#include "hw_primary.h" +#include "hw_hdmi.h" +#include "hw_virtual.h" +#include "hw_info_interface.h" + +#define __CLASS__ "HWDevice" + +using std::string; +using std::to_string; +using std::fstream; + +namespace sdm { + +HWDevice::HWDevice(BufferSyncHandler *buffer_sync_handler) + : fb_node_index_(-1), fb_path_("/sys/devices/virtual/graphics/fb"), + buffer_sync_handler_(buffer_sync_handler), synchronous_commit_(false) { +} + +DisplayError HWDevice::Init() { + // Read the fb node index + fb_node_index_ = GetFBNodeIndex(device_type_); + if (fb_node_index_ == -1) { + DLOGE("device type = %d should be present", device_type_); + return kErrorHardware; + } + + const char *dev_name = NULL; + vector<string> dev_paths = {"/dev/graphics/fb", "/dev/fb"}; + for (size_t i = 0; i < dev_paths.size(); i++) { + dev_paths[i] += to_string(fb_node_index_); + if (Sys::access_(dev_paths[i].c_str(), F_OK) >= 0) { + dev_name = dev_paths[i].c_str(); + DLOGI("access(%s) successful", dev_name); + break; + } + + DLOGI("access(%s), errno = %d, error = %s", dev_paths[i].c_str(), errno, strerror(errno)); + } + + if (!dev_name) { + DLOGE("access() failed for all possible paths"); + return kErrorHardware; + } + + // Populate Panel Info (Used for Partial Update) + PopulateHWPanelInfo(); + // Populate HW Capabilities + hw_resource_ = HWResourceInfo(); + hw_info_intf_->GetHWResourceInfo(&hw_resource_); + + device_fd_ = Sys::open_(dev_name, O_RDWR); + if (device_fd_ < 0) { + DLOGE("open %s failed errno = %d, error = %s", dev_name, errno, strerror(errno)); + return kErrorResources; + } + + return HWScale::Create(&hw_scale_, hw_resource_.has_qseed3); +} + +DisplayError HWDevice::Deinit() { + HWScale::Destroy(hw_scale_); + + if (device_fd_ >= 0) { + Sys::close_(device_fd_); + device_fd_ = -1; + } + + if (stored_retire_fence >= 0) { + Sys::close_(stored_retire_fence); + stored_retire_fence = -1; + } + return kErrorNone; +} + +DisplayError HWDevice::GetActiveConfig(uint32_t *active_config) { + *active_config = 0; + return kErrorNone; +} + +DisplayError HWDevice::GetNumDisplayAttributes(uint32_t *count) { + *count = 1; + return kErrorNone; +} + +DisplayError HWDevice::GetDisplayAttributes(uint32_t index, + HWDisplayAttributes *display_attributes) { + return kErrorNone; +} + +DisplayError HWDevice::GetHWPanelInfo(HWPanelInfo *panel_info) { + *panel_info = hw_panel_info_; + return kErrorNone; +} + +DisplayError HWDevice::SetDisplayAttributes(uint32_t index) { + return kErrorNone; +} + +DisplayError HWDevice::SetDisplayAttributes(const HWDisplayAttributes &display_attributes) { + return kErrorNotSupported; +} + +DisplayError HWDevice::GetConfigIndex(uint32_t mode, uint32_t *index) { + return kErrorNone; +} + +DisplayError HWDevice::PowerOn() { + DTRACE_SCOPED(); + + if (Sys::ioctl_(device_fd_, FBIOBLANK, FB_BLANK_UNBLANK) < 0) { + if (errno == ESHUTDOWN) { + DLOGI_IF(kTagDriverConfig, "Driver is processing shutdown sequence"); + return kErrorShutDown; + } + IOCTL_LOGE(FB_BLANK_UNBLANK, device_type_); + return kErrorHardware; + } + + return kErrorNone; +} + +DisplayError HWDevice::PowerOff() { + return kErrorNone; +} + +DisplayError HWDevice::Doze() { + return kErrorNone; +} + +DisplayError HWDevice::DozeSuspend() { + return kErrorNone; +} + +DisplayError HWDevice::Standby() { + return kErrorNone; +} + +DisplayError HWDevice::Validate(HWLayers *hw_layers) { + DTRACE_SCOPED(); + + DisplayError error = kErrorNone; + + HWLayersInfo &hw_layer_info = hw_layers->info; + uint32_t hw_layer_count = UINT32(hw_layer_info.hw_layers.size()); + + DLOGD_IF(kTagDriverConfig, "************************** %s Validate Input ***********************", + device_name_); + DLOGD_IF(kTagDriverConfig, "SDE layer count is %d", hw_layer_count); + + mdp_layer_commit_v1 &mdp_commit = mdp_disp_commit_.commit_v1; + uint32_t &mdp_layer_count = mdp_commit.input_layer_cnt; + + DLOGI_IF(kTagDriverConfig, "left_roi: x = %d, y = %d, w = %d, h = %d", mdp_commit.left_roi.x, + mdp_commit.left_roi.y, mdp_commit.left_roi.w, mdp_commit.left_roi.h); + DLOGI_IF(kTagDriverConfig, "right_roi: x = %d, y = %d, w = %d, h = %d", mdp_commit.right_roi.x, + mdp_commit.right_roi.y, mdp_commit.right_roi.w, mdp_commit.right_roi.h); + + for (uint32_t i = 0; i < hw_layer_count; i++) { + const Layer &layer = hw_layer_info.hw_layers.at(i); + LayerBuffer input_buffer = layer.input_buffer; + HWPipeInfo *left_pipe = &hw_layers->config[i].left_pipe; + HWPipeInfo *right_pipe = &hw_layers->config[i].right_pipe; + HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session; + bool is_rotator_used = (hw_rotator_session->hw_block_count != 0); + bool is_cursor_pipe_used = (hw_layer_info.use_hw_cursor & layer.flags.cursor); + + for (uint32_t count = 0; count < 2; count++) { + HWPipeInfo *pipe_info = (count == 0) ? left_pipe : right_pipe; + HWRotateInfo *hw_rotate_info = &hw_rotator_session->hw_rotate_info[count]; + + if (hw_rotate_info->valid) { + input_buffer = hw_rotator_session->output_buffer; + } + + if (pipe_info->valid) { + mdp_input_layer &mdp_layer = mdp_in_layers_[mdp_layer_count]; + mdp_layer_buffer &mdp_buffer = mdp_layer.buffer; + + mdp_buffer.width = input_buffer.width; + mdp_buffer.height = input_buffer.height; + mdp_buffer.comp_ratio.denom = 1000; + mdp_buffer.comp_ratio.numer = UINT32(hw_layers->config[i].compression * 1000); + + if (layer.flags.solid_fill) { + mdp_buffer.format = MDP_ARGB_8888; + } else { + error = SetFormat(input_buffer.format, &mdp_buffer.format); + if (error != kErrorNone) { + return error; + } + } + mdp_layer.alpha = layer.plane_alpha; + mdp_layer.z_order = UINT16(pipe_info->z_order); + mdp_layer.transp_mask = 0xffffffff; + SetBlending(layer.blending, &mdp_layer.blend_op); + mdp_layer.pipe_ndx = pipe_info->pipe_id; + mdp_layer.horz_deci = pipe_info->horizontal_decimation; + mdp_layer.vert_deci = pipe_info->vertical_decimation; +#ifdef MDP_COMMIT_RECT_NUM + mdp_layer.rect_num = pipe_info->rect; +#endif + SetRect(pipe_info->src_roi, &mdp_layer.src_rect); + SetRect(pipe_info->dst_roi, &mdp_layer.dst_rect); + SetMDPFlags(&layer, is_rotator_used, is_cursor_pipe_used, &mdp_layer.flags); + SetCSC(layer.input_buffer.color_metadata, &mdp_layer.color_space); + if (pipe_info->flags & kIGC) { + SetIGC(&layer.input_buffer, mdp_layer_count); + } + if (pipe_info->flags & kMultiRect) { + mdp_layer.flags |= MDP_LAYER_MULTIRECT_ENABLE; + if (pipe_info->flags & kMultiRectParallelMode) { + mdp_layer.flags |= MDP_LAYER_MULTIRECT_PARALLEL_MODE; + } + } + mdp_layer.bg_color = layer.solid_fill_color; + + // HWScaleData to MDP driver + hw_scale_->SetHWScaleData(pipe_info->scale_data, mdp_layer_count, &mdp_commit, + pipe_info->sub_block_type); + mdp_layer.scale = hw_scale_->GetScaleDataRef(mdp_layer_count, pipe_info->sub_block_type); + + mdp_layer_count++; + + DLOGD_IF(kTagDriverConfig, "******************* Layer[%d] %s pipe Input ******************", + i, count ? "Right" : "Left"); + DLOGD_IF(kTagDriverConfig, "in_w %d, in_h %d, in_f %d", mdp_buffer.width, mdp_buffer.height, + mdp_buffer.format); + DLOGD_IF(kTagDriverConfig, "plane_alpha %d, zorder %d, blending %d, horz_deci %d, " + "vert_deci %d, pipe_id = 0x%x, mdp_flags 0x%x", mdp_layer.alpha, mdp_layer.z_order, + mdp_layer.blend_op, mdp_layer.horz_deci, mdp_layer.vert_deci, mdp_layer.pipe_ndx, + mdp_layer.flags); + DLOGV_IF(kTagDriverConfig, "src_rect [%d, %d, %d, %d]", mdp_layer.src_rect.x, + mdp_layer.src_rect.y, mdp_layer.src_rect.w, mdp_layer.src_rect.h); + DLOGV_IF(kTagDriverConfig, "dst_rect [%d, %d, %d, %d]", mdp_layer.dst_rect.x, + mdp_layer.dst_rect.y, mdp_layer.dst_rect.w, mdp_layer.dst_rect.h); + hw_scale_->DumpScaleData(mdp_layer.scale); + DLOGD_IF(kTagDriverConfig, "*************************************************************"); + } + } + } + + // TODO(user): This block should move to the derived class + if (device_type_ == kDeviceVirtual) { + LayerBuffer *output_buffer = hw_layers->info.stack->output_buffer; + mdp_out_layer_.writeback_ndx = hw_resource_.writeback_index; + mdp_out_layer_.buffer.width = output_buffer->width; + mdp_out_layer_.buffer.height = output_buffer->height; + if (output_buffer->flags.secure) { + mdp_out_layer_.flags |= MDP_LAYER_SECURE_SESSION; + } + mdp_out_layer_.buffer.comp_ratio.denom = 1000; + mdp_out_layer_.buffer.comp_ratio.numer = UINT32(hw_layers->output_compression * 1000); +#ifdef OUT_LAYER_COLOR_SPACE + SetCSC(output_buffer->color_metadata, &mdp_out_layer_.color_space); +#endif + SetFormat(output_buffer->format, &mdp_out_layer_.buffer.format); + + DLOGI_IF(kTagDriverConfig, "********************* Output buffer Info ************************"); + DLOGI_IF(kTagDriverConfig, "out_w %d, out_h %d, out_f %d, wb_id %d", + mdp_out_layer_.buffer.width, mdp_out_layer_.buffer.height, + mdp_out_layer_.buffer.format, mdp_out_layer_.writeback_ndx); + DLOGI_IF(kTagDriverConfig, "*****************************************************************"); + } + + uint32_t index = 0; + for (uint32_t i = 0; i < hw_resource_.hw_dest_scalar_info.count; i++) { + DestScaleInfoMap::iterator it = hw_layer_info.dest_scale_info_map.find(i); + + if (it == hw_layer_info.dest_scale_info_map.end()) { + continue; + } + + HWDestScaleInfo *dest_scale_info = it->second; + + mdp_destination_scaler_data *dest_scalar_data = &mdp_dest_scalar_data_[index]; + hw_scale_->SetHWScaleData(dest_scale_info->scale_data, index, &mdp_commit, + kHWDestinationScalar); + + if (dest_scale_info->scale_update) { + dest_scalar_data->flags |= MDP_DESTSCALER_SCALE_UPDATE; + } + + dest_scalar_data->dest_scaler_ndx = i; + dest_scalar_data->lm_width = dest_scale_info->mixer_width; + dest_scalar_data->lm_height = dest_scale_info->mixer_height; +#ifdef MDP_DESTSCALER_ROI_ENABLE + SetRect(dest_scale_info->panel_roi, &dest_scalar_data->panel_roi); + dest_scalar_data->flags |= MDP_DESTSCALER_ROI_ENABLE; +#endif + dest_scalar_data->scale = reinterpret_cast <uint64_t> + (hw_scale_->GetScaleDataRef(index, kHWDestinationScalar)); + + index++; + + DLOGD_IF(kTagDriverConfig, "************************ DestScalar[%d] **************************", + dest_scalar_data->dest_scaler_ndx); + DLOGD_IF(kTagDriverConfig, "Mixer WxH %dx%d flags %x", dest_scalar_data->lm_width, + dest_scalar_data->lm_height, dest_scalar_data->flags); +#ifdef MDP_DESTSCALER_ROI_ENABLE + DLOGD_IF(kTagDriverConfig, "Panel ROI [%d, %d, %d, %d]", dest_scalar_data->panel_roi.x, + dest_scalar_data->panel_roi.y, dest_scalar_data->panel_roi.w, + dest_scalar_data->panel_roi.h); +#endif + DLOGD_IF(kTagDriverConfig, "*****************************************************************"); + } + mdp_commit.dest_scaler_cnt = UINT32(hw_layer_info.dest_scale_info_map.size()); + + mdp_commit.flags |= MDP_VALIDATE_LAYER; +#ifdef MDP_COMMIT_RECT_NUM + mdp_commit.flags |= MDP_COMMIT_RECT_NUM; +#endif + if (Sys::ioctl_(device_fd_, INT(MSMFB_ATOMIC_COMMIT), &mdp_disp_commit_) < 0) { + if (errno == ESHUTDOWN) { + DLOGI_IF(kTagDriverConfig, "Driver is processing shutdown sequence"); + return kErrorShutDown; + } + IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, device_type_); + DumpLayerCommit(mdp_disp_commit_); + return kErrorHardware; + } + + return kErrorNone; +} + +void HWDevice::DumpLayerCommit(const mdp_layer_commit &layer_commit) { + const mdp_layer_commit_v1 &mdp_commit = layer_commit.commit_v1; + const mdp_input_layer *mdp_layers = mdp_commit.input_layers; + const mdp_rect &l_roi = mdp_commit.left_roi; + const mdp_rect &r_roi = mdp_commit.right_roi; + + DLOGI("mdp_commit: flags = %x, release fence = %x", mdp_commit.flags, mdp_commit.release_fence); + DLOGI("left_roi: x = %d, y = %d, w = %d, h = %d", l_roi.x, l_roi.y, l_roi.w, l_roi.h); + DLOGI("right_roi: x = %d, y = %d, w = %d, h = %d", r_roi.x, r_roi.y, r_roi.w, r_roi.h); + for (uint32_t i = 0; i < mdp_commit.dest_scaler_cnt; i++) { + mdp_destination_scaler_data *dest_scalar_data = &mdp_dest_scalar_data_[i]; + mdp_scale_data_v2 *mdp_scale = reinterpret_cast<mdp_scale_data_v2 *>(dest_scalar_data->scale); + + DLOGI("Dest scalar index %d Mixer WxH %dx%d", dest_scalar_data->dest_scaler_ndx, + dest_scalar_data->lm_width, dest_scalar_data->lm_height); +#ifdef MDP_DESTSCALER_ROI_ENABLE + DLOGI("Panel ROI [%d, %d, %d, %d]", dest_scalar_data->panel_roi.x, + dest_scalar_data->panel_roi.y, dest_scalar_data->panel_roi.w, + dest_scalar_data->panel_roi.h); +#endif + DLOGI("Dest scalar Dst WxH %dx%d", mdp_scale->dst_width, mdp_scale->dst_height); + } + for (uint32_t i = 0; i < mdp_commit.input_layer_cnt; i++) { + const mdp_input_layer &layer = mdp_layers[i]; + const mdp_rect &src_rect = layer.src_rect; + const mdp_rect &dst_rect = layer.dst_rect; + DLOGI("layer = %d, pipe_ndx = %x, z = %d, flags = %x", + i, layer.pipe_ndx, layer.z_order, layer.flags); + DLOGI("src_width = %d, src_height = %d, src_format = %d", + layer.buffer.width, layer.buffer.height, layer.buffer.format); + DLOGI("src_rect: x = %d, y = %d, w = %d, h = %d", + src_rect.x, src_rect.y, src_rect.w, src_rect.h); + DLOGI("dst_rect: x = %d, y = %d, w = %d, h = %d", + dst_rect.x, dst_rect.y, dst_rect.w, dst_rect.h); + } +} + +DisplayError HWDevice::Commit(HWLayers *hw_layers) { + DTRACE_SCOPED(); + + HWLayersInfo &hw_layer_info = hw_layers->info; + uint32_t hw_layer_count = UINT32(hw_layer_info.hw_layers.size()); + + DLOGD_IF(kTagDriverConfig, "*************************** %s Commit Input ************************", + device_name_); + DLOGD_IF(kTagDriverConfig, "SDE layer count is %d", hw_layer_count); + + mdp_layer_commit_v1 &mdp_commit = mdp_disp_commit_.commit_v1; + uint32_t mdp_layer_index = 0; + + for (uint32_t i = 0; i < hw_layer_count; i++) { + const Layer &layer = hw_layer_info.hw_layers.at(i); + LayerBuffer *input_buffer = const_cast<LayerBuffer *>(&layer.input_buffer); + HWPipeInfo *left_pipe = &hw_layers->config[i].left_pipe; + HWPipeInfo *right_pipe = &hw_layers->config[i].right_pipe; + HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session; + + for (uint32_t count = 0; count < 2; count++) { + HWPipeInfo *pipe_info = (count == 0) ? left_pipe : right_pipe; + HWRotateInfo *hw_rotate_info = &hw_rotator_session->hw_rotate_info[count]; + + if (hw_rotate_info->valid) { + input_buffer = &hw_rotator_session->output_buffer; + } + + if (pipe_info->valid) { + mdp_layer_buffer &mdp_buffer = mdp_in_layers_[mdp_layer_index].buffer; + mdp_input_layer &mdp_layer = mdp_in_layers_[mdp_layer_index]; + if (input_buffer->planes[0].fd >= 0) { + mdp_buffer.plane_count = 1; + mdp_buffer.planes[0].fd = input_buffer->planes[0].fd; + mdp_buffer.planes[0].offset = input_buffer->planes[0].offset; + SetStride(device_type_, input_buffer->format, input_buffer->planes[0].stride, + &mdp_buffer.planes[0].stride); + } else { + mdp_buffer.plane_count = 0; + } + + mdp_buffer.fence = input_buffer->acquire_fence_fd; + mdp_layer_index++; + + DLOGD_IF(kTagDriverConfig, "****************** Layer[%d] %s pipe Input *******************", + i, count ? "Right" : "Left"); + DLOGD_IF(kTagDriverConfig, "in_w %d, in_h %d, in_f %d, horz_deci %d, vert_deci %d", + mdp_buffer.width, mdp_buffer.height, mdp_buffer.format, mdp_layer.horz_deci, + mdp_layer.vert_deci); + DLOGV_IF(kTagDriverConfig, "in_buf_fd %d, in_buf_offset %d, in_buf_stride %d, " \ + "in_plane_count %d, in_fence %d, layer count %d", mdp_buffer.planes[0].fd, + mdp_buffer.planes[0].offset, mdp_buffer.planes[0].stride, mdp_buffer.plane_count, + mdp_buffer.fence, mdp_commit.input_layer_cnt); + DLOGD_IF(kTagDriverConfig, "*************************************************************"); + } + } + } + + // TODO(user): Move to derived class + if (device_type_ == kDeviceVirtual) { + LayerBuffer *output_buffer = hw_layers->info.stack->output_buffer; + + if (output_buffer->planes[0].fd >= 0) { + mdp_out_layer_.buffer.planes[0].fd = output_buffer->planes[0].fd; + mdp_out_layer_.buffer.planes[0].offset = output_buffer->planes[0].offset; + SetStride(device_type_, output_buffer->format, output_buffer->planes[0].stride, + &mdp_out_layer_.buffer.planes[0].stride); + mdp_out_layer_.buffer.plane_count = 1; + } else { + DLOGE("Invalid output buffer fd"); + return kErrorParameters; + } + + mdp_out_layer_.buffer.fence = output_buffer->acquire_fence_fd; + + DLOGI_IF(kTagDriverConfig, "********************** Output buffer Info ***********************"); + DLOGI_IF(kTagDriverConfig, "out_fd %d, out_offset %d, out_stride %d, acquire_fence %d", + mdp_out_layer_.buffer.planes[0].fd, mdp_out_layer_.buffer.planes[0].offset, + mdp_out_layer_.buffer.planes[0].stride, mdp_out_layer_.buffer.fence); + DLOGI_IF(kTagDriverConfig, "*****************************************************************"); + } + + mdp_commit.release_fence = -1; + mdp_commit.flags &= UINT32(~MDP_VALIDATE_LAYER); + if (synchronous_commit_) { + mdp_commit.flags |= MDP_COMMIT_WAIT_FOR_FINISH; + } + if (bl_update_commit && bl_level_update_commit >= 0) { +#ifdef MDP_COMMIT_UPDATE_BRIGHTNESS + mdp_commit.bl_level = (uint32_t)bl_level_update_commit; + mdp_commit.flags |= MDP_COMMIT_UPDATE_BRIGHTNESS; +#endif + } + if (Sys::ioctl_(device_fd_, INT(MSMFB_ATOMIC_COMMIT), &mdp_disp_commit_) < 0) { + if (errno == ESHUTDOWN) { + DLOGI_IF(kTagDriverConfig, "Driver is processing shutdown sequence"); + return kErrorShutDown; + } + IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, device_type_); + DumpLayerCommit(mdp_disp_commit_); + synchronous_commit_ = false; + return kErrorHardware; + } + + LayerStack *stack = hw_layer_info.stack; + stack->retire_fence_fd = mdp_commit.retire_fence; +#ifdef VIDEO_MODE_DEFER_RETIRE_FENCE + if (hw_panel_info_.mode == kModeVideo) { + stack->retire_fence_fd = stored_retire_fence; + stored_retire_fence = mdp_commit.retire_fence; + } +#endif + // MDP returns only one release fence for the entire layer stack. Duplicate this fence into all + // layers being composed by MDP. + + for (uint32_t i = 0; i < hw_layer_count; i++) { + const Layer &layer = hw_layer_info.hw_layers.at(i); + LayerBuffer *input_buffer = const_cast<LayerBuffer *>(&layer.input_buffer); + HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session; + + if (hw_rotator_session->hw_block_count) { + input_buffer = &hw_rotator_session->output_buffer; + input_buffer->release_fence_fd = Sys::dup_(mdp_commit.release_fence); + continue; + } + + input_buffer->release_fence_fd = Sys::dup_(mdp_commit.release_fence); + } + + hw_layer_info.sync_handle = Sys::dup_(mdp_commit.release_fence); + + DLOGI_IF(kTagDriverConfig, "*************************** %s Commit Input ************************", + device_name_); + DLOGI_IF(kTagDriverConfig, "retire_fence_fd %d", stack->retire_fence_fd); + DLOGI_IF(kTagDriverConfig, "*******************************************************************"); + + if (mdp_commit.release_fence >= 0) { + Sys::close_(mdp_commit.release_fence); + } + + if (synchronous_commit_) { + // A synchronous commit can be requested when changing the display mode so we need to update + // panel info. + PopulateHWPanelInfo(); + synchronous_commit_ = false; + } + + if (bl_update_commit) + bl_update_commit = false; + + return kErrorNone; +} + +DisplayError HWDevice::Flush() { + ResetDisplayParams(); + mdp_layer_commit_v1 &mdp_commit = mdp_disp_commit_.commit_v1; + mdp_commit.input_layer_cnt = 0; + mdp_commit.output_layer = NULL; + + mdp_commit.flags &= UINT32(~MDP_VALIDATE_LAYER); + if (Sys::ioctl_(device_fd_, INT(MSMFB_ATOMIC_COMMIT), &mdp_disp_commit_) < 0) { + if (errno == ESHUTDOWN) { + DLOGI_IF(kTagDriverConfig, "Driver is processing shutdown sequence"); + return kErrorShutDown; + } + IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, device_type_); + DumpLayerCommit(mdp_disp_commit_); + return kErrorHardware; + } + return kErrorNone; +} + +DisplayError HWDevice::SetFormat(const LayerBufferFormat &source, uint32_t *target) { + switch (source) { + case kFormatARGB8888: *target = MDP_ARGB_8888; break; + case kFormatRGBA8888: *target = MDP_RGBA_8888; break; + case kFormatBGRA8888: *target = MDP_BGRA_8888; break; + case kFormatRGBX8888: *target = MDP_RGBX_8888; break; + case kFormatBGRX8888: *target = MDP_BGRX_8888; break; + case kFormatRGBA5551: *target = MDP_RGBA_5551; break; + case kFormatRGBA4444: *target = MDP_RGBA_4444; break; + case kFormatRGB888: *target = MDP_RGB_888; break; + case kFormatBGR888: *target = MDP_BGR_888; break; + case kFormatRGB565: *target = MDP_RGB_565; break; + case kFormatBGR565: *target = MDP_BGR_565; break; + case kFormatYCbCr420Planar: *target = MDP_Y_CB_CR_H2V2; break; + case kFormatYCrCb420Planar: *target = MDP_Y_CR_CB_H2V2; break; + case kFormatYCrCb420PlanarStride16: *target = MDP_Y_CR_CB_GH2V2; break; + case kFormatYCbCr420SemiPlanar: *target = MDP_Y_CBCR_H2V2; break; + case kFormatYCrCb420SemiPlanar: *target = MDP_Y_CRCB_H2V2; break; + case kFormatYCbCr422H1V2SemiPlanar: *target = MDP_Y_CBCR_H1V2; break; + case kFormatYCrCb422H1V2SemiPlanar: *target = MDP_Y_CRCB_H1V2; break; + case kFormatYCbCr422H2V1SemiPlanar: *target = MDP_Y_CBCR_H2V1; break; + case kFormatYCrCb422H2V1SemiPlanar: *target = MDP_Y_CRCB_H2V1; break; + case kFormatYCbCr422H2V1Packed: *target = MDP_YCBYCR_H2V1; break; + case kFormatYCbCr420SemiPlanarVenus: *target = MDP_Y_CBCR_H2V2_VENUS; break; + case kFormatRGBA8888Ubwc: *target = MDP_RGBA_8888_UBWC; break; + case kFormatRGBX8888Ubwc: *target = MDP_RGBX_8888_UBWC; break; + case kFormatBGR565Ubwc: *target = MDP_RGB_565_UBWC; break; + case kFormatYCbCr420SPVenusUbwc: *target = MDP_Y_CBCR_H2V2_UBWC; break; + case kFormatCbYCrY422H2V1Packed: *target = MDP_CBYCRY_H2V1; break; + case kFormatRGBA1010102: *target = MDP_RGBA_1010102; break; + case kFormatARGB2101010: *target = MDP_ARGB_2101010; break; + case kFormatRGBX1010102: *target = MDP_RGBX_1010102; break; + case kFormatXRGB2101010: *target = MDP_XRGB_2101010; break; + case kFormatBGRA1010102: *target = MDP_BGRA_1010102; break; + case kFormatABGR2101010: *target = MDP_ABGR_2101010; break; + case kFormatBGRX1010102: *target = MDP_BGRX_1010102; break; + case kFormatXBGR2101010: *target = MDP_XBGR_2101010; break; + case kFormatRGBA1010102Ubwc: *target = MDP_RGBA_1010102_UBWC; break; + case kFormatRGBX1010102Ubwc: *target = MDP_RGBX_1010102_UBWC; break; + case kFormatYCbCr420P010: *target = MDP_Y_CBCR_H2V2_P010; break; + case kFormatYCbCr420TP10Ubwc: *target = MDP_Y_CBCR_H2V2_TP10_UBWC; break; + default: + DLOGE("Unsupported format type %d", source); + return kErrorParameters; + } + + return kErrorNone; +} + +DisplayError HWDevice::SetStride(HWDeviceType device_type, LayerBufferFormat format, + uint32_t width, uint32_t *target) { + // TODO(user): This SetStride function is a workaround to satisfy the driver expectation for + // rotator and virtual devices. Eventually this will be taken care in the driver. + if (device_type != kDeviceRotator && device_type != kDeviceVirtual) { + *target = width; + return kErrorNone; + } + + switch (format) { + case kFormatARGB8888: + case kFormatRGBA8888: + case kFormatBGRA8888: + case kFormatRGBX8888: + case kFormatBGRX8888: + case kFormatRGBA8888Ubwc: + case kFormatRGBX8888Ubwc: + case kFormatRGBA1010102: + case kFormatARGB2101010: + case kFormatRGBX1010102: + case kFormatXRGB2101010: + case kFormatBGRA1010102: + case kFormatABGR2101010: + case kFormatBGRX1010102: + case kFormatXBGR2101010: + case kFormatRGBA1010102Ubwc: + case kFormatRGBX1010102Ubwc: + *target = width * 4; + break; + case kFormatRGB888: + case kFormatBGR888: + *target = width * 3; + break; + case kFormatRGB565: + case kFormatBGR565: + case kFormatBGR565Ubwc: + *target = width * 2; + break; + case kFormatYCbCr420SemiPlanarVenus: + case kFormatYCbCr420SPVenusUbwc: + case kFormatYCbCr420Planar: + case kFormatYCrCb420Planar: + case kFormatYCrCb420PlanarStride16: + case kFormatYCbCr420SemiPlanar: + case kFormatYCrCb420SemiPlanar: + case kFormatYCbCr420TP10Ubwc: + *target = width; + break; + case kFormatYCbCr422H2V1Packed: + case kFormatCbYCrY422H2V1Packed: + case kFormatYCrCb422H2V1SemiPlanar: + case kFormatYCrCb422H1V2SemiPlanar: + case kFormatYCbCr422H2V1SemiPlanar: + case kFormatYCbCr422H1V2SemiPlanar: + case kFormatYCbCr420P010: + case kFormatRGBA5551: + case kFormatRGBA4444: + *target = width * 2; + break; + default: + DLOGE("Unsupported format type %d", format); + return kErrorParameters; + } + + return kErrorNone; +} + +void HWDevice::SetBlending(const LayerBlending &source, mdss_mdp_blend_op *target) { + switch (source) { + case kBlendingPremultiplied: *target = BLEND_OP_PREMULTIPLIED; break; + case kBlendingOpaque: *target = BLEND_OP_OPAQUE; break; + case kBlendingCoverage: *target = BLEND_OP_COVERAGE; break; + default: *target = BLEND_OP_NOT_DEFINED; break; + } +} + +void HWDevice::SetRect(const LayerRect &source, mdp_rect *target) { + target->x = UINT32(source.left); + target->y = UINT32(source.top); + target->w = UINT32(source.right) - target->x; + target->h = UINT32(source.bottom) - target->y; +} + +void HWDevice::SetMDPFlags(const Layer *layer, const bool &is_rotator_used, + bool is_cursor_pipe_used, uint32_t *mdp_flags) { + const LayerBuffer &input_buffer = layer->input_buffer; + + // Flips will be taken care by rotator, if layer uses rotator for downscale/rotation. So ignore + // flip flags for MDP. + if (!is_rotator_used) { + if (layer->transform.flip_vertical) { + *mdp_flags |= MDP_LAYER_FLIP_UD; + } + + if (layer->transform.flip_horizontal) { + *mdp_flags |= MDP_LAYER_FLIP_LR; + } + + if (input_buffer.flags.interlace) { + *mdp_flags |= MDP_LAYER_DEINTERLACE; + } + } + + if (input_buffer.flags.secure_camera) { + *mdp_flags |= MDP_LAYER_SECURE_CAMERA_SESSION; + } else if (input_buffer.flags.secure) { + *mdp_flags |= MDP_LAYER_SECURE_SESSION; + } + + if (input_buffer.flags.secure_display) { + *mdp_flags |= MDP_LAYER_SECURE_DISPLAY_SESSION; + } + + if (layer->flags.solid_fill) { + *mdp_flags |= MDP_LAYER_SOLID_FILL; + } + + if (hw_panel_info_.mode != kModeCommand && layer->flags.cursor && is_cursor_pipe_used) { + // command mode panels does not support async position update + *mdp_flags |= MDP_LAYER_ASYNC; + } +} + +int HWDevice::GetFBNodeIndex(HWDeviceType device_type) { + for (int i = 0; i < kFBNodeMax; i++) { + HWPanelInfo panel_info; + GetHWPanelInfoByNode(i, &panel_info); + switch (device_type) { + case kDevicePrimary: + if (panel_info.is_primary_panel) { + return i; + } + break; + case kDeviceHDMI: + if (panel_info.is_pluggable == true) { + if (IsFBNodeConnected(i)) { + return i; + } + } + break; + case kDeviceVirtual: + if (panel_info.port == kPortWriteBack) { + return i; + } + break; + default: + break; + } + } + return -1; +} + +void HWDevice::PopulateHWPanelInfo() { + hw_panel_info_ = HWPanelInfo(); + GetHWPanelInfoByNode(fb_node_index_, &hw_panel_info_); + DLOGI("Device type = %d, Display Port = %d, Display Mode = %d, Device Node = %d, Is Primary = %d", + device_type_, hw_panel_info_.port, hw_panel_info_.mode, fb_node_index_, + hw_panel_info_.is_primary_panel); + DLOGI("Partial Update = %d, supported roi_count =%d, Dynamic FPS = %d", + hw_panel_info_.partial_update, hw_panel_info_.left_roi_count, hw_panel_info_.dynamic_fps); + DLOGI("Align: left = %d, width = %d, top = %d, height = %d", + hw_panel_info_.left_align, hw_panel_info_.width_align, + hw_panel_info_.top_align, hw_panel_info_.height_align); + DLOGI("ROI: min_width = %d, min_height = %d, need_merge = %d", + hw_panel_info_.min_roi_width, hw_panel_info_.min_roi_height, + hw_panel_info_.needs_roi_merge); + DLOGI("FPS: min = %d, max =%d", hw_panel_info_.min_fps, hw_panel_info_.max_fps); + DLOGI("Ping Pong Split = %d", hw_panel_info_.ping_pong_split); + DLOGI("Left Split = %d, Right Split = %d", hw_panel_info_.split_info.left_split, + hw_panel_info_.split_info.right_split); +} + +void HWDevice::GetHWPanelNameByNode(int device_node, HWPanelInfo *panel_info) { + string file_name = fb_path_ + to_string(device_node) + "/msm_fb_panel_info"; + + Sys::fstream fs(file_name, fstream::in); + if (!fs.is_open()) { + DLOGW("Failed to open msm_fb_panel_info node device node %d", device_node); + return; + } + + string line; + while (Sys::getline_(fs, line)) { + uint32_t token_count = 0; + const uint32_t max_count = 10; + char *tokens[max_count] = { NULL }; + if (!ParseLine(line.c_str(), "=\n", tokens, max_count, &token_count)) { + if (!strncmp(tokens[0], "panel_name", strlen("panel_name"))) { + snprintf(panel_info->panel_name, sizeof(panel_info->panel_name), "%s", tokens[1]); + break; + } + } + } +} + +void HWDevice::GetHWPanelInfoByNode(int device_node, HWPanelInfo *panel_info) { + string file_name = fb_path_ + to_string(device_node) + "/msm_fb_panel_info"; + + Sys::fstream fs(file_name, fstream::in); + if (!fs.is_open()) { + DLOGW("Failed to open msm_fb_panel_info node device node %d", device_node); + return; + } + + string line; + while (Sys::getline_(fs, line)) { + uint32_t token_count = 0; + const uint32_t max_count = 10; + char *tokens[max_count] = { NULL }; + if (!ParseLine(line.c_str(), tokens, max_count, &token_count)) { + if (!strncmp(tokens[0], "pu_en", strlen("pu_en"))) { + panel_info->partial_update = atoi(tokens[1]); + } else if (!strncmp(tokens[0], "xstart", strlen("xstart"))) { + panel_info->left_align = atoi(tokens[1]); + } else if (!strncmp(tokens[0], "walign", strlen("walign"))) { + panel_info->width_align = atoi(tokens[1]); + } else if (!strncmp(tokens[0], "ystart", strlen("ystart"))) { + panel_info->top_align = atoi(tokens[1]); + } else if (!strncmp(tokens[0], "halign", strlen("halign"))) { + panel_info->height_align = atoi(tokens[1]); + } else if (!strncmp(tokens[0], "min_w", strlen("min_w"))) { + panel_info->min_roi_width = atoi(tokens[1]); + } else if (!strncmp(tokens[0], "min_h", strlen("min_h"))) { + panel_info->min_roi_height = atoi(tokens[1]); + } else if (!strncmp(tokens[0], "roi_merge", strlen("roi_merge"))) { + panel_info->needs_roi_merge = atoi(tokens[1]); + } else if (!strncmp(tokens[0], "dyn_fps_en", strlen("dyn_fps_en"))) { + panel_info->dynamic_fps = atoi(tokens[1]); + } else if (!strncmp(tokens[0], "dfps_porch_mode", strlen("dfps_porch_mode"))) { + panel_info->dfps_porch_mode = atoi(tokens[1]); + } else if (!strncmp(tokens[0], "is_pingpong_split", strlen("is_pingpong_split"))) { + panel_info->ping_pong_split = atoi(tokens[1]); + } else if (!strncmp(tokens[0], "min_fps", strlen("min_fps"))) { + panel_info->min_fps = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "max_fps", strlen("max_fps"))) { + panel_info->max_fps = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "primary_panel", strlen("primary_panel"))) { + panel_info->is_primary_panel = atoi(tokens[1]); + } else if (!strncmp(tokens[0], "is_pluggable", strlen("is_pluggable"))) { + panel_info->is_pluggable = atoi(tokens[1]); + } else if (!strncmp(tokens[0], "pu_roi_cnt", strlen("pu_roi_cnt"))) { + panel_info->left_roi_count = UINT32(atoi(tokens[1])); + panel_info->right_roi_count = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "is_hdr_enabled", strlen("is_hdr_enabled"))) { + panel_info->hdr_enabled = atoi(tokens[1]); + } else if (!strncmp(tokens[0], "peak_brightness", strlen("peak_brightness"))) { + panel_info->peak_luminance = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "average_brightness", strlen("average_brightness"))) { + panel_info->average_luminance = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "blackness_level", strlen("blackness_level"))) { + panel_info->blackness_level = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "white_chromaticity_x", strlen("white_chromaticity_x"))) { + panel_info->primaries.white_point[0] = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "white_chromaticity_y", strlen("white_chromaticity_y"))) { + panel_info->primaries.white_point[1] = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "red_chromaticity_x", strlen("red_chromaticity_x"))) { + panel_info->primaries.red[0] = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "red_chromaticity_y", strlen("red_chromaticity_y"))) { + panel_info->primaries.red[1] = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "green_chromaticity_x", strlen("green_chromaticity_x"))) { + panel_info->primaries.green[0] = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "green_chromaticity_y", strlen("green_chromaticity_y"))) { + panel_info->primaries.green[1] = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "blue_chromaticity_x", strlen("blue_chromaticity_x"))) { + panel_info->primaries.blue[0] = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "blue_chromaticity_y", strlen("blue_chromaticity_y"))) { + panel_info->primaries.blue[1] = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "panel_orientation", strlen("panel_orientation"))) { + int32_t panel_orient = atoi(tokens[1]); + panel_info->panel_orientation.flip_horizontal = ((panel_orient & MDP_FLIP_LR) > 0); + panel_info->panel_orientation.flip_vertical = ((panel_orient & MDP_FLIP_UD) > 0); + panel_info->panel_orientation.rotation = ((panel_orient & MDP_ROT_90) > 0); + } + } + } + + GetHWDisplayPortAndMode(device_node, panel_info); + GetSplitInfo(device_node, panel_info); + GetHWPanelNameByNode(device_node, panel_info); + GetHWPanelMaxBrightnessFromNode(panel_info); +} + +void HWDevice::GetHWDisplayPortAndMode(int device_node, HWPanelInfo *panel_info) { + DisplayPort *port = &panel_info->port; + HWDisplayMode *mode = &panel_info->mode; + + *port = kPortDefault; + *mode = kModeDefault; + + string file_name = fb_path_ + to_string(device_node) + "/msm_fb_type"; + + Sys::fstream fs(file_name, fstream::in); + if (!fs.is_open()) { + DLOGW("File not found %s", file_name.c_str()); + return; + } + + string line; + if (!Sys::getline_(fs, line)) { + return; + } + + if ((strncmp(line.c_str(), "mipi dsi cmd panel", strlen("mipi dsi cmd panel")) == 0)) { + *port = kPortDSI; + *mode = kModeCommand; + } else if ((strncmp(line.c_str(), "mipi dsi video panel", strlen("mipi dsi video panel")) == 0)) { + *port = kPortDSI; + *mode = kModeVideo; + } else if ((strncmp(line.c_str(), "lvds panel", strlen("lvds panel")) == 0)) { + *port = kPortLVDS; + *mode = kModeVideo; + } else if ((strncmp(line.c_str(), "edp panel", strlen("edp panel")) == 0)) { + *port = kPortEDP; + *mode = kModeVideo; + } else if ((strncmp(line.c_str(), "dtv panel", strlen("dtv panel")) == 0)) { + *port = kPortDTV; + *mode = kModeVideo; + } else if ((strncmp(line.c_str(), "writeback panel", strlen("writeback panel")) == 0)) { + *port = kPortWriteBack; + *mode = kModeCommand; + } else if ((strncmp(line.c_str(), "dp panel", strlen("dp panel")) == 0)) { + *port = kPortDP; + *mode = kModeVideo; + } + + return; +} + +void HWDevice::GetSplitInfo(int device_node, HWPanelInfo *panel_info) { + // Split info - for MDSS Version 5 - No need to check version here + string file_name = fb_path_ + to_string(device_node) + "/msm_fb_split"; + + Sys::fstream fs(file_name, fstream::in); + if (!fs.is_open()) { + DLOGW("File not found %s", file_name.c_str()); + return; + } + + // Format "left right" space as delimiter + uint32_t token_count = 0; + const uint32_t max_count = 10; + char *tokens[max_count] = { NULL }; + string line; + if (Sys::getline_(fs, line)) { + if (!ParseLine(line.c_str(), tokens, max_count, &token_count)) { + panel_info->split_info.left_split = UINT32(atoi(tokens[0])); + panel_info->split_info.right_split = UINT32(atoi(tokens[1])); + } + } +} + +void HWDevice::GetHWPanelMaxBrightnessFromNode(HWPanelInfo *panel_info) { + char brightness[kMaxStringLength] = { 0 }; + char kMaxBrightnessNode[64] = { 0 }; + + snprintf(kMaxBrightnessNode, sizeof(kMaxBrightnessNode), "%s", + "/sys/class/leds/lcd-backlight/max_brightness"); + + panel_info->panel_max_brightness = 0; + int fd = Sys::open_(kMaxBrightnessNode, O_RDONLY); + if (fd < 0) { + DLOGW("Failed to open max brightness node = %s, error = %s", kMaxBrightnessNode, + strerror(errno)); + return; + } + + if (Sys::pread_(fd, brightness, sizeof(brightness), 0) > 0) { + panel_info->panel_max_brightness = atoi(brightness); + DLOGI("Max brightness level = %d", panel_info->panel_max_brightness); + } else { + DLOGW("Failed to read max brightness level. error = %s", strerror(errno)); + } + Sys::close_(fd); +} + +int HWDevice::ParseLine(const char *input, char *tokens[], const uint32_t max_token, + uint32_t *count) { + char *tmp_token = NULL; + char *temp_ptr; + uint32_t index = 0; + const char *delim = ", =\n"; + if (!input) { + return -1; + } + tmp_token = strtok_r(const_cast<char *>(input), delim, &temp_ptr); + while (tmp_token && index < max_token) { + tokens[index++] = tmp_token; + tmp_token = strtok_r(NULL, delim, &temp_ptr); + } + *count = index; + + return 0; +} + +int HWDevice::ParseLine(const char *input, const char *delim, char *tokens[], + const uint32_t max_token, uint32_t *count) { + char *tmp_token = NULL; + char *temp_ptr; + uint32_t index = 0; + if (!input) { + return -1; + } + tmp_token = strtok_r(const_cast<char *>(input), delim, &temp_ptr); + while (tmp_token && index < max_token) { + tokens[index++] = tmp_token; + tmp_token = strtok_r(NULL, delim, &temp_ptr); + } + *count = index; + + return 0; +} + +bool HWDevice::EnableHotPlugDetection(int enable) { + char hpdpath[kMaxStringLength]; + const char *value = enable ? "1" : "0"; + + // Enable HPD for all pluggable devices. + for (int i = 0; i < kFBNodeMax; i++) { + HWPanelInfo panel_info; + GetHWPanelInfoByNode(i, &panel_info); + if (panel_info.is_pluggable == true) { + snprintf(hpdpath , sizeof(hpdpath), "%s%d/hpd", fb_path_, i); + + ssize_t length = SysFsWrite(hpdpath, value, 1); + if (length <= 0) { + return false; + } + } + } + + return true; +} + +void HWDevice::ResetDisplayParams() { + memset(&mdp_disp_commit_, 0, sizeof(mdp_disp_commit_)); + memset(&mdp_in_layers_, 0, sizeof(mdp_in_layers_)); + memset(&mdp_out_layer_, 0, sizeof(mdp_out_layer_)); + mdp_out_layer_.buffer.fence = -1; + hw_scale_->ResetScaleParams(); + memset(&pp_params_, 0, sizeof(pp_params_)); + memset(&igc_lut_data_, 0, sizeof(igc_lut_data_)); + + for (size_t i = 0; i < mdp_dest_scalar_data_.size(); i++) { + mdp_dest_scalar_data_[i] = {}; + } + + for (uint32_t i = 0; i < kMaxSDELayers * 2; i++) { + mdp_in_layers_[i].buffer.fence = -1; + } + + mdp_disp_commit_.version = MDP_COMMIT_VERSION_1_0; + mdp_disp_commit_.commit_v1.input_layers = mdp_in_layers_; + mdp_disp_commit_.commit_v1.output_layer = &mdp_out_layer_; + mdp_disp_commit_.commit_v1.release_fence = -1; + mdp_disp_commit_.commit_v1.retire_fence = -1; + mdp_disp_commit_.commit_v1.dest_scaler = mdp_dest_scalar_data_.data(); +} + +void HWDevice::SetCSC(const ColorMetaData &color_metadata, mdp_color_space *color_space) { + switch (color_metadata.colorPrimaries) { + case ColorPrimaries_BT601_6_525: + case ColorPrimaries_BT601_6_625: + *color_space = ((color_metadata.range == Range_Full) ? MDP_CSC_ITU_R_601_FR : + MDP_CSC_ITU_R_601); + break; + case ColorPrimaries_BT709_5: + *color_space = MDP_CSC_ITU_R_709; + break; +#if defined MDP_CSC_ITU_R_2020 && defined MDP_CSC_ITU_R_2020_FR + case ColorPrimaries_BT2020: + *color_space = static_cast<mdp_color_space>((color_metadata.range == Range_Full) ? + MDP_CSC_ITU_R_2020_FR : MDP_CSC_ITU_R_2020); + break; +#endif + default: + break; + } +} + +void HWDevice::SetIGC(const LayerBuffer *layer_buffer, uint32_t index) { + mdp_input_layer &mdp_layer = mdp_in_layers_[index]; + mdp_overlay_pp_params &pp_params = pp_params_[index]; + mdp_igc_lut_data_v1_7 &igc_lut_data = igc_lut_data_[index]; + + switch (layer_buffer->igc) { + case kIGCsRGB: + igc_lut_data.table_fmt = mdp_igc_srgb; + pp_params.igc_cfg.ops = MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE; + break; + + default: + pp_params.igc_cfg.ops = MDP_PP_OPS_DISABLE; + break; + } + + pp_params.config_ops = MDP_OVERLAY_PP_IGC_CFG; + pp_params.igc_cfg.version = mdp_igc_v1_7; + pp_params.igc_cfg.cfg_payload = &igc_lut_data; + + mdp_layer.pp_info = &pp_params; + mdp_layer.flags |= MDP_LAYER_PP; +} + +DisplayError HWDevice::SetCursorPosition(HWLayers *hw_layers, int x, int y) { + DTRACE_SCOPED(); + + HWLayersInfo &hw_layer_info = hw_layers->info; + uint32_t count = UINT32(hw_layer_info.hw_layers.size()); + uint32_t cursor_index = count - 1; + HWPipeInfo *left_pipe = &hw_layers->config[cursor_index].left_pipe; + + mdp_async_layer async_layer = {}; + async_layer.flags = MDP_LAYER_ASYNC; + async_layer.pipe_ndx = left_pipe->pipe_id; + async_layer.src.x = UINT32(left_pipe->src_roi.left); + async_layer.src.y = UINT32(left_pipe->src_roi.top); + async_layer.dst.x = UINT32(left_pipe->dst_roi.left); + async_layer.dst.y = UINT32(left_pipe->dst_roi.top); + + mdp_position_update pos_update = {}; + pos_update.input_layer_cnt = 1; + pos_update.input_layers = &async_layer; + if (Sys::ioctl_(device_fd_, INT(MSMFB_ASYNC_POSITION_UPDATE), &pos_update) < 0) { + if (errno == ESHUTDOWN) { + DLOGI_IF(kTagDriverConfig, "Driver is processing shutdown sequence"); + return kErrorShutDown; + } + IOCTL_LOGE(MSMFB_ASYNC_POSITION_UPDATE, device_type_); + return kErrorHardware; + } + + return kErrorNone; +} + +DisplayError HWDevice::GetPPFeaturesVersion(PPFeatureVersion *vers) { + return kErrorNotSupported; +} + +DisplayError HWDevice::SetPPFeatures(PPFeaturesConfig *feature_list) { + return kErrorNotSupported; +} + +DisplayError HWDevice::SetVSyncState(bool enable) { + int vsync_on = enable ? 1 : 0; + if (Sys::ioctl_(device_fd_, MSMFB_OVERLAY_VSYNC_CTRL, &vsync_on) < 0) { + if (errno == ESHUTDOWN) { + DLOGI_IF(kTagDriverConfig, "Driver is processing shutdown sequence"); + return kErrorShutDown; + } + IOCTL_LOGE(MSMFB_OVERLAY_VSYNC_CTRL, device_type_); + return kErrorHardware; + } + return kErrorNone; +} + +void HWDevice::SetIdleTimeoutMs(uint32_t timeout_ms) { +} + +DisplayError HWDevice::SetDisplayMode(const HWDisplayMode hw_display_mode) { + return kErrorNotSupported; +} + +DisplayError HWDevice::SetRefreshRate(uint32_t refresh_rate) { + return kErrorNotSupported; +} + +DisplayError HWDevice::SetPanelBrightness(int level) { + return kErrorNotSupported; +} + +DisplayError HWDevice::CachePanelBrightness(int level) { + return kErrorNotSupported; +} + +DisplayError HWDevice::GetHWScanInfo(HWScanInfo *scan_info) { + return kErrorNotSupported; +} + +DisplayError HWDevice::GetVideoFormat(uint32_t config_index, uint32_t *video_format) { + return kErrorNotSupported; +} + +DisplayError HWDevice::GetMaxCEAFormat(uint32_t *max_cea_format) { + return kErrorNotSupported; +} + +DisplayError HWDevice::OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level) { + return kErrorNotSupported; +} + +DisplayError HWDevice::GetPanelBrightness(int *level) { + return kErrorNotSupported; +} + +ssize_t HWDevice::SysFsWrite(const char* file_node, const char* value, ssize_t length) { + int fd = Sys::open_(file_node, O_RDWR, 0); + if (fd < 0) { + DLOGW("Open failed = %s", file_node); + return -1; + } + ssize_t len = Sys::pwrite_(fd, value, static_cast<size_t>(length), 0); + if (len <= 0) { + DLOGE("Write failed for path %s with value %s", file_node, value); + } + Sys::close_(fd); + + return len; +} + +bool HWDevice::IsFBNodeConnected(int fb_node) { + string file_name = fb_path_ + to_string(fb_node) + "/connected"; + + Sys::fstream fs(file_name, fstream::in); + if (!fs.is_open()) { + DLOGW("File not found %s", file_name.c_str()); + return false; + } + + string line; + if (!Sys::getline_(fs, line)) { + return false; + } + + return atoi(line.c_str()); +} + +DisplayError HWDevice::SetS3DMode(HWS3DMode s3d_mode) { + return kErrorNotSupported; +} + +DisplayError HWDevice::SetScaleLutConfig(HWScaleLutInfo *lut_info) { + mdp_scale_luts_info mdp_lut_info = {}; + mdp_set_cfg cfg = {}; + + if (!hw_resource_.has_qseed3) { + DLOGV_IF(kTagDriverConfig, "No support for QSEED3 luts"); + return kErrorNone; + } + + if (!lut_info->dir_lut_size && !lut_info->dir_lut && !lut_info->cir_lut_size && + !lut_info->cir_lut && !lut_info->sep_lut_size && !lut_info->sep_lut) { + // HWSupports QSEED3, but LutInfo is invalid as scalar is disabled by property or + // its loading failed. Driver will use default settings/filter + return kErrorNone; + } + + mdp_lut_info.dir_lut_size = lut_info->dir_lut_size; + mdp_lut_info.dir_lut = lut_info->dir_lut; + mdp_lut_info.cir_lut_size = lut_info->cir_lut_size; + mdp_lut_info.cir_lut = lut_info->cir_lut; + mdp_lut_info.sep_lut_size = lut_info->sep_lut_size; + mdp_lut_info.sep_lut = lut_info->sep_lut; + + cfg.flags = MDP_QSEED3_LUT_CFG; + cfg.len = sizeof(mdp_scale_luts_info); + cfg.payload = reinterpret_cast<uint64_t>(&mdp_lut_info); + + if (Sys::ioctl_(device_fd_, MSMFB_MDP_SET_CFG, &cfg) < 0) { + if (errno == ESHUTDOWN) { + DLOGI_IF(kTagDriverConfig, "Driver is processing shutdown sequence"); + return kErrorShutDown; + } + IOCTL_LOGE(MSMFB_MDP_SET_CFG, device_type_); + return kErrorHardware; + } + + return kErrorNone; +} + +DisplayError HWDevice::SetMixerAttributes(const HWMixerAttributes &mixer_attributes) { + if (!hw_resource_.hw_dest_scalar_info.count) { + return kErrorNotSupported; + } + + if (mixer_attributes.width > display_attributes_.x_pixels || + mixer_attributes.height > display_attributes_.y_pixels) { + DLOGW_IF(kTagDriverConfig, "Input resolution exceeds display resolution! input: res %dx%d "\ + "display: res %dx%d", mixer_attributes.width, mixer_attributes.height, + display_attributes_.x_pixels, display_attributes_.y_pixels); + return kErrorNotSupported; + } + + uint32_t max_input_width = hw_resource_.hw_dest_scalar_info.max_input_width; + if (display_attributes_.is_device_split) { + max_input_width *= 2; + } + + if (mixer_attributes.width > max_input_width) { + DLOGW_IF(kTagDriverConfig, "Input width exceeds width limit! input_width %d width_limit %d", + mixer_attributes.width, max_input_width); + return kErrorNotSupported; + } + + float mixer_aspect_ratio = FLOAT(mixer_attributes.width) / FLOAT(mixer_attributes.height); + float display_aspect_ratio = + FLOAT(display_attributes_.x_pixels) / FLOAT(display_attributes_.y_pixels); + + if (display_aspect_ratio != mixer_aspect_ratio) { + DLOGW_IF(kTagDriverConfig, "Aspect ratio mismatch! input: res %dx%d display: res %dx%d", + mixer_attributes.width, mixer_attributes.height, display_attributes_.x_pixels, + display_attributes_.y_pixels); + return kErrorNotSupported; + } + + float scale_x = FLOAT(display_attributes_.x_pixels) / FLOAT(mixer_attributes.width); + float scale_y = FLOAT(display_attributes_.y_pixels) / FLOAT(mixer_attributes.height); + float max_scale_up = hw_resource_.hw_dest_scalar_info.max_scale_up; + if (scale_x > max_scale_up || scale_y > max_scale_up) { + DLOGW_IF(kTagDriverConfig, "Up scaling ratio exceeds for destination scalar upscale " \ + "limit scale_x %f scale_y %f max_scale_up %f", scale_x, scale_y, max_scale_up); + return kErrorNotSupported; + } + + float mixer_split_ratio = FLOAT(mixer_attributes_.split_left) / FLOAT(mixer_attributes_.width); + + mixer_attributes_ = mixer_attributes; + mixer_attributes_.split_left = mixer_attributes_.width; + if (display_attributes_.is_device_split) { + mixer_attributes_.split_left = UINT32(FLOAT(mixer_attributes.width) * mixer_split_ratio); + } + + return kErrorNone; +} + +DisplayError HWDevice::GetMixerAttributes(HWMixerAttributes *mixer_attributes) { + if (!mixer_attributes) { + return kErrorParameters; + } + + *mixer_attributes = mixer_attributes_; + + return kErrorNone; +} + +} // namespace sdm + diff --git a/msm8909/sdm/libs/core/fb/hw_device.h b/msm8909/sdm/libs/core/fb/hw_device.h new file mode 100644 index 00000000..374df568 --- /dev/null +++ b/msm8909/sdm/libs/core/fb/hw_device.h @@ -0,0 +1,167 @@ +/* +* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __HW_DEVICE_H__ +#define __HW_DEVICE_H__ + +#include <errno.h> +#include <linux/msm_mdp_ext.h> +#include <linux/mdss_rotator.h> +#include <pthread.h> +#include <vector> + +#include "hw_interface.h" +#include "hw_scale.h" + +#define IOCTL_LOGE(ioctl, type) DLOGE("ioctl %s, device = %d errno = %d, desc = %s", #ioctl, \ + type, errno, strerror(errno)) + +#ifndef MDP_LAYER_MULTIRECT_ENABLE +#define MDP_LAYER_MULTIRECT_ENABLE 0 +#endif + +#ifndef MDP_LAYER_MULTIRECT_PARALLEL_MODE +#define MDP_LAYER_MULTIRECT_PARALLEL_MODE 0 +#endif + +#ifndef MDP_LAYER_SECURE_CAMERA_SESSION +#define MDP_LAYER_SECURE_CAMERA_SESSION 0 +#endif + +namespace sdm { +class HWInfoInterface; + +class HWDevice : public HWInterface { + public: + virtual ~HWDevice() {} + virtual DisplayError Init(); + virtual DisplayError Deinit(); + + protected: + explicit HWDevice(BufferSyncHandler *buffer_sync_handler); + + // From HWInterface + virtual DisplayError GetActiveConfig(uint32_t *active_config); + virtual DisplayError GetNumDisplayAttributes(uint32_t *count); + virtual DisplayError GetDisplayAttributes(uint32_t index, + HWDisplayAttributes *display_attributes); + virtual DisplayError GetHWPanelInfo(HWPanelInfo *panel_info); + virtual DisplayError SetDisplayAttributes(uint32_t index); + virtual DisplayError SetDisplayAttributes(const HWDisplayAttributes &display_attributes); + virtual DisplayError GetConfigIndex(uint32_t mode, uint32_t *index); + virtual DisplayError PowerOn(); + virtual DisplayError PowerOff(); + virtual DisplayError Doze(); + virtual DisplayError DozeSuspend(); + virtual DisplayError Standby(); + virtual DisplayError Validate(HWLayers *hw_layers); + virtual DisplayError Commit(HWLayers *hw_layers); + virtual DisplayError Flush(); + virtual DisplayError GetPPFeaturesVersion(PPFeatureVersion *vers); + virtual DisplayError SetPPFeatures(PPFeaturesConfig *feature_list); + virtual DisplayError SetVSyncState(bool enable); + virtual void SetIdleTimeoutMs(uint32_t timeout_ms); + virtual DisplayError SetDisplayMode(const HWDisplayMode hw_display_mode); + virtual DisplayError SetRefreshRate(uint32_t refresh_rate); + virtual DisplayError SetPanelBrightness(int level); + virtual DisplayError CachePanelBrightness(int level); + virtual DisplayError GetHWScanInfo(HWScanInfo *scan_info); + virtual DisplayError GetVideoFormat(uint32_t config_index, uint32_t *video_format); + virtual DisplayError GetMaxCEAFormat(uint32_t *max_cea_format); + virtual DisplayError SetCursorPosition(HWLayers *hw_layers, int x, int y); + virtual DisplayError OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level); + virtual DisplayError GetPanelBrightness(int *level); + virtual DisplayError SetAutoRefresh(bool enable) { return kErrorNone; } + virtual DisplayError SetS3DMode(HWS3DMode s3d_mode); + virtual DisplayError SetScaleLutConfig(HWScaleLutInfo *lut_info); + virtual DisplayError SetMixerAttributes(const HWMixerAttributes &mixer_attributes); + virtual DisplayError GetMixerAttributes(HWMixerAttributes *mixer_attributes); + + enum { + kHWEventVSync, + kHWEventBlank, + }; + + static const int kMaxStringLength = 1024; + static const int kNumPhysicalDisplays = 2; + // This indicates the number of fb devices created in the driver for all interfaces. Any addition + // of new fb devices should be added here. + static const int kFBNodeMax = 4; + + void DumpLayerCommit(const mdp_layer_commit &layer_commit); + DisplayError SetFormat(const LayerBufferFormat &source, uint32_t *target); + DisplayError SetStride(HWDeviceType device_type, LayerBufferFormat format, + uint32_t width, uint32_t *target); + void SetBlending(const LayerBlending &source, mdss_mdp_blend_op *target); + void SetRect(const LayerRect &source, mdp_rect *target); + void SetMDPFlags(const Layer *layer, const bool &is_rotator_used, + bool is_cursor_pipe_used, uint32_t *mdp_flags); + // Retrieves HW FrameBuffer Node Index + int GetFBNodeIndex(HWDeviceType device_type); + // Populates HWPanelInfo based on node index + void PopulateHWPanelInfo(); + void GetHWPanelInfoByNode(int device_node, HWPanelInfo *panel_info); + void GetHWPanelNameByNode(int device_node, HWPanelInfo *panel_info); + void GetHWDisplayPortAndMode(int device_node, HWPanelInfo *panel_info); + void GetSplitInfo(int device_node, HWPanelInfo *panel_info); + void GetHWPanelMaxBrightnessFromNode(HWPanelInfo *panel_info); + int ParseLine(const char *input, char *tokens[], const uint32_t max_token, uint32_t *count); + int ParseLine(const char *input, const char *delim, char *tokens[], + const uint32_t max_token, uint32_t *count); + void ResetDisplayParams(); + void SetCSC(const ColorMetaData &color_metadata, mdp_color_space *color_space); + void SetIGC(const LayerBuffer *layer_buffer, uint32_t index); + + bool EnableHotPlugDetection(int enable); + ssize_t SysFsWrite(const char* file_node, const char* value, ssize_t length); + bool IsFBNodeConnected(int fb_node); + + HWResourceInfo hw_resource_; + HWPanelInfo hw_panel_info_; + HWInfoInterface *hw_info_intf_; + int fb_node_index_; + const char *fb_path_; + BufferSyncHandler *buffer_sync_handler_; + int device_fd_ = -1; + int stored_retire_fence = -1; + HWDeviceType device_type_; + mdp_layer_commit mdp_disp_commit_; + mdp_input_layer mdp_in_layers_[kMaxSDELayers * 2]; // split panel (left + right) + HWScale *hw_scale_ = NULL; + mdp_overlay_pp_params pp_params_[kMaxSDELayers * 2]; + mdp_igc_lut_data_v1_7 igc_lut_data_[kMaxSDELayers * 2]; + mdp_output_layer mdp_out_layer_; + const char *device_name_; + bool synchronous_commit_; + HWDisplayAttributes display_attributes_ = {}; + HWMixerAttributes mixer_attributes_ = {}; + std::vector<mdp_destination_scaler_data> mdp_dest_scalar_data_; + int bl_level_update_commit = -1; + bool bl_update_commit = false; +}; + +} // namespace sdm + +#endif // __HW_DEVICE_H__ + diff --git a/msm8909/sdm/libs/core/fb/hw_events.cpp b/msm8909/sdm/libs/core/fb/hw_events.cpp new file mode 100644 index 00000000..52a80112 --- /dev/null +++ b/msm8909/sdm/libs/core/fb/hw_events.cpp @@ -0,0 +1,237 @@ +/* +* Copyright (c) 2015 - 2017, 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 <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/resource.h> +#include <sys/prctl.h> +#include <utils/debug.h> +#include <utils/sys.h> +#include <pthread.h> +#include <algorithm> +#include <vector> +#include <map> +#include <utility> + +#include "hw_events.h" + +#define __CLASS__ "HWEvents" + +namespace sdm { + +pollfd HWEvents::InitializePollFd(HWEventData *event_data) { + char node_path[kMaxStringLength] = {0}; + char data[kMaxStringLength] = {0}; + pollfd poll_fd = {0}; + poll_fd.fd = -1; + + if (event_data->event_type == HWEvent::EXIT) { + // Create an eventfd to be used to unblock the poll system call when + // a thread is exiting. + poll_fd.fd = Sys::eventfd_(0, 0); + poll_fd.events |= POLLIN; + exit_fd_ = poll_fd.fd; + } else { + snprintf(node_path, sizeof(node_path), "%s%d/%s", fb_path_, fb_num_, + map_event_to_node_[event_data->event_type]); + poll_fd.fd = Sys::open_(node_path, O_RDONLY); + poll_fd.events |= POLLPRI | POLLERR; + } + + if (poll_fd.fd < 0) { + DLOGW("open failed for display=%d event=%s, error=%s", fb_num_, + map_event_to_node_[event_data->event_type], strerror(errno)); + return poll_fd; + } + + // Read once on all fds to clear data on all fds. + Sys::pread_(poll_fd.fd, data , kMaxStringLength, 0); + + return poll_fd; +} + +DisplayError HWEvents::SetEventParser(HWEvent event_type, HWEventData *event_data) { + DisplayError error = kErrorNone; + switch (event_type) { + case HWEvent::VSYNC: + event_data->event_parser = &HWEvents::HandleVSync; + break; + case HWEvent::IDLE_NOTIFY: + event_data->event_parser = &HWEvents::HandleIdleTimeout; + break; + case HWEvent::EXIT: + event_data->event_parser = &HWEvents::HandleThreadExit; + break; + case HWEvent::SHOW_BLANK_EVENT: + event_data->event_parser = &HWEvents::HandleBlank; + break; + case HWEvent::THERMAL_LEVEL: + event_data->event_parser = &HWEvents::HandleThermal; + break; + case HWEvent::IDLE_POWER_COLLAPSE: + event_data->event_parser = &HWEvents::HandleIdlePowerCollapse; + break; + default: + error = kErrorParameters; + break; + } + + return error; +} + +void HWEvents::PopulateHWEventData() { + for (uint32_t i = 0; i < event_list_.size(); i++) { + HWEventData event_data; + event_data.event_type = event_list_[i]; + SetEventParser(event_list_[i], &event_data); + poll_fds_[i] = InitializePollFd(&event_data); + event_data_list_.push_back(event_data); + } +} + +DisplayError HWEvents::Init(int fb_num, HWEventHandler *event_handler, + const vector<HWEvent> &event_list) { + if (!event_handler) + return kErrorParameters; + + event_handler_ = event_handler; + fb_num_ = fb_num; + event_list_ = event_list; + poll_fds_.resize(event_list_.size()); + event_thread_name_ += " - " + std::to_string(fb_num_); + map_event_to_node_ = {{HWEvent::VSYNC, "vsync_event"}, {HWEvent::EXIT, "thread_exit"}, + {HWEvent::IDLE_NOTIFY, "idle_notify"}, {HWEvent::SHOW_BLANK_EVENT, "show_blank_event"}, + {HWEvent::THERMAL_LEVEL, "msm_fb_thermal_level"}, {HWEvent::IDLE_POWER_COLLAPSE, "idle_power_collapse"}}; + + PopulateHWEventData(); + + if (pthread_create(&event_thread_, NULL, &DisplayEventThread, this) < 0) { + DLOGE("Failed to start %s, error = %s", event_thread_name_.c_str()); + return kErrorResources; + } + + return kErrorNone; +} + +DisplayError HWEvents::Deinit() { + exit_threads_ = true; + Sys::pthread_cancel_(event_thread_); + + uint64_t exit_value = 1; + ssize_t write_size = Sys::write_(exit_fd_, &exit_value, sizeof(uint64_t)); + if (write_size != sizeof(uint64_t)) + DLOGW("Error triggering exit_fd_ (%d). write size = %d, error = %s", exit_fd_, write_size, + strerror(errno)); + + pthread_join(event_thread_, NULL); + + for (uint32_t i = 0; i < event_list_.size(); i++) { + Sys::close_(poll_fds_[i].fd); + poll_fds_[i].fd = -1; + } + + return kErrorNone; +} + +void* HWEvents::DisplayEventThread(void *context) { + if (context) { + return reinterpret_cast<HWEvents *>(context)->DisplayEventHandler(); + } + + return NULL; +} + +void* HWEvents::DisplayEventHandler() { + char data[kMaxStringLength] = {0}; + + prctl(PR_SET_NAME, event_thread_name_.c_str(), 0, 0, 0); + setpriority(PRIO_PROCESS, 0, kThreadPriorityUrgent); + + while (!exit_threads_) { + int error = Sys::poll_(poll_fds_.data(), UINT32(event_list_.size()), -1); + + if (error <= 0) { + DLOGW("poll failed. error = %s", strerror(errno)); + continue; + } + + for (uint32_t event = 0; event < event_list_.size(); event++) { + pollfd &poll_fd = poll_fds_[event]; + + if (event_list_.at(event) == HWEvent::EXIT) { + if ((poll_fd.revents & POLLIN) && (Sys::read_(poll_fd.fd, data, kMaxStringLength) > 0)) { + (this->*(event_data_list_[event]).event_parser)(data); + } + } else { + if ((poll_fd.revents & POLLPRI) && + (Sys::pread_(poll_fd.fd, data, kMaxStringLength, 0) > 0)) { + (this->*(event_data_list_[event]).event_parser)(data); + } + } + } + } + + pthread_exit(0); + + return NULL; +} + +void HWEvents::HandleVSync(char *data) { + int64_t timestamp = 0; + if (!strncmp(data, "VSYNC=", strlen("VSYNC="))) { + timestamp = strtoll(data + strlen("VSYNC="), NULL, 0); + } + + event_handler_->VSync(timestamp); +} + +void HWEvents::HandleIdleTimeout(char *data) { + event_handler_->IdleTimeout(); +} + +void HWEvents::HandleThermal(char *data) { + int64_t thermal_level = 0; + if (!strncmp(data, "thermal_level=", strlen("thermal_level="))) { + thermal_level = strtoll(data + strlen("thermal_level="), NULL, 0); + } + + DLOGI("Received thermal notification with thermal level = %d", thermal_level); + + event_handler_->ThermalEvent(thermal_level); +} + +void HWEvents::HandleIdlePowerCollapse(char *data) { + event_handler_->IdlePowerCollapse(); +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/core/fb/hw_events.h b/msm8909/sdm/libs/core/fb/hw_events.h new file mode 100644 index 00000000..b4607a87 --- /dev/null +++ b/msm8909/sdm/libs/core/fb/hw_events.h @@ -0,0 +1,86 @@ +/* +* Copyright (c) 2015 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __HW_EVENTS_H__ +#define __HW_EVENTS_H__ + +#include <sys/poll.h> +#include <string> +#include <vector> +#include <map> +#include <utility> + +#include "hw_interface.h" +#include "hw_events_interface.h" + +namespace sdm { + +using std::vector; +using std::map; + +class HWEvents : public HWEventsInterface { + public: + virtual DisplayError Init(int fb_num, HWEventHandler *event_handler, + const vector<HWEvent> &event_list); + virtual DisplayError Deinit(); + + private: + static const int kMaxStringLength = 1024; + + typedef void (HWEvents::*EventParser)(char *); + + struct HWEventData { + HWEvent event_type {}; + EventParser event_parser {}; + }; + + static void* DisplayEventThread(void *context); + void* DisplayEventHandler(); + void HandleVSync(char *data); + void HandleBlank(char *data) { } + void HandleIdleTimeout(char *data); + void HandleThermal(char *data); + void HandleThreadExit(char *data) { } + void HandleIdlePowerCollapse(char *data); + void PopulateHWEventData(); + DisplayError SetEventParser(HWEvent event_type, HWEventData *event_data); + pollfd InitializePollFd(HWEventData *event_data); + + HWEventHandler *event_handler_ = {}; + vector<HWEvent> event_list_ = {}; + vector<HWEventData> event_data_list_ = {}; + vector<pollfd> poll_fds_ = {}; + map<HWEvent, const char *> map_event_to_node_ = {}; + pthread_t event_thread_ = {}; + std::string event_thread_name_ = "SDM_EventThread"; + bool exit_threads_ = false; + const char* fb_path_ = "/sys/devices/virtual/graphics/fb"; + int fb_num_ = -1; + int exit_fd_ = -1; +}; + +} // namespace sdm + +#endif // __HW_EVENTS_H__ + diff --git a/msm8909/sdm/libs/core/fb/hw_hdmi.cpp b/msm8909/sdm/libs/core/fb/hw_hdmi.cpp new file mode 100644 index 00000000..15b47da0 --- /dev/null +++ b/msm8909/sdm/libs/core/fb/hw_hdmi.cpp @@ -0,0 +1,1129 @@ +/* +* Copyright (c) 2015 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <sys/ioctl.h> +#include <ctype.h> +#include <fcntl.h> +#include <linux/videodev2.h> +#include <utils/debug.h> +#include <utils/sys.h> +#include <utils/formats.h> + +#include <vector> +#include <map> +#include <utility> + +#include "hw_hdmi.h" + +#define __CLASS__ "HWHDMI" + +#define MIN_HDR_RESET_WAITTIME_SEC 2 + +namespace sdm { + +#ifdef MDP_HDR_STREAM +static int32_t GetEOTF(const GammaTransfer &transfer) { + int32_t mdp_transfer = -1; + + switch (transfer) { + case Transfer_SMPTE_ST2084: + mdp_transfer = MDP_HDR_EOTF_SMTPE_ST2084; + break; + case Transfer_HLG: + mdp_transfer = MDP_HDR_EOTF_HLG; + break; + default: + DLOGW("Unknown Transfer: %d", transfer); + } + + return mdp_transfer; +} + +static int32_t GetColoriMetry(const LayerBuffer & layer_buffer) { + bool is_yuv = layer_buffer.flags.video; + int32_t colorimetry = -1; + + if (is_yuv) { + switch (layer_buffer.color_metadata.colorPrimaries) { + case ColorPrimaries_BT601_6_525: + case ColorPrimaries_BT601_6_625: + colorimetry = MDP_COLORIMETRY_YCBCR_ITU_R_BT_601; + break; + case ColorPrimaries_BT709_5: + colorimetry = MDP_COLORIMETRY_YCBCR_ITU_R_BT_709; + break; + case ColorPrimaries_BT2020: + colorimetry = MDP_COLORIMETRY_YCBCR_ITU_R_BT_2020_YCBCR; + break; + default: + DLOGW("Unknown color primary = %d for YUV", layer_buffer.color_metadata.colorPrimaries); + } + } + + return colorimetry; +} + +static int32_t GetPixelEncoding(const LayerBuffer &layer_buffer) { + bool is_yuv = layer_buffer.flags.video; + int32_t mdp_pixel_encoding = -1; + mdp_pixel_encoding = MDP_PIXEL_ENCODING_RGB; // set RGB as default + + if (is_yuv) { + switch (layer_buffer.format) { + case kFormatYCbCr420SemiPlanarVenus: + case kFormatYCbCr420SPVenusUbwc: + case kFormatYCbCr420Planar: + case kFormatYCrCb420Planar: + case kFormatYCrCb420PlanarStride16: + case kFormatYCbCr420SemiPlanar: + case kFormatYCrCb420SemiPlanar: + case kFormatYCbCr420P010: + case kFormatYCbCr420TP10Ubwc: + mdp_pixel_encoding = MDP_PIXEL_ENCODING_YCBCR_420; + break; + case kFormatYCbCr422H2V1Packed: + case kFormatYCrCb422H2V1SemiPlanar: + case kFormatYCrCb422H1V2SemiPlanar: + case kFormatYCbCr422H2V1SemiPlanar: + case kFormatYCbCr422H1V2SemiPlanar: + mdp_pixel_encoding = MDP_PIXEL_ENCODING_YCBCR_422; + break; + default: // other yuv formats + DLOGW("New YUV format = %d, need to add support", layer_buffer.format); + break; + } + } + + return mdp_pixel_encoding; +} +static int32_t GetBitsPerComponent(const LayerBuffer &layer_buffer) { + bool is_yuv = layer_buffer.flags.video; + bool is_10_bit = Is10BitFormat(layer_buffer.format); + int32_t mdp_bpc = -1; + + if (is_yuv) { + mdp_bpc = is_10_bit ? MDP_YUV_10_BPC : MDP_YUV_8_BPC; + } else { + mdp_bpc = is_10_bit ? MDP_RGB_10_BPC : MDP_RGB_8_BPC; + } + + return mdp_bpc; +} + +static uint32_t GetRange(const ColorRange &range) { + return ((range == Range_Full) ? MDP_DYNAMIC_RANGE_VESA : MDP_DYNAMIC_RANGE_CEA); +} + +static uint32_t GetContentType(const LayerBuffer &layer_buffer) { + return (layer_buffer.flags.video ? MDP_CONTENT_TYPE_VIDEO : MDP_CONTENT_TYPE_GRAPHICS); +} +#endif + +static bool MapHDMIDisplayTiming(const msm_hdmi_mode_timing_info *mode, + fb_var_screeninfo *info) { + if (!mode || !info) { + return false; + } + + info->reserved[0] = 0; + info->reserved[1] = 0; + info->reserved[2] = 0; + info->reserved[3] = (info->reserved[3] & 0xFFFF) | (mode->video_format << 16); + info->xoffset = 0; + info->yoffset = 0; + info->xres = mode->active_h; + info->yres = mode->active_v; + info->pixclock = (mode->pixel_freq) * 1000; + info->vmode = mode->interlaced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED; + info->right_margin = mode->front_porch_h; + info->hsync_len = mode->pulse_width_h; + info->left_margin = mode->back_porch_h; + info->lower_margin = mode->front_porch_v; + info->vsync_len = mode->pulse_width_v; + info->upper_margin = mode->back_porch_v; + + info->grayscale = V4L2_PIX_FMT_RGB24; + // If the mode supports YUV420 set grayscale to the FOURCC value for YUV420. + std::bitset<32> pixel_formats = mode->pixel_formats; + if (pixel_formats[1]) { + info->grayscale = V4L2_PIX_FMT_NV12; + } + + if (!mode->active_low_h) { + info->sync |= (uint32_t)FB_SYNC_HOR_HIGH_ACT; + } else { + info->sync &= (uint32_t)~FB_SYNC_HOR_HIGH_ACT; + } + + if (!mode->active_low_v) { + info->sync |= (uint32_t)FB_SYNC_VERT_HIGH_ACT; + } else { + info->sync &= (uint32_t)~FB_SYNC_VERT_HIGH_ACT; + } + + return true; +} + +HWHDMI::HWHDMI(BufferSyncHandler *buffer_sync_handler, HWInfoInterface *hw_info_intf) + : HWDevice(buffer_sync_handler), hw_scan_info_(), active_config_index_(0) { + HWDevice::device_type_ = kDeviceHDMI; + HWDevice::device_name_ = "HDMI Display Device"; + HWDevice::hw_info_intf_ = hw_info_intf; + (void)hdr_reset_start_; + (void)hdr_reset_end_; + (void)reset_hdr_flag_; + (void)cdm_color_space_; +} + +DisplayError HWHDMI::Init() { + DisplayError error = kErrorNone; + + SetSourceProductInformation("vendor_name", "ro.product.manufacturer"); + SetSourceProductInformation("product_description", "ro.product.name"); + + error = HWDevice::Init(); + if (error != kErrorNone) { + return error; + } + + mdp_dest_scalar_data_.resize(hw_resource_.hw_dest_scalar_info.count); + + error = ReadEDIDInfo(); + if (error != kErrorNone) { + Deinit(); + return error; + } + + if (!IsResolutionFilePresent()) { + Deinit(); + return kErrorHardware; + } + + error = ReadTimingInfo(); + if (error != kErrorNone) { + Deinit(); + return error; + } + + ReadScanInfo(); + + GetPanelS3DMode(); + + s3d_mode_sdm_to_mdp_.insert(std::pair<HWS3DMode, msm_hdmi_s3d_mode> + (kS3DModeNone, HDMI_S3D_NONE)); + s3d_mode_sdm_to_mdp_.insert(std::pair<HWS3DMode, msm_hdmi_s3d_mode> + (kS3DModeLR, HDMI_S3D_SIDE_BY_SIDE)); + s3d_mode_sdm_to_mdp_.insert(std::pair<HWS3DMode, msm_hdmi_s3d_mode> + (kS3DModeRL, HDMI_S3D_SIDE_BY_SIDE)); + s3d_mode_sdm_to_mdp_.insert(std::pair<HWS3DMode, msm_hdmi_s3d_mode> + (kS3DModeTB, HDMI_S3D_TOP_AND_BOTTOM)); + s3d_mode_sdm_to_mdp_.insert(std::pair<HWS3DMode, msm_hdmi_s3d_mode> + (kS3DModeFP, HDMI_S3D_FRAME_PACKING)); + + return error; +} + +DisplayError HWHDMI::GetNumDisplayAttributes(uint32_t *count) { + *count = UINT32(hdmi_modes_.size()); + if (*count <= 0) { + return kErrorHardware; + } + + return kErrorNone; +} + +DisplayError HWHDMI::GetActiveConfig(uint32_t *active_config_index) { + *active_config_index = active_config_index_; + return kErrorNone; +} + +DisplayError HWHDMI::ReadEDIDInfo() { + ssize_t length = -1; + char edid_str[kPageSize] = {'\0'}; + char edid_path[kMaxStringLength] = {'\0'}; + snprintf(edid_path, sizeof(edid_path), "%s%d/edid_modes", fb_path_, fb_node_index_); + int edid_file = Sys::open_(edid_path, O_RDONLY); + if (edid_file < 0) { + DLOGE("EDID file open failed."); + return kErrorHardware; + } + + length = Sys::pread_(edid_file, edid_str, sizeof(edid_str)-1, 0); + if (length <= 0) { + DLOGE("%s: edid_modes file empty"); + return kErrorHardware; + } + Sys::close_(edid_file); + + DLOGI("EDID mode string: %s", edid_str); + while (length > 1 && isspace(edid_str[length-1])) { + --length; + } + edid_str[length] = '\0'; + + if (length > 0) { + // Get EDID modes from the EDID string + char *ptr = edid_str; + const uint32_t edid_count_max = 128; + char *tokens[edid_count_max] = { NULL }; + uint32_t hdmi_mode_count = 0; + + ParseLine(ptr, tokens, edid_count_max, &hdmi_mode_count); + + supported_video_modes_.resize(hdmi_mode_count); + + hdmi_modes_.resize(hdmi_mode_count); + for (uint32_t i = 0; i < hdmi_mode_count; i++) { + hdmi_modes_[i] = UINT32(atoi(tokens[i])); + } + } + + return kErrorNone; +} + +DisplayError HWHDMI::GetDisplayAttributes(uint32_t index, + HWDisplayAttributes *display_attributes) { + DTRACE_SCOPED(); + + if (index >= hdmi_modes_.size()) { + return kErrorNotSupported; + } + + // Get the resolution info from the look up table + msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[0]; + for (uint32_t i = 0; i < hdmi_modes_.size(); i++) { + msm_hdmi_mode_timing_info *cur = &supported_video_modes_[i]; + if (cur->video_format == hdmi_modes_[index]) { + timing_mode = cur; + break; + } + } + display_attributes->x_pixels = timing_mode->active_h; + display_attributes->y_pixels = timing_mode->active_v; + display_attributes->v_front_porch = timing_mode->front_porch_v; + display_attributes->v_back_porch = timing_mode->back_porch_v; + display_attributes->v_pulse_width = timing_mode->pulse_width_v; + uint32_t h_blanking = timing_mode->front_porch_h + timing_mode->back_porch_h + + timing_mode->pulse_width_h; + display_attributes->h_total = timing_mode->active_h + h_blanking; + display_attributes->x_dpi = 0; + display_attributes->y_dpi = 0; + display_attributes->fps = timing_mode->refresh_rate / 1000; + display_attributes->vsync_period_ns = UINT32(1000000000L / display_attributes->fps); + display_attributes->is_device_split = false; + if (display_attributes->x_pixels > hw_resource_.max_mixer_width) { + display_attributes->is_device_split = true; + display_attributes->h_total += h_blanking; + } + + GetDisplayS3DSupport(index, display_attributes); + std::bitset<32> pixel_formats = timing_mode->pixel_formats; + + display_attributes->is_yuv = pixel_formats[1]; + + return kErrorNone; +} + +DisplayError HWHDMI::SetDisplayAttributes(uint32_t index) { + DTRACE_SCOPED(); + + if (index > hdmi_modes_.size()) { + return kErrorNotSupported; + } + + // Variable screen info + fb_var_screeninfo vscreeninfo = {}; + if (Sys::ioctl_(device_fd_, FBIOGET_VSCREENINFO, &vscreeninfo) < 0) { + IOCTL_LOGE(FBIOGET_VSCREENINFO, device_type_); + return kErrorHardware; + } + + DLOGI("GetInfo<Mode=%d %dx%d (%d,%d,%d),(%d,%d,%d) %dMHz>", vscreeninfo.reserved[3], + vscreeninfo.xres, vscreeninfo.yres, vscreeninfo.right_margin, vscreeninfo.hsync_len, + vscreeninfo.left_margin, vscreeninfo.lower_margin, vscreeninfo.vsync_len, + vscreeninfo.upper_margin, vscreeninfo.pixclock/1000000); + + msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[0]; + for (uint32_t i = 0; i < hdmi_modes_.size(); i++) { + msm_hdmi_mode_timing_info *cur = &supported_video_modes_[i]; + if (cur->video_format == hdmi_modes_[index]) { + timing_mode = cur; + break; + } + } + + if (MapHDMIDisplayTiming(timing_mode, &vscreeninfo) == false) { + return kErrorParameters; + } + + msmfb_metadata metadata = {}; + metadata.op = metadata_op_vic; + metadata.data.video_info_code = timing_mode->video_format; + if (Sys::ioctl_(device_fd_, MSMFB_METADATA_SET, &metadata) < 0) { + IOCTL_LOGE(MSMFB_METADATA_SET, device_type_); + return kErrorHardware; + } + + DLOGI("SetInfo<Mode=%d %dx%d (%d,%d,%d),(%d,%d,%d) %dMHz>", vscreeninfo.reserved[3] & 0xFF00, + vscreeninfo.xres, vscreeninfo.yres, vscreeninfo.right_margin, vscreeninfo.hsync_len, + vscreeninfo.left_margin, vscreeninfo.lower_margin, vscreeninfo.vsync_len, + vscreeninfo.upper_margin, vscreeninfo.pixclock/1000000); + + vscreeninfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE; + if (Sys::ioctl_(device_fd_, FBIOPUT_VSCREENINFO, &vscreeninfo) < 0) { + IOCTL_LOGE(FBIOPUT_VSCREENINFO, device_type_); + return kErrorHardware; + } + + active_config_index_ = index; + + frame_rate_ = timing_mode->refresh_rate; + + // Get the display attributes for current active config index + GetDisplayAttributes(active_config_index_, &display_attributes_); + UpdateMixerAttributes(); + + supported_s3d_modes_.clear(); + supported_s3d_modes_.push_back(kS3DModeNone); + for (uint32_t mode = kS3DModeNone + 1; mode < kS3DModeMax; mode ++) { + if (display_attributes_.s3d_config[(HWS3DMode)mode]) { + supported_s3d_modes_.push_back((HWS3DMode)mode); + } + } + + SetS3DMode(kS3DModeNone); + + return kErrorNone; +} + +DisplayError HWHDMI::GetConfigIndex(uint32_t mode, uint32_t *index) { + // Check if the mode is valid and return corresponding index + for (uint32_t i = 0; i < hdmi_modes_.size(); i++) { + if (hdmi_modes_[i] == mode) { + *index = i; + DLOGI("Index = %d for config = %d", *index, mode); + return kErrorNone; + } + } + + DLOGE("Config = %d not supported", mode); + return kErrorNotSupported; +} + +DisplayError HWHDMI::Validate(HWLayers *hw_layers) { + HWDevice::ResetDisplayParams(); + return HWDevice::Validate(hw_layers); +} + +DisplayError HWHDMI::Commit(HWLayers *hw_layers) { + DisplayError error = UpdateHDRMetaData(hw_layers); + if (error != kErrorNone) { + return error; + } + if (cdm_color_space_commit_) { +#ifdef MDP_COMMIT_UPDATE_CDM_COLOR_SPACE + mdp_layer_commit_v1 &mdp_commit = mdp_disp_commit_.commit_v1; + mdp_commit.cdm_color_space = cdm_color_space_; + mdp_commit.flags |= MDP_COMMIT_UPDATE_CDM_COLOR_SPACE; +#endif + } + + error = HWDevice::Commit(hw_layers); + if (cdm_color_space_commit_) + cdm_color_space_commit_ = false; + + return error; +} + +DisplayError HWHDMI::GetHWScanInfo(HWScanInfo *scan_info) { + if (!scan_info) { + return kErrorParameters; + } + *scan_info = hw_scan_info_; + return kErrorNone; +} + +DisplayError HWHDMI::GetVideoFormat(uint32_t config_index, uint32_t *video_format) { + if (config_index > hdmi_modes_.size()) { + return kErrorNotSupported; + } + + *video_format = hdmi_modes_[config_index]; + + return kErrorNone; +} + +DisplayError HWHDMI::GetMaxCEAFormat(uint32_t *max_cea_format) { + *max_cea_format = HDMI_VFRMT_END; + + return kErrorNone; +} + +DisplayError HWHDMI::OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level) { + DisplayError error = kErrorNone; + int fd = -1; + char data[kMaxStringLength] = {'\0'}; + + snprintf(data, sizeof(data), "%s%d/hdcp2p2/min_level_change", fb_path_, fb_node_index_); + + fd = Sys::open_(data, O_WRONLY); + if (fd < 0) { + DLOGW("File '%s' could not be opened.", data); + return kErrorHardware; + } + + snprintf(data, sizeof(data), "%d", min_enc_level); + + ssize_t err = Sys::pwrite_(fd, data, strlen(data), 0); + if (err <= 0) { + DLOGE("Write failed, Error = %s", strerror(errno)); + error = kErrorHardware; + } + + Sys::close_(fd); + + return error; +} + +HWScanSupport HWHDMI::MapHWScanSupport(uint32_t value) { + switch (value) { + // TODO(user): Read the scan type from driver defined values instead of hardcoding + case 0: + return kScanNotSupported; + case 1: + return kScanAlwaysOverscanned; + case 2: + return kScanAlwaysUnderscanned; + case 3: + return kScanBoth; + default: + return kScanNotSupported; + break; + } +} + +void HWHDMI::ReadScanInfo() { + int scan_info_file = -1; + ssize_t len = -1; + char data[kPageSize] = {'\0'}; + + snprintf(data, sizeof(data), "%s%d/scan_info", fb_path_, fb_node_index_); + scan_info_file = Sys::open_(data, O_RDONLY); + if (scan_info_file < 0) { + DLOGW("File '%s' not found.", data); + return; + } + + memset(&data[0], 0, sizeof(data)); + len = Sys::pread_(scan_info_file, data, sizeof(data) - 1, 0); + if (len <= 0) { + Sys::close_(scan_info_file); + DLOGW("File %s%d/scan_info is empty.", fb_path_, fb_node_index_); + return; + } + data[len] = '\0'; + Sys::close_(scan_info_file); + + const uint32_t scan_info_max_count = 3; + uint32_t scan_info_count = 0; + char *tokens[scan_info_max_count] = { NULL }; + ParseLine(data, tokens, scan_info_max_count, &scan_info_count); + if (scan_info_count != scan_info_max_count) { + DLOGW("Failed to parse scan info string %s", data); + return; + } + + hw_scan_info_.pt_scan_support = MapHWScanSupport(UINT32(atoi(tokens[0]))); + hw_scan_info_.it_scan_support = MapHWScanSupport(UINT32(atoi(tokens[1]))); + hw_scan_info_.cea_scan_support = MapHWScanSupport(UINT32(atoi(tokens[2]))); + DLOGI("PT %d IT %d CEA %d", hw_scan_info_.pt_scan_support, hw_scan_info_.it_scan_support, + hw_scan_info_.cea_scan_support); +} + +int HWHDMI::OpenResolutionFile(int file_mode) { + char file_path[kMaxStringLength]; + memset(file_path, 0, sizeof(file_path)); + snprintf(file_path , sizeof(file_path), "%s%d/res_info", fb_path_, fb_node_index_); + + int fd = Sys::open_(file_path, file_mode); + + if (fd < 0) { + DLOGE("file '%s' not found : ret = %d err str: %s", file_path, fd, strerror(errno)); + } + + return fd; +} + +// Method to request HDMI driver to write a new page of timing info into res_info node +void HWHDMI::RequestNewPage(uint32_t page_number) { + char page_string[kPageSize]; + int fd = OpenResolutionFile(O_WRONLY); + if (fd < 0) { + return; + } + + snprintf(page_string, sizeof(page_string), "%d", page_number); + + DLOGI_IF(kTagDriverConfig, "page=%s", page_string); + + ssize_t err = Sys::pwrite_(fd, page_string, sizeof(page_string), 0); + if (err <= 0) { + DLOGE("Write to res_info failed (%s)", strerror(errno)); + } + + Sys::close_(fd); +} + +// Reads the contents of res_info node into a buffer if the file is not empty +bool HWHDMI::ReadResolutionFile(char *config_buffer) { + ssize_t bytes_read = 0; + int fd = OpenResolutionFile(O_RDONLY); + if (fd >= 0) { + bytes_read = Sys::pread_(fd, config_buffer, kPageSize, 0); + Sys::close_(fd); + } + + DLOGI_IF(kTagDriverConfig, "bytes_read = %d", bytes_read); + + return (bytes_read > 0); +} + +// Populates the internal timing info structure with the timing info obtained +// from the HDMI driver +DisplayError HWHDMI::ReadTimingInfo() { + uint32_t config_index = 0; + uint32_t page_number = MSM_HDMI_INIT_RES_PAGE; + uint32_t size = sizeof(msm_hdmi_mode_timing_info); + + while (true) { + char config_buffer[kPageSize] = {0}; + msm_hdmi_mode_timing_info *info = reinterpret_cast<msm_hdmi_mode_timing_info *>(config_buffer); + RequestNewPage(page_number); + + if (!ReadResolutionFile(config_buffer)) { + break; + } + + while (info->video_format && size < kPageSize && config_index < hdmi_modes_.size()) { + supported_video_modes_[config_index] = *info; + size += sizeof(msm_hdmi_mode_timing_info); + + DLOGI_IF(kTagDriverConfig, "Config=%d Mode %d: (%dx%d) @ %d, pixel formats %d", + config_index, + supported_video_modes_[config_index].video_format, + supported_video_modes_[config_index].active_h, + supported_video_modes_[config_index].active_v, + supported_video_modes_[config_index].refresh_rate, + supported_video_modes_[config_index].pixel_formats); + + info++; + config_index++; + } + + size = sizeof(msm_hdmi_mode_timing_info); + // Request HDMI driver to populate res_info with more + // timing information + page_number++; + } + + if (page_number == MSM_HDMI_INIT_RES_PAGE || config_index == 0) { + DLOGE("No timing information found."); + return kErrorHardware; + } + + return kErrorNone; +} + +bool HWHDMI::IsResolutionFilePresent() { + bool is_file_present = false; + int fd = OpenResolutionFile(O_RDONLY); + if (fd >= 0) { + is_file_present = true; + Sys::close_(fd); + } + + return is_file_present; +} + +void HWHDMI::SetSourceProductInformation(const char *node, const char *name) { + char property_value[kMaxStringLength]; + char sys_fs_path[kMaxStringLength]; + int hdmi_node_index = GetFBNodeIndex(kDeviceHDMI); + if (hdmi_node_index < 0) { + return; + } + + ssize_t length = 0; + bool prop_read_success = Debug::GetProperty(name, property_value); + if (!prop_read_success) { + return; + } + + snprintf(sys_fs_path , sizeof(sys_fs_path), "%s%d/%s", fb_path_, hdmi_node_index, node); + length = HWDevice::SysFsWrite(sys_fs_path, property_value, + static_cast<ssize_t>(strlen(property_value))); + if (length <= 0) { + DLOGW("Failed to write %s = %s", node, property_value); + } +} + +DisplayError HWHDMI::GetDisplayS3DSupport(uint32_t index, + HWDisplayAttributes *attrib) { + ssize_t length = -1; + char edid_s3d_str[kPageSize] = {'\0'}; + char edid_s3d_path[kMaxStringLength] = {'\0'}; + snprintf(edid_s3d_path, sizeof(edid_s3d_path), "%s%d/edid_3d_modes", fb_path_, fb_node_index_); + + if (index > hdmi_modes_.size()) { + return kErrorNotSupported; + } + + attrib->s3d_config[kS3DModeNone] = 1; + + // Three level inception! + // The string looks like 16=SSH,4=FP:TAB:SSH,5=FP:SSH,32=FP:TAB:SSH + // Initialize all the pointers to NULL to avoid crash in function strtok_r() + char *saveptr_l1 = NULL, *saveptr_l2 = NULL, *saveptr_l3 = NULL; + char *l1 = NULL, *l2 = NULL, *l3 = NULL; + + int edid_s3d_node = Sys::open_(edid_s3d_path, O_RDONLY); + if (edid_s3d_node < 0) { + DLOGW("%s could not be opened : %s", edid_s3d_path, strerror(errno)); + return kErrorNotSupported; + } + + length = Sys::pread_(edid_s3d_node, edid_s3d_str, sizeof(edid_s3d_str)-1, 0); + if (length <= 0) { + Sys::close_(edid_s3d_node); + return kErrorNotSupported; + } + + l1 = strtok_r(edid_s3d_str, ",", &saveptr_l1); + while (l1 != NULL) { + l2 = strtok_r(l1, "=", &saveptr_l2); + if (l2 != NULL) { + if (hdmi_modes_[index] == (uint32_t)atoi(l2)) { + l3 = strtok_r(saveptr_l2, ":", &saveptr_l3); + while (l3 != NULL) { + if (strncmp("SSH", l3, strlen("SSH")) == 0) { + attrib->s3d_config[kS3DModeLR] = 1; + attrib->s3d_config[kS3DModeRL] = 1; + } else if (strncmp("TAB", l3, strlen("TAB")) == 0) { + attrib->s3d_config[kS3DModeTB] = 1; + } else if (strncmp("FP", l3, strlen("FP")) == 0) { + attrib->s3d_config[kS3DModeFP] = 1; + } + l3 = strtok_r(NULL, ":", &saveptr_l3); + } + } + } + l1 = strtok_r(NULL, ",", &saveptr_l1); + } + + Sys::close_(edid_s3d_node); + return kErrorNone; +} + +bool HWHDMI::IsSupportedS3DMode(HWS3DMode s3d_mode) { + for (uint32_t i = 0; i < supported_s3d_modes_.size(); i++) { + if (supported_s3d_modes_[i] == s3d_mode) { + return true; + } + } + return false; +} + +DisplayError HWHDMI::SetS3DMode(HWS3DMode s3d_mode) { + if (!IsSupportedS3DMode(s3d_mode)) { + DLOGW("S3D mode is not supported s3d_mode = %d", s3d_mode); + return kErrorNotSupported; + } + + std::map<HWS3DMode, msm_hdmi_s3d_mode>::iterator it = s3d_mode_sdm_to_mdp_.find(s3d_mode); + if (it == s3d_mode_sdm_to_mdp_.end()) { + return kErrorNotSupported; + } + msm_hdmi_s3d_mode s3d_mdp_mode = it->second; + + if (active_mdp_s3d_mode_ == s3d_mdp_mode) { + // HDMI_S3D_SIDE_BY_SIDE is an mdp mapping for kS3DModeLR and kS3DModeRL s3d modes. So no need + // to update the s3d_mode node. hw_panel_info needs to be updated to differentiate these two s3d + // modes in strategy + hw_panel_info_.s3d_mode = s3d_mode; + return kErrorNone; + } + + ssize_t length = -1; + char s3d_mode_path[kMaxStringLength] = {'\0'}; + char s3d_mode_string[kMaxStringLength] = {'\0'}; + snprintf(s3d_mode_path, sizeof(s3d_mode_path), "%s%d/s3d_mode", fb_path_, fb_node_index_); + + int s3d_mode_node = Sys::open_(s3d_mode_path, O_RDWR); + if (s3d_mode_node < 0) { + DLOGW("%s could not be opened : %s", s3d_mode_path, strerror(errno)); + return kErrorNotSupported; + } + + snprintf(s3d_mode_string, sizeof(s3d_mode_string), "%d", s3d_mdp_mode); + length = Sys::pwrite_(s3d_mode_node, s3d_mode_string, sizeof(s3d_mode_string), 0); + if (length <= 0) { + DLOGW("Failed to write into s3d node: %s", strerror(errno)); + Sys::close_(s3d_mode_node); + return kErrorNotSupported; + } + + active_mdp_s3d_mode_ = s3d_mdp_mode; + hw_panel_info_.s3d_mode = s3d_mode; + Sys::close_(s3d_mode_node); + + DLOGI_IF(kTagDriverConfig, "Set s3d mode %d", hw_panel_info_.s3d_mode); + return kErrorNone; +} + +DisplayError HWHDMI::GetPanelS3DMode() { + ssize_t length = -1; + char s3d_mode_path[kMaxStringLength] = {'\0'}; + char s3d_mode_string[kMaxStringLength] = {'\0'}; + snprintf(s3d_mode_path, sizeof(s3d_mode_path), "%s%d/s3d_mode", fb_path_, fb_node_index_); + int panel_s3d_mode = 0; + + int s3d_mode_node = Sys::open_(s3d_mode_path, O_RDWR); + if (s3d_mode_node < 0) { + DLOGE("%s could not be opened : %s", s3d_mode_path, strerror(errno)); + return kErrorNotSupported; + } + + length = Sys::pread_(s3d_mode_node, s3d_mode_string, sizeof(s3d_mode_string), 0); + if (length <= 0) { + DLOGE("Failed read s3d node: %s", strerror(errno)); + Sys::close_(s3d_mode_node); + return kErrorNotSupported; + } + + panel_s3d_mode = atoi(s3d_mode_string); + if (panel_s3d_mode < HDMI_S3D_NONE || panel_s3d_mode >= HDMI_S3D_MAX) { + Sys::close_(s3d_mode_node); + DLOGW("HDMI panel S3D mode is not supported panel_s3d_mode = %d", panel_s3d_mode); + return kErrorUndefined; + } + + active_mdp_s3d_mode_ = static_cast<msm_hdmi_s3d_mode>(panel_s3d_mode); + Sys::close_(s3d_mode_node); + + DLOGI_IF(kTagDriverConfig, "Get HDMI panel s3d mode %d", active_mdp_s3d_mode_); + return kErrorNone; +} + +DisplayError HWHDMI::GetDynamicFrameRateMode(uint32_t refresh_rate, uint32_t *mode, + DynamicFPSData *data, uint32_t *config_index) { + msm_hdmi_mode_timing_info *cur = NULL; + msm_hdmi_mode_timing_info *dst = NULL; + uint32_t i = 0; + int pre_refresh_rate_diff = 0; + bool pre_unstd_mode = false; + + for (i = 0; i < hdmi_modes_.size(); i++) { + msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[i]; + if (timing_mode->video_format == hdmi_modes_[active_config_index_]) { + cur = timing_mode; + break; + } + } + + if (cur == NULL) { + DLOGE("can't find timing info for active config index(%d)", active_config_index_); + return kErrorUndefined; + } + + if (cur->refresh_rate != frame_rate_) { + pre_unstd_mode = true; + } + + if (i >= hdmi_modes_.size()) { + return kErrorNotSupported; + } + + dst = cur; + pre_refresh_rate_diff = static_cast<int>(dst->refresh_rate) - static_cast<int>(refresh_rate); + + for (i = 0; i < hdmi_modes_.size(); i++) { + msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[i]; + if (cur->active_h == timing_mode->active_h && + cur->active_v == timing_mode->active_v && + cur->pixel_formats == timing_mode->pixel_formats ) { + int cur_refresh_rate_diff = static_cast<int>(timing_mode->refresh_rate) - + static_cast<int>(refresh_rate); + if (abs(pre_refresh_rate_diff) > abs(cur_refresh_rate_diff)) { + pre_refresh_rate_diff = cur_refresh_rate_diff; + dst = timing_mode; + } + } + } + + if (pre_refresh_rate_diff > kThresholdRefreshRate) { + return kErrorNotSupported; + } + + GetConfigIndex(dst->video_format, config_index); + + data->hor_front_porch = dst->front_porch_h; + data->hor_back_porch = dst->back_porch_h; + data->hor_pulse_width = dst->pulse_width_h; + data->clk_rate_hz = dst->pixel_freq; + data->fps = refresh_rate; + + if (dst->front_porch_h != cur->front_porch_h) { + *mode = kModeHFP; + } + + if (dst->refresh_rate != refresh_rate || dst->pixel_freq != cur->pixel_freq) { + if (*mode == kModeHFP) { + if (dst->refresh_rate != refresh_rate) { + *mode = kModeHFPCalcClock; + } else { + *mode = kModeClockHFP; + } + } else { + *mode = kModeClock; + } + } + + if (pre_unstd_mode && (*mode == kModeHFP)) { + *mode = kModeClockHFP; + } + + return kErrorNone; +} + +DisplayError HWHDMI::SetRefreshRate(uint32_t refresh_rate) { + char mode_path[kMaxStringLength] = {0}; + char node_path[kMaxStringLength] = {0}; + uint32_t mode = kModeClock; + uint32_t config_index = 0; + DynamicFPSData data; + DisplayError error = kErrorNone; + + if (refresh_rate == frame_rate_) { + return error; + } + + error = GetDynamicFrameRateMode(refresh_rate, &mode, &data, &config_index); + if (error != kErrorNone) { + return error; + } + + snprintf(mode_path, sizeof(mode_path), "%s%d/msm_fb_dfps_mode", fb_path_, fb_node_index_); + snprintf(node_path, sizeof(node_path), "%s%d/dynamic_fps", fb_path_, fb_node_index_); + + int fd_mode = Sys::open_(mode_path, O_WRONLY); + if (fd_mode < 0) { + DLOGE("Failed to open %s with error %s", mode_path, strerror(errno)); + return kErrorFileDescriptor; + } + + char dfps_mode[kMaxStringLength]; + snprintf(dfps_mode, sizeof(dfps_mode), "%d", mode); + DLOGI_IF(kTagDriverConfig, "Setting dfps_mode = %d", mode); + ssize_t len = Sys::pwrite_(fd_mode, dfps_mode, strlen(dfps_mode), 0); + if (len < 0) { + DLOGE("Failed to enable dfps mode %d with error %s", mode, strerror(errno)); + Sys::close_(fd_mode); + return kErrorUndefined; + } + Sys::close_(fd_mode); + + int fd_node = Sys::open_(node_path, O_WRONLY); + if (fd_node < 0) { + DLOGE("Failed to open %s with error %s", node_path, strerror(errno)); + return kErrorFileDescriptor; + } + + char refresh_rate_string[kMaxStringLength]; + if (mode == kModeHFP || mode == kModeClock) { + snprintf(refresh_rate_string, sizeof(refresh_rate_string), "%d", data.fps); + DLOGI_IF(kTagDriverConfig, "Setting refresh rate = %d", data.fps); + } else { + snprintf(refresh_rate_string, sizeof(refresh_rate_string), "%d %d %d %d %d", + data.hor_front_porch, data.hor_back_porch, data.hor_pulse_width, + data.clk_rate_hz, data.fps); + } + len = Sys::pwrite_(fd_node, refresh_rate_string, strlen(refresh_rate_string), 0); + if (len < 0) { + DLOGE("Failed to write %d with error %s", refresh_rate, strerror(errno)); + Sys::close_(fd_node); + return kErrorUndefined; + } + Sys::close_(fd_node); + + error = ReadTimingInfo(); + if (error != kErrorNone) { + return error; + } + + GetDisplayAttributes(config_index, &display_attributes_); + UpdateMixerAttributes(); + + frame_rate_ = refresh_rate; + active_config_index_ = config_index; + + DLOGI_IF(kTagDriverConfig, "config_index(%d) Mode(%d) frame_rate(%d)", + config_index, + mode, + frame_rate_); + + return kErrorNone; +} + +void HWHDMI::UpdateMixerAttributes() { + mixer_attributes_.width = display_attributes_.x_pixels; + mixer_attributes_.height = display_attributes_.y_pixels; + mixer_attributes_.split_left = display_attributes_.is_device_split ? + (display_attributes_.x_pixels / 2) : mixer_attributes_.width; +} + +DisplayError HWHDMI::UpdateHDRMetaData(HWLayers *hw_layers) { + if (!hw_panel_info_.hdr_enabled) { + return kErrorNone; + } + + DisplayError error = kErrorNone; + +#ifdef MDP_HDR_STREAM + const HWHDRLayerInfo &hdr_layer_info = hw_layers->info.hdr_layer_info; + char hdr_stream_path[kMaxStringLength] = {}; + snprintf(hdr_stream_path, sizeof(hdr_stream_path), "%s%d/hdr_stream", fb_path_, fb_node_index_); + + Layer hdr_layer = {}; + if (hdr_layer_info.operation == HWHDRLayerInfo::kSet && hdr_layer_info.layer_index > -1) { + hdr_layer = *(hw_layers->info.stack->layers.at(UINT32(hdr_layer_info.layer_index))); + } + + const LayerBuffer *layer_buffer = &hdr_layer.input_buffer; + const MasteringDisplay &mastering_display = layer_buffer->color_metadata.masteringDisplayInfo; + const ContentLightLevel &light_level = layer_buffer->color_metadata.contentLightLevel; + const Primaries &primaries = mastering_display.primaries; + + mdp_hdr_stream_ctrl hdr_ctrl = {}; + if (hdr_layer_info.operation == HWHDRLayerInfo::kSet) { + int32_t eotf = GetEOTF(layer_buffer->color_metadata.transfer); + hdr_ctrl.hdr_stream.eotf = (eotf < 0) ? 0 : UINT32(eotf); + hdr_ctrl.hdr_stream.white_point_x = primaries.whitePoint[0]; + hdr_ctrl.hdr_stream.white_point_y = primaries.whitePoint[1]; + hdr_ctrl.hdr_stream.display_primaries_x[0] = primaries.rgbPrimaries[0][0]; + hdr_ctrl.hdr_stream.display_primaries_y[0] = primaries.rgbPrimaries[0][1]; + hdr_ctrl.hdr_stream.display_primaries_x[1] = primaries.rgbPrimaries[1][0]; + hdr_ctrl.hdr_stream.display_primaries_y[1] = primaries.rgbPrimaries[1][1]; + hdr_ctrl.hdr_stream.display_primaries_x[2] = primaries.rgbPrimaries[2][0]; + hdr_ctrl.hdr_stream.display_primaries_y[2] = primaries.rgbPrimaries[2][1]; + hdr_ctrl.hdr_stream.min_luminance = mastering_display.minDisplayLuminance; + hdr_ctrl.hdr_stream.max_luminance = mastering_display.maxDisplayLuminance/10000; + hdr_ctrl.hdr_stream.max_content_light_level = light_level.maxContentLightLevel; + hdr_ctrl.hdr_stream.max_average_light_level = light_level.minPicAverageLightLevel; + hdr_ctrl.hdr_state = HDR_ENABLE; + reset_hdr_flag_ = false; +#ifdef MDP_COMMIT_UPDATE_CDM_COLOR_SPACE + HWDevice::SetCSC(layer_buffer->color_metadata, &cdm_color_space_); + cdm_color_space_commit_ = true; +#endif + // DP related + int32_t pixel_encoding = GetPixelEncoding(hdr_layer.input_buffer); + hdr_ctrl.hdr_stream.pixel_encoding = (pixel_encoding < 0) ? 0 : UINT32(pixel_encoding); + int32_t colorimetry = GetColoriMetry(hdr_layer.input_buffer); + hdr_ctrl.hdr_stream.colorimetry = (colorimetry < 0) ? 0 : UINT32(colorimetry); + hdr_ctrl.hdr_stream.range = GetRange(hdr_layer.input_buffer.color_metadata.range); + int32_t bits_per_component = GetBitsPerComponent(hdr_layer.input_buffer); + hdr_ctrl.hdr_stream.bits_per_component = + (bits_per_component < 0) ? 0 : UINT32(bits_per_component); + hdr_ctrl.hdr_stream.content_type = GetContentType(hdr_layer.input_buffer); + + DLOGD_IF(kTagDriverConfig, "kSet: HDR Stream : MaxDisplayLuminance = %d\n" + "MinDisplayLuminance = %d MaxContentLightLevel = %d MaxAverageLightLevel = %d\n" + "Red_x = %d Red_y = %d Green_x = %d Green_y = %d Blue_x = %d Blue_y = %d\n" + "WhitePoint_x = %d WhitePoint_y = %d EOTF = %d PixelEncoding = %d Colorimetry = %d\n" + "Range = %d BPC = %d ContentType = %d hdr_state = %d", + hdr_ctrl.hdr_stream.max_luminance, hdr_ctrl.hdr_stream.min_luminance, + hdr_ctrl.hdr_stream.max_content_light_level, hdr_ctrl.hdr_stream.max_average_light_level, + hdr_ctrl.hdr_stream.display_primaries_x[0], hdr_ctrl.hdr_stream.display_primaries_y[0], + hdr_ctrl.hdr_stream.display_primaries_x[1], hdr_ctrl.hdr_stream.display_primaries_y[1], + hdr_ctrl.hdr_stream.display_primaries_x[2], hdr_ctrl.hdr_stream.display_primaries_y[2], + hdr_ctrl.hdr_stream.white_point_x, hdr_ctrl.hdr_stream.white_point_x, + hdr_ctrl.hdr_stream.eotf, hdr_ctrl.hdr_stream.pixel_encoding, + hdr_ctrl.hdr_stream.colorimetry, hdr_ctrl.hdr_stream.range, + hdr_ctrl.hdr_stream.bits_per_component, hdr_ctrl.hdr_stream.content_type, + hdr_ctrl.hdr_state); + } else if (hdr_layer_info.operation == HWHDRLayerInfo::kReset) { + memset(&hdr_ctrl.hdr_stream, 0, sizeof(hdr_ctrl.hdr_stream)); + hdr_ctrl.hdr_state = HDR_RESET; + reset_hdr_flag_ = true; + hdr_reset_start_ = time(NULL); +#ifdef MDP_COMMIT_UPDATE_CDM_COLOR_SPACE + cdm_color_space_ = (mdp_color_space) MDP_CSC_DEFAULT; + cdm_color_space_commit_ = true; +#endif + DLOGD_IF(kTagDriverConfig, "kReset: HDR Stream: HDR_RESET"); + } else if (hdr_layer_info.operation == HWHDRLayerInfo::kNoOp) { + if (reset_hdr_flag_) { + hdr_reset_end_ = time(NULL); + + if ((hdr_reset_end_ - hdr_reset_start_) >= MIN_HDR_RESET_WAITTIME_SEC) { + reset_hdr_flag_ = false; + memset(&hdr_ctrl.hdr_stream, 0, sizeof(hdr_ctrl.hdr_stream)); + hdr_ctrl.hdr_state = HDR_DISABLE; + DLOGD_IF(kTagDriverConfig, "kNoOp: HDR Stream: HDR_DISABLE"); + } else { + return kErrorNone; + } + } else { + return kErrorNone; + } + } + + int fd = Sys::open_(hdr_stream_path, O_WRONLY); + if (fd < 0) { + DLOGE("Failed to open %s with error %s", hdr_stream_path, strerror(errno)); + return kErrorFileDescriptor; + } + + const void *hdr_metadata = reinterpret_cast<const void*>(&hdr_ctrl); + ssize_t len = Sys::pwrite_(fd, hdr_metadata, sizeof(hdr_ctrl), 0); + if (len <= 0) { + DLOGE("Failed to write hdr_metadata"); + error = kErrorUndefined; + } + Sys::close_(fd); +#endif + + return error; +} + +} // namespace sdm + diff --git a/msm8909/sdm/libs/core/fb/hw_hdmi.h b/msm8909/sdm/libs/core/fb/hw_hdmi.h new file mode 100644 index 00000000..1496a24c --- /dev/null +++ b/msm8909/sdm/libs/core/fb/hw_hdmi.h @@ -0,0 +1,130 @@ +/* +* Copyright (c) 2015 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __HW_HDMI_H__ +#define __HW_HDMI_H__ + +#include <video/msm_hdmi_modes.h> +#include <map> +#include <vector> + +#include "hw_device.h" + +namespace sdm { + +using std::vector; + +class HWHDMI : public HWDevice { + public: + HWHDMI(BufferSyncHandler *buffer_sync_handler, HWInfoInterface *hw_info_intf); + + protected: + enum HWFramerateUpdate { + // Switch framerate by switch to other standard modes though panel blank/unblank + kModeSuspendResume, + // Switch framerate by tuning pixel clock + kModeClock, + // Switch framerate by tuning vertical front porch + kModeVFP, + // Switch framerate by tuning horizontal front porch + kModeHFP, + // Switch framerate by tuning horizontal front porch and clock + kModeClockHFP, + // Switch framerate by tuning horizontal front porch and re-caculate clock + kModeHFPCalcClock, + kModeMAX + }; + + /** + * struct DynamicFPSData - defines dynamic fps related data + * @hor_front_porch: horizontal front porch + * @hor_back_porch: horizontal back porch + * @hor_pulse_width: horizontal pulse width + * @clk_rate_hz: panel clock rate in HZ + * @fps: frames per second + */ + struct DynamicFPSData { + uint32_t hor_front_porch; + uint32_t hor_back_porch; + uint32_t hor_pulse_width; + uint32_t clk_rate_hz; + uint32_t fps; + }; + + virtual DisplayError Init(); + virtual DisplayError GetNumDisplayAttributes(uint32_t *count); + // Requirement to call this only after the first config has been explicitly set by client + virtual DisplayError GetActiveConfig(uint32_t *active_config); + virtual DisplayError GetDisplayAttributes(uint32_t index, + HWDisplayAttributes *display_attributes); + virtual DisplayError GetHWScanInfo(HWScanInfo *scan_info); + virtual DisplayError GetVideoFormat(uint32_t config_index, uint32_t *video_format); + virtual DisplayError GetMaxCEAFormat(uint32_t *max_cea_format); + virtual DisplayError OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level); + virtual DisplayError SetDisplayAttributes(uint32_t index); + virtual DisplayError GetConfigIndex(uint32_t mode, uint32_t *index); + virtual DisplayError Validate(HWLayers *hw_layers); + virtual DisplayError Commit(HWLayers *hw_layers); + virtual DisplayError SetS3DMode(HWS3DMode s3d_mode); + virtual DisplayError SetRefreshRate(uint32_t refresh_rate); + + private: + DisplayError ReadEDIDInfo(); + void ReadScanInfo(); + HWScanSupport MapHWScanSupport(uint32_t value); + int OpenResolutionFile(int file_mode); + void RequestNewPage(uint32_t page_number); + DisplayError ReadTimingInfo(); + bool ReadResolutionFile(char *config_buffer); + bool IsResolutionFilePresent(); + void SetSourceProductInformation(const char *node, const char *name); + DisplayError GetDisplayS3DSupport(uint32_t index, + HWDisplayAttributes *attrib); + DisplayError GetPanelS3DMode(); + bool IsSupportedS3DMode(HWS3DMode s3d_mode); + void UpdateMixerAttributes(); + DisplayError UpdateHDRMetaData(HWLayers *hw_layers); + + DisplayError GetDynamicFrameRateMode(uint32_t refresh_rate, uint32_t*mode, + DynamicFPSData *data, uint32_t *config_index); + static const int kThresholdRefreshRate = 1000; + vector<uint32_t> hdmi_modes_; + // Holds the hdmi timing information. Ex: resolution, fps etc., + vector<msm_hdmi_mode_timing_info> supported_video_modes_; + HWScanInfo hw_scan_info_; + uint32_t active_config_index_; + std::map<HWS3DMode, msm_hdmi_s3d_mode> s3d_mode_sdm_to_mdp_; + vector<HWS3DMode> supported_s3d_modes_; + msm_hdmi_s3d_mode active_mdp_s3d_mode_ = HDMI_S3D_NONE; + uint32_t frame_rate_ = 0; + time_t hdr_reset_start_ = 0, hdr_reset_end_ = 0; + bool reset_hdr_flag_ = false; + mdp_color_space cdm_color_space_ = {}; + bool cdm_color_space_commit_ = false; +}; + +} // namespace sdm + +#endif // __HW_HDMI_H__ + diff --git a/msm8909/sdm/libs/core/fb/hw_info.cpp b/msm8909/sdm/libs/core/fb/hw_info.cpp new file mode 100644 index 00000000..636acb92 --- /dev/null +++ b/msm8909/sdm/libs/core/fb/hw_info.cpp @@ -0,0 +1,565 @@ +/* +* Copyright (c) 2015-2017, 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 <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <utils/constants.h> +#include <utils/debug.h> +#include <utils/sys.h> +#include <dlfcn.h> + +#include <algorithm> +#include <iostream> +#include <fstream> +#include <map> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "hw_info.h" + +#define __CLASS__ "HWInfo" + +using std::vector; +using std::map; +using std::string; +using std::fstream; +using std::to_string; + +namespace sdm { + +// kDefaultFormatSupport contains the bit map of supported formats for each hw blocks. +// For eg: if Cursor supports MDP_RGBA_8888[bit-13] and MDP_RGB_565[bit-0], then cursor pipe array +// contains { 0x01[0-3], 0x00[4-7], 0x00[8-12], 0x01[13-16], 0x00[17-20], 0x00[21-24], 0x00[24-28] } +const std::bitset<8> HWInfo::kDefaultFormatSupport[kHWSubBlockMax][ + BITS_TO_BYTES(MDP_IMGTYPE_LIMIT1)] = { + { 0xFF, 0xF5, 0x1C, 0x1E, 0x20, 0xFF, 0x01, 0x00, 0xFE, 0x1F }, // kHWVIGPipe + { 0x33, 0xE0, 0x00, 0x16, 0x00, 0xBF, 0x00, 0x00, 0xFE, 0x07 }, // kHWRGBPipe + { 0x33, 0xE0, 0x00, 0x16, 0x00, 0xBF, 0x00, 0x00, 0xFE, 0x07 }, // kHWDMAPipe + { 0x12, 0x60, 0x0C, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00 }, // kHWCursorPipe + { 0xFF, 0xF5, 0x1C, 0x1E, 0x20, 0xFF, 0x01, 0x00, 0xFE, 0x1F }, // kHWRotatorInput + { 0xFF, 0xF5, 0x1C, 0x1E, 0x20, 0xFF, 0x01, 0x00, 0xFE, 0x1F }, // kHWRotatorOutput + { 0x3F, 0xF4, 0x10, 0x1E, 0x20, 0xFF, 0x01, 0x00, 0xAA, 0x16 }, // kHWWBIntfOutput +}; + +int HWInfo::ParseString(const char *input, char *tokens[], const uint32_t max_token, + const char *delim, uint32_t *count) { + char *tmp_token = NULL; + char *temp_ptr; + uint32_t index = 0; + if (!input) { + return -1; + } + tmp_token = strtok_r(const_cast<char *>(input), delim, &temp_ptr); + while (tmp_token && index < max_token) { + tokens[index++] = tmp_token; + tmp_token = strtok_r(NULL, delim, &temp_ptr); + } + *count = index; + + return 0; +} + +DisplayError HWInfo::GetDynamicBWLimits(HWResourceInfo *hw_resource) { + Sys::fstream fs(kBWModeBitmap, fstream::in); + if (!fs.is_open()) { + DLOGE("File '%s' not found", kBWModeBitmap); + return kErrorHardware; + } + + HWDynBwLimitInfo* bw_info = &hw_resource->dyn_bw_info; + for (int index = 0; index < kBwModeMax; index++) { + bw_info->total_bw_limit[index] = UINT32(hw_resource->max_bandwidth_low); + bw_info->pipe_bw_limit[index] = hw_resource->max_pipe_bw; + } + + uint32_t token_count = 0; + const uint32_t max_count = kBwModeMax; + char *tokens[max_count] = { NULL }; + string line; + while (Sys::getline_(fs, line)) { + if (!ParseString(line.c_str(), tokens, max_count, ":, =\n", &token_count)) { + if (!strncmp(tokens[0], "default_pipe", strlen("default_pipe"))) { + bw_info->pipe_bw_limit[kBwDefault] = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "camera_pipe", strlen("camera_pipe"))) { + bw_info->pipe_bw_limit[kBwCamera] = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "vflip_pipe", strlen("vflip_pipe"))) { + bw_info->pipe_bw_limit[kBwVFlip] = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "hflip_pipe", strlen("hflip_pipe"))) { + bw_info->pipe_bw_limit[kBwHFlip] = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "default", strlen("default"))) { + bw_info->total_bw_limit[kBwDefault] = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "camera", strlen("camera"))) { + bw_info->total_bw_limit[kBwCamera] = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "vflip", strlen("vflip"))) { + bw_info->total_bw_limit[kBwVFlip] = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "hflip", strlen("hflip"))) { + bw_info->total_bw_limit[kBwHFlip] = UINT32(atoi(tokens[1])); + } + } + } + + return kErrorNone; +} + +DisplayError HWInfo::GetHWResourceInfo(HWResourceInfo *hw_resource) { + if (hw_resource_) { + *hw_resource = *hw_resource_; + return kErrorNone; + } + string fb_path = "/sys/devices/virtual/graphics/fb" + + to_string(kHWCapabilitiesNode) + "/mdp/caps"; + + Sys::fstream fs(fb_path, fstream::in); + if (!fs.is_open()) { + DLOGE("File '%s' not found", fb_path.c_str()); + return kErrorHardware; + } + + hw_resource_ = new HWResourceInfo; + + InitSupportedFormatMap(hw_resource_); + hw_resource_->hw_version = kHWMdssVersion5; + + uint32_t token_count = 0; + const uint32_t max_count = 256; + char *tokens[max_count] = { NULL }; + string line; + while (Sys::getline_(fs, line)) { + // parse the line and update information accordingly + if (!ParseString(line.c_str(), tokens, max_count, ":, =\n", &token_count)) { + if (!strncmp(tokens[0], "mdp_version", strlen("mdp_version"))) { + hw_resource_->hw_version = UINT32(atoi(tokens[1])); // HW Version 3/5 + } else if (!strncmp(tokens[0], "hw_rev", strlen("hw_rev"))) { + hw_resource_->hw_revision = UINT32(atoi(tokens[1])); // HW Rev, v1/v2 + } else if (!strncmp(tokens[0], "rot_input_fmts", strlen("rot_input_fmts"))) { + ParseFormats(&tokens[1], (token_count - 1), kHWRotatorInput, hw_resource_); + } else if (!strncmp(tokens[0], "rot_output_fmts", strlen("rot_output_fmts"))) { + ParseFormats(&tokens[1], (token_count - 1), kHWRotatorOutput, hw_resource_); + } else if (!strncmp(tokens[0], "wb_output_fmts", strlen("wb_output_fmts"))) { + ParseFormats(&tokens[1], (token_count - 1), kHWWBIntfOutput, hw_resource_); + } else if (!strncmp(tokens[0], "blending_stages", strlen("blending_stages"))) { + hw_resource_->num_blending_stages = UINT8(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "max_downscale_ratio", strlen("max_downscale_ratio"))) { + hw_resource_->max_scale_down = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "max_upscale_ratio", strlen("max_upscale_ratio"))) { + hw_resource_->max_scale_up = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "rot_dwnscale_max", strlen("rot_dwnscale_max"))) { + hw_resource_->rot_downscale_max = FLOAT(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "max_bandwidth_low", strlen("max_bandwidth_low"))) { + hw_resource_->max_bandwidth_low = UINT64(atol(tokens[1])); + } else if (!strncmp(tokens[0], "max_bandwidth_high", strlen("max_bandwidth_high"))) { + hw_resource_->max_bandwidth_high = UINT64(atol(tokens[1])); + } else if (!strncmp(tokens[0], "max_mixer_width", strlen("max_mixer_width"))) { + hw_resource_->max_mixer_width = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "max_pipe_width", strlen("max_pipe_width"))) { + hw_resource_->max_pipe_width = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "max_cursor_size", strlen("max_cursor_size"))) { + hw_resource_->max_cursor_size = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "max_pipe_bw", strlen("max_pipe_bw"))) { + hw_resource_->max_pipe_bw = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "max_mdp_clk", strlen("max_mdp_clk"))) { + hw_resource_->max_sde_clk = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "clk_fudge_factor", strlen("clk_fudge_factor"))) { + hw_resource_->clk_fudge_factor = FLOAT(atoi(tokens[1])) / FLOAT(atoi(tokens[2])); + } else if (!strncmp(tokens[0], "fmt_mt_nv12_factor", strlen("fmt_mt_nv12_factor"))) { + hw_resource_->macrotile_nv12_factor = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "fmt_mt_factor", strlen("fmt_mt_factor"))) { + hw_resource_->macrotile_factor = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "fmt_linear_factor", strlen("fmt_linear_factor"))) { + hw_resource_->linear_factor = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "scale_factor", strlen("scale_factor"))) { + hw_resource_->scale_factor = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "xtra_ff_factor", strlen("xtra_ff_factor"))) { + hw_resource_->extra_fudge_factor = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "amortizable_threshold", strlen("amortizable_threshold"))) { + hw_resource_->amortizable_threshold = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "system_overhead_lines", strlen("system_overhead_lines"))) { + hw_resource_->system_overhead_lines = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "wb_intf_index", strlen("wb_intf_index"))) { + hw_resource_->writeback_index = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "dest_scaler_count", strlen("dest_scaler_count"))) { + hw_resource_->hw_dest_scalar_info.count = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "max_dest_scale_up", strlen("max_dest_scale_up"))) { + hw_resource_->hw_dest_scalar_info.max_scale_up = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "max_dest_scaler_input_width", + strlen("max_dest_scaler_input_width"))) { + hw_resource_->hw_dest_scalar_info.max_input_width = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "max_dest_scaler_output_width", + strlen("max_dest_scaler_output_width"))) { + hw_resource_->hw_dest_scalar_info.max_output_width = UINT32(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "features", strlen("features"))) { + for (uint32_t i = 0; i < token_count; i++) { + if (!strncmp(tokens[i], "bwc", strlen("bwc"))) { + hw_resource_->has_bwc = true; + } else if (!strncmp(tokens[i], "ubwc", strlen("ubwc"))) { + hw_resource_->has_ubwc = true; + } else if (!strncmp(tokens[i], "decimation", strlen("decimation"))) { + hw_resource_->has_decimation = true; + } else if (!strncmp(tokens[i], "tile_format", strlen("tile_format"))) { + hw_resource_->has_macrotile = true; + } else if (!strncmp(tokens[i], "src_split", strlen("src_split"))) { + hw_resource_->is_src_split = true; + } else if (!strncmp(tokens[i], "non_scalar_rgb", strlen("non_scalar_rgb"))) { + hw_resource_->has_non_scalar_rgb = true; + } else if (!strncmp(tokens[i], "perf_calc", strlen("perf_calc"))) { + hw_resource_->perf_calc = true; + } else if (!strncmp(tokens[i], "dynamic_bw_limit", strlen("dynamic_bw_limit"))) { + hw_resource_->has_dyn_bw_support = true; + } else if (!strncmp(tokens[i], "separate_rotator", strlen("separate_rotator"))) { + hw_resource_->separate_rotator = true; + } else if (!strncmp(tokens[i], "qseed3", strlen("qseed3"))) { + hw_resource_->has_qseed3 = true; + } else if (!strncmp(tokens[i], "has_ppp", strlen("has_ppp"))) { + hw_resource_->has_ppp = true; + } else if (!strncmp(tokens[i], "concurrent_writeback", strlen("concurrent_writeback"))) { + hw_resource_->has_concurrent_writeback = true; + } else if (!strncmp(tokens[i], "avr", strlen("avr"))) { + hw_resource_->has_avr = true; + } else if (!strncmp(tokens[i], "hdr", strlen("hdr"))) { + hw_resource_->has_hdr = true; + } + } + } else if (!strncmp(tokens[0], "pipe_count", strlen("pipe_count"))) { + uint32_t pipe_count = UINT8(atoi(tokens[1])); + for (uint32_t i = 0; i < pipe_count; i++) { + Sys::getline_(fs, line); + if (!ParseString(line.c_str(), tokens, max_count, ": =\n", &token_count)) { + HWPipeCaps pipe_caps; + pipe_caps.type = kPipeTypeUnused; + for (uint32_t j = 0; j < token_count; j += 2) { + if (!strncmp(tokens[j], "pipe_type", strlen("pipe_type"))) { + if (!strncmp(tokens[j+1], "vig", strlen("vig"))) { + pipe_caps.type = kPipeTypeVIG; + hw_resource_->num_vig_pipe++; + } else if (!strncmp(tokens[j+1], "rgb", strlen("rgb"))) { + pipe_caps.type = kPipeTypeRGB; + hw_resource_->num_rgb_pipe++; + } else if (!strncmp(tokens[j+1], "dma", strlen("dma"))) { + pipe_caps.type = kPipeTypeDMA; + hw_resource_->num_dma_pipe++; + } else if (!strncmp(tokens[j+1], "cursor", strlen("cursor"))) { + pipe_caps.type = kPipeTypeCursor; + hw_resource_->num_cursor_pipe++; + } + } else if (!strncmp(tokens[j], "pipe_ndx", strlen("pipe_ndx"))) { + pipe_caps.id = UINT32(atoi(tokens[j+1])); + } else if (!strncmp(tokens[j], "rects", strlen("rects"))) { + pipe_caps.max_rects = UINT32(atoi(tokens[j+1])); + } else if (!strncmp(tokens[j], "fmts_supported", strlen("fmts_supported"))) { + char *tokens_fmt[max_count] = { NULL }; + uint32_t token_fmt_count = 0; + if (!ParseString(tokens[j+1], tokens_fmt, max_count, ",\n", &token_fmt_count)) { + if (pipe_caps.type == kPipeTypeVIG) { + ParseFormats(tokens_fmt, token_fmt_count, kHWVIGPipe, hw_resource_); + } else if (pipe_caps.type == kPipeTypeRGB) { + ParseFormats(tokens_fmt, token_fmt_count, kHWRGBPipe, hw_resource_); + } else if (pipe_caps.type == kPipeTypeDMA) { + ParseFormats(tokens_fmt, token_fmt_count, kHWDMAPipe, hw_resource_); + } else if (pipe_caps.type == kPipeTypeCursor) { + ParseFormats(tokens_fmt, token_fmt_count, kHWCursorPipe, hw_resource_); + } + } + } + } + hw_resource_->hw_pipes.push_back(pipe_caps); + } + } + } + } + } + + // Disable destination scalar count to 0 if extension library is not present + DynLib extension_lib; + if (!extension_lib.Open("libsdmextension.so")) { + hw_resource_->hw_dest_scalar_info.count = 0; + } + + DLOGI("SDE Version = %d, SDE Revision = %x, RGB = %d, VIG = %d, DMA = %d, Cursor = %d", + hw_resource_->hw_version, hw_resource_->hw_revision, hw_resource_->num_rgb_pipe, + hw_resource_->num_vig_pipe, hw_resource_->num_dma_pipe, hw_resource_->num_cursor_pipe); + DLOGI("Upscale Ratio = %d, Downscale Ratio = %d, Blending Stages = %d", + hw_resource_->max_scale_up, hw_resource_->max_scale_down, + hw_resource_->num_blending_stages); + DLOGI("SourceSplit = %d QSEED3 = %d", hw_resource_->is_src_split, hw_resource_->has_qseed3); + DLOGI("BWC = %d, UBWC = %d, Decimation = %d, Tile Format = %d Concurrent Writeback = %d", + hw_resource_->has_bwc, hw_resource_->has_ubwc, hw_resource_->has_decimation, + hw_resource_->has_macrotile, hw_resource_->has_concurrent_writeback); + DLOGI("MaxLowBw = %" PRIu64 " , MaxHighBw = % " PRIu64 "", hw_resource_->max_bandwidth_low, + hw_resource_->max_bandwidth_high); + DLOGI("MaxPipeBw = %" PRIu64 " KBps, MaxSDEClock = % " PRIu64 " Hz, ClockFudgeFactor = %f", + hw_resource_->max_pipe_bw, hw_resource_->max_sde_clk, hw_resource_->clk_fudge_factor); + DLOGI("Prefill factors: Tiled_NV12 = %d, Tiled = %d, Linear = %d, Scale = %d, Fudge_factor = %d", + hw_resource_->macrotile_nv12_factor, hw_resource_->macrotile_factor, + hw_resource_->linear_factor, hw_resource_->scale_factor, hw_resource_->extra_fudge_factor); + + // Avoid rotator for MDP3 harware. + if ((hw_resource_->separate_rotator || hw_resource_->num_dma_pipe) && !hw_resource_->has_ppp) { + GetHWRotatorInfo(hw_resource_); + } + + // If the driver doesn't spell out the wb index, assume it to be the number of rotators, + // based on legacy implementation. + if (hw_resource_->writeback_index == kHWBlockMax) { + hw_resource_->writeback_index = hw_resource_->hw_rot_info.num_rotator; + } + + if (hw_resource_->has_dyn_bw_support) { + DisplayError ret = GetDynamicBWLimits(hw_resource_); + if (ret != kErrorNone) { + DLOGE("Failed to read dynamic band width info"); + return ret; + } + + DLOGI("Has Support for multiple bw limits shown below"); + for (int index = 0; index < kBwModeMax; index++) { + DLOGI("Mode-index=%d total_bw_limit=%d and pipe_bw_limit=%d", + index, hw_resource_->dyn_bw_info.total_bw_limit[index], + hw_resource_->dyn_bw_info.pipe_bw_limit[index]); + } + } + + *hw_resource = *hw_resource_; + + return kErrorNone; +} + +DisplayError HWInfo::GetHWRotatorInfo(HWResourceInfo *hw_resource) { + if (GetMDSSRotatorInfo(hw_resource) != kErrorNone) + return GetV4L2RotatorInfo(hw_resource); + + return kErrorNone; +} + +DisplayError HWInfo::GetMDSSRotatorInfo(HWResourceInfo *hw_resource) { + Sys::fstream fs(kRotatorCapsPath, fstream::in); + if (!fs.is_open()) { + DLOGW("File '%s' not found", kRotatorCapsPath); + return kErrorNotSupported; + } + + uint32_t token_count = 0; + const uint32_t max_count = 10; + char *tokens[max_count] = { NULL }; + string line; + + hw_resource->hw_rot_info.type = HWRotatorInfo::ROT_TYPE_MDSS; + while (Sys::getline_(fs, line)) { + if (!ParseString(line.c_str(), tokens, max_count, ":, =\n", &token_count)) { + if (!strncmp(tokens[0], "wb_count", strlen("wb_count"))) { + hw_resource->hw_rot_info.num_rotator = UINT8(atoi(tokens[1])); + hw_resource->hw_rot_info.device_path = "/dev/mdss_rotator"; + } else if (!strncmp(tokens[0], "downscale", strlen("downscale"))) { + hw_resource->hw_rot_info.has_downscale = UINT8(atoi(tokens[1])); + } + } + } + + DLOGI("MDSS Rotator: Count = %d, Downscale = %d, Min_downscale = %f", + hw_resource->hw_rot_info.num_rotator, hw_resource->hw_rot_info.has_downscale, + hw_resource->hw_rot_info.min_downscale); + + return kErrorNone; +} + +DisplayError HWInfo::GetV4L2RotatorInfo(HWResourceInfo *hw_resource) { + string v4l2_path = "/sys/class/video4linux/video"; + const uint32_t kMaxV4L2Nodes = 64; + bool found = false; + + for (uint32_t i = 0; (i < kMaxV4L2Nodes) && (false == found); i++) { + string path = v4l2_path + to_string(i) + "/name"; + Sys::fstream fs(path, fstream::in); + if (!fs.is_open()) { + continue; + } + + string line; + if (Sys::getline_(fs, line) && + (!strncmp(line.c_str(), "sde_rotator", strlen("sde_rotator")))) { + hw_resource->hw_rot_info.device_path = string("/dev/video" + to_string(i)); + hw_resource->hw_rot_info.num_rotator++; + hw_resource->hw_rot_info.type = HWRotatorInfo::ROT_TYPE_V4L2; + hw_resource->hw_rot_info.has_downscale = true; + + string caps_path = v4l2_path + to_string(i) + "/device/caps"; + Sys::fstream caps_fs(caps_path, fstream::in); + + if (caps_fs.is_open()) { + uint32_t token_count = 0; + const uint32_t max_count = 10; + char *tokens[max_count] = { NULL }; + string caps; + while (Sys::getline_(caps_fs, caps)) { + if (!ParseString(caps.c_str(), tokens, max_count, ":, =\n", &token_count)) { + if (!strncmp(tokens[0], "downscale_compression", strlen("downscale_compression"))) { + hw_resource->hw_rot_info.downscale_compression = UINT8(atoi(tokens[1])); + } else if (!strncmp(tokens[0], "min_downscale", strlen("min_downscale"))) { + hw_resource->hw_rot_info.min_downscale = FLOAT(atof(tokens[1])); + } + } + } + } + + // We support only 1 rotator + found = true; + } + } + + DLOGI("V4L2 Rotator: Count = %d, Downscale = %d, Min_downscale = %f, Downscale_compression = %d", + hw_resource->hw_rot_info.num_rotator, hw_resource->hw_rot_info.has_downscale, + hw_resource->hw_rot_info.min_downscale, hw_resource->hw_rot_info.downscale_compression); + + return kErrorNone; +} + +LayerBufferFormat HWInfo::GetSDMFormat(int mdp_format) { + switch (mdp_format) { + case MDP_ARGB_8888: return kFormatARGB8888; + case MDP_RGBA_8888: return kFormatRGBA8888; + case MDP_BGRA_8888: return kFormatBGRA8888; + case MDP_XRGB_8888: return kFormatXRGB8888; + case MDP_RGBX_8888: return kFormatRGBX8888; + case MDP_BGRX_8888: return kFormatBGRX8888; + case MDP_RGBA_5551: return kFormatRGBA5551; + case MDP_RGBA_4444: return kFormatRGBA4444; + case MDP_RGB_888: return kFormatRGB888; + case MDP_BGR_888: return kFormatBGR888; + case MDP_RGB_565: return kFormatRGB565; + case MDP_BGR_565: return kFormatBGR565; + case MDP_RGBA_8888_UBWC: return kFormatRGBA8888Ubwc; + case MDP_RGBX_8888_UBWC: return kFormatRGBX8888Ubwc; + case MDP_RGB_565_UBWC: return kFormatBGR565Ubwc; + case MDP_Y_CB_CR_H2V2: return kFormatYCbCr420Planar; + case MDP_Y_CR_CB_H2V2: return kFormatYCrCb420Planar; + case MDP_Y_CR_CB_GH2V2: return kFormatYCrCb420PlanarStride16; + case MDP_Y_CBCR_H2V2: return kFormatYCbCr420SemiPlanar; + case MDP_Y_CRCB_H2V2: return kFormatYCrCb420SemiPlanar; + case MDP_Y_CBCR_H2V2_VENUS: return kFormatYCbCr420SemiPlanarVenus; + case MDP_Y_CBCR_H1V2: return kFormatYCbCr422H1V2SemiPlanar; + case MDP_Y_CRCB_H1V2: return kFormatYCrCb422H1V2SemiPlanar; + case MDP_Y_CBCR_H2V1: return kFormatYCbCr422H2V1SemiPlanar; + case MDP_Y_CRCB_H2V1: return kFormatYCrCb422H2V1SemiPlanar; + case MDP_Y_CBCR_H2V2_UBWC: return kFormatYCbCr420SPVenusUbwc; + case MDP_Y_CRCB_H2V2_VENUS: return kFormatYCrCb420SemiPlanarVenus; + case MDP_YCBYCR_H2V1: return kFormatYCbCr422H2V1Packed; + case MDP_RGBA_1010102: return kFormatRGBA1010102; + case MDP_ARGB_2101010: return kFormatARGB2101010; + case MDP_RGBX_1010102: return kFormatRGBX1010102; + case MDP_XRGB_2101010: return kFormatXRGB2101010; + case MDP_BGRA_1010102: return kFormatBGRA1010102; + case MDP_ABGR_2101010: return kFormatABGR2101010; + case MDP_BGRX_1010102: return kFormatBGRX1010102; + case MDP_XBGR_2101010: return kFormatXBGR2101010; + case MDP_RGBA_1010102_UBWC: return kFormatRGBA1010102Ubwc; + case MDP_RGBX_1010102_UBWC: return kFormatRGBX1010102Ubwc; + case MDP_Y_CBCR_H2V2_P010: return kFormatYCbCr420P010; + case MDP_Y_CBCR_H2V2_TP10_UBWC: return kFormatYCbCr420TP10Ubwc; + default: return kFormatInvalid; + } +} + +void HWInfo::InitSupportedFormatMap(HWResourceInfo *hw_resource) { + hw_resource->supported_formats_map.clear(); + + for (int sub_blk_type = INT(kHWVIGPipe); sub_blk_type < INT(kHWSubBlockMax); sub_blk_type++) { + PopulateSupportedFormatMap(kDefaultFormatSupport[sub_blk_type], MDP_IMGTYPE_LIMIT1, + (HWSubBlockType)sub_blk_type, hw_resource); + } +} + +void HWInfo::ParseFormats(char *tokens[], uint32_t token_count, HWSubBlockType sub_blk_type, + HWResourceInfo *hw_resource) { + if (token_count > BITS_TO_BYTES(MDP_IMGTYPE_LIMIT1)) { + return; + } + + std::unique_ptr<std::bitset<8>[]> format_supported(new std::bitset<8>[token_count]); + for (uint32_t i = 0; i < token_count; i++) { + format_supported[i] = UINT8(atoi(tokens[i])); + } + + PopulateSupportedFormatMap(format_supported.get(), (token_count << 3), sub_blk_type, hw_resource); +} + +void HWInfo::PopulateSupportedFormatMap(const std::bitset<8> *format_supported, + uint32_t format_count, HWSubBlockType sub_blk_type, + HWResourceInfo *hw_resource) { + vector <LayerBufferFormat> supported_sdm_formats; + for (uint32_t mdp_format = 0; mdp_format < format_count; mdp_format++) { + if (format_supported[mdp_format >> 3][mdp_format & 7]) { + LayerBufferFormat sdm_format = GetSDMFormat(INT(mdp_format)); + if (sdm_format != kFormatInvalid) { + supported_sdm_formats.push_back(sdm_format); + } + } + } + + hw_resource->supported_formats_map.erase(sub_blk_type); + hw_resource->supported_formats_map.insert(make_pair(sub_blk_type, supported_sdm_formats)); +} + +DisplayError HWInfo::GetFirstDisplayInterfaceType(HWDisplayInterfaceInfo *hw_disp_info) { + Sys::fstream fs("/sys/devices/virtual/graphics/fb0/msm_fb_type", fstream::in); + if (!fs.is_open()) { + return kErrorHardware; + } + + string line; + if (!Sys::getline_(fs, line)) { + return kErrorHardware; + } + + if (!strncmp(line.c_str(), "dtv panel", strlen("dtv panel")) || + !strncmp(line.c_str(), "dp panel", strlen("dp panel"))) { + hw_disp_info->type = kHDMI; + DLOGI("First display is HDMI"); + } else { + hw_disp_info->type = kPrimary; + DLOGI("First display is internal display"); + } + + fs.close(); + fs.open("/sys/devices/virtual/graphics/fb0/connected", fstream::in); + if (!fs.is_open()) { + // If fb0 is for a DSI/connected panel, then connected node will not exist. + hw_disp_info->is_connected = true; + } else { + if (!Sys::getline_(fs, line)) { + return kErrorHardware; + } + + hw_disp_info->is_connected = (!strncmp(line.c_str(), "1", strlen("1"))); + } + + return kErrorNone; +} + +} // namespace sdm + diff --git a/msm8909/sdm/libs/core/fb/hw_info.h b/msm8909/sdm/libs/core/fb/hw_info.h new file mode 100644 index 00000000..cbceba06 --- /dev/null +++ b/msm8909/sdm/libs/core/fb/hw_info.h @@ -0,0 +1,81 @@ +/* +* Copyright (c) 2015 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __HW_INFO_H__ +#define __HW_INFO_H__ + +#include <core/sdm_types.h> +#include <core/core_interface.h> +#include <private/hw_info_types.h> +#include <linux/msm_mdp.h> +#include <bitset> + +#include "hw_info_interface.h" + +#ifndef MDP_IMGTYPE_END +#define MDP_IMGTYPE_LIMIT1 0x100 +#endif + +namespace sdm { + +class HWInfo: public HWInfoInterface { + public: + virtual ~HWInfo() { delete hw_resource_; } + virtual DisplayError GetHWResourceInfo(HWResourceInfo *hw_resource); + virtual DisplayError GetFirstDisplayInterfaceType(HWDisplayInterfaceInfo *hw_disp_info); + + private: + virtual DisplayError GetHWRotatorInfo(HWResourceInfo *hw_resource); + virtual DisplayError GetMDSSRotatorInfo(HWResourceInfo *hw_resource); + virtual DisplayError GetV4L2RotatorInfo(HWResourceInfo *hw_resource); + + // TODO(user): Read Mdss version from the driver + static const int kHWMdssVersion5 = 500; // MDSS_V5 + static const int kMaxStringLength = 1024; + // MDP Capabilities are replicated across all frame buffer devices. + // However, we rely on reading the capabalities from fbO since this + // is guaranteed to be available. + static const int kHWCapabilitiesNode = 0; + static const std::bitset<8> kDefaultFormatSupport[kHWSubBlockMax][ + BITS_TO_BYTES(MDP_IMGTYPE_LIMIT1)]; + static constexpr const char *kRotatorCapsPath = "/sys/devices/virtual/rotator/mdss_rotator/caps"; + static constexpr const char *kBWModeBitmap + = "/sys/devices/virtual/graphics/fb0/mdp/bw_mode_bitmap"; + + static int ParseString(const char *input, char *tokens[], const uint32_t max_token, + const char *delim, uint32_t *count); + DisplayError GetDynamicBWLimits(HWResourceInfo *hw_resource); + LayerBufferFormat GetSDMFormat(int mdp_format); + void InitSupportedFormatMap(HWResourceInfo *hw_resource); + void ParseFormats(char *tokens[], uint32_t token_count, HWSubBlockType sub_block_type, + HWResourceInfo *hw_resource); + void PopulateSupportedFormatMap(const std::bitset<8> *format_supported, uint32_t format_count, + HWSubBlockType sub_blk_type, HWResourceInfo *hw_resource); + HWResourceInfo *hw_resource_ = NULL; +}; + +} // namespace sdm + +#endif // __HW_INFO_H__ + diff --git a/msm8909/sdm/libs/core/fb/hw_primary.cpp b/msm8909/sdm/libs/core/fb/hw_primary.cpp new file mode 100644 index 00000000..60a658b4 --- /dev/null +++ b/msm8909/sdm/libs/core/fb/hw_primary.cpp @@ -0,0 +1,687 @@ +/* +* Copyright (c) 2015 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <pthread.h> +#include <fcntl.h> +#include <sys/prctl.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <utils/debug.h> +#include <utils/sys.h> +#include <core/display_interface.h> +#include <linux/msm_mdp_ext.h> +#include <utils/rect.h> + +#include <string> + +#include "hw_primary.h" +#include "hw_color_manager.h" + +#define __CLASS__ "HWPrimary" + +#ifndef MDP_COMMIT_CWB_EN +#define MDP_COMMIT_CWB_EN 0x800 +#endif + +#ifndef MDP_COMMIT_CWB_DSPP +#define MDP_COMMIT_CWB_DSPP 0x1000 +#endif + +#ifndef MDP_COMMIT_AVR_EN +#define MDP_COMMIT_AVR_EN 0x08 +#endif + +#ifndef MDP_COMMIT_AVR_ONE_SHOT_MODE +#define MDP_COMMIT_AVR_ONE_SHOT_MODE 0x10 +#endif + +#ifndef MDP_COMMIT_PARTIAL_UPDATE_DUAL_ROI +#define MDP_COMMIT_PARTIAL_UPDATE_DUAL_ROI 0x20 +#endif + +namespace sdm { + +using std::string; +using std::to_string; +using std::fstream; + +HWPrimary::HWPrimary(BufferSyncHandler *buffer_sync_handler, HWInfoInterface *hw_info_intf) + : HWDevice(buffer_sync_handler) { + HWDevice::device_type_ = kDevicePrimary; + HWDevice::device_name_ = "Primary Display Device"; + HWDevice::hw_info_intf_ = hw_info_intf; +} + +DisplayError HWPrimary::Init() { + DisplayError error = kErrorNone; + + error = HWDevice::Init(); + if (error != kErrorNone) { + return error; + } + + mdp_dest_scalar_data_.resize(hw_resource_.hw_dest_scalar_info.count); + + error = PopulateDisplayAttributes(); + if (error != kErrorNone) { + return error; + } + + UpdateMixerAttributes(); + + // Need to enable HPD, but toggle at start when HDMI is external + // This helps for framework reboot or adb shell stop/start + EnableHotPlugDetection(0); + EnableHotPlugDetection(1); + InitializeConfigs(); + + avr_prop_disabled_ = Debug::IsAVRDisabled(); + + return error; +} + +bool HWPrimary::GetCurrentModeFromSysfs(size_t *curr_x_pixels, size_t *curr_y_pixels) { + bool ret = false; + string mode_path = fb_path_ + string("0/mode"); + + Sys::fstream fs(mode_path, fstream::in); + if (!fs.is_open()) { + return false; + } + + string line; + if (Sys::getline_(fs, line)) { + // String is of form "U:1600x2560p-0". Documentation/fb/modedb.txt in + // kernel has more info on the format. + size_t xpos = line.find(':'); + size_t ypos = line.find('x'); + + if (xpos == string::npos || ypos == string::npos) { + DLOGI("Resolution switch not supported"); + } else { + *curr_x_pixels = static_cast<size_t>(atoi(line.c_str() + xpos + 1)); + *curr_y_pixels = static_cast<size_t>(atoi(line.c_str() + ypos + 1)); + DLOGI("Current Config: %u x %u", *curr_x_pixels, *curr_y_pixels); + ret = true; + } + } + + return ret; +} + +void HWPrimary::InitializeConfigs() { + size_t curr_x_pixels = 0; + size_t curr_y_pixels = 0; + + if (!GetCurrentModeFromSysfs(&curr_x_pixels, &curr_y_pixels)) { + return; + } + + string modes_path = string(fb_path_) + string("0/modes"); + + Sys::fstream fs(modes_path, fstream::in); + if (!fs.is_open()) { + DLOGI("Unable to process modes"); + return; + } + + string line; + while (Sys::getline_(fs, line)) { + DisplayConfigVariableInfo config; + // std::getline (unlike ::getline) removes \n while driver expects it in mode, so add back + line += '\n'; + size_t xpos = line.find(':'); + size_t ypos = line.find('x'); + + if (xpos == string::npos || ypos == string::npos) { + continue; + } + + config.x_pixels = UINT32(atoi(line.c_str() + xpos + 1)); + config.y_pixels = UINT32(atoi(line.c_str() + ypos + 1)); + DLOGI("Found mode %d x %d", config.x_pixels, config.y_pixels); + display_configs_.push_back(config); + display_config_strings_.push_back(string(line.c_str())); + + if (curr_x_pixels == config.x_pixels && curr_y_pixels == config.y_pixels) { + active_config_index_ = UINT32(display_configs_.size() - 1); + DLOGI("Active config index %u", active_config_index_); + } + } +} + +DisplayError HWPrimary::GetNumDisplayAttributes(uint32_t *count) { + *count = IsResolutionSwitchEnabled() ? UINT32(display_configs_.size()) : 1; + return kErrorNone; +} + +DisplayError HWPrimary::GetActiveConfig(uint32_t *active_config_index) { + *active_config_index = active_config_index_; + return kErrorNone; +} + +DisplayError HWPrimary::GetDisplayAttributes(uint32_t index, + HWDisplayAttributes *display_attributes) { + if (!display_attributes) { + return kErrorParameters; + } + + if (IsResolutionSwitchEnabled() && index >= display_configs_.size()) { + return kErrorParameters; + } + + *display_attributes = display_attributes_; + if (IsResolutionSwitchEnabled()) { + // Overwrite only the parent portion of object + display_attributes->x_pixels = display_configs_.at(index).x_pixels; + display_attributes->y_pixels = display_configs_.at(index).y_pixels; + } + + return kErrorNone; +} + +DisplayError HWPrimary::PopulateDisplayAttributes() { + DTRACE_SCOPED(); + + // Variable screen info + fb_var_screeninfo var_screeninfo = {}; + + if (Sys::ioctl_(device_fd_, FBIOGET_VSCREENINFO, &var_screeninfo) < 0) { + IOCTL_LOGE(FBIOGET_VSCREENINFO, device_type_); + return kErrorHardware; + } + + // Frame rate + msmfb_metadata meta_data = {}; + meta_data.op = metadata_op_frame_rate; + if (Sys::ioctl_(device_fd_, MSMFB_METADATA_GET, &meta_data) < 0) { + IOCTL_LOGE(MSMFB_METADATA_GET, device_type_); + return kErrorHardware; + } + + // If driver doesn't return width/height information, default to 320 dpi + if (INT(var_screeninfo.width) <= 0 || INT(var_screeninfo.height) <= 0) { + var_screeninfo.width = UINT32(((FLOAT(var_screeninfo.xres) * 25.4f)/320.0f) + 0.5f); + var_screeninfo.height = UINT32(((FLOAT(var_screeninfo.yres) * 25.4f)/320.0f) + 0.5f); + DLOGW("Driver doesn't report panel physical width and height - defaulting to 320dpi"); + } + + display_attributes_.x_pixels = var_screeninfo.xres; + display_attributes_.y_pixels = var_screeninfo.yres; + display_attributes_.v_front_porch = var_screeninfo.lower_margin; + display_attributes_.v_back_porch = var_screeninfo.upper_margin; + display_attributes_.v_pulse_width = var_screeninfo.vsync_len; + uint32_t h_blanking = var_screeninfo.right_margin + var_screeninfo.left_margin + + var_screeninfo.hsync_len; + display_attributes_.h_total = var_screeninfo.xres + h_blanking; + display_attributes_.x_dpi = + (FLOAT(var_screeninfo.xres) * 25.4f) / FLOAT(var_screeninfo.width); + display_attributes_.y_dpi = + (FLOAT(var_screeninfo.yres) * 25.4f) / FLOAT(var_screeninfo.height); + display_attributes_.fps = meta_data.data.panel_frame_rate; + display_attributes_.vsync_period_ns = UINT32(1000000000L / display_attributes_.fps); + display_attributes_.is_device_split = (hw_panel_info_.split_info.right_split || + (var_screeninfo.xres > hw_resource_.max_mixer_width)); + display_attributes_.h_total += (display_attributes_.is_device_split || + hw_panel_info_.ping_pong_split)? h_blanking : 0; + + return kErrorNone; +} + +DisplayError HWPrimary::SetDisplayAttributes(uint32_t index) { + DisplayError ret = kErrorNone; + + if (!IsResolutionSwitchEnabled()) { + return kErrorNotSupported; + } + + if (index >= display_configs_.size()) { + return kErrorParameters; + } + + string mode_path = string(fb_path_) + string("0/mode"); + int fd = Sys::open_(mode_path.c_str(), O_WRONLY); + + if (fd < 0) { + DLOGE("Opening mode failed"); + return kErrorNotSupported; + } + + ssize_t written = Sys::pwrite_(fd, display_config_strings_.at(index).c_str(), + display_config_strings_.at(index).length(), 0); + if (written > 0) { + DLOGI("Successfully set config %u", index); + PopulateHWPanelInfo(); + PopulateDisplayAttributes(); + UpdateMixerAttributes(); + active_config_index_ = index; + } else { + DLOGE("Writing config index %u failed with error: %s", index, strerror(errno)); + ret = kErrorParameters; + } + + Sys::close_(fd); + + return ret; +} + +DisplayError HWPrimary::SetRefreshRate(uint32_t refresh_rate) { + char node_path[kMaxStringLength] = {0}; + + if (hw_resource_.has_avr && !avr_prop_disabled_) { + return kErrorNotSupported; + } + + snprintf(node_path, sizeof(node_path), "%s%d/dynamic_fps", fb_path_, fb_node_index_); + + int fd = Sys::open_(node_path, O_WRONLY); + if (fd < 0) { + DLOGE("Failed to open %s with error %s", node_path, strerror(errno)); + return kErrorFileDescriptor; + } + + char refresh_rate_string[kMaxStringLength]; + snprintf(refresh_rate_string, sizeof(refresh_rate_string), "%d", refresh_rate); + DLOGI_IF(kTagDriverConfig, "Setting refresh rate = %d", refresh_rate); + ssize_t len = Sys::pwrite_(fd, refresh_rate_string, strlen(refresh_rate_string), 0); + if (len < 0) { + DLOGE("Failed to write %d with error %s", refresh_rate, strerror(errno)); + Sys::close_(fd); + return kErrorUndefined; + } + Sys::close_(fd); + + DisplayError error = PopulateDisplayAttributes(); + if (error != kErrorNone) { + return error; + } + + return kErrorNone; +} + +DisplayError HWPrimary::GetConfigIndex(uint32_t mode, uint32_t *index) { + return HWDevice::GetConfigIndex(mode, index); +} + +DisplayError HWPrimary::PowerOff() { + if (Sys::ioctl_(device_fd_, FBIOBLANK, FB_BLANK_POWERDOWN) < 0) { + IOCTL_LOGE(FB_BLANK_POWERDOWN, device_type_); + return kErrorHardware; + } + + auto_refresh_ = false; + + return kErrorNone; +} + +DisplayError HWPrimary::Doze() { + if (Sys::ioctl_(device_fd_, FBIOBLANK, FB_BLANK_NORMAL) < 0) { + IOCTL_LOGE(FB_BLANK_NORMAL, device_type_); + return kErrorHardware; + } + + return kErrorNone; +} + +DisplayError HWPrimary::DozeSuspend() { + if (Sys::ioctl_(device_fd_, FBIOBLANK, FB_BLANK_VSYNC_SUSPEND) < 0) { + IOCTL_LOGE(FB_BLANK_VSYNC_SUSPEND, device_type_); + return kErrorHardware; + } + + return kErrorNone; +} + +DisplayError HWPrimary::Validate(HWLayers *hw_layers) { + HWLayersInfo &hw_layer_info = hw_layers->info; + LayerStack *stack = hw_layer_info.stack; + + HWDevice::ResetDisplayParams(); + + mdp_layer_commit_v1 &mdp_commit = mdp_disp_commit_.commit_v1; + + LayerRect left_roi = hw_layer_info.left_frame_roi.at(0); + LayerRect right_roi = hw_layer_info.right_frame_roi.at(0); + + mdp_commit.left_roi.x = UINT32(left_roi.left); + mdp_commit.left_roi.y = UINT32(left_roi.top); + mdp_commit.left_roi.w = UINT32(left_roi.right - left_roi.left); + mdp_commit.left_roi.h = UINT32(left_roi.bottom - left_roi.top); + + // Update second roi information in right_roi + if (hw_layer_info.left_frame_roi.size() == 2) { + mdp_commit.flags |= MDP_COMMIT_PARTIAL_UPDATE_DUAL_ROI; + right_roi = hw_layer_info.left_frame_roi.at(1); + } + + // SDM treats ROI as one full coordinate system. + // In case source split is disabled, However, Driver assumes Mixer to operate in + // different co-ordinate system. + if (IsValid(right_roi)) { + mdp_commit.right_roi.x = UINT32(right_roi.left); + if (!hw_resource_.is_src_split) { + mdp_commit.right_roi.x = UINT32(right_roi.left) - mixer_attributes_.split_left; + } + mdp_commit.right_roi.y = UINT32(right_roi.top); + mdp_commit.right_roi.w = UINT32(right_roi.right - right_roi.left); + mdp_commit.right_roi.h = UINT32(right_roi.bottom - right_roi.top); + } + + if (stack->output_buffer && hw_resource_.has_concurrent_writeback) { + LayerBuffer *output_buffer = stack->output_buffer; + mdp_out_layer_.writeback_ndx = hw_resource_.writeback_index; + mdp_out_layer_.buffer.width = output_buffer->unaligned_width; + mdp_out_layer_.buffer.height = output_buffer->unaligned_height; + mdp_out_layer_.buffer.comp_ratio.denom = 1000; + mdp_out_layer_.buffer.comp_ratio.numer = UINT32(hw_layers->output_compression * 1000); + mdp_out_layer_.buffer.fence = -1; +#ifdef OUT_LAYER_COLOR_SPACE + SetCSC(output_buffer->color_metadata, &mdp_out_layer_.color_space); +#endif + SetFormat(output_buffer->format, &mdp_out_layer_.buffer.format); + mdp_commit.flags |= MDP_COMMIT_CWB_EN; + mdp_commit.flags |= (stack->flags.post_processed_output) ? MDP_COMMIT_CWB_DSPP : 0; + DLOGI_IF(kTagDriverConfig, "****************** Conc WB Output buffer Info ******************"); + DLOGI_IF(kTagDriverConfig, "out_w %d, out_h %d, out_f %d, wb_id %d DSPP output %d", + mdp_out_layer_.buffer.width, mdp_out_layer_.buffer.height, + mdp_out_layer_.buffer.format, mdp_out_layer_.writeback_ndx, + stack->flags.post_processed_output); + DLOGI_IF(kTagDriverConfig, "****************************************************************"); + } + + if (hw_resource_.has_avr) { + SetAVRFlags(hw_layers->hw_avr_info, &mdp_commit.flags); + } + + return HWDevice::Validate(hw_layers); +} + +DisplayError HWPrimary::Commit(HWLayers *hw_layers) { + LayerBuffer *output_buffer = hw_layers->info.stack->output_buffer; + + if (hw_resource_.has_concurrent_writeback && output_buffer) { + if (output_buffer->planes[0].fd >= 0) { + mdp_out_layer_.buffer.planes[0].fd = output_buffer->planes[0].fd; + mdp_out_layer_.buffer.planes[0].offset = output_buffer->planes[0].offset; + SetStride(device_type_, output_buffer->format, output_buffer->planes[0].stride, + &mdp_out_layer_.buffer.planes[0].stride); + mdp_out_layer_.buffer.plane_count = 1; + mdp_out_layer_.buffer.fence = -1; + + DLOGI_IF(kTagDriverConfig, "****************** Conc WB Output buffer Info ****************"); + DLOGI_IF(kTagDriverConfig, "out_fd %d, out_offset %d, out_stride %d", + mdp_out_layer_.buffer.planes[0].fd, mdp_out_layer_.buffer.planes[0].offset, + mdp_out_layer_.buffer.planes[0].stride); + DLOGI_IF(kTagDriverConfig, "**************************************************************"); + } else { + DLOGE("Invalid output buffer fd"); + return kErrorParameters; + } + } + + DisplayError ret = HWDevice::Commit(hw_layers); + + if (ret == kErrorNone && hw_resource_.has_concurrent_writeback && output_buffer) { + output_buffer->release_fence_fd = mdp_out_layer_.buffer.fence; + } + + return ret; +} + +void HWPrimary::SetIdleTimeoutMs(uint32_t timeout_ms) { + char node_path[kMaxStringLength] = {0}; + + DLOGI_IF(kTagDriverConfig, "Setting idle timeout to = %d ms", timeout_ms); + + snprintf(node_path, sizeof(node_path), "%s%d/idle_time", fb_path_, fb_node_index_); + + // Open a sysfs node to send the timeout value to driver. + int fd = Sys::open_(node_path, O_WRONLY); + if (fd < 0) { + DLOGE("Unable to open %s, node %s", node_path, strerror(errno)); + return; + } + + char timeout_string[64]; + snprintf(timeout_string, sizeof(timeout_string), "%d", timeout_ms); + + // Notify driver about the timeout value + ssize_t length = Sys::pwrite_(fd, timeout_string, strlen(timeout_string), 0); + if (length <= 0) { + DLOGE("Unable to write into %s, node %s", node_path, strerror(errno)); + } + + Sys::close_(fd); +} + +DisplayError HWPrimary::SetVSyncState(bool enable) { + DTRACE_SCOPED(); + return HWDevice::SetVSyncState(enable); +} + +DisplayError HWPrimary::SetDisplayMode(const HWDisplayMode hw_display_mode) { + uint32_t mode = kModeDefault; + + switch (hw_display_mode) { + case kModeVideo: + mode = kModeLPMVideo; + break; + case kModeCommand: + mode = kModeLPMCommand; + break; + default: + DLOGW("Failed to translate SDE display mode %d to a MSMFB_LPM_ENABLE mode", + hw_display_mode); + return kErrorParameters; + } + + if (Sys::ioctl_(device_fd_, INT(MSMFB_LPM_ENABLE), &mode) < 0) { + IOCTL_LOGE(MSMFB_LPM_ENABLE, device_type_); + return kErrorHardware; + } + + DLOGI("Triggering display mode change to %d on next commit.", hw_display_mode); + synchronous_commit_ = true; + + return kErrorNone; +} + +DisplayError HWPrimary::SetPanelBrightness(int level) { + char buffer[kMaxSysfsCommandLength] = {0}; + + DLOGV_IF(kTagDriverConfig, "Set brightness level to %d", level); + int fd = Sys::open_(kBrightnessNode, O_RDWR); + if (fd < 0) { + DLOGV_IF(kTagDriverConfig, "Failed to open node = %s, error = %s ", kBrightnessNode, + strerror(errno)); + return kErrorFileDescriptor; + } + + int32_t bytes = snprintf(buffer, kMaxSysfsCommandLength, "%d\n", level); + if (bytes < 0) { + DLOGV_IF(kTagDriverConfig, "Failed to copy new brightness level = %d", level); + Sys::close_(fd); + return kErrorUndefined; + } + + ssize_t ret = Sys::pwrite_(fd, buffer, static_cast<size_t>(bytes), 0); + if (ret <= 0) { + DLOGV_IF(kTagDriverConfig, "Failed to write to node = %s, error = %s ", kBrightnessNode, + strerror(errno)); + Sys::close_(fd); + return kErrorUndefined; + } + Sys::close_(fd); + + return kErrorNone; +} + +DisplayError HWPrimary::GetPanelBrightness(int *level) { + char brightness[kMaxStringLength] = {0}; + + if (!level) { + DLOGV_IF(kTagDriverConfig, "Invalid input, null pointer."); + return kErrorParameters; + } + + int fd = Sys::open_(kBrightnessNode, O_RDWR); + if (fd < 0) { + DLOGV_IF(kTagDriverConfig, "Failed to open brightness node = %s, error = %s", kBrightnessNode, + strerror(errno)); + return kErrorFileDescriptor; + } + + if (Sys::pread_(fd, brightness, sizeof(brightness), 0) > 0) { + *level = atoi(brightness); + DLOGV_IF(kTagDriverConfig, "Brightness level = %d", *level); + } + Sys::close_(fd); + + return kErrorNone; +} + +DisplayError HWPrimary::CachePanelBrightness(int level) { + bl_level_update_commit = level; + bl_update_commit = true; + return kErrorNone; +} + +DisplayError HWPrimary::SetAutoRefresh(bool enable) { + const int kWriteLength = 2; + char buffer[kWriteLength] = {'\0'}; + ssize_t bytes = snprintf(buffer, kWriteLength, "%d", enable); + + if (enable == auto_refresh_) { + return kErrorNone; + } + + if (HWDevice::SysFsWrite(kAutoRefreshNode, buffer, bytes) <= 0) { // Returns bytes written + return kErrorUndefined; + } + + auto_refresh_ = enable; + + return kErrorNone; +} + +DisplayError HWPrimary::GetPPFeaturesVersion(PPFeatureVersion *vers) { + mdp_pp_feature_version version = {}; + +#ifdef PA_DITHER + uint32_t feature_id_mapping[kMaxNumPPFeatures] = { PCC, IGC, GC, GC, PA, + DITHER, GAMUT, PA_DITHER }; +#else + uint32_t feature_id_mapping[kMaxNumPPFeatures] = { PCC, IGC, GC, GC, PA, DITHER, GAMUT }; +#endif + + if (hw_resource_.hw_version != kHWMdssVersion3) { + // Do not query kGlobalColorFeatureCsc for kHWMdssVersion5 + for (int i(0); i < (kMaxNumPPFeatures - 1); i++) { + version.pp_feature = feature_id_mapping[i]; + + if (Sys::ioctl_(device_fd_, INT(MSMFB_MDP_PP_GET_FEATURE_VERSION), &version) < 0) { + IOCTL_LOGE(MSMFB_MDP_PP_GET_FEATURE_VERSION, device_type_); + return kErrorHardware; + } + vers->version[i] = version.version_info; + } + } else { + for (int i(0); i < kMaxNumPPFeatures; i++) { + version.pp_feature = feature_id_mapping[i]; + vers->version[i] = mdp_pp_legacy; + } + } + + return kErrorNone; +} + +// It was entered with PPFeaturesConfig::locker_ being hold. +DisplayError HWPrimary::SetPPFeatures(PPFeaturesConfig *feature_list) { + msmfb_mdp_pp kernel_params = {}; + int ret = 0; + PPFeatureInfo *feature = NULL; + + while (true) { + ret = feature_list->RetrieveNextFeature(&feature); + if (ret) + break; + + if (feature) { + DLOGV_IF(kTagDriverConfig, "feature_id = %d", feature->feature_id_); + + if ((feature->feature_id_ < kMaxNumPPFeatures)) { + HWColorManager::SetFeature[feature->feature_id_](*feature, &kernel_params); + if (Sys::ioctl_(device_fd_, INT(MSMFB_MDP_PP), &kernel_params) < 0) { + IOCTL_LOGE(MSMFB_MDP_PP, device_type_); + + feature_list->Reset(); + return kErrorHardware; + } + } + } + } // while(true) + + // Once all features were consumed, then destroy all feature instance from feature_list, + // Then mark it as non-dirty of PPFeaturesConfig cache. + feature_list->Reset(); + + return kErrorNone; +} + +DisplayError HWPrimary::SetMixerAttributes(const HWMixerAttributes &mixer_attributes) { + if (IsResolutionSwitchEnabled()) { + return kErrorNotSupported; + } + + return HWDevice::SetMixerAttributes(mixer_attributes); +} + +void HWPrimary::UpdateMixerAttributes() { + mixer_attributes_.width = display_attributes_.x_pixels; + mixer_attributes_.height = display_attributes_.y_pixels; + mixer_attributes_.split_left = display_attributes_.is_device_split ? + hw_panel_info_.split_info.left_split : mixer_attributes_.width; +} + +void HWPrimary::SetAVRFlags(const HWAVRInfo &hw_avr_info, uint32_t *avr_flags) { + if (hw_avr_info.enable) { + *avr_flags |= MDP_COMMIT_AVR_EN; + } + + if (hw_avr_info.mode == kOneShotMode) { + *avr_flags |= MDP_COMMIT_AVR_ONE_SHOT_MODE; + } +} + +} // namespace sdm + diff --git a/msm8909/sdm/libs/core/fb/hw_primary.h b/msm8909/sdm/libs/core/fb/hw_primary.h new file mode 100644 index 00000000..a8251456 --- /dev/null +++ b/msm8909/sdm/libs/core/fb/hw_primary.h @@ -0,0 +1,96 @@ +/* +* 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. +*/ + +#ifndef __HW_PRIMARY_H__ +#define __HW_PRIMARY_H__ + +#include <sys/poll.h> +#include <vector> +#include <string> + +#include "hw_device.h" + +namespace sdm { + +class HWPrimary : public HWDevice { + public: + HWPrimary(BufferSyncHandler *buffer_sync_handler, HWInfoInterface *hw_info_intf); + + protected: + virtual DisplayError Init(); + virtual DisplayError GetNumDisplayAttributes(uint32_t *count); + virtual DisplayError GetActiveConfig(uint32_t *active_config); + virtual DisplayError GetDisplayAttributes(uint32_t index, + HWDisplayAttributes *display_attributes); + virtual DisplayError SetDisplayAttributes(uint32_t index); + virtual DisplayError GetConfigIndex(uint32_t mode, uint32_t *index); + virtual DisplayError PowerOff(); + virtual DisplayError Doze(); + virtual DisplayError DozeSuspend(); + virtual DisplayError Validate(HWLayers *hw_layers); + virtual DisplayError Commit(HWLayers *hw_layers); + virtual void SetIdleTimeoutMs(uint32_t timeout_ms); + virtual DisplayError SetVSyncState(bool enable); + virtual DisplayError SetDisplayMode(const HWDisplayMode hw_display_mode); + virtual DisplayError SetRefreshRate(uint32_t refresh_rate); + virtual DisplayError SetPanelBrightness(int level); + virtual DisplayError CachePanelBrightness(int level); + virtual DisplayError GetPPFeaturesVersion(PPFeatureVersion *vers); + virtual DisplayError SetPPFeatures(PPFeaturesConfig *feature_list); + virtual DisplayError GetPanelBrightness(int *level); + virtual DisplayError SetAutoRefresh(bool enable); + virtual DisplayError SetMixerAttributes(const HWMixerAttributes &mixer_attributes); + + private: + // Panel modes for the MSMFB_LPM_ENABLE ioctl + enum { + kModeLPMVideo, + kModeLPMCommand, + }; + + enum { + kMaxSysfsCommandLength = 12, + }; + + static const int kHWMdssVersion3 = 3; + DisplayError PopulateDisplayAttributes(); + void InitializeConfigs(); + bool IsResolutionSwitchEnabled() { return !display_configs_.empty(); } + bool GetCurrentModeFromSysfs(size_t *curr_x_pixels, size_t *curr_y_pixels); + void UpdateMixerAttributes(); + void SetAVRFlags(const HWAVRInfo &hw_avr_info, uint32_t *avr_flags); + + std::vector<DisplayConfigVariableInfo> display_configs_; + std::vector<std::string> display_config_strings_; + uint32_t active_config_index_ = 0; + const char *kBrightnessNode = "/sys/class/leds/lcd-backlight/brightness"; + const char *kAutoRefreshNode = "/sys/devices/virtual/graphics/fb0/msm_cmd_autorefresh_en"; + bool auto_refresh_ = false; + bool avr_prop_disabled_ = false; +}; + +} // namespace sdm + +#endif // __HW_PRIMARY_H__ + diff --git a/msm8909/sdm/libs/core/fb/hw_scale.cpp b/msm8909/sdm/libs/core/fb/hw_scale.cpp new file mode 100644 index 00000000..02585704 --- /dev/null +++ b/msm8909/sdm/libs/core/fb/hw_scale.cpp @@ -0,0 +1,314 @@ +/* +* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdio.h> +#include <utils/debug.h> +#include "hw_scale.h" + +#define __CLASS__ "HWScale" + +namespace sdm { + +DisplayError HWScale::Create(HWScale **intf, bool has_qseed3) { + if (has_qseed3) { + *intf = new HWScaleV2(); + } else { + *intf = new HWScaleV1(); + } + + return kErrorNone; +} + +DisplayError HWScale::Destroy(HWScale *intf) { + delete intf; + + return kErrorNone; +} + +void HWScaleV1::SetHWScaleData(const HWScaleData &scale_data, uint32_t index, + mdp_layer_commit_v1 *mdp_commit, HWSubBlockType sub_block_type) { + if (!scale_data.enable.scale) { + return; + } + + if (sub_block_type == kHWDestinationScalar) { + return; + } + + mdp_input_layer *mdp_layer = &mdp_commit->input_layers[index]; + mdp_layer->flags |= MDP_LAYER_ENABLE_PIXEL_EXT; + mdp_scale_data *mdp_scale = &scale_data_v1_.at(index); + mdp_scale->enable_pxl_ext = scale_data.enable.scale; + for (int i = 0; i < MAX_PLANES; i++) { + const HWPlane &plane = scale_data.plane[i]; + mdp_scale->init_phase_x[i] = plane.init_phase_x; + mdp_scale->phase_step_x[i] = plane.phase_step_x; + mdp_scale->init_phase_y[i] = plane.init_phase_y; + mdp_scale->phase_step_y[i] = plane.phase_step_y; + + mdp_scale->num_ext_pxls_left[i] = plane.left.extension; + mdp_scale->left_ftch[i] = plane.left.overfetch; + mdp_scale->left_rpt[i] = plane.left.repeat; + + mdp_scale->num_ext_pxls_top[i] = plane.top.extension; + mdp_scale->top_ftch[i] = plane.top.overfetch; + mdp_scale->top_rpt[i] = plane.top.repeat; + + mdp_scale->num_ext_pxls_right[i] = plane.right.extension; + mdp_scale->right_ftch[i] = plane.right.overfetch; + mdp_scale->right_rpt[i] = plane.right.repeat; + + mdp_scale->num_ext_pxls_btm[i] = plane.bottom.extension; + mdp_scale->btm_ftch[i] = plane.bottom.overfetch; + mdp_scale->btm_rpt[i] = plane.bottom.repeat; + + mdp_scale->roi_w[i] = plane.roi_width; + } + + return; +} + +void* HWScaleV1::GetScaleDataRef(uint32_t index, HWSubBlockType sub_block_type) { + if (sub_block_type != kHWDestinationScalar) { + return &scale_data_v1_.at(index); + } + + return NULL; +} + +void HWScaleV1::DumpScaleData(void *mdp_scale) { + if (!mdp_scale) { + return; + } + + mdp_scale_data *scale = reinterpret_cast<mdp_scale_data *>(mdp_scale); + if (scale->enable_pxl_ext) { + DLOGD_IF(kTagDriverConfig, "Scale Enable = %d", scale->enable_pxl_ext); + for (int j = 0; j < MAX_PLANES; j++) { + DLOGV_IF(kTagDriverConfig, "Scale Data[%d] : Phase=[%x %x %x %x] Pixel_Ext=[%d %d %d %d]", + j, scale->init_phase_x[j], scale->phase_step_x[j], scale->init_phase_y[j], + scale->phase_step_y[j], scale->num_ext_pxls_left[j], scale->num_ext_pxls_top[j], + scale->num_ext_pxls_right[j], scale->num_ext_pxls_btm[j]); + DLOGV_IF(kTagDriverConfig, "Fetch=[%d %d %d %d] Repeat=[%d %d %d %d] roi_width = %d", + scale->left_ftch[j], scale->top_ftch[j], scale->right_ftch[j], scale->btm_ftch[j], + scale->left_rpt[j], scale->top_rpt[j], scale->right_rpt[j], scale->btm_rpt[j], + scale->roi_w[j]); + } + } + + return; +} + +void HWScaleV2::SetHWScaleData(const HWScaleData &scale_data, uint32_t index, + mdp_layer_commit_v1 *mdp_commit, HWSubBlockType sub_block_type) { + if (!scale_data.enable.scale && !scale_data.enable.direction_detection && + !scale_data.enable.detail_enhance ) { + return; + } + + mdp_scale_data_v2 *mdp_scale; + if (sub_block_type != kHWDestinationScalar) { + mdp_input_layer *mdp_layer = &mdp_commit->input_layers[index]; + mdp_layer->flags |= MDP_LAYER_ENABLE_QSEED3_SCALE; + mdp_scale = &scale_data_v2_.at(index); + } else { + mdp_scale_data_v2 mdp_dest_scale = {0}; + + dest_scale_data_v2_.insert(std::make_pair(index, mdp_dest_scale)); + mdp_scale = &dest_scale_data_v2_[index]; + } + + mdp_scale->enable = (scale_data.enable.scale ? ENABLE_SCALE : 0) | + (scale_data.enable.direction_detection ? ENABLE_DIRECTION_DETECTION : 0) | + (scale_data.enable.detail_enhance ? ENABLE_DETAIL_ENHANCE : 0); + + if (sub_block_type == kHWDestinationScalar) { + mdp_destination_scaler_data *mdp_dest_scalar = + reinterpret_cast<mdp_destination_scaler_data *>(mdp_commit->dest_scaler); + + mdp_dest_scalar[index].flags = mdp_scale->enable ? MDP_DESTSCALER_ENABLE : 0; + + if (scale_data.enable.detail_enhance) { + mdp_dest_scalar[index].flags |= MDP_DESTSCALER_ENHANCER_UPDATE; + } + } + + for (int i = 0; i < MAX_PLANES; i++) { + const HWPlane &plane = scale_data.plane[i]; + mdp_scale->init_phase_x[i] = plane.init_phase_x; + mdp_scale->phase_step_x[i] = plane.phase_step_x; + mdp_scale->init_phase_y[i] = plane.init_phase_y; + mdp_scale->phase_step_y[i] = plane.phase_step_y; + + mdp_scale->num_ext_pxls_left[i] = UINT32(plane.left.extension); + mdp_scale->left_ftch[i] = plane.left.overfetch; + mdp_scale->left_rpt[i] = plane.left.repeat; + + mdp_scale->num_ext_pxls_top[i] = UINT32(plane.top.extension); + mdp_scale->top_ftch[i] = UINT32(plane.top.overfetch); + mdp_scale->top_rpt[i] = UINT32(plane.top.repeat); + + mdp_scale->num_ext_pxls_right[i] = UINT32(plane.right.extension); + mdp_scale->right_ftch[i] = plane.right.overfetch; + mdp_scale->right_rpt[i] = plane.right.repeat; + + mdp_scale->num_ext_pxls_btm[i] = UINT32(plane.bottom.extension); + mdp_scale->btm_ftch[i] = UINT32(plane.bottom.overfetch); + mdp_scale->btm_rpt[i] = UINT32(plane.bottom.repeat); + + mdp_scale->roi_w[i] = plane.roi_width; + + mdp_scale->preload_x[i] = UINT32(plane.preload_x); + mdp_scale->preload_y[i] = UINT32(plane.preload_y); + + mdp_scale->src_width[i] = plane.src_width; + mdp_scale->src_height[i] = plane.src_height; + } + + mdp_scale->dst_width = scale_data.dst_width; + mdp_scale->dst_height = scale_data.dst_height; + + mdp_scale->y_rgb_filter_cfg = GetMDPScalingFilter(scale_data.y_rgb_filter_cfg); + mdp_scale->uv_filter_cfg = GetMDPScalingFilter(scale_data.uv_filter_cfg); + mdp_scale->alpha_filter_cfg = GetMDPAlphaInterpolation(scale_data.alpha_filter_cfg); + mdp_scale->blend_cfg = scale_data.blend_cfg; + + mdp_scale->lut_flag = (scale_data.lut_flag.lut_swap ? SCALER_LUT_SWAP : 0) | + (scale_data.lut_flag.lut_dir_wr ? SCALER_LUT_DIR_WR : 0) | + (scale_data.lut_flag.lut_y_cir_wr ? SCALER_LUT_Y_CIR_WR : 0) | + (scale_data.lut_flag.lut_uv_cir_wr ? SCALER_LUT_UV_CIR_WR : 0) | + (scale_data.lut_flag.lut_y_sep_wr ? SCALER_LUT_Y_SEP_WR : 0) | + (scale_data.lut_flag.lut_uv_sep_wr ? SCALER_LUT_UV_SEP_WR : 0); + + mdp_scale->dir_lut_idx = scale_data.dir_lut_idx; + mdp_scale->y_rgb_cir_lut_idx = scale_data.y_rgb_cir_lut_idx; + mdp_scale->uv_cir_lut_idx = scale_data.uv_cir_lut_idx; + mdp_scale->y_rgb_sep_lut_idx = scale_data.y_rgb_sep_lut_idx; + mdp_scale->uv_sep_lut_idx = scale_data.uv_sep_lut_idx; + + if (mdp_scale->enable & ENABLE_DETAIL_ENHANCE) { + mdp_det_enhance_data *mdp_det_enhance = &mdp_scale->detail_enhance; + mdp_det_enhance->enable = scale_data.detail_enhance.enable; + mdp_det_enhance->sharpen_level1 = scale_data.detail_enhance.sharpen_level1; + mdp_det_enhance->sharpen_level2 = scale_data.detail_enhance.sharpen_level2; + mdp_det_enhance->clip = scale_data.detail_enhance.clip; + mdp_det_enhance->limit = scale_data.detail_enhance.limit; + mdp_det_enhance->thr_quiet = scale_data.detail_enhance.thr_quiet; + mdp_det_enhance->thr_dieout = scale_data.detail_enhance.thr_dieout; + mdp_det_enhance->thr_low = scale_data.detail_enhance.thr_low; + mdp_det_enhance->thr_high = scale_data.detail_enhance.thr_high; + mdp_det_enhance->prec_shift = scale_data.detail_enhance.prec_shift; + + for (int i = 0; i < MAX_DET_CURVES; i++) { + mdp_det_enhance->adjust_a[i] = scale_data.detail_enhance.adjust_a[i]; + mdp_det_enhance->adjust_b[i] = scale_data.detail_enhance.adjust_b[i]; + mdp_det_enhance->adjust_c[i] = scale_data.detail_enhance.adjust_c[i]; + } + } + + return; +} + +void* HWScaleV2::GetScaleDataRef(uint32_t index, HWSubBlockType sub_block_type) { + if (sub_block_type != kHWDestinationScalar) { + return &scale_data_v2_.at(index); + } else { + return &dest_scale_data_v2_[index]; + } +} + +uint32_t HWScaleV2::GetMDPScalingFilter(ScalingFilterConfig filter_cfg) { + switch (filter_cfg) { + case kFilterEdgeDirected: + return FILTER_EDGE_DIRECTED_2D; + case kFilterCircular: + return FILTER_CIRCULAR_2D; + case kFilterSeparable: + return FILTER_SEPARABLE_1D; + case kFilterBilinear: + return FILTER_BILINEAR; + default: + DLOGE("Invalid Scaling Filter"); + return kFilterMax; + } +} + +uint32_t HWScaleV2::GetMDPAlphaInterpolation(HWAlphaInterpolation alpha_filter_cfg) { + switch (alpha_filter_cfg) { + case kInterpolationPixelRepeat: + return FILTER_ALPHA_DROP_REPEAT; + case kInterpolationBilinear: + return FILTER_ALPHA_BILINEAR; + default: + DLOGE("Invalid Alpha Interpolation"); + return kInterpolationMax; + } +} + +void HWScaleV2::DumpScaleData(void *mdp_scale) { + if (!mdp_scale) { + return; + } + + mdp_scale_data_v2 *scale = reinterpret_cast<mdp_scale_data_v2 *>(mdp_scale); + if (scale->enable) { + DLOGD_IF(kTagDriverConfig, "Scale Enable = %d", scale->enable); + for (int j = 0; j < MAX_PLANES; j++) { + DLOGV_IF(kTagDriverConfig, "Scale Data[%d]: Phase_init[x y]=[%x %x] Phase_step:[x y]=[%x %x]", + j, scale->init_phase_x[j], scale->init_phase_y[j], scale->phase_step_x[j], + scale->phase_step_y[j]); + DLOGV_IF(kTagDriverConfig, "Preload[x y]=[%x %x], Pixel Ext=[%d %d] Ovfetch=[%d %d %d %d]", + scale->preload_x[j], scale->preload_y[j], scale->num_ext_pxls_left[j], + scale->num_ext_pxls_top[j], scale->left_ftch[j], scale->top_ftch[j], scale->right_ftch[j], + scale->btm_ftch[j]); + DLOGV_IF(kTagDriverConfig, "Repeat=[%d %d %d %d] Src[w x h]=[%d %d] roi_width = %d", + scale->left_rpt[j], scale->top_rpt[j], scale->right_rpt[j], scale->btm_rpt[j], + scale->src_width[j], scale->src_height[j], scale->roi_w[j]); + } + + DLOGD_IF(kTagDriverConfig, "LUT flags = %d", scale->lut_flag); + DLOGV_IF(kTagDriverConfig, "y_rgb_filter=%d, uv_filter=%d, alpha_filter=%d, blend_cfg=%d", + scale->y_rgb_filter_cfg, scale->uv_filter_cfg, scale->alpha_filter_cfg, scale->blend_cfg); + DLOGV_IF(kTagDriverConfig, "dir_lut=%d, y_rgb_cir=%d, uv_cir=%d, y_rgb_sep=%d, uv_sep=%d", + scale->dir_lut_idx, scale->y_rgb_cir_lut_idx, scale->uv_cir_lut_idx, + scale->y_rgb_sep_lut_idx, scale->uv_sep_lut_idx); + if (scale->enable & ENABLE_DETAIL_ENHANCE) { + mdp_det_enhance_data *de = &scale->detail_enhance; + DLOGV_IF(kTagDriverConfig, "Detail Enhance: enable: %d sharpen_level1: %d sharpen_level2: %d", + de->enable, de->sharpen_level1, de->sharpen_level2); + DLOGV_IF(kTagDriverConfig, "clip: %d limit:%d thr_quiet: %d thr_dieout: %d", + de->clip, de->limit, de->thr_quiet, de->thr_dieout); + DLOGV_IF(kTagDriverConfig, "thr_low: %d thr_high: %d prec_shift: %d", de->thr_low, + de->thr_high, de->prec_shift); + for (uint32_t i = 0; i < MAX_DET_CURVES; i++) { + DLOGV_IF(kTagDriverConfig, "adjust_a[%d]: %d adjust_b[%d]: %d adjust_c[%d]: %d", i, + de->adjust_a[i], i, de->adjust_b[i], i, de->adjust_c[i]); + } + } + } + + return; +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/core/fb/hw_scale.h b/msm8909/sdm/libs/core/fb/hw_scale.h new file mode 100644 index 00000000..7590833b --- /dev/null +++ b/msm8909/sdm/libs/core/fb/hw_scale.h @@ -0,0 +1,85 @@ +/* +* 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 __HW_SCALE_H__ +#define __HW_SCALE_H__ + +#include <linux/msm_mdp_ext.h> +#include <private/hw_info_types.h> + +#include <cstring> +#include <array> +#include <map> + +namespace sdm { + +class HWScale { + public: + static DisplayError Create(HWScale **intf, bool has_qseed3); + static DisplayError Destroy(HWScale *intf); + + virtual void SetHWScaleData(const HWScaleData &scale, uint32_t index, + mdp_layer_commit_v1 *mdp_commit, HWSubBlockType sub_block_type) = 0; + virtual void* GetScaleDataRef(uint32_t index, HWSubBlockType sub_block_type) = 0; + virtual void DumpScaleData(void *mdp_scale) = 0; + virtual void ResetScaleParams() = 0; + protected: + virtual ~HWScale() { } +}; + +class HWScaleV1 : public HWScale { + public: + virtual void SetHWScaleData(const HWScaleData &scale, uint32_t index, + mdp_layer_commit_v1 *mdp_commit, HWSubBlockType sub_block_type); + virtual void* GetScaleDataRef(uint32_t index, HWSubBlockType sub_block_type); + virtual void DumpScaleData(void *mdp_scale); + virtual void ResetScaleParams() { scale_data_v1_ = {}; } + + protected: + ~HWScaleV1() {} + std::array<mdp_scale_data, (kMaxSDELayers * 2)> scale_data_v1_ = {}; +}; + +class HWScaleV2 : public HWScale { + public: + virtual void SetHWScaleData(const HWScaleData &scale, uint32_t index, + mdp_layer_commit_v1 *mdp_commit, HWSubBlockType sub_block_type); + virtual void* GetScaleDataRef(uint32_t index, HWSubBlockType sub_block_type); + virtual void DumpScaleData(void *mdp_scale); + virtual void ResetScaleParams() { scale_data_v2_ = {}; dest_scale_data_v2_ = {}; } + + protected: + ~HWScaleV2() {} + std::array<mdp_scale_data_v2, (kMaxSDELayers * 2)> scale_data_v2_ = {}; + std::map<uint32_t, mdp_scale_data_v2> dest_scale_data_v2_ = {}; + + private: + uint32_t GetMDPAlphaInterpolation(HWAlphaInterpolation alpha_filter_cfg); + uint32_t GetMDPScalingFilter(ScalingFilterConfig filter_cfg); +}; + +} // namespace sdm + +#endif // __HW_SCALE_H__ + diff --git a/msm8909/sdm/libs/core/fb/hw_virtual.cpp b/msm8909/sdm/libs/core/fb/hw_virtual.cpp new file mode 100644 index 00000000..21017a5c --- /dev/null +++ b/msm8909/sdm/libs/core/fb/hw_virtual.cpp @@ -0,0 +1,86 @@ +/* +* 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 <utils/debug.h> +#include "hw_virtual.h" + +#define __CLASS__ "HWVirtual" + +namespace sdm { + +HWVirtual::HWVirtual(BufferSyncHandler *buffer_sync_handler, HWInfoInterface *hw_info_intf) + : HWDevice(buffer_sync_handler) { + HWDevice::device_type_ = kDeviceVirtual; + HWDevice::device_name_ = "Virtual Display Device"; + HWDevice::hw_info_intf_ = hw_info_intf; +} + +DisplayError HWVirtual::Init() { + return HWDevice::Init(); +} + +DisplayError HWVirtual::Validate(HWLayers *hw_layers) { + HWDevice::ResetDisplayParams(); + return HWDevice::Validate(hw_layers); +} + +DisplayError HWVirtual::GetMixerAttributes(HWMixerAttributes *mixer_attributes) { + mixer_attributes->width = display_attributes_.x_pixels; + mixer_attributes->height = display_attributes_.y_pixels; + mixer_attributes_.split_left = display_attributes_.is_device_split ? + (display_attributes_.x_pixels / 2) : mixer_attributes_.width; + + return kErrorNone; +} + +DisplayError HWVirtual::SetDisplayAttributes(const HWDisplayAttributes &display_attributes) { + if (display_attributes.x_pixels == 0 || display_attributes.y_pixels == 0) { + return kErrorParameters; + } + + display_attributes_ = display_attributes; + + if (display_attributes_.x_pixels > hw_resource_.max_mixer_width) { + display_attributes_.is_device_split = true; + } + + return kErrorNone; +} + +DisplayError HWVirtual::GetDisplayAttributes(uint32_t index, + HWDisplayAttributes *display_attributes) { + display_attributes->fps = 60; + // TODO(user): Need to update WB fps + + return kErrorNone; +} + + +} // namespace sdm + diff --git a/msm8909/sdm/libs/core/fb/hw_virtual.h b/msm8909/sdm/libs/core/fb/hw_virtual.h new file mode 100644 index 00000000..1c204cdf --- /dev/null +++ b/msm8909/sdm/libs/core/fb/hw_virtual.h @@ -0,0 +1,52 @@ +/* +* 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. +*/ + +#ifndef __HW_VIRTUAL_H__ +#define __HW_VIRTUAL_H__ + +#include "hw_device.h" + +namespace sdm { + +class HWVirtual : public HWDevice { + public: + HWVirtual(BufferSyncHandler *buffer_sync_handler, HWInfoInterface *hw_info_intf); + virtual DisplayError SetVSyncState(bool enable) { return kErrorNotSupported; } + virtual DisplayError SetMixerAttributes(const HWMixerAttributes &mixer_attributes) { + return kErrorNotSupported; + } + virtual DisplayError GetMixerAttributes(HWMixerAttributes *mixer_attributes); + virtual DisplayError SetDisplayAttributes(const HWDisplayAttributes &display_attributes); + virtual DisplayError GetDisplayAttributes(uint32_t index, + HWDisplayAttributes *display_attributes); + + protected: + virtual DisplayError Init(); + virtual DisplayError Validate(HWLayers *hw_layers); +}; + +} // namespace sdm + +#endif // __HW_VIRTUAL_H__ + diff --git a/msm8909/sdm/libs/core/hw_events_interface.cpp b/msm8909/sdm/libs/core/hw_events_interface.cpp new file mode 100644 index 00000000..ed62b86b --- /dev/null +++ b/msm8909/sdm/libs/core/hw_events_interface.cpp @@ -0,0 +1,75 @@ +/* +* Copyright (c) 2017, 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/utils.h> +#include <vector> + +#include "hw_events_interface.h" +#include "fb/hw_events.h" +#ifdef COMPILE_DRM +#include "drm/hw_events_drm.h" +#endif + +#define __CLASS__ "HWEventsInterface" + +namespace sdm { + +DisplayError HWEventsInterface::Create(int display_type, HWEventHandler *event_handler, + const std::vector<HWEvent> &event_list, + HWEventsInterface **intf) { + DisplayError error = kErrorNone; + HWEventsInterface *hw_events = nullptr; + if (GetDriverType() == DriverType::FB) { + hw_events = new HWEvents(); + } else { +#ifdef COMPILE_DRM + hw_events = new HWEventsDRM(); +#endif + } + + error = hw_events->Init(display_type, event_handler, event_list); + if (error != kErrorNone) { + delete hw_events; + } else { + *intf = hw_events; + } + + return error; +} + +DisplayError HWEventsInterface::Destroy(HWEventsInterface *intf) { + if (intf) { + intf->Deinit(); + delete intf; + } + + return kErrorNone; +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/core/hw_events_interface.h b/msm8909/sdm/libs/core/hw_events_interface.h new file mode 100644 index 00000000..17fb7df3 --- /dev/null +++ b/msm8909/sdm/libs/core/hw_events_interface.h @@ -0,0 +1,63 @@ +/* +* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __HW_EVENTS_INTERFACE_H__ +#define __HW_EVENTS_INTERFACE_H__ + +#include <private/hw_info_types.h> +#include <inttypes.h> +#include <utility> +#include <vector> + +namespace sdm { + +class HWEventHandler; + +enum HWEvent { + VSYNC = 0, + EXIT, + IDLE_NOTIFY, + SHOW_BLANK_EVENT, + THERMAL_LEVEL, + IDLE_POWER_COLLAPSE, +}; + +class HWEventsInterface { + public: + virtual DisplayError Init(int display_type, HWEventHandler *event_handler, + const std::vector<HWEvent> &event_list) = 0; + virtual DisplayError Deinit() = 0; + + static DisplayError Create(int display_type, HWEventHandler *event_handler, + const std::vector<HWEvent> &event_list, HWEventsInterface **intf); + static DisplayError Destroy(HWEventsInterface *intf); + + protected: + virtual ~HWEventsInterface() { } +}; + +} // namespace sdm + +#endif // __HW_EVENTS_INTERFACE_H__ + diff --git a/msm8909/sdm/libs/core/hw_info_interface.cpp b/msm8909/sdm/libs/core/hw_info_interface.cpp new file mode 100644 index 00000000..1773fe52 --- /dev/null +++ b/msm8909/sdm/libs/core/hw_info_interface.cpp @@ -0,0 +1,62 @@ +/* +* Copyright (c) 2017, 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/utils.h> + +#include "hw_info_interface.h" +#include "fb/hw_info.h" +#ifdef COMPILE_DRM +#include "drm/hw_info_drm.h" +#endif + +#define __CLASS__ "HWInfoInterface" + +namespace sdm { + +DisplayError HWInfoInterface::Create(HWInfoInterface **intf) { + if (GetDriverType() == DriverType::FB) { + *intf = new HWInfo(); + } else { +#ifdef COMPILE_DRM + *intf = new HWInfoDRM(); +#endif + } + + return kErrorNone; +} + +DisplayError HWInfoInterface::Destroy(HWInfoInterface *intf) { + if (intf) { + delete intf; + } + + return kErrorNone; +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/core/hw_info_interface.h b/msm8909/sdm/libs/core/hw_info_interface.h new file mode 100644 index 00000000..401c8bf6 --- /dev/null +++ b/msm8909/sdm/libs/core/hw_info_interface.h @@ -0,0 +1,48 @@ +/* +* 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 __HW_INFO_INTERFACE_H__ +#define __HW_INFO_INTERFACE_H__ + +#include <inttypes.h> +#include <core/core_interface.h> +#include <private/hw_info_types.h> + +namespace sdm { + +class HWInfoInterface { + public: + static DisplayError Create(HWInfoInterface **intf); + static DisplayError Destroy(HWInfoInterface *intf); + virtual DisplayError GetHWResourceInfo(HWResourceInfo *hw_resource) = 0; + virtual DisplayError GetFirstDisplayInterfaceType(HWDisplayInterfaceInfo *hw_disp_info) = 0; + + protected: + virtual ~HWInfoInterface() { } +}; + +} // namespace sdm + +#endif // __HW_INFO_INTERFACE_H__ + diff --git a/msm8909/sdm/libs/core/hw_interface.cpp b/msm8909/sdm/libs/core/hw_interface.cpp new file mode 100644 index 00000000..b5c9fe90 --- /dev/null +++ b/msm8909/sdm/libs/core/hw_interface.cpp @@ -0,0 +1,102 @@ +/* +* Copyright (c) 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <utils/debug.h> +#include <utils/utils.h> + +#include "hw_interface.h" +#include "fb/hw_device.h" +#include "fb/hw_primary.h" +#include "fb/hw_hdmi.h" +#include "fb/hw_virtual.h" +#ifdef COMPILE_DRM +#include "drm/hw_device_drm.h" +#endif + +#define __CLASS__ "HWInterface" + +namespace sdm { + +DisplayError HWInterface::Create(DisplayType type, HWInfoInterface *hw_info_intf, + BufferSyncHandler *buffer_sync_handler, + BufferAllocator *buffer_allocator, HWInterface **intf) { + DisplayError error = kErrorNone; + HWInterface *hw = nullptr; + DriverType driver_type = GetDriverType(); + + switch (type) { + case kPrimary: + if (driver_type == DriverType::FB) { + hw = new HWPrimary(buffer_sync_handler, hw_info_intf); + } else { +#ifdef COMPILE_DRM + hw = new HWDeviceDRM(buffer_sync_handler, buffer_allocator, hw_info_intf); +#endif + } + break; + case kHDMI: + if (driver_type == DriverType::FB) { + hw = new HWHDMI(buffer_sync_handler, hw_info_intf); + } else { + return kErrorNotSupported; + } + break; + case kVirtual: + if (driver_type == DriverType::FB) { + hw = new HWVirtual(buffer_sync_handler, hw_info_intf); + } else { + return kErrorNotSupported; + } + break; + default: + DLOGE("Undefined display type"); + return kErrorUndefined; + } + + error = hw->Init(); + if (error != kErrorNone) { + delete hw; + DLOGE("Init on HW Intf type %d failed", type); + return error; + } + *intf = hw; + + return error; +} + +DisplayError HWInterface::Destroy(HWInterface *intf) { + if (intf) { + intf->Deinit(); + delete intf; + } + + return kErrorNone; +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/core/hw_interface.h b/msm8909/sdm/libs/core/hw_interface.h new file mode 100644 index 00000000..312ad985 --- /dev/null +++ b/msm8909/sdm/libs/core/hw_interface.h @@ -0,0 +1,120 @@ +/* +* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __HW_INTERFACE_H__ +#define __HW_INTERFACE_H__ + +#include <core/buffer_allocator.h> +#include <core/buffer_sync_handler.h> +#include <core/display_interface.h> +#include <private/hw_info_types.h> +#include <private/color_interface.h> +#include <utils/constants.h> + +#include "hw_info_interface.h" + +namespace sdm { + +enum HWScanSupport { + kScanNotSupported, + kScanAlwaysOverscanned, + kScanAlwaysUnderscanned, + kScanBoth, +}; + +struct HWScanInfo { + HWScanSupport pt_scan_support; // Scan support for preferred timing + HWScanSupport it_scan_support; // Scan support for digital monitor or industry timings + HWScanSupport cea_scan_support; // Scan support for CEA resolution timings + + HWScanInfo() : pt_scan_support(kScanNotSupported), it_scan_support(kScanNotSupported), + cea_scan_support(kScanNotSupported) { } +}; + +// HWEventHandler - Implemented in DisplayBase and HWInterface implementation +class HWEventHandler { + public: + virtual DisplayError VSync(int64_t timestamp) = 0; + virtual DisplayError Blank(bool blank) = 0; + virtual void IdleTimeout() = 0; + virtual void ThermalEvent(int64_t thermal_level) = 0; + virtual void IdlePowerCollapse() = 0; + + protected: + virtual ~HWEventHandler() { } +}; + +class HWInterface { + public: + static DisplayError Create(DisplayType type, HWInfoInterface *hw_info_intf, + BufferSyncHandler *buffer_sync_handler, + BufferAllocator *buffer_allocator, HWInterface **intf); + static DisplayError Destroy(HWInterface *intf); + + virtual DisplayError Init() = 0; + virtual DisplayError Deinit() = 0; + virtual DisplayError GetActiveConfig(uint32_t *active_config) = 0; + virtual DisplayError GetNumDisplayAttributes(uint32_t *count) = 0; + virtual DisplayError GetDisplayAttributes(uint32_t index, + HWDisplayAttributes *display_attributes) = 0; + virtual DisplayError GetHWPanelInfo(HWPanelInfo *panel_info) = 0; + virtual DisplayError SetDisplayAttributes(uint32_t index) = 0; + virtual DisplayError SetDisplayAttributes(const HWDisplayAttributes &display_attributes) = 0; + virtual DisplayError GetConfigIndex(uint32_t mode, uint32_t *index) = 0; + virtual DisplayError PowerOn() = 0; + virtual DisplayError PowerOff() = 0; + virtual DisplayError Doze() = 0; + virtual DisplayError DozeSuspend() = 0; + virtual DisplayError Standby() = 0; + virtual DisplayError Validate(HWLayers *hw_layers) = 0; + virtual DisplayError Commit(HWLayers *hw_layers) = 0; + virtual DisplayError Flush() = 0; + virtual DisplayError GetPPFeaturesVersion(PPFeatureVersion *vers) = 0; + virtual DisplayError SetPPFeatures(PPFeaturesConfig *feature_list) = 0; + virtual DisplayError SetVSyncState(bool enable) = 0; + virtual void SetIdleTimeoutMs(uint32_t timeout_ms) = 0; + virtual DisplayError SetDisplayMode(const HWDisplayMode hw_display_mode) = 0; + virtual DisplayError SetRefreshRate(uint32_t refresh_rate) = 0; + virtual DisplayError SetPanelBrightness(int level) = 0; + virtual DisplayError CachePanelBrightness(int level) = 0; + virtual DisplayError GetHWScanInfo(HWScanInfo *scan_info) = 0; + virtual DisplayError GetVideoFormat(uint32_t config_index, uint32_t *video_format) = 0; + virtual DisplayError GetMaxCEAFormat(uint32_t *max_cea_format) = 0; + virtual DisplayError SetCursorPosition(HWLayers *hw_layers, int x, int y) = 0; + virtual DisplayError OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level) = 0; + virtual DisplayError GetPanelBrightness(int *level) = 0; + virtual DisplayError SetAutoRefresh(bool enable) = 0; + virtual DisplayError SetS3DMode(HWS3DMode s3d_mode) = 0; + virtual DisplayError SetScaleLutConfig(HWScaleLutInfo *lut_info) = 0; + virtual DisplayError SetMixerAttributes(const HWMixerAttributes &mixer_attributes) = 0; + virtual DisplayError GetMixerAttributes(HWMixerAttributes *mixer_attributes) = 0; + + protected: + virtual ~HWInterface() { } +}; + +} // namespace sdm + +#endif // __HW_INTERFACE_H__ + diff --git a/msm8909/sdm/libs/core/resource_default.cpp b/msm8909/sdm/libs/core/resource_default.cpp new file mode 100644 index 00000000..6a4f3e5b --- /dev/null +++ b/msm8909/sdm/libs/core/resource_default.cpp @@ -0,0 +1,950 @@ +/* +* 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 <math.h> +#include <utils/constants.h> +#include <utils/debug.h> +#include <utils/rect.h> +#include <utils/formats.h> +#include <utils/sys.h> +#include <dlfcn.h> +#include <algorithm> + +#include "resource_default.h" + +#define __CLASS__ "ResourceDefault" + +namespace sdm { + +DisplayError ResourceDefault::CreateResourceDefault(const HWResourceInfo &hw_resource_info, + ResourceInterface **resource_intf) { + DisplayError error = kErrorNone; + + ResourceDefault *resource_default = new ResourceDefault(hw_resource_info); + if (!resource_default) { + return kErrorNone; + } + + error = resource_default->Init(); + if (error != kErrorNone) { + delete resource_default; + } + + *resource_intf = resource_default; + + return kErrorNone; +} + +DisplayError ResourceDefault::DestroyResourceDefault(ResourceInterface *resource_intf) { + ResourceDefault *resource_default = static_cast<ResourceDefault *>(resource_intf); + + resource_default->Deinit(); + delete resource_default; + + return kErrorNone; +} + +ResourceDefault::ResourceDefault(const HWResourceInfo &hw_res_info) + : hw_res_info_(hw_res_info) { +} + +DisplayError ResourceDefault::Init() { + DisplayError error = kErrorNone; + + num_pipe_ = hw_res_info_.num_vig_pipe + hw_res_info_.num_rgb_pipe + hw_res_info_.num_dma_pipe; + + if (!num_pipe_) { + DLOGE("Number of H/W pipes is Zero!"); + return kErrorParameters; + } + + src_pipes_.resize(num_pipe_); + + // Priority order of pipes: VIG, RGB, DMA + uint32_t vig_index = 0; + uint32_t rgb_index = hw_res_info_.num_vig_pipe; + uint32_t dma_index = rgb_index + hw_res_info_.num_rgb_pipe; + + for (uint32_t i = 0; i < num_pipe_; i++) { + const HWPipeCaps &pipe_caps = hw_res_info_.hw_pipes.at(i); + if (pipe_caps.type == kPipeTypeVIG) { + src_pipes_[vig_index].type = kPipeTypeVIG; + src_pipes_[vig_index].index = i; + src_pipes_[vig_index].mdss_pipe_id = pipe_caps.id; + vig_index++; + } else if (pipe_caps.type == kPipeTypeRGB) { + src_pipes_[rgb_index].type = kPipeTypeRGB; + src_pipes_[rgb_index].index = i; + src_pipes_[rgb_index].mdss_pipe_id = pipe_caps.id; + rgb_index++; + } else if (pipe_caps.type == kPipeTypeDMA) { + src_pipes_[dma_index].type = kPipeTypeDMA; + src_pipes_[dma_index].index = i; + src_pipes_[dma_index].mdss_pipe_id = pipe_caps.id; + dma_index++; + } + } + + for (uint32_t i = 0; i < num_pipe_; i++) { + src_pipes_[i].priority = INT(i); + } + + DLOGI("hw_rev=%x, DMA=%d RGB=%d VIG=%d", hw_res_info_.hw_revision, hw_res_info_.num_dma_pipe, + hw_res_info_.num_rgb_pipe, hw_res_info_.num_vig_pipe); + + if (hw_res_info_.max_scale_down < 1 || hw_res_info_.max_scale_up < 1) { + DLOGE("Max scaling setting is invalid! max_scale_down = %d, max_scale_up = %d", + hw_res_info_.max_scale_down, hw_res_info_.max_scale_up); + hw_res_info_.max_scale_down = 1; + hw_res_info_.max_scale_up = 1; + } + + // TODO(user): clean it up, query from driver for initial pipe status. +#ifndef SDM_VIRTUAL_DRIVER + rgb_index = hw_res_info_.num_vig_pipe; + src_pipes_[rgb_index].owner = kPipeOwnerKernelMode; + src_pipes_[rgb_index + 1].owner = kPipeOwnerKernelMode; +#endif + + return error; +} + +DisplayError ResourceDefault::Deinit() { + return kErrorNone; +} + +DisplayError ResourceDefault::RegisterDisplay(DisplayType type, + const HWDisplayAttributes &display_attributes, + const HWPanelInfo &hw_panel_info, + const HWMixerAttributes &mixer_attributes, + Handle *display_ctx) { + DisplayError error = kErrorNone; + + HWBlockType hw_block_id = kHWBlockMax; + switch (type) { + case kPrimary: + if (!hw_block_ctx_[kHWPrimary].is_in_use) { + hw_block_id = kHWPrimary; + } + break; + + case kHDMI: + if (!hw_block_ctx_[kHWHDMI].is_in_use) { + hw_block_id = kHWHDMI; + } + break; + + default: + DLOGW("RegisterDisplay, invalid type %d", type); + return kErrorParameters; + } + + if (hw_block_id == kHWBlockMax) { + return kErrorResources; + } + + DisplayResourceContext *display_resource_ctx = new DisplayResourceContext(); + if (!display_resource_ctx) { + return kErrorMemory; + } + + hw_block_ctx_[hw_block_id].is_in_use = true; + + display_resource_ctx->display_attributes = display_attributes; + display_resource_ctx->hw_block_id = hw_block_id; + display_resource_ctx->mixer_attributes = mixer_attributes; + + *display_ctx = display_resource_ctx; + return error; +} + +DisplayError ResourceDefault::UnregisterDisplay(Handle display_ctx) { + DisplayResourceContext *display_resource_ctx = + reinterpret_cast<DisplayResourceContext *>(display_ctx); + Purge(display_ctx); + + hw_block_ctx_[display_resource_ctx->hw_block_id].is_in_use = false; + + delete display_resource_ctx; + + return kErrorNone; +} + +DisplayError ResourceDefault::ReconfigureDisplay(Handle display_ctx, + const HWDisplayAttributes &display_attributes, + const HWPanelInfo &hw_panel_info, + const HWMixerAttributes &mixer_attributes) { + SCOPE_LOCK(locker_); + + DisplayResourceContext *display_resource_ctx = + reinterpret_cast<DisplayResourceContext *>(display_ctx); + + display_resource_ctx->display_attributes = display_attributes; + display_resource_ctx->mixer_attributes = mixer_attributes; + + return kErrorNone; +} + +DisplayError ResourceDefault::Start(Handle display_ctx) { + locker_.Lock(); + + return kErrorNone; +} + +DisplayError ResourceDefault::Stop(Handle display_ctx, HWLayers *hw_layers) { + locker_.Unlock(); + + return kErrorNone; +} + +DisplayError ResourceDefault::Prepare(Handle display_ctx, HWLayers *hw_layers) { + DisplayResourceContext *display_resource_ctx = + reinterpret_cast<DisplayResourceContext *>(display_ctx); + + DisplayError error = kErrorNone; + const struct HWLayersInfo &layer_info = hw_layers->info; + HWBlockType hw_block_id = display_resource_ctx->hw_block_id; + + DLOGV_IF(kTagResources, "==== Resource reserving start: hw_block = %d ====", hw_block_id); + + if (layer_info.hw_layers.size() > 1) { + DLOGV_IF(kTagResources, "More than one FB layers"); + return kErrorResources; + } + + const Layer &layer = layer_info.hw_layers.at(0); + + if (layer.composition != kCompositionGPUTarget) { + DLOGV_IF(kTagResources, "Not an FB layer"); + return kErrorParameters; + } + + error = Config(display_resource_ctx, hw_layers); + if (error != kErrorNone) { + DLOGV_IF(kTagResources, "Resource config failed"); + return error; + } + + for (uint32_t i = 0; i < num_pipe_; i++) { + if (src_pipes_[i].hw_block_id == hw_block_id && src_pipes_[i].owner == kPipeOwnerUserMode) { + src_pipes_[i].ResetState(); + } + } + + uint32_t left_index = num_pipe_; + uint32_t right_index = num_pipe_; + bool need_scale = false; + + struct HWLayerConfig &layer_config = hw_layers->config[0]; + + HWPipeInfo *left_pipe = &layer_config.left_pipe; + HWPipeInfo *right_pipe = &layer_config.right_pipe; + + // left pipe is needed + if (left_pipe->valid) { + need_scale = IsScalingNeeded(left_pipe); + left_index = GetPipe(hw_block_id, need_scale); + if (left_index >= num_pipe_) { + DLOGV_IF(kTagResources, "Get left pipe failed: hw_block_id = %d, need_scale = %d", + hw_block_id, need_scale); + ResourceStateLog(); + goto CleanupOnError; + } + } + + error = SetDecimationFactor(left_pipe); + if (error != kErrorNone) { + goto CleanupOnError; + } + + if (!right_pipe->valid) { + // assign single pipe + if (left_index < num_pipe_) { + left_pipe->pipe_id = src_pipes_[left_index].mdss_pipe_id; + } + DLOGV_IF(kTagResources, "1 pipe acquired for FB layer, left_pipe = %x", left_pipe->pipe_id); + return kErrorNone; + } + + need_scale = IsScalingNeeded(right_pipe); + + right_index = GetPipe(hw_block_id, need_scale); + if (right_index >= num_pipe_) { + DLOGV_IF(kTagResources, "Get right pipe failed: hw_block_id = %d, need_scale = %d", hw_block_id, + need_scale); + ResourceStateLog(); + goto CleanupOnError; + } + + if (src_pipes_[right_index].priority < src_pipes_[left_index].priority) { + // Swap pipe based on priority + std::swap(left_index, right_index); + } + + // assign dual pipes + left_pipe->pipe_id = src_pipes_[left_index].mdss_pipe_id; + right_pipe->pipe_id = src_pipes_[right_index].mdss_pipe_id; + + error = SetDecimationFactor(right_pipe); + if (error != kErrorNone) { + goto CleanupOnError; + } + + DLOGV_IF(kTagResources, "2 pipes acquired for FB layer, left_pipe = %x, right_pipe = %x", + left_pipe->pipe_id, right_pipe->pipe_id); + + return kErrorNone; + +CleanupOnError: + DLOGV_IF(kTagResources, "Resource reserving failed! hw_block = %d", hw_block_id); + + return kErrorResources; +} + +DisplayError ResourceDefault::PostPrepare(Handle display_ctx, HWLayers *hw_layers) { + SCOPE_LOCK(locker_); + + return kErrorNone; +} + +DisplayError ResourceDefault::Commit(Handle display_ctx, HWLayers *hw_layers) { + SCOPE_LOCK(locker_); + + return kErrorNone; +} + +DisplayError ResourceDefault::PostCommit(Handle display_ctx, HWLayers *hw_layers) { + SCOPE_LOCK(locker_); + DisplayResourceContext *display_resource_ctx = + reinterpret_cast<DisplayResourceContext *>(display_ctx); + HWBlockType hw_block_id = display_resource_ctx->hw_block_id; + uint64_t frame_count = display_resource_ctx->frame_count; + + DLOGV_IF(kTagResources, "Resource for hw_block = %d, frame_count = %d", hw_block_id, frame_count); + + // handoff pipes which are used by splash screen + if ((frame_count == 0) && (hw_block_id == kHWPrimary)) { + for (uint32_t i = 0; i < num_pipe_; i++) { + if (src_pipes_[i].hw_block_id == hw_block_id && src_pipes_[i].owner == kPipeOwnerKernelMode) { + src_pipes_[i].owner = kPipeOwnerUserMode; + } + } + } + + if (hw_layers->info.sync_handle >= 0) + Sys::close_(hw_layers->info.sync_handle); + + display_resource_ctx->frame_count++; + + return kErrorNone; +} + +void ResourceDefault::Purge(Handle display_ctx) { + SCOPE_LOCK(locker_); + + DisplayResourceContext *display_resource_ctx = + reinterpret_cast<DisplayResourceContext *>(display_ctx); + HWBlockType hw_block_id = display_resource_ctx->hw_block_id; + + for (uint32_t i = 0; i < num_pipe_; i++) { + if (src_pipes_[i].hw_block_id == hw_block_id && src_pipes_[i].owner == kPipeOwnerUserMode) { + src_pipes_[i].ResetState(); + } + } + DLOGV_IF(kTagResources, "display id = %d", display_resource_ctx->hw_block_id); +} + +DisplayError ResourceDefault::SetMaxMixerStages(Handle display_ctx, uint32_t max_mixer_stages) { + SCOPE_LOCK(locker_); + + return kErrorNone; +} + +uint32_t ResourceDefault::SearchPipe(HWBlockType hw_block_id, SourcePipe *src_pipes, + uint32_t num_pipe) { + uint32_t index = num_pipe_; + SourcePipe *src_pipe; + + // search the pipe being used + for (uint32_t i = 0; i < num_pipe; i++) { + src_pipe = &src_pipes[i]; + if (src_pipe->owner == kPipeOwnerUserMode && src_pipe->hw_block_id == kHWBlockMax) { + index = src_pipe->index; + src_pipe->hw_block_id = hw_block_id; + break; + } + } + + return index; +} + +uint32_t ResourceDefault::NextPipe(PipeType type, HWBlockType hw_block_id) { + uint32_t num_pipe = 0; + SourcePipe *src_pipes = NULL; + + switch (type) { + case kPipeTypeVIG: + src_pipes = &src_pipes_[0]; + num_pipe = hw_res_info_.num_vig_pipe; + break; + case kPipeTypeRGB: + src_pipes = &src_pipes_[hw_res_info_.num_vig_pipe]; + num_pipe = hw_res_info_.num_rgb_pipe; + break; + case kPipeTypeDMA: + default: + src_pipes = &src_pipes_[hw_res_info_.num_vig_pipe + hw_res_info_.num_rgb_pipe]; + num_pipe = hw_res_info_.num_dma_pipe; + break; + } + + return SearchPipe(hw_block_id, src_pipes, num_pipe); +} + +uint32_t ResourceDefault::GetPipe(HWBlockType hw_block_id, bool need_scale) { + uint32_t index = num_pipe_; + + // The default behavior is to assume RGB and VG pipes have scalars + if (!need_scale) { + index = NextPipe(kPipeTypeDMA, hw_block_id); + } + + if ((index >= num_pipe_) && (!need_scale || !hw_res_info_.has_non_scalar_rgb)) { + index = NextPipe(kPipeTypeRGB, hw_block_id); + } + + if (index >= num_pipe_) { + index = NextPipe(kPipeTypeVIG, hw_block_id); + } + + return index; +} + +bool ResourceDefault::IsScalingNeeded(const HWPipeInfo *pipe_info) { + const LayerRect &src_roi = pipe_info->src_roi; + const LayerRect &dst_roi = pipe_info->dst_roi; + + return ((dst_roi.right - dst_roi.left) != (src_roi.right - src_roi.left)) || + ((dst_roi.bottom - dst_roi.top) != (src_roi.bottom - src_roi.top)); +} + +void ResourceDefault::ResourceStateLog() { + DLOGV_IF(kTagResources, "==== resource manager pipe state ===="); + uint32_t i; + for (i = 0; i < num_pipe_; i++) { + SourcePipe *src_pipe = &src_pipes_[i]; + DLOGV_IF(kTagResources, "index = %d, id = %x, hw_block = %d, owner = %s", + src_pipe->index, src_pipe->mdss_pipe_id, src_pipe->hw_block_id, + (src_pipe->owner == kPipeOwnerUserMode) ? "user mode" : "kernel mode"); + } +} + +DisplayError ResourceDefault::SrcSplitConfig(DisplayResourceContext *display_resource_ctx, + const LayerRect &src_rect, const LayerRect &dst_rect, + HWLayerConfig *layer_config) { + HWPipeInfo *left_pipe = &layer_config->left_pipe; + HWPipeInfo *right_pipe = &layer_config->right_pipe; + float src_width = src_rect.right - src_rect.left; + float dst_width = dst_rect.right - dst_rect.left; + + // Layer cannot qualify for SrcSplit if source or destination width exceeds max pipe width. + if ((src_width > hw_res_info_.max_pipe_width) || (dst_width > hw_res_info_.max_pipe_width)) { + SplitRect(src_rect, dst_rect, &left_pipe->src_roi, &left_pipe->dst_roi, &right_pipe->src_roi, + &right_pipe->dst_roi); + left_pipe->valid = true; + right_pipe->valid = true; + } else { + left_pipe->src_roi = src_rect; + left_pipe->dst_roi = dst_rect; + left_pipe->valid = true; + right_pipe->Reset(); + } + + return kErrorNone; +} + +DisplayError ResourceDefault::DisplaySplitConfig(DisplayResourceContext *display_resource_ctx, + const LayerRect &src_rect, const LayerRect &dst_rect, + HWLayerConfig *layer_config) { + HWMixerAttributes &mixer_attributes = display_resource_ctx->mixer_attributes; + + // for display split case + HWPipeInfo *left_pipe = &layer_config->left_pipe; + HWPipeInfo *right_pipe = &layer_config->right_pipe; + LayerRect scissor_left, scissor_right, dst_left, crop_left, crop_right, dst_right; + + scissor_left.right = FLOAT(mixer_attributes.split_left); + scissor_left.bottom = FLOAT(mixer_attributes.height); + + scissor_right.left = FLOAT(mixer_attributes.split_left); + scissor_right.top = 0.0f; + scissor_right.right = FLOAT(mixer_attributes.width); + scissor_right.bottom = FLOAT(mixer_attributes.height); + + crop_left = src_rect; + dst_left = dst_rect; + crop_right = crop_left; + dst_right = dst_left; + + bool crop_left_valid = CalculateCropRects(scissor_left, &crop_left, &dst_left); + bool crop_right_valid = false; + + if (IsValid(scissor_right)) { + crop_right_valid = CalculateCropRects(scissor_right, &crop_right, &dst_right); + } + + // Reset left_pipe and right_pipe to invalid by default + left_pipe->Reset(); + right_pipe->Reset(); + + if (crop_left_valid) { + // assign left pipe + left_pipe->src_roi = crop_left; + left_pipe->dst_roi = dst_left; + left_pipe->valid = true; + } + + // assign right pipe if needed + if (crop_right_valid) { + right_pipe->src_roi = crop_right; + right_pipe->dst_roi = dst_right; + right_pipe->valid = true; + } + + return kErrorNone; +} + +DisplayError ResourceDefault::Config(DisplayResourceContext *display_resource_ctx, + HWLayers *hw_layers) { + HWLayersInfo &layer_info = hw_layers->info; + DisplayError error = kErrorNone; + const Layer &layer = layer_info.hw_layers.at(0); + + error = ValidateLayerParams(&layer); + if (error != kErrorNone) { + return error; + } + + struct HWLayerConfig *layer_config = &hw_layers->config[0]; + HWPipeInfo &left_pipe = layer_config->left_pipe; + HWPipeInfo &right_pipe = layer_config->right_pipe; + + LayerRect src_rect = layer.src_rect; + LayerRect dst_rect = layer.dst_rect; + + error = ValidateDimensions(src_rect, dst_rect); + if (error != kErrorNone) { + return error; + } + + BufferLayout layout = GetBufferLayout(layer.input_buffer.format); + error = ValidateScaling(src_rect, dst_rect, false /*rotated90 */, layout, + false /* use_rotator_downscale */); + if (error != kErrorNone) { + return error; + } + + if (hw_res_info_.is_src_split) { + error = SrcSplitConfig(display_resource_ctx, src_rect, dst_rect, layer_config); + } else { + error = DisplaySplitConfig(display_resource_ctx, src_rect, dst_rect, layer_config); + } + + if (error != kErrorNone) { + return error; + } + + error = AlignPipeConfig(&layer, &left_pipe, &right_pipe); + if (error != kErrorNone) { + return error; + } + + // set z_order, left_pipe should always be valid + left_pipe.z_order = 0; + + DLOGV_IF(kTagResources, "==== FB layer Config ===="); + Log(kTagResources, "input layer src_rect", layer.src_rect); + Log(kTagResources, "input layer dst_rect", layer.dst_rect); + Log(kTagResources, "cropped src_rect", src_rect); + Log(kTagResources, "cropped dst_rect", dst_rect); + Log(kTagResources, "left pipe src", layer_config->left_pipe.src_roi); + Log(kTagResources, "left pipe dst", layer_config->left_pipe.dst_roi); + if (right_pipe.valid) { + right_pipe.z_order = 0; + Log(kTagResources, "right pipe src", layer_config->right_pipe.src_roi); + Log(kTagResources, "right pipe dst", layer_config->right_pipe.dst_roi); + } + + return error; +} + +bool ResourceDefault::CalculateCropRects(const LayerRect &scissor, LayerRect *crop, + LayerRect *dst) { + float &crop_left = crop->left; + float &crop_top = crop->top; + float &crop_right = crop->right; + float &crop_bottom = crop->bottom; + float crop_width = crop->right - crop->left; + float crop_height = crop->bottom - crop->top; + + float &dst_left = dst->left; + float &dst_top = dst->top; + float &dst_right = dst->right; + float &dst_bottom = dst->bottom; + float dst_width = dst->right - dst->left; + float dst_height = dst->bottom - dst->top; + + const float &sci_left = scissor.left; + const float &sci_top = scissor.top; + const float &sci_right = scissor.right; + const float &sci_bottom = scissor.bottom; + + float left_cut_ratio = 0.0, right_cut_ratio = 0.0, top_cut_ratio = 0.0, bottom_cut_ratio = 0.0; + bool need_cut = false; + + if (dst_left < sci_left) { + left_cut_ratio = (sci_left - dst_left) / dst_width; + dst_left = sci_left; + need_cut = true; + } + + if (dst_right > sci_right) { + right_cut_ratio = (dst_right - sci_right) / dst_width; + dst_right = sci_right; + need_cut = true; + } + + if (dst_top < sci_top) { + top_cut_ratio = (sci_top - dst_top) / (dst_height); + dst_top = sci_top; + need_cut = true; + } + + if (dst_bottom > sci_bottom) { + bottom_cut_ratio = (dst_bottom - sci_bottom) / (dst_height); + dst_bottom = sci_bottom; + need_cut = true; + } + + if (!need_cut) + return true; + + crop_left += crop_width * left_cut_ratio; + crop_top += crop_height * top_cut_ratio; + crop_right -= crop_width * right_cut_ratio; + crop_bottom -= crop_height * bottom_cut_ratio; + Normalize(1, 1, crop); + Normalize(1, 1, dst); + if (IsValid(*crop) && IsValid(*dst)) + return true; + else + return false; +} + +DisplayError ResourceDefault::ValidateLayerParams(const Layer *layer) { + const LayerRect &src = layer->src_rect; + const LayerRect &dst = layer->dst_rect; + const LayerBuffer &input_buffer = layer->input_buffer; + + if (input_buffer.format == kFormatInvalid) { + DLOGV_IF(kTagResources, "Invalid input buffer format %d", input_buffer.format); + return kErrorNotSupported; + } + + if (!IsValid(src) || !IsValid(dst)) { + Log(kTagResources, "input layer src_rect", src); + Log(kTagResources, "input layer dst_rect", dst); + return kErrorNotSupported; + } + + // Make sure source in integral only if it is a non secure layer. + if (!input_buffer.flags.secure && + ((src.left - roundf(src.left) != 0.0f) || + (src.top - roundf(src.top) != 0.0f) || + (src.right - roundf(src.right) != 0.0f) || + (src.bottom - roundf(src.bottom) != 0.0f))) { + DLOGV_IF(kTagResources, "Input ROI is not integral"); + return kErrorNotSupported; + } + + return kErrorNone; +} + +DisplayError ResourceDefault::ValidateDimensions(const LayerRect &crop, const LayerRect &dst) { + if (!IsValid(crop)) { + Log(kTagResources, "Invalid crop rect", crop); + return kErrorNotSupported; + } + + if (!IsValid(dst)) { + Log(kTagResources, "Invalid dst rect", dst); + return kErrorNotSupported; + } + + float crop_width = crop.right - crop.left; + float crop_height = crop.bottom - crop.top; + float dst_width = dst.right - dst.left; + float dst_height = dst.bottom - dst.top; + + if ((UINT32(crop_width - dst_width) == 1) || (UINT32(crop_height - dst_height) == 1)) { + DLOGV_IF(kTagResources, "One pixel downscaling detected crop_w = %.0f, dst_w = %.0f, " \ + "crop_h = %.0f, dst_h = %.0f", crop_width, dst_width, crop_height, dst_height); + return kErrorNotSupported; + } + + return kErrorNone; +} + +DisplayError ResourceDefault::ValidatePipeParams(HWPipeInfo *pipe_info, LayerBufferFormat format) { + DisplayError error = kErrorNone; + + const LayerRect &src_rect = pipe_info->src_roi; + const LayerRect &dst_rect = pipe_info->dst_roi; + + error = ValidateDimensions(src_rect, dst_rect); + if (error != kErrorNone) { + return error; + } + + BufferLayout layout = GetBufferLayout(format); + error = ValidateScaling(src_rect, dst_rect, false /* rotated90 */, layout, + false /* use_rotator_downscale */); + if (error != kErrorNone) { + return error; + } + + return kErrorNone; +} + +DisplayError ResourceDefault::ValidateScaling(const LayerRect &crop, const LayerRect &dst, + bool rotate90, BufferLayout layout, + bool use_rotator_downscale) { + DisplayError error = kErrorNone; + + float scale_x = 1.0f; + float scale_y = 1.0f; + + error = GetScaleFactor(crop, dst, &scale_x, &scale_y); + if (error != kErrorNone) { + return error; + } + + error = ValidateDownScaling(scale_x, scale_y, (layout != kLinear)); + if (error != kErrorNone) { + return error; + } + + error = ValidateUpScaling(scale_x, scale_y); + if (error != kErrorNone) { + return error; + } + + return kErrorNone; +} + +DisplayError ResourceDefault::ValidateDownScaling(float scale_x, float scale_y, bool ubwc_tiled) { + if ((UINT32(scale_x) > 1) || (UINT32(scale_y) > 1)) { + float max_scale_down = FLOAT(hw_res_info_.max_scale_down); + + // MDP H/W cannot apply decimation on UBWC tiled framebuffer + if (!ubwc_tiled && hw_res_info_.has_decimation) { + max_scale_down *= FLOAT(kMaxDecimationDownScaleRatio); + } + + if (scale_x > max_scale_down || scale_y > max_scale_down) { + DLOGV_IF(kTagResources, + "Scaling down is over the limit: scale_x = %.0f, scale_y = %.0f, " \ + "has_deci = %d", scale_x, scale_y, hw_res_info_.has_decimation); + return kErrorNotSupported; + } + } + + DLOGV_IF(kTagResources, "scale_x = %.4f, scale_y = %.4f", scale_x, scale_y); + + return kErrorNone; +} + +DisplayError ResourceDefault::ValidateUpScaling(float scale_x, float scale_y) { + float max_scale_up = FLOAT(hw_res_info_.max_scale_up); + + if (UINT32(scale_x) < 1 && scale_x > 0.0f) { + if ((1.0f / scale_x) > max_scale_up) { + DLOGV_IF(kTagResources, "Scaling up is over limit scale_x = %f", 1.0f / scale_x); + return kErrorNotSupported; + } + } + + if (UINT32(scale_y) < 1 && scale_y > 0.0f) { + if ((1.0f / scale_y) > max_scale_up) { + DLOGV_IF(kTagResources, "Scaling up is over limit scale_y = %f", 1.0f / scale_y); + return kErrorNotSupported; + } + } + + DLOGV_IF(kTagResources, "scale_x = %.4f, scale_y = %.4f", scale_x, scale_y); + + return kErrorNone; +} + +DisplayError ResourceDefault::GetScaleFactor(const LayerRect &crop, const LayerRect &dst, + float *scale_x, float *scale_y) { + float crop_width = crop.right - crop.left; + float crop_height = crop.bottom - crop.top; + float dst_width = dst.right - dst.left; + float dst_height = dst.bottom - dst.top; + + *scale_x = crop_width / dst_width; + *scale_y = crop_height / dst_height; + + return kErrorNone; +} + +DisplayError ResourceDefault::SetDecimationFactor(HWPipeInfo *pipe) { + float src_h = pipe->src_roi.bottom - pipe->src_roi.top; + float dst_h = pipe->dst_roi.bottom - pipe->dst_roi.top; + float down_scale_h = src_h / dst_h; + + float src_w = pipe->src_roi.right - pipe->src_roi.left; + float dst_w = pipe->dst_roi.right - pipe->dst_roi.left; + float down_scale_w = src_w / dst_w; + + pipe->horizontal_decimation = 0; + pipe->vertical_decimation = 0; + + if (CalculateDecimation(down_scale_w, &pipe->horizontal_decimation) != kErrorNone) { + return kErrorNotSupported; + } + + if (CalculateDecimation(down_scale_h, &pipe->vertical_decimation) != kErrorNone) { + return kErrorNotSupported; + } + + DLOGI_IF(kTagResources, "horizontal_decimation %d, vertical_decimation %d", + pipe->horizontal_decimation, pipe->vertical_decimation); + + return kErrorNone; +} + +void ResourceDefault::SplitRect(const LayerRect &src_rect, const LayerRect &dst_rect, + LayerRect *src_left, LayerRect *dst_left, LayerRect *src_right, + LayerRect *dst_right) { + // Split rectangle horizontally and evenly into two. + float src_width = src_rect.right - src_rect.left; + float dst_width = dst_rect.right - dst_rect.left; + float src_width_ori = src_width; + src_width = ROUND_UP_ALIGN_DOWN(src_width / 2, 1); + dst_width = ROUND_UP_ALIGN_DOWN(dst_width * src_width / src_width_ori, 1); + + src_left->left = src_rect.left; + src_left->right = src_rect.left + src_width; + src_right->left = src_left->right; + src_right->right = src_rect.right; + + src_left->top = src_rect.top; + src_left->bottom = src_rect.bottom; + src_right->top = src_rect.top; + src_right->bottom = src_rect.bottom; + + dst_left->top = dst_rect.top; + dst_left->bottom = dst_rect.bottom; + dst_right->top = dst_rect.top; + dst_right->bottom = dst_rect.bottom; + + dst_left->left = dst_rect.left; + dst_left->right = dst_rect.left + dst_width; + dst_right->left = dst_left->right; + dst_right->right = dst_rect.right; +} + +DisplayError ResourceDefault::AlignPipeConfig(const Layer *layer, HWPipeInfo *left_pipe, + HWPipeInfo *right_pipe) { + DisplayError error = kErrorNone; + if (!left_pipe->valid) { + DLOGE_IF(kTagResources, "left_pipe should not be invalid"); + return kErrorNotSupported; + } + + error = ValidatePipeParams(left_pipe, layer->input_buffer.format); + if (error != kErrorNone) { + goto PipeConfigExit; + } + + if (right_pipe->valid) { + // Make sure the left and right ROI are conjunct + right_pipe->src_roi.left = left_pipe->src_roi.right; + right_pipe->dst_roi.left = left_pipe->dst_roi.right; + error = ValidatePipeParams(right_pipe, layer->input_buffer.format); + } + +PipeConfigExit: + if (error != kErrorNone) { + DLOGV_IF(kTagResources, "AlignPipeConfig failed"); + } + return error; +} + +DisplayError ResourceDefault::CalculateDecimation(float downscale, uint8_t *decimation) { + float max_down_scale = FLOAT(hw_res_info_.max_scale_down); + + if (downscale <= max_down_scale) { + *decimation = 0; + return kErrorNone; + } else if (!hw_res_info_.has_decimation) { + DLOGE("Downscaling exceeds the maximum MDP downscale limit but decimation not enabled"); + return kErrorNotSupported; + } + + // Decimation is the remaining downscale factor after doing max SDE downscale. + // In SDE, decimation is supported in powers of 2. + // For ex: If a pipe needs downscale of 8 but max_down_scale is 4 + // So decimation = powf(2.0, ceilf(log2f(8 / 4))) = powf(2.0, 1.0) = 2 + *decimation = UINT8(ceilf(log2f(downscale / max_down_scale))); + return kErrorNone; +} + +DisplayError ResourceDefault::ValidateCursorConfig(Handle display_ctx, const Layer *layer, + bool is_top) { + return kErrorNotSupported; +} + +DisplayError ResourceDefault::ValidateAndSetCursorPosition(Handle display_ctx, HWLayers *hw_layers, + int x, int y, + DisplayConfigVariableInfo *fb_config) { + return kErrorNotSupported; +} + +DisplayError ResourceDefault::SetMaxBandwidthMode(HWBwModes mode) { + return kErrorNotSupported; +} + +DisplayError ResourceDefault::GetScaleLutConfig(HWScaleLutInfo *lut_info) { + return kErrorNone; +} + +DisplayError ResourceDefault::SetDetailEnhancerData(Handle display_ctx, + const DisplayDetailEnhancerData &de_data) { + return kErrorNotSupported; +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/core/resource_default.h b/msm8909/sdm/libs/core/resource_default.h new file mode 100644 index 00000000..a67eb09b --- /dev/null +++ b/msm8909/sdm/libs/core/resource_default.h @@ -0,0 +1,150 @@ +/* +* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __RESOURCE_DEFAULT_H__ +#define __RESOURCE_DEFAULT_H__ + +#include <core/display_interface.h> +#include <private/resource_interface.h> +#include <utils/locker.h> +#include <vector> + +#include "hw_interface.h" + +namespace sdm { + +class ResourceDefault : public ResourceInterface { + public: + static DisplayError CreateResourceDefault(const HWResourceInfo &hw_resource_info, + ResourceInterface **resource_intf); + static DisplayError DestroyResourceDefault(ResourceInterface *resource_intf); + virtual DisplayError RegisterDisplay(DisplayType type, + const HWDisplayAttributes &display_attributes, + const HWPanelInfo &hw_panel_info, + const HWMixerAttributes &mixer_attributes, + Handle *display_ctx); + virtual DisplayError UnregisterDisplay(Handle display_ctx); + virtual DisplayError ReconfigureDisplay(Handle display_ctx, + const HWDisplayAttributes &display_attributes, + const HWPanelInfo &hw_panel_info, + const HWMixerAttributes &mixer_attributes); + virtual DisplayError Start(Handle display_ctx); + virtual DisplayError Stop(Handle display_ctx, HWLayers *hw_layers); + virtual DisplayError Prepare(Handle display_ctx, HWLayers *hw_layers); + virtual DisplayError PostPrepare(Handle display_ctx, HWLayers *hw_layers); + virtual DisplayError Commit(Handle display_ctx, HWLayers *hw_layers); + virtual DisplayError PostCommit(Handle display_ctx, HWLayers *hw_layers); + virtual void Purge(Handle display_ctx); + virtual DisplayError SetMaxMixerStages(Handle display_ctx, uint32_t max_mixer_stages); + virtual DisplayError ValidateScaling(const LayerRect &crop, const LayerRect &dst, bool rotate90, + BufferLayout layout, bool use_rotator_downscale); + DisplayError ValidateCursorConfig(Handle display_ctx, const Layer *layer, bool is_top); + DisplayError ValidateAndSetCursorPosition(Handle display_ctx, HWLayers *hw_layers, int x, int y, + DisplayConfigVariableInfo *fb_config); + DisplayError SetMaxBandwidthMode(HWBwModes mode); + virtual DisplayError SetDetailEnhancerData(Handle display_ctx, + const DisplayDetailEnhancerData &de_data); + virtual DisplayError Perform(int cmd, ...) { return kErrorNone; } + + private: + enum PipeOwner { + kPipeOwnerUserMode, // Pipe state when it is available for reservation + kPipeOwnerKernelMode, // Pipe state when pipe is owned by kernel + }; + + // todo: retrieve all these from kernel + enum { + kMaxDecimationDownScaleRatio = 16, + }; + + struct SourcePipe { + PipeType type; + PipeOwner owner; + uint32_t mdss_pipe_id; + uint32_t index; + HWBlockType hw_block_id; + int priority; + + SourcePipe() : type(kPipeTypeUnused), owner(kPipeOwnerUserMode), mdss_pipe_id(0), + index(0), hw_block_id(kHWBlockMax), priority(0) { } + + inline void ResetState() { hw_block_id = kHWBlockMax;} + }; + + struct DisplayResourceContext { + HWDisplayAttributes display_attributes; + HWBlockType hw_block_id; + uint64_t frame_count; + HWMixerAttributes mixer_attributes; + + DisplayResourceContext() : hw_block_id(kHWBlockMax), frame_count(0) { } + }; + + struct HWBlockContext { + bool is_in_use; + HWBlockContext() : is_in_use(false) { } + }; + + explicit ResourceDefault(const HWResourceInfo &hw_res_info); + DisplayError Init(); + DisplayError Deinit(); + uint32_t NextPipe(PipeType pipe_type, HWBlockType hw_block_id); + uint32_t SearchPipe(HWBlockType hw_block_id, SourcePipe *src_pipes, uint32_t num_pipe); + uint32_t GetPipe(HWBlockType hw_block_id, bool need_scale); + bool IsScalingNeeded(const HWPipeInfo *pipe_info); + DisplayError Config(DisplayResourceContext *display_resource_ctx, HWLayers *hw_layers); + DisplayError DisplaySplitConfig(DisplayResourceContext *display_resource_ctx, + const LayerRect &src_rect, const LayerRect &dst_rect, + HWLayerConfig *layer_config); + DisplayError SrcSplitConfig(DisplayResourceContext *display_resource_ctx, + const LayerRect &src_rect, const LayerRect &dst_rect, + HWLayerConfig *layer_config); + bool CalculateCropRects(const LayerRect &scissor, LayerRect *crop, LayerRect *dst); + DisplayError ValidateLayerParams(const Layer *layer); + DisplayError ValidateDimensions(const LayerRect &crop, const LayerRect &dst); + DisplayError ValidatePipeParams(HWPipeInfo *pipe_info, LayerBufferFormat format); + DisplayError ValidateDownScaling(float scale_x, float scale_y, bool ubwc_tiled); + DisplayError ValidateUpScaling(float scale_x, float scale_y); + DisplayError GetScaleFactor(const LayerRect &crop, const LayerRect &dst, float *scale_x, + float *scale_y); + DisplayError SetDecimationFactor(HWPipeInfo *pipe); + void SplitRect(const LayerRect &src_rect, const LayerRect &dst_rect, LayerRect *src_left, + LayerRect *dst_left, LayerRect *src_right, LayerRect *dst_right); + DisplayError AlignPipeConfig(const Layer *layer, HWPipeInfo *left_pipe, + HWPipeInfo *right_pipe); + void ResourceStateLog(void); + DisplayError CalculateDecimation(float downscale, uint8_t *decimation); + DisplayError GetScaleLutConfig(HWScaleLutInfo *lut_info); + + Locker locker_; + HWResourceInfo hw_res_info_; + HWBlockContext hw_block_ctx_[kHWBlockMax]; + std::vector<SourcePipe> src_pipes_; + uint32_t num_pipe_ = 0; +}; + +} // namespace sdm + +#endif // __RESOURCE_DEFAULT_H__ + diff --git a/msm8909/sdm/libs/core/strategy.cpp b/msm8909/sdm/libs/core/strategy.cpp new file mode 100644 index 00000000..8398bbd4 --- /dev/null +++ b/msm8909/sdm/libs/core/strategy.cpp @@ -0,0 +1,265 @@ +/* +* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <utils/constants.h> +#include <utils/debug.h> + +#include "strategy.h" +#include "utils/rect.h" + +#define __CLASS__ "Strategy" + +namespace sdm { + +Strategy::Strategy(ExtensionInterface *extension_intf, BufferAllocator *buffer_allocator, + DisplayType type, + const HWResourceInfo &hw_resource_info, const HWPanelInfo &hw_panel_info, + const HWMixerAttributes &mixer_attributes, + const HWDisplayAttributes &display_attributes, + const DisplayConfigVariableInfo &fb_config) + : extension_intf_(extension_intf), display_type_(type), hw_resource_info_(hw_resource_info), + hw_panel_info_(hw_panel_info), mixer_attributes_(mixer_attributes), + display_attributes_(display_attributes), fb_config_(fb_config), + buffer_allocator_(buffer_allocator) { +} + +DisplayError Strategy::Init() { + DisplayError error = kErrorNone; + + if (extension_intf_) { + error = extension_intf_->CreateStrategyExtn(display_type_, buffer_allocator_, hw_resource_info_, + hw_panel_info_, mixer_attributes_, fb_config_, + &strategy_intf_); + if (error != kErrorNone) { + DLOGE("Failed to create strategy"); + return error; + } + + error = extension_intf_->CreatePartialUpdate(display_type_, hw_resource_info_, hw_panel_info_, + mixer_attributes_, display_attributes_, fb_config_, + &partial_update_intf_); + } + + return kErrorNone; +} + +DisplayError Strategy::Deinit() { + if (strategy_intf_) { + if (partial_update_intf_) { + extension_intf_->DestroyPartialUpdate(partial_update_intf_); + } + + extension_intf_->DestroyStrategyExtn(strategy_intf_); + } + + return kErrorNone; +} + +DisplayError Strategy::Start(HWLayersInfo *hw_layers_info, uint32_t *max_attempts, + const PUConstraints &pu_constraints) { + DisplayError error = kErrorNone; + + hw_layers_info_ = hw_layers_info; + extn_start_success_ = false; + tried_default_ = false; + + if (!disable_gpu_comp_ && !hw_layers_info_->gpu_target_index) { + DLOGE("GPU composition is enabled and GPU target buffer not provided."); + return kErrorNotSupported; + } + + if (partial_update_intf_) { + partial_update_intf_->Start(pu_constraints); + } + GenerateROI(); + + if (strategy_intf_) { + error = strategy_intf_->Start(hw_layers_info_, max_attempts); + if (error == kErrorNone) { + extn_start_success_ = true; + return kErrorNone; + } + } + + *max_attempts = 1; + + return kErrorNone; +} + +DisplayError Strategy::Stop() { + if (strategy_intf_) { + return strategy_intf_->Stop(); + } + + return kErrorNone; +} + +DisplayError Strategy::GetNextStrategy(StrategyConstraints *constraints) { + DisplayError error = kErrorNone; + + if (extn_start_success_) { + error = strategy_intf_->GetNextStrategy(constraints); + if (error == kErrorNone) { + return kErrorNone; + } + } + + // Do not fallback to GPU if GPU comp is disabled. + if (disable_gpu_comp_) { + return kErrorNotSupported; + } + + // Default composition is already tried. + if (tried_default_) { + return kErrorUndefined; + } + + // Mark all application layers for GPU composition. Find GPU target buffer and store its index for + // programming the hardware. + LayerStack *layer_stack = hw_layers_info_->stack; + for (uint32_t i = 0; i < hw_layers_info_->app_layer_count; i++) { + layer_stack->layers.at(i)->composition = kCompositionGPU; + layer_stack->layers.at(i)->request.flags.request_flags = 0; // Reset layer request + } + + if (!extn_start_success_) { + // When mixer resolution and panel resolutions are same (1600x2560) and FB resolution is + // 1080x1920 FB_Target destination coordinates(mapped to FB resolution 1080x1920) need to + // be mapped to destination coordinates of mixer resolution(1600x2560). + Layer *gpu_target_layer = layer_stack->layers.at(hw_layers_info_->gpu_target_index); + float layer_mixer_width = FLOAT(mixer_attributes_.width); + float layer_mixer_height = FLOAT(mixer_attributes_.height); + float fb_width = FLOAT(fb_config_.x_pixels); + float fb_height = FLOAT(fb_config_.y_pixels); + LayerRect src_domain = (LayerRect){0.0f, 0.0f, fb_width, fb_height}; + LayerRect dst_domain = (LayerRect){0.0f, 0.0f, layer_mixer_width, layer_mixer_height}; + + Layer layer = *gpu_target_layer; + hw_layers_info_->index[0] = hw_layers_info_->gpu_target_index; + MapRect(src_domain, dst_domain, layer.dst_rect, &layer.dst_rect); + hw_layers_info_->hw_layers.clear(); + hw_layers_info_->hw_layers.push_back(layer); + } + + tried_default_ = true; + + return kErrorNone; +} + +void Strategy::GenerateROI() { + bool split_display = false; + + if (partial_update_intf_ && partial_update_intf_->GenerateROI(hw_layers_info_) == kErrorNone) { + return; + } + + float layer_mixer_width = mixer_attributes_.width; + float layer_mixer_height = mixer_attributes_.height; + + if (!hw_resource_info_.is_src_split && display_attributes_.is_device_split) { + split_display = true; + } + + hw_layers_info_->left_frame_roi = {}; + hw_layers_info_->right_frame_roi = {}; + + if (split_display) { + float left_split = FLOAT(mixer_attributes_.split_left); + hw_layers_info_->left_frame_roi.push_back(LayerRect(0.0f, 0.0f, + left_split, layer_mixer_height)); + hw_layers_info_->right_frame_roi.push_back(LayerRect(left_split, + 0.0f, layer_mixer_width, layer_mixer_height)); + } else { + hw_layers_info_->left_frame_roi.push_back(LayerRect(0.0f, 0.0f, + layer_mixer_width, layer_mixer_height)); + hw_layers_info_->right_frame_roi.push_back(LayerRect(0.0f, 0.0f, 0.0f, 0.0f)); + } +} + +DisplayError Strategy::Reconfigure(const HWPanelInfo &hw_panel_info, + const HWDisplayAttributes &display_attributes, + const HWMixerAttributes &mixer_attributes, + const DisplayConfigVariableInfo &fb_config) { + DisplayError error = kErrorNone; + + if (!extension_intf_) { + return kErrorNone; + } + + // TODO(user): PU Intf will not be created for video mode panels, hence re-evaluate if + // reconfigure is needed. + if (partial_update_intf_) { + extension_intf_->DestroyPartialUpdate(partial_update_intf_); + partial_update_intf_ = NULL; + } + + extension_intf_->CreatePartialUpdate(display_type_, hw_resource_info_, hw_panel_info, + mixer_attributes, display_attributes, fb_config, + &partial_update_intf_); + + error = strategy_intf_->Reconfigure(hw_panel_info, hw_resource_info_, mixer_attributes, + fb_config); + if (error != kErrorNone) { + return error; + } + + hw_panel_info_ = hw_panel_info; + display_attributes_ = display_attributes; + mixer_attributes_ = mixer_attributes; + fb_config_ = fb_config; + + return kErrorNone; +} + +DisplayError Strategy::SetCompositionState(LayerComposition composition_type, bool enable) { + DLOGI("composition type = %d, enable = %d", composition_type, enable); + + if (composition_type == kCompositionGPU) { + disable_gpu_comp_ = !enable; + } + + if (strategy_intf_) { + return strategy_intf_->SetCompositionState(composition_type, enable); + } + + return kErrorNone; +} + +DisplayError Strategy::Purge() { + if (strategy_intf_) { + return strategy_intf_->Purge(); + } + + return kErrorNone; +} + +DisplayError Strategy::SetIdleTimeoutMs(uint32_t active_ms) { + if (strategy_intf_) { + return strategy_intf_->SetIdleTimeoutMs(active_ms); + } + + return kErrorNotSupported; +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/core/strategy.h b/msm8909/sdm/libs/core/strategy.h new file mode 100644 index 00000000..f05f66b6 --- /dev/null +++ b/msm8909/sdm/libs/core/strategy.h @@ -0,0 +1,79 @@ +/* +* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __STRATEGY_H__ +#define __STRATEGY_H__ + +#include <core/display_interface.h> +#include <private/extension_interface.h> +#include <core/buffer_allocator.h> + +namespace sdm { + +class Strategy { + public: + Strategy(ExtensionInterface *extension_intf, BufferAllocator *buffer_allocator, + DisplayType type, + const HWResourceInfo &hw_resource_info, const HWPanelInfo &hw_panel_info, + const HWMixerAttributes &mixer_attributes, const HWDisplayAttributes &display_attributes, + const DisplayConfigVariableInfo &fb_config); + + DisplayError Init(); + DisplayError Deinit(); + + DisplayError Start(HWLayersInfo *hw_layers_info, uint32_t *max_attempts, + const PUConstraints &pu_constraints); + DisplayError GetNextStrategy(StrategyConstraints *constraints); + DisplayError Stop(); + DisplayError Reconfigure(const HWPanelInfo &hw_panel_info, + const HWDisplayAttributes &hw_display_attributes, + const HWMixerAttributes &mixer_attributes, + const DisplayConfigVariableInfo &fb_config); + DisplayError SetCompositionState(LayerComposition composition_type, bool enable); + DisplayError Purge(); + DisplayError SetIdleTimeoutMs(uint32_t active_ms); + + private: + void GenerateROI(); + + ExtensionInterface *extension_intf_ = NULL; + StrategyInterface *strategy_intf_ = NULL; + PartialUpdateInterface *partial_update_intf_ = NULL; + DisplayType display_type_; + HWResourceInfo hw_resource_info_; + HWPanelInfo hw_panel_info_; + HWLayersInfo *hw_layers_info_ = NULL; + HWMixerAttributes mixer_attributes_ = {}; + HWDisplayAttributes display_attributes_ = {}; + DisplayConfigVariableInfo fb_config_ = {}; + bool extn_start_success_ = false; + bool tried_default_ = false; + bool disable_gpu_comp_ = false; + BufferAllocator *buffer_allocator_ = NULL; +}; + +} // namespace sdm + +#endif // __STRATEGY_H__ + diff --git a/msm8909/sdm/libs/hwc/Android.mk b/msm8909/sdm/libs/hwc/Android.mk new file mode 100644 index 00000000..a2142e33 --- /dev/null +++ b/msm8909/sdm/libs/hwc/Android.mk @@ -0,0 +1,39 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +include $(LOCAL_PATH)/../../../common.mk +ifeq ($(use_hwc2),false) + +LOCAL_MODULE := hwcomposer.$(TARGET_BOARD_PLATFORM) +LOCAL_VENDOR_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_MODULE_TAGS := optional +LOCAL_C_INCLUDES := $(common_includes) +LOCAL_HEADER_LIBRARIES := display_headers + +LOCAL_CFLAGS := $(common_flags) -Wno-missing-field-initializers -Wno-unused-parameter \ + -std=c++11 -fcolor-diagnostics -Wno-sign-conversion -DLOG_TAG=\"SDM\" +LOCAL_CLANG := true + +LOCAL_SHARED_LIBRARIES := libsdmcore libqservice libbinder libhardware libhardware_legacy \ + libutils libcutils libsync libmemalloc libqdutils libdl \ + libpowermanager libsdmutils libgpu_tonemapper libc++ liblog \ + libdrmutils libui + +LOCAL_SRC_FILES := hwc_session.cpp \ + hwc_display.cpp \ + hwc_display_null.cpp \ + hwc_display_primary.cpp \ + hwc_display_external.cpp \ + hwc_display_virtual.cpp \ + hwc_debugger.cpp \ + hwc_buffer_allocator.cpp \ + hwc_buffer_sync_handler.cpp \ + hwc_color_manager.cpp \ + blit_engine_c2d.cpp \ + cpuhint.cpp \ + hwc_tonemapper.cpp \ + hwc_socket_handler.cpp \ + hwc_display_external_test.cpp + +include $(BUILD_SHARED_LIBRARY) +endif diff --git a/msm8909/sdm/libs/hwc/blit_engine.h b/msm8909/sdm/libs/hwc/blit_engine.h new file mode 100644 index 00000000..6fa9733e --- /dev/null +++ b/msm8909/sdm/libs/hwc/blit_engine.h @@ -0,0 +1,66 @@ +/* +* Copyright (c) 2015, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/*! @file blit_engine.h + @brief Interface file for Blit based compositior. + + @details The client can use this interface to get the blit composition done + +*/ + +#ifndef __BLIT_ENGINE_H__ +#define __BLIT_ENGINE_H__ + +namespace sdm { + +/*! @brief Blit Engine implemented by the client + + @details This class declares prototype for BlitEngine Interface which must be + implemented by the client. HWC will use this interface to use a Blit engine to get the + composition done. + +*/ +class BlitEngine { + public: + BlitEngine() { } + virtual ~BlitEngine() { } + + virtual int Init() = 0; + virtual void DeInit() = 0; + virtual int Prepare(LayerStack *layer_stack) = 0; + virtual int PreCommit(hwc_display_contents_1_t *content_list, LayerStack *layer_stack) = 0; + virtual int Commit(hwc_display_contents_1_t *content_list, LayerStack *layer_stack) = 0; + virtual void PostCommit(LayerStack *layer_stack) = 0; + virtual bool BlitActive() = 0; + virtual void SetFrameDumpConfig(uint32_t count) = 0; +}; + +} // namespace sdm + +#endif // __BLIT_ENGINE_H__ diff --git a/msm8909/sdm/libs/hwc/blit_engine_c2d.cpp b/msm8909/sdm/libs/hwc/blit_engine_c2d.cpp new file mode 100644 index 00000000..4efe2f1a --- /dev/null +++ b/msm8909/sdm/libs/hwc/blit_engine_c2d.cpp @@ -0,0 +1,608 @@ +/* Copyright (c) 2012-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. + +* Portions formerly licensed under Apache License, Version 2.0, are re licensed +* under section 4 of Apache License, Version 2.0. + +* Copyright (C) 2010 The Android Open Source Project + +* Not a Contribution. + +* 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 <hardware/hardware.h> +#include <sync/sync.h> +#include <copybit.h> +#include <memalloc.h> +#include <alloc_controller.h> +#include <gr.h> + +#include <utils/constants.h> +#include <utils/rect.h> +#include <utils/formats.h> +#include <algorithm> + +#include "blit_engine_c2d.h" +#include "hwc_debugger.h" + +#define __CLASS__ "BlitEngineC2D" + +// TODO(user): Remove pragma after fixing sign conversion errors +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wsign-conversion" +#endif + +namespace sdm { + + +BlitEngineC2d::RegionIterator::RegionIterator(LayerRectArray rect) { + rect_array = rect; + r.end = INT(rect.count); + r.current = 0; + this->next = iterate; +} + +int BlitEngineC2d::RegionIterator::iterate(copybit_region_t const *self, copybit_rect_t *rect) { + if (!self || !rect) { + DLOGE("iterate invalid parameters"); + return 0; + } + + RegionIterator const *me = static_cast<RegionIterator const*>(self); + if (me->r.current != me->r.end) { + rect->l = INT(me->rect_array.rect[me->r.current].left); + rect->t = INT(me->rect_array.rect[me->r.current].top); + rect->r = INT(me->rect_array.rect[me->r.current].right); + rect->b = INT(me->rect_array.rect[me->r.current].bottom); + me->r.current++; + return 1; + } + return 0; +} + +BlitEngineC2d::BlitEngineC2d() { + for (uint32_t i = 0; i < kNumBlitTargetBuffers; i++) { + blit_target_buffer_[i] = NULL; + release_fence_fd_[i] = -1; + } +} + +BlitEngineC2d::~BlitEngineC2d() { + if (blit_engine_c2d_) { + copybit_close(blit_engine_c2d_); + blit_engine_c2d_ = NULL; + } + FreeBlitTargetBuffers(); +} + +int BlitEngineC2d::Init() { + hw_module_t const *module; + if (hw_get_module("copybit", &module) == 0) { + if (copybit_open(module, &blit_engine_c2d_) < 0) { + DLOGI("CopyBitC2D Open failed."); + return -1; + } + DLOGI("Opened Copybit Module"); + } else { + DLOGI("Copybit HW Module not found"); + return -1; + } + + return 0; +} + +void BlitEngineC2d::DeInit() { + FreeBlitTargetBuffers(); + if (blit_engine_c2d_) { + copybit_close(blit_engine_c2d_); + blit_engine_c2d_ = NULL; + } +} + +int BlitEngineC2d::AllocateBlitTargetBuffers(uint32_t width, uint32_t height, uint32_t format, + uint32_t usage) { + int status = 0; + if (width <= 0 || height <= 0) { + return false; + } + + if (blit_target_buffer_[0]) { + // Free and reallocate the buffers if the w/h changes + if (INT(width) != blit_target_buffer_[0]->width || + INT(height) != blit_target_buffer_[0]->height) { + FreeBlitTargetBuffers(); + } + } + + for (uint32_t i = 0; i < kNumBlitTargetBuffers; i++) { + if (blit_target_buffer_[i] == NULL) { + status = alloc_buffer(&blit_target_buffer_[i], width, height, format, usage); + } + if (status < 0) { + DLOGE("Allocation of Blit target Buffer failed"); + FreeBlitTargetBuffers(); + break; + } + } + + return status; +} + +void BlitEngineC2d::FreeBlitTargetBuffers() { + for (uint32_t i = 0; i < kNumBlitTargetBuffers; i++) { + private_handle_t **target_buffer = &blit_target_buffer_[i]; + if (*target_buffer) { + // Free the valid fence + if (release_fence_fd_[i] >= 0) { + close(release_fence_fd_[i]); + release_fence_fd_[i] = -1; + } + free_buffer(*target_buffer); + *target_buffer = NULL; + } + } +} + +int BlitEngineC2d::ClearTargetBuffer(private_handle_t* hnd, const LayerRect& rect) { + int status = 0; + copybit_rect_t clear_rect = {INT(rect.left), INT(rect.top), INT(rect.right), INT(rect.bottom)}; + + copybit_image_t buffer; + buffer.w = ALIGN((hnd->width), 32); + buffer.h = hnd->height; + buffer.format = hnd->format; + buffer.base = reinterpret_cast<void *>(hnd->base); + buffer.handle = reinterpret_cast<native_handle_t *>(hnd); + int dst_format_mode = COPYBIT_LINEAR; + if (hnd->flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) { + dst_format_mode = COPYBIT_UBWC_COMPRESSED; + } + blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_DST_FORMAT_MODE, dst_format_mode); + + status = blit_engine_c2d_->clear(blit_engine_c2d_, &buffer, &clear_rect); + return status; +} + +void BlitEngineC2d::PostCommit(LayerStack *layer_stack) { + int fence_fd = -1; + uint32_t count = 0; + int fd = -1; + + for (uint32_t i = blit_target_start_index_-2; (i > 0) && (count < num_blit_target_); i--) { + Layer *layer = layer_stack->layers.at(i); + LayerBuffer &layer_buffer = layer->input_buffer; + if (layer->composition == kCompositionBlit) { + int index = blit_target_start_index_ + count; + layer_buffer.release_fence_fd = + layer_stack->layers.at(index)->input_buffer.release_fence_fd; + fence_fd = layer_buffer.release_fence_fd; + close(layer_buffer.acquire_fence_fd); + layer_buffer.acquire_fence_fd = -1; + layer_stack->layers.at(index)->input_buffer.release_fence_fd = -1; + fd = layer_stack->layers.at(index)->input_buffer.acquire_fence_fd; + layer_stack->layers.at(index)->input_buffer.acquire_fence_fd = -1; + count++; + } + } + + if (fd >= 0) { + // Close the C2D fence FD + close(fd); + } + SetReleaseFence(fence_fd); +} + +// Sync wait to close the previous fd +void BlitEngineC2d::SetReleaseFence(int fd) { + if (release_fence_fd_[current_blit_target_index_] >= 0) { + int ret = -1; + ret = sync_wait(release_fence_fd_[current_blit_target_index_], 1000); + if (ret < 0) { + DLOGE("sync_wait error! errno = %d, err str = %s", errno, strerror(errno)); + } + close(release_fence_fd_[current_blit_target_index_]); + } + release_fence_fd_[current_blit_target_index_] = dup(fd); +} + +bool BlitEngineC2d::BlitActive() { + return blit_active_; +} + +void BlitEngineC2d::SetFrameDumpConfig(uint32_t count) { + dump_frame_count_ = count; + dump_frame_index_ = 0; +} + +int BlitEngineC2d::Prepare(LayerStack *layer_stack) { + blit_target_start_index_ = 0; + + uint32_t layer_count = UINT32(layer_stack->layers.size()); + uint32_t gpu_target_index = layer_count - 1; // default assumption + uint32_t i = 0; + + for (; i < layer_count; i++) { + Layer *layer = layer_stack->layers.at(i); + + // No 10 bit support for C2D + if (Is10BitFormat(layer->input_buffer.format)) { + return -1; + } + + if (layer->composition == kCompositionGPUTarget) { + // Need FBT size for allocating buffers + gpu_target_index = i; + break; + } + } + + if ((layer_count - 1) == gpu_target_index) { + // No blit target layer + return -1; + } + + blit_target_start_index_ = ++i; + num_blit_target_ = layer_count - blit_target_start_index_; + + LayerBuffer &layer_buffer = layer_stack->layers.at(gpu_target_index)->input_buffer; + int fbwidth = INT(layer_buffer.unaligned_width); + int fbheight = INT(layer_buffer.unaligned_height); + if ((fbwidth < 0) || (fbheight < 0)) { + return -1; + } + + current_blit_target_index_ = (current_blit_target_index_ + 1) % kNumBlitTargetBuffers; + int k = blit_target_start_index_; + + for (uint32_t j = 0; j < num_blit_target_; j++, k++) { + Layer *layer = layer_stack->layers.at(k); + LayerBuffer &layer_buffer = layer->input_buffer; + int aligned_w = 0; + int aligned_h = 0; + + // Set the buffer height and width + AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(fbwidth, fbheight/3, + INT(HAL_PIXEL_FORMAT_RGBA_8888), 0, aligned_w, aligned_h); + layer_buffer.width = aligned_w; + layer_buffer.height = aligned_h; + layer_buffer.unaligned_width = fbwidth; + layer_buffer.unaligned_height = fbheight/3; + + layer->plane_alpha = 0xFF; + layer->blending = kBlendingOpaque; + layer->composition = kCompositionBlitTarget; + layer->frame_rate = layer_stack->layers.at(gpu_target_index)->frame_rate; + } + + return 0; +} + +int BlitEngineC2d::PreCommit(hwc_display_contents_1_t *content_list, LayerStack *layer_stack) { + int status = 0; + uint32_t num_app_layers = (uint32_t) content_list->numHwLayers-1; + int target_width = 0; + int target_height = 0; + int target_aligned_width = 0; + int target_aligned_height = 0; + uint32_t processed_blit = 0; + LayerRect dst_rects[kMaxBlitTargetLayers]; + bool blit_needed = false; + uint32_t usage = 0; + + if (!num_app_layers) { + return -1; + } + + for (uint32_t i = num_app_layers-1; (i > 0) && (processed_blit < num_blit_target_); i--) { + Layer *layer = layer_stack->layers.at(i); + if (layer->composition != kCompositionBlit) { + continue; + } + blit_needed = true; + layer_stack->flags.attributes_changed = true; + + Layer *blit_layer = layer_stack->layers.at(blit_target_start_index_ + processed_blit); + LayerRect &blit_src_rect = blit_layer->src_rect; + int width = INT(layer->dst_rect.right - layer->dst_rect.left); + int height = INT(layer->dst_rect.bottom - layer->dst_rect.top); + int aligned_w = 0; + int aligned_h = 0; + usage = GRALLOC_USAGE_PRIVATE_IOMMU_HEAP | GRALLOC_USAGE_HW_TEXTURE; + if (blit_engine_c2d_->get(blit_engine_c2d_, COPYBIT_UBWC_SUPPORT) > 0) { + usage |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + } + // TODO(user): FrameBuffer is assumed to be RGBA + target_width = std::max(target_width, width); + target_height += height; + + AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width, height, + INT(HAL_PIXEL_FORMAT_RGBA_8888), usage, aligned_w, aligned_h); + + target_aligned_width = std::max(target_aligned_width, aligned_w); + target_aligned_height += aligned_h; + + // Left will be zero always + dst_rects[processed_blit].top = FLOAT(target_aligned_height - aligned_h); + dst_rects[processed_blit].right = dst_rects[processed_blit].left + + (layer->dst_rect.right - layer->dst_rect.left); + dst_rects[processed_blit].bottom = (dst_rects[processed_blit].top + + (layer->dst_rect.bottom - layer->dst_rect.top)); + blit_src_rect = dst_rects[processed_blit]; + processed_blit++; + } + + // Allocate a single buffer of RGBA8888 format + if (blit_needed && (AllocateBlitTargetBuffers(target_width, target_height, + HAL_PIXEL_FORMAT_RGBA_8888, usage) < 0)) { + status = -1; + return status; + } + + if (blit_needed) { + for (uint32_t j = 0; j < num_blit_target_; j++) { + Layer *layer = layer_stack->layers.at(j + content_list->numHwLayers); + private_handle_t *target_buffer = blit_target_buffer_[current_blit_target_index_]; + // Set the fd information + layer->input_buffer.width = target_aligned_width; + layer->input_buffer.height = target_aligned_height; + layer->input_buffer.unaligned_width = target_width; + layer->input_buffer.unaligned_height = target_height; + if (target_buffer->flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) { + layer->input_buffer.format = kFormatRGBA8888Ubwc; + } + layer->input_buffer.planes[0].fd = target_buffer->fd; + layer->input_buffer.planes[0].offset = 0; + layer->input_buffer.planes[0].stride = target_buffer->width; + } + } + + return status; +} + +int BlitEngineC2d::Commit(hwc_display_contents_1_t *content_list, LayerStack *layer_stack) { + int fd = -1; + int status = 0; + bool hybrid_present = false; + uint32_t num_app_layers = (uint32_t) content_list->numHwLayers-1; + private_handle_t *target_buffer = blit_target_buffer_[current_blit_target_index_]; + blit_active_ = false; + + if (!num_app_layers) { + return -1; + } + + // if not Blit Targets return + for (uint32_t i = 0; i < num_app_layers; i++) { + Layer *layer = layer_stack->layers.at(i); + if (layer->composition == kCompositionHybrid || layer->composition == kCompositionBlit) { + hybrid_present = true; + } + } + + if (!hybrid_present) { + return status; + } + + // Clear blit target buffer + LayerRect clear_rect; + clear_rect.left = 0; + clear_rect.top = 0; + clear_rect.right = FLOAT(target_buffer->width); + clear_rect.bottom = FLOAT(target_buffer->height); + ClearTargetBuffer(target_buffer, clear_rect); + + int copybit_layer_count = 0; + uint32_t processed_blit = 0; + for (uint32_t i = num_app_layers-1; (i > 0) && (processed_blit < num_blit_target_) && + (status == 0); i--) { + Layer *layer = layer_stack->layers.at(i); + if (layer->composition != kCompositionBlit) { + continue; + } + + for (uint32_t k = 0; k <= i; k++) { + Layer *bottom_layer = layer_stack->layers.at(k); + LayerBuffer &layer_buffer = bottom_layer->input_buffer; + // if layer below the blit layer does not intersect, ignore that layer + LayerRect inter_sect = Intersection(layer->dst_rect, bottom_layer->dst_rect); + if (bottom_layer->composition != kCompositionHybrid && !IsValid(inter_sect)) { + continue; + } + if (bottom_layer->composition == kCompositionGPU || + bottom_layer->composition == kCompositionSDE || + bottom_layer->composition == kCompositionGPUTarget) { + continue; + } + + // For each layer marked as Hybrid, wait for acquire fence and then blit using the C2D + if (layer_buffer.acquire_fence_fd >= 0) { + // Wait for acquire fence on the App buffers. + if (sync_wait(layer_buffer.acquire_fence_fd, 1000) < 0) { + DLOGE("sync_wait error!! error no = %d err str = %s", errno, strerror(errno)); + } + layer_buffer.acquire_fence_fd = -1; + } + hwc_layer_1_t *hwc_layer = &content_list->hwLayers[k]; + LayerRect &src_rect = bottom_layer->blit_regions.at(processed_blit); + Layer *blit_layer = layer_stack->layers.at(blit_target_start_index_ + processed_blit); + LayerRect dest_rect = blit_layer->src_rect; + int ret_val = DrawRectUsingCopybit(hwc_layer, bottom_layer, src_rect, dest_rect); + copybit_layer_count++; + if (ret_val < 0) { + copybit_layer_count = 0; + DLOGE("DrawRectUsingCopyBit failed"); + status = -1; + break; + } + } + processed_blit++; + } + + if (copybit_layer_count) { + blit_active_ = true; + blit_engine_c2d_->flush_get_fence(blit_engine_c2d_, &fd); + } + + if (blit_active_) { + // dump the render buffer + DumpBlitTargetBuffer(fd); + + // Set the fd to the LayerStack BlitTargets fd + uint32_t layer_count = UINT32(layer_stack->layers.size()); + for (uint32_t k = blit_target_start_index_; k < layer_count; k++) { + Layer *layer = layer_stack->layers.at(k); + LayerBuffer &layer_buffer = layer->input_buffer; + layer_buffer.acquire_fence_fd = fd; + } + } + + return status; +} + +int BlitEngineC2d::DrawRectUsingCopybit(hwc_layer_1_t *hwc_layer, Layer *layer, + LayerRect blit_rect, LayerRect blit_dest_Rect) { + private_handle_t *target_buffer = blit_target_buffer_[current_blit_target_index_]; + const private_handle_t *hnd = static_cast<const private_handle_t *>(hwc_layer->handle); + LayerBuffer &layer_buffer = layer->input_buffer; + + // Set the Copybit Source + copybit_image_t src; + src.handle = const_cast<native_handle_t *>(hwc_layer->handle); + src.w = hnd->width; + src.h = hnd->height; + src.base = reinterpret_cast<void *>(hnd->base); + src.format = hnd->format; + src.horiz_padding = 0; + src.vert_padding = 0; + + // Copybit source rect + copybit_rect_t src_rect = {INT(blit_rect.left), INT(blit_rect.top), INT(blit_rect.right), + INT(blit_rect.bottom)}; + + // Copybit destination rect + copybit_rect_t dst_rect = {INT(blit_dest_Rect.left), INT(blit_dest_Rect.top), + INT(blit_dest_Rect.right), INT(blit_dest_Rect.bottom)}; + + // Copybit destination buffer + copybit_image_t dst; + dst.handle = static_cast<native_handle_t *>(target_buffer); + dst.w = ALIGN(target_buffer->width, 32); + dst.h = ALIGN((target_buffer->height), 32); + dst.base = reinterpret_cast<void *>(target_buffer->base); + dst.format = target_buffer->format; + + // Copybit region is the destRect + LayerRect region_rect; + region_rect.left = FLOAT(dst_rect.l); + region_rect.top = FLOAT(dst_rect.t); + region_rect.right = FLOAT(dst_rect.r); + region_rect.bottom = FLOAT(dst_rect.b); + + LayerRectArray region; + region.count = 1; + region.rect = ®ion_rect; + RegionIterator copybitRegion(region); + int acquireFd = layer_buffer.acquire_fence_fd; + + // FRAMEBUFFER_WIDTH/HEIGHT for c2d is the target buffer w/h + blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_FRAMEBUFFER_WIDTH, + target_buffer->width); + blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_FRAMEBUFFER_HEIGHT, + target_buffer->height); + int transform = 0; + if (layer->transform.rotation != 0.0f) transform |= COPYBIT_TRANSFORM_ROT_90; + if (layer->transform.flip_horizontal) transform |= COPYBIT_TRANSFORM_FLIP_H; + if (layer->transform.flip_vertical) transform |= COPYBIT_TRANSFORM_FLIP_V; + blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_TRANSFORM, transform); + blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_PLANE_ALPHA, hwc_layer->planeAlpha); + blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_BLEND_MODE, hwc_layer->blending); + blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_DITHER, + (dst.format == HAL_PIXEL_FORMAT_RGB_565) ? COPYBIT_ENABLE : COPYBIT_DISABLE); + + int src_format_mode = COPYBIT_LINEAR; + if (hnd->flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) { + src_format_mode = COPYBIT_UBWC_COMPRESSED; + } + blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_SRC_FORMAT_MODE, src_format_mode); + + blit_engine_c2d_->set_sync(blit_engine_c2d_, acquireFd); + int err = blit_engine_c2d_->stretch(blit_engine_c2d_, &dst, &src, &dst_rect, &src_rect, + ©bitRegion); + + if (err < 0) { + DLOGE("copybit stretch failed"); + } + + return err; +} + +void BlitEngineC2d::DumpBlitTargetBuffer(int fd) { + if (!dump_frame_count_) { + return; + } + + private_handle_t *target_buffer = blit_target_buffer_[current_blit_target_index_]; + + if (fd >= 0) { + int error = sync_wait(fd, 1000); + if (error < 0) { + DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno)); + return; + } + } + + char dump_file_name[PATH_MAX]; + size_t result = 0; + snprintf(dump_file_name, sizeof(dump_file_name), "/data/misc/display/frame_dump_primary" + "/blit_target_%d.raw", (dump_frame_index_)); + FILE* fp = fopen(dump_file_name, "w+"); + if (fp) { + result = fwrite(reinterpret_cast<void *>(target_buffer->base), target_buffer->size, 1, fp); + fclose(fp); + } + dump_frame_count_--; + dump_frame_index_++; +} + +} // namespace sdm +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + diff --git a/msm8909/sdm/libs/hwc/blit_engine_c2d.h b/msm8909/sdm/libs/hwc/blit_engine_c2d.h new file mode 100644 index 00000000..6536d442 --- /dev/null +++ b/msm8909/sdm/libs/hwc/blit_engine_c2d.h @@ -0,0 +1,121 @@ +/* Copyright (c) 2012 - 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. + +* Portions formerly licensed under Apache License, Version 2.0, are re licensed +* under section 4 of Apache License, Version 2.0. + +* Copyright (C) 2010 The Android Open Source Project + +* Not a Contribution. + +* 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. +*/ + +/*! @file blit_engine.h + @brief Interface file for Blit based compositior. + + @details The client can use this interface to get the blit composition done + +*/ + +#include <hardware/hwcomposer.h> +#include <core/layer_stack.h> +#include <copybit.h> +#include "blit_engine.h" + +#ifndef __BLIT_ENGINE_C2D_H__ +#define __BLIT_ENGINE_C2D_H__ + +namespace sdm { + +// C2D Blit implemented by the client +// This class implements the BlitEngine Interface which is used to get the +// Blit composition using C2D +class BlitEngineC2d : public BlitEngine { + public: + BlitEngineC2d(); + virtual ~BlitEngineC2d(); + + virtual int Init(); + virtual void DeInit(); + virtual int Prepare(LayerStack *layer_stack); + virtual int PreCommit(hwc_display_contents_1_t *content_list, LayerStack *layer_stack); + virtual int Commit(hwc_display_contents_1_t *content_list, LayerStack *layer_stack); + virtual void PostCommit(LayerStack *layer_stack); + virtual bool BlitActive(); + virtual void SetFrameDumpConfig(uint32_t count); + + + private: + static const uint32_t kNumBlitTargetBuffers = 3; + + struct Range { + int current; + int end; + }; + + struct RegionIterator : public copybit_region_t { + explicit RegionIterator(LayerRectArray rect); + private: + static int iterate(copybit_region_t const *self, copybit_rect_t *rect); + LayerRectArray rect_array; + mutable Range r; + }; + + int AllocateBlitTargetBuffers(uint32_t width, uint32_t height, uint32_t format, uint32_t usage); + void FreeBlitTargetBuffers(); + int ClearTargetBuffer(private_handle_t* hnd, const LayerRect& rect); + int DrawRectUsingCopybit(hwc_layer_1_t *hwc_layer, Layer *layer, LayerRect blit_rect, + LayerRect blit_dest_Rect); + void SetReleaseFence(int fence_fd); + void DumpBlitTargetBuffer(int fd); + + copybit_device_t *blit_engine_c2d_ = NULL; + private_handle_t *blit_target_buffer_[kNumBlitTargetBuffers]; + uint32_t current_blit_target_index_ = 0; + int release_fence_fd_[kNumBlitTargetBuffers]; + uint32_t num_blit_target_ = 0; + int blit_target_start_index_ = 0; + bool blit_active_ = false; + uint32_t dump_frame_count_ = 0; + uint32_t dump_frame_index_ = 0; +}; + +} // namespace sdm + +#endif // __BLIT_ENGINE_C2D_H__ diff --git a/msm8909/sdm/libs/hwc/cpuhint.cpp b/msm8909/sdm/libs/hwc/cpuhint.cpp new file mode 100644 index 00000000..2675c9bf --- /dev/null +++ b/msm8909/sdm/libs/hwc/cpuhint.cpp @@ -0,0 +1,108 @@ +/* Copyright (c) 2015,2018 The Linux Foundataion. 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 <dlfcn.h> +#include <utils/debug.h> + +#include "cpuhint.h" +#include "hwc_debugger.h" + +#define __CLASS__ "CPUHint" + +namespace sdm { + +DisplayError CPUHint::Init(HWCDebugHandler *debug_handler) { + char path[PROPERTY_VALUE_MAX]; + if (debug_handler->GetProperty("ro.vendor.extension_library", path) != kErrorNone) { + DLOGI("Vendor Extension Library not enabled"); + return kErrorNotSupported; + } + + int pre_enable_window = -1; + debug_handler->GetProperty(PERF_HINT_WINDOW_PROP, &pre_enable_window); + if (pre_enable_window <= 0) { + DLOGI("Invalid CPU Hint Pre-enable Window %d", pre_enable_window); + return kErrorNotSupported; + } + + DLOGI("CPU Hint Pre-enable Window %d", pre_enable_window); + pre_enable_window_ = pre_enable_window; + + if (vendor_ext_lib_.Open(path)) { + if (!vendor_ext_lib_.Sym("perf_lock_acq", reinterpret_cast<void **>(&fn_lock_acquire_)) || + !vendor_ext_lib_.Sym("perf_lock_rel", reinterpret_cast<void **>(&fn_lock_release_))) { + DLOGW("Failed to load symbols for Vendor Extension Library"); + return kErrorNotSupported; + } + DLOGI("Successfully Loaded Vendor Extension Library symbols"); + enabled_ = true; + } else { + DLOGW("Failed to open %s : %s", path, vendor_ext_lib_.Error()); + } + + return kErrorNone; +} + +void CPUHint::Set() { + if (!enabled_) { + return; + } + if (lock_acquired_) { + return; + } + if (frame_countdown_) { + --frame_countdown_; + return; + } + + int hint = HINT; + lock_handle_ = fn_lock_acquire_(0 /*handle*/, 0/*duration*/, + &hint, sizeof(hint) / sizeof(int)); + if (lock_handle_ >= 0) { + lock_acquired_ = true; + } +} + +void CPUHint::Reset() { + if (!enabled_) { + return; + } + + frame_countdown_ = pre_enable_window_; + + if (!lock_acquired_) { + return; + } + + fn_lock_release_(lock_handle_); + lock_acquired_ = false; +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/hwc/cpuhint.h b/msm8909/sdm/libs/hwc/cpuhint.h new file mode 100644 index 00000000..e7587630 --- /dev/null +++ b/msm8909/sdm/libs/hwc/cpuhint.h @@ -0,0 +1,61 @@ +/* Copyright (c) 2015, The Linux Foundataion. 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 __CPUHINT_H__ +#define __CPUHINT_H__ + +#include <core/sdm_types.h> +#include <utils/sys.h> + +namespace sdm { + +class HWCDebugHandler; + +class CPUHint { + public: + DisplayError Init(HWCDebugHandler *debug_handler); + void Set(); + void Reset(); + + private: + enum { HINT = 0x4501 /* 45-display layer hint, 01-Enable */ }; + bool enabled_ = false; + // frames to wait before setting this hint + int pre_enable_window_ = 0; + int frame_countdown_ = 0; + int lock_handle_ = 0; + bool lock_acquired_ = false; + DynLib vendor_ext_lib_; + int (*fn_lock_acquire_)(int handle, int duration, int *hints, int num_args) = NULL; + int (*fn_lock_release_)(int value) = NULL; +}; + +} // namespace sdm + +#endif // __CPUHINT_H__ diff --git a/msm8909/sdm/libs/hwc/hwc_buffer_allocator.cpp b/msm8909/sdm/libs/hwc/hwc_buffer_allocator.cpp new file mode 100644 index 00000000..25f366f0 --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_buffer_allocator.cpp @@ -0,0 +1,330 @@ +/* +* Copyright (c) 2015 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <gralloc_priv.h> +#include <memalloc.h> +#include <gr.h> +#include <alloc_controller.h> +#include <utils/constants.h> +#include <utils/debug.h> +#include <core/buffer_allocator.h> + +#include "hwc_debugger.h" +#include "hwc_buffer_allocator.h" + +#define __CLASS__ "HWCBufferAllocator" + +namespace sdm { + +HWCBufferAllocator::HWCBufferAllocator() { + alloc_controller_ = gralloc::IAllocController::getInstance(); +} + +DisplayError HWCBufferAllocator::AllocateBuffer(BufferInfo *buffer_info) { + gralloc::alloc_data data; + + const BufferConfig &buffer_config = buffer_info->buffer_config; + AllocatedBufferInfo *alloc_buffer_info = &buffer_info->alloc_buffer_info; + MetaBufferInfo *meta_buffer_info = new MetaBufferInfo(); + + if (!meta_buffer_info) { + return kErrorMemory; + } + + int alloc_flags = INT(GRALLOC_USAGE_PRIVATE_IOMMU_HEAP); + int error = 0; + + int width = INT(buffer_config.width); + int height = INT(buffer_config.height); + int format; + + if (buffer_config.secure_camera) { + alloc_flags = GRALLOC_USAGE_HW_CAMERA_WRITE; + alloc_flags |= (GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_HW_COMPOSER); + data.align = SZ_2M; + } else if (buffer_config.secure) { + alloc_flags = INT(GRALLOC_USAGE_PRIVATE_MM_HEAP); + alloc_flags |= INT(GRALLOC_USAGE_PROTECTED); + data.align = SECURE_ALIGN; + } else { + data.align = UINT32(getpagesize()); + } + + if (buffer_config.cache == false) { + // Allocate uncached buffers + alloc_flags |= GRALLOC_USAGE_PRIVATE_UNCACHED; + } + + error = SetBufferInfo(buffer_config.format, &format, &alloc_flags); + if (error != 0) { + delete meta_buffer_info; + return kErrorParameters; + } + + int aligned_width = 0, aligned_height = 0; + uint32_t buffer_size = getBufferSizeAndDimensions(width, height, format, alloc_flags, + aligned_width, aligned_height); + + buffer_size = ROUND_UP(buffer_size, data.align) * buffer_config.buffer_count; + + data.base = 0; + data.fd = -1; + data.offset = 0; + data.size = buffer_size; + data.uncached = !buffer_config.cache; + + error = alloc_controller_->allocate(data, alloc_flags); + if (error != 0) { + DLOGE("Error allocating memory size %d uncached %d", data.size, data.uncached); + delete meta_buffer_info; + return kErrorMemory; + } + + alloc_buffer_info->fd = data.fd; + // TODO(user): define stride for all planes and fix stride in bytes + alloc_buffer_info->stride = UINT32(aligned_width); + alloc_buffer_info->aligned_width = UINT32(aligned_width); + alloc_buffer_info->aligned_height = UINT32(aligned_height); + alloc_buffer_info->size = buffer_size; + + meta_buffer_info->base_addr = data.base; + meta_buffer_info->alloc_type = data.allocType; + + buffer_info->private_data = meta_buffer_info; + + return kErrorNone; +} + +DisplayError HWCBufferAllocator::FreeBuffer(BufferInfo *buffer_info) { + int ret = 0; + AllocatedBufferInfo *alloc_buffer_info = &buffer_info->alloc_buffer_info; + + // Deallocate the buffer, only if the buffer fd is valid. + if (alloc_buffer_info->fd > 0) { + MetaBufferInfo *meta_buffer_info = static_cast<MetaBufferInfo *> (buffer_info->private_data); + gralloc::IMemAlloc *memalloc = alloc_controller_->getAllocator(meta_buffer_info->alloc_type); + if (memalloc == NULL) { + DLOGE("Memalloc handle is NULL, alloc type %d", meta_buffer_info->alloc_type); + return kErrorResources; + } + + ret = memalloc->free_buffer(meta_buffer_info->base_addr, alloc_buffer_info->size, 0, + alloc_buffer_info->fd); + if (ret != 0) { + DLOGE("Error freeing buffer base_addr %p size %d fd %d", meta_buffer_info->base_addr, + alloc_buffer_info->size, alloc_buffer_info->fd); + return kErrorMemory; + } + + alloc_buffer_info->fd = -1; + alloc_buffer_info->stride = 0; + alloc_buffer_info->aligned_width = 0; + alloc_buffer_info->aligned_height = 0; + alloc_buffer_info->size = 0; + + meta_buffer_info->base_addr = NULL; + meta_buffer_info->alloc_type = 0; + + delete meta_buffer_info; + meta_buffer_info = NULL; + } + + return kErrorNone; +} + +uint32_t HWCBufferAllocator::GetBufferSize(BufferInfo *buffer_info) { + uint32_t align = UINT32(getpagesize()); + + const BufferConfig &buffer_config = buffer_info->buffer_config; + + int alloc_flags = INT(GRALLOC_USAGE_PRIVATE_IOMMU_HEAP); + + int width = INT(buffer_config.width); + int height = INT(buffer_config.height); + int format; + + if (buffer_config.secure_camera) { + alloc_flags = GRALLOC_USAGE_HW_CAMERA_WRITE; + alloc_flags |= (GRALLOC_USAGE_PROTECTED | GRALLOC_USAGE_HW_COMPOSER); + align = SZ_2M; + } else if (buffer_config.secure) { + alloc_flags = INT(GRALLOC_USAGE_PRIVATE_MM_HEAP); + alloc_flags |= INT(GRALLOC_USAGE_PROTECTED); + align = SECURE_ALIGN; + } + + if (buffer_config.cache == false) { + // Allocate uncached buffers + alloc_flags |= GRALLOC_USAGE_PRIVATE_UNCACHED; + } + + if (SetBufferInfo(buffer_config.format, &format, &alloc_flags) < 0) { + return 0; + } + + int aligned_width = 0; + int aligned_height = 0; + uint32_t buffer_size = getBufferSizeAndDimensions(width, height, format, alloc_flags, + aligned_width, aligned_height); + + buffer_size = ROUND_UP(buffer_size, align) * buffer_config.buffer_count; + + return buffer_size; +} + +int HWCBufferAllocator::SetBufferInfo(LayerBufferFormat format, int *target, int *flags) { + switch (format) { + case kFormatRGBA8888: *target = HAL_PIXEL_FORMAT_RGBA_8888; break; + case kFormatRGBX8888: *target = HAL_PIXEL_FORMAT_RGBX_8888; break; + case kFormatRGB888: *target = HAL_PIXEL_FORMAT_RGB_888; break; + case kFormatRGB565: *target = HAL_PIXEL_FORMAT_RGB_565; break; + case kFormatBGR565: *target = HAL_PIXEL_FORMAT_BGR_565; break; + case kFormatBGRA8888: *target = HAL_PIXEL_FORMAT_BGRA_8888; break; + case kFormatYCrCb420PlanarStride16: *target = HAL_PIXEL_FORMAT_YV12; break; + case kFormatYCrCb420SemiPlanar: *target = HAL_PIXEL_FORMAT_YCrCb_420_SP; break; + case kFormatYCbCr420SemiPlanar: *target = HAL_PIXEL_FORMAT_YCbCr_420_SP; break; + case kFormatYCbCr422H2V1Packed: *target = HAL_PIXEL_FORMAT_YCbCr_422_I; break; + case kFormatCbYCrY422H2V1Packed: *target = HAL_PIXEL_FORMAT_CbYCrY_422_I; break; + case kFormatYCbCr422H2V1SemiPlanar: *target = HAL_PIXEL_FORMAT_YCbCr_422_SP; break; + case kFormatYCbCr420SemiPlanarVenus: *target = HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS; break; + case kFormatYCrCb420SemiPlanarVenus: *target = HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS; break; + case kFormatYCbCr420SPVenusUbwc: + *target = HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC; + *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + break; + case kFormatRGBA5551: *target = HAL_PIXEL_FORMAT_RGBA_5551; break; + case kFormatRGBA4444: *target = HAL_PIXEL_FORMAT_RGBA_4444; break; + case kFormatRGBA1010102: *target = HAL_PIXEL_FORMAT_RGBA_1010102; break; + case kFormatARGB2101010: *target = HAL_PIXEL_FORMAT_ARGB_2101010; break; + case kFormatRGBX1010102: *target = HAL_PIXEL_FORMAT_RGBX_1010102; break; + case kFormatXRGB2101010: *target = HAL_PIXEL_FORMAT_XRGB_2101010; break; + case kFormatBGRA1010102: *target = HAL_PIXEL_FORMAT_BGRA_1010102; break; + case kFormatABGR2101010: *target = HAL_PIXEL_FORMAT_ABGR_2101010; break; + case kFormatBGRX1010102: *target = HAL_PIXEL_FORMAT_BGRX_1010102; break; + case kFormatXBGR2101010: *target = HAL_PIXEL_FORMAT_XBGR_2101010; break; + case kFormatYCbCr420P010: *target = HAL_PIXEL_FORMAT_YCbCr_420_P010; break; + case kFormatYCbCr420TP10Ubwc: + *target = HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC; + *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + break; + case kFormatYCbCr420P010Ubwc: + *target = HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC; + *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + break; + case kFormatRGBA8888Ubwc: + *target = HAL_PIXEL_FORMAT_RGBA_8888; + *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + break; + case kFormatRGBX8888Ubwc: + *target = HAL_PIXEL_FORMAT_RGBX_8888; + *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + break; + case kFormatBGR565Ubwc: + *target = HAL_PIXEL_FORMAT_BGR_565; + *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + break; + case kFormatRGBA1010102Ubwc: + *target = HAL_PIXEL_FORMAT_RGBA_1010102; + *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + break; + case kFormatRGBX1010102Ubwc: + *target = HAL_PIXEL_FORMAT_RGBX_1010102; + *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + break; + default: + DLOGE("Unsupported format = 0x%x", format); + return -EINVAL; + } + + return 0; +} + +DisplayError HWCBufferAllocator::GetAllocatedBufferInfo(const BufferConfig &buffer_config, + AllocatedBufferInfo *allocated_buffer_info) { + int width = INT(buffer_config.width); + int height = INT(buffer_config.height); + int alloc_flags = INT(GRALLOC_USAGE_PRIVATE_IOMMU_HEAP); + + if (buffer_config.secure) { + alloc_flags = INT(GRALLOC_USAGE_PRIVATE_MM_HEAP); + alloc_flags |= INT(GRALLOC_USAGE_PROTECTED); + } + + if (buffer_config.cache == false) { + // Allocate uncached buffers + alloc_flags |= GRALLOC_USAGE_PRIVATE_UNCACHED; + } + + int format; + int error = SetBufferInfo(buffer_config.format, &format, &alloc_flags); + if (error) { + DLOGE("Failed: format = %d or width = %d height = %d", buffer_config.format, width, height); + return kErrorNotSupported; + } + + int width_aligned = 0, height_aligned = 0; + uint32_t buffer_size = 0; + buffer_size = getBufferSizeAndDimensions(width, height, format, alloc_flags, + width_aligned, height_aligned); + + allocated_buffer_info->stride = UINT32(width_aligned); + allocated_buffer_info->aligned_width = UINT32(width_aligned); + allocated_buffer_info->aligned_height = UINT32(height_aligned); + allocated_buffer_info->size = UINT32(buffer_size); + allocated_buffer_info->format = buffer_config.format; + + return kErrorNone; +} + +DisplayError HWCBufferAllocator::GetBufferLayout(const AllocatedBufferInfo &buf_info, + uint32_t stride[4], uint32_t offset[4], + uint32_t *num_planes) { + private_handle_t hnd(-1, 0, 0, 0, 0, 0, 0); + int format = HAL_PIXEL_FORMAT_RGBA_8888; + int flags = 0; + + SetBufferInfo(buf_info.format, &format, &flags); + // Setup only the required stuff, skip rest + hnd.format = format; + hnd.width = buf_info.aligned_width; + hnd.height = buf_info.aligned_height; + if (flags & GRALLOC_USAGE_PRIVATE_ALLOC_UBWC) { + hnd.flags = private_handle_t::PRIV_FLAGS_UBWC_ALIGNED; + } + + int ret = getBufferLayout(&hnd, stride, offset, num_planes); + if (ret < 0) { + DLOGE("getBufferLayout failed"); + return kErrorParameters; + } + + return kErrorNone; +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/hwc/hwc_buffer_allocator.h b/msm8909/sdm/libs/hwc/hwc_buffer_allocator.h new file mode 100644 index 00000000..a8cf4621 --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_buffer_allocator.h @@ -0,0 +1,70 @@ +/* +* 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. +*/ + + +#ifndef __HWC_BUFFER_ALLOCATOR_H__ +#define __HWC_BUFFER_ALLOCATOR_H__ + +#include <sys/mman.h> +#include <fcntl.h> + +namespace gralloc { + +class IAllocController; + +} // namespace gralloc + +namespace sdm { + +class HWCBufferAllocator : public BufferAllocator { + public: + HWCBufferAllocator(); + + DisplayError AllocateBuffer(BufferInfo *buffer_info); + DisplayError FreeBuffer(BufferInfo *buffer_info); + uint32_t GetBufferSize(BufferInfo *buffer_info); + DisplayError GetAllocatedBufferInfo(const BufferConfig &buffer_config, + AllocatedBufferInfo *allocated_buffer_info); + DisplayError GetBufferLayout(const AllocatedBufferInfo &buf_info, + uint32_t stride[4], uint32_t offset[4], + uint32_t *num_planes); + int SetBufferInfo(LayerBufferFormat format, int *target, int *flags); + + private: + struct MetaBufferInfo { + int alloc_type; //!< Specifies allocation type set by the buffer allocator. + void *base_addr; //!< Specifies the base address of the allocated output buffer. + }; + + gralloc::IAllocController *alloc_controller_; +}; + +} // namespace sdm +#endif // __HWC_BUFFER_ALLOCATOR_H__ + diff --git a/msm8909/sdm/libs/hwc/hwc_buffer_sync_handler.cpp b/msm8909/sdm/libs/hwc/hwc_buffer_sync_handler.cpp new file mode 100644 index 00000000..f2dacb22 --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_buffer_sync_handler.cpp @@ -0,0 +1,92 @@ +/* +* Copyright (c) 2015, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <errno.h> +#include <sync/sync.h> +#include <utils/constants.h> +#include <utils/debug.h> + +#include "hwc_debugger.h" +#include "hwc_buffer_sync_handler.h" + +#define __CLASS__ "HWCBufferSyncHandler" + +namespace sdm { + +DisplayError HWCBufferSyncHandler::SyncWait(int fd) { + int error = 0; + + if (fd >= 0) { + error = sync_wait(fd, 1000); + if (error < 0) { + DLOGE("sync_wait error errno = %d, desc = %s", errno, strerror(errno)); + return kErrorTimeOut; + } + } + + return kErrorNone; +} + +DisplayError HWCBufferSyncHandler::SyncMerge(int fd1, int fd2, int *merged_fd) { + DisplayError error = kErrorNone; + + // Merge the two fences. In the case where one of the fences is not a + // valid fence (e.g. NO_FENCE) merge the one valid fence with itself so + // that a new fence with the given name is created. + // TODO(user): "SyncMerge"string should be replaced with user-defined string to represent + // why it is merged. + if (fd1 >= 0 && fd2 >= 0) { + *merged_fd = sync_merge("SyncMerge", fd1, fd2); + } else if (fd1 >= 0) { + *merged_fd = sync_merge("SyncMerge", fd1, fd1); + } else if (fd2 >= 0) { + *merged_fd = sync_merge("SyncMerge", fd2, fd2); + } else { + *merged_fd = -1; + return kErrorNone; + } + + if (*merged_fd == -1) { + DLOGE("Sync merge error! fd1 %d fd2 %d", fd1, fd2); + error = kErrorFileDescriptor; + } + + return error; +} + +bool HWCBufferSyncHandler::IsSyncSignaled(int fd) { + if (sync_wait(fd, 0) < 0) { + return false; + } else { + return true; + } +} + +} // namespace sdm + diff --git a/msm8909/sdm/libs/hwc/hwc_buffer_sync_handler.h b/msm8909/sdm/libs/hwc/hwc_buffer_sync_handler.h new file mode 100644 index 00000000..81479d81 --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_buffer_sync_handler.h @@ -0,0 +1,53 @@ +/* +* Copyright (c) 2015, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef __HWC_BUFFER_SYNC_HANDLER_H__ +#define __HWC_BUFFER_SYNC_HANDLER_H__ + +#include <sys/mman.h> +#include <fcntl.h> +#include <core/sdm_types.h> +#include <core/buffer_sync_handler.h> + +namespace sdm { + +class HWCBufferSyncHandler : public BufferSyncHandler { + public: + HWCBufferSyncHandler() { } + + virtual DisplayError SyncWait(int fd); + virtual DisplayError SyncMerge(int fd1, int fd2, int *merged_fd); + virtual bool IsSyncSignaled(int fd); +}; + +} // namespace sdm +#endif // __HWC_BUFFER_SYNC_HANDLER_H__ + + diff --git a/msm8909/sdm/libs/hwc/hwc_color_manager.cpp b/msm8909/sdm/libs/hwc/hwc_color_manager.cpp new file mode 100644 index 00000000..a02f1ce0 --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_color_manager.cpp @@ -0,0 +1,651 @@ +/* +* Copyright (c) 2015 - 2017, 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 << 8) & 0xff00) | + ((params.color.b) & 0xff); + 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) { + // Load display API interface library. And retrieve color API function tables. + DynLib &color_apis_lib = color_mgr->color_apis_lib_; + if (color_apis_lib.Open(DISPLAY_API_INTERFACE_LIBRARY_NAME)) { + if (!color_apis_lib.Sym(DISPLAY_API_FUNC_TABLES, &color_mgr->color_apis_)) { + DLOGE("Fail to retrieve = %s from %s", DISPLAY_API_FUNC_TABLES, + DISPLAY_API_INTERFACE_LIBRARY_NAME); + 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. + DynLib &diag_client_lib = color_mgr->diag_client_lib_; + if (diag_client_lib.Open(QDCM_DIAG_CLIENT_LIBRARY_NAME)) { + if (!diag_client_lib.Sym(INIT_QDCM_DIAG_CLIENT_NAME, + reinterpret_cast<void **>(&color_mgr->qdcm_diag_init_)) || + !diag_client_lib.Sym(DEINIT_QDCM_DIAG_CLIENT_NAME, + reinterpret_cast<void **>(&color_mgr->qdcm_diag_deinit_))) { + DLOGE("Fail to retrieve = %s from %s", INIT_QDCM_DIAG_CLIENT_NAME, + QDCM_DIAG_CLIENT_LIBRARY_NAME); + } 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_(); + } + 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); + 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) { + 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->GetMixerResolution(&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->GetPanelResolution(&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) { + buffer_info.buffer_config.format = kFormatRGBA1010102; + } 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.aligned_width; + frame_capture_data->buffer_size = buffer_info.alloc_buffer_info.size; + } + ret = hwc_display->FrameCaptureAsync(buffer_info, 1); + if (ret < 0) { + DLOGE("FrameCaptureAsync failed. ret = %d", ret); + } + } + } else { + ret = hwc_display->GetFrameCaptureStatus(); + if (!ret) { + 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; + } + } else { + DLOGE("GetFrameCaptureStatus failed. ret = %d", ret); + } + } + return ret; +} + +int HWCColorManager::SetHWDetailedEnhancerConfig(void *params, HWCDisplay *hwc_display) { + int err = -1; + DisplayDetailEnhancerData de_data; + + PPDETuningCfgData *de_tuning_cfg_data = reinterpret_cast<PPDETuningCfgData*>(params); + if (de_tuning_cfg_data->cfg_pending == true) { + if (!de_tuning_cfg_data->cfg_en) { + de_data.enable = 0; + } else { + de_data.override_flags = kOverrideDEEnable; + de_data.enable = 1; + + if (de_tuning_cfg_data->params.flags & kDeTuningFlagSharpFactor) { + de_data.override_flags |= kOverrideDESharpen1; + de_data.sharp_factor = de_tuning_cfg_data->params.sharp_factor; + } + + if (de_tuning_cfg_data->params.flags & kDeTuningFlagClip) { + de_data.override_flags |= kOverrideDEClip; + de_data.clip = de_tuning_cfg_data->params.clip; + } + + if (de_tuning_cfg_data->params.flags & kDeTuningFlagThrQuiet) { + de_data.override_flags |= kOverrideDEThrQuiet; + de_data.thr_quiet = de_tuning_cfg_data->params.thr_quiet; + } + + if (de_tuning_cfg_data->params.flags & kDeTuningFlagThrDieout) { + de_data.override_flags |= kOverrideDEThrDieout; + de_data.thr_dieout = de_tuning_cfg_data->params.thr_dieout; + } + + if (de_tuning_cfg_data->params.flags & kDeTuningFlagThrLow) { + de_data.override_flags |= kOverrideDEThrLow; + de_data.thr_low = de_tuning_cfg_data->params.thr_low; + } + + if (de_tuning_cfg_data->params.flags & kDeTuningFlagThrHigh) { + de_data.override_flags |= kOverrideDEThrHigh; + de_data.thr_high = de_tuning_cfg_data->params.thr_high; + } + + if (de_tuning_cfg_data->params.flags & kDeTuningFlagContentQualLevel) { + switch (de_tuning_cfg_data->params.quality) { + case kDeContentQualLow: + de_data.quality_level = kContentQualityLow; + break; + case kDeContentQualMedium: + de_data.quality_level = kContentQualityMedium; + break; + case kDeContentQualHigh: + de_data.quality_level = kContentQualityHigh; + break; + case kDeContentQualUnknown: + default: + de_data.quality_level = kContentQualityUnknown; + break; + } + } + } + err = hwc_display->SetDetailEnhancerConfig(de_data); + if (err) { + DLOGW("SetDetailEnhancerConfig failed. err = %d", err); + } + de_tuning_cfg_data->cfg_pending = false; + } + return err; +} + +void HWCColorManager::SetColorModeDetailEnhancer(HWCDisplay *hwc_display) { + SCOPE_LOCK(locker_); + int err = -1; + PPPendingParams pending_action; + PPDisplayAPIPayload req_payload; + + pending_action.action = kGetDetailedEnhancerData; + pending_action.params = NULL; + + if (hwc_display) { + err = hwc_display->ColorSVCRequestRoute(req_payload, NULL, &pending_action); + if (!err && pending_action.action == kConfigureDetailedEnhancer) { + err = SetHWDetailedEnhancerConfig(pending_action.params, hwc_display); + } + } + return; +} + +int HWCColorManager::SetDetailedEnhancer(void *params, HWCDisplay *hwc_display) { + SCOPE_LOCK(locker_); + int err = -1; + err = SetHWDetailedEnhancerConfig(params, hwc_display); + return err; +} + +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 diff --git a/msm8909/sdm/libs/hwc/hwc_color_manager.h b/msm8909/sdm/libs/hwc/hwc_color_manager.h new file mode 100644 index 00000000..20d2b391 --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_color_manager.h @@ -0,0 +1,149 @@ +/* Copyright (c) 2015-2017, The Linux Foundataion. 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_COLOR_MANAGER_H__ +#define __HWC_COLOR_MANAGER_H__ + +#include <stdlib.h> +#include <binder/Parcel.h> +#include <powermanager/IPowerManager.h> +#include <binder/BinderService.h> +#include <core/sdm_types.h> +#include <utils/locker.h> +#include <utils/sys.h> + +namespace sdm { + +// This macro defines name for display APIs interface wrapper library. +// This macro shall be used to load library using dlopen(). +#define DISPLAY_API_INTERFACE_LIBRARY_NAME "libsdm-disp-vndapis.so" + +// This macro defines variable name of display color APIs function tables +// This macro shall be used to specify name of the variable in dlsym(). +#define DISPLAY_API_FUNC_TABLES "display_color_apis_ftables" +#define QDCM_DIAG_CLIENT_LIBRARY_NAME "libsdm-diag.so" +#define INIT_QDCM_DIAG_CLIENT_NAME "QDCMDiagInit" +#define DEINIT_QDCM_DIAG_CLIENT_NAME "QDCMDiagDeInit" + +typedef int (*QDCMDiagInit)(void *ftables); + +typedef int (*QDCMDiagDeInit)(void); + +// Class to encapsulte all details of managing QDCM operating mode. +class HWCQDCMModeManager { + public: + static const uint32_t kSocketCMDMaxLength = 4096; + static const uint32_t kFullWakeLock = 0x0000001a; + static const uint32_t kAcquireCauseWakeup = 0x10000000; + static const uint32_t kONAfterRelease = 0x20000000; + enum ActiveFeatureID { + kCABLFeature, + kADFeature, + kSVIFeature, + kMaxNumActiveFeature, + }; + + struct ActiveFeatureCMD { + const char *cmd_on = NULL; + const char *cmd_off = NULL; + const char *cmd_query_status = NULL; + const char *running = NULL; + ActiveFeatureCMD(const char *arg1, const char *arg2, const char *arg3, const char *arg4) + : cmd_on(arg1), cmd_off(arg2), cmd_query_status(arg3), running(arg4) {} + }; + + static const ActiveFeatureCMD kActiveFeatureCMD[kMaxNumActiveFeature]; + + public: + static HWCQDCMModeManager *CreateQDCMModeMgr(); + ~HWCQDCMModeManager(); + int EnableQDCMMode(bool enable, HWCDisplay *hwc_display); + + protected: + bool SendSocketCmd(); + int AcquireAndroidWakeLock(bool enable); + int EnableActiveFeatures(bool enable); + int EnableActiveFeatures(bool enable, const ActiveFeatureCMD &cmds, bool *was_running); + + private: + bool cabl_was_running_ = false; + int socket_fd_ = -1; + android::sp<android::IBinder> wakelock_token_ = NULL; + android::sp<android::IPowerManager> power_mgr_ = NULL; + uint32_t entry_timeout_ = 0; + static const char *const kSocketName; + static const char *const kTagName; + static const char *const kPackageName; +}; + +// Class to encapsulte all HWC/OS specific behaviours for ColorManager. +class HWCColorManager { + public: + static const int kNumSolidFillLayers = 2; + static HWCColorManager *CreateColorManager(); + static int CreatePayloadFromParcel(const android::Parcel &in, uint32_t *disp_id, + PPDisplayAPIPayload *sink); + static void MarshallStructIntoParcel(const PPDisplayAPIPayload &data, + android::Parcel *out_parcel); + + ~HWCColorManager(); + void DestroyColorManager(); + int EnableQDCMMode(bool enable, HWCDisplay *hwc_display); + int SetSolidFill(const void *params, bool enable, HWCDisplay *hwc_display); + bool SolidFillLayersPrepare(hwc_display_contents_1_t **displays, HWCDisplay *hwc_display); + bool SolidFillLayersSet(hwc_display_contents_1_t **displays, HWCDisplay *hwc_display); + int SetFrameCapture(void *params, bool enable, HWCDisplay *hwc_display); + int SetDetailedEnhancer(void *params, HWCDisplay *hwc_display); + void SetColorModeDetailEnhancer(HWCDisplay *hwc_display); + int SetHWDetailedEnhancerConfig(void *params, HWCDisplay *hwc_display); + + protected: + int CreateSolidFillLayers(HWCDisplay *hwc_display); + void DestroySolidFillLayers(); + static uint32_t Get8BitsARGBColorValue(const PPColorFillParams ¶ms); + + private: + DynLib color_apis_lib_; + DynLib diag_client_lib_; + void *color_apis_ = NULL; + QDCMDiagInit qdcm_diag_init_ = NULL; + QDCMDiagDeInit qdcm_diag_deinit_ = NULL; + HWCQDCMModeManager *qdcm_mode_mgr_ = NULL; + + bool solid_fill_enable_ = false; + PPColorFillParams solid_fill_params_; + hwc_display_contents_1_t *solid_fill_layers_ = NULL; + HWCBufferAllocator *buffer_allocator_ = NULL; + BufferInfo buffer_info; + Locker locker_; +}; + +} // namespace sdm + +#endif // __HWC_COLOR_MANAGER_H__ diff --git a/msm8909/sdm/libs/hwc/hwc_debugger.cpp b/msm8909/sdm/libs/hwc/hwc_debugger.cpp new file mode 100644 index 00000000..18a448d5 --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_debugger.cpp @@ -0,0 +1,232 @@ +/* +* Copyright (c) 2014 - 2018, 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 <cutils/properties.h> +#include <utils/debug.h> + +#include "hwc_debugger.h" + +namespace sdm { + +HWCDebugHandler HWCDebugHandler::debug_handler_; +std::bitset<32> HWCDebugHandler::debug_flags_ = 0x1; +int32_t HWCDebugHandler::verbose_level_ = 0x0; + +void HWCDebugHandler::DebugAll(bool enable, int verbose_level) { + if (enable) { + debug_flags_ = 0x7FFFFFFF; + if (verbose_level) { + // Enable verbose scalar logs only when explicitely enabled + debug_flags_[kTagScalar] = 0; + } + verbose_level_ = verbose_level; + } else { + debug_flags_ = 0x1; // kTagNone should always be printed. + verbose_level_ = 0; + } +} + +void HWCDebugHandler::DebugResources(bool enable, int verbose_level) { + if (enable) { + debug_flags_[kTagResources] = 1; + verbose_level_ = verbose_level; + } else { + debug_flags_[kTagResources] = 0; + verbose_level_ = 0; + } +} + +void HWCDebugHandler::DebugStrategy(bool enable, int verbose_level) { + if (enable) { + debug_flags_[kTagStrategy] = 1; + verbose_level_ = verbose_level; + } else { + debug_flags_[kTagStrategy] = 0; + verbose_level_ = 0; + } +} + +void HWCDebugHandler::DebugCompManager(bool enable, int verbose_level) { + if (enable) { + debug_flags_[kTagCompManager] = 1; + verbose_level_ = verbose_level; + } else { + debug_flags_[kTagCompManager] = 0; + verbose_level_ = 0; + } +} + +void HWCDebugHandler::DebugDriverConfig(bool enable, int verbose_level) { + if (enable) { + debug_flags_[kTagDriverConfig] = 1; + verbose_level_ = verbose_level; + } else { + debug_flags_[kTagDriverConfig] = 0; + verbose_level_ = 0; + } +} + +void HWCDebugHandler::DebugRotator(bool enable, int verbose_level) { + if (enable) { + debug_flags_[kTagRotator] = 1; + verbose_level_ = verbose_level; + } else { + debug_flags_[kTagRotator] = 0; + verbose_level_ = 0; + } +} + +void HWCDebugHandler::DebugScalar(bool enable, int verbose_level) { + if (enable) { + debug_flags_[kTagScalar] = 1; + verbose_level_ = verbose_level; + } else { + debug_flags_[kTagScalar] = 0; + verbose_level_ = 0; + } +} + +void HWCDebugHandler::DebugQdcm(bool enable, int verbose_level) { + if (enable) { + debug_flags_[kTagQDCM] = 1; + verbose_level_ = verbose_level; + } else { + debug_flags_[kTagQDCM] = 0; + verbose_level_ = 0; + } +} + +void HWCDebugHandler::DebugClient(bool enable, int verbose_level) { + if (enable) { + debug_flags_[kTagClient] = 1; + verbose_level_ = verbose_level; + } else { + debug_flags_[kTagClient] = 0; + verbose_level_ = 0; + } +} + +void HWCDebugHandler::DebugDisplay(bool enable, int verbose_level) { + if (enable) { + debug_flags_[kTagDisplay] = 1; + verbose_level_ = verbose_level; + } else { + debug_flags_[kTagDisplay] = 0; + verbose_level_ = 0; + } +} + +void HWCDebugHandler::Error(DebugTag tag, const char *format, ...) { + if (debug_flags_[tag]) { + va_list list; + va_start(list, format); + __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, list); + } +} + +void HWCDebugHandler::Warning(DebugTag tag, const char *format, ...) { + if (debug_flags_[tag]) { + va_list list; + va_start(list, format); + __android_log_vprint(ANDROID_LOG_WARN, LOG_TAG, format, list); + } +} + +void HWCDebugHandler::Info(DebugTag tag, const char *format, ...) { + if (debug_flags_[tag]) { + va_list list; + va_start(list, format); + __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, list); + } +} + +void HWCDebugHandler::Debug(DebugTag tag, const char *format, ...) { + if (debug_flags_[tag]) { + va_list list; + va_start(list, format); + __android_log_vprint(ANDROID_LOG_DEBUG, LOG_TAG, format, list); + } +} + +void HWCDebugHandler::Verbose(DebugTag tag, const char *format, ...) { + if (debug_flags_[tag] && verbose_level_) { + va_list list; + va_start(list, format); + __android_log_vprint(ANDROID_LOG_VERBOSE, LOG_TAG, format, list); + } +} + +void HWCDebugHandler::BeginTrace(const char *class_name, const char *function_name, + const char *custom_string) { + char name[PATH_MAX] = {0}; + snprintf(name, sizeof(name), "%s::%s::%s", class_name, function_name, custom_string); + atrace_begin(ATRACE_TAG, name); +} + +void HWCDebugHandler::EndTrace() { + atrace_end(ATRACE_TAG); +} + +int HWCDebugHandler::GetIdleTimeoutMs() { + int value = IDLE_TIMEOUT_DEFAULT_MS; + debug_handler_.GetProperty(IDLE_TIME_PROP, &value); + + return value; +} + +DisplayError HWCDebugHandler::GetProperty(const char *property_name, int *value) { + char property[PROPERTY_VALUE_MAX]; + + if (property_get(property_name, property, NULL) > 0) { + *value = atoi(property); + return kErrorNone; + } + + return kErrorNotSupported; +} + +DisplayError HWCDebugHandler::GetProperty(const char *property_name, char *value) { + if (property_get(property_name, value, NULL) > 0) { + return kErrorNone; + } + + return kErrorNotSupported; +} + +DisplayError HWCDebugHandler::SetProperty(const char *property_name, const char *value) { + if (property_set(property_name, value) == 0) { + return kErrorNone; + } + + return kErrorNotSupported; +} + +} // namespace sdm + diff --git a/msm8909/sdm/libs/hwc/hwc_debugger.h b/msm8909/sdm/libs/hwc/hwc_debugger.h new file mode 100644 index 00000000..3a3d7872 --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_debugger.h @@ -0,0 +1,81 @@ +/* +* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __HWC_DEBUGGER_H__ +#define __HWC_DEBUGGER_H__ + +#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL) + +#include <core/sdm_types.h> +#include <core/debug_interface.h> +#include <log/log.h> +#include <utils/Trace.h> +#include <bitset> + +namespace sdm { + +class HWCDebugHandler : public DebugHandler { + public: + static inline DebugHandler* Get() { return &debug_handler_; } + static const char* DumpDir() { return "/data/vendor/display"; } + + static void DebugAll(bool enable, int verbose_level); + static void DebugResources(bool enable, int verbose_level); + static void DebugStrategy(bool enable, int verbose_level); + static void DebugCompManager(bool enable, int verbose_level); + static void DebugDriverConfig(bool enable, int verbose_level); + static void DebugRotator(bool enable, int verbose_level); + static void DebugScalar(bool enable, int verbose_level); + static void DebugQdcm(bool enable, int verbose_level); + static void DebugClient(bool enable, int verbose_level); + static void DebugDisplay(bool enable, int verbose_level); + static int GetIdleTimeoutMs(); + + virtual void Error(DebugTag tag, const char *format, ...); + virtual void Warning(DebugTag tag, const char *format, ...); + virtual void Info(DebugTag tag, const char *format, ...); + virtual void Debug(DebugTag tag, const char *format, ...); + virtual void Verbose(DebugTag tag, const char *format, ...); + virtual void BeginTrace(const char *class_name, const char *function_name, + const char *custom_string); + virtual void EndTrace(); + virtual DisplayError GetProperty(const char *property_name, int *value); + virtual DisplayError GetProperty(const char *property_name, char *value); + virtual DisplayError SetProperty(const char *property_name, const char *value); + + private: + static HWCDebugHandler debug_handler_; + static std::bitset<32> debug_flags_; + static int32_t verbose_level_; +}; + +} // namespace sdm + +#endif // __HWC_DEBUGGER_H__ + diff --git a/msm8909/sdm/libs/hwc/hwc_display.cpp b/msm8909/sdm/libs/hwc/hwc_display.cpp new file mode 100644 index 00000000..47915c7b --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_display.cpp @@ -0,0 +1,1536 @@ +/* +* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <math.h> +#include <errno.h> +#include <gralloc_priv.h> +#include <gr.h> +#include <utils/constants.h> +#include <utils/formats.h> +#include <utils/rect.h> +#include <utils/debug.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sync/sync.h> +#include <cutils/properties.h> +#include <qd_utils.h> +#include <map> +#include <utility> +#include <vector> +#include <string> + +#include "blit_engine_c2d.h" +#include "hwc_debugger.h" +#include "hwc_display.h" +#include "hwc_tonemapper.h" + +#ifdef QTI_BSP +#include <hardware/display_defs.h> +#endif + +#define __CLASS__ "HWCDisplay" + +namespace sdm { + +void HWCColorMode::Init() { + int ret = PopulateColorModes(); + if (ret != 0) { + DLOGW("Failed!!"); + } + return; +} + +int HWCColorMode::SetColorMode(const std::string &color_mode) { + if (color_modes_.empty()) { + DLOGW("No Color Modes supported"); + return -1; + } + + std::vector<std::string>::iterator it = std::find(color_modes_.begin(), color_modes_.end(), + color_mode); + if (it == color_modes_.end()) { + DLOGE("Invalid colorMode request: %s", color_mode.c_str()); + return -1; + } + + DisplayError error = display_intf_->SetColorMode(color_mode); + if (error != kErrorNone) { + DLOGE("Failed to set color_mode = %s", color_mode.c_str()); + return -1; + } + current_color_mode_ = color_mode; + + return 0; +} + +const std::vector<std::string> &HWCColorMode::GetColorModes() { + return color_modes_; +} + +int HWCColorMode::SetColorTransform(uint32_t matrix_count, const float *matrix) { + if (matrix_count > kColorTransformMatrixCount) { + DLOGE("Transform matrix count = %d, exceeds max = %d", matrix_count, + kColorTransformMatrixCount); + return -1; + } + + double color_matrix[kColorTransformMatrixCount] = {0}; + CopyColorTransformMatrix(matrix, color_matrix); + DisplayError error = display_intf_->SetColorTransform(matrix_count, color_matrix); + if (error != kErrorNone) { + DLOGE("Failed!"); + return -1; + } + + return 0; +} + +int HWCColorMode::PopulateColorModes() { + uint32_t color_mode_count = 0; + DisplayError error = display_intf_->GetColorModeCount(&color_mode_count); + if (error != kErrorNone || (color_mode_count == 0)) { + return -1; + } + + DLOGI("Color Mode count = %d", color_mode_count); + + color_modes_.resize(color_mode_count); + + // SDM returns modes which is string + error = display_intf_->GetColorModes(&color_mode_count, &color_modes_); + if (error != kErrorNone) { + DLOGE("GetColorModes Failed for count = %d", color_mode_count); + return -1; + } + + return 0; +} + +HWCDisplay::HWCDisplay(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, DisplayType type, + int id, bool needs_blit, qService::QService *qservice, + DisplayClass display_class) + : core_intf_(core_intf), hwc_procs_(hwc_procs), type_(type), id_(id), needs_blit_(needs_blit), + qservice_(qservice), display_class_(display_class) { +} + +int HWCDisplay::Init() { + DisplayError error = core_intf_->CreateDisplay(type_, this, &display_intf_); + if (error != kErrorNone) { + DLOGE("Display create failed. Error = %d display_type %d event_handler %p disp_intf %p", + error, type_, this, &display_intf_); + return -EINVAL; + } + + HWCDebugHandler::Get()->GetProperty("sys.hwc_disable_hdr", &disable_hdr_handling_); + if (disable_hdr_handling_) { + DLOGI("HDR Handling disabled"); + } + + int property_swap_interval = 1; + HWCDebugHandler::Get()->GetProperty("debug.egl.swapinterval", &property_swap_interval); + if (property_swap_interval == 0) { + swap_interval_zero_ = true; + } + + int blit_enabled = 0; + HWCDebugHandler::Get()->GetProperty("persist.hwc.blit.comp", &blit_enabled); + if (needs_blit_ && blit_enabled) { + blit_engine_ = new BlitEngineC2d(); + if (!blit_engine_) { + DLOGI("Create Blit Engine C2D failed"); + } else { + if (blit_engine_->Init() < 0) { + DLOGI("Blit Engine Init failed, Blit Composition will not be used!!"); + delete blit_engine_; + blit_engine_ = NULL; + } + } + } + + tone_mapper_ = new HWCToneMapper(); + + display_intf_->GetRefreshRateRange(&min_refresh_rate_, &max_refresh_rate_); + current_refresh_rate_ = max_refresh_rate_; + + s3d_format_hwc_to_sdm_.insert(std::pair<int, LayerBufferS3DFormat>(HAL_NO_3D, kS3dFormatNone)); + s3d_format_hwc_to_sdm_.insert(std::pair<int, LayerBufferS3DFormat>(HAL_3D_SIDE_BY_SIDE_L_R, + kS3dFormatLeftRight)); + s3d_format_hwc_to_sdm_.insert(std::pair<int, LayerBufferS3DFormat>(HAL_3D_SIDE_BY_SIDE_R_L, + kS3dFormatRightLeft)); + s3d_format_hwc_to_sdm_.insert(std::pair<int, LayerBufferS3DFormat>(HAL_3D_TOP_BOTTOM, + kS3dFormatTopBottom)); + + disable_animation_ = Debug::IsExtAnimDisabled(); + + return 0; +} + +int HWCDisplay::Deinit() { + DisplayError error = core_intf_->DestroyDisplay(display_intf_); + if (error != kErrorNone) { + DLOGE("Display destroy failed. Error = %d", error); + return -EINVAL; + } + + if (blit_engine_) { + blit_engine_->DeInit(); + delete blit_engine_; + blit_engine_ = NULL; + } + + delete tone_mapper_; + tone_mapper_ = NULL; + + return 0; +} + +int HWCDisplay::EventControl(int event, int enable) { + DisplayError error = kErrorNone; + + if (shutdown_pending_) { + return 0; + } + + switch (event) { + case HWC_EVENT_VSYNC: + error = display_intf_->SetVSyncState(enable); + break; + default: + DLOGW("Unsupported event = %d", event); + } + + if (error != kErrorNone) { + if (error == kErrorShutDown) { + shutdown_pending_ = true; + return 0; + } + DLOGE("Failed. event = %d, enable = %d, error = %d", event, enable, error); + return -EINVAL; + } + + return 0; +} + +int HWCDisplay::SetPowerMode(int mode) { + DLOGI("display = %d, mode = %d", id_, mode); + DisplayState state = kStateOff; + bool flush_on_error = flush_on_error_; + + if (shutdown_pending_) { + return 0; + } + + switch (mode) { + case HWC_POWER_MODE_OFF: + // During power off, all of the buffers are released. + // Do not flush until a buffer is successfully submitted again. + flush_on_error = false; + state = kStateOff; + tone_mapper_->Terminate(); + break; + + case HWC_POWER_MODE_NORMAL: + state = kStateOn; + last_power_mode_ = HWC_POWER_MODE_NORMAL; + break; + + case HWC_POWER_MODE_DOZE: + state = kStateDoze; + last_power_mode_ = HWC_POWER_MODE_DOZE; + break; + + case HWC_POWER_MODE_DOZE_SUSPEND: + state = kStateDozeSuspend; + last_power_mode_ = HWC_POWER_MODE_DOZE_SUSPEND; + break; + + default: + return -EINVAL; + } + + DisplayError error = display_intf_->SetDisplayState(state); + if (error == kErrorNone) { + flush_on_error_ = flush_on_error; + } else { + if (error == kErrorShutDown) { + shutdown_pending_ = true; + return 0; + } + DLOGE("Set state failed. Error = %d", error); + return -EINVAL; + } + + return 0; +} + +int HWCDisplay::GetDisplayConfigs(uint32_t *configs, size_t *num_configs) { + if (*num_configs > 0) { + configs[0] = 0; + *num_configs = 1; + } + + return 0; +} + +int HWCDisplay::GetDisplayAttributes(uint32_t config, const uint32_t *display_attributes, + int32_t *values) { + DisplayConfigVariableInfo variable_config; + DisplayError error = display_intf_->GetFrameBufferConfig(&variable_config); + if (error != kErrorNone) { + DLOGV("Get variable config failed. Error = %d", error); + return -EINVAL; + } + + for (int i = 0; display_attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) { + switch (display_attributes[i]) { + case HWC_DISPLAY_VSYNC_PERIOD: + values[i] = INT32(variable_config.vsync_period_ns); + break; + case HWC_DISPLAY_WIDTH: + values[i] = INT32(variable_config.x_pixels); + break; + case HWC_DISPLAY_HEIGHT: + values[i] = INT32(variable_config.y_pixels); + break; + case HWC_DISPLAY_DPI_X: + values[i] = INT32(variable_config.x_dpi * 1000.0f); + break; + case HWC_DISPLAY_DPI_Y: + values[i] = INT32(variable_config.y_dpi * 1000.0f); + break; + default: + DLOGW("Spurious attribute type = %d", display_attributes[i]); + return -EINVAL; + } + } + + return 0; +} + +int HWCDisplay::GetActiveConfig() { + return 0; +} + +int HWCDisplay::SetActiveConfig(int index) { + return -1; +} + +DisplayError HWCDisplay::SetMixerResolution(uint32_t width, uint32_t height) { + return kErrorNotSupported; +} + +void HWCDisplay::SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type) { + dump_frame_count_ = count; + dump_frame_index_ = 0; + dump_input_layers_ = ((bit_mask_layer_type & (1 << INPUT_LAYER_DUMP)) != 0); + + if (blit_engine_) { + blit_engine_->SetFrameDumpConfig(count); + } + + if (tone_mapper_) { + tone_mapper_->SetFrameDumpConfig(count); + } + + DLOGI("num_frame_dump %d, input_layer_dump_enable %d", dump_frame_count_, dump_input_layers_); +} + +uint32_t HWCDisplay::GetLastPowerMode() { + return last_power_mode_; +} + +DisplayError HWCDisplay::VSync(const DisplayEventVSync &vsync) { + const hwc_procs_t *hwc_procs = *hwc_procs_; + + if (!hwc_procs) { + return kErrorParameters; + } + + hwc_procs->vsync(hwc_procs, id_, vsync.timestamp); + + return kErrorNone; +} + +DisplayError HWCDisplay::Refresh() { + return kErrorNotSupported; +} + +DisplayError HWCDisplay::CECMessage(char *message) { + if (qservice_) { + qservice_->onCECMessageReceived(message, 0); + } else { + DLOGW("Qservice instance not available."); + } + + return kErrorNone; +} + +int HWCDisplay::AllocateLayerStack(hwc_display_contents_1_t *content_list) { + if (!content_list || !content_list->numHwLayers) { + DLOGW("Invalid content list"); + return -EINVAL; + } + + size_t num_hw_layers = content_list->numHwLayers; + uint32_t blit_target_count = 0; + + if (blit_engine_) { + blit_target_count = kMaxBlitTargetLayers; + } + + FreeLayerStack(); + + for (size_t i = 0; i < num_hw_layers + blit_target_count; i++) { + Layer *layer = new Layer(); + layer_stack_.layers.push_back(layer); + } + + return 0; +} + +void HWCDisplay::FreeLayerStack() { + for (Layer *layer : layer_stack_.layers) { + delete layer; + } + layer_stack_ = {}; +} + +int HWCDisplay::PrepareLayerParams(hwc_layer_1_t *hwc_layer, Layer* layer) { + const private_handle_t *pvt_handle = static_cast<const private_handle_t *>(hwc_layer->handle); + + LayerBuffer &layer_buffer = layer->input_buffer; + + if (pvt_handle) { + layer_buffer.planes[0].fd = pvt_handle->fd; + layer_buffer.format = GetSDMFormat(pvt_handle->format, pvt_handle->flags); + int aligned_width, aligned_height; + int unaligned_width, unaligned_height; + + AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(pvt_handle, aligned_width, + aligned_height); + AdrenoMemInfo::getInstance().getUnalignedWidthAndHeight(pvt_handle, unaligned_width, + unaligned_height); + + layer_buffer.width = UINT32(aligned_width); + layer_buffer.height = UINT32(aligned_height); + layer_buffer.unaligned_width = UINT32(unaligned_width); + layer_buffer.unaligned_height = UINT32(unaligned_height); + + if (SetMetaData(pvt_handle, layer) != kErrorNone) { + return -EINVAL; + } + + if (pvt_handle->bufferType == BUFFER_TYPE_VIDEO) { + layer_stack_.flags.video_present = true; + layer_buffer.flags.video = true; + } + // TZ Protected Buffer - L1 + if (pvt_handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) { + layer_stack_.flags.secure_present = true; + layer_buffer.flags.secure = true; + if (pvt_handle->flags & private_handle_t::PRIV_FLAGS_CAMERA_WRITE) { + layer_buffer.flags.secure_camera = true; + } + } + // Gralloc Usage Protected Buffer - L3 - which needs to be treated as Secure & avoid fallback + if (pvt_handle->flags & private_handle_t::PRIV_FLAGS_PROTECTED_BUFFER) { + layer_stack_.flags.secure_present = true; + } + if (pvt_handle->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY) { + layer_buffer.flags.secure_display = true; + } + + // check if this is special solid_fill layer without input_buffer. + if (solid_fill_enable_ && pvt_handle->fd == -1) { + layer->flags.solid_fill = true; + layer->solid_fill_color = solid_fill_color_; + } + } else { + // for FBT layer + if (hwc_layer->compositionType == HWC_FRAMEBUFFER_TARGET) { + uint32_t x_pixels; + uint32_t y_pixels; + int aligned_width; + int aligned_height; + int usage = GRALLOC_USAGE_HW_FB; + int format = HAL_PIXEL_FORMAT_RGBA_8888; + int ubwc_enabled = 0; + int flags = 0; + HWCDebugHandler::Get()->GetProperty("debug.gralloc.enable_fb_ubwc", &ubwc_enabled); + bool linear = layer_stack_.output_buffer && !IsUBWCFormat(layer_stack_.output_buffer->format); + if ((ubwc_enabled == 1) && !linear) { + usage |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + flags |= private_handle_t::PRIV_FLAGS_UBWC_ALIGNED; + } + + GetFrameBufferResolution(&x_pixels, &y_pixels); + + AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(INT(x_pixels), INT(y_pixels), format, + usage, aligned_width, aligned_height); + layer_buffer.width = UINT32(aligned_width); + layer_buffer.height = UINT32(aligned_height); + layer_buffer.unaligned_width = x_pixels; + layer_buffer.unaligned_height = y_pixels; + layer_buffer.format = GetSDMFormat(format, flags); + } + } + + return 0; +} + +void HWCDisplay::CommitLayerParams(hwc_layer_1_t *hwc_layer, Layer *layer) { + const private_handle_t *pvt_handle = static_cast<const private_handle_t *>(hwc_layer->handle); + LayerBuffer &layer_buffer = layer->input_buffer; + + if (pvt_handle) { + layer_buffer.planes[0].fd = pvt_handle->fd; + layer_buffer.planes[0].offset = pvt_handle->offset; + layer_buffer.planes[0].stride = UINT32(pvt_handle->width); + layer_buffer.size = pvt_handle->size; + } + + // if swapinterval property is set to 0 then close and reset the acquireFd + if (swap_interval_zero_ && hwc_layer->acquireFenceFd >= 0) { + close(hwc_layer->acquireFenceFd); + hwc_layer->acquireFenceFd = -1; + } + layer_buffer.acquire_fence_fd = hwc_layer->acquireFenceFd; +} + +int HWCDisplay::PrePrepareLayerStack(hwc_display_contents_1_t *content_list) { + if (shutdown_pending_) { + return 0; + } + + size_t num_hw_layers = content_list->numHwLayers; + + use_blit_comp_ = false; + metadata_refresh_rate_ = 0; + display_rect_ = LayerRect(); + + // Configure each layer + for (size_t i = 0; i < num_hw_layers; i++) { + hwc_layer_1_t &hwc_layer = content_list->hwLayers[i]; + + const private_handle_t *pvt_handle = static_cast<const private_handle_t *>(hwc_layer.handle); + Layer *layer = layer_stack_.layers.at(i); + int ret = PrepareLayerParams(&content_list->hwLayers[i], layer); + + if (ret != kErrorNone) { + return ret; + } + + layer->flags.skip = ((hwc_layer.flags & HWC_SKIP_LAYER) > 0); + layer->flags.solid_fill = (hwc_layer.flags & kDimLayer) || solid_fill_enable_; + if (layer->flags.skip || layer->flags.solid_fill) { + layer->dirty_regions.clear(); + } + + hwc_rect_t scaled_display_frame = hwc_layer.displayFrame; + ApplyScanAdjustment(&scaled_display_frame); + + SetRect(scaled_display_frame, &layer->dst_rect); + if (pvt_handle) { + bool NonIntegralSourceCrop = IsNonIntegralSourceCrop(hwc_layer.sourceCropf); + bool secure = (pvt_handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) || + (pvt_handle->flags & private_handle_t::PRIV_FLAGS_PROTECTED_BUFFER) || + (pvt_handle->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY); + if (NonIntegralSourceCrop && (!secure && pvt_handle->bufferType != BUFFER_TYPE_VIDEO)) { + layer->flags.skip = true; + } + } + SetRect(hwc_layer.sourceCropf, &layer->src_rect); + + uint32_t num_visible_rects = UINT32(hwc_layer.visibleRegionScreen.numRects); + uint32_t num_dirty_rects = UINT32(hwc_layer.surfaceDamage.numRects); + + for (uint32_t j = 0; j < num_visible_rects; j++) { + LayerRect visible_rect = {}; + SetRect(hwc_layer.visibleRegionScreen.rects[j], &visible_rect); + layer->visible_regions.push_back(visible_rect); + } + + for (uint32_t j = 0; j < num_dirty_rects; j++) { + LayerRect dirty_rect = {}; + SetRect(hwc_layer.surfaceDamage.rects[j], &dirty_rect); + layer->dirty_regions.push_back(dirty_rect); + } + + if (blit_engine_) { + for (uint32_t j = 0; j < kMaxBlitTargetLayers; j++) { + LayerRect blit_rect = {}; + layer->blit_regions.push_back(blit_rect); + } + } + + SetComposition(hwc_layer.compositionType, &layer->composition); + if (hwc_layer.compositionType != HWC_FRAMEBUFFER_TARGET) { + display_rect_ = Union(display_rect_, layer->dst_rect); + } + + // For dim layers, SurfaceFlinger + // - converts planeAlpha to per pixel alpha, + // - sets appropriate RGB color, + // - sets planeAlpha to 0xff, + // - blending to Premultiplied. + // This can be achieved at hardware by + // - solid fill ARGB to appropriate value, + // - incoming planeAlpha, + // - blending to Coverage. + if (hwc_layer.flags & kDimLayer) { + layer->input_buffer.format = kFormatARGB8888; + layer->solid_fill_color = 0xff000000; +#ifdef QTI_BSP + // Get ARGB color from HWC Dim Layer color + uint32_t a = UINT32(hwc_layer.color.a) << 24; + uint32_t r = UINT32(hwc_layer.color.r) << 16; + uint32_t g = UINT32(hwc_layer.color.g) << 8; + uint32_t b = UINT32(hwc_layer.color.b); + layer->solid_fill_color = a | r | g | b; +#endif + SetBlending(HWC_BLENDING_COVERAGE, &layer->blending); + } else { + SetBlending(hwc_layer.blending, &layer->blending); + LayerTransform &layer_transform = layer->transform; + uint32_t &hwc_transform = hwc_layer.transform; + layer_transform.flip_horizontal = ((hwc_transform & HWC_TRANSFORM_FLIP_H) > 0); + layer_transform.flip_vertical = ((hwc_transform & HWC_TRANSFORM_FLIP_V) > 0); + layer_transform.rotation = ((hwc_transform & HWC_TRANSFORM_ROT_90) ? 90.0f : 0.0f); + } + + // TODO(user): Remove below block. + // For solid fill, only dest rect need to be specified. + if (layer->flags.solid_fill) { + LayerBuffer &input_buffer = layer->input_buffer; + input_buffer.width = UINT32(layer->dst_rect.right - layer->dst_rect.left); + input_buffer.height = UINT32(layer->dst_rect.bottom - layer->dst_rect.top); + input_buffer.unaligned_width = input_buffer.width; + input_buffer.unaligned_height = input_buffer.height; + layer->src_rect.left = 0; + layer->src_rect.top = 0; + layer->src_rect.right = input_buffer.width; + layer->src_rect.bottom = input_buffer.height; + } + + layer->plane_alpha = hwc_layer.planeAlpha; + layer->flags.cursor = ((hwc_layer.flags & HWC_IS_CURSOR_LAYER) > 0); + layer->flags.updating = true; + + if (num_hw_layers <= kMaxLayerCount) { + layer->flags.updating = IsLayerUpdating(content_list, layer); + } +#ifdef QTI_BSP + if (hwc_layer.flags & HWC_SCREENSHOT_ANIMATOR_LAYER) { + layer_stack_.flags.animating = true; + } +#endif + if (layer->flags.skip) { + layer_stack_.flags.skip_present = true; + } + + if (layer->flags.cursor) { + layer_stack_.flags.cursor_present = true; + } + + PrepareDynamicRefreshRate(layer); + + layer->input_buffer.buffer_id = reinterpret_cast<uint64_t>(hwc_layer.handle); + } + + // Prepare the Blit Target + if (blit_engine_) { + // TODO(user): Fix this to enable BLIT +#if 0 + int ret = blit_engine_->Prepare(&layer_stack_); + if (ret) { + // Blit engine cannot handle this layer stack, hence set the layer stack + // count to num_hw_layers + layer_stack_.layer_count -= kMaxBlitTargetLayers; + } else { + use_blit_comp_ = true; + } +#endif + } + + // Configure layer stack + layer_stack_.flags.geometry_changed = ((content_list->flags & HWC_GEOMETRY_CHANGED) > 0); + + return 0; +} + +void HWCDisplay::SetLayerS3DMode(const LayerBufferS3DFormat &source, uint32_t *target) { +#ifdef QTI_BSP + switch (source) { + case kS3dFormatNone: *target = HWC_S3DMODE_NONE; break; + case kS3dFormatLeftRight: *target = HWC_S3DMODE_LR; break; + case kS3dFormatRightLeft: *target = HWC_S3DMODE_RL; break; + case kS3dFormatTopBottom: *target = HWC_S3DMODE_TB; break; + case kS3dFormatFramePacking: *target = HWC_S3DMODE_FP; break; + default: *target = HWC_S3DMODE_MAX; break; + } +#endif +} + +int HWCDisplay::PrepareLayerStack(hwc_display_contents_1_t *content_list) { + if (shutdown_pending_) { + return 0; + } + + size_t num_hw_layers = content_list->numHwLayers; + + if (!skip_prepare_cnt) { + DisplayError error = display_intf_->Prepare(&layer_stack_); + if (error != kErrorNone) { + if (error == kErrorShutDown) { + shutdown_pending_ = true; + } else if ((error != kErrorPermission) && (error != kErrorNoAppLayers)) { + DLOGE("Prepare failed. Error = %d", error); + // To prevent surfaceflinger infinite wait, flush the previous frame during Commit() + // so that previous buffer and fences are released, and override the error. + flush_ = true; + } else { + DLOGV("Prepare failed for Display = %d Error = %d", type_, error); + } + return 0; + } + } else { + // Skip is not set + MarkLayersForGPUBypass(content_list); + skip_prepare_cnt = skip_prepare_cnt - 1; + DLOGI("SecureDisplay %s, Skip Prepare/Commit and Flush", secure_display_active_ ? "Starting" : + "Stopping"); + flush_ = true; + } + + for (size_t i = 0; i < num_hw_layers; i++) { + hwc_layer_1_t &hwc_layer = content_list->hwLayers[i]; + Layer *layer = layer_stack_.layers.at(i); + LayerComposition composition = layer->composition; + private_handle_t* pvt_handle = static_cast<private_handle_t*> + (const_cast<native_handle_t*>(hwc_layer.handle)); + MetaData_t *meta_data = pvt_handle ? + reinterpret_cast<MetaData_t *>(pvt_handle->base_metadata) : NULL; + + if ((composition == kCompositionSDE) || (composition == kCompositionHybrid) || + (composition == kCompositionBlit)) { + hwc_layer.hints |= HWC_HINT_CLEAR_FB; + } + SetComposition(composition, &hwc_layer.compositionType); + + if (meta_data != NULL) { + if (composition == kCompositionGPUS3D) { + // Align HWC and client's dispaly ID in case of HDMI as primary + meta_data->s3dComp.displayId = + display_intf_->IsPrimaryDisplay() ? HWC_DISPLAY_PRIMARY: id_; + SetLayerS3DMode(layer->input_buffer.s3d_format, + &meta_data->s3dComp.s3dMode); + } + } + } + + return 0; +} + +int HWCDisplay::CommitLayerStack(hwc_display_contents_1_t *content_list) { + if (!content_list || !content_list->numHwLayers) { + DLOGW("Invalid content list"); + return -EINVAL; + } + + if (shutdown_pending_) { + return 0; + } + + int status = 0; + + size_t num_hw_layers = content_list->numHwLayers; + + DumpInputBuffers(content_list); + + if (!flush_) { + for (size_t i = 0; i < num_hw_layers; i++) { + CommitLayerParams(&content_list->hwLayers[i], layer_stack_.layers.at(i)); + } + + if (use_blit_comp_) { + status = blit_engine_->PreCommit(content_list, &layer_stack_); + if (status == 0) { + status = blit_engine_->Commit(content_list, &layer_stack_); + if (status != 0) { + DLOGE("Blit Comp Failed!"); + } + } + } + + if (layer_stack_.flags.hdr_present) { + status = tone_mapper_->HandleToneMap(content_list, &layer_stack_); + if (status != 0) { + DLOGE("Error handling HDR in ToneMapper"); + } + } else { + tone_mapper_->Terminate(); + } + + DisplayError error = kErrorUndefined; + if (status == 0) { + error = display_intf_->Commit(&layer_stack_); + status = 0; + } + + if (error == kErrorNone) { + // A commit is successfully submitted, start flushing on failure now onwards. + flush_on_error_ = true; + } else { + if (error == kErrorShutDown) { + shutdown_pending_ = true; + return status; + } else if (error != kErrorPermission) { + DLOGE("Commit failed. Error = %d", error); + // To prevent surfaceflinger infinite wait, flush the previous frame during Commit() + // so that previous buffer and fences are released, and override the error. + flush_ = true; + } else { + DLOGI("Commit failed for Display = %d Error = %d", type_, error); + } + } + } + + return status; +} + +int HWCDisplay::PostCommitLayerStack(hwc_display_contents_1_t *content_list) { + size_t num_hw_layers = content_list->numHwLayers; + int status = 0; + + // Do no call flush on errors, if a successful buffer is never submitted. + if (flush_ && flush_on_error_) { + display_intf_->Flush(); + } + + + if (tone_mapper_ && tone_mapper_->IsActive()) { + tone_mapper_->PostCommit(&layer_stack_); + } + + // Set the release fence fd to the blit engine + if (use_blit_comp_ && blit_engine_->BlitActive()) { + blit_engine_->PostCommit(&layer_stack_); + } + + for (size_t i = 0; i < num_hw_layers; i++) { + hwc_layer_1_t &hwc_layer = content_list->hwLayers[i]; + Layer *layer = layer_stack_.layers.at(i); + LayerBuffer &layer_buffer = layer->input_buffer; + + if (!flush_) { + // If swapinterval property is set to 0 or for single buffer layers, do not update f/w + // release fences and discard fences from driver + if (swap_interval_zero_ || layer->flags.single_buffer) { + hwc_layer.releaseFenceFd = -1; + close(layer_buffer.release_fence_fd); + layer_buffer.release_fence_fd = -1; + } else if (layer->composition != kCompositionGPU) { + hwc_layer.releaseFenceFd = layer_buffer.release_fence_fd; + } + + // During animation on external/virtual display, SDM will use the cached + // framebuffer layer throughout animation and do not allow framework to do eglswapbuffer on + // framebuffer target. So graphics doesn't close the release fence fd of framebuffer target, + // Hence close the release fencefd of framebuffer target here. + if (disable_animation_) { + if (layer->composition == kCompositionGPUTarget && animating_) { + close(hwc_layer.releaseFenceFd); + hwc_layer.releaseFenceFd = -1; + } + } + } + + if (hwc_layer.acquireFenceFd >= 0) { + close(hwc_layer.acquireFenceFd); + hwc_layer.acquireFenceFd = -1; + } + } + + if (!flush_) { + animating_ = layer_stack_.flags.animating; + // if swapinterval property is set to 0 then close and reset the list retire fence + if (swap_interval_zero_) { + close(layer_stack_.retire_fence_fd); + layer_stack_.retire_fence_fd = -1; + } + content_list->retireFenceFd = layer_stack_.retire_fence_fd; + + if (dump_frame_count_) { + dump_frame_count_--; + dump_frame_index_++; + } + } + + flush_ = false; + + return status; +} + +bool HWCDisplay::IsLayerUpdating(hwc_display_contents_1_t *content_list, const Layer *layer) { + // Layer should be considered updating if + // a) layer is in single buffer mode, or + // b) valid dirty_regions(android specific hint for updating status), or + // c) layer stack geometry has changed + return (layer->flags.single_buffer || IsSurfaceUpdated(layer->dirty_regions) || + (layer_stack_.flags.geometry_changed)); +} + +bool HWCDisplay::IsNonIntegralSourceCrop(const hwc_frect_t &source) { + if ((source.left != roundf(source.left)) || + (source.top != roundf(source.top)) || + (source.right != roundf(source.right)) || + (source.bottom != roundf(source.bottom))) { + return true; + } else { + return false; + } +} + +void HWCDisplay::SetRect(const hwc_rect_t &source, LayerRect *target) { + target->left = FLOAT(source.left); + target->top = FLOAT(source.top); + target->right = FLOAT(source.right); + target->bottom = FLOAT(source.bottom); +} + +void HWCDisplay::SetRect(const hwc_frect_t &source, LayerRect *target) { + target->left = floorf(source.left); + target->top = floorf(source.top); + target->right = ceilf(source.right); + target->bottom = ceilf(source.bottom); +} + +void HWCDisplay::SetComposition(const int32_t &source, LayerComposition *target) { + switch (source) { + case HWC_FRAMEBUFFER_TARGET: *target = kCompositionGPUTarget; break; + default: *target = kCompositionGPU; break; + } +} + +void HWCDisplay::SetComposition(const LayerComposition &source, int32_t *target) { + switch (source) { + case kCompositionGPUTarget: *target = HWC_FRAMEBUFFER_TARGET; break; + case kCompositionGPU: *target = HWC_FRAMEBUFFER; break; + case kCompositionGPUS3D: *target = HWC_FRAMEBUFFER; break; + case kCompositionHWCursor: *target = HWC_CURSOR_OVERLAY; break; + default: *target = HWC_OVERLAY; break; + } +} + +void HWCDisplay::SetBlending(const int32_t &source, LayerBlending *target) { + switch (source) { + case HWC_BLENDING_PREMULT: *target = kBlendingPremultiplied; break; + case HWC_BLENDING_COVERAGE: *target = kBlendingCoverage; break; + default: *target = kBlendingOpaque; break; + } +} + +void HWCDisplay::SetIdleTimeoutMs(uint32_t timeout_ms) { + return; +} + +DisplayError HWCDisplay::SetMaxMixerStages(uint32_t max_mixer_stages) { + DisplayError error = kErrorNone; + + if (display_intf_) { + error = display_intf_->SetMaxMixerStages(max_mixer_stages); + } + + return error; +} + +LayerBufferFormat HWCDisplay::GetSDMFormat(const int32_t &source, const int flags) { + LayerBufferFormat format = kFormatInvalid; + if (flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) { + switch (source) { + case HAL_PIXEL_FORMAT_RGBA_8888: format = kFormatRGBA8888Ubwc; break; + case HAL_PIXEL_FORMAT_RGBX_8888: format = kFormatRGBX8888Ubwc; break; + case HAL_PIXEL_FORMAT_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; + case HAL_PIXEL_FORMAT_RGBA_1010102: format = kFormatRGBA1010102Ubwc; break; + case HAL_PIXEL_FORMAT_RGBX_1010102: format = kFormatRGBX1010102Ubwc; break; + case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC: format = kFormatYCbCr420TP10Ubwc; break; + case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC: format = kFormatYCbCr420P010Ubwc; 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; + case HAL_PIXEL_FORMAT_CbYCrY_422_I: format = kFormatCbYCrY422H2V1Packed; break; + case HAL_PIXEL_FORMAT_RGBA_1010102: format = kFormatRGBA1010102; break; + case HAL_PIXEL_FORMAT_ARGB_2101010: format = kFormatARGB2101010; break; + case HAL_PIXEL_FORMAT_RGBX_1010102: format = kFormatRGBX1010102; break; + case HAL_PIXEL_FORMAT_XRGB_2101010: format = kFormatXRGB2101010; break; + case HAL_PIXEL_FORMAT_BGRA_1010102: format = kFormatBGRA1010102; break; + case HAL_PIXEL_FORMAT_ABGR_2101010: format = kFormatABGR2101010; break; + case HAL_PIXEL_FORMAT_BGRX_1010102: format = kFormatBGRX1010102; break; + case HAL_PIXEL_FORMAT_XBGR_2101010: format = kFormatXBGR2101010; break; + case HAL_PIXEL_FORMAT_YCbCr_420_P010: format = kFormatYCbCr420P010; break; + case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC: format = kFormatYCbCr420TP10Ubwc; break; + case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC: format = kFormatYCbCr420P010Ubwc; break; + default: + DLOGW("Unsupported format type = %d", source); + return kFormatInvalid; + } + + return format; +} + +void HWCDisplay::DumpInputBuffers(hwc_display_contents_1_t *content_list) { + size_t num_hw_layers = content_list->numHwLayers; + char dir_path[PATH_MAX]; + + if (!dump_frame_count_ || flush_ || !dump_input_layers_) { + return; + } + + snprintf(dir_path, sizeof(dir_path), "/data/misc/display/frame_dump_%s", GetDisplayString()); + + if (mkdir(dir_path, 0777) != 0 && errno != EEXIST) { + DLOGW("Failed to create %s directory errno = %d, desc = %s", dir_path, errno, strerror(errno)); + return; + } + + // if directory exists already, need to explicitly change the permission. + if (errno == EEXIST && chmod(dir_path, 0777) != 0) { + DLOGW("Failed to change permissions on %s directory", dir_path); + return; + } + + for (uint32_t i = 0; i < num_hw_layers; i++) { + hwc_layer_1_t &hwc_layer = content_list->hwLayers[i]; + const private_handle_t *pvt_handle = static_cast<const private_handle_t *>(hwc_layer.handle); + + if (hwc_layer.acquireFenceFd >= 0) { + int error = sync_wait(hwc_layer.acquireFenceFd, 1000); + if (error < 0) { + DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno)); + return; + } + } + + if (pvt_handle && pvt_handle->base) { + char dump_file_name[PATH_MAX]; + size_t result = 0; + + snprintf(dump_file_name, sizeof(dump_file_name), "%s/input_layer%d_%dx%d_%s_frame%d.raw", + dir_path, i, pvt_handle->width, pvt_handle->height, + qdutils::GetHALPixelFormatString(pvt_handle->format), dump_frame_index_); + + FILE* fp = fopen(dump_file_name, "w+"); + if (fp) { + result = fwrite(reinterpret_cast<void *>(pvt_handle->base), pvt_handle->size, 1, fp); + fclose(fp); + } + + DLOGI("Frame Dump %s: is %s", dump_file_name, result ? "Successful" : "Failed"); + } + } +} + +void HWCDisplay::DumpOutputBuffer(const BufferInfo& buffer_info, void *base, int fence) { + char dir_path[PATH_MAX]; + + snprintf(dir_path, sizeof(dir_path), "/data/misc/display/frame_dump_%s", GetDisplayString()); + + if (mkdir(dir_path, 777) != 0 && errno != EEXIST) { + DLOGW("Failed to create %s directory errno = %d, desc = %s", dir_path, errno, strerror(errno)); + return; + } + + // if directory exists already, need to explicitly change the permission. + if (errno == EEXIST && chmod(dir_path, 0777) != 0) { + DLOGW("Failed to change permissions on %s directory", dir_path); + return; + } + + if (base) { + char dump_file_name[PATH_MAX]; + size_t result = 0; + + if (fence >= 0) { + int error = sync_wait(fence, 1000); + if (error < 0) { + DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno)); + return; + } + } + + snprintf(dump_file_name, sizeof(dump_file_name), "%s/output_layer_%dx%d_%s_frame%d.raw", + dir_path, buffer_info.alloc_buffer_info.aligned_width, + buffer_info.alloc_buffer_info.aligned_height, + GetFormatString(buffer_info.buffer_config.format), dump_frame_index_); + + FILE* fp = fopen(dump_file_name, "w+"); + if (fp) { + result = fwrite(base, buffer_info.alloc_buffer_info.size, 1, fp); + fclose(fp); + } + + DLOGI("Frame Dump of %s is %s", dump_file_name, result ? "Successful" : "Failed"); + } +} + +const char *HWCDisplay::GetDisplayString() { + switch (type_) { + case kPrimary: + return "primary"; + case kHDMI: + return "hdmi"; + case kVirtual: + return "virtual"; + default: + return "invalid"; + } +} + +int HWCDisplay::SetFrameBufferResolution(uint32_t x_pixels, uint32_t y_pixels) { + DisplayConfigVariableInfo fb_config; + DisplayError error = display_intf_->GetFrameBufferConfig(&fb_config); + if (error != kErrorNone) { + DLOGV("Get frame buffer config failed. Error = %d", error); + return -EINVAL; + } + + fb_config.x_pixels = x_pixels; + fb_config.y_pixels = y_pixels; + + error = display_intf_->SetFrameBufferConfig(fb_config); + if (error != kErrorNone) { + DLOGV("Set frame buffer config failed. Error = %d", error); + return -EINVAL; + } + + DLOGI("New framebuffer resolution (%dx%d)", x_pixels, y_pixels); + + return 0; +} + +void HWCDisplay::GetFrameBufferResolution(uint32_t *x_pixels, uint32_t *y_pixels) { + DisplayConfigVariableInfo fb_config; + display_intf_->GetFrameBufferConfig(&fb_config); + + *x_pixels = fb_config.x_pixels; + *y_pixels = fb_config.y_pixels; +} + +DisplayError HWCDisplay::GetMixerResolution(uint32_t *x_pixels, uint32_t *y_pixels) { + return display_intf_->GetMixerResolution(x_pixels, y_pixels); +} + + +void HWCDisplay::GetPanelResolution(uint32_t *x_pixels, uint32_t *y_pixels) { + DisplayConfigVariableInfo display_config; + uint32_t active_index = 0; + + display_intf_->GetActiveConfig(&active_index); + display_intf_->GetConfig(active_index, &display_config); + + *x_pixels = display_config.x_pixels; + *y_pixels = display_config.y_pixels; +} + +int HWCDisplay::SetDisplayStatus(uint32_t display_status) { + int status = 0; + const hwc_procs_t *hwc_procs = *hwc_procs_; + + switch (display_status) { + case kDisplayStatusResume: + display_paused_ = false; + case kDisplayStatusOnline: + status = SetPowerMode(HWC_POWER_MODE_NORMAL); + break; + case kDisplayStatusPause: + display_paused_ = true; + case kDisplayStatusOffline: + status = SetPowerMode(HWC_POWER_MODE_OFF); + break; + default: + DLOGW("Invalid display status %d", display_status); + return -EINVAL; + } + + if (display_status == kDisplayStatusResume || + display_status == kDisplayStatusPause) { + hwc_procs->invalidate(hwc_procs); + } + + return status; +} + +int HWCDisplay::SetCursorPosition(int x, int y) { + DisplayError error = kErrorNone; + + if (shutdown_pending_) { + return 0; + } + + error = display_intf_->SetCursorPosition(x, y); + if (error != kErrorNone) { + if (error == kErrorShutDown) { + shutdown_pending_ = true; + return 0; + } + DLOGE("Failed for x = %d y = %d, Error = %d", x, y, error); + return -1; + } + + return 0; +} + +int HWCDisplay::OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level) { + DisplayError error = display_intf_->OnMinHdcpEncryptionLevelChange(min_enc_level); + if (error != kErrorNone) { + DLOGE("Failed. Error = %d", error); + return -1; + } + + return 0; +} + +void HWCDisplay::MarkLayersForGPUBypass(hwc_display_contents_1_t *content_list) { + for (size_t i = 0 ; i < (content_list->numHwLayers - 1); i++) { + hwc_layer_1_t *layer = &content_list->hwLayers[i]; + layer->compositionType = HWC_OVERLAY; + } +} + +void HWCDisplay::ApplyScanAdjustment(hwc_rect_t *display_frame) { +} + +DisplayError HWCDisplay::SetCSC(const MetaData_t *meta_data, ColorMetaData *color_metadata) { + if (meta_data->operation & COLOR_METADATA) { +#ifdef USE_COLOR_METADATA + *color_metadata = meta_data->color; +#endif + } else if (meta_data->operation & UPDATE_COLOR_SPACE) { + ColorSpace_t csc = meta_data->colorSpace; + color_metadata->range = Range_Limited; + + if (csc == ITU_R_601_FR || csc == ITU_R_2020_FR) { + color_metadata->range = Range_Full; + } + + switch (csc) { + case ITU_R_601: + case ITU_R_601_FR: + // display driver uses 601 irrespective of 525 or 625 + color_metadata->colorPrimaries = ColorPrimaries_BT601_6_525; + break; + case ITU_R_709: + color_metadata->colorPrimaries = ColorPrimaries_BT709_5; + break; + case ITU_R_2020: + case ITU_R_2020_FR: + color_metadata->colorPrimaries = ColorPrimaries_BT2020; + break; + default: + DLOGE("Unsupported CSC: %d", csc); + return kErrorNotSupported; + } + } + + return kErrorNone; +} + +DisplayError HWCDisplay::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; +} + +DisplayError HWCDisplay::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 (SetCSC(meta_data, &layer_buffer.color_metadata) != kErrorNone) { + return kErrorNotSupported; + } + + bool hdr_layer = layer_buffer.color_metadata.colorPrimaries == ColorPrimaries_BT2020 && + (layer_buffer.color_metadata.transfer == Transfer_SMPTE_ST2084 || + layer_buffer.color_metadata.transfer == Transfer_HLG); + if (hdr_layer && !disable_hdr_handling_) { + // dont honor HDR when its handling is disabled + layer_buffer.flags.hdr = true; + layer_stack_.flags.hdr_present = true; + } + + if (meta_data->operation & SET_IGC) { + if (SetIGC(meta_data->igc, &layer_buffer.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 & SET_SINGLE_BUFFER_MODE) { + layer->flags.single_buffer = meta_data->isSingleBufferMode; + // Graphics can set this operation on all types of layers including FB and set the actual value + // to 0. To protect against SET operations of 0 value, we need to do a logical OR. + layer_stack_.flags.single_buffered_layer_present |= meta_data->isSingleBufferMode; + } + + if (meta_data->operation & S3D_FORMAT) { + std::map<int, LayerBufferS3DFormat>::iterator it = + s3d_format_hwc_to_sdm_.find(INT32(meta_data->s3dFormat)); + if (it != s3d_format_hwc_to_sdm_.end()) { + layer->input_buffer.s3d_format = it->second; + } else { + DLOGW("Invalid S3D format %d", meta_data->s3dFormat); + } + } + + return kErrorNone; +} + +int HWCDisplay::SetPanelBrightness(int level) { + int ret = 0; + if (display_intf_) + ret = display_intf_->SetPanelBrightness(level); + else + ret = -EINVAL; + + return ret; +} + +int HWCDisplay::GetPanelBrightness(int *level) { + return display_intf_->GetPanelBrightness(level); +} + +int HWCDisplay::CachePanelBrightness(int level) { + int ret = 0; + if (display_intf_) + ret = display_intf_->CachePanelBrightness(level); + else + ret = -EINVAL; + + return ret; +} + +int HWCDisplay::ToggleScreenUpdates(bool enable) { + const hwc_procs_t *hwc_procs = *hwc_procs_; + display_paused_ = enable ? false : true; + hwc_procs->invalidate(hwc_procs); + return 0; +} + +int HWCDisplay::ColorSVCRequestRoute(const PPDisplayAPIPayload &in_payload, + PPDisplayAPIPayload *out_payload, + PPPendingParams *pending_action) { + int ret = 0; + + if (display_intf_) + ret = display_intf_->ColorSVCRequestRoute(in_payload, out_payload, pending_action); + else + ret = -EINVAL; + + return ret; +} + +int HWCDisplay::GetVisibleDisplayRect(hwc_rect_t* visible_rect) { + if (!IsValid(display_rect_)) { + return -EINVAL; + } + + visible_rect->left = INT(display_rect_.left); + visible_rect->top = INT(display_rect_.top); + visible_rect->right = INT(display_rect_.right); + visible_rect->bottom = INT(display_rect_.bottom); + DLOGI("Dpy = %d Visible Display Rect(%d %d %d %d)", visible_rect->left, visible_rect->top, + visible_rect->right, visible_rect->bottom); + + return 0; +} + +void HWCDisplay::SetSecureDisplay(bool secure_display_active, bool force_flush) { + secure_display_active_ = secure_display_active; + return; +} + +int HWCDisplay::SetActiveDisplayConfig(int config) { + return display_intf_->SetActiveConfig(UINT32(config)) == kErrorNone ? 0 : -1; +} + +int HWCDisplay::GetActiveDisplayConfig(uint32_t *config) { + return display_intf_->GetActiveConfig(config) == kErrorNone ? 0 : -1; +} + +int HWCDisplay::GetDisplayConfigCount(uint32_t *count) { + return display_intf_->GetNumVariableInfoConfigs(count) == kErrorNone ? 0 : -1; +} + +int HWCDisplay::GetDisplayAttributesForConfig(int config, + DisplayConfigVariableInfo *display_attributes) { + return display_intf_->GetConfig(UINT32(config), display_attributes) == kErrorNone ? 0 : -1; +} + +int HWCDisplay::GetDisplayFixedConfig(DisplayConfigFixedInfo *fixed_info) { + return display_intf_->GetConfig(fixed_info) == kErrorNone ? 0 : -1; +} + +// TODO(user): HWC needs to know updating for dyn_fps, cpu hint features, +// once the features are moved to SDM, the two functions below can be removed. +uint32_t HWCDisplay::GetUpdatingLayersCount(uint32_t app_layer_count) { + uint32_t updating_count = 0; + + for (uint i = 0; i < app_layer_count; i++) { + Layer *layer = layer_stack_.layers.at(i); + if (layer->flags.updating) { + updating_count++; + } + } + + return updating_count; +} + +bool HWCDisplay::SingleVideoLayerUpdating(uint32_t app_layer_count) { + uint32_t updating_count = 0; + + for (uint i = 0; i < app_layer_count; i++) { + Layer *layer = layer_stack_.layers[i]; + // TODO(user): disable DRC feature in S3D playbacl case.S3D video + // need play in dedicate resolution and fps, if DRC switch the + // mode to an non S3D supported mode, it would break S3D playback. + // Need figure out a way to make S3D and DRC co-exist. + if (layer->flags.updating && (layer->input_buffer.flags.video == true) && + (layer->input_buffer.s3d_format == kS3dFormatNone)) { + updating_count++; + } + } + + return (updating_count == 1); +} + +uint32_t HWCDisplay::RoundToStandardFPS(float fps) { + static const uint32_t standard_fps[4] = {30, 24, 48, 60}; + uint32_t frame_rate = (uint32_t)(fps); + + int count = INT(sizeof(standard_fps) / sizeof(standard_fps[0])); + for (int i = 0; i < count; i++) { + if ((standard_fps[i] - frame_rate) < 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 frame_rate; +} + +uint32_t HWCDisplay::SanitizeRefreshRate(uint32_t req_refresh_rate) { + uint32_t refresh_rate = req_refresh_rate; + + if (refresh_rate < min_refresh_rate_) { + // Pick the next multiple of request which is within the range + refresh_rate = (((min_refresh_rate_ / refresh_rate) + + ((min_refresh_rate_ % refresh_rate) ? 1 : 0)) * refresh_rate); + } + + if (refresh_rate > max_refresh_rate_) { + refresh_rate = max_refresh_rate_; + } + + return refresh_rate; +} + +DisplayClass HWCDisplay::GetDisplayClass() { + return display_class_; +} + +void HWCDisplay::PrepareDynamicRefreshRate(Layer *layer) { + if (layer->frame_rate > metadata_refresh_rate_) { + metadata_refresh_rate_ = SanitizeRefreshRate(layer->frame_rate); + } else { + layer->frame_rate = current_refresh_rate_; + } +} + +bool HWCDisplay::IsSurfaceUpdated(const std::vector<LayerRect> &dirty_regions) { + // based on dirty_regions determine if its updating + // dirty_rect count = 0 - whole layer - updating. + // dirty_rect count = 1 or more valid rects - updating. + // dirty_rect count = 1 with (0,0,0,0) - not updating. + return (dirty_regions.empty() || IsValid(dirty_regions.at(0))); +} + +int HWCDisplay::GetDisplayPort(DisplayPort *port) { + return display_intf_->GetDisplayPort(port) == kErrorNone ? 0 : -1; +} + + +} // namespace sdm diff --git a/msm8909/sdm/libs/hwc/hwc_display.h b/msm8909/sdm/libs/hwc/hwc_display.h new file mode 100644 index 00000000..b0a40d5b --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_display.h @@ -0,0 +1,266 @@ +/* +* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __HWC_DISPLAY_H__ +#define __HWC_DISPLAY_H__ + +#include <hardware/hwcomposer.h> +#include <core/core_interface.h> +#include <qdMetaData.h> +#include <QService.h> +#include <private/color_params.h> +#include <map> +#include <vector> +#include <string> + +namespace sdm { + +class BlitEngine; +class HWCToneMapper; + +// 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 HWCColorMode { + public: + explicit HWCColorMode(DisplayInterface *display_intf) : display_intf_(display_intf) {} + ~HWCColorMode() {} + void Init(); + void DeInit() {} + int SetColorMode(const std::string &color_mode); + const std::vector<std::string> &GetColorModes(); + int SetColorTransform(uint32_t matrix_count, const float *matrix); + + private: + static const uint32_t kColorTransformMatrixCount = 16; + template <class T> + void CopyColorTransformMatrix(const T *input_matrix, double *output_matrix) { + for (uint32_t i = 0; i < kColorTransformMatrixCount; i++) { + output_matrix[i] = static_cast<double>(input_matrix[i]); + } + } + int PopulateColorModes(); + DisplayInterface *display_intf_ = NULL; + std::vector<std::string> color_modes_ = {}; + std::string current_color_mode_ = {}; +}; + +class HWCDisplay : public DisplayEventHandler { + 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, + }; + + virtual ~HWCDisplay() { } + virtual int Init(); + virtual int Deinit(); + virtual int Prepare(hwc_display_contents_1_t *content_list) = 0; + virtual int Commit(hwc_display_contents_1_t *content_list) = 0; + virtual int EventControl(int event, int enable); + virtual int SetPowerMode(int mode); + + // Framebuffer configurations + virtual int GetDisplayConfigs(uint32_t *configs, size_t *num_configs); + virtual int GetDisplayAttributes(uint32_t config, const uint32_t *display_attributes, + int32_t *values); + virtual int GetActiveConfig(); + virtual int SetActiveConfig(int index); + + 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) { + return kErrorNotSupported; + } + virtual uint32_t GetLastPowerMode(); + virtual int SetFrameBufferResolution(uint32_t x_pixels, uint32_t y_pixels); + virtual void GetFrameBufferResolution(uint32_t *x_pixels, uint32_t *y_pixels); + virtual int SetDisplayStatus(uint32_t display_status); + virtual int OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level); + virtual int Perform(uint32_t operation, ...); + virtual int SetCursorPosition(int x, int y); + virtual void SetSecureDisplay(bool secure_display_active, bool force_flush); + virtual DisplayError SetMixerResolution(uint32_t width, uint32_t height); + virtual DisplayError GetMixerResolution(uint32_t *width, uint32_t *height); + virtual void GetPanelResolution(uint32_t *width, uint32_t *height); + + // 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; } + + virtual DisplayError SetDetailEnhancerConfig(const DisplayDetailEnhancerData &de_data) { + return kErrorNotSupported; + } + + // 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 *display_attributes); + virtual int GetDisplayFixedConfig(DisplayConfigFixedInfo *fixed_info); + + int SetPanelBrightness(int level); + int GetPanelBrightness(int *level); + int CachePanelBrightness(int level); + int ToggleScreenUpdates(bool enable); + int ColorSVCRequestRoute(const PPDisplayAPIPayload &in_payload, + PPDisplayAPIPayload *out_payload, + PPPendingParams *pending_action); + int GetVisibleDisplayRect(hwc_rect_t* rect); + DisplayClass GetDisplayClass(); + int GetDisplayPort(DisplayPort *port); + + protected: + enum DisplayStatus { + kDisplayStatusOffline = 0, + kDisplayStatusOnline, + kDisplayStatusPause, + kDisplayStatusResume, + }; + + // Dim layer flag set by SurfaceFlinger service. + static const uint32_t kDimLayer = 0x80000000; + + // Maximum number of layers supported by display manager. + static const uint32_t kMaxLayerCount = 32; + + HWCDisplay(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, DisplayType type, int 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); + + int AllocateLayerStack(hwc_display_contents_1_t *content_list); + void FreeLayerStack(); + virtual int PrePrepareLayerStack(hwc_display_contents_1_t *content_list); + virtual int PrepareLayerStack(hwc_display_contents_1_t *content_list); + virtual int CommitLayerStack(hwc_display_contents_1_t *content_list); + virtual int PostCommitLayerStack(hwc_display_contents_1_t *content_list); + virtual void DumpOutputBuffer(const BufferInfo& buffer_info, void *base, int fence); + virtual uint32_t RoundToStandardFPS(float fps); + virtual uint32_t SanitizeRefreshRate(uint32_t req_refresh_rate); + virtual void PrepareDynamicRefreshRate(Layer *layer); + virtual DisplayError DisablePartialUpdateOneFrame() { + return kErrorNotSupported; + } + inline void SetRect(const hwc_rect_t &source, LayerRect *target); + inline void SetRect(const hwc_frect_t &source, LayerRect *target); + inline void SetComposition(const int32_t &source, LayerComposition *target); + inline void SetComposition(const LayerComposition &source, int32_t *target); + inline void SetBlending(const int32_t &source, LayerBlending *target); + int SetFormat(const int32_t &source, const int flags, LayerBufferFormat *target); + void SetLayerS3DMode(const LayerBufferS3DFormat &source, uint32_t *target); + LayerBufferFormat GetSDMFormat(const int32_t &source, const int flags); + const char *GetDisplayString(); + void MarkLayersForGPUBypass(hwc_display_contents_1_t *content_list); + virtual void ApplyScanAdjustment(hwc_rect_t *display_frame); + DisplayError SetCSC(const MetaData_t *meta_data, ColorMetaData *color_metadata); + DisplayError SetIGC(IGC_t source, LayerIGC *target); + DisplayError SetMetaData(const private_handle_t *pvt_handle, Layer *layer); + bool NeedsFrameBufferRefresh(hwc_display_contents_1_t *content_list); + bool IsLayerUpdating(hwc_display_contents_1_t *content_list, const Layer *layer); + bool IsNonIntegralSourceCrop(const hwc_frect_t &source); + uint32_t GetUpdatingLayersCount(uint32_t app_layer_count); + bool SingleVideoLayerUpdating(uint32_t app_layer_count); + bool IsSurfaceUpdated(const std::vector<LayerRect> &dirty_regions); + + enum { + INPUT_LAYER_DUMP, + OUTPUT_LAYER_DUMP, + }; + + CoreInterface *core_intf_; + hwc_procs_t const **hwc_procs_; + DisplayType type_; + int id_; + bool needs_blit_ = false; + DisplayInterface *display_intf_ = NULL; + LayerStack layer_stack_; + 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; + uint32_t last_power_mode_; + bool swap_interval_zero_ = false; + 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; + uint32_t skip_prepare_cnt = 0; + bool solid_fill_enable_ = false; + bool disable_animation_ = false; + uint32_t solid_fill_color_ = 0; + LayerRect display_rect_; + std::map<int, LayerBufferS3DFormat> s3d_format_hwc_to_sdm_; + bool animating_ = false; + HWCToneMapper *tone_mapper_ = NULL; + HWCColorMode *color_mode_ = NULL; + int disable_hdr_handling_ = 0; // disables HDR handling. + + private: + void DumpInputBuffers(hwc_display_contents_1_t *content_list); + int PrepareLayerParams(hwc_layer_1_t *hwc_layer, Layer *layer); + void CommitLayerParams(hwc_layer_1_t *hwc_layer, Layer *layer); + BlitEngine *blit_engine_ = NULL; + qService::QService *qservice_ = NULL; + DisplayClass display_class_; +}; + +inline int HWCDisplay::Perform(uint32_t operation, ...) { + return 0; +} + +} // namespace sdm + +#endif // __HWC_DISPLAY_H__ + diff --git a/msm8909/sdm/libs/hwc/hwc_display_external.cpp b/msm8909/sdm/libs/hwc/hwc_display_external.cpp new file mode 100644 index 00000000..a5358190 --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_display_external.cpp @@ -0,0 +1,336 @@ +/* +* 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 <algorithm> + +#include "hwc_display_external.h" +#include "hwc_debugger.h" + +#define __CLASS__ "HWCDisplayExternal" + +namespace sdm { + +int HWCDisplayExternal::Create(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, + qService::QService *qservice, HWCDisplay **hwc_display) { + return Create(core_intf, hwc_procs, 0, 0, qservice, false, hwc_display); +} + +int HWCDisplayExternal::Create(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, + 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; + int drc_enabled = 0; + int drc_reset_fps_enabled = 0; + DisplayError error = kErrorNone; + + HWCDisplay *hwc_display_external = new HWCDisplayExternal(core_intf, hwc_procs, qservice); + int status = hwc_display_external->Init(); + if (status) { + delete hwc_display_external; + return status; + } + + error = hwc_display_external->GetMixerResolution(&external_width, &external_height); + if (error != kErrorNone) { + return -EINVAL; + } + + 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; + } + + HWCDebugHandler::Get()->GetProperty("sdm.hdmi.drc_enabled", &(drc_enabled)); + reinterpret_cast<HWCDisplayExternal *>(hwc_display_external)->drc_enabled_ = drc_enabled; + + HWCDebugHandler::Get()->GetProperty("sdm.hdmi.drc_reset_fps", &(drc_reset_fps_enabled)); + reinterpret_cast<HWCDisplayExternal *>(hwc_display_external)->drc_reset_fps_enabled_ = + drc_reset_fps_enabled; + + *hwc_display = hwc_display_external; + + return status; +} + +void HWCDisplayExternal::Destroy(HWCDisplay *hwc_display) { + hwc_display->Deinit(); + delete hwc_display; +} + +HWCDisplayExternal::HWCDisplayExternal(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, + qService::QService *qservice) + : HWCDisplay(core_intf, hwc_procs, kHDMI, HWC_DISPLAY_EXTERNAL, false, qservice, + DISPLAY_CLASS_EXTERNAL) { +} + +int HWCDisplayExternal::Prepare(hwc_display_contents_1_t *content_list) { + int status = 0; + DisplayError error = kErrorNone; + + if (secure_display_active_) { + MarkLayersForGPUBypass(content_list); + return status; + } + + status = AllocateLayerStack(content_list); + if (status) { + return status; + } + + status = PrePrepareLayerStack(content_list); + if (status) { + return status; + } + + if (content_list->numHwLayers <= 1) { + flush_ = true; + return 0; + } + + bool one_video_updating_layer = SingleVideoLayerUpdating(UINT32(content_list->numHwLayers - 1)); + + uint32_t refresh_rate = GetOptimalRefreshRate(one_video_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; + } + } + + status = PrepareLayerStack(content_list); + if (status) { + return status; + } + + return 0; +} + +int HWCDisplayExternal::Commit(hwc_display_contents_1_t *content_list) { + int status = 0; + + if (secure_display_active_) { + return status; + } + + status = HWCDisplay::CommitLayerStack(content_list); + if (status) { + return status; + } + + status = HWCDisplay::PostCommitLayerStack(content_list); + if (status) { + return status; + } + + return 0; +} + +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 mixer_width = 0; + uint32_t mixer_height = 0; + GetMixerResolution(&mixer_width, &mixer_height); + + if (mixer_width == 0 || mixer_height == 0) { + DLOGV("Invalid mixer dimensions (%d, %d)", mixer_width, mixer_height); + return; + } + + uint32_t new_mixer_width = UINT32(mixer_width * FLOAT(1.0f - width_ratio)); + uint32_t new_mixer_height = UINT32(mixer_height * FLOAT(1.0f - height_ratio)); + + int x_offset = INT((FLOAT(mixer_width) * width_ratio) / 2.0f); + int y_offset = INT((FLOAT(mixer_height) * height_ratio) / 2.0f); + + display_frame->left = (display_frame->left * INT32(new_mixer_width) / INT32(mixer_width)) + + x_offset; + display_frame->top = (display_frame->top * INT32(new_mixer_height) / INT32(mixer_height)) + + y_offset; + display_frame->right = ((display_frame->right * INT32(new_mixer_width)) / INT32(mixer_width)) + + x_offset; + display_frame->bottom = ((display_frame->bottom * INT32(new_mixer_height)) / INT32(mixer_height)) + + y_offset; +} + +void HWCDisplayExternal::SetSecureDisplay(bool secure_display_active, bool force_flush) { + 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) { + std::swap(primary_height, primary_width); + } + AdjustSourceResolution(primary_width, primary_height, non_primary_width, non_primary_height); + } +} + +uint32_t HWCDisplayExternal::RoundToStandardFPS(float fps) { + static const uint32_t standard_fps[] = {23976, 24000, 25000, 29970, 30000, 50000, 59940, 60000}; + static const uint32_t mapping_fps[] = {59940, 60000, 60000, 59940, 60000, 50000, 59940, 60000}; + uint32_t frame_rate = (uint32_t)(fps * 1000); + + // process non valid + if (frame_rate == 0) { + return current_refresh_rate_; + } + + int count = INT(sizeof(standard_fps) / sizeof(standard_fps[0])); + for (int i = 0; i < count; i++) { + // Most likely used for video, the fps for frames should be stable from video side. + if (standard_fps[i] > frame_rate) { + if (i > 0) { + if ((standard_fps[i] - frame_rate) > (frame_rate - standard_fps[i-1])) { + return mapping_fps[i-1]; + } else { + return mapping_fps[i]; + } + } else { + return mapping_fps[i]; + } + } + } + + return standard_fps[count - 1]; +} + +void HWCDisplayExternal::PrepareDynamicRefreshRate(Layer *layer) { + if (layer->input_buffer.flags.video) { + if (layer->frame_rate != 0) { + metadata_refresh_rate_ = SanitizeRefreshRate(layer->frame_rate); + } else { + metadata_refresh_rate_ = current_refresh_rate_; + } + layer->frame_rate = current_refresh_rate_; + } else if (!layer->frame_rate) { + layer->frame_rate = current_refresh_rate_; + } +} + +void HWCDisplayExternal::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; +} + +uint32_t HWCDisplayExternal::GetOptimalRefreshRate(bool one_updating_layer) { + if (force_refresh_rate_) { + return force_refresh_rate_; + } else if (one_updating_layer && drc_enabled_) { + return metadata_refresh_rate_; + } + + if (drc_reset_fps_enabled_) { + DisplayConfigVariableInfo fb_config; + display_intf_->GetFrameBufferConfig(&fb_config); + return (fb_config.fps * 1000); + } + + return current_refresh_rate_; +} + +int HWCDisplayExternal::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_BINDER_DYN_REFRESH_RATE: + ForceRefreshRate(UINT32(val)); + break; + default: + DLOGW("Invalid operation %d", operation); + return -EINVAL; + } + + return 0; +} + +} // namespace sdm + diff --git a/msm8909/sdm/libs/hwc/hwc_display_external.h b/msm8909/sdm/libs/hwc/hwc_display_external.h new file mode 100644 index 00000000..c5ac3d75 --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_display_external.h @@ -0,0 +1,64 @@ +/* +* 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, hwc_procs_t const **hwc_procs, uint32_t primary_width, + uint32_t primary_height, qService::QService *qservice, bool use_primary_res, + HWCDisplay **hwc_display); + static int Create(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, + qService::QService *qservice, HWCDisplay **hwc_display); + static void Destroy(HWCDisplay *hwc_display); + virtual int Prepare(hwc_display_contents_1_t *content_list); + virtual int Commit(hwc_display_contents_1_t *content_list); + virtual void SetSecureDisplay(bool secure_display_active, bool force_flush); + virtual int Perform(uint32_t operation, ...); + + protected: + virtual uint32_t RoundToStandardFPS(float fps); + virtual void PrepareDynamicRefreshRate(Layer *layer); + int drc_enabled_ = 0; + int drc_reset_fps_enabled_ = 0; + + private: + HWCDisplayExternal(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, + 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); + void ForceRefreshRate(uint32_t refresh_rate); + uint32_t GetOptimalRefreshRate(bool one_updating_layer); +}; + +} // namespace sdm + +#endif // __HWC_DISPLAY_EXTERNAL_H__ + diff --git a/msm8909/sdm/libs/hwc/hwc_display_external_test.cpp b/msm8909/sdm/libs/hwc/hwc_display_external_test.cpp new file mode 100644 index 00000000..e629cd61 --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_display_external_test.cpp @@ -0,0 +1,764 @@ +/* +* Copyright (c) 2017, 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 <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <utils/constants.h> +#include <utils/debug.h> +#include <utils/formats.h> +#include <algorithm> +#include <array> +#include <sstream> +#include <string> +#include <fstream> + +#include "hwc_display_external_test.h" +#include "hwc_debugger.h" + +#define __CLASS__ "HWCDisplayExternalTest" + +namespace sdm { + +using std::array; + +int HWCDisplayExternalTest::Create(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, + qService::QService *qservice, uint32_t panel_bpp, + uint32_t pattern_type, HWCDisplay **hwc_display) { + HWCDisplay *hwc_external_test = new HWCDisplayExternalTest(core_intf, hwc_procs, qservice, + panel_bpp, pattern_type); + + int status = static_cast<HWCDisplayExternalTest *>(hwc_external_test)->Init(); + if (status) { + delete hwc_external_test; + return status; + } + + *hwc_display = hwc_external_test; + + DLOGI("panel_bpp %d, pattern_type %d", panel_bpp, pattern_type); + + return status; +} + +void HWCDisplayExternalTest::Destroy(HWCDisplay *hwc_display) { + static_cast<HWCDisplayExternalTest *>(hwc_display)->Deinit(); + + delete hwc_display; +} + +HWCDisplayExternalTest::HWCDisplayExternalTest(CoreInterface *core_intf, + hwc_procs_t const **hwc_procs, + qService::QService *qservice, uint32_t panel_bpp, + uint32_t pattern_type) + : HWCDisplay(core_intf, hwc_procs, kHDMI, HWC_DISPLAY_EXTERNAL, false, qservice, + DISPLAY_CLASS_EXTERNAL), panel_bpp_(panel_bpp), pattern_type_(pattern_type) { +} + +int HWCDisplayExternalTest::Init() { + uint32_t external_width = 0; + uint32_t external_height = 0; + + int status = HWCDisplay::Init(); + if (status) { + return status; + } + + buffer_allocator_ = new HWCBufferAllocator(); + + status = CreateLayerStack(); + if (status) { + Deinit(); + return status; + } + + DisplayError error = HWCDisplay::GetMixerResolution(&external_width, &external_height); + if (error != kErrorNone) { + Deinit(); + return -EINVAL; + } + + status = HWCDisplay::SetFrameBufferResolution(external_width, external_height); + if (status) { + Deinit(); + return status; + } + + return status; +} + +int HWCDisplayExternalTest::Deinit() { + DestroyLayerStack(); + + delete buffer_allocator_; + buffer_allocator_ = NULL; + + return HWCDisplay::Deinit(); +} + + +int HWCDisplayExternalTest::Prepare(hwc_display_contents_1_t *content_list) { + int status = 0; + + if (secure_display_active_) { + MarkLayersForGPUBypass(content_list); + return status; + } + + if (!content_list || !content_list->numHwLayers) { + DLOGW("Invalid content list"); + return -EINVAL; + } + + if (shutdown_pending_) { + return 0; + } + + DisplayError error = display_intf_->Prepare(&layer_stack_); + if (error != kErrorNone) { + if (error == kErrorShutDown) { + shutdown_pending_ = true; + } else if (error != kErrorPermission) { + DLOGE("Prepare failed. Error = %d", error); + // To prevent surfaceflinger infinite wait, flush the previous frame during Commit() + // so that previous buffer and fences are released, and override the error. + flush_ = true; + } + } + + MarkLayersForGPUBypass(content_list); + + return 0; +} + +int HWCDisplayExternalTest::Commit(hwc_display_contents_1_t *content_list) { + int status = 0; + + if (secure_display_active_) { + return status; + } + + if (!content_list || !content_list->numHwLayers) { + DLOGW("Invalid content list"); + return -EINVAL; + } + + if (shutdown_pending_) { + return 0; + } + + DumpInputBuffer(); + + if (!flush_) { + DisplayError error = kErrorUndefined; + + error = display_intf_->Commit(&layer_stack_); + if (error == kErrorNone) { + // A commit is successfully submitted, start flushing on failure now onwards. + flush_on_error_ = true; + } else { + if (error == kErrorShutDown) { + shutdown_pending_ = true; + return status; + } else if (error != kErrorPermission) { + DLOGE("Commit failed. Error = %d", error); + // To prevent surfaceflinger infinite wait, flush the previous frame during Commit() + // so that previous buffer and fences are released, and override the error. + flush_ = true; + } + } + } + + return PostCommit(content_list); +} + +void HWCDisplayExternalTest::SetSecureDisplay(bool secure_display_active, bool force_flush) { + 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; +} + +int HWCDisplayExternalTest::Perform(uint32_t operation, ...) { + return 0; +} + +void HWCDisplayExternalTest::DumpInputBuffer() { + if (!dump_frame_count_ || flush_ || !dump_input_layers_) { + return; + } + + const char *dir_path = "/data/misc/display/frame_dump_external"; + uint32_t width = buffer_info_.alloc_buffer_info.aligned_width; + uint32_t height = buffer_info_.alloc_buffer_info.aligned_height; + string format_str = GetFormatString(buffer_info_.buffer_config.format); + + char *buffer = reinterpret_cast<char *>(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) { + DLOGW("mmap failed. err = %d", errno); + return; + } + + if (mkdir(dir_path, 0777) != 0 && errno != EEXIST) { + DLOGW("Failed to create %s directory errno = %d, desc = %s", dir_path, errno, strerror(errno)); + return; + } + + // if directory exists already, need to explicitly change the permission. + if (errno == EEXIST && chmod(dir_path, 0777) != 0) { + DLOGW("Failed to change permissions on %s directory", dir_path); + return; + } + + if (buffer) { + std::stringstream dump_file_name; + dump_file_name << dir_path; + dump_file_name << "/input_layer_" << width << "x" << height << "_" << format_str << ".raw"; + + std::fstream fs; + fs.open(dump_file_name.str().c_str(), std::fstream::in | std::fstream::out | std::fstream::app); + if (!fs.is_open()) { + DLOGI("File open failed %s", dump_file_name.str().c_str()); + return; + } + + fs.write(buffer, (std::streamsize)buffer_info_.alloc_buffer_info.size); + fs.close(); + + DLOGI("Frame Dump %s: is successful", dump_file_name.str().c_str()); + } + + // Dump only once as the content is going to be same for all draw cycles + if (dump_frame_count_) { + dump_frame_count_ = 0; + } + + if (munmap(buffer, buffer_info_.alloc_buffer_info.size) != 0) { + DLOGW("munmap failed. err = %d", errno); + return; + } +} + +void HWCDisplayExternalTest::CalcCRC(uint32_t color_val, std::bitset<16> *crc_data) { + std::bitset<16> color = {}; + std::bitset<16> temp_crc = {}; + + switch (panel_bpp_) { + case kDisplayBpp18: + color = (color_val & 0xFC) << 8; + break; + case kDisplayBpp24: + color = color_val << 8; + break; + case kDisplayBpp30: + color = color_val << 6; + break; + default: + return; + } + + temp_crc[15] = (*crc_data)[0] ^ (*crc_data)[1] ^ (*crc_data)[2] ^ (*crc_data)[3] ^ + (*crc_data)[4] ^ (*crc_data)[5] ^ (*crc_data)[6] ^ (*crc_data)[7] ^ + (*crc_data)[8] ^ (*crc_data)[9] ^ (*crc_data)[10] ^ (*crc_data)[11] ^ + (*crc_data)[12] ^ (*crc_data)[14] ^ (*crc_data)[15] ^ color[0] ^ color[1] ^ + color[2] ^ color[3] ^ color[4] ^ color[5] ^ color[6] ^ color[7] ^ color[8] ^ + color[9] ^ color[10] ^ color[11] ^ color[12] ^ color[14] ^ color[15]; + + temp_crc[14] = (*crc_data)[12] ^ (*crc_data)[13] ^ color[12] ^ color[13]; + temp_crc[13] = (*crc_data)[11] ^ (*crc_data)[12] ^ color[11] ^ color[12]; + temp_crc[12] = (*crc_data)[10] ^ (*crc_data)[11] ^ color[10] ^ color[11]; + temp_crc[11] = (*crc_data)[9] ^ (*crc_data)[10] ^ color[9] ^ color[10]; + temp_crc[10] = (*crc_data)[8] ^ (*crc_data)[9] ^ color[8] ^ color[9]; + temp_crc[9] = (*crc_data)[7] ^ (*crc_data)[8] ^ color[7] ^ color[8]; + temp_crc[8] = (*crc_data)[6] ^ (*crc_data)[7] ^ color[6] ^ color[7]; + temp_crc[7] = (*crc_data)[5] ^ (*crc_data)[6] ^ color[5] ^ color[6]; + temp_crc[6] = (*crc_data)[4] ^ (*crc_data)[5] ^ color[4] ^ color[5]; + temp_crc[5] = (*crc_data)[3] ^ (*crc_data)[4] ^ color[3] ^ color[4]; + temp_crc[4] = (*crc_data)[2] ^ (*crc_data)[3] ^ color[2] ^ color[3]; + temp_crc[3] = (*crc_data)[1] ^ (*crc_data)[2] ^ (*crc_data)[15] ^ color[1] ^ color[2] ^ color[15]; + temp_crc[2] = (*crc_data)[0] ^ (*crc_data)[1] ^ (*crc_data)[14] ^ color[0] ^ color[1] ^ color[14]; + + temp_crc[1] = (*crc_data)[1] ^ (*crc_data)[2] ^ (*crc_data)[3] ^ (*crc_data)[4] ^ (*crc_data)[5] ^ + (*crc_data)[6] ^ (*crc_data)[7] ^ (*crc_data)[8] ^ (*crc_data)[9] ^ + (*crc_data)[10] ^ (*crc_data)[11] ^ (*crc_data)[12] ^ (*crc_data)[13] ^ + (*crc_data)[14] ^ color[1] ^ color[2] ^ color[3] ^ color[4] ^ color[5] ^ color[6] ^ + color[7] ^ color[8] ^ color[9] ^ color[10] ^ color[11] ^ color[12] ^ color[13] ^ + color[14]; + + temp_crc[0] = (*crc_data)[0] ^ (*crc_data)[1] ^ (*crc_data)[2] ^ (*crc_data)[3] ^ (*crc_data)[4] ^ + (*crc_data)[5] ^ (*crc_data)[6] ^ (*crc_data)[7] ^ (*crc_data)[8] ^ (*crc_data)[9] ^ + (*crc_data)[10] ^ (*crc_data)[11] ^ (*crc_data)[12] ^ (*crc_data)[13] ^ + (*crc_data)[15] ^ color[0] ^ color[1] ^ color[2] ^ color[3] ^ color[4] ^ color[5] ^ + color[6] ^ color[7] ^ color[8] ^ color[9] ^ color[10] ^ color[11] ^ color[12] ^ + color[13] ^ color[15]; + + (*crc_data) = temp_crc; +} + +int HWCDisplayExternalTest::FillBuffer() { + uint8_t *buffer = reinterpret_cast<uint8_t *>(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); + return -EFAULT; + } + + switch (pattern_type_) { + case kPatternColorRamp: + GenerateColorRamp(buffer); + break; + case kPatternBWVertical: + GenerateBWVertical(buffer); + break; + case kPatternColorSquare: + GenerateColorSquare(buffer); + break; + default: + DLOGW("Invalid Pattern type %d", pattern_type_); + return -EINVAL; + } + + if (munmap(buffer, buffer_info_.alloc_buffer_info.size) != 0) { + DLOGE("munmap failed. err = %d", errno); + return -EFAULT; + } + + return 0; +} + +int HWCDisplayExternalTest::GetStride(LayerBufferFormat format, uint32_t width, uint32_t *stride) { + switch (format) { + case kFormatRGBA8888: + case kFormatRGBA1010102: + *stride = width * 4; + break; + case kFormatRGB888: + *stride = width * 3; + break; + default: + DLOGE("Unsupported format type %d", format); + return -EINVAL; + } + + return 0; +} + +void HWCDisplayExternalTest::PixelCopy(uint32_t red, uint32_t green, uint32_t blue, uint32_t alpha, + uint8_t **buffer) { + LayerBufferFormat format = buffer_info_.buffer_config.format; + + switch (format) { + case kFormatRGBA8888: + *(*buffer)++ = UINT8(red & 0xFF); + *(*buffer)++ = UINT8(green & 0xFF); + *(*buffer)++ = UINT8(blue & 0xFF); + *(*buffer)++ = UINT8(alpha & 0xFF); + break; + case kFormatRGB888: + *(*buffer)++ = UINT8(red & 0xFF); + *(*buffer)++ = UINT8(green & 0xFF); + *(*buffer)++ = UINT8(blue & 0xFF); + break; + case kFormatRGBA1010102: + // Lower 8 bits of red + *(*buffer)++ = UINT8(red & 0xFF); + + // Upper 2 bits of Red + Lower 6 bits of green + *(*buffer)++ = UINT8(((green & 0x3F) << 2) | ((red >> 0x8) & 0x3)); + + // Upper 4 bits of green + Lower 4 bits of blue + *(*buffer)++ = UINT8(((blue & 0xF) << 4) | ((green >> 6) & 0xF)); + + // Upper 6 bits of blue + Lower 2 bits of alpha + *(*buffer)++ = UINT8(((alpha & 0x3) << 6) | ((blue >> 4) & 0x3F)); + break; + default: + DLOGW("format not supported format = %d", format); + break; + } +} + +void HWCDisplayExternalTest::GenerateColorRamp(uint8_t *buffer) { + uint32_t width = buffer_info_.buffer_config.width; + uint32_t height = buffer_info_.buffer_config.height; + LayerBufferFormat format = buffer_info_.buffer_config.format; + uint32_t aligned_width = buffer_info_.alloc_buffer_info.aligned_width; + uint32_t buffer_stride = 0; + + uint32_t color_ramp = 0; + uint32_t start_color_val = 0; + uint32_t step_size = 1; + uint32_t ramp_width = 0; + uint32_t ramp_height = 0; + uint32_t shift_by = 0; + + std::bitset<16> crc_red = {}; + std::bitset<16> crc_green = {}; + std::bitset<16> crc_blue = {}; + + switch (panel_bpp_) { + case kDisplayBpp18: + ramp_height = 64; + ramp_width = 64; + shift_by = 2; + break; + case kDisplayBpp24: + ramp_height = 64; + ramp_width = 256; + break; + case kDisplayBpp30: + ramp_height = 32; + ramp_width = 256; + start_color_val = 0x180; + break; + default: + return; + } + + GetStride(format, aligned_width, &buffer_stride); + + for (uint32_t loop_height = 0; loop_height < height; loop_height++) { + uint32_t color_value = start_color_val; + uint8_t *temp = buffer + (loop_height * buffer_stride); + + for (uint32_t loop_width = 0; loop_width < width; loop_width++) { + if (color_ramp == kColorRedRamp) { + PixelCopy(color_value, 0, 0, 0, &temp); + CalcCRC(color_value, &crc_red); + CalcCRC(0, &crc_green); + CalcCRC(0, &crc_blue); + } + if (color_ramp == kColorGreenRamp) { + PixelCopy(0, color_value, 0, 0, &temp); + CalcCRC(0, &crc_red); + CalcCRC(color_value, &crc_green); + CalcCRC(0, &crc_blue); + } + if (color_ramp == kColorBlueRamp) { + PixelCopy(0, 0, color_value, 0, &temp); + CalcCRC(0, &crc_red); + CalcCRC(0, &crc_green); + CalcCRC(color_value, &crc_blue); + } + if (color_ramp == kColorWhiteRamp) { + PixelCopy(color_value, color_value, color_value, 0, &temp); + CalcCRC(color_value, &crc_red); + CalcCRC(color_value, &crc_green); + CalcCRC(color_value, &crc_blue); + } + + color_value = (start_color_val + (((loop_width + 1) % ramp_width) * step_size)) << shift_by; + } + + if (panel_bpp_ == kDisplayBpp30 && ((loop_height + 1) % ramp_height) == 0) { + if (start_color_val == 0x180) { + start_color_val = 0; + step_size = 4; + } else { + start_color_val = 0x180; + step_size = 1; + color_ramp = (color_ramp + 1) % 4; + } + continue; + } + + if (((loop_height + 1) % ramp_height) == 0) { + color_ramp = (color_ramp + 1) % 4; + } + } + + DLOGI("CRC red %x", crc_red.to_ulong()); + DLOGI("CRC green %x", crc_green.to_ulong()); + DLOGI("CRC blue %x", crc_blue.to_ulong()); +} + +void HWCDisplayExternalTest::GenerateBWVertical(uint8_t *buffer) { + uint32_t width = buffer_info_.buffer_config.width; + uint32_t height = buffer_info_.buffer_config.height; + LayerBufferFormat format = buffer_info_.buffer_config.format; + uint32_t aligned_width = buffer_info_.alloc_buffer_info.aligned_width; + uint32_t buffer_stride = 0; + uint32_t bits_per_component = panel_bpp_ / 3; + uint32_t max_color_val = (1 << bits_per_component) - 1; + + std::bitset<16> crc_red = {}; + std::bitset<16> crc_green = {}; + std::bitset<16> crc_blue = {}; + + if (panel_bpp_ == kDisplayBpp18) { + max_color_val <<= 2; + } + + GetStride(format, aligned_width, &buffer_stride); + + for (uint32_t loop_height = 0; loop_height < height; loop_height++) { + uint32_t color = 0; + uint8_t *temp = buffer + (loop_height * buffer_stride); + + for (uint32_t loop_width = 0; loop_width < width; loop_width++) { + if (color == kColorBlack) { + PixelCopy(0, 0, 0, 0, &temp); + CalcCRC(0, &crc_red); + CalcCRC(0, &crc_green); + CalcCRC(0, &crc_blue); + } + if (color == kColorWhite) { + PixelCopy(max_color_val, max_color_val, max_color_val, 0, &temp); + CalcCRC(max_color_val, &crc_red); + CalcCRC(max_color_val, &crc_green); + CalcCRC(max_color_val, &crc_blue); + } + + color = (color + 1) % 2; + } + } + + DLOGI("CRC red %x", crc_red.to_ulong()); + DLOGI("CRC green %x", crc_green.to_ulong()); + DLOGI("CRC blue %x", crc_blue.to_ulong()); +} + +void HWCDisplayExternalTest::GenerateColorSquare(uint8_t *buffer) { + uint32_t width = buffer_info_.buffer_config.width; + uint32_t height = buffer_info_.buffer_config.height; + LayerBufferFormat format = buffer_info_.buffer_config.format; + uint32_t aligned_width = buffer_info_.alloc_buffer_info.aligned_width; + uint32_t buffer_stride = 0; + uint32_t max_color_val = 0; + uint32_t min_color_val = 0; + + std::bitset<16> crc_red = {}; + std::bitset<16> crc_green = {}; + std::bitset<16> crc_blue = {}; + + switch (panel_bpp_) { + case kDisplayBpp18: + max_color_val = 63 << 2; // CEA Dynamic range for 18bpp 0 - 63 + min_color_val = 0; + break; + case kDisplayBpp24: + max_color_val = 235; // CEA Dynamic range for 24bpp 16 - 235 + min_color_val = 16; + break; + case kDisplayBpp30: + max_color_val = 940; // CEA Dynamic range for 30bpp 64 - 940 + min_color_val = 64; + break; + default: + return; + } + + array<array<uint32_t, 3>, 8> colors = {{ + {{max_color_val, max_color_val, max_color_val}}, // White Color + {{max_color_val, max_color_val, min_color_val}}, // Yellow Color + {{min_color_val, max_color_val, max_color_val}}, // Cyan Color + {{min_color_val, max_color_val, min_color_val}}, // Green Color + {{max_color_val, min_color_val, max_color_val}}, // Megenta Color + {{max_color_val, min_color_val, min_color_val}}, // Red Color + {{min_color_val, min_color_val, max_color_val}}, // Blue Color + {{min_color_val, min_color_val, min_color_val}}, // Black Color + }}; + + GetStride(format, aligned_width, &buffer_stride); + + for (uint32_t loop_height = 0; loop_height < height; loop_height++) { + uint32_t color = 0; + uint8_t *temp = buffer + (loop_height * buffer_stride); + + for (uint32_t loop_width = 0; loop_width < width; loop_width++) { + PixelCopy(colors[color][0], colors[color][1], colors[color][2], 0, &temp); + CalcCRC(colors[color][0], &crc_red); + CalcCRC(colors[color][1], &crc_green); + CalcCRC(colors[color][2], &crc_blue); + + if (((loop_width + 1) % 64) == 0) { + color = (color + 1) % colors.size(); + } + } + + if (((loop_height + 1) % 64) == 0) { + std::reverse(colors.begin(), (colors.end() - 1)); + } + } + + DLOGI("CRC red %x", crc_red.to_ulong()); + DLOGI("CRC green %x", crc_green.to_ulong()); + DLOGI("CRC blue %x", crc_blue.to_ulong()); +} + +int HWCDisplayExternalTest::InitLayer(Layer *layer) { + uint32_t active_config = 0; + DisplayConfigVariableInfo var_info = {}; + + GetActiveDisplayConfig(&active_config); + + GetDisplayAttributesForConfig(INT32(active_config), &var_info); + + layer->flags.updating = 1; + layer->src_rect = LayerRect(0, 0, var_info.x_pixels, var_info.y_pixels); + layer->dst_rect = layer->src_rect; + layer->frame_rate = var_info.fps; + layer->blending = kBlendingPremultiplied; + + layer->input_buffer.unaligned_width = var_info.x_pixels; + layer->input_buffer.unaligned_height = var_info.y_pixels; + buffer_info_.buffer_config.format = kFormatRGBA8888; + + if (layer->composition != kCompositionGPUTarget) { + buffer_info_.buffer_config.width = var_info.x_pixels; + buffer_info_.buffer_config.height = var_info.y_pixels; + switch (panel_bpp_) { + case kDisplayBpp18: + case kDisplayBpp24: + buffer_info_.buffer_config.format = kFormatRGB888; + break; + case kDisplayBpp30: + buffer_info_.buffer_config.format = kFormatRGBA1010102; + break; + default: + DLOGW("panel bpp not supported %d", panel_bpp_); + return -EINVAL; + } + buffer_info_.buffer_config.buffer_count = 1; + + int ret = buffer_allocator_->AllocateBuffer(&buffer_info_); + if (ret != 0) { + DLOGE("Buffer allocation failed. ret: %d", ret); + return -ENOMEM; + } + + ret = FillBuffer(); + if (ret != 0) { + buffer_allocator_->FreeBuffer(&buffer_info_); + return ret; + } + + layer->input_buffer.width = buffer_info_.alloc_buffer_info.aligned_width; + layer->input_buffer.height = buffer_info_.alloc_buffer_info.aligned_height; + layer->input_buffer.size = buffer_info_.alloc_buffer_info.size; + layer->input_buffer.planes[0].fd = buffer_info_.alloc_buffer_info.fd; + layer->input_buffer.planes[0].stride = buffer_info_.alloc_buffer_info.stride; + layer->input_buffer.format = buffer_info_.buffer_config.format; + + DLOGI("Input buffer WxH %dx%d format %s size %d fd %d stride %d", layer->input_buffer.width, + layer->input_buffer.height, GetFormatString(layer->input_buffer.format), + layer->input_buffer.size, layer->input_buffer.planes[0].fd, + layer->input_buffer.planes[0].stride); + } + + return 0; +} + +int HWCDisplayExternalTest::DeinitLayer(Layer *layer) { + if (layer->composition != kCompositionGPUTarget) { + int ret = buffer_allocator_->FreeBuffer(&buffer_info_); + if (ret != 0) { + DLOGE("Buffer deallocation failed. ret: %d", ret); + return -ENOMEM; + } + } + + return 0; +} + +int HWCDisplayExternalTest::CreateLayerStack() { + for (uint32_t i = 0; i < (kTestLayerCnt + 1 /* one dummy gpu_target layer */); i++) { + Layer *layer = new Layer(); + + if (i == kTestLayerCnt) { + layer->composition = kCompositionGPUTarget; + } + + int ret = InitLayer(layer); + if (ret != 0) { + delete layer; + return ret; + } + layer_stack_.layers.push_back(layer); + } + + return 0; +} + +int HWCDisplayExternalTest::DestroyLayerStack() { + for (uint32_t i = 0; i < UINT32(layer_stack_.layers.size()); i++) { + Layer *layer = layer_stack_.layers.at(i); + int ret = DeinitLayer(layer); + if (ret != 0) { + return ret; + } + + delete layer; + } + + layer_stack_.layers = {}; + + return 0; +} + +int HWCDisplayExternalTest::PostCommit(hwc_display_contents_1_t *content_list) { + int status = 0; + + // Do no call flush on errors, if a successful buffer is never submitted. + if (flush_ && flush_on_error_) { + display_intf_->Flush(); + } + + if (!flush_) { + for (size_t i = 0; i < layer_stack_.layers.size(); i++) { + Layer *layer = layer_stack_.layers.at(i); + LayerBuffer &layer_buffer = layer->input_buffer; + + close(layer_buffer.release_fence_fd); + layer_buffer.release_fence_fd = -1; + } + + close(layer_stack_.retire_fence_fd); + layer_stack_.retire_fence_fd = -1; + content_list->retireFenceFd = -1; + } + + flush_ = false; + + return status; +} + +} // namespace sdm + diff --git a/msm8909/sdm/libs/hwc/hwc_display_external_test.h b/msm8909/sdm/libs/hwc/hwc_display_external_test.h new file mode 100644 index 00000000..050823e2 --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_display_external_test.h @@ -0,0 +1,102 @@ +/* +* Copyright (c) 2017, 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_TEST_H__ +#define __HWC_DISPLAY_EXTERNAL_TEST_H__ + +#include<bitset> + +#include "hwc_display.h" +#include "hwc_buffer_allocator.h" + +namespace sdm { + +class HWCDisplayExternalTest : public HWCDisplay { + public: + static int Create(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, + qService::QService *qservice, uint32_t panel_bpp, uint32_t pattern_type, + HWCDisplay **hwc_display); + static void Destroy(HWCDisplay *hwc_display); + virtual int Prepare(hwc_display_contents_1_t *content_list); + virtual int Commit(hwc_display_contents_1_t *content_list); + virtual void SetSecureDisplay(bool secure_display_active, bool force_flush); + virtual int Perform(uint32_t operation, ...); + + protected: + HWCBufferAllocator *buffer_allocator_ = NULL; + BufferInfo buffer_info_ = {}; + uint32_t panel_bpp_ = 0; + uint32_t pattern_type_ = 0; + + enum ColorPatternType { + kPatternNone = 0, + kPatternColorRamp, + kPatternBWVertical, + kPatternColorSquare, + }; + + enum DisplayBpp { + kDisplayBpp18 = 18, + kDisplayBpp24 = 24, + kDisplayBpp30 = 30, + }; + + enum ColorRamp { + kColorRedRamp = 0, + kColorGreenRamp = 1, + kColorBlueRamp = 2, + kColorWhiteRamp = 3, + }; + + enum Colors { + kColorBlack = 0, + kColorWhite = 1, + }; + + private: + HWCDisplayExternalTest(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, + qService::QService *qservice, uint32_t panel_bpp, uint32_t pattern_type); + int Init(); + int Deinit(); + void DumpInputBuffer(); + void CalcCRC(uint32_t color_value, std::bitset<16> *crc_data); + int FillBuffer(); + int GetStride(LayerBufferFormat format, uint32_t width, uint32_t *stride); + void PixelCopy(uint32_t red, uint32_t green, uint32_t blue, uint32_t alpha, uint8_t **buffer); + void GenerateColorRamp(uint8_t *buffer); + void GenerateBWVertical(uint8_t *buffer); + void GenerateColorSquare(uint8_t *buffer); + int InitLayer(Layer *layer); + int DeinitLayer(Layer *layer); + int CreateLayerStack(); + int DestroyLayerStack(); + int PostCommit(hwc_display_contents_1_t *content_list); + + static const uint32_t kTestLayerCnt = 1; +}; + +} // namespace sdm + +#endif // __HWC_DISPLAY_EXTERNAL_TEST_H__ + diff --git a/msm8909/sdm/libs/hwc/hwc_display_null.cpp b/msm8909/sdm/libs/hwc/hwc_display_null.cpp new file mode 100644 index 00000000..649f40c3 --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_display_null.cpp @@ -0,0 +1,120 @@ +/* +* 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 <hardware/hwcomposer_defs.h> +#include <utils/constants.h> +#include <utils/debug.h> +#include "hwc_display_null.h" + +#define __CLASS__ "HWCDisplayNull" + +namespace sdm { + +int HWCDisplayNull::Create(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, + HWCDisplay **hwc_display) { + int status; + + DLOGI("Null display is being created"); + HWCDisplayNull *hwc_display_null = new HWCDisplayNull(core_intf, hwc_procs); + + status = hwc_display_null->Init(); + if (status) { + delete hwc_display_null; + return status; + } + + *hwc_display = hwc_display_null; + + return 0; +} + +void HWCDisplayNull::Destroy(HWCDisplay *hwc_display) { + DLOGI("Null display is being destroyed"); + hwc_display->Deinit(); + delete hwc_display; +} + +// We pass the display type as HWC_DISPLAY_PRIMARY to HWCDisplay, but since we override +// and don't chain to HWCDisplay::Init(), that type does not actually get used. +HWCDisplayNull::HWCDisplayNull(CoreInterface *core_intf, hwc_procs_t const **hwc_procs) + : HWCDisplay(core_intf, hwc_procs, kPrimary, HWC_DISPLAY_PRIMARY, false, NULL, + DISPLAY_CLASS_NULL) { +} + +int HWCDisplayNull::Init() { + // Don't call HWCDisplay::Init() for null display, we don't want the chain of + // DisplayPrimary / HWPrimary etc objects to be created. + return 0; +} + +int HWCDisplayNull::Deinit() { + return 0; +} + +int HWCDisplayNull::Prepare(hwc_display_contents_1_t *content_list) { + for (size_t i = 0; i < content_list->numHwLayers; i++) { + if (content_list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET || + content_list->hwLayers[i].compositionType == HWC_BACKGROUND) { + continue; + } + + content_list->hwLayers[i].compositionType = HWC_OVERLAY; + } + + return 0; +} + +int HWCDisplayNull::Commit(hwc_display_contents_1_t *content_list) { + // HWCSession::Commit (from where this is called) already closes all the acquire + // fences once we return from here. So no need to close acquire fences here. + for (size_t i = 0; i < content_list->numHwLayers; i++) { + content_list->hwLayers[i].releaseFenceFd = -1; + } + + return 0; +} + +#define NULL_DISPLAY_FPS 60 + +int HWCDisplayNull::GetDisplayAttributes(uint32_t config, const uint32_t *display_attributes, + int32_t *values) { + for (int i = 0; display_attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) { + // We fake display resolution as 1080P by default, though it can be overriden through a call to + // SetResolution(), and DPI as 160, though what the DPI value does is not clear + switch (display_attributes[i]) { + case HWC_DISPLAY_VSYNC_PERIOD: + values[i] = INT32(1000000000L / NULL_DISPLAY_FPS); + break; + case HWC_DISPLAY_WIDTH: + values[i] = static_cast<int32_t>(x_res_); + break; + case HWC_DISPLAY_HEIGHT: + values[i] = static_cast<int32_t>(y_res_); + break; + } + } + return 0; +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/hwc/hwc_display_null.h b/msm8909/sdm/libs/hwc/hwc_display_null.h new file mode 100644 index 00000000..f1e0e5e8 --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_display_null.h @@ -0,0 +1,106 @@ +/* +* 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_DISPLAY_NULL_H__ +#define __HWC_DISPLAY_NULL_H__ + +#include <qdMetaData.h> +#include <gralloc_priv.h> +#include "hwc_display.h" + +namespace sdm { + +class HWCDisplayNull : public HWCDisplay { + public: + static int Create(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, + HWCDisplay **hwc_display); + static void Destroy(HWCDisplay *hwc_display); + virtual int Init(); + virtual int Deinit(); + virtual int Prepare(hwc_display_contents_1_t *content_list); + virtual int Commit(hwc_display_contents_1_t *content_list); + virtual int EventControl(int event, int enable) { return 0; } + virtual int SetPowerMode(int mode) { return 0; } + + // Framebuffer configurations + virtual int GetDisplayConfigs(uint32_t *configs, size_t *num_configs) { + return HWCDisplay::GetDisplayConfigs(configs, num_configs); + } + + virtual int GetDisplayAttributes(uint32_t config, const uint32_t *display_attributes, + int32_t *values); + virtual int GetActiveConfig() { return 0; } + virtual int SetActiveConfig(int index) { return -1; } + + virtual void SetIdleTimeoutMs(uint32_t timeout_ms) { return; } + virtual void SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type) { return; } + virtual DisplayError SetMaxMixerStages(uint32_t max_mixer_stages) { return kErrorNone; } + virtual DisplayError ControlPartialUpdate(bool enable, uint32_t *pending) { return kErrorNone; } + virtual uint32_t GetLastPowerMode() { return 0; } + virtual int SetFrameBufferResolution(uint32_t x_pixels, uint32_t y_pixels) { return 0; } + + virtual void GetFrameBufferResolution(uint32_t *x_pixels, uint32_t *y_pixels) { + *x_pixels = x_res_; + *y_pixels = y_res_; + } + + virtual void GetPanelResolution(uint32_t *x_pixels, uint32_t *y_pixels) { + *x_pixels = x_res_; + *y_pixels = y_res_; + } + + virtual int SetDisplayStatus(uint32_t display_status) { return 0; } + virtual int OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level) { return 0; } + virtual int Perform(uint32_t operation, ...) { return 0; } + virtual int SetCursorPosition(int x, int y) { return 0; } + virtual void SetSecureDisplay(bool secure_display_active, bool force_flush) { return; } + + // Display Configurations + virtual int SetActiveDisplayConfig(int config) { return 0; } + virtual int GetActiveDisplayConfig(uint32_t *config) { return -1; } + virtual int GetDisplayConfigCount(uint32_t *count) { return -1; } + virtual int GetDisplayAttributesForConfig(int config, + DisplayConfigVariableInfo *display_attributes) { + return -1; + } + virtual bool IsValidContentList(hwc_display_contents_1_t *content_list) { + return true; + } + + void SetResolution(uint32_t x_res, uint32_t y_res) { + x_res_ = x_res; + y_res_ = y_res; + } + + + private: + HWCDisplayNull(CoreInterface *core_intf, hwc_procs_t const **hwc_procs); + uint32_t x_res_ = 1920; + uint32_t y_res_ = 1080; +}; + +} // namespace sdm + +#endif // __HWC_DISPLAY_NULL_H__ + diff --git a/msm8909/sdm/libs/hwc/hwc_display_primary.cpp b/msm8909/sdm/libs/hwc/hwc_display_primary.cpp new file mode 100644 index 00000000..ba351b5b --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_display_primary.cpp @@ -0,0 +1,574 @@ +/* +* Copyright (c) 2014 - 2017, 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 <gr.h> +#include "hwc_display_primary.h" +#include "hwc_debugger.h" + +#define __CLASS__ "HWCDisplayPrimary" + +namespace sdm { + +int HWCDisplayPrimary::Create(CoreInterface *core_intf, BufferAllocator *buffer_allocator, + hwc_procs_t const **hwc_procs, 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, + hwc_procs, qservice); + status = hwc_display_primary->Init(); + if (status) { + delete hwc_display_primary; + return status; + } + + hwc_display_primary->GetMixerResolution(&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, + hwc_procs_t const **hwc_procs, + qService::QService *qservice) + : HWCDisplay(core_intf, hwc_procs, kPrimary, HWC_DISPLAY_PRIMARY, true, qservice, + DISPLAY_CLASS_PRIMARY), buffer_allocator_(buffer_allocator) { +} + +int HWCDisplayPrimary::Init() { + cpu_hint_.Init(static_cast<HWCDebugHandler*>(HWCDebugHandler::Get())); + + 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; + } + + int status = HWCDisplay::Init(); + if (status) { + return status; + } + color_mode_ = new HWCColorMode(display_intf_); + color_mode_->Init(); + + return status; +} + +int HWCDisplayPrimary::Deinit() { + color_mode_->DeInit(); + delete color_mode_; + color_mode_ = NULL; + + return HWCDisplay::Deinit(); +} + + +void HWCDisplayPrimary::ProcessBootAnimCompleted(hwc_display_contents_1_t *list) { + uint32_t numBootUpLayers = 0; + + 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)) && + (list->numHwLayers > 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(); + } +} + +int HWCDisplayPrimary::Prepare(hwc_display_contents_1_t *content_list) { + int status = 0; + DisplayError error = kErrorNone; + + if (!boot_animation_completed_) + ProcessBootAnimCompleted(content_list); + + if (display_paused_) { + MarkLayersForGPUBypass(content_list); + return status; + } + + status = AllocateLayerStack(content_list); + if (status) { + return status; + } + + status = PrePrepareLayerStack(content_list); + if (status) { + return status; + } + + 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_; + } + + uint32_t num_updating_layers = GetUpdatingLayersCount(UINT32(content_list->numHwLayers - 1)); + bool one_updating_layer = (num_updating_layers == 1); + + if (num_updating_layers != 0) { + ToggleCPUHint(one_updating_layer); + } + + uint32_t refresh_rate = GetOptimalRefreshRate(one_updating_layer); + // TODO(user): Need to read current refresh rate to avoid + // redundant calls to set refresh rate during idle fall back. + if ((current_refresh_rate_ != refresh_rate) || (handle_idle_timeout_)) { + 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; + } + + if (content_list->numHwLayers <= 1) { + flush_ = true; + } + + status = PrepareLayerStack(content_list); + if (status) { + return status; + } + + return 0; +} + +int HWCDisplayPrimary::Commit(hwc_display_contents_1_t *content_list) { + int status = 0; + + DisplayConfigFixedInfo display_config; + display_intf_->GetConfig(&display_config); + if (content_list->numHwLayers <= 1 && display_config.is_cmdmode) { + DLOGV("Skipping null commit on cmd mode panel"); + flush_ = false; + return 0; + } + + if (display_paused_) { + if (content_list->outbufAcquireFenceFd >= 0) { + // If we do not handle the frame set retireFenceFd to outbufAcquireFenceFd, + // which will make sure the framework waits on it and closes it. + content_list->retireFenceFd = dup(content_list->outbufAcquireFenceFd); + close(content_list->outbufAcquireFenceFd); + content_list->outbufAcquireFenceFd = -1; + } + + DisplayError error = display_intf_->Flush(); + if (error != kErrorNone) { + DLOGE("Flush failed. Error = %d", error); + } + return status; + } + + status = HWCDisplay::CommitLayerStack(content_list); + if (status) { + return status; + } + + HandleFrameOutput(); + + status = HWCDisplay::PostCommitLayerStack(content_list); + if (status) { + return status; + } + + return 0; +} + +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 (set) { + cpu_hint_.Set(); + } else { + cpu_hint_.Reset(); + } +} + +void HWCDisplayPrimary::SetSecureDisplay(bool secure_display_active, bool force_flush) { + 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_cnt = 1; + + // Issue two null commits for command mode panels when external displays are connected. + // Two null commits are required to handle non secure to secure transitions at 30fps. + // TODO(user): Need two null commits on video mode also to handle transition cases of + // primary at higher fps (ex60) and external at lower fps. + + // Avoid flush for command mode panels when no external displays are connected. + // This is to avoid flicker/blink on primary during transitions. + DisplayConfigFixedInfo display_config; + display_intf_->GetConfig(&display_config); + if (display_config.is_cmdmode) { + if (force_flush) { + DLOGI("Issue two null commits for command mode panels"); + skip_prepare_cnt = 2; + } else { + DLOGI("Avoid flush for command mode panel when no external displays are connected"); + skip_prepare_cnt = 0; + } + } + } +} + +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; + } + + const hwc_procs_t *hwc_procs = *hwc_procs_; + force_refresh_rate_ = refresh_rate; + + hwc_procs->invalidate(hwc_procs); + + 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() { + const hwc_procs_t *hwc_procs = *hwc_procs_; + DisplayError error = kErrorNone; + + if (!hwc_procs) { + return kErrorParameters; + } + + hwc_procs->invalidate(hwc_procs); + 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) { + const BufferConfig& buffer_config = output_buffer_info.buffer_config; + const AllocatedBufferInfo &alloc_buffer_info = output_buffer_info.alloc_buffer_info; + + output_buffer->width = alloc_buffer_info.aligned_width; + output_buffer->height = alloc_buffer_info.aligned_height; + output_buffer->unaligned_width = buffer_config.width; + output_buffer->unaligned_height = buffer_config.height; + output_buffer->format = buffer_config.format; + output_buffer->planes[0].fd = alloc_buffer_info.fd; + output_buffer->planes[0].stride = 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_ = {}; +} + +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; + } +} + +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; + DisablePartialUpdateOneFrame(); +} + +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; + DisablePartialUpdateOneFrame(); + + return 0; +} + +DisplayError HWCDisplayPrimary::SetDetailEnhancerConfig( + const DisplayDetailEnhancerData &de_data) { + DisplayError error = kErrorNotSupported; + if (display_intf_) { + error = display_intf_->SetDetailEnhancerData(de_data); + } + return error; +} + +DisplayError HWCDisplayPrimary::ControlPartialUpdate(bool enable, uint32_t *pending) { + DisplayError error = kErrorNone; + + if (display_intf_) { + error = display_intf_->ControlPartialUpdate(enable, pending); + } + + return error; +} + +DisplayError HWCDisplayPrimary::DisablePartialUpdateOneFrame() { + DisplayError error = kErrorNone; + + if (display_intf_) { + error = display_intf_->DisablePartialUpdateOneFrame(); + } + + return error; +} + +DisplayError HWCDisplayPrimary::SetMixerResolution(uint32_t width, uint32_t height) { + return display_intf_->SetMixerResolution(width, height); +} + +DisplayError HWCDisplayPrimary::GetMixerResolution(uint32_t *width, uint32_t *height) { + return display_intf_->GetMixerResolution(width, height); +} + +} // namespace sdm + diff --git a/msm8909/sdm/libs/hwc/hwc_display_primary.h b/msm8909/sdm/libs/hwc/hwc_display_primary.h new file mode 100644 index 00000000..8a2ff87c --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_display_primary.h @@ -0,0 +1,91 @@ +/* +* 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: + static int Create(CoreInterface *core_intf, BufferAllocator *buffer_allocator, + hwc_procs_t const **hwc_procs, qService::QService *qservice, + HWCDisplay **hwc_display); + static void Destroy(HWCDisplay *hwc_display); + virtual int Init(); + virtual int Deinit(); + virtual int Prepare(hwc_display_contents_1_t *content_list); + virtual int Commit(hwc_display_contents_1_t *content_list); + virtual int Perform(uint32_t operation, ...); + virtual void SetSecureDisplay(bool secure_display_active, bool force_flush); + 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_; } + virtual DisplayError SetDetailEnhancerConfig(const DisplayDetailEnhancerData &de_data); + virtual DisplayError ControlPartialUpdate(bool enable, uint32_t *pending); + + private: + HWCDisplayPrimary(CoreInterface *core_intf, BufferAllocator *buffer_allocator, + hwc_procs_t const **hwc_procs, qService::QService *qservice); + void SetMetaDataRefreshRateFlag(bool enable); + virtual DisplayError SetDisplayMode(uint32_t mode); + virtual DisplayError DisablePartialUpdateOneFrame(); + void ProcessBootAnimCompleted(hwc_display_contents_1_t *content_list); + 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(); + DisplayError SetMixerResolution(uint32_t width, uint32_t height); + DisplayError GetMixerResolution(uint32_t *width, uint32_t *height); + + BufferAllocator *buffer_allocator_ = nullptr; + CPUHint cpu_hint_; + 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__ + diff --git a/msm8909/sdm/libs/hwc/hwc_display_virtual.cpp b/msm8909/sdm/libs/hwc/hwc_display_virtual.cpp new file mode 100644 index 00000000..0279fc2a --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_display_virtual.cpp @@ -0,0 +1,334 @@ +/* +* 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, hwc_procs_t const **hwc_procs, + uint32_t primary_width, uint32_t primary_height, + hwc_display_contents_1_t *content_list, + HWCDisplay **hwc_display) { + int status = 0; + HWCDisplayVirtual *hwc_display_virtual = new HWCDisplayVirtual(core_intf, hwc_procs); + uint32_t virtual_width = 0, virtual_height = 0; + + status = hwc_display_virtual->Init(); + if (status) { + delete hwc_display_virtual; + return status; + } + + status = hwc_display_virtual->SetPowerMode(HWC_POWER_MODE_NORMAL); + if (status) { + Destroy(hwc_display_virtual); + return status; + } + + // TODO(user): Need to update resolution(and not aligned resolution) on writeback. + status = hwc_display_virtual->SetOutputSliceFromMetadata(content_list); + if (status) { + Destroy(hwc_display_virtual); + return status; + } + + hwc_display_virtual->GetMixerResolution(&virtual_width, &virtual_height); + + if (content_list->numHwLayers < 1) { + Destroy(hwc_display_virtual); + return -1; + } + + hwc_layer_1_t &fb_layer = content_list->hwLayers[content_list->numHwLayers-1]; + int fb_width = fb_layer.displayFrame.right - fb_layer.displayFrame.left; + int fb_height = fb_layer.displayFrame.bottom - fb_layer.displayFrame.top; + + status = hwc_display_virtual->SetFrameBufferResolution(UINT32(fb_width), UINT32(fb_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, hwc_procs_t const **hwc_procs) + : HWCDisplay(core_intf, hwc_procs, kVirtual, HWC_DISPLAY_VIRTUAL, false, NULL, + DISPLAY_CLASS_VIRTUAL) { +} + +int HWCDisplayVirtual::Init() { + output_buffer_ = new LayerBuffer(); + if (!output_buffer_) { + return -ENOMEM; + } + + return HWCDisplay::Init(); +} + +int HWCDisplayVirtual::Deinit() { + int status = 0; + + status = HWCDisplay::Deinit(); + if (status) { + return status; + } + + if (output_buffer_) { + delete output_buffer_; + output_buffer_ = NULL; + } + + return status; +} + +int HWCDisplayVirtual::Prepare(hwc_display_contents_1_t *content_list) { + int status = 0; + + status = SetOutputSliceFromMetadata(content_list); + if (status) { + return status; + } + + if (display_paused_) { + MarkLayersForGPUBypass(content_list); + return status; + } + + status = AllocateLayerStack(content_list); + if (status) { + return status; + } + + status = SetOutputBuffer(content_list); + if (status) { + return status; + } + + status = PrePrepareLayerStack(content_list); + if (status) { + return status; + } + + status = PrepareLayerStack(content_list); + if (status) { + return status; + } + + return 0; +} + +int HWCDisplayVirtual::Commit(hwc_display_contents_1_t *content_list) { + int status = 0; + if (display_paused_) { + DisplayError error = display_intf_->Flush(); + if (error != kErrorNone) { + DLOGE("Flush failed. Error = %d", error); + } + return status; + } + + CommitOutputBufferParams(content_list); + + status = HWCDisplay::CommitLayerStack(content_list); + if (status) { + return status; + } + + if (dump_frame_count_ && !flush_ && dump_output_layer_) { + const private_handle_t *output_handle = (const private_handle_t *)(content_list->outbuf); + if (output_handle && output_handle->base) { + BufferInfo buffer_info; + 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(content_list); + if (status) { + return status; + } + + return 0; +} + +int HWCDisplayVirtual::SetOutputSliceFromMetadata(hwc_display_contents_1_t *content_list) { + const private_handle_t *output_handle = + static_cast<const private_handle_t *>(content_list->outbuf); + DisplayError error = kErrorNone; + int status = 0; + + if (output_handle) { + int output_handle_format = output_handle->format; + if (output_handle_format == HAL_PIXEL_FORMAT_RGBA_8888) { + output_handle_format = HAL_PIXEL_FORMAT_RGBX_8888; + } + + LayerBufferFormat format = GetSDMFormat(output_handle_format, output_handle->flags); + if (format == kFormatInvalid) { + return -EINVAL; + } + + int active_width; + int active_height; + + AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(output_handle, active_width, + active_height); + + if ((active_width != INT(output_buffer_->width)) || + (active_height!= INT(output_buffer_->height)) || + (format != output_buffer_->format)) { + // Populate virtual display attributes based on displayFrame of FBT. + // For DRC, use width and height populated in metadata (unaligned values) + // for setting attributes of virtual display. This is needed because if + // we use aligned width and height, scaling will be required for FBT layer. + DisplayConfigVariableInfo variable_info; + hwc_layer_1_t &fbt_layer = content_list->hwLayers[content_list->numHwLayers-1]; + hwc_rect_t &frame = fbt_layer.displayFrame; + int fbt_width = frame.right - frame.left; + int fbt_height = frame.bottom - frame.top; + const MetaData_t *meta_data = reinterpret_cast<MetaData_t *>(output_handle->base_metadata); + if (meta_data && meta_data->operation & UPDATE_BUFFER_GEOMETRY) { + variable_info.x_pixels = UINT32(meta_data->bufferDim.sliceWidth); + variable_info.y_pixels = UINT32(meta_data->bufferDim.sliceHeight); + } else { + variable_info.x_pixels = UINT32(fbt_width); + variable_info.y_pixels = UINT32(fbt_height); + } + // TODO(user): Need to get the framerate of primary display and update it. + variable_info.fps = 60; + + error = display_intf_->SetActiveConfig(&variable_info); + if (error != kErrorNone) { + return -EINVAL; + } + + status = SetOutputBuffer(content_list); + if (status) { + return status; + } + } + } + + return 0; +} + +int HWCDisplayVirtual::SetOutputBuffer(hwc_display_contents_1_t *content_list) { + const private_handle_t *output_handle = + static_cast<const private_handle_t *>(content_list->outbuf); + + if (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 -EINVAL; + } + + int aligned_width, aligned_height; + int unaligned_width, unaligned_height; + + AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(output_handle, aligned_width, + aligned_height); + AdrenoMemInfo::getInstance().getUnalignedWidthAndHeight(output_handle, unaligned_width, + unaligned_height); + + output_buffer_->width = UINT32(aligned_width); + output_buffer_->height = UINT32(aligned_height); + output_buffer_->unaligned_width = UINT32(unaligned_width); + output_buffer_->unaligned_height = UINT32(unaligned_height); + output_buffer_->flags.secure = 0; + output_buffer_->flags.video = 0; + + const MetaData_t *meta_data = reinterpret_cast<MetaData_t *>(output_handle->base_metadata); + if (meta_data && SetCSC(meta_data, &output_buffer_->color_metadata) != kErrorNone) { + return kErrorNotSupported; + } + + // TZ Protected Buffer - L1 + if (output_handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) { + output_buffer_->flags.secure = 1; + } + } + + layer_stack_.output_buffer = output_buffer_; + + return 0; +} + +void HWCDisplayVirtual::CommitOutputBufferParams(hwc_display_contents_1_t *content_list) { + const private_handle_t *output_handle = + static_cast<const private_handle_t *>(content_list->outbuf); + + // Fill output buffer parameters (width, height, format, plane information, fence) + output_buffer_->acquire_fence_fd = content_list->outbufAcquireFenceFd; + + if (output_handle) { + // 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); + } +} + +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 + diff --git a/msm8909/sdm/libs/hwc/hwc_display_virtual.h b/msm8909/sdm/libs/hwc/hwc_display_virtual.h new file mode 100644 index 00000000..77e16d53 --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_display_virtual.h @@ -0,0 +1,64 @@ +/* +* 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, hwc_procs_t const **hwc_procs, + uint32_t primary_width, uint32_t primary_height, + hwc_display_contents_1_t *content_list, HWCDisplay **hwc_display); + static void Destroy(HWCDisplay *hwc_display); + static bool IsValidContentList(hwc_display_contents_1_t *content_list); + virtual int Init(); + virtual int Deinit(); + virtual int Prepare(hwc_display_contents_1_t *content_list); + virtual int Commit(hwc_display_contents_1_t *content_list); + virtual void SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type); + + private: + HWCDisplayVirtual(CoreInterface *core_intf, hwc_procs_t const **hwc_procs); + int SetOutputBuffer(hwc_display_contents_1_t *content_list); + int SetOutputSliceFromMetadata(hwc_display_contents_1_t *content_list); + void CommitOutputBufferParams(hwc_display_contents_1_t *content_list); + + bool dump_output_layer_ = false; + LayerBuffer *output_buffer_ = NULL; +}; + +inline bool HWCDisplayVirtual::IsValidContentList(hwc_display_contents_1_t *content_list) { + return (content_list && content_list->numHwLayers > 0 && content_list->outbuf); +} + +} // namespace sdm + +#endif // __HWC_DISPLAY_VIRTUAL_H__ + diff --git a/msm8909/sdm/libs/hwc/hwc_session.cpp b/msm8909/sdm/libs/hwc/hwc_session.cpp new file mode 100644 index 00000000..31594408 --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_session.cpp @@ -0,0 +1,1734 @@ +/* +* Copyright (c) 2014 - 2018, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <core/dump_interface.h> +#include <core/buffer_allocator.h> +#include <private/color_params.h> +#include <utils/constants.h> +#include <utils/String16.h> +#include <cutils/properties.h> +#include <hardware_legacy/uevent.h> +#include <sys/resource.h> +#include <sys/prctl.h> +#include <binder/Parcel.h> +#include <QService.h> +#include <gr.h> +#include <gralloc_priv.h> +#include <display_config.h> +#include <utils/debug.h> +#include <sync/sync.h> +#include <profiler.h> +#include <bitset> +#include <vector> + +#include "hwc_buffer_allocator.h" +#include "hwc_buffer_sync_handler.h" +#include "hwc_session.h" +#include "hwc_debugger.h" +#include "hwc_display_null.h" +#include "hwc_display_primary.h" +#include "hwc_display_virtual.h" +#include "hwc_display_external_test.h" +#include "qd_utils.h" + +#define __CLASS__ "HWCSession" + +#define HWC_UEVENT_SWITCH_HDMI "change@/devices/virtual/switch/hdmi" +#define HWC_UEVENT_GRAPHICS_FB0 "change@/devices/virtual/graphics/fb0" + +static sdm::HWCSession::HWCModuleMethods g_hwc_module_methods; + +hwc_module_t HAL_MODULE_INFO_SYM = { + .common = { + .tag = HARDWARE_MODULE_TAG, + .version_major = 2, + .version_minor = 0, + .id = HWC_HARDWARE_MODULE_ID, + .name = "QTI Hardware Composer Module", + .author = "CodeAurora Forum", + .methods = &g_hwc_module_methods, + .dso = 0, + .reserved = {0}, + } +}; + +namespace sdm { + +Locker HWCSession::locker_; + +static void Invalidate(const struct hwc_procs *procs) { +} + +static void VSync(const struct hwc_procs* procs, int disp, int64_t timestamp) { +} + +static void Hotplug(const struct hwc_procs* procs, int disp, int connected) { +} + +HWCSession::HWCSession(const hw_module_t *module) { + // By default, drop any events. Calls will be routed to SurfaceFlinger after registerProcs. + hwc_procs_default_.invalidate = Invalidate; + hwc_procs_default_.vsync = VSync; + hwc_procs_default_.hotplug = Hotplug; + + hwc_composer_device_1_t::common.tag = HARDWARE_DEVICE_TAG; + hwc_composer_device_1_t::common.version = HWC_DEVICE_API_VERSION_1_5; + hwc_composer_device_1_t::common.module = const_cast<hw_module_t*>(module); + hwc_composer_device_1_t::common.close = Close; + hwc_composer_device_1_t::prepare = Prepare; + hwc_composer_device_1_t::set = Set; + hwc_composer_device_1_t::eventControl = EventControl; + hwc_composer_device_1_t::setPowerMode = SetPowerMode; + hwc_composer_device_1_t::query = Query; + hwc_composer_device_1_t::registerProcs = RegisterProcs; + hwc_composer_device_1_t::dump = Dump; + hwc_composer_device_1_t::getDisplayConfigs = GetDisplayConfigs; + hwc_composer_device_1_t::getDisplayAttributes = GetDisplayAttributes; + hwc_composer_device_1_t::getActiveConfig = GetActiveConfig; + hwc_composer_device_1_t::setActiveConfig = SetActiveConfig; + hwc_composer_device_1_t::setCursorPositionAsync = SetCursorPositionAsync; +} + +int HWCSession::Init() { + int status = -EINVAL; + const char *qservice_name = "display.qservice"; + + // Start QService and connect to it. + qService::QService::init(); + android::sp<qService::IQService> iqservice = android::interface_cast<qService::IQService>( + android::defaultServiceManager()->getService(android::String16(qservice_name))); + + if (iqservice.get()) { + iqservice->connect(android::sp<qClient::IQClient>(this)); + qservice_ = reinterpret_cast<qService::QService* >(iqservice.get()); + } else { + DLOGE("Failed to acquire %s", qservice_name); + return -EINVAL; + } + + DisplayError error = CoreInterface::CreateCore(HWCDebugHandler::Get(), &buffer_allocator_, + &buffer_sync_handler_, &socket_handler_, + &core_intf_); + if (error != kErrorNone) { + DLOGE("Display core initialization failed. Error = %d", error); + return -EINVAL; + } + + SCOPE_LOCK(uevent_locker_); + + if (pthread_create(&uevent_thread_, NULL, &HWCUeventThread, this) < 0) { + DLOGE("Failed to start = %s, error = %s", uevent_thread_name_, strerror(errno)); + CoreInterface::DestroyCore(); + return -errno; + } + + // Wait for uevent_init() to happen and let the uevent thread wait for uevents, so that hdmi + // connect/disconnect events won't be missed + uevent_locker_.Wait(); + + // Read which display is first, and create it and store it in primary slot + HWDisplayInterfaceInfo hw_disp_info; + error = core_intf_->GetFirstDisplayInterfaceType(&hw_disp_info); + if (error == kErrorNone) { + if (hw_disp_info.type == kHDMI) { + // HDMI is primary display. If already connected, then create it and store in + // primary display slot. If not connected, create a NULL display for now. + HWCDebugHandler::Get()->SetProperty("persist.sys.is_hdmi_primary", "1"); + is_hdmi_primary_ = true; + if (hw_disp_info.is_connected) { + status = CreateExternalDisplay(HWC_DISPLAY_PRIMARY, 0, 0, false); + is_hdmi_yuv_ = IsDisplayYUV(HWC_DISPLAY_PRIMARY); + } else { + // NullDisplay simply closes all its fences, and advertizes a standard + // resolution to SurfaceFlinger + status = HWCDisplayNull::Create(core_intf_, &hwc_procs_, + &hwc_display_[HWC_DISPLAY_PRIMARY]); + } + } else { + // Create and power on primary display + status = HWCDisplayPrimary::Create(core_intf_, &buffer_allocator_, &hwc_procs_, qservice_, + &hwc_display_[HWC_DISPLAY_PRIMARY]); + } + } else { + // Create and power on primary display + status = HWCDisplayPrimary::Create(core_intf_, &buffer_allocator_, &hwc_procs_, qservice_, + &hwc_display_[HWC_DISPLAY_PRIMARY]); + } + + if (status) { + CoreInterface::DestroyCore(); + uevent_thread_exit_ = true; + pthread_join(uevent_thread_, NULL); + return status; + } + + color_mgr_ = HWCColorManager::CreateColorManager(); + if (!color_mgr_) { + DLOGW("Failed to load HWCColorManager."); + } + + connected_displays_[HWC_DISPLAY_PRIMARY] = 1; + struct rlimit fd_limit = {}; + getrlimit(RLIMIT_NOFILE, &fd_limit); + fd_limit.rlim_cur = fd_limit.rlim_cur * 2; + auto err = setrlimit(RLIMIT_NOFILE, &fd_limit); + if (err) { + DLOGW("Unable to increase fd limit - err: %d, %s", errno, strerror(errno)); + } + return 0; +} + +int HWCSession::Deinit() { + HWCDisplayPrimary::Destroy(hwc_display_[HWC_DISPLAY_PRIMARY]); + hwc_display_[HWC_DISPLAY_PRIMARY] = 0; + if (color_mgr_) { + color_mgr_->DestroyColorManager(); + } + uevent_thread_exit_ = true; + pthread_join(uevent_thread_, NULL); + + DisplayError error = CoreInterface::DestroyCore(); + if (error != kErrorNone) { + DLOGE("Display core de-initialization failed. Error = %d", error); + } + + connected_displays_[HWC_DISPLAY_PRIMARY] = 0; + return 0; +} + +int HWCSession::Open(const hw_module_t *module, const char *name, hw_device_t **device) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_); + + if (!module || !name || !device) { + DLOGE("Invalid parameters."); + return -EINVAL; + } + + if (!strcmp(name, HWC_HARDWARE_COMPOSER)) { + HWCSession *hwc_session = new HWCSession(module); + if (!hwc_session) { + return -ENOMEM; + } + + int status = hwc_session->Init(); + if (status != 0) { + delete hwc_session; + return status; + } + + hwc_composer_device_1_t *composer_device = hwc_session; + *device = reinterpret_cast<hw_device_t *>(composer_device); + } + + return 0; +} + +int HWCSession::Close(hw_device_t *device) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_); + + if (!device) { + return -EINVAL; + } + + hwc_composer_device_1_t *composer_device = reinterpret_cast<hwc_composer_device_1_t *>(device); + HWCSession *hwc_session = static_cast<HWCSession *>(composer_device); + + hwc_session->Deinit(); + delete hwc_session; + + return 0; +} + +int HWCSession::Prepare(hwc_composer_device_1 *device, size_t num_displays, + hwc_display_contents_1_t **displays) { + DTRACE_SCOPED(); + + if (!device || !displays || num_displays > HWC_NUM_DISPLAY_TYPES) { + return -EINVAL; + } + + HWCSession *hwc_session = static_cast<HWCSession *>(device); + hwc_procs_t const *hwc_procs = NULL; + bool hotplug_connect = false; + + // Hold mutex only in this scope. + { + SEQUENCE_ENTRY_SCOPE_LOCK(locker_); + + hwc_procs = hwc_session->hwc_procs_; + + if (hwc_session->reset_panel_) { + DLOGW("panel is in bad state, resetting the panel"); + hwc_session->ResetPanel(); + } + + if (hwc_session->need_invalidate_) { + hwc_procs->invalidate(hwc_procs); + hwc_session->need_invalidate_ = false; + } + + hwc_session->HandleSecureDisplaySession(displays); + + if (hwc_session->color_mgr_) { + HWCDisplay *primary_display = hwc_session->hwc_display_[HWC_DISPLAY_PRIMARY]; + if (primary_display && !hwc_session->is_hdmi_primary_) { + int ret = hwc_session->color_mgr_->SolidFillLayersPrepare(displays, primary_display); + if (ret) + return 0; + } + } + + for (ssize_t dpy = static_cast<ssize_t>(num_displays - 1); dpy >= 0; dpy--) { + hwc_display_contents_1_t *content_list = displays[dpy]; + // If external display is connected, ignore virtual display content list. + // If virtual display content list is valid, connect virtual display if not connected. + // If virtual display content list is invalid, disconnect virtual display if connected. + // If external display connection is pending, connect external display when virtual + // display is destroyed. + // If HDMI is primary and the output format is YUV then ignore the virtual display + // content list. + if (dpy == HWC_DISPLAY_VIRTUAL) { + if (hwc_session->hwc_display_[HWC_DISPLAY_EXTERNAL] || + (hwc_session->is_hdmi_primary_ && hwc_session->is_hdmi_yuv_)) { + continue; + } + + bool valid_content = HWCDisplayVirtual::IsValidContentList(content_list); + bool connected = (hwc_session->hwc_display_[HWC_DISPLAY_VIRTUAL] != NULL); + + if (valid_content && !connected) { + hwc_session->ConnectDisplay(HWC_DISPLAY_VIRTUAL, content_list); + } else if (!valid_content && connected) { + hwc_session->DisconnectDisplay(HWC_DISPLAY_VIRTUAL); + + if (hwc_session->external_pending_connect_) { + DLOGI("Process pending external display connection"); + hwc_session->ConnectDisplay(HWC_DISPLAY_EXTERNAL, NULL); + hwc_session->external_pending_connect_ = false; + hotplug_connect = true; + } + } + } + + if (hwc_session->hwc_display_[dpy]) { + if (!content_list) { + DLOGI("Display[%d] connected. content_list is null", dpy); + } else if (!content_list->numHwLayers) { + DLOGE("Display[%d] connected. numHwLayers is zero", dpy); + } else { + hwc_session->hwc_display_[dpy]->Prepare(content_list); + } + } + } + } + + if (hotplug_connect) { + // notify client + hwc_procs->hotplug(hwc_procs, HWC_DISPLAY_EXTERNAL, true); + } + // Return 0, else client will go into bad state + return 0; +} + +int HWCSession::GetVsyncPeriod(int disp) { + SCOPE_LOCK(locker_); + // default value + int32_t vsync_period = 1000000000l / 60; + const uint32_t attribute = HWC_DISPLAY_VSYNC_PERIOD; + + if (hwc_display_[disp]) { + hwc_display_[disp]->GetDisplayAttributes(0, &attribute, &vsync_period); + } + + return vsync_period; +} + +int HWCSession::Set(hwc_composer_device_1 *device, size_t num_displays, + hwc_display_contents_1_t **displays) { + DTRACE_SCOPED(); + + SEQUENCE_EXIT_SCOPE_LOCK(locker_); + + if (!device || !displays || num_displays > HWC_NUM_DISPLAY_TYPES) { + return -EINVAL; + } + + HWCSession *hwc_session = static_cast<HWCSession *>(device); + + if (hwc_session->color_mgr_) { + HWCDisplay *primary_display = hwc_session->hwc_display_[HWC_DISPLAY_PRIMARY]; + if (primary_display) { + int ret = hwc_session->color_mgr_->SolidFillLayersSet(displays, primary_display); + if (ret) + return 0; + hwc_session->color_mgr_->SetColorModeDetailEnhancer(primary_display); + } + } + + for (size_t dpy = 0; dpy < num_displays; dpy++) { + hwc_display_contents_1_t *content_list = displays[dpy]; + + // Drop virtual display composition if virtual display object could not be created + // due to HDMI concurrency. + if (dpy == HWC_DISPLAY_VIRTUAL && !hwc_session->hwc_display_[HWC_DISPLAY_VIRTUAL]) { + CloseAcquireFds(content_list); + if (content_list) { + content_list->retireFenceFd = -1; + } + + continue; + } + + if (hwc_session->hwc_display_[dpy]) { + hwc_session->hwc_display_[dpy]->Commit(content_list); + } + CloseAcquireFds(content_list); + } + + if (hwc_session->new_bw_mode_) { + hwc_display_contents_1_t *content_list = displays[HWC_DISPLAY_PRIMARY]; + hwc_session->new_bw_mode_ = false; + if (hwc_session->bw_mode_release_fd_ >= 0) { + close(hwc_session->bw_mode_release_fd_); + } + hwc_session->bw_mode_release_fd_ = dup(content_list->retireFenceFd); + } + + // This is only indicative of how many times SurfaceFlinger posts + // frames to the display. + CALC_FPS(); + + // Return 0, else client will go into bad state + return 0; +} + +void HWCSession::CloseAcquireFds(hwc_display_contents_1_t *content_list) { + if (content_list) { + for (size_t i = 0; i < content_list->numHwLayers; i++) { + int &acquireFenceFd = content_list->hwLayers[i].acquireFenceFd; + if (acquireFenceFd >= 0) { + close(acquireFenceFd); + acquireFenceFd = -1; + } + } + + int &outbufAcquireFenceFd = content_list->outbufAcquireFenceFd; + if (outbufAcquireFenceFd >= 0) { + close(outbufAcquireFenceFd); + outbufAcquireFenceFd = -1; + } + } +} + +bool HWCSession::IsDisplayYUV(int disp) { + int error = -EINVAL; + bool is_yuv = false; + DisplayConfigVariableInfo attributes = {}; + + if (disp < 0 || disp >= HWC_NUM_DISPLAY_TYPES || !hwc_display_[disp]) { + DLOGE("Invalid input parameters. Display = %d", disp); + return is_yuv; + } + + uint32_t active_config = 0; + error = hwc_display_[disp]->GetActiveDisplayConfig(&active_config); + if (!error) { + error = hwc_display_[disp]->GetDisplayAttributesForConfig(INT(active_config), &attributes); + if (error == 0) { + is_yuv = attributes.is_yuv; + } else { + DLOGW("Error querying display attributes. Display = %d, Config = %d", disp, active_config); + } + } + + return is_yuv; +} + +int HWCSession::EventControl(hwc_composer_device_1 *device, int disp, int event, int enable) { + SCOPE_LOCK(locker_); + + if (!device) { + return -EINVAL; + } + + HWCSession *hwc_session = static_cast<HWCSession *>(device); + int status = -EINVAL; + if (hwc_session->hwc_display_[disp]) { + status = hwc_session->hwc_display_[disp]->EventControl(event, enable); + } + + return status; +} + +int HWCSession::SetPowerMode(hwc_composer_device_1 *device, int disp, int mode) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_); + + if (!device) { + return -EINVAL; + } + + HWCSession *hwc_session = static_cast<HWCSession *>(device); + int status = -EINVAL; + if (hwc_session->hwc_display_[disp]) { + status = hwc_session->hwc_display_[disp]->SetPowerMode(mode); + } + + return status; +} + +int HWCSession::Query(hwc_composer_device_1 *device, int param, int *value) { + SCOPE_LOCK(locker_); + + if (!device || !value) { + return -EINVAL; + } + + int status = 0; + + switch (param) { + case HWC_BACKGROUND_LAYER_SUPPORTED: + value[0] = 1; + break; + + default: + status = -EINVAL; + } + + return status; +} + +void HWCSession::RegisterProcs(hwc_composer_device_1 *device, hwc_procs_t const *procs) { + SCOPE_LOCK(locker_); + + if (!device || !procs) { + return; + } + + HWCSession *hwc_session = static_cast<HWCSession *>(device); + hwc_session->hwc_procs_ = procs; +} + +void HWCSession::Dump(hwc_composer_device_1 *device, char *buffer, int length) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_); + + if (!device || !buffer || !length) { + return; + } + + DumpInterface::GetDump(buffer, UINT32(length)); +} + +int HWCSession::GetDisplayConfigs(hwc_composer_device_1 *device, int disp, uint32_t *configs, + size_t *num_configs) { + SCOPE_LOCK(locker_); + + if (!device || !configs || !num_configs) { + return -EINVAL; + } + + if (disp < HWC_DISPLAY_PRIMARY || disp > HWC_NUM_PHYSICAL_DISPLAY_TYPES) { + return -EINVAL; + } + + HWCSession *hwc_session = static_cast<HWCSession *>(device); + int status = -EINVAL; + if (hwc_session->hwc_display_[disp]) { + status = hwc_session->hwc_display_[disp]->GetDisplayConfigs(configs, num_configs); + } + + return status; +} + +int HWCSession::GetDisplayAttributes(hwc_composer_device_1 *device, int disp, uint32_t config, + const uint32_t *display_attributes, int32_t *values) { + SCOPE_LOCK(locker_); + + if (!device || !display_attributes || !values) { + return -EINVAL; + } + + if (disp < HWC_DISPLAY_PRIMARY || disp > HWC_NUM_PHYSICAL_DISPLAY_TYPES) { + return -EINVAL; + } + + HWCSession *hwc_session = static_cast<HWCSession *>(device); + int status = -EINVAL; + if (hwc_session->hwc_display_[disp]) { + status = hwc_session->hwc_display_[disp]->GetDisplayAttributes(config, display_attributes, + values); + } + + return status; +} + +int HWCSession::GetActiveConfig(hwc_composer_device_1 *device, int disp) { + SCOPE_LOCK(locker_); + + if (!device) { + return -EINVAL; + } + + if (disp < HWC_DISPLAY_PRIMARY || disp > HWC_NUM_PHYSICAL_DISPLAY_TYPES) { + return -EINVAL; + } + + HWCSession *hwc_session = static_cast<HWCSession *>(device); + int active_config = -1; + if (hwc_session->hwc_display_[disp]) { + active_config = hwc_session->hwc_display_[disp]->GetActiveConfig(); + } + + return active_config; +} + +int HWCSession::SetActiveConfig(hwc_composer_device_1 *device, int disp, int index) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_); + + if (!device) { + return -EINVAL; + } + + if (disp < HWC_DISPLAY_PRIMARY || disp > HWC_NUM_PHYSICAL_DISPLAY_TYPES) { + return -EINVAL; + } + + HWCSession *hwc_session = static_cast<HWCSession *>(device); + int status = -EINVAL; + + if (hwc_session->hwc_display_[disp]) { + status = hwc_session->hwc_display_[disp]->SetActiveConfig(index); + } + + return status; +} + +int HWCSession::SetCursorPositionAsync(hwc_composer_device_1 *device, int disp, int x, int y) { + DTRACE_SCOPED(); + + SCOPE_LOCK(locker_); + + if (!device || (disp < HWC_DISPLAY_PRIMARY) || (disp > HWC_DISPLAY_VIRTUAL)) { + return -EINVAL; + } + + int status = -EINVAL; + HWCSession *hwc_session = static_cast<HWCSession *>(device); + if (hwc_session->hwc_display_[disp]) { + status = hwc_session->hwc_display_[disp]->SetCursorPosition(x, y); + } + + return status; +} + +int HWCSession::ConnectDisplay(int disp, hwc_display_contents_1_t *content_list) { + DLOGI("Display = %d", disp); + + int status = 0; + uint32_t primary_width = 0; + uint32_t primary_height = 0; + + hwc_display_[HWC_DISPLAY_PRIMARY]->GetFrameBufferResolution(&primary_width, &primary_height); + + if (disp == HWC_DISPLAY_EXTERNAL) { + status = CreateExternalDisplay(disp, primary_width, primary_height, false); + connected_displays_[HWC_DISPLAY_EXTERNAL] = 1; + } else if (disp == HWC_DISPLAY_VIRTUAL) { + status = HWCDisplayVirtual::Create(core_intf_, &hwc_procs_, primary_width, primary_height, + content_list, &hwc_display_[disp]); + connected_displays_[HWC_DISPLAY_VIRTUAL] = 1; + } else { + DLOGE("Invalid display type"); + return -1; + } + + if (!status) { + hwc_display_[disp]->SetSecureDisplay(secure_display_active_, true); + } + + return status; +} + +int HWCSession::DisconnectDisplay(int disp) { + DLOGI("Display = %d", disp); + + if (disp == HWC_DISPLAY_EXTERNAL) { + HWCDisplayExternal::Destroy(hwc_display_[disp]); + connected_displays_[HWC_DISPLAY_EXTERNAL] = 0; + } else if (disp == HWC_DISPLAY_VIRTUAL) { + HWCDisplayVirtual::Destroy(hwc_display_[disp]); + connected_displays_[HWC_DISPLAY_VIRTUAL] = 0; + } else { + DLOGE("Invalid display type"); + return -1; + } + + hwc_display_[disp] = NULL; + + return 0; +} + +android::status_t HWCSession::notifyCallback(uint32_t command, const android::Parcel *input_parcel, + android::Parcel *output_parcel) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_); + + android::status_t status = 0; + + switch (command) { + case qService::IQService::DYNAMIC_DEBUG: + DynamicDebug(input_parcel); + break; + + case qService::IQService::SCREEN_REFRESH: + hwc_procs_->invalidate(hwc_procs_); + break; + + case qService::IQService::SET_IDLE_TIMEOUT: + if (hwc_display_[HWC_DISPLAY_PRIMARY]) { + uint32_t timeout = UINT32(input_parcel->readInt32()); + hwc_display_[HWC_DISPLAY_PRIMARY]->SetIdleTimeoutMs(timeout); + } + break; + + case qService::IQService::SET_FRAME_DUMP_CONFIG: + SetFrameDumpConfig(input_parcel); + break; + + case qService::IQService::SET_MAX_PIPES_PER_MIXER: + status = SetMaxMixerStages(input_parcel); + break; + + case qService::IQService::SET_DISPLAY_MODE: + status = SetDisplayMode(input_parcel); + break; + + case qService::IQService::SET_SECONDARY_DISPLAY_STATUS: + status = SetSecondaryDisplayStatus(input_parcel, output_parcel); + break; + + case qService::IQService::CONFIGURE_DYN_REFRESH_RATE: + status = ConfigureRefreshRate(input_parcel); + break; + + case qService::IQService::SET_VIEW_FRAME: + break; + + case qService::IQService::TOGGLE_SCREEN_UPDATES: + status = ToggleScreenUpdates(input_parcel, output_parcel); + break; + + case qService::IQService::QDCM_SVC_CMDS: + status = QdcmCMDHandler(input_parcel, output_parcel); + break; + + case qService::IQService::MIN_HDCP_ENCRYPTION_LEVEL_CHANGED: + status = OnMinHdcpEncryptionLevelChange(input_parcel, output_parcel); + break; + + case qService::IQService::CONTROL_PARTIAL_UPDATE: + status = ControlPartialUpdate(input_parcel, output_parcel); + break; + + case qService::IQService::SET_ACTIVE_CONFIG: + status = HandleSetActiveDisplayConfig(input_parcel, output_parcel); + break; + + case qService::IQService::GET_ACTIVE_CONFIG: + status = HandleGetActiveDisplayConfig(input_parcel, output_parcel); + break; + + case qService::IQService::GET_CONFIG_COUNT: + status = HandleGetDisplayConfigCount(input_parcel, output_parcel); + break; + + case qService::IQService::GET_DISPLAY_ATTRIBUTES_FOR_CONFIG: + status = HandleGetDisplayAttributesForConfig(input_parcel, output_parcel); + break; + + case qService::IQService::GET_PANEL_BRIGHTNESS: + status = GetPanelBrightness(input_parcel, output_parcel); + break; + + case qService::IQService::SET_PANEL_BRIGHTNESS: + status = SetPanelBrightness(input_parcel, output_parcel); + break; + + case qService::IQService::GET_DISPLAY_VISIBLE_REGION: + status = GetVisibleDisplayRect(input_parcel, output_parcel); + break; + + case qService::IQService::SET_CAMERA_STATUS: + status = SetDynamicBWForCamera(input_parcel, output_parcel); + break; + + case qService::IQService::GET_BW_TRANSACTION_STATUS: + status = GetBWTransactionStatus(input_parcel, output_parcel); + break; + + case qService::IQService::SET_LAYER_MIXER_RESOLUTION: + status = SetMixerResolution(input_parcel); + break; + + case qService::IQService::GET_HDR_CAPABILITIES: + status = GetHdrCapabilities(input_parcel, output_parcel); + break; + + default: + DLOGW("QService command = %d is not supported", command); + return -EINVAL; + } + + return status; +} + +android::status_t HWCSession::ToggleScreenUpdates(const android::Parcel *input_parcel, + android::Parcel *output_parcel) { + int input = input_parcel->readInt32(); + int error = android::BAD_VALUE; + + if (hwc_display_[HWC_DISPLAY_PRIMARY] && (input <= 1) && (input >= 0)) { + error = hwc_display_[HWC_DISPLAY_PRIMARY]->ToggleScreenUpdates(input == 1); + if (error != 0) { + DLOGE("Failed to toggle screen updates = %d. Error = %d", input, error); + } + } + output_parcel->writeInt32(error); + + return error; +} + +android::status_t HWCSession::SetPanelBrightness(const android::Parcel *input_parcel, + android::Parcel *output_parcel) { + int level = input_parcel->readInt32(); + int error = android::BAD_VALUE; + + if (hwc_display_[HWC_DISPLAY_PRIMARY]) { + error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(level); + if (error != 0) { + DLOGE("Failed to set the panel brightness = %d. Error = %d", level, error); + } + } + output_parcel->writeInt32(error); + + return error; +} + +android::status_t HWCSession::GetPanelBrightness(const android::Parcel *input_parcel, + android::Parcel *output_parcel) { + int error = android::BAD_VALUE; + int ret = error; + + if (hwc_display_[HWC_DISPLAY_PRIMARY]) { + error = hwc_display_[HWC_DISPLAY_PRIMARY]->GetPanelBrightness(&ret); + if (error != 0) { + ret = error; + DLOGE("Failed to get the panel brightness. Error = %d", error); + } + } + output_parcel->writeInt32(ret); + + return error; +} + +android::status_t HWCSession::ControlPartialUpdate(const android::Parcel *input_parcel, + android::Parcel *out) { + DisplayError error = kErrorNone; + int ret = 0; + uint32_t disp_id = UINT32(input_parcel->readInt32()); + uint32_t enable = UINT32(input_parcel->readInt32()); + + if (disp_id != HWC_DISPLAY_PRIMARY) { + DLOGW("CONTROL_PARTIAL_UPDATE is not applicable for display = %d", disp_id); + ret = -EINVAL; + out->writeInt32(ret); + return ret; + } + + if (!hwc_display_[HWC_DISPLAY_PRIMARY]) { + DLOGE("primary display object is not instantiated"); + ret = -EINVAL; + out->writeInt32(ret); + return ret; + } + + uint32_t pending = 0; + error = hwc_display_[HWC_DISPLAY_PRIMARY]->ControlPartialUpdate(enable, &pending); + + if (error == kErrorNone) { + if (!pending) { + out->writeInt32(ret); + return ret; + } + } else if (error == kErrorNotSupported) { + out->writeInt32(ret); + return ret; + } else { + ret = -EINVAL; + out->writeInt32(ret); + return ret; + } + + // Todo(user): Unlock it before sending events to client. It may cause deadlocks in future. + hwc_procs_->invalidate(hwc_procs_); + + // Wait until partial update control is complete + ret = locker_.WaitFinite(kPartialUpdateControlTimeoutMs); + + out->writeInt32(ret); + + return ret; +} + +android::status_t HWCSession::HandleSetActiveDisplayConfig(const android::Parcel *input_parcel, + android::Parcel *output_parcel) { + int config = input_parcel->readInt32(); + int dpy = input_parcel->readInt32(); + int error = android::BAD_VALUE; + + if (dpy > HWC_DISPLAY_VIRTUAL) { + return android::BAD_VALUE; + } + + if (hwc_display_[dpy]) { + error = hwc_display_[dpy]->SetActiveDisplayConfig(config); + if (error == 0) { + hwc_procs_->invalidate(hwc_procs_); + } + } + + return error; +} + +android::status_t HWCSession::HandleGetActiveDisplayConfig(const android::Parcel *input_parcel, + android::Parcel *output_parcel) { + int dpy = input_parcel->readInt32(); + int error = android::BAD_VALUE; + + if (dpy > HWC_DISPLAY_VIRTUAL) { + return android::BAD_VALUE; + } + + if (hwc_display_[dpy]) { + uint32_t config = 0; + error = hwc_display_[dpy]->GetActiveDisplayConfig(&config); + if (error == 0) { + output_parcel->writeInt32(INT(config)); + } + } + + return error; +} + +android::status_t HWCSession::HandleGetDisplayConfigCount(const android::Parcel *input_parcel, + android::Parcel *output_parcel) { + int dpy = input_parcel->readInt32(); + int error = android::BAD_VALUE; + + if (dpy > HWC_DISPLAY_VIRTUAL) { + return android::BAD_VALUE; + } + + uint32_t count = 0; + if (hwc_display_[dpy]) { + error = hwc_display_[dpy]->GetDisplayConfigCount(&count); + if (error == 0) { + output_parcel->writeInt32(INT(count)); + } + } + + return error; +} + +android::status_t HWCSession::SetDisplayPort(DisplayPort sdm_disp_port, int *hwc_disp_port) { + if (!hwc_disp_port) { + return -EINVAL; + } + + switch (sdm_disp_port) { + case kPortDSI: + *hwc_disp_port = qdutils::DISPLAY_PORT_DSI; + break; + case kPortDTV: + *hwc_disp_port = qdutils::DISPLAY_PORT_DTV; + break; + case kPortLVDS: + *hwc_disp_port = qdutils::DISPLAY_PORT_LVDS; + break; + case kPortEDP: + *hwc_disp_port = qdutils::DISPLAY_PORT_EDP; + break; + case kPortWriteBack: + *hwc_disp_port = qdutils::DISPLAY_PORT_WRITEBACK; + break; + case kPortDP: + *hwc_disp_port = qdutils::DISPLAY_PORT_DP; + break; + case kPortDefault: + *hwc_disp_port = qdutils::DISPLAY_PORT_DEFAULT; + break; + default: + DLOGE("Invalid sdm display port %d", sdm_disp_port); + return -EINVAL; + } + + return 0; +} + +android::status_t HWCSession::HandleGetDisplayAttributesForConfig(const android::Parcel + *input_parcel, + android::Parcel *output_parcel) { + int config = input_parcel->readInt32(); + int dpy = input_parcel->readInt32(); + int error = android::BAD_VALUE; + DisplayConfigVariableInfo display_attributes; + DisplayPort sdm_disp_port = kPortDefault; + int hwc_disp_port = qdutils::DISPLAY_PORT_DEFAULT; + + if (dpy < HWC_DISPLAY_PRIMARY || dpy >= HWC_NUM_DISPLAY_TYPES || config < 0) { + return android::BAD_VALUE; + } + + if (hwc_display_[dpy]) { + error = hwc_display_[dpy]->GetDisplayAttributesForConfig(config, &display_attributes); + if (error == 0) { + hwc_display_[dpy]->GetDisplayPort(&sdm_disp_port); + + SetDisplayPort(sdm_disp_port, &hwc_disp_port); + + output_parcel->writeInt32(INT(display_attributes.vsync_period_ns)); + output_parcel->writeInt32(INT(display_attributes.x_pixels)); + output_parcel->writeInt32(INT(display_attributes.y_pixels)); + output_parcel->writeFloat(display_attributes.x_dpi); + output_parcel->writeFloat(display_attributes.y_dpi); + output_parcel->writeInt32(hwc_disp_port); + output_parcel->writeInt32(display_attributes.is_yuv); + } + } + + return error; +} + +android::status_t HWCSession::SetSecondaryDisplayStatus(const android::Parcel *input_parcel, + android::Parcel *output_parcel) { + int ret = -EINVAL; + + uint32_t display_id = UINT32(input_parcel->readInt32()); + uint32_t display_status = UINT32(input_parcel->readInt32()); + + DLOGI("Display = %d, Status = %d", display_id, display_status); + + if (display_id >= HWC_NUM_DISPLAY_TYPES) { + DLOGE("Invalid display_id"); + } else if (display_id == HWC_DISPLAY_PRIMARY) { + DLOGE("Not supported for this display"); + } else if (!hwc_display_[display_id]) { + DLOGW("Display is not connected"); + } else { + ret = hwc_display_[display_id]->SetDisplayStatus(display_status); + } + + output_parcel->writeInt32(ret); + + return ret; +} + +android::status_t HWCSession::ConfigureRefreshRate(const android::Parcel *input_parcel) { + uint32_t operation = UINT32(input_parcel->readInt32()); + switch (operation) { + case qdutils::DISABLE_METADATA_DYN_REFRESH_RATE: + return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform( + HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, false); + case qdutils::ENABLE_METADATA_DYN_REFRESH_RATE: + return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform( + HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, true); + case qdutils::SET_BINDER_DYN_REFRESH_RATE: + { + uint32_t refresh_rate = UINT32(input_parcel->readInt32()); + return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform( + HWCDisplayPrimary::SET_BINDER_DYN_REFRESH_RATE, + refresh_rate); + } + default: + DLOGW("Invalid operation %d", operation); + return -EINVAL; + } + + return 0; +} + +android::status_t HWCSession::SetDisplayMode(const android::Parcel *input_parcel) { + uint32_t mode = UINT32(input_parcel->readInt32()); + return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(HWCDisplayPrimary::SET_DISPLAY_MODE, mode); +} + +android::status_t HWCSession::SetMaxMixerStages(const android::Parcel *input_parcel) { + DisplayError error = kErrorNone; + std::bitset<32> bit_mask_display_type = UINT32(input_parcel->readInt32()); + uint32_t max_mixer_stages = UINT32(input_parcel->readInt32()); + + if (bit_mask_display_type[HWC_DISPLAY_PRIMARY]) { + if (hwc_display_[HWC_DISPLAY_PRIMARY]) { + error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetMaxMixerStages(max_mixer_stages); + if (error != kErrorNone) { + return -EINVAL; + } + } + } + + if (bit_mask_display_type[HWC_DISPLAY_EXTERNAL]) { + if (hwc_display_[HWC_DISPLAY_EXTERNAL]) { + error = hwc_display_[HWC_DISPLAY_EXTERNAL]->SetMaxMixerStages(max_mixer_stages); + if (error != kErrorNone) { + return -EINVAL; + } + } + } + + if (bit_mask_display_type[HWC_DISPLAY_VIRTUAL]) { + if (hwc_display_[HWC_DISPLAY_VIRTUAL]) { + error = hwc_display_[HWC_DISPLAY_VIRTUAL]->SetMaxMixerStages(max_mixer_stages); + if (error != kErrorNone) { + return -EINVAL; + } + } + } + + return 0; +} + +android::status_t HWCSession::SetDynamicBWForCamera(const android::Parcel *input_parcel, + android::Parcel *output_parcel) { + DisplayError error = kErrorNone; + uint32_t camera_status = UINT32(input_parcel->readInt32()); + HWBwModes mode = camera_status > 0 ? kBwCamera : kBwDefault; + + // trigger invalidate to apply new bw caps. + hwc_procs_->invalidate(hwc_procs_); + + error = core_intf_->SetMaxBandwidthMode(mode); + if (error != kErrorNone) { + return -EINVAL; + } + + new_bw_mode_ = true; + need_invalidate_ = true; + + return 0; +} + +android::status_t HWCSession::GetBWTransactionStatus(const android::Parcel *input_parcel, + android::Parcel *output_parcel) { + bool state = true; + + if (hwc_display_[HWC_DISPLAY_PRIMARY]) { + if (sync_wait(bw_mode_release_fd_, 0) < 0) { + DLOGI("bw_transaction_release_fd is not yet signalled: err= %s", strerror(errno)); + state = false; + } + output_parcel->writeInt32(state); + } + + return 0; +} + +void HWCSession::SetFrameDumpConfig(const android::Parcel *input_parcel) { + uint32_t frame_dump_count = UINT32(input_parcel->readInt32()); + std::bitset<32> bit_mask_display_type = UINT32(input_parcel->readInt32()); + uint32_t bit_mask_layer_type = UINT32(input_parcel->readInt32()); + + if (bit_mask_display_type[HWC_DISPLAY_PRIMARY]) { + if (hwc_display_[HWC_DISPLAY_PRIMARY]) { + hwc_display_[HWC_DISPLAY_PRIMARY]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type); + } + } + + if (bit_mask_display_type[HWC_DISPLAY_EXTERNAL]) { + if (hwc_display_[HWC_DISPLAY_EXTERNAL]) { + hwc_display_[HWC_DISPLAY_EXTERNAL]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type); + } + } + + if (bit_mask_display_type[HWC_DISPLAY_VIRTUAL]) { + if (hwc_display_[HWC_DISPLAY_VIRTUAL]) { + hwc_display_[HWC_DISPLAY_VIRTUAL]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type); + } + } +} + +android::status_t HWCSession::SetMixerResolution(const android::Parcel *input_parcel) { + DisplayError error = kErrorNone; + uint32_t dpy = UINT32(input_parcel->readInt32()); + + if (dpy != HWC_DISPLAY_PRIMARY) { + DLOGI("Resoulution change not supported for this display %d", dpy); + return -EINVAL; + } + + if (!hwc_display_[HWC_DISPLAY_PRIMARY]) { + DLOGI("Primary display is not initialized"); + return -EINVAL; + } + + uint32_t width = UINT32(input_parcel->readInt32()); + uint32_t height = UINT32(input_parcel->readInt32()); + + error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetMixerResolution(width, height); + if (error != kErrorNone) { + return -EINVAL; + } + + return 0; +} + +android::status_t HWCSession::GetHdrCapabilities(const android::Parcel *input_parcel, + android::Parcel *output_parcel) { + uint32_t display_id = UINT32(input_parcel->readInt32()); + if (display_id >= HWC_NUM_DISPLAY_TYPES) { + DLOGE("Invalid display id = %d", display_id); + return -EINVAL; + } + + if (hwc_display_[display_id] == NULL) { + DLOGW("Display = %d not initialized", display_id); + return -EINVAL; + } + + DisplayConfigFixedInfo fixed_info = {}; + int ret = hwc_display_[display_id]->GetDisplayFixedConfig(&fixed_info); + if (ret) { + DLOGE("Failed"); + return ret; + } + + if (!fixed_info.hdr_supported) { + DLOGI("HDR is not supported"); + return 0; + } + + std::vector<int32_t> supported_hdr_types; + // Only HDR10 supported now, in future add other supported HDR formats(HLG, DolbyVision) + supported_hdr_types.push_back(HAL_HDR_HDR10); + + static const float kLuminanceFactor = 10000.0; + // luminance is expressed in the unit of 0.0001 cd/m2, convert it to 1cd/m2. + float max_luminance = FLOAT(fixed_info.max_luminance)/kLuminanceFactor; + float max_average_luminance = FLOAT(fixed_info.average_luminance)/kLuminanceFactor; + float min_luminance = FLOAT(fixed_info.min_luminance)/kLuminanceFactor; + + if (output_parcel != nullptr) { + output_parcel->writeInt32Vector(supported_hdr_types); + output_parcel->writeFloat(max_luminance); + output_parcel->writeFloat(max_average_luminance); + output_parcel->writeFloat(min_luminance); + } + + return 0; +} + +void HWCSession::DynamicDebug(const android::Parcel *input_parcel) { + int type = input_parcel->readInt32(); + bool enable = (input_parcel->readInt32() > 0); + DLOGI("type = %d enable = %d", type, enable); + int verbose_level = input_parcel->readInt32(); + + switch (type) { + case qService::IQService::DEBUG_ALL: + HWCDebugHandler::DebugAll(enable, verbose_level); + break; + + case qService::IQService::DEBUG_MDPCOMP: + HWCDebugHandler::DebugStrategy(enable, verbose_level); + HWCDebugHandler::DebugCompManager(enable, verbose_level); + break; + + case qService::IQService::DEBUG_PIPE_LIFECYCLE: + HWCDebugHandler::DebugResources(enable, verbose_level); + break; + + case qService::IQService::DEBUG_DRIVER_CONFIG: + HWCDebugHandler::DebugDriverConfig(enable, verbose_level); + break; + + case qService::IQService::DEBUG_ROTATOR: + HWCDebugHandler::DebugResources(enable, verbose_level); + HWCDebugHandler::DebugDriverConfig(enable, verbose_level); + HWCDebugHandler::DebugRotator(enable, verbose_level); + break; + + case qService::IQService::DEBUG_QDCM: + HWCDebugHandler::DebugQdcm(enable, verbose_level); + break; + + default: + DLOGW("type = %d is not supported", type); + } +} + +android::status_t HWCSession::QdcmCMDHandler(const android::Parcel *input_parcel, + android::Parcel *output_parcel) { + int ret = 0; + int32_t *brightness_value = NULL; + uint32_t display_id(0); + PPPendingParams pending_action; + PPDisplayAPIPayload resp_payload, req_payload; + + if (!color_mgr_) { + return -1; + } + + pending_action.action = kNoAction; + pending_action.params = NULL; + + // Read display_id, payload_size and payload from in_parcel. + ret = HWCColorManager::CreatePayloadFromParcel(*input_parcel, &display_id, &req_payload); + if (!ret) { + if (HWC_DISPLAY_PRIMARY == display_id && hwc_display_[HWC_DISPLAY_PRIMARY]) + ret = hwc_display_[HWC_DISPLAY_PRIMARY]->ColorSVCRequestRoute(req_payload, + &resp_payload, &pending_action); + + if (HWC_DISPLAY_EXTERNAL == display_id && hwc_display_[HWC_DISPLAY_EXTERNAL]) + ret = hwc_display_[HWC_DISPLAY_EXTERNAL]->ColorSVCRequestRoute(req_payload, &resp_payload, + &pending_action); + } + + if (ret) { + output_parcel->writeInt32(ret); // first field in out parcel indicates return code. + req_payload.DestroyPayload(); + resp_payload.DestroyPayload(); + return ret; + } + + switch (pending_action.action) { + case kInvalidating: + hwc_procs_->invalidate(hwc_procs_); + break; + case kEnterQDCMMode: + ret = color_mgr_->EnableQDCMMode(true, hwc_display_[HWC_DISPLAY_PRIMARY]); + break; + case kExitQDCMMode: + ret = color_mgr_->EnableQDCMMode(false, hwc_display_[HWC_DISPLAY_PRIMARY]); + break; + case kApplySolidFill: + ret = color_mgr_->SetSolidFill(pending_action.params, + true, hwc_display_[HWC_DISPLAY_PRIMARY]); + hwc_procs_->invalidate(hwc_procs_); + break; + case kDisableSolidFill: + ret = color_mgr_->SetSolidFill(pending_action.params, + false, hwc_display_[HWC_DISPLAY_PRIMARY]); + hwc_procs_->invalidate(hwc_procs_); + break; + case kSetPanelBrightness: + brightness_value = reinterpret_cast<int32_t*>(resp_payload.payload); + if (brightness_value == NULL) { + DLOGE("Brightness value is Null"); + return -EINVAL; + } + if (HWC_DISPLAY_PRIMARY == display_id) + ret = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(*brightness_value); + break; + case kEnableFrameCapture: + ret = color_mgr_->SetFrameCapture(pending_action.params, + true, hwc_display_[HWC_DISPLAY_PRIMARY]); + hwc_procs_->invalidate(hwc_procs_); + break; + case kDisableFrameCapture: + ret = color_mgr_->SetFrameCapture(pending_action.params, + false, hwc_display_[HWC_DISPLAY_PRIMARY]); + break; + case kConfigureDetailedEnhancer: + ret = color_mgr_->SetDetailedEnhancer(pending_action.params, + hwc_display_[HWC_DISPLAY_PRIMARY]); + hwc_procs_->invalidate(hwc_procs_); + break; + case kInvalidatingAndkSetPanelBrightness: + brightness_value = reinterpret_cast<int32_t*>(resp_payload.payload); + if (brightness_value == NULL) { + DLOGE("Brightness value is Null"); + return -EINVAL; + } + if (HWC_DISPLAY_PRIMARY == display_id) + ret = hwc_display_[HWC_DISPLAY_PRIMARY]->CachePanelBrightness(*brightness_value); + hwc_procs_->invalidate(hwc_procs_); + break; + case kNoAction: + break; + default: + DLOGW("Invalid pending action = %d!", pending_action.action); + break; + } + + // for display API getter case, marshall returned params into out_parcel. + output_parcel->writeInt32(ret); + HWCColorManager::MarshallStructIntoParcel(resp_payload, output_parcel); + req_payload.DestroyPayload(); + resp_payload.DestroyPayload(); + + return (ret? -EINVAL : 0); +} + +android::status_t HWCSession::OnMinHdcpEncryptionLevelChange(const android::Parcel *input_parcel, + android::Parcel *output_parcel) { + int ret = -EINVAL; + uint32_t display_id = UINT32(input_parcel->readInt32()); + uint32_t min_enc_level = UINT32(input_parcel->readInt32()); + + DLOGI("Display %d", display_id); + + if (display_id >= HWC_NUM_DISPLAY_TYPES) { + DLOGE("Invalid display_id"); + } else if (display_id != HWC_DISPLAY_EXTERNAL) { + DLOGE("Not supported for display"); + } else if (!hwc_display_[display_id]) { + DLOGW("Display is not connected"); + } else { + ret = hwc_display_[display_id]->OnMinHdcpEncryptionLevelChange(min_enc_level); + } + + output_parcel->writeInt32(ret); + + return ret; +} + +void* HWCSession::HWCUeventThread(void *context) { + if (context) { + return reinterpret_cast<HWCSession *>(context)->HWCUeventThreadHandler(); + } + + return NULL; +} + +void* HWCSession::HWCUeventThreadHandler() { + static char uevent_data[PAGE_SIZE]; + int length = 0; + + uevent_locker_.Lock(); + prctl(PR_SET_NAME, uevent_thread_name_, 0, 0, 0); + setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY); + if (!uevent_init()) { + DLOGE("Failed to init uevent"); + pthread_exit(0); + uevent_locker_.Signal(); + uevent_locker_.Unlock(); + return NULL; + } + + uevent_locker_.Signal(); + uevent_locker_.Unlock(); + + while (!uevent_thread_exit_) { + // keep last 2 zeroes to ensure double 0 termination + length = uevent_next_event(uevent_data, INT32(sizeof(uevent_data)) - 2); + + if (strcasestr(HWC_UEVENT_SWITCH_HDMI, uevent_data)) { + DLOGI("Uevent HDMI = %s", uevent_data); + int connected = GetEventValue(uevent_data, length, "SWITCH_STATE="); + if (connected >= 0) { + DLOGI("HDMI = %s", connected ? "connected" : "disconnected"); + if (HotPlugHandler(connected) == -1) { + DLOGE("Failed handling Hotplug = %s", connected ? "connected" : "disconnected"); + } + } + } else if (strcasestr(HWC_UEVENT_GRAPHICS_FB0, uevent_data)) { + DLOGI("Uevent FB0 = %s", uevent_data); + int panel_reset = GetEventValue(uevent_data, length, "PANEL_ALIVE="); + if (panel_reset == 0) { + if (hwc_procs_) { + reset_panel_ = true; + hwc_procs_->invalidate(hwc_procs_); + } else { + DLOGW("Ignore resetpanel - hwc_proc not registered"); + } + } + } + } + pthread_exit(0); + + return NULL; +} + +int HWCSession::GetEventValue(const char *uevent_data, int length, const char *event_info) { + const char *iterator_str = uevent_data; + while (((iterator_str - uevent_data) <= length) && (*iterator_str)) { + const char *pstr = strstr(iterator_str, event_info); + if (pstr != NULL) { + return (atoi(iterator_str + strlen(event_info))); + } + iterator_str += strlen(iterator_str) + 1; + } + + return -1; +} + +void HWCSession::ResetPanel() { + int status = -EINVAL; + + DLOGI("Powering off primary"); + status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPowerMode(HWC_POWER_MODE_OFF); + if (status) { + DLOGE("power-off on primary failed with error = %d", status); + } + + DLOGI("Restoring power mode on primary"); + int32_t mode = INT(hwc_display_[HWC_DISPLAY_PRIMARY]->GetLastPowerMode()); + status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPowerMode(mode); + if (status) { + DLOGE("Setting power mode = %d on primary failed with error = %d", mode, status); + } + + status = hwc_display_[HWC_DISPLAY_PRIMARY]->EventControl(HWC_EVENT_VSYNC, 1); + if (status) { + DLOGE("enabling vsync failed for primary with error = %d", status); + } + + reset_panel_ = false; +} + +int HWCSession::HotPlugHandler(bool connected) { + int status = 0; + bool notify_hotplug = false; + bool refresh_screen = false; + + // To prevent sending events to client while a lock is held, acquire scope locks only within + // below scope so that those get automatically unlocked after the scope ends. + { + SEQUENCE_WAIT_SCOPE_LOCK(locker_); + + if (!hwc_display_[HWC_DISPLAY_PRIMARY]) { + DLOGE("Primay display is not connected."); + return -1; + } + + + HWCDisplay *primary_display = hwc_display_[HWC_DISPLAY_PRIMARY]; + HWCDisplay *external_display = NULL; + HWCDisplay *null_display = NULL; + + if (primary_display->GetDisplayClass() == DISPLAY_CLASS_EXTERNAL) { + external_display = static_cast<HWCDisplayExternal *>(hwc_display_[HWC_DISPLAY_PRIMARY]); + } else if (primary_display->GetDisplayClass() == DISPLAY_CLASS_NULL) { + null_display = static_cast<HWCDisplayNull *>(hwc_display_[HWC_DISPLAY_PRIMARY]); + } + + // If primary display connected is a NULL display, then replace it with the external display + if (connected) { + // If we are in HDMI as primary and the primary display just got plugged in + if (is_hdmi_primary_ && null_display) { + uint32_t primary_width, primary_height; + int status = 0; + null_display->GetFrameBufferResolution(&primary_width, &primary_height); + delete null_display; + hwc_display_[HWC_DISPLAY_PRIMARY] = NULL; + + // Create external display with a forced framebuffer resolution to that of what the NULL + // display had. This is necessary because SurfaceFlinger does not dynamically update + // framebuffer resolution once it reads it at bootup. So we always have to have the NULL + // display/external display both at the bootup resolution. + status = CreateExternalDisplay(HWC_DISPLAY_PRIMARY, primary_width, primary_height, true); + if (status) { + DLOGE("Could not create external display"); + return -1; + } + + status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPowerMode(HWC_POWER_MODE_NORMAL); + if (status) { + DLOGE("power-on on primary failed with error = %d", status); + } + + is_hdmi_yuv_ = IsDisplayYUV(HWC_DISPLAY_PRIMARY); + + // Next, go ahead and enable vsync on external display. This is expliclity required + // because in HDMI as primary case, SurfaceFlinger may not be aware of underlying + // changing display. and thus may not explicitly enable vsync + + status = hwc_display_[HWC_DISPLAY_PRIMARY]->EventControl(HWC_EVENT_VSYNC, true); + if (status) { + DLOGE("Error enabling vsync for HDMI as primary case"); + } + // Don't do hotplug notification for HDMI as primary case for now + notify_hotplug = false; + refresh_screen = true; + } else { + if (hwc_display_[HWC_DISPLAY_EXTERNAL]) { + DLOGE("HDMI is already connected"); + return -1; + } + + // Connect external display if virtual display is not connected. + // Else, defer external display connection and process it when virtual display + // tears down; Do not notify SurfaceFlinger since connection is deferred now. + if (!hwc_display_[HWC_DISPLAY_VIRTUAL]) { + status = ConnectDisplay(HWC_DISPLAY_EXTERNAL, NULL); + if (status) { + return status; + } + notify_hotplug = true; + } else { + DLOGI("Virtual display is connected, pending connection"); + external_pending_connect_ = true; + } + } + } else { + // Do not return error if external display is not in connected status. + // Due to virtual display concurrency, external display connection might be still pending + // but hdmi got disconnected before pending connection could be processed. + + if (is_hdmi_primary_ && external_display) { + uint32_t x_res, y_res; + external_display->GetFrameBufferResolution(&x_res, &y_res); + // Need to manually disable VSYNC as SF is not aware of connect/disconnect cases + // for HDMI as primary + external_display->EventControl(HWC_EVENT_VSYNC, false); + HWCDisplayExternal::Destroy(external_display); + + HWCDisplayNull *null_display; + + int status = HWCDisplayNull::Create(core_intf_, &hwc_procs_, + reinterpret_cast<HWCDisplay **>(&null_display)); + + if (status) { + DLOGE("Could not create Null display when primary got disconnected"); + return -1; + } + + null_display->SetResolution(x_res, y_res); + hwc_display_[HWC_DISPLAY_PRIMARY] = null_display; + + // Don't do hotplug notification for HDMI as primary case for now + notify_hotplug = false; + } else { + if (hwc_display_[HWC_DISPLAY_EXTERNAL]) { + status = DisconnectDisplay(HWC_DISPLAY_EXTERNAL); + notify_hotplug = true; + } + external_pending_connect_ = false; + } + } + } + + if (connected && (notify_hotplug || refresh_screen)) { + // trigger screen refresh to ensure sufficient resources are available to process new + // new display connection. + hwc_procs_->invalidate(hwc_procs_); + uint32_t vsync_period = UINT32(GetVsyncPeriod(HWC_DISPLAY_PRIMARY)); + usleep(vsync_period * 2 / 1000); + } + // notify client + if (notify_hotplug) { + hwc_procs_->hotplug(hwc_procs_, HWC_DISPLAY_EXTERNAL, connected); + } + + qservice_->onHdmiHotplug(INT(connected)); + + return 0; +} + +void HWCSession::HandleSecureDisplaySession(hwc_display_contents_1_t **displays) { + secure_display_active_ = false; + if (!*displays) { + DLOGW("Invalid display contents"); + return; + } + + hwc_display_contents_1_t *content_list = displays[HWC_DISPLAY_PRIMARY]; + if (!content_list) { + DLOGW("Invalid primary content list"); + return; + } + size_t num_hw_layers = content_list->numHwLayers; + + for (size_t i = 0; i < num_hw_layers - 1; i++) { + hwc_layer_1_t &hwc_layer = content_list->hwLayers[i]; + const private_handle_t *pvt_handle = static_cast<const private_handle_t *>(hwc_layer.handle); + if (pvt_handle && pvt_handle->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY) { + secure_display_active_ = true; + } + } + + // Force flush on primary during transitions(secure<->non secure) + // when external displays are connected. + bool force_flush = false; + if ((connected_displays_[HWC_DISPLAY_PRIMARY] == 1) && + ((connected_displays_[HWC_DISPLAY_EXTERNAL] == 1) || + (connected_displays_[HWC_DISPLAY_VIRTUAL] == 1))) { + force_flush = true; + } + + for (ssize_t dpy = static_cast<ssize_t>(HWC_NUM_DISPLAY_TYPES - 1); dpy >= 0; dpy--) { + if (hwc_display_[dpy]) { + hwc_display_[dpy]->SetSecureDisplay(secure_display_active_, force_flush); + } + } +} + +android::status_t HWCSession::GetVisibleDisplayRect(const android::Parcel *input_parcel, + android::Parcel *output_parcel) { + int dpy = input_parcel->readInt32(); + + if (dpy < HWC_DISPLAY_PRIMARY || dpy >= HWC_NUM_DISPLAY_TYPES) { + return android::BAD_VALUE;; + } + + if (!hwc_display_[dpy]) { + return android::NO_INIT; + } + + hwc_rect_t visible_rect = {0, 0, 0, 0}; + int error = hwc_display_[dpy]->GetVisibleDisplayRect(&visible_rect); + if (error < 0) { + return error; + } + + output_parcel->writeInt32(visible_rect.left); + output_parcel->writeInt32(visible_rect.top); + output_parcel->writeInt32(visible_rect.right); + output_parcel->writeInt32(visible_rect.bottom); + + return android::NO_ERROR; +} + +int HWCSession::CreateExternalDisplay(int disp, uint32_t primary_width, uint32_t primary_height, + bool use_primary_res) { + uint32_t panel_bpp = 0; + uint32_t pattern_type = 0; + + if (qdutils::isDPConnected()) { + qdutils::getDPTestConfig(&panel_bpp, &pattern_type); + } + + if (panel_bpp && pattern_type) { + return HWCDisplayExternalTest::Create(core_intf_, &hwc_procs_, qservice_, panel_bpp, + pattern_type, &hwc_display_[disp]); + } + + return HWCDisplayExternal::Create(core_intf_, &hwc_procs_, primary_width, primary_height, + qservice_, use_primary_res, &hwc_display_[disp]); +} + +} // namespace sdm + diff --git a/msm8909/sdm/libs/hwc/hwc_session.h b/msm8909/sdm/libs/hwc/hwc_session.h new file mode 100644 index 00000000..1cd3e336 --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_session.h @@ -0,0 +1,162 @@ +/* +* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted +* provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright notice, this list of +* conditions and the following disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its contributors may be used to +* endorse or promote products derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __HWC_SESSION_H__ +#define __HWC_SESSION_H__ + +#include <hardware/hwcomposer.h> +#include <core/core_interface.h> +#include <utils/locker.h> + +#include "hwc_display_primary.h" +#include "hwc_display_external.h" +#include "hwc_display_virtual.h" +#include "hwc_color_manager.h" +#include "hwc_socket_handler.h" + +namespace sdm { + +class HWCSession : hwc_composer_device_1_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(); + + 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 int Prepare(hwc_composer_device_1 *device, size_t num_displays, + hwc_display_contents_1_t **displays); + static int Set(hwc_composer_device_1 *device, size_t num_displays, + hwc_display_contents_1_t **displays); + static int EventControl(hwc_composer_device_1 *device, int disp, int event, int enable); + static int SetPowerMode(hwc_composer_device_1 *device, int disp, int mode); + static int Query(hwc_composer_device_1 *device, int param, int *value); + static void RegisterProcs(hwc_composer_device_1 *device, hwc_procs_t const *procs); + static void Dump(hwc_composer_device_1 *device, char *buffer, int length); + // These config functions always return FB params, the actual display params may differ. + static int GetDisplayConfigs(hwc_composer_device_1 *device, int disp, uint32_t *configs, + size_t *numConfigs); + static int GetDisplayAttributes(hwc_composer_device_1 *device, int disp, uint32_t config, + const uint32_t *display_attributes, int32_t *values); + static int GetActiveConfig(hwc_composer_device_1 *device, int disp); + static int SetActiveConfig(hwc_composer_device_1 *device, int disp, int index); + static int SetCursorPositionAsync(hwc_composer_device_1 *device, int disp, int x, int y); + static void CloseAcquireFds(hwc_display_contents_1_t *content_list); + bool IsDisplayYUV(int disp); + + // 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(); + int ConnectDisplay(int disp, hwc_display_contents_1_t *content_list); + int DisconnectDisplay(int disp); + void HandleSecureDisplaySession(hwc_display_contents_1_t **displays); + int GetVsyncPeriod(int disp); + int CreateExternalDisplay(int disp, uint32_t primary_width, uint32_t primary_height, + bool use_primary_res); + + // 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); + android::status_t SetMixerResolution(const android::Parcel *input_parcel); + android::status_t SetDisplayPort(DisplayPort sdm_disp_port, int *hwc_disp_port); + android::status_t GetHdrCapabilities(const android::Parcel *input_parcel, + android::Parcel *output_parcel); + + static Locker locker_; + CoreInterface *core_intf_ = NULL; + hwc_procs_t hwc_procs_default_; + hwc_procs_t const *hwc_procs_ = &hwc_procs_default_; + HWCDisplay *hwc_display_[HWC_NUM_DISPLAY_TYPES] = { NULL }; + pthread_t uevent_thread_; + bool uevent_thread_exit_ = false; + const char *uevent_thread_name_ = "HWC_UeventThread"; + HWCBufferAllocator buffer_allocator_; + HWCBufferSyncHandler buffer_sync_handler_; + 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; + bool is_hdmi_primary_ = false; + bool is_hdmi_yuv_ = false; + std::bitset<HWC_NUM_DISPLAY_TYPES> connected_displays_; // Bit mask of connected displays + HWCSocketHandler socket_handler_; + Locker uevent_locker_; +}; + +} // namespace sdm + +#endif // __HWC_SESSION_H__ + diff --git a/msm8909/sdm/libs/hwc/hwc_socket_handler.cpp b/msm8909/sdm/libs/hwc/hwc_socket_handler.cpp new file mode 100644 index 00000000..7ebaab48 --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_socket_handler.cpp @@ -0,0 +1,48 @@ +/* +* 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 <cutils/sockets.h> +#include "hwc_socket_handler.h" + +#define __CLASS__ "HWCSocketHandler" + +#define DPPS_SOCKET "pps" + +namespace sdm { + +int HWCSocketHandler::GetSocketFd(SocketType socket_type) { + switch (socket_type) { + case kDpps: + return socket_local_client(DPPS_SOCKET, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); + default: + return -1; + } +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/hwc/hwc_socket_handler.h b/msm8909/sdm/libs/hwc/hwc_socket_handler.h new file mode 100644 index 00000000..5b2292a2 --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_socket_handler.h @@ -0,0 +1,47 @@ +/* +* 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_SOCKET_HANDLER_H__ +#define __HWC_SOCKET_HANDLER_H__ + +#include <core/socket_handler.h> + +namespace sdm { + +class HWCSocketHandler : public SocketHandler { + public: + HWCSocketHandler() { } + + virtual int GetSocketFd(SocketType socket_type); +}; + +} // namespace sdm + +#endif // __HWC_SOCKET_HANDLER_H__ diff --git a/msm8909/sdm/libs/hwc/hwc_tonemapper.cpp b/msm8909/sdm/libs/hwc/hwc_tonemapper.cpp new file mode 100644 index 00000000..c09ff9e2 --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_tonemapper.cpp @@ -0,0 +1,341 @@ +/* +* Copyright (c) 2016 - 2017, 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 <alloc_controller.h> +#include <gr.h> +#include <gralloc_priv.h> +#include <memalloc.h> +#include <sync/sync.h> + +#include <TonemapFactory.h> + +#include <core/buffer_allocator.h> + +#include <utils/constants.h> +#include <utils/debug.h> +#include <utils/formats.h> +#include <utils/rect.h> +#include <utils/utils.h> + +#include <vector> + +#include "hwc_debugger.h" +#include "hwc_tonemapper.h" + +#define __CLASS__ "HWCToneMapper" + +namespace sdm { + +ToneMapSession::~ToneMapSession() { + delete gpu_tone_mapper_; + gpu_tone_mapper_ = NULL; + FreeIntermediateBuffers(); +} + +DisplayError ToneMapSession::AllocateIntermediateBuffers(int w, int h, int format, int usage) { + for (uint8_t i = 0; i < kNumIntermediateBuffers; i++) { + int status = alloc_buffer(&intermediate_buffer_[i], w, h, format, usage); + if (status < 0) { + FreeIntermediateBuffers(); + return kErrorMemory; + } + } + + return kErrorNone; +} + +void ToneMapSession::FreeIntermediateBuffers() { + for (uint8_t i = 0; i < kNumIntermediateBuffers; i++) { + private_handle_t *buffer = intermediate_buffer_[i]; + if (buffer) { + // Free the valid fence + if (release_fence_fd_[i] >= 0) { + CloseFd(&release_fence_fd_[i]); + } + free_buffer(buffer); + intermediate_buffer_[i] = NULL; + } + } +} + +void ToneMapSession::UpdateBuffer(int acquire_fence, LayerBuffer *buffer) { + // Acquire fence will be closed by HWC Display. + // Fence returned by GPU will be closed in PostCommit. + buffer->acquire_fence_fd = acquire_fence; + buffer->size = intermediate_buffer_[current_buffer_index_]->size; + buffer->planes[0].fd = intermediate_buffer_[current_buffer_index_]->fd; +} + +void ToneMapSession::SetReleaseFence(int fd) { + CloseFd(&release_fence_fd_[current_buffer_index_]); + // Used to give to GPU tonemapper along with input layer fd + release_fence_fd_[current_buffer_index_] = dup(fd); +} + +void ToneMapSession::SetToneMapConfig(Layer *layer) { + // HDR -> SDR is FORWARD and SDR - > HDR is INVERSE + tone_map_config_.type = layer->input_buffer.flags.hdr ? TONEMAP_FORWARD : TONEMAP_INVERSE; + tone_map_config_.colorPrimaries = layer->input_buffer.color_metadata.colorPrimaries; + tone_map_config_.transfer = layer->input_buffer.color_metadata.transfer; + tone_map_config_.secure = layer->request.flags.secure; + tone_map_config_.format = layer->request.format; +} + +bool ToneMapSession::IsSameToneMapConfig(Layer *layer) { + LayerBuffer& buffer = layer->input_buffer; + private_handle_t *handle = intermediate_buffer_[0]; + int tonemap_type = buffer.flags.hdr ? TONEMAP_FORWARD : TONEMAP_INVERSE; + + return ((tonemap_type == tone_map_config_.type) && + (buffer.color_metadata.colorPrimaries == tone_map_config_.colorPrimaries) && + (buffer.color_metadata.transfer == tone_map_config_.transfer) && + (layer->request.flags.secure == tone_map_config_.secure) && + (layer->request.format == tone_map_config_.format) && + (layer->request.width == UINT32(handle->unaligned_width)) && + (layer->request.height == UINT32(handle->unaligned_height))); +} + +int HWCToneMapper::HandleToneMap(hwc_display_contents_1_t *content_list, LayerStack *layer_stack) { + uint32_t gpu_count = 0; + DisplayError error = kErrorNone; + + for (uint32_t i = 0; i < layer_stack->layers.size(); i++) { + uint32_t session_index = 0; + Layer *layer = layer_stack->layers.at(i); + if (layer->composition == kCompositionGPU) { + gpu_count++; + } + + if (layer->request.flags.tone_map) { + switch (layer->composition) { + case kCompositionGPUTarget: + if (!gpu_count) { + // When all layers are on FrameBuffer and if they do not update in the next draw cycle, + // then SDM marks them for SDE Composition because the cached FB layer gets displayed. + // GPU count will be 0 in this case. Try to use the existing tone-mapped frame buffer. + // No ToneMap/Blit is required. Just update the buffer & acquire fence fd of FB layer. + if (!tone_map_sessions_.empty()) { + ToneMapSession *fb_tone_map_session = tone_map_sessions_.at(fb_session_index_); + fb_tone_map_session->UpdateBuffer(-1 /* acquire_fence */, &layer->input_buffer); + fb_tone_map_session->layer_index_ = INT(i); + fb_tone_map_session->acquired_ = true; + return 0; + } + } + error = AcquireToneMapSession(layer, &session_index); + fb_session_index_ = session_index; + break; + default: + error = AcquireToneMapSession(layer, &session_index); + break; + } + + if (error != kErrorNone) { + Terminate(); + return -1; + } + + ToneMapSession *session = tone_map_sessions_.at(session_index); + ToneMap(&content_list->hwLayers[i], layer, session); + session->layer_index_ = INT(i); + } + } + + return 0; +} + +void HWCToneMapper::ToneMap(hwc_layer_1_t *hwc_layer, Layer* layer, ToneMapSession *session) { + int fence_fd = -1; + int acquire_fd = -1; + int merged_fd = -1; + + uint8_t buffer_index = session->current_buffer_index_; + const private_handle_t *dst_hnd = session->intermediate_buffer_[buffer_index]; + const private_handle_t *src_hnd = static_cast<const private_handle_t *>(hwc_layer->handle); + + acquire_fd = dup(layer->input_buffer.acquire_fence_fd); + buffer_sync_handler_.SyncMerge(session->release_fence_fd_[buffer_index], acquire_fd, &merged_fd); + + if (acquire_fd >= 0) { + CloseFd(&acquire_fd); + } + + if (session->release_fence_fd_[buffer_index] >= 0) { + CloseFd(&session->release_fence_fd_[buffer_index]); + } + + DTRACE_BEGIN("GPU_TM_BLIT"); + fence_fd = session->gpu_tone_mapper_->blit(reinterpret_cast<const void *>(dst_hnd), + reinterpret_cast<const void *>(src_hnd), merged_fd); + DTRACE_END(); + + DumpToneMapOutput(session, &fence_fd); + session->UpdateBuffer(fence_fd, &layer->input_buffer); +} + +void HWCToneMapper::PostCommit(LayerStack *layer_stack) { + auto it = tone_map_sessions_.begin(); + while (it != tone_map_sessions_.end()) { + uint32_t session_index = UINT32(std::distance(tone_map_sessions_.begin(), it)); + ToneMapSession *session = tone_map_sessions_.at(session_index); + Layer *layer = layer_stack->layers.at(UINT32(session->layer_index_)); + if (session->acquired_) { + // Close the fd returned by GPU ToneMapper and set release fence. + LayerBuffer &layer_buffer = layer->input_buffer; + CloseFd(&layer_buffer.acquire_fence_fd); + session->SetReleaseFence(layer_buffer.release_fence_fd); + session->acquired_ = false; + it++; + } else { + delete session; + it = tone_map_sessions_.erase(it); + } + } +} + +void HWCToneMapper::Terminate() { + if (tone_map_sessions_.size()) { + while (!tone_map_sessions_.empty()) { + delete tone_map_sessions_.back(); + tone_map_sessions_.pop_back(); + } + fb_session_index_ = 0; + } +} + +void HWCToneMapper::SetFrameDumpConfig(uint32_t count) { + DLOGI("Dump FrameConfig count = %d", count); + dump_frame_count_ = count; + dump_frame_index_ = 0; +} + +void HWCToneMapper::DumpToneMapOutput(ToneMapSession *session, int *acquire_fd) { + if (!dump_frame_count_) { + return; + } + + private_handle_t *target_buffer = session->intermediate_buffer_[session->current_buffer_index_]; + + if (*acquire_fd >= 0) { + int error = sync_wait(*acquire_fd, 1000); + if (error < 0) { + DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno)); + return; + } + } + + size_t result = 0; + char dump_file_name[PATH_MAX]; + snprintf(dump_file_name, sizeof(dump_file_name), "/data/misc/display/frame_dump_primary" + "/tonemap_%dx%d_frame%d.raw", target_buffer->width, target_buffer->height, + dump_frame_index_); + + FILE* fp = fopen(dump_file_name, "w+"); + if (fp) { + DLOGI("base addr = %x", target_buffer->base); + result = fwrite(reinterpret_cast<void *>(target_buffer->base), target_buffer->size, 1, fp); + fclose(fp); + } + dump_frame_count_--; + dump_frame_index_++; + CloseFd(acquire_fd); +} + +DisplayError HWCToneMapper::AcquireToneMapSession(Layer *layer, uint32_t *session_index) { + Color10Bit *grid_entries = NULL; + int grid_size = 0; + + if (layer->lut_3d.validGridEntries) { + grid_entries = layer->lut_3d.gridEntries; + grid_size = INT(layer->lut_3d.gridSize); + } + + // When the property sdm.disable_hdr_lut_gen is set, the lutEntries and gridEntries in + // the Lut3d will be NULL, clients needs to allocate the memory and set correct 3D Lut + // for Tonemapping. + if (!layer->lut_3d.lutEntries || !layer->lut_3d.dim) { + // Atleast lutEntries must be valid for GPU Tonemapper. + DLOGE("Invalid Lut Entries or lut dimension = %d", layer->lut_3d.dim); + return kErrorParameters; + } + + // Check if we can re-use an existing tone map session. + for (uint32_t i = 0; i < tone_map_sessions_.size(); i++) { + ToneMapSession *tonemap_session = tone_map_sessions_.at(i); + if (!tonemap_session->acquired_ && tonemap_session->IsSameToneMapConfig(layer)) { + tonemap_session->current_buffer_index_ = (tonemap_session->current_buffer_index_ + 1) % + ToneMapSession::kNumIntermediateBuffers; + tonemap_session->acquired_ = true; + *session_index = i; + return kErrorNone; + } + } + + ToneMapSession *session = new ToneMapSession(); + + session->SetToneMapConfig(layer); + session->gpu_tone_mapper_ = TonemapperFactory_GetInstance(session->tone_map_config_.type, + layer->lut_3d.lutEntries, + layer->lut_3d.dim, + grid_entries, grid_size, + session->tone_map_config_.secure); + + if (session->gpu_tone_mapper_ == NULL) { + DLOGE("Get Tonemapper failed!"); + delete session; + return kErrorNotSupported; + } + + int status, format; + DisplayError error = kErrorNone; + int usage = INT(GRALLOC_USAGE_PRIVATE_IOMMU_HEAP | GRALLOC_USAGE_HW_TEXTURE); + + if (layer->request.flags.secure) { + usage = INT(GRALLOC_USAGE_PRIVATE_MM_HEAP); + usage |= INT(GRALLOC_USAGE_PROTECTED); + } + + status = buffer_allocator_.SetBufferInfo(layer->request.format, &format, &usage); + error = session->AllocateIntermediateBuffers(INT(layer->request.width), + INT(layer->request.height), format, usage); + + if (error != kErrorNone) { + DLOGE("Allocation of Intermediate Buffers failed!"); + delete session; + return error; + } + + session->acquired_ = true; + tone_map_sessions_.push_back(session); + *session_index = UINT32(tone_map_sessions_.size() - 1); + + return kErrorNone; +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/hwc/hwc_tonemapper.h b/msm8909/sdm/libs/hwc/hwc_tonemapper.h new file mode 100644 index 00000000..0a463fe3 --- /dev/null +++ b/msm8909/sdm/libs/hwc/hwc_tonemapper.h @@ -0,0 +1,101 @@ +/* +* Copyright (c) 2016 - 2017, 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_TONEMAPPER_H__ +#define __HWC_TONEMAPPER_H__ + +#include <fcntl.h> +#include <sys/mman.h> + +#include <hardware/hwcomposer.h> + +#include <core/layer_stack.h> +#include <utils/sys.h> +#include <vector> +#include "hwc_buffer_sync_handler.h" +#include "hwc_buffer_allocator.h" + +class Tonemapper; + +namespace sdm { + +struct ToneMapConfig { + int type = 0; + ColorPrimaries colorPrimaries = ColorPrimaries_Max; + GammaTransfer transfer = Transfer_Max; + LayerBufferFormat format = kFormatRGBA8888; + bool secure = false; +}; + +class ToneMapSession { + public: + ~ToneMapSession(); + DisplayError AllocateIntermediateBuffers(int width, int height, int format, int usage); + void FreeIntermediateBuffers(); + void UpdateBuffer(int acquire_fence, LayerBuffer *buffer); + void SetReleaseFence(int fd); + void SetToneMapConfig(Layer *layer); + bool IsSameToneMapConfig(Layer *layer); + + static const uint8_t kNumIntermediateBuffers = 2; + Tonemapper *gpu_tone_mapper_ = NULL; + ToneMapConfig tone_map_config_ = {}; + uint8_t current_buffer_index_ = 0; + private_handle_t *intermediate_buffer_[kNumIntermediateBuffers] = {NULL, NULL}; + int release_fence_fd_[kNumIntermediateBuffers] = {-1, -1}; + bool acquired_ = false; + int layer_index_ = -1; +}; + +class HWCToneMapper { + public: + HWCToneMapper() {} + ~HWCToneMapper() {} + + int HandleToneMap(hwc_display_contents_1_t *content_list, LayerStack *layer_stack); + bool IsActive() { return !tone_map_sessions_.empty(); } + void PostCommit(LayerStack *layer_stack); + void SetFrameDumpConfig(uint32_t count); + void Terminate(); + + private: + void ToneMap(hwc_layer_1_t *hwc_layer, Layer *layer, ToneMapSession *session); + DisplayError AcquireToneMapSession(Layer *layer, uint32_t *session_index); + void DumpToneMapOutput(ToneMapSession *session, int *acquire_fence); + + std::vector<ToneMapSession*> tone_map_sessions_; + HWCBufferSyncHandler buffer_sync_handler_ = {}; + HWCBufferAllocator buffer_allocator_ = {}; + uint32_t dump_frame_count_ = 0; + uint32_t dump_frame_index_ = 0; + uint32_t fb_session_index_ = 0; +}; + +} // namespace sdm +#endif // __HWC_TONEMAPPER_H__ diff --git a/msm8909/sdm/libs/hwc2/Android.mk b/msm8909/sdm/libs/hwc2/Android.mk new file mode 100644 index 00000000..2d03c130 --- /dev/null +++ b/msm8909/sdm/libs/hwc2/Android.mk @@ -0,0 +1,67 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +include $(LOCAL_PATH)/../../../common.mk + +ifeq ($(use_hwc2),true) + +LOCAL_MODULE := hwcomposer.$(TARGET_BOARD_PLATFORM) +LOCAL_VENDOR_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_MODULE_TAGS := optional +LOCAL_C_INCLUDES := $(common_includes) +LOCAL_HEADER_LIBRARIES := display_headers + +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 +ifeq ($(TARGET_EXCLUDES_DISPLAY_PP), true) +LOCAL_CFLAGS += -DEXCLUDE_DISPLAY_PP +endif + +LOCAL_CLANG := true + +# TODO: Remove libui after addressing gpu_tonemapper issues +LOCAL_SHARED_LIBRARIES := libsdmcore libqservice libbinder libhardware libhardware_legacy \ + libutils libcutils libsync libqdutils libqdMetaData libdl libdrmutils \ + libsdmutils libc++ liblog libgrallocutils libdl \ + vendor.display.config@1.0 libhidlbase libhidltransport \ + libui libgpu_tonemapper + +ifneq ($(TARGET_USES_GRALLOC1), true) + LOCAL_SHARED_LIBRARIES += libmemalloc +endif + +ifeq ($(display_config_version), DISPLAY_CONFIG_1_1) +LOCAL_SHARED_LIBRARIES += vendor.display.config@1.1 +endif + +LOCAL_SRC_FILES := hwc_session.cpp \ + hwc_session_services.cpp \ + hwc_display.cpp \ + hwc_display_primary.cpp \ + hwc_display_external.cpp \ + hwc_display_virtual.cpp \ + ../hwc/hwc_debugger.cpp \ + ../hwc/hwc_buffer_sync_handler.cpp \ + hwc_color_manager.cpp \ + hwc_layers.cpp \ + hwc_callbacks.cpp \ + ../hwc/cpuhint.cpp \ + ../hwc/hwc_socket_handler.cpp \ + display_null.cpp \ + hwc_tonemapper.cpp \ + hwc_display_external_test.cpp + +ifneq ($(TARGET_USES_GRALLOC1), true) + LOCAL_SRC_FILES += ../hwc/hwc_buffer_allocator.cpp +else + LOCAL_SRC_FILES += hwc_buffer_allocator.cpp +endif + +ifeq ($(TARGET_HAS_WIDE_COLOR_DISPLAY), true) + LOCAL_CFLAGS += -DFEATURE_WIDE_COLOR +endif + +include $(BUILD_SHARED_LIBRARY) +endif diff --git a/msm8909/sdm/libs/hwc2/display_null.cpp b/msm8909/sdm/libs/hwc2/display_null.cpp new file mode 100644 index 00000000..16f4da66 --- /dev/null +++ b/msm8909/sdm/libs/hwc2/display_null.cpp @@ -0,0 +1,68 @@ +/* +* Copyright (c) 2017, 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 "display_null.h" + +#define __CLASS__ "DisplayNull" + +namespace sdm { + +DisplayError DisplayNull::Commit(LayerStack *layer_stack) { + for (Layer *layer : layer_stack->layers) { + if (layer->composition != kCompositionGPUTarget) { + layer->composition = kCompositionSDE; + layer->input_buffer.release_fence_fd = -1; + } + } + layer_stack->retire_fence_fd = -1; + + return kErrorNone; +} + +DisplayError DisplayNull::GetDisplayState(DisplayState *state) { + *state = state_; + return kErrorNone; +} + +DisplayError DisplayNull::SetDisplayState(DisplayState state) { + state_ = state; + return kErrorNone; +} + +DisplayError DisplayNull::SetFrameBufferConfig(const DisplayConfigVariableInfo &variable_info) { + fb_config_ = variable_info; + return kErrorNone; +} + +DisplayError DisplayNull::GetFrameBufferConfig(DisplayConfigVariableInfo *variable_info) { + *variable_info = fb_config_; + return kErrorNone; +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/hwc2/display_null.h b/msm8909/sdm/libs/hwc2/display_null.h new file mode 100644 index 00000000..c2db54e1 --- /dev/null +++ b/msm8909/sdm/libs/hwc2/display_null.h @@ -0,0 +1,110 @@ +/* +* Copyright (c) 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __DISPLAY_NULL_H__ +#define __DISPLAY_NULL_H__ + +#include <core/display_interface.h> +#include <string> +#include <vector> + +namespace sdm { + +#define MAKE_NO_OP(virtual_method_name) \ + virtual DisplayError virtual_method_name { return kErrorNone; } + +class DisplayNull : public DisplayInterface { + public: + virtual ~DisplayNull() { } + virtual DisplayError Commit(LayerStack *layer_stack); + virtual DisplayError GetDisplayState(DisplayState *state); + virtual DisplayError SetDisplayState(DisplayState state); + virtual DisplayError SetFrameBufferConfig(const DisplayConfigVariableInfo &variable_info); + virtual DisplayError GetFrameBufferConfig(DisplayConfigVariableInfo *variable_info); + virtual bool IsUnderscanSupported() { return true; } + virtual void SetIdleTimeoutMs(uint32_t active_ms) { } + virtual bool IsPrimaryDisplay() { return true; } + + void SetActive(bool active) { + active_ = active; + } + + bool IsActive() { + return active_; + } + + MAKE_NO_OP(Prepare(LayerStack *)) + MAKE_NO_OP(Flush()) + MAKE_NO_OP(GetNumVariableInfoConfigs(uint32_t *)) + MAKE_NO_OP(GetConfig(uint32_t, DisplayConfigVariableInfo *)) + MAKE_NO_OP(GetConfig(DisplayConfigFixedInfo *)) + MAKE_NO_OP(GetActiveConfig(uint32_t *)) + MAKE_NO_OP(GetVSyncState(bool *)) + MAKE_NO_OP(SetActiveConfig(uint32_t)) + MAKE_NO_OP(SetActiveConfig(DisplayConfigVariableInfo *)) + MAKE_NO_OP(SetMaxMixerStages(uint32_t)) + MAKE_NO_OP(ControlPartialUpdate(bool, uint32_t *)) + MAKE_NO_OP(DisablePartialUpdateOneFrame()) + MAKE_NO_OP(SetDisplayMode(uint32_t)) + MAKE_NO_OP(SetPanelBrightness(int)) + MAKE_NO_OP(CachePanelBrightness(int)) + MAKE_NO_OP(OnMinHdcpEncryptionLevelChange(uint32_t)) + MAKE_NO_OP(ColorSVCRequestRoute(const PPDisplayAPIPayload &, PPDisplayAPIPayload *, + PPPendingParams *)) + MAKE_NO_OP(GetColorModeCount(uint32_t *)) + MAKE_NO_OP(GetColorModes(uint32_t *, std::vector<std::string> *)) + MAKE_NO_OP(GetColorModeAttr(const std::string &, AttrVal *)) + MAKE_NO_OP(SetColorMode(const std::string &)) + MAKE_NO_OP(SetColorModeById(int32_t)) + MAKE_NO_OP(SetColorTransform(const uint32_t, const double *)) + MAKE_NO_OP(GetDefaultColorMode(std::string *)) + MAKE_NO_OP(ApplyDefaultDisplayMode()) + MAKE_NO_OP(SetCursorPosition(int, int)) + MAKE_NO_OP(GetRefreshRateRange(uint32_t *, uint32_t *)) + MAKE_NO_OP(SetRefreshRate(uint32_t)) + MAKE_NO_OP(GetPanelBrightness(int *)) + MAKE_NO_OP(SetVSyncState(bool)) + MAKE_NO_OP(SetMixerResolution(uint32_t, uint32_t)) + MAKE_NO_OP(GetMixerResolution(uint32_t *, uint32_t *)) + MAKE_NO_OP(SetDetailEnhancerData(const DisplayDetailEnhancerData &)) + MAKE_NO_OP(GetDisplayPort(DisplayPort *)) + MAKE_NO_OP(SetCompositionState(LayerComposition, bool)) + MAKE_NO_OP(GetClientTargetSupport(uint32_t, uint32_t, LayerBufferFormat, + const ColorMetaData &)) + std::string Dump() { return ""; } + + private: + bool active_ = false; + DisplayState state_ = kStateOff; + DisplayConfigVariableInfo fb_config_ = {}; +}; + +} // namespace sdm + +#endif // __DISPLAY_NULL_H__ diff --git a/msm8909/sdm/libs/hwc2/hwc_buffer_allocator.cpp b/msm8909/sdm/libs/hwc2/hwc_buffer_allocator.cpp new file mode 100644 index 00000000..a1796630 --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_buffer_allocator.cpp @@ -0,0 +1,409 @@ +/* +* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <gralloc_priv.h> + +#include <core/buffer_allocator.h> +#include <utils/constants.h> +#include <utils/debug.h> + +#include "hwc_buffer_allocator.h" +#include "hwc_debugger.h" +#include "gr_utils.h" + +#define __CLASS__ "HWCBufferAllocator" + +namespace sdm { + +DisplayError HWCBufferAllocator::Init() { + int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module_); + if (err != 0) { + DLOGE("FATAL: can not get GRALLOC module"); + return kErrorResources; + } + + err = gralloc1_open(module_, &gralloc_device_); + if (err != 0) { + DLOGE("FATAL: can not open GRALLOC device"); + return kErrorResources; + } + + if (gralloc_device_ == nullptr) { + DLOGE("FATAL: gralloc device is null"); + return kErrorResources; + } + + ReleaseBuffer_ = reinterpret_cast<GRALLOC1_PFN_RELEASE>( + gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_RELEASE)); + Perform_ = reinterpret_cast<GRALLOC1_PFN_PERFORM>( + gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_PERFORM)); + Lock_ = reinterpret_cast<GRALLOC1_PFN_LOCK>( + gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_LOCK)); + Unlock_ = reinterpret_cast<GRALLOC1_PFN_UNLOCK>( + gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_UNLOCK)); + + return kErrorNone; +} + +DisplayError HWCBufferAllocator::Deinit() { + if (gralloc_device_ != nullptr) { + int err = gralloc1_close(gralloc_device_); + if (err != 0) { + DLOGE("FATAL: can not close GRALLOC device"); + return kErrorResources; + } + } + return kErrorNone; +} + +DisplayError HWCBufferAllocator::AllocateBuffer(BufferInfo *buffer_info) { + const BufferConfig &buffer_config = buffer_info->buffer_config; + AllocatedBufferInfo *alloc_buffer_info = &buffer_info->alloc_buffer_info; + uint32_t width = buffer_config.width; + uint32_t height = buffer_config.height; + int format; + uint64_t alloc_flags = 0; + int error = SetBufferInfo(buffer_config.format, &format, &alloc_flags); + if (error != 0) { + return kErrorParameters; + } + + if (buffer_config.secure) { + alloc_flags |= GRALLOC1_PRODUCER_USAGE_PROTECTED; + } + + if (buffer_config.secure_camera) { + alloc_flags |= GRALLOC1_PRODUCER_USAGE_CAMERA; + } + + if (!buffer_config.cache) { + // Allocate uncached buffers + alloc_flags |= GRALLOC_USAGE_PRIVATE_UNCACHED; + } + + if (buffer_config.gfx_client) { + alloc_flags |= GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE; + } + + uint64_t producer_usage = alloc_flags; + uint64_t consumer_usage = (alloc_flags | GRALLOC1_CONSUMER_USAGE_HWCOMPOSER); + // CreateBuffer + private_handle_t *hnd = nullptr; + Perform_(gralloc_device_, GRALLOC1_MODULE_PERFORM_ALLOCATE_BUFFER, width, height, format, + producer_usage, consumer_usage, &hnd); + + if (hnd) { + alloc_buffer_info->fd = hnd->fd; + alloc_buffer_info->stride = UINT32(hnd->width); + alloc_buffer_info->aligned_width = UINT32(hnd->width); + alloc_buffer_info->aligned_height = UINT32(hnd->height); + alloc_buffer_info->size = hnd->size; + } else { + DLOGE("Failed to allocate memory"); + return kErrorMemory; + } + + buffer_info->private_data = reinterpret_cast<void *>(hnd); + return kErrorNone; +} + +DisplayError HWCBufferAllocator::FreeBuffer(BufferInfo *buffer_info) { + DisplayError err = kErrorNone; + buffer_handle_t hnd = static_cast<private_handle_t *>(buffer_info->private_data); + ReleaseBuffer_(gralloc_device_, hnd); + AllocatedBufferInfo *alloc_buffer_info = &buffer_info->alloc_buffer_info; + + alloc_buffer_info->fd = -1; + alloc_buffer_info->stride = 0; + alloc_buffer_info->size = 0; + buffer_info->private_data = NULL; + return err; +} + +void HWCBufferAllocator::GetCustomWidthAndHeight(const private_handle_t *handle, int *width, + int *height) { + Perform_(gralloc_device_, GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_AND_HEIGHT_FROM_HANDLE, handle, + width, height); +} + +void HWCBufferAllocator::GetAlignedWidthAndHeight(int width, int height, int format, + uint32_t alloc_type, int *aligned_width, + int *aligned_height) { + int tile_enabled; + gralloc1_producer_usage_t producer_usage = GRALLOC1_PRODUCER_USAGE_NONE; + gralloc1_consumer_usage_t consumer_usage = GRALLOC1_CONSUMER_USAGE_NONE; + if (alloc_type & GRALLOC_USAGE_HW_FB) { + consumer_usage = GRALLOC1_CONSUMER_USAGE_CLIENT_TARGET; + } + if (alloc_type & GRALLOC_USAGE_PRIVATE_ALLOC_UBWC) { + producer_usage = GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + } + + Perform_(gralloc_device_, GRALLOC_MODULE_PERFORM_GET_ATTRIBUTES, width, height, format, + producer_usage, consumer_usage, aligned_width, aligned_height, &tile_enabled); +} + +uint32_t HWCBufferAllocator::GetBufferSize(BufferInfo *buffer_info) { + const BufferConfig &buffer_config = buffer_info->buffer_config; + uint64_t alloc_flags = GRALLOC_USAGE_PRIVATE_IOMMU_HEAP; + + int width = INT(buffer_config.width); + int height = INT(buffer_config.height); + int format; + + if (buffer_config.secure) { + alloc_flags |= INT(GRALLOC_USAGE_PROTECTED); + } + + if (!buffer_config.cache) { + // Allocate uncached buffers + alloc_flags |= GRALLOC_USAGE_PRIVATE_UNCACHED; + } + + if (SetBufferInfo(buffer_config.format, &format, &alloc_flags) < 0) { + return 0; + } + + uint32_t aligned_width = 0, aligned_height = 0, buffer_size = 0; + gralloc1_producer_usage_t producer_usage = GRALLOC1_PRODUCER_USAGE_NONE; + gralloc1_consumer_usage_t consumer_usage = GRALLOC1_CONSUMER_USAGE_NONE; + // TODO(user): Currently both flags are treated similarly in gralloc + producer_usage = gralloc1_producer_usage_t(alloc_flags); + consumer_usage = gralloc1_consumer_usage_t(alloc_flags); + gralloc1::BufferInfo info(width, height, format, producer_usage, consumer_usage); + GetBufferSizeAndDimensions(info, &buffer_size, &aligned_width, &aligned_height); + return buffer_size; +} + +int HWCBufferAllocator::SetBufferInfo(LayerBufferFormat format, int *target, uint64_t *flags) { + switch (format) { + case kFormatRGBA8888: + *target = HAL_PIXEL_FORMAT_RGBA_8888; + break; + case kFormatRGBX8888: + *target = HAL_PIXEL_FORMAT_RGBX_8888; + break; + case kFormatRGB888: + *target = HAL_PIXEL_FORMAT_RGB_888; + break; + case kFormatRGB565: + *target = HAL_PIXEL_FORMAT_RGB_565; + break; + case kFormatBGR565: + *target = HAL_PIXEL_FORMAT_BGR_565; + break; + case kFormatBGR888: + *target = HAL_PIXEL_FORMAT_BGR_888; + break; + case kFormatBGRA8888: + *target = HAL_PIXEL_FORMAT_BGRA_8888; + break; + case kFormatYCrCb420PlanarStride16: + *target = HAL_PIXEL_FORMAT_YV12; + break; + case kFormatYCrCb420SemiPlanar: + *target = HAL_PIXEL_FORMAT_YCrCb_420_SP; + break; + case kFormatYCbCr420SemiPlanar: + *target = HAL_PIXEL_FORMAT_YCbCr_420_SP; + break; + case kFormatYCbCr422H2V1Packed: + *target = HAL_PIXEL_FORMAT_YCbCr_422_I; + break; + case kFormatCbYCrY422H2V1Packed: + *target = HAL_PIXEL_FORMAT_CbYCrY_422_I; + break; + case kFormatYCbCr422H2V1SemiPlanar: + *target = HAL_PIXEL_FORMAT_YCbCr_422_SP; + break; + case kFormatYCbCr420SemiPlanarVenus: + *target = HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS; + break; + case kFormatYCrCb420SemiPlanarVenus: + *target = HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS; + break; + case kFormatYCbCr420SPVenusUbwc: + *target = HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC; + *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + break; + case kFormatRGBA5551: + *target = HAL_PIXEL_FORMAT_RGBA_5551; + break; + case kFormatRGBA4444: + *target = HAL_PIXEL_FORMAT_RGBA_4444; + break; + case kFormatRGBA1010102: + *target = HAL_PIXEL_FORMAT_RGBA_1010102; + break; + case kFormatARGB2101010: + *target = HAL_PIXEL_FORMAT_ARGB_2101010; + break; + case kFormatRGBX1010102: + *target = HAL_PIXEL_FORMAT_RGBX_1010102; + break; + case kFormatXRGB2101010: + *target = HAL_PIXEL_FORMAT_XRGB_2101010; + break; + case kFormatBGRA1010102: + *target = HAL_PIXEL_FORMAT_BGRA_1010102; + break; + case kFormatABGR2101010: + *target = HAL_PIXEL_FORMAT_ABGR_2101010; + break; + case kFormatBGRX1010102: + *target = HAL_PIXEL_FORMAT_BGRX_1010102; + break; + case kFormatXBGR2101010: + *target = HAL_PIXEL_FORMAT_XBGR_2101010; + break; + case kFormatYCbCr420P010: + *target = HAL_PIXEL_FORMAT_YCbCr_420_P010; + break; + case kFormatYCbCr420TP10Ubwc: + *target = HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC; + *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + break; + case kFormatYCbCr420P010Ubwc: + *target = HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC; + *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + break; + case kFormatRGBA8888Ubwc: + *target = HAL_PIXEL_FORMAT_RGBA_8888; + *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + break; + case kFormatRGBX8888Ubwc: + *target = HAL_PIXEL_FORMAT_RGBX_8888; + *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + break; + case kFormatBGR565Ubwc: + *target = HAL_PIXEL_FORMAT_BGR_565; + *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + break; + case kFormatRGBA1010102Ubwc: + *target = HAL_PIXEL_FORMAT_RGBA_1010102; + *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + break; + case kFormatRGBX1010102Ubwc: + *target = HAL_PIXEL_FORMAT_RGBX_1010102; + *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + break; + default: + DLOGE("Unsupported format = 0x%x", format); + return -EINVAL; + } + return 0; +} + +DisplayError HWCBufferAllocator::GetAllocatedBufferInfo( + const BufferConfig &buffer_config, AllocatedBufferInfo *allocated_buffer_info) { + // TODO(user): This API should pass the buffer_info of the already allocated buffer + // The private_data can then be typecast to the private_handle and used directly. + uint64_t alloc_flags = GRALLOC_USAGE_PRIVATE_IOMMU_HEAP; + + int width = INT(buffer_config.width); + int height = INT(buffer_config.height); + int format; + + if (buffer_config.secure) { + alloc_flags |= INT(GRALLOC_USAGE_PROTECTED); + } + + if (!buffer_config.cache) { + // Allocate uncached buffers + alloc_flags |= GRALLOC_USAGE_PRIVATE_UNCACHED; + } + + if (SetBufferInfo(buffer_config.format, &format, &alloc_flags) < 0) { + return kErrorParameters; + } + + uint32_t aligned_width = 0, aligned_height = 0, buffer_size = 0; + gralloc1_producer_usage_t producer_usage = GRALLOC1_PRODUCER_USAGE_NONE; + gralloc1_consumer_usage_t consumer_usage = GRALLOC1_CONSUMER_USAGE_NONE; + // TODO(user): Currently both flags are treated similarly in gralloc + producer_usage = gralloc1_producer_usage_t(alloc_flags); + consumer_usage = gralloc1_consumer_usage_t(alloc_flags); + gralloc1::BufferInfo info(width, height, format, producer_usage, consumer_usage); + GetBufferSizeAndDimensions(info, &buffer_size, &aligned_width, &aligned_height); + allocated_buffer_info->stride = UINT32(aligned_width); + allocated_buffer_info->aligned_width = UINT32(aligned_width); + allocated_buffer_info->aligned_height = UINT32(aligned_height); + allocated_buffer_info->size = UINT32(buffer_size); + + return kErrorNone; +} + +DisplayError HWCBufferAllocator::GetBufferLayout(const AllocatedBufferInfo &buf_info, + uint32_t stride[4], uint32_t offset[4], + uint32_t *num_planes) { + // TODO(user): Transition APIs to not need a private handle + private_handle_t hnd(-1, 0, 0, 0, 0, 0, 0); + int format = HAL_PIXEL_FORMAT_RGBA_8888; + uint64_t flags = 0; + + SetBufferInfo(buf_info.format, &format, &flags); + // Setup only the required stuff, skip rest + hnd.format = format; + hnd.width = INT32(buf_info.aligned_width); + hnd.height = INT32(buf_info.aligned_height); + if (flags & GRALLOC_USAGE_PRIVATE_ALLOC_UBWC) { + hnd.flags = private_handle_t::PRIV_FLAGS_UBWC_ALIGNED; + } + + int ret = gralloc1::GetBufferLayout(&hnd, stride, offset, num_planes); + if (ret < 0) { + DLOGE("GetBufferLayout failed"); + return kErrorParameters; + } + + return kErrorNone; +} + +DisplayError HWCBufferAllocator::MapBuffer(const private_handle_t *handle, int acquire_fence) { + void* buffer_ptr = NULL; + const gralloc1_rect_t accessRegion = { + .left = 0, + .top = 0, + .width = 0, + .height = 0 + }; + Lock_(gralloc_device_, handle, GRALLOC1_PRODUCER_USAGE_CPU_READ, GRALLOC1_CONSUMER_USAGE_NONE, + &accessRegion, &buffer_ptr, acquire_fence); + if (!buffer_ptr) { + return kErrorUndefined; + } + + return kErrorNone; +} + +DisplayError HWCBufferAllocator::UnmapBuffer(const private_handle_t *handle, int* release_fence) { + return (DisplayError)(Unlock_(gralloc_device_, handle, release_fence)); +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/hwc2/hwc_buffer_allocator.h b/msm8909/sdm/libs/hwc2/hwc_buffer_allocator.h new file mode 100644 index 00000000..2cc50b1d --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_buffer_allocator.h @@ -0,0 +1,80 @@ +/* +* Copyright (c) 2015-2017, 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. +*/ +#ifdef USE_GRALLOC1 +#ifndef __HWC_BUFFER_ALLOCATOR_H__ +#define __HWC_BUFFER_ALLOCATOR_H__ + +#include <fcntl.h> +#include <sys/mman.h> + +#include <hardware/gralloc1.h> +#include "gralloc_priv.h" + +namespace sdm { + +template <class Type> +inline Type ALIGN(Type x, Type align) { + return (x + align - 1) & ~(align - 1); +} + +class HWCBufferAllocator : public BufferAllocator { + public: + DisplayError Init(); + DisplayError Deinit(); + DisplayError AllocateBuffer(BufferInfo *buffer_info); + DisplayError FreeBuffer(BufferInfo *buffer_info); + uint32_t GetBufferSize(BufferInfo *buffer_info); + + void GetCustomWidthAndHeight(const private_handle_t *handle, int *width, int *height); + void GetAlignedWidthAndHeight(int width, int height, int format, uint32_t alloc_type, + int *aligned_width, int *aligned_height); + DisplayError GetAllocatedBufferInfo(const BufferConfig &buffer_config, + AllocatedBufferInfo *allocated_buffer_info); + DisplayError GetBufferLayout(const AllocatedBufferInfo &buf_info, + uint32_t stride[4], uint32_t offset[4], + uint32_t *num_planes); + int SetBufferInfo(LayerBufferFormat format, int *target, uint64_t *flags); + DisplayError MapBuffer(const private_handle_t *handle, int acquire_fence); + DisplayError UnmapBuffer(const private_handle_t *handle, int* release_fence); + + private: + gralloc1_device_t *gralloc_device_ = nullptr; + const hw_module_t *module_; + GRALLOC1_PFN_RELEASE ReleaseBuffer_ = nullptr; + GRALLOC1_PFN_PERFORM Perform_ = nullptr; + GRALLOC1_PFN_LOCK Lock_ = nullptr; + GRALLOC1_PFN_UNLOCK Unlock_ = nullptr; +}; + +} // namespace sdm +#endif // __HWC_BUFFER_ALLOCATOR_H__ +#else +#include "../hwc/hwc_buffer_allocator.h" +#endif // __HWC_BUFFER_ALLOCATOR_H__ + diff --git a/msm8909/sdm/libs/hwc2/hwc_callbacks.cpp b/msm8909/sdm/libs/hwc2/hwc_callbacks.cpp new file mode 100644 index 00000000..3be3bf64 --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_callbacks.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016-2017, 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 { + +HWC2::Error HWCCallbacks::Hotplug(hwc2_display_t display, HWC2::Connection state) { + if (!hotplug_) { + return HWC2::Error::NoResources; + } + hotplug_(hotplug_data_, display, INT32(state)); + return HWC2::Error::None; +} + +HWC2::Error HWCCallbacks::Refresh(hwc2_display_t display) { + if (!refresh_) { + return HWC2::Error::NoResources; + } + refresh_(refresh_data_, display); + return HWC2::Error::None; +} + +HWC2::Error HWCCallbacks::Vsync(hwc2_display_t display, int64_t timestamp) { + if (!vsync_) { + return HWC2::Error::NoResources; + } + vsync_(vsync_data_, display, timestamp); + return HWC2::Error::None; +} + +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 diff --git a/msm8909/sdm/libs/hwc2/hwc_callbacks.h b/msm8909/sdm/libs/hwc2/hwc_callbacks.h new file mode 100644 index 00000000..d3f4e529 --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_callbacks.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016-2017, 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: + HWC2::Error Hotplug(hwc2_display_t display, HWC2::Connection state); + HWC2::Error Refresh(hwc2_display_t display); + HWC2::Error Vsync(hwc2_display_t display, int64_t timestamp); + HWC2::Error Register(HWC2::Callback, hwc2_callback_data_t callback_data, + hwc2_function_pointer_t pointer); + + bool VsyncCallbackRegistered() { return (vsync_ != nullptr && vsync_data_ != nullptr); } + + 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__ diff --git a/msm8909/sdm/libs/hwc2/hwc_color_manager.cpp b/msm8909/sdm/libs/hwc2/hwc_color_manager.cpp new file mode 100644 index 00000000..5578fde1 --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_color_manager.cpp @@ -0,0 +1,461 @@ +/* +* Copyright (c) 2015 - 2017, 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 <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 <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 << 8) & 0xff00) | + ((params.color.b) & 0xff); + 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(HWCBufferAllocator * buffer_allocator) { + HWCColorManager *color_mgr = new HWCColorManager(buffer_allocator); + + if (color_mgr) { + // Load display API interface library. And retrieve color API function tables. + DynLib &color_apis_lib = color_mgr->color_apis_lib_; + if (color_apis_lib.Open(DISPLAY_API_INTERFACE_LIBRARY_NAME)) { + if (!color_apis_lib.Sym(DISPLAY_API_FUNC_TABLES, &color_mgr->color_apis_)) { + DLOGE("Fail to retrieve = %s from %s", DISPLAY_API_FUNC_TABLES, + DISPLAY_API_INTERFACE_LIBRARY_NAME); + 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. + DynLib &diag_client_lib = color_mgr->diag_client_lib_; + if (diag_client_lib.Open(QDCM_DIAG_CLIENT_LIBRARY_NAME)) { + if (!diag_client_lib.Sym(INIT_QDCM_DIAG_CLIENT_NAME, + reinterpret_cast<void **>(&color_mgr->qdcm_diag_init_)) || + !diag_client_lib.Sym(DEINIT_QDCM_DIAG_CLIENT_NAME, + reinterpret_cast<void **>(&color_mgr->qdcm_diag_deinit_))) { + DLOGE("Fail to retrieve = %s from %s", INIT_QDCM_DIAG_CLIENT_NAME, + QDCM_DIAG_CLIENT_LIBRARY_NAME); + } 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(HWCBufferAllocator *buffer_allocator) : + buffer_allocator_(buffer_allocator) { +} + +HWCColorManager::~HWCColorManager() { +} + +void HWCColorManager::DestroyColorManager() { + if (qdcm_mode_mgr_) { + delete qdcm_mode_mgr_; + } + if (qdcm_diag_deinit_) { + qdcm_diag_deinit_(); + } + 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; +} + +int HWCColorManager::SetSolidFill(const void *params, bool enable, HWCDisplay *hwc_display) { + SCOPE_LOCK(locker_); + + if (params) { + solid_fill_params_ = *reinterpret_cast<const PPColorFillParams *>(params); + } else { + solid_fill_params_ = PPColorFillParams(); + } + + uint32_t solid_fill_color = Get8BitsARGBColorValue(solid_fill_params_); + if (enable) { + LayerRect solid_fill_rect = { + FLOAT(solid_fill_params_.rect.x), FLOAT(solid_fill_params_.rect.y), + FLOAT(solid_fill_params_.rect.x) + FLOAT(solid_fill_params_.rect.width), + FLOAT(solid_fill_params_.rect.y) + FLOAT(solid_fill_params_.rect.height), + }; + + hwc_display->Perform(HWCDisplayPrimary::SET_QDCM_SOLID_FILL_INFO, solid_fill_color); + hwc_display->Perform(HWCDisplayPrimary::SET_QDCM_SOLID_FILL_RECT, &solid_fill_rect); + } else { + hwc_display->Perform(HWCDisplayPrimary::UNSET_QDCM_SOLID_FILL_INFO, 0); + } + + return 0; +} + +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->GetPanelResolution(&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) { + buffer_info.buffer_config.format = kFormatRGBA1010102; + } 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; + + ret = buffer_allocator_->AllocateBuffer(&buffer_info); + if (ret != 0) { + DLOGE("Buffer allocation failed. ret: %d", ret); + 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); + 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; + } + ret = hwc_display->FrameCaptureAsync(buffer_info, 1); + if (ret < 0) { + DLOGE("FrameCaptureAsync failed. ret = %d", ret); + } + } + } else { + ret = hwc_display->GetFrameCaptureStatus(); + if (!ret) { + 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); + } + } + } else { + DLOGE("GetFrameCaptureStatus failed. ret = %d", ret); + } + } + return ret; +} + +int HWCColorManager::SetHWDetailedEnhancerConfig(void *params, HWCDisplay *hwc_display) { + int err = -1; + DisplayDetailEnhancerData de_data; + + PPDETuningCfgData *de_tuning_cfg_data = reinterpret_cast<PPDETuningCfgData*>(params); + if (de_tuning_cfg_data->cfg_pending == true) { + if (!de_tuning_cfg_data->cfg_en) { + de_data.enable = 0; + } else { + de_data.override_flags = kOverrideDEEnable; + de_data.enable = 1; + + if (de_tuning_cfg_data->params.flags & kDeTuningFlagSharpFactor) { + de_data.override_flags |= kOverrideDESharpen1; + de_data.sharp_factor = de_tuning_cfg_data->params.sharp_factor; + } + + if (de_tuning_cfg_data->params.flags & kDeTuningFlagClip) { + de_data.override_flags |= kOverrideDEClip; + de_data.clip = de_tuning_cfg_data->params.clip; + } + + if (de_tuning_cfg_data->params.flags & kDeTuningFlagThrQuiet) { + de_data.override_flags |= kOverrideDEThrQuiet; + de_data.thr_quiet = de_tuning_cfg_data->params.thr_quiet; + } + + if (de_tuning_cfg_data->params.flags & kDeTuningFlagThrDieout) { + de_data.override_flags |= kOverrideDEThrDieout; + de_data.thr_dieout = de_tuning_cfg_data->params.thr_dieout; + } + + if (de_tuning_cfg_data->params.flags & kDeTuningFlagThrLow) { + de_data.override_flags |= kOverrideDEThrLow; + de_data.thr_low = de_tuning_cfg_data->params.thr_low; + } + + if (de_tuning_cfg_data->params.flags & kDeTuningFlagThrHigh) { + de_data.override_flags |= kOverrideDEThrHigh; + de_data.thr_high = de_tuning_cfg_data->params.thr_high; + } + + if (de_tuning_cfg_data->params.flags & kDeTuningFlagContentQualLevel) { + switch (de_tuning_cfg_data->params.quality) { + case kDeContentQualLow: + de_data.quality_level = kContentQualityLow; + break; + case kDeContentQualMedium: + de_data.quality_level = kContentQualityMedium; + break; + case kDeContentQualHigh: + de_data.quality_level = kContentQualityHigh; + break; + case kDeContentQualUnknown: + default: + de_data.quality_level = kContentQualityUnknown; + break; + } + } + } + err = hwc_display->SetDetailEnhancerConfig(de_data); + if (err) { + DLOGW("SetDetailEnhancerConfig failed. err = %d", err); + } + de_tuning_cfg_data->cfg_pending = false; + } + return err; +} + +void HWCColorManager::SetColorModeDetailEnhancer(HWCDisplay *hwc_display) { + SCOPE_LOCK(locker_); + int err = -1; + PPPendingParams pending_action; + PPDisplayAPIPayload req_payload; + + pending_action.action = kGetDetailedEnhancerData; + pending_action.params = NULL; + + if (hwc_display) { + err = hwc_display->ColorSVCRequestRoute(req_payload, NULL, &pending_action); + if (!err && pending_action.action == kConfigureDetailedEnhancer) { + err = SetHWDetailedEnhancerConfig(pending_action.params, hwc_display); + } + } + return; +} + +int HWCColorManager::SetDetailedEnhancer(void *params, HWCDisplay *hwc_display) { + SCOPE_LOCK(locker_); + int err = -1; + err = SetHWDetailedEnhancerConfig(params, hwc_display); + return err; +} + +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()); + } + + return mode_mgr; +} + +HWCQDCMModeManager::~HWCQDCMModeManager() { + if (socket_fd_ >= 0) + ::close(socket_fd_); +} + +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_); + + // 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 diff --git a/msm8909/sdm/libs/hwc2/hwc_color_manager.h b/msm8909/sdm/libs/hwc2/hwc_color_manager.h new file mode 100644 index 00000000..f88a5bbb --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_color_manager.h @@ -0,0 +1,143 @@ +/* Copyright (c) 2015-2017, The Linux Foundataion. 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_COLOR_MANAGER_H__ +#define __HWC_COLOR_MANAGER_H__ + +#include <stdlib.h> +#include <binder/Parcel.h> +#include <binder/BinderService.h> +#include <core/sdm_types.h> +#include <utils/locker.h> + +namespace sdm { + +// This macro defines name for display APIs interface wrapper library. +// This macro shall be used to load library using dlopen(). +#define DISPLAY_API_INTERFACE_LIBRARY_NAME "libsdm-disp-vndapis.so" + +// This macro defines variable name of display color APIs function tables +// This macro shall be used to specify name of the variable in dlsym(). +#define DISPLAY_API_FUNC_TABLES "display_color_apis_ftables" +#define QDCM_DIAG_CLIENT_LIBRARY_NAME "libsdm-diag.so" +#define INIT_QDCM_DIAG_CLIENT_NAME "QDCMDiagInit" +#define DEINIT_QDCM_DIAG_CLIENT_NAME "QDCMDiagDeInit" + +typedef int (*QDCMDiagInit)(void *ftables); + +typedef int (*QDCMDiagDeInit)(void); + +// Class to encapsulte all details of managing QDCM operating mode. +class HWCQDCMModeManager { + public: + static const uint32_t kSocketCMDMaxLength = 4096; + static const uint32_t kFullWakeLock = 0x0000001a; + static const uint32_t kAcquireCauseWakeup = 0x10000000; + static const uint32_t kONAfterRelease = 0x20000000; + enum ActiveFeatureID { + kCABLFeature, + kADFeature, + kSVIFeature, + kMaxNumActiveFeature, + }; + + struct ActiveFeatureCMD { + const char *cmd_on = NULL; + const char *cmd_off = NULL; + const char *cmd_query_status = NULL; + const char *running = NULL; + ActiveFeatureCMD(const char *arg1, const char *arg2, const char *arg3, const char *arg4) + : cmd_on(arg1), cmd_off(arg2), cmd_query_status(arg3), running(arg4) {} + }; + + static const ActiveFeatureCMD kActiveFeatureCMD[kMaxNumActiveFeature]; + + public: + static HWCQDCMModeManager *CreateQDCMModeMgr(); + ~HWCQDCMModeManager(); + int EnableQDCMMode(bool enable, HWCDisplay *hwc_display); + + protected: + bool SendSocketCmd(); + int AcquireAndroidWakeLock(bool enable); + int EnableActiveFeatures(bool enable); + int EnableActiveFeatures(bool enable, const ActiveFeatureCMD &cmds, bool *was_running); + + private: + bool cabl_was_running_ = false; + int socket_fd_ = -1; + android::sp<android::IBinder> wakelock_token_ = NULL; + uint32_t entry_timeout_ = 0; + static const char *const kSocketName; + static const char *const kTagName; + static const char *const kPackageName; +}; + +// Class to encapsulte all HWC/OS specific behaviours for ColorManager. +class HWCColorManager { + public: + static const int kNumSolidFillLayers = 2; + static HWCColorManager *CreateColorManager(HWCBufferAllocator *buffer_allocator); + static int CreatePayloadFromParcel(const android::Parcel &in, uint32_t *disp_id, + PPDisplayAPIPayload *sink); + static void MarshallStructIntoParcel(const PPDisplayAPIPayload &data, + android::Parcel *out_parcel); + + explicit HWCColorManager(HWCBufferAllocator *buffer_allocator); + ~HWCColorManager(); + void DestroyColorManager(); + int EnableQDCMMode(bool enable, HWCDisplay *hwc_display); + int SetSolidFill(const void *params, bool enable, HWCDisplay *hwc_display); + int SetFrameCapture(void *params, bool enable, HWCDisplay *hwc_display); + int SetDetailedEnhancer(void *params, HWCDisplay *hwc_display); + void SetColorModeDetailEnhancer(HWCDisplay *hwc_display); + int SetHWDetailedEnhancerConfig(void *params, HWCDisplay *hwc_display); + + protected: + int CreateSolidFillLayers(HWCDisplay *hwc_display); + void DestroySolidFillLayers(); + static uint32_t Get8BitsARGBColorValue(const PPColorFillParams ¶ms); + + private: + DynLib color_apis_lib_; + DynLib diag_client_lib_; + void *color_apis_ = NULL; + QDCMDiagInit qdcm_diag_init_ = NULL; + QDCMDiagDeInit qdcm_diag_deinit_ = NULL; + HWCQDCMModeManager *qdcm_mode_mgr_ = NULL; + + PPColorFillParams solid_fill_params_; + HWCBufferAllocator *buffer_allocator_ = NULL; + BufferInfo buffer_info; + Locker locker_; +}; + +} // namespace sdm + +#endif // __HWC_COLOR_MANAGER_H__ diff --git a/msm8909/sdm/libs/hwc2/hwc_display.cpp b/msm8909/sdm/libs/hwc2/hwc_display.cpp new file mode 100644 index 00000000..3a159ba9 --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_display.cpp @@ -0,0 +1,2049 @@ +/* + * Copyright (c) 2014-2018, 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 <cutils/properties.h> +#include <errno.h> +#include <math.h> +#include <sync/sync.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <utils/constants.h> +#include <utils/debug.h> +#include <utils/formats.h> +#include <utils/rect.h> +#include <qd_utils.h> + +#include <algorithm> +#include <iomanip> +#include <map> +#include <sstream> +#include <string> +#include <utility> +#include <vector> + +#include "hwc_display.h" +#include "hwc_debugger.h" +#include "blit_engine_c2d.h" +#include "hwc_tonemapper.h" + +#ifndef USE_GRALLOC1 +#include <gr.h> +#endif + +#ifdef QTI_BSP +#include <hardware/display_defs.h> +#endif + +#define __CLASS__ "HWCDisplay" + +namespace sdm { + +std::bitset<kDisplayMax> HWCDisplay::validated_ = 0; + +// This weight function is needed because the color primaries are not sorted by gamut size +static ColorPrimaries WidestPrimaries(ColorPrimaries p1, ColorPrimaries p2) { + int weight = 10; + int lp1 = p1, lp2 = p2; + // TODO(user) add weight to other wide gamut primaries + if (lp1 == ColorPrimaries_BT2020) { + lp1 *= weight; + } + if (lp1 == ColorPrimaries_BT2020) { + lp2 *= weight; + } + if (lp1 >= lp2) { + return p1; + } else { + return p2; + } +} + +HWCColorMode::HWCColorMode(DisplayInterface *display_intf) : display_intf_(display_intf) {} + +HWC2::Error HWCColorMode::Init() { + PopulateColorModes(); + return ApplyDefaultColorMode(); +} + +HWC2::Error HWCColorMode::DeInit() { + color_mode_transform_map_.clear(); + return HWC2::Error::None; +} + +uint32_t HWCColorMode::GetColorModeCount() { + uint32_t count = UINT32(color_mode_transform_map_.size()); + DLOGI("Supported color mode count = %d", count); +#ifdef EXCLUDE_DISPLAY_PP + return count; +#else + return std::max(1U, count); +#endif +} + +HWC2::Error HWCColorMode::GetColorModes(uint32_t *out_num_modes, + android_color_mode_t *out_modes) { + auto it = color_mode_transform_map_.begin(); + for (auto i = 0; it != color_mode_transform_map_.end(); it++, i++) { + out_modes[i] = it->first; + DLOGI("Supports color mode[%d] = %d", i, it->first); + } + *out_num_modes = UINT32(color_mode_transform_map_.size()); + return HWC2::Error::None; +} + +HWC2::Error HWCColorMode::SetColorMode(android_color_mode_t mode) { + // first mode in 2D matrix is the mode (identity) + if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_DISPLAY_P3) { + DLOGE("Could not find mode: %d", mode); + return HWC2::Error::BadParameter; + } + if (color_mode_transform_map_.find(mode) == color_mode_transform_map_.end()) { + return HWC2::Error::Unsupported; + } + + auto status = HandleColorModeTransform(mode, current_color_transform_, color_matrix_); + if (status != HWC2::Error::None) { + DLOGE("failed for mode = %d", mode); + } + + DLOGV_IF(kTagClient, "Color mode %d successfully set.", mode); + return status; +} + +HWC2::Error HWCColorMode::RestoreColorTransform() { + DisplayError error = display_intf_->SetColorTransform(kColorTransformMatrixCount, color_matrix_); + if (error != kErrorNone) { + DLOGI_IF(kTagClient,"Failed to set Color Transform"); + return HWC2::Error::BadParameter; + } + + return HWC2::Error::None; +} + +HWC2::Error HWCColorMode::SetColorTransform(const float *matrix, android_color_transform_t hint) { + DTRACE_SCOPED(); + double color_matrix[kColorTransformMatrixCount] = {0}; + CopyColorTransformMatrix(matrix, color_matrix); + + auto status = HandleColorModeTransform(current_color_mode_, hint, color_matrix); + if (status != HWC2::Error::None) { + DLOGE("failed for hint = %d", hint); + } + + return status; +} + +HWC2::Error HWCColorMode::HandleColorModeTransform(android_color_mode_t mode, + android_color_transform_t hint, + const double *matrix) { + android_color_transform_t transform_hint = hint; + std::string color_mode_transform; + bool use_matrix = false; + if (hint != HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX) { + // if the mode + transfrom request from HWC matches one mode in SDM, set that + if (color_mode_transform.empty()) { + transform_hint = HAL_COLOR_TRANSFORM_IDENTITY; + use_matrix = true; + } else { + color_mode_transform = color_mode_transform_map_[mode][hint]; + } + } else { + use_matrix = true; + transform_hint = HAL_COLOR_TRANSFORM_IDENTITY; + } + + // if the mode count is 1, then only native mode is supported, so just apply matrix w/o + // setting mode + if (color_mode_transform_map_.size() > 1U && current_color_mode_ != mode) { + color_mode_transform = color_mode_transform_map_[mode][transform_hint]; + DisplayError error = display_intf_->SetColorMode(color_mode_transform); + if (error != kErrorNone) { + DLOGE("Failed to set color_mode = %d transform_hint = %d", mode, hint); + // failure to force client composition + return HWC2::Error::Unsupported; + } + DLOGI("Setting Color Mode = %d Transform Hint = %d Success", mode, hint); + } + + if (use_matrix) { + DisplayError error = display_intf_->SetColorTransform(kColorTransformMatrixCount, matrix); + if (error != kErrorNone) { + DLOGE("Failed to set Color Transform Matrix"); + // failure to force client composition + return HWC2::Error::Unsupported; + } + } + + current_color_mode_ = mode; + current_color_transform_ = hint; + CopyColorTransformMatrix(matrix, color_matrix_); + + return HWC2::Error::None; +} + +void HWCColorMode::PopulateColorModes() { + uint32_t color_mode_count = 0; + // SDM returns modes which is string combination of mode + transform. + DisplayError error = display_intf_->GetColorModeCount(&color_mode_count); + if (error != kErrorNone || (color_mode_count == 0)) { +#ifndef EXCLUDE_DISPLAY_PP + DLOGW("GetColorModeCount failed, use native color mode"); + PopulateTransform(HAL_COLOR_MODE_NATIVE, "native", "identity"); +#endif + return; + } + + DLOGV_IF(kTagClient, "Color Modes supported count = %d", color_mode_count); + + const std::string color_transform = "identity"; + std::vector<std::string> color_modes(color_mode_count); + error = display_intf_->GetColorModes(&color_mode_count, &color_modes); + for (uint32_t i = 0; i < color_mode_count; i++) { + std::string &mode_string = color_modes.at(i); + DLOGV_IF(kTagClient, "Color Mode[%d] = %s", i, mode_string.c_str()); + AttrVal attr; + error = display_intf_->GetColorModeAttr(mode_string, &attr); + std::string color_gamut, dynamic_range, pic_quality; + if (!attr.empty()) { + for (auto &it : attr) { + if (it.first.find(kColorGamutAttribute) != std::string::npos) { + color_gamut = it.second; + } else if (it.first.find(kDynamicRangeAttribute) != std::string::npos) { + dynamic_range = it.second; + } else if (it.first.find(kPictureQualityAttribute) != std::string::npos) { + pic_quality = it.second; + } + } + + DLOGV_IF(kTagClient, "color_gamut : %s, dynamic_range : %s, pic_quality : %s", + color_gamut.c_str(), dynamic_range.c_str(), pic_quality.c_str()); + + if (dynamic_range == kHdr) { + continue; + } + if ((color_gamut == kNative) && + (pic_quality.empty() || pic_quality == kStandard)) { + PopulateTransform(HAL_COLOR_MODE_NATIVE, mode_string, color_transform); + } else if ((color_gamut == kSrgb) && + (pic_quality.empty() || pic_quality == kStandard)) { + PopulateTransform(HAL_COLOR_MODE_SRGB, mode_string, color_transform); + } else if ((color_gamut == kDcip3) && + (pic_quality.empty() || pic_quality == kStandard)) { + PopulateTransform(HAL_COLOR_MODE_DISPLAY_P3, mode_string, color_transform); + } else if ((color_gamut == kDisplayP3) && + (pic_quality.empty() || pic_quality == kStandard)) { + PopulateTransform(HAL_COLOR_MODE_DISPLAY_P3, mode_string, color_transform); + } + } + + // Look at the mode name, if no color gamut is found + if (color_gamut.empty()) { + if (mode_string.find("hal_native") != std::string::npos) { + PopulateTransform(HAL_COLOR_MODE_NATIVE, mode_string, mode_string); + } else if (mode_string.find("hal_srgb") != std::string::npos) { + PopulateTransform(HAL_COLOR_MODE_SRGB, mode_string, mode_string); + } else if (mode_string.find("hal_adobe") != std::string::npos) { + PopulateTransform(HAL_COLOR_MODE_ADOBE_RGB, mode_string, mode_string); + } else if (mode_string.find("hal_dci_p3") != std::string::npos) { + PopulateTransform(HAL_COLOR_MODE_DCI_P3, mode_string, mode_string); + } else if (mode_string.find("hal_display_p3") != std::string::npos) { + PopulateTransform(HAL_COLOR_MODE_DISPLAY_P3, mode_string, mode_string); + } + } + } +} + +void HWCColorMode::PopulateTransform(const android_color_mode_t &mode, + const std::string &color_mode, + const std::string &color_transform) { + // TODO(user): Check the substring from QDCM + if (color_transform.find("identity") != std::string::npos) { + color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_IDENTITY] = color_mode; + } else if (color_transform.find("arbitrary") != std::string::npos) { + // no color mode for arbitrary + } else if (color_transform.find("inverse") != std::string::npos) { + color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_VALUE_INVERSE] = color_mode; + } else if (color_transform.find("grayscale") != std::string::npos) { + color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_GRAYSCALE] = color_mode; + } else if (color_transform.find("correct_protonopia") != std::string::npos) { + color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA] = color_mode; + } else if (color_transform.find("correct_deuteranopia") != std::string::npos) { + color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA] = color_mode; + } else if (color_transform.find("correct_tritanopia") != std::string::npos) { + color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA] = color_mode; + } else { + color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_IDENTITY] = color_mode; + } +} + +HWC2::Error HWCColorMode::ApplyDefaultColorMode() { + android_color_mode_t color_mode = HAL_COLOR_MODE_NATIVE; + if (color_mode_transform_map_.size() == 1U) { + color_mode = color_mode_transform_map_.begin()->first; + } else if (color_mode_transform_map_.size() > 1U) { + std::string default_color_mode; + bool found = false; + DisplayError error = display_intf_->GetDefaultColorMode(&default_color_mode); + if (error == kErrorNone) { + // get the default mode corresponding android_color_mode_t + for (auto &it_mode : color_mode_transform_map_) { + for (auto &it : it_mode.second) { + if (it.second == default_color_mode) { + found = true; + break; + } + } + if (found) { + color_mode = it_mode.first; + break; + } + } + } + + // return the first andrid_color_mode_t when we encouter if not found + if (!found) { + color_mode = color_mode_transform_map_.begin()->first; + } + } + return SetColorMode(color_mode); +} + +void HWCColorMode::Dump(std::ostringstream* os) { + *os << "color modes supported: "; + for (auto it : color_mode_transform_map_) { + *os << it.first <<" "; + } + *os << "current mode: " << current_color_mode_ << std::endl; + *os << "current transform: "; + for (uint32_t i = 0; i < kColorTransformMatrixCount; i++) { + if (i % 4 == 0) { + *os << std::endl; + } + *os << std::fixed << std::setprecision(2) << std::setw(6) << std::setfill(' ') + << color_matrix_[i] << " "; + } + *os << std::endl; +} + +HWCDisplay::HWCDisplay(CoreInterface *core_intf, HWCCallbacks *callbacks, DisplayType type, + hwc2_display_t id, bool needs_blit, qService::QService *qservice, + DisplayClass display_class, BufferAllocator *buffer_allocator) + : core_intf_(core_intf), + callbacks_(callbacks), + type_(type), + id_(id), + needs_blit_(needs_blit), + qservice_(qservice), + display_class_(display_class) { + buffer_allocator_ = static_cast<HWCBufferAllocator *>(buffer_allocator); +} + +int HWCDisplay::Init() { + DisplayError error = core_intf_->CreateDisplay(type_, this, &display_intf_); + if (error != kErrorNone) { + DLOGE("Display create failed. Error = %d display_type %d event_handler %p disp_intf %p", error, + type_, this, &display_intf_); + return -EINVAL; + } + + validated_.reset(); + HWCDebugHandler::Get()->GetProperty(DISABLE_HDR, &disable_hdr_handling_); + if (disable_hdr_handling_) { + DLOGI("HDR Handling disabled"); + } + + int property_swap_interval = 1; + HWCDebugHandler::Get()->GetProperty("debug.egl.swapinterval", &property_swap_interval); + if (property_swap_interval == 0) { + swap_interval_zero_ = true; + } + + client_target_ = new HWCLayer(id_, buffer_allocator_); + + int blit_enabled = 0; + HWCDebugHandler::Get()->GetProperty(DISABLE_BLIT_COMPOSITION_PROP, &blit_enabled); + if (needs_blit_ && blit_enabled) { + // TODO(user): Add blit engine when needed + } + + error = display_intf_->GetNumVariableInfoConfigs(&num_configs_); + if (error != kErrorNone) { + DLOGE("Getting config count failed. Error = %d", error); + return -EINVAL; + } + + tone_mapper_ = new HWCToneMapper(buffer_allocator_); + + display_intf_->GetRefreshRateRange(&min_refresh_rate_, &max_refresh_rate_); + current_refresh_rate_ = max_refresh_rate_; + + GetUnderScanConfig(); + DLOGI("Display created with id: %d", id_); + + return 0; +} + +int HWCDisplay::Deinit() { + DisplayError error = core_intf_->DestroyDisplay(display_intf_); + if (error != kErrorNone) { + DLOGE("Display destroy failed. Error = %d", error); + return -EINVAL; + } + + delete client_target_; + for (auto hwc_layer : layer_set_) { + delete hwc_layer; + } + + if (color_mode_) { + color_mode_->DeInit(); + delete color_mode_; + } + + delete tone_mapper_; + tone_mapper_ = nullptr; + + return 0; +} + +// LayerStack operations +HWC2::Error HWCDisplay::CreateLayer(hwc2_layer_t *out_layer_id) { + HWCLayer *layer = *layer_set_.emplace(new HWCLayer(id_, buffer_allocator_)); + layer_map_.emplace(std::make_pair(layer->GetId(), layer)); + *out_layer_id = layer->GetId(); + geometry_changes_ |= GeometryChanges::kAdded; + validated_.reset(); + return HWC2::Error::None; +} + +HWCLayer *HWCDisplay::GetHWCLayer(hwc2_layer_t layer_id) { + const auto map_layer = layer_map_.find(layer_id); + if (map_layer == layer_map_.end()) { + DLOGE("[%" PRIu64 "] GetLayer(%" PRIu64 ") failed: no such layer", id_, layer_id); + return nullptr; + } else { + return map_layer->second; + } +} + +HWC2::Error HWCDisplay::DestroyLayer(hwc2_layer_t layer_id) { + const auto map_layer = layer_map_.find(layer_id); + if (map_layer == layer_map_.end()) { + DLOGE("[%" PRIu64 "] destroyLayer(%" PRIu64 ") failed: no such layer", id_, layer_id); + return HWC2::Error::BadLayer; + } + const auto layer = map_layer->second; + layer_map_.erase(map_layer); + const auto z_range = layer_set_.equal_range(layer); + for (auto current = z_range.first; current != z_range.second; ++current) { + if (*current == layer) { + current = layer_set_.erase(current); + delete layer; + break; + } + } + + geometry_changes_ |= GeometryChanges::kRemoved; + validated_.reset(); + return HWC2::Error::None; +} + + +void HWCDisplay::BuildLayerStack() { + layer_stack_ = LayerStack(); + display_rect_ = LayerRect(); + metadata_refresh_rate_ = 0; + auto working_primaries = ColorPrimaries_BT709_5; + bool secure_display_active = false; + layer_stack_.flags.animating = animating_; + + // Add one layer for fb target + // TODO(user): Add blit target layers + for (auto hwc_layer : layer_set_) { + Layer *layer = hwc_layer->GetSDMLayer(); + layer->flags = {}; // Reset earlier flags + if (hwc_layer->GetClientRequestedCompositionType() == HWC2::Composition::Client) { + layer->flags.skip = true; + } else if (hwc_layer->GetClientRequestedCompositionType() == HWC2::Composition::SolidColor) { + layer->flags.solid_fill = true; + } + + if (!hwc_layer->ValidateAndSetCSC()) { +#ifdef FEATURE_WIDE_COLOR + layer->flags.skip = true; +#endif + } + + working_primaries = WidestPrimaries(working_primaries, + layer->input_buffer.color_metadata.colorPrimaries); + + // set default composition as GPU for SDM + layer->composition = kCompositionGPU; + + if (swap_interval_zero_) { + if (layer->input_buffer.acquire_fence_fd >= 0) { + close(layer->input_buffer.acquire_fence_fd); + layer->input_buffer.acquire_fence_fd = -1; + } + } + + const private_handle_t *handle = + reinterpret_cast<const private_handle_t *>(layer->input_buffer.buffer_id); + if (handle) { +#ifdef USE_GRALLOC1 + if (handle->buffer_type == BUFFER_TYPE_VIDEO) { +#else + if (handle->bufferType == BUFFER_TYPE_VIDEO) { +#endif + layer_stack_.flags.video_present = true; + } + // TZ Protected Buffer - L1 + if (handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) { + layer_stack_.flags.secure_present = true; + } + // Gralloc Usage Protected Buffer - L3 - which needs to be treated as Secure & avoid fallback + if (handle->flags & private_handle_t::PRIV_FLAGS_PROTECTED_BUFFER) { + layer_stack_.flags.secure_present = true; + } + } + + if (layer->flags.skip) { + layer_stack_.flags.skip_present = true; + } + + if (layer->input_buffer.flags.secure_display) { + secure_display_active = true; + } + + if (hwc_layer->GetClientRequestedCompositionType() == HWC2::Composition::Cursor) { + // Currently we support only one HWCursor & only at top most z-order + if ((*layer_set_.rbegin())->GetId() == hwc_layer->GetId()) { + layer->flags.cursor = true; + layer_stack_.flags.cursor_present = true; + } + } + + bool hdr_layer = layer->input_buffer.color_metadata.colorPrimaries == ColorPrimaries_BT2020 && + (layer->input_buffer.color_metadata.transfer == Transfer_SMPTE_ST2084 || + layer->input_buffer.color_metadata.transfer == Transfer_HLG); + if (hdr_layer && !disable_hdr_handling_) { + // dont honor HDR when its handling is disabled + layer->input_buffer.flags.hdr = true; + layer_stack_.flags.hdr_present = true; + } + + // TODO(user): Move to a getter if this is needed at other places + hwc_rect_t scaled_display_frame = {INT(layer->dst_rect.left), INT(layer->dst_rect.top), + INT(layer->dst_rect.right), INT(layer->dst_rect.bottom)}; + if (hwc_layer->GetGeometryChanges() & kDisplayFrame) { + ApplyScanAdjustment(&scaled_display_frame); + } + hwc_layer->SetLayerDisplayFrame(scaled_display_frame); + // SDM requires these details even for solid fill + if (layer->flags.solid_fill) { + LayerBuffer *layer_buffer = &layer->input_buffer; + layer_buffer->width = UINT32(layer->dst_rect.right - layer->dst_rect.left); + layer_buffer->height = UINT32(layer->dst_rect.bottom - layer->dst_rect.top); + layer_buffer->unaligned_width = layer_buffer->width; + layer_buffer->unaligned_height = layer_buffer->height; + layer_buffer->acquire_fence_fd = -1; + layer_buffer->release_fence_fd = -1; + layer->src_rect.left = 0; + layer->src_rect.top = 0; + layer->src_rect.right = layer_buffer->width; + layer->src_rect.bottom = layer_buffer->height; + } + + if (layer->frame_rate > metadata_refresh_rate_) { + metadata_refresh_rate_ = SanitizeRefreshRate(layer->frame_rate); + } else { + layer->frame_rate = current_refresh_rate_; + } + display_rect_ = Union(display_rect_, layer->dst_rect); + geometry_changes_ |= hwc_layer->GetGeometryChanges(); + + layer->flags.updating = true; + if (layer_set_.size() <= kMaxLayerCount) { + layer->flags.updating = IsLayerUpdating(layer); + } + + layer_stack_.layers.push_back(layer); + } + + +#ifdef FEATURE_WIDE_COLOR + for (auto hwc_layer : layer_set_) { + auto layer = hwc_layer->GetSDMLayer(); + if (layer->input_buffer.color_metadata.colorPrimaries != working_primaries && + !hwc_layer->SupportLocalConversion(working_primaries)) { + layer->flags.skip = true; + } + if (layer->flags.skip) { + layer_stack_.flags.skip_present = true; + } + } +#endif + + // TODO(user): Set correctly when SDM supports geometry_changes as bitmask + layer_stack_.flags.geometry_changed = UINT32(geometry_changes_ > 0); + // Append client target to the layer stack + + Layer *sdm_client_target = client_target_->GetSDMLayer(); + layer_stack_.layers.push_back(sdm_client_target); + // fall back frame composition to GPU when client target is 10bit + // TODO(user): clarify the behaviour from Client(SF) and SDM Extn - + // when handling 10bit FBT, as it would affect blending + if (Is10BitFormat(sdm_client_target->input_buffer.format)) { + // Must fall back to client composition + MarkLayersForClientComposition(); + } + + // set secure display + SetSecureDisplay(secure_display_active); +} + +void HWCDisplay::BuildSolidFillStack() { + layer_stack_ = LayerStack(); + display_rect_ = LayerRect(); + + layer_stack_.layers.push_back(solid_fill_layer_); + layer_stack_.flags.geometry_changed = 1U; + // Append client target to the layer stack + layer_stack_.layers.push_back(client_target_->GetSDMLayer()); +} + +HWC2::Error HWCDisplay::SetLayerZOrder(hwc2_layer_t layer_id, uint32_t z) { + const auto map_layer = layer_map_.find(layer_id); + if (map_layer == layer_map_.end()) { + DLOGE("[%" PRIu64 "] updateLayerZ failed to find layer", id_); + return HWC2::Error::BadLayer; + } + + const auto layer = map_layer->second; + const auto z_range = layer_set_.equal_range(layer); + bool layer_on_display = false; + for (auto current = z_range.first; current != z_range.second; ++current) { + if (*current == layer) { + if ((*current)->GetZ() == z) { + // Don't change anything if the Z hasn't changed + return HWC2::Error::None; + } + current = layer_set_.erase(current); + layer_on_display = true; + break; + } + } + + if (!layer_on_display) { + DLOGE("[%" PRIu64 "] updateLayerZ failed to find layer on display", id_); + return HWC2::Error::BadLayer; + } + + layer->SetLayerZOrder(z); + layer_set_.emplace(layer); + return HWC2::Error::None; +} + +HWC2::Error HWCDisplay::SetVsyncEnabled(HWC2::Vsync enabled) { + DLOGV("Display ID: %d enabled: %s", id_, to_string(enabled).c_str()); + DisplayError error = kErrorNone; + + if (shutdown_pending_ || !callbacks_->VsyncCallbackRegistered()) { + return HWC2::Error::None; + } + + bool state; + if (enabled == HWC2::Vsync::Enable) + state = true; + else if (enabled == HWC2::Vsync::Disable) + state = false; + else + return HWC2::Error::BadParameter; + + error = display_intf_->SetVSyncState(state); + + if (error != kErrorNone) { + if (error == kErrorShutDown) { + shutdown_pending_ = true; + return HWC2::Error::None; + } + DLOGE("Failed. enabled = %s, error = %d", to_string(enabled).c_str(), error); + return HWC2::Error::BadDisplay; + } + + return HWC2::Error::None; +} + +HWC2::Error HWCDisplay::SetPowerMode(HWC2::PowerMode mode) { + DLOGV("display = %d, mode = %s", id_, to_string(mode).c_str()); + DisplayState state = kStateOff; + bool flush_on_error = flush_on_error_; + + if (shutdown_pending_) { + return HWC2::Error::None; + } + + switch (mode) { + case HWC2::PowerMode::Off: + // During power off, all of the buffers are released. + // Do not flush until a buffer is successfully submitted again. + flush_on_error = false; + state = kStateOff; + if (tone_mapper_) { + tone_mapper_->Terminate(); + } + break; + case HWC2::PowerMode::On: + state = kStateOn; + last_power_mode_ = HWC2::PowerMode::On; + break; + case HWC2::PowerMode::Doze: + state = kStateDoze; + last_power_mode_ = HWC2::PowerMode::Doze; + break; + case HWC2::PowerMode::DozeSuspend: + state = kStateDozeSuspend; + last_power_mode_ = HWC2::PowerMode::DozeSuspend; + break; + default: + return HWC2::Error::BadParameter; + } + + DisplayError error = display_intf_->SetDisplayState(state); + validated_.reset(); + + if (error == kErrorNone) { + flush_on_error_ = flush_on_error; + } else { + if (error == kErrorShutDown) { + shutdown_pending_ = true; + return HWC2::Error::None; + } + DLOGE("Set state failed. Error = %d", error); + return HWC2::Error::BadParameter; + } + + return HWC2::Error::None; +} + +HWC2::Error HWCDisplay::GetClientTargetSupport(uint32_t width, uint32_t height, int32_t format, + int32_t dataspace) { + ColorMetaData color_metadata = {}; + if (dataspace != HAL_DATASPACE_UNKNOWN) { + GetColorPrimary(dataspace, &(color_metadata.colorPrimaries)); + GetTransfer(dataspace, &(color_metadata.transfer)); + GetRange(dataspace, &(color_metadata.range)); + } + + LayerBufferFormat sdm_format = GetSDMFormat(format, 0); + if (display_intf_->GetClientTargetSupport(width, height, sdm_format, + color_metadata) != kErrorNone) { + return HWC2::Error::Unsupported; + } + + return HWC2::Error::None; +} + +HWC2::Error HWCDisplay::GetColorModes(uint32_t *out_num_modes, android_color_mode_t *out_modes) { + if (out_modes) { + out_modes[0] = HAL_COLOR_MODE_NATIVE; + } + *out_num_modes = 1; + + return HWC2::Error::None; +} + +HWC2::Error HWCDisplay::GetDisplayConfigs(uint32_t *out_num_configs, hwc2_config_t *out_configs) { + if (out_configs == nullptr) { + *out_num_configs = num_configs_; + return HWC2::Error::None; + } + + *out_num_configs = num_configs_; + + for (uint32_t i = 0; i < num_configs_; i++) { + out_configs[i] = i; + } + + return HWC2::Error::None; +} + +HWC2::Error HWCDisplay::GetDisplayAttribute(hwc2_config_t config, HWC2::Attribute attribute, + int32_t *out_value) { + DisplayConfigVariableInfo variable_config; + // Get display attributes from config index only if resolution switch is supported. + // Otherwise always send mixer attributes. This is to support destination scaler. + if (num_configs_ > 1) { + if (GetDisplayAttributesForConfig(INT(config), &variable_config) != kErrorNone) { + DLOGE("Get variable config failed"); + return HWC2::Error::BadDisplay; + } + } else { + if (display_intf_->GetFrameBufferConfig(&variable_config) != kErrorNone) { + DLOGV("Get variable config failed"); + return HWC2::Error::BadDisplay; + } + } + + switch (attribute) { + case HWC2::Attribute::VsyncPeriod: + *out_value = INT32(variable_config.vsync_period_ns); + break; + case HWC2::Attribute::Width: + *out_value = INT32(variable_config.x_pixels); + break; + case HWC2::Attribute::Height: + *out_value = INT32(variable_config.y_pixels); + break; + case HWC2::Attribute::DpiX: + *out_value = INT32(variable_config.x_dpi * 1000.0f); + break; + case HWC2::Attribute::DpiY: + *out_value = INT32(variable_config.y_dpi * 1000.0f); + break; + default: + DLOGW("Spurious attribute type = %s", to_string(attribute).c_str()); + *out_value = -1; + return HWC2::Error::BadConfig; + } + + return HWC2::Error::None; +} + +HWC2::Error HWCDisplay::GetDisplayName(uint32_t *out_size, char *out_name) { + // TODO(user): Get panel name and EDID name and populate it here + if (out_name == nullptr) { + *out_size = 32; + } else { + std::string name; + switch (id_) { + case HWC_DISPLAY_PRIMARY: + name = "Primary Display"; + break; + case HWC_DISPLAY_EXTERNAL: + name = "External Display"; + break; + case HWC_DISPLAY_VIRTUAL: + name = "Virtual Display"; + break; + default: + name = "Unknown"; + break; + } + std::strncpy(out_name, name.c_str(), name.size()); + *out_size = UINT32(name.size()); + } + return HWC2::Error::None; +} + +HWC2::Error HWCDisplay::GetDisplayType(int32_t *out_type) { + if (out_type != nullptr) { + if (id_ == HWC_DISPLAY_VIRTUAL) { + *out_type = HWC2_DISPLAY_TYPE_VIRTUAL; + } else { + *out_type = HWC2_DISPLAY_TYPE_PHYSICAL; + } + return HWC2::Error::None; + } else { + return HWC2::Error::BadParameter; + } +} + +HWC2::Error HWCDisplay::GetActiveConfig(hwc2_config_t *out_config) { + if (out_config == nullptr) { + return HWC2::Error::BadDisplay; + } + + uint32_t active_index = 0; + if (GetActiveDisplayConfig(&active_index) != kErrorNone) { + return HWC2::Error::BadConfig; + } + + *out_config = active_index; + + return HWC2::Error::None; +} + +HWC2::Error HWCDisplay::SetClientTarget(buffer_handle_t target, int32_t acquire_fence, + int32_t dataspace, hwc_region_t damage) { + // TODO(user): SurfaceFlinger gives us a null pointer here when doing full SDE composition + // The error is problematic for layer caching as it would overwrite our cached client target. + // Reported bug 28569722 to resolve this. + // For now, continue to use the last valid buffer reported to us for layer caching. + if (target == nullptr) { + return HWC2::Error::None; + } + + if (acquire_fence == 0) { + DLOGE("acquire_fence is zero"); + return HWC2::Error::BadParameter; + } + + client_target_->SetLayerBuffer(target, acquire_fence); + client_target_->SetLayerSurfaceDamage(damage); + if (client_target_->GetLayerDataspace() != dataspace) { + client_target_->SetLayerDataspace(dataspace); + Layer *sdm_layer = client_target_->GetSDMLayer(); + // Data space would be validated at GetClientTargetSupport, so just use here. + sdm::GetSDMColorSpace(dataspace, &sdm_layer->input_buffer.color_metadata); + } + + return HWC2::Error::None; +} + +HWC2::Error HWCDisplay::SetActiveConfig(hwc2_config_t config) { + if (SetActiveDisplayConfig(config) != kErrorNone) { + return HWC2::Error::BadConfig; + } + + validated_.reset(); + return HWC2::Error::None; +} + +DisplayError HWCDisplay::SetMixerResolution(uint32_t width, uint32_t height) { + return kErrorNotSupported; +} + +void HWCDisplay::SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type) { + dump_frame_count_ = count; + dump_frame_index_ = 0; + dump_input_layers_ = ((bit_mask_layer_type & (1 << INPUT_LAYER_DUMP)) != 0); + + if (tone_mapper_) { + tone_mapper_->SetFrameDumpConfig(count); + } + + DLOGI("num_frame_dump %d, input_layer_dump_enable %d", dump_frame_count_, dump_input_layers_); + validated_.reset(); +} + +HWC2::PowerMode HWCDisplay::GetLastPowerMode() { + return last_power_mode_; +} + +DisplayError HWCDisplay::VSync(const DisplayEventVSync &vsync) { + callbacks_->Vsync(id_, vsync.timestamp); + return kErrorNone; +} + +DisplayError HWCDisplay::Refresh() { + return kErrorNotSupported; +} + +DisplayError HWCDisplay::CECMessage(char *message) { + if (qservice_) { + qservice_->onCECMessageReceived(message, 0); + } else { + DLOGW("Qservice instance not available."); + } + + return kErrorNone; +} + +DisplayError HWCDisplay::HandleEvent(DisplayEvent event) { + switch (event) { + case kIdleTimeout: + break; + case kThermalEvent: + validated_.reset(); + break; + default: + DLOGW("Unknown event: %d", event); + break; + } + + return kErrorNone; +} + +HWC2::Error HWCDisplay::PrepareLayerStack(uint32_t *out_num_types, uint32_t *out_num_requests) { + layer_changes_.clear(); + layer_requests_.clear(); + if (shutdown_pending_) { + return HWC2::Error::BadDisplay; + } + + if (!skip_prepare_) { + DisplayError error = display_intf_->Prepare(&layer_stack_); + if (error != kErrorNone) { + if (error == kErrorShutDown) { + shutdown_pending_ = true; + } else if (error != kErrorPermission) { + DLOGE("Prepare failed. Error = %d", error); + // To prevent surfaceflinger infinite wait, flush the previous frame during Commit() + // so that previous buffer and fences are released, and override the error. + flush_ = true; + } + return HWC2::Error::BadDisplay; + } else { + validated_.set(type_); + } + } else { + // Skip is not set + MarkLayersForGPUBypass(); + skip_prepare_ = false; + DLOGI("SecureDisplay %s, Skip Prepare/Commit and Flush", + secure_display_active_ ? "Starting" : "Stopping"); + flush_ = true; + } + + for (auto hwc_layer : layer_set_) { + Layer *layer = hwc_layer->GetSDMLayer(); + LayerComposition &composition = layer->composition; + + if ((composition == kCompositionSDE) || (composition == kCompositionHybrid) || + (composition == kCompositionBlit)) { + layer_requests_[hwc_layer->GetId()] = HWC2::LayerRequest::ClearClientTarget; + } + + HWC2::Composition requested_composition = hwc_layer->GetClientRequestedCompositionType(); + // Set SDM composition to HWC2 type in HWCLayer + hwc_layer->SetComposition(composition); + HWC2::Composition device_composition = hwc_layer->GetDeviceSelectedCompositionType(); + // Update the changes list only if the requested composition is different from SDM comp type + // TODO(user): Take Care of other comptypes(BLIT) + if (requested_composition != device_composition) { + layer_changes_[hwc_layer->GetId()] = device_composition; + } + hwc_layer->ResetValidation(); + } + client_target_->ResetValidation(); + *out_num_types = UINT32(layer_changes_.size()); + *out_num_requests = UINT32(layer_requests_.size()); + skip_validate_ = false; + if (*out_num_types > 0) { + return HWC2::Error::HasChanges; + } else { + return HWC2::Error::None; + } +} + +HWC2::Error HWCDisplay::AcceptDisplayChanges() { + if (layer_set_.empty()) { + return HWC2::Error::None; + } + + if (!validated_.test(type_)) { + return HWC2::Error::NotValidated; + } + + for (const auto& change : layer_changes_) { + auto hwc_layer = layer_map_[change.first]; + auto composition = change.second; + if (hwc_layer != nullptr) { + hwc_layer->UpdateClientCompositionType(composition); + } else { + DLOGW("Invalid layer: %" PRIu64, change.first); + } + } + return HWC2::Error::None; +} + +HWC2::Error HWCDisplay::GetChangedCompositionTypes(uint32_t *out_num_elements, + hwc2_layer_t *out_layers, int32_t *out_types) { + if (layer_set_.empty()) { + return HWC2::Error::None; + } + + if (!validated_.test(type_)) { + DLOGW("Display is not validated"); + return HWC2::Error::NotValidated; + } + + *out_num_elements = UINT32(layer_changes_.size()); + if (out_layers != nullptr && out_types != nullptr) { + int i = 0; + for (auto change : layer_changes_) { + out_layers[i] = change.first; + out_types[i] = INT32(change.second); + i++; + } + } + return HWC2::Error::None; +} + +HWC2::Error HWCDisplay::GetReleaseFences(uint32_t *out_num_elements, hwc2_layer_t *out_layers, + int32_t *out_fences) { + if (out_layers != nullptr && out_fences != nullptr) { + int i = 0; + for (auto hwc_layer : layer_set_) { + out_layers[i] = hwc_layer->GetId(); + out_fences[i] = hwc_layer->PopReleaseFence(); + i++; + } + } + *out_num_elements = UINT32(layer_set_.size()); + return HWC2::Error::None; +} + +HWC2::Error HWCDisplay::GetDisplayRequests(int32_t *out_display_requests, + uint32_t *out_num_elements, hwc2_layer_t *out_layers, + int32_t *out_layer_requests) { + if (layer_set_.empty()) { + return HWC2::Error::None; + } + + // No display requests for now + // Use for sharing blit buffers and + // writing wfd buffer directly to output if there is full GPU composition + // and no color conversion needed + if (!validated_.test(type_)) { + DLOGW("Display is not validated"); + return HWC2::Error::NotValidated; + } + + *out_display_requests = 0; + *out_num_elements = UINT32(layer_requests_.size()); + if (out_layers != nullptr && out_layer_requests != nullptr) { + int i = 0; + for (auto &request : layer_requests_) { + out_layers[i] = request.first; + out_layer_requests[i] = INT32(request.second); + i++; + } + } + + auto client_target_layer = client_target_->GetSDMLayer(); + if (client_target_layer->request.flags.flip_buffer) { + *out_display_requests = INT32(HWC2::DisplayRequest::FlipClientTarget); + } + + return HWC2::Error::None; +} + +HWC2::Error HWCDisplay::GetHdrCapabilities(uint32_t *out_num_types, int32_t *out_types, + float *out_max_luminance, + float *out_max_average_luminance, + float *out_min_luminance) { + DisplayConfigFixedInfo fixed_info = {}; + display_intf_->GetConfig(&fixed_info); + + if (!fixed_info.hdr_supported) { + *out_num_types = 0; + DLOGI("HDR is not supported"); + return HWC2::Error::None; + } + + if (out_types == nullptr) { + // 1(now) - because we support only HDR10, change when HLG & DOLBY vision are supported + *out_num_types = 1; + } else { + // Only HDR10 supported + *out_types = HAL_HDR_HDR10; + static const float kLuminanceFactor = 10000.0; + // luminance is expressed in the unit of 0.0001 cd/m2, convert it to 1cd/m2. + *out_max_luminance = FLOAT(fixed_info.max_luminance)/kLuminanceFactor; + *out_max_average_luminance = FLOAT(fixed_info.average_luminance)/kLuminanceFactor; + *out_min_luminance = FLOAT(fixed_info.min_luminance)/kLuminanceFactor; + } + + return HWC2::Error::None; +} + + +HWC2::Error HWCDisplay::CommitLayerStack(void) { + if (shutdown_pending_ || layer_set_.empty()) { + return HWC2::Error::None; + } + + if (skip_validate_ && !CanSkipValidate()) { + validated_.reset(type_); + } + + if (!validated_.test(type_)) { + DLOGV_IF(kTagClient, "Display %d is not validated", id_); + return HWC2::Error::NotValidated; + } + + DumpInputBuffers(); + + if (!flush_) { + DisplayError error = kErrorUndefined; + int status = 0; + if (tone_mapper_) { + if (layer_stack_.flags.hdr_present) { + status = tone_mapper_->HandleToneMap(&layer_stack_); + if (status != 0) { + DLOGE("Error handling HDR in ToneMapper"); + } + } else { + tone_mapper_->Terminate(); + } + } + error = display_intf_->Commit(&layer_stack_); + + if (error == kErrorNone) { + // A commit is successfully submitted, start flushing on failure now onwards. + flush_on_error_ = true; + } else { + if (error == kErrorShutDown) { + shutdown_pending_ = true; + return HWC2::Error::Unsupported; + } else if (error == kErrorNotValidated) { + validated_.reset(type_); + return HWC2::Error::NotValidated; + } else if (error != kErrorPermission) { + DLOGE("Commit failed. Error = %d", error); + // To prevent surfaceflinger infinite wait, flush the previous frame during Commit() + // so that previous buffer and fences are released, and override the error. + flush_ = true; + } + } + } + + skip_validate_ = true; + return HWC2::Error::None; +} + +HWC2::Error HWCDisplay::PostCommitLayerStack(int32_t *out_retire_fence) { + auto status = HWC2::Error::None; + + // Do no call flush on errors, if a successful buffer is never submitted. + if (flush_ && flush_on_error_) { + display_intf_->Flush(); + validated_.reset(); + } + + if (tone_mapper_ && tone_mapper_->IsActive()) { + tone_mapper_->PostCommit(&layer_stack_); + } + + // TODO(user): No way to set the client target release fence on SF + int32_t &client_target_release_fence = + client_target_->GetSDMLayer()->input_buffer.release_fence_fd; + if (client_target_release_fence >= 0) { + close(client_target_release_fence); + client_target_release_fence = -1; + } + client_target_->ResetGeometryChanges(); + + for (auto hwc_layer : layer_set_) { + hwc_layer->ResetGeometryChanges(); + Layer *layer = hwc_layer->GetSDMLayer(); + LayerBuffer *layer_buffer = &layer->input_buffer; + + if (!flush_) { + // If swapinterval property is set to 0 or for single buffer layers, do not update f/w + // release fences and discard fences from driver + if (swap_interval_zero_ || layer->flags.single_buffer) { + close(layer_buffer->release_fence_fd); + } else if (layer->composition != kCompositionGPU) { + hwc_layer->PushReleaseFence(layer_buffer->release_fence_fd); + } else { + hwc_layer->PushReleaseFence(-1); + } + } else { + // In case of flush, we don't return an error to f/w, so it will get a release fence out of + // the hwc_layer's release fence queue. We should push a -1 to preserve release fence + // circulation semantics. + hwc_layer->PushReleaseFence(-1); + } + + layer_buffer->release_fence_fd = -1; + if (layer_buffer->acquire_fence_fd >= 0) { + close(layer_buffer->acquire_fence_fd); + layer_buffer->acquire_fence_fd = -1; + } + } + + *out_retire_fence = -1; + if (!flush_) { + // if swapinterval property is set to 0 then close and reset the list retire fence + if (swap_interval_zero_) { + close(layer_stack_.retire_fence_fd); + layer_stack_.retire_fence_fd = -1; + } + *out_retire_fence = layer_stack_.retire_fence_fd; + layer_stack_.retire_fence_fd = -1; + + if (dump_frame_count_) { + dump_frame_count_--; + dump_frame_index_++; + } + } + + geometry_changes_ = GeometryChanges::kNone; + flush_ = false; + + ClearRequestFlags(); + + return status; +} + +void HWCDisplay::SetIdleTimeoutMs(uint32_t timeout_ms) { + return; +} + +DisplayError HWCDisplay::SetMaxMixerStages(uint32_t max_mixer_stages) { + DisplayError error = kErrorNone; + + if (display_intf_) { + error = display_intf_->SetMaxMixerStages(max_mixer_stages); + validated_.reset(); + } + + return error; +} + +LayerBufferFormat HWCDisplay::GetSDMFormat(const int32_t &source, const int flags) { + LayerBufferFormat format = kFormatInvalid; + if (flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) { + switch (source) { + case HAL_PIXEL_FORMAT_RGBA_8888: + format = kFormatRGBA8888Ubwc; + break; + case HAL_PIXEL_FORMAT_RGBX_8888: + format = kFormatRGBX8888Ubwc; + break; + case HAL_PIXEL_FORMAT_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; + case HAL_PIXEL_FORMAT_RGBA_1010102: + format = kFormatRGBA1010102Ubwc; + break; + case HAL_PIXEL_FORMAT_RGBX_1010102: + format = kFormatRGBX1010102Ubwc; + break; + case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC: + format = kFormatYCbCr420TP10Ubwc; + break; + case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC: + format = kFormatYCbCr420P010Ubwc; + 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_BGR_888: + format = kFormatBGR888; + 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; + case HAL_PIXEL_FORMAT_CbYCrY_422_I: + format = kFormatCbYCrY422H2V1Packed; + break; + case HAL_PIXEL_FORMAT_RGBA_1010102: + format = kFormatRGBA1010102; + break; + case HAL_PIXEL_FORMAT_ARGB_2101010: + format = kFormatARGB2101010; + break; + case HAL_PIXEL_FORMAT_RGBX_1010102: + format = kFormatRGBX1010102; + break; + case HAL_PIXEL_FORMAT_XRGB_2101010: + format = kFormatXRGB2101010; + break; + case HAL_PIXEL_FORMAT_BGRA_1010102: + format = kFormatBGRA1010102; + break; + case HAL_PIXEL_FORMAT_ABGR_2101010: + format = kFormatABGR2101010; + break; + case HAL_PIXEL_FORMAT_BGRX_1010102: + format = kFormatBGRX1010102; + break; + case HAL_PIXEL_FORMAT_XBGR_2101010: + format = kFormatXBGR2101010; + break; + case HAL_PIXEL_FORMAT_YCbCr_420_P010: + format = kFormatYCbCr420P010; + break; + case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC: + format = kFormatYCbCr420TP10Ubwc; + break; + case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC: + format = kFormatYCbCr420P010Ubwc; + break; + default: + DLOGW("Unsupported format type = %d", source); + return kFormatInvalid; + } + + return format; +} + +void HWCDisplay::DumpInputBuffers() { + char dir_path[PATH_MAX]; + + if (!dump_frame_count_ || flush_ || !dump_input_layers_) { + return; + } + + DLOGI("dump_frame_count %d dump_input_layers %d", dump_frame_count_, dump_input_layers_); + snprintf(dir_path, sizeof(dir_path), "%s/frame_dump_%s", HWCDebugHandler::DumpDir(), + GetDisplayString()); + + if (mkdir(dir_path, 0777) != 0 && errno != EEXIST) { + DLOGW("Failed to create %s directory errno = %d, desc = %s", dir_path, errno, strerror(errno)); + return; + } + + // if directory exists already, need to explicitly change the permission. + if (errno == EEXIST && chmod(dir_path, 0777) != 0) { + DLOGW("Failed to change permissions on %s directory", dir_path); + return; + } + + for (uint32_t i = 0; i < layer_stack_.layers.size(); i++) { + auto layer = layer_stack_.layers.at(i); + const private_handle_t *pvt_handle = + reinterpret_cast<const private_handle_t *>(layer->input_buffer.buffer_id); + auto acquire_fence_fd = layer->input_buffer.acquire_fence_fd; + + if (acquire_fence_fd >= 0) { + int error = sync_wait(acquire_fence_fd, 1000); + if (error < 0) { + DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno)); + return; + } + } + + DLOGI("Dump layer[%d] of %d pvt_handle %x pvt_handle->base %x", i, layer_stack_.layers.size(), + pvt_handle, pvt_handle? pvt_handle->base : 0); + + if (!pvt_handle) { + DLOGE("Buffer handle is null"); + return; + } + + if (!pvt_handle->base) { + DisplayError error = buffer_allocator_->MapBuffer(pvt_handle, -1); + if (error != kErrorNone) { + DLOGE("Failed to map buffer, error = %d", error); + return; + } + } + + char dump_file_name[PATH_MAX]; + size_t result = 0; + + snprintf(dump_file_name, sizeof(dump_file_name), "%s/input_layer%d_%dx%d_%s_frame%d.raw", + dir_path, i, pvt_handle->width, pvt_handle->height, + qdutils::GetHALPixelFormatString(pvt_handle->format), dump_frame_index_); + + FILE *fp = fopen(dump_file_name, "w+"); + if (fp) { + result = fwrite(reinterpret_cast<void *>(pvt_handle->base), pvt_handle->size, 1, fp); + fclose(fp); + } + + int release_fence = -1; + DisplayError error = buffer_allocator_->UnmapBuffer(pvt_handle, &release_fence); + if (error != kErrorNone) { + DLOGE("Failed to unmap buffer, error = %d", error); + return; + } + + DLOGI("Frame Dump %s: is %s", dump_file_name, result ? "Successful" : "Failed"); + } +} + +void HWCDisplay::DumpOutputBuffer(const BufferInfo &buffer_info, void *base, int fence) { + char dir_path[PATH_MAX]; + + snprintf(dir_path, sizeof(dir_path), "%s/frame_dump_%s", HWCDebugHandler::DumpDir(), + GetDisplayString()); + + if (mkdir(dir_path, 777) != 0 && errno != EEXIST) { + DLOGW("Failed to create %s directory errno = %d, desc = %s", dir_path, errno, strerror(errno)); + return; + } + + // if directory exists already, need to explicitly change the permission. + if (errno == EEXIST && chmod(dir_path, 0777) != 0) { + DLOGW("Failed to change permissions on %s directory", dir_path); + return; + } + + if (base) { + char dump_file_name[PATH_MAX]; + size_t result = 0; + + if (fence >= 0) { + int error = sync_wait(fence, 1000); + if (error < 0) { + DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno)); + return; + } + } + + snprintf(dump_file_name, sizeof(dump_file_name), "%s/output_layer_%dx%d_%s_frame%d.raw", + dir_path, buffer_info.buffer_config.width, buffer_info.buffer_config.height, + GetFormatString(buffer_info.buffer_config.format), dump_frame_index_); + + FILE *fp = fopen(dump_file_name, "w+"); + if (fp) { + result = fwrite(base, buffer_info.alloc_buffer_info.size, 1, fp); + fclose(fp); + } + + DLOGI("Frame Dump of %s is %s", dump_file_name, result ? "Successful" : "Failed"); + } +} + +const char *HWCDisplay::GetDisplayString() { + switch (type_) { + case kPrimary: + return "primary"; + case kHDMI: + return "hdmi"; + case kVirtual: + return "virtual"; + default: + return "invalid"; + } +} + +int HWCDisplay::SetFrameBufferResolution(uint32_t x_pixels, uint32_t y_pixels) { + if (x_pixels <= 0 || y_pixels <= 0) { + DLOGW("Unsupported config: x_pixels=%d, y_pixels=%d", x_pixels, y_pixels); + return -EINVAL; + } + + DisplayConfigVariableInfo fb_config; + DisplayError error = display_intf_->GetFrameBufferConfig(&fb_config); + if (error != kErrorNone) { + DLOGV("Get frame buffer config failed. Error = %d", error); + return -EINVAL; + } + + fb_config.x_pixels = x_pixels; + fb_config.y_pixels = y_pixels; + + error = display_intf_->SetFrameBufferConfig(fb_config); + if (error != kErrorNone) { + DLOGV("Set frame buffer config failed. Error = %d", error); + return -EINVAL; + } + + // Create rects to represent the new source and destination crops + LayerRect crop = LayerRect(0, 0, FLOAT(x_pixels), FLOAT(y_pixels)); + hwc_rect_t scaled_display_frame = {0, 0, INT(x_pixels), INT(y_pixels)}; + ApplyScanAdjustment(&scaled_display_frame); + client_target_->SetLayerDisplayFrame(scaled_display_frame); + + auto client_target_layer = client_target_->GetSDMLayer(); + client_target_layer->src_rect = crop; + + int aligned_width; + int aligned_height; + uint32_t usage = GRALLOC_USAGE_HW_FB; + int format = HAL_PIXEL_FORMAT_RGBA_8888; + int ubwc_disabled = 0; + int flags = 0; + + // By default UBWC is enabled and below property is global enable/disable for all + // buffers allocated through gralloc , including framebuffer targets. + HWCDebugHandler::Get()->GetProperty(DISABLE_UBWC_PROP, &ubwc_disabled); + if (!ubwc_disabled) { + usage |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; + flags |= private_handle_t::PRIV_FLAGS_UBWC_ALIGNED; + } + +#ifdef USE_GRALLOC1 + buffer_allocator_->GetAlignedWidthAndHeight(INT(x_pixels), INT(y_pixels), format, usage, + &aligned_width, &aligned_height); +#else + AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(INT(x_pixels), INT(y_pixels), format, + INT(usage), aligned_width, aligned_height); +#endif + + // TODO(user): How does the dirty region get set on the client target? File bug on Google + client_target_layer->composition = kCompositionGPUTarget; + client_target_layer->input_buffer.format = GetSDMFormat(format, flags); + client_target_layer->input_buffer.width = UINT32(aligned_width); + client_target_layer->input_buffer.height = UINT32(aligned_height); + client_target_layer->input_buffer.unaligned_width = x_pixels; + client_target_layer->input_buffer.unaligned_height = y_pixels; + client_target_layer->plane_alpha = 255; + + DLOGI("New framebuffer resolution (%dx%d)", fb_config.x_pixels, fb_config.y_pixels); + + return 0; +} + +void HWCDisplay::GetFrameBufferResolution(uint32_t *x_pixels, uint32_t *y_pixels) { + DisplayConfigVariableInfo fb_config; + display_intf_->GetFrameBufferConfig(&fb_config); + + *x_pixels = fb_config.x_pixels; + *y_pixels = fb_config.y_pixels; +} + +DisplayError HWCDisplay::GetMixerResolution(uint32_t *x_pixels, uint32_t *y_pixels) { + return display_intf_->GetMixerResolution(x_pixels, y_pixels); +} + +void HWCDisplay::GetPanelResolution(uint32_t *x_pixels, uint32_t *y_pixels) { + DisplayConfigVariableInfo display_config; + uint32_t active_index = 0; + + display_intf_->GetActiveConfig(&active_index); + display_intf_->GetConfig(active_index, &display_config); + + *x_pixels = display_config.x_pixels; + *y_pixels = display_config.y_pixels; +} + +int HWCDisplay::SetDisplayStatus(DisplayStatus display_status) { + int status = 0; + + switch (display_status) { + case kDisplayStatusResume: + display_paused_ = false; + case kDisplayStatusOnline: + status = INT32(SetPowerMode(HWC2::PowerMode::On)); + break; + case kDisplayStatusPause: + display_paused_ = true; + case kDisplayStatusOffline: + status = INT32(SetPowerMode(HWC2::PowerMode::Off)); + break; + default: + DLOGW("Invalid display status %d", display_status); + return -EINVAL; + } + + if (display_status == kDisplayStatusResume || display_status == kDisplayStatusPause) { + callbacks_->Refresh(HWC_DISPLAY_PRIMARY); + validated_.reset(); + } + + return status; +} + +HWC2::Error HWCDisplay::SetCursorPosition(hwc2_layer_t layer, int x, int y) { + if (shutdown_pending_) { + return HWC2::Error::None; + } + + HWCLayer *hwc_layer = GetHWCLayer(layer); + if (hwc_layer == nullptr) { + return HWC2::Error::BadLayer; + } + if (hwc_layer->GetDeviceSelectedCompositionType() != HWC2::Composition::Cursor) { + return HWC2::Error::None; + } + if (!skip_validate_ && validated_.test(type_)) { + // the device is currently in the middle of the validate/present sequence, + // cannot set the Position(as per HWC2 spec) + return HWC2::Error::NotValidated; + } + + DisplayState state; + if (display_intf_->GetDisplayState(&state) == kErrorNone) { + if (state != kStateOn) { + return HWC2::Error::None; + } + } + + // TODO(user): HWC1.5 was not letting SetCursorPosition before validateDisplay, + // but HWC2.0 doesn't let setting cursor position after validate before present. + // Need to revisit. + + auto error = display_intf_->SetCursorPosition(x, y); + if (error != kErrorNone) { + if (error == kErrorShutDown) { + shutdown_pending_ = true; + return HWC2::Error::None; + } + + DLOGE("Failed for x = %d y = %d, Error = %d", x, y, error); + return HWC2::Error::BadDisplay; + } + + return HWC2::Error::None; +} + +int HWCDisplay::OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level) { + DisplayError error = display_intf_->OnMinHdcpEncryptionLevelChange(min_enc_level); + if (error != kErrorNone) { + DLOGE("Failed. Error = %d", error); + return -1; + } + + validated_.reset(); + return 0; +} + +void HWCDisplay::MarkLayersForGPUBypass() { + for (auto hwc_layer : layer_set_) { + auto layer = hwc_layer->GetSDMLayer(); + layer->composition = kCompositionSDE; + } + validated_.set(type_); +} + +void HWCDisplay::MarkLayersForClientComposition() { + // ClientComposition - GPU comp, to achieve this, set skip flag so that + // SDM does not handle this layer and hwc_layer composition will be + // set correctly at the end of Prepare. + DLOGV_IF(kTagClient, "HWC Layers marked for GPU comp"); + for (auto hwc_layer : layer_set_) { + Layer *layer = hwc_layer->GetSDMLayer(); + layer->flags.skip = true; + } + layer_stack_.flags.skip_present = true; +} + +void HWCDisplay::ApplyScanAdjustment(hwc_rect_t *display_frame) { +} + +int HWCDisplay::SetPanelBrightness(int level) { + int ret = 0; + if (display_intf_) { + ret = display_intf_->SetPanelBrightness(level); + validated_.reset(); + } else { + ret = -EINVAL; + } + + return ret; +} + +int HWCDisplay::GetPanelBrightness(int *level) { + return display_intf_->GetPanelBrightness(level); +} + +int HWCDisplay::ToggleScreenUpdates(bool enable) { + display_paused_ = enable ? false : true; + callbacks_->Refresh(HWC_DISPLAY_PRIMARY); + validated_.reset(); + return 0; +} + +int HWCDisplay::ColorSVCRequestRoute(const PPDisplayAPIPayload &in_payload, + PPDisplayAPIPayload *out_payload, + PPPendingParams *pending_action) { + int ret = 0; + + if (display_intf_) + ret = display_intf_->ColorSVCRequestRoute(in_payload, out_payload, pending_action); + else + ret = -EINVAL; + + return ret; +} + +void HWCDisplay::SolidFillPrepare() { + if (solid_fill_enable_) { + if (solid_fill_layer_ == NULL) { + // Create a dummy layer here + solid_fill_layer_ = new Layer(); + } + uint32_t primary_width = 0, primary_height = 0; + GetMixerResolution(&primary_width, &primary_height); + + LayerBuffer *layer_buffer = &solid_fill_layer_->input_buffer; + layer_buffer->width = primary_width; + layer_buffer->height = primary_height; + layer_buffer->unaligned_width = primary_width; + layer_buffer->unaligned_height = primary_height; + layer_buffer->acquire_fence_fd = -1; + layer_buffer->release_fence_fd = -1; + + LayerRect rect; + rect.top = 0; rect.left = 0; + rect.right = primary_width; + rect.bottom = primary_height; + + solid_fill_layer_->composition = kCompositionGPU; + solid_fill_layer_->src_rect = rect; + solid_fill_layer_->dst_rect = rect; + + solid_fill_layer_->blending = kBlendingPremultiplied; + solid_fill_layer_->solid_fill_color = solid_fill_color_; + solid_fill_layer_->frame_rate = 60; + solid_fill_layer_->visible_regions.push_back(solid_fill_layer_->dst_rect); + solid_fill_layer_->flags.updating = 1; + solid_fill_layer_->flags.solid_fill = true; + } else { + // delete the dummy layer + delete solid_fill_layer_; + solid_fill_layer_ = NULL; + } + + if (solid_fill_enable_ && solid_fill_layer_) { + BuildSolidFillStack(); + MarkLayersForGPUBypass(); + } + + return; +} + +void HWCDisplay::SolidFillCommit() { + if (solid_fill_enable_ && solid_fill_layer_) { + LayerBuffer *layer_buffer = &solid_fill_layer_->input_buffer; + if (layer_buffer->release_fence_fd > 0) { + close(layer_buffer->release_fence_fd); + layer_buffer->release_fence_fd = -1; + } + if (layer_stack_.retire_fence_fd > 0) { + close(layer_stack_.retire_fence_fd); + layer_stack_.retire_fence_fd = -1; + } + } +} + +int HWCDisplay::GetVisibleDisplayRect(hwc_rect_t *visible_rect) { + if (!IsValid(display_rect_)) { + return -EINVAL; + } + + visible_rect->left = INT(display_rect_.left); + visible_rect->top = INT(display_rect_.top); + visible_rect->right = INT(display_rect_.right); + visible_rect->bottom = INT(display_rect_.bottom); + DLOGI("Dpy = %d Visible Display Rect(%d %d %d %d)", visible_rect->left, visible_rect->top, + visible_rect->right, visible_rect->bottom); + + return 0; +} + +void HWCDisplay::SetSecureDisplay(bool secure_display_active) { + if (secure_display_active_ != secure_display_active) { + 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; +} + +int HWCDisplay::SetActiveDisplayConfig(uint32_t config) { + int status = (display_intf_->SetActiveConfig(config) == kErrorNone) ? 0 : -1; + validated_.reset(); + return status; +} + +int HWCDisplay::GetActiveDisplayConfig(uint32_t *config) { + return display_intf_->GetActiveConfig(config) == kErrorNone ? 0 : -1; +} + +int HWCDisplay::GetDisplayConfigCount(uint32_t *count) { + return display_intf_->GetNumVariableInfoConfigs(count) == kErrorNone ? 0 : -1; +} + +int HWCDisplay::GetDisplayAttributesForConfig(int config, + DisplayConfigVariableInfo *display_attributes) { + return display_intf_->GetConfig(UINT32(config), display_attributes) == kErrorNone ? 0 : -1; +} + +uint32_t HWCDisplay::GetUpdatingLayersCount(void) { + uint32_t updating_count = 0; + + for (uint i = 0; i < layer_stack_.layers.size(); i++) { + auto layer = layer_stack_.layers.at(i); + if (layer->flags.updating) { + updating_count++; + } + } + + return updating_count; +} + +bool HWCDisplay::IsLayerUpdating(const Layer *layer) { + // Layer should be considered updating if + // a) layer is in single buffer mode, or + // b) valid dirty_regions(android specific hint for updating status), or + // c) layer stack geometry has changed (TODO(user): Remove when SDM accepts + // geometry_changed as bit fields). + return (layer->flags.single_buffer || IsSurfaceUpdated(layer->dirty_regions) || + geometry_changes_); +} + +bool HWCDisplay::IsSurfaceUpdated(const std::vector<LayerRect> &dirty_regions) { + // based on dirty_regions determine if its updating + // dirty_rect count = 0 - whole layer - updating. + // dirty_rect count = 1 or more valid rects - updating. + // dirty_rect count = 1 with (0,0,0,0) - not updating. + return (dirty_regions.empty() || IsValid(dirty_regions.at(0))); +} + +uint32_t HWCDisplay::SanitizeRefreshRate(uint32_t req_refresh_rate) { + uint32_t refresh_rate = req_refresh_rate; + + if (refresh_rate < min_refresh_rate_) { + // Pick the next multiple of request which is within the range + refresh_rate = + (((min_refresh_rate_ / refresh_rate) + ((min_refresh_rate_ % refresh_rate) ? 1 : 0)) * + refresh_rate); + } + + if (refresh_rate > max_refresh_rate_) { + refresh_rate = max_refresh_rate_; + } + + return refresh_rate; +} + +DisplayClass HWCDisplay::GetDisplayClass() { + return display_class_; +} + +void HWCDisplay::CloseAcquireFds() { + for (auto hwc_layer : layer_set_) { + auto layer = hwc_layer->GetSDMLayer(); + if (layer->input_buffer.acquire_fence_fd >= 0) { + close(layer->input_buffer.acquire_fence_fd); + layer->input_buffer.acquire_fence_fd = -1; + } + } + int32_t &client_target_acquire_fence = + client_target_->GetSDMLayer()->input_buffer.acquire_fence_fd; + if (client_target_acquire_fence >= 0) { + close(client_target_acquire_fence); + client_target_acquire_fence = -1; + } +} + +void HWCDisplay::ClearRequestFlags() { + for (Layer *layer : layer_stack_.layers) { + layer->request.flags = {}; + } +} + +std::string HWCDisplay::Dump() { + std::ostringstream os; + os << "\n------------HWC----------------\n"; + os << "HWC2 display_id: " << id_ << std::endl; + for (auto layer : layer_set_) { + auto sdm_layer = layer->GetSDMLayer(); + auto transform = sdm_layer->transform; + os << "layer: " << std::setw(4) << layer->GetId(); + os << " z: " << layer->GetZ(); + os << " compositon: " << + to_string(layer->GetClientRequestedCompositionType()).c_str(); + os << "/" << + to_string(layer->GetDeviceSelectedCompositionType()).c_str(); + os << " alpha: " << std::to_string(sdm_layer->plane_alpha).c_str(); + os << " format: " << std::setw(22) << GetFormatString(sdm_layer->input_buffer.format); + os << " dataspace:" << std::hex << "0x" << std::setw(8) << std::setfill('0') + << layer->GetLayerDataspace() << std::dec << std::setfill(' '); + os << " transform: " << transform.rotation << "/" << transform.flip_horizontal << + "/"<< transform.flip_vertical; + os << " buffer_id: " << std::hex << "0x" << sdm_layer->input_buffer.buffer_id << std::dec + << std::endl; + } + + if (color_mode_) { + os << "\n----------Color Modes---------\n"; + color_mode_->Dump(&os); + } + + if (display_intf_) { + os << "\n------------SDM----------------\n"; + os << display_intf_->Dump(); + } + + os << "\n"; + + return os.str(); +} + +bool HWCDisplay::CanSkipValidate() { + // Layer Stack checks + if (layer_stack_.flags.hdr_present && (tone_mapper_ && tone_mapper_->IsActive())) { + DLOGV_IF(kTagClient, "HDR content present with tone mapping enabled. Returning false."); + return false; + } + + if (client_target_->NeedsValidation()) { + DLOGV_IF(kTagClient, "Framebuffer target needs validation. Returning false."); + return false; + } + + for (auto hwc_layer : layer_set_) { + if (hwc_layer->NeedsValidation()) { + DLOGV_IF(kTagClient, "hwc_layer[%d] needs validation. Returning false.", + hwc_layer->GetId()); + return false; + } + + // Do not allow Skip Validate, if any layer needs GPU Composition. + if (hwc_layer->GetDeviceSelectedCompositionType() == HWC2::Composition::Client) { + DLOGV_IF(kTagClient, "hwc_layer[%d] is GPU composed. Returning false.", + hwc_layer->GetId()); + return false; + } + } + + return true; +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/hwc2/hwc_display.h b/msm8909/sdm/libs/hwc2/hwc_display.h new file mode 100644 index 00000000..0c69be7b --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_display.h @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2014-2017, 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 <sys/stat.h> +#include <QService.h> +#include <core/core_interface.h> +#include <hardware/hwcomposer.h> +#include <private/color_params.h> +#include <qdMetaData.h> +#include <map> +#include <queue> +#include <set> +#include <string> +#include <utility> +#include <vector> + +#include "hwc_buffer_allocator.h" +#include "hwc_callbacks.h" +#include "hwc_layers.h" + +namespace sdm { + +class BlitEngine; +class HWCToneMapper; + +// 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 HWCColorMode { + public: + explicit HWCColorMode(DisplayInterface *display_intf); + ~HWCColorMode() {} + HWC2::Error Init(); + HWC2::Error DeInit(); + void Dump(std::ostringstream* os); + uint32_t GetColorModeCount(); + HWC2::Error GetColorModes(uint32_t *out_num_modes, android_color_mode_t *out_modes); + HWC2::Error SetColorMode(android_color_mode_t mode); + HWC2::Error SetColorTransform(const float *matrix, android_color_transform_t hint); + HWC2::Error RestoreColorTransform(); + + private: + static const uint32_t kColorTransformMatrixCount = 16; + + HWC2::Error HandleColorModeTransform(android_color_mode_t mode, + android_color_transform_t hint, const double *matrix); + void PopulateColorModes(); + void PopulateTransform(const android_color_mode_t &mode, + const std::string &color_mode, const std::string &color_transform); + template <class T> + void CopyColorTransformMatrix(const T *input_matrix, double *output_matrix) { + for (uint32_t i = 0; i < kColorTransformMatrixCount; i++) { + output_matrix[i] = static_cast<double>(input_matrix[i]); + } + } + HWC2::Error ApplyDefaultColorMode(); + + DisplayInterface *display_intf_ = NULL; + android_color_mode_t current_color_mode_ = HAL_COLOR_MODE_NATIVE; + android_color_transform_t current_color_transform_ = HAL_COLOR_TRANSFORM_IDENTITY; + typedef std::map<android_color_transform_t, std::string> TransformMap; + std::map<android_color_mode_t, TransformMap> color_mode_transform_map_ = {}; + double color_matrix_[kColorTransformMatrixCount] = { 1.0, 0.0, 0.0, 0.0, \ + 0.0, 1.0, 0.0, 0.0, \ + 0.0, 0.0, 1.0, 0.0, \ + 0.0, 0.0, 0.0, 1.0 }; +}; + +class HWCDisplay : public DisplayEventHandler { + public: + enum DisplayStatus { + kDisplayStatusInvalid = -1, + kDisplayStatusOffline, + kDisplayStatusOnline, + kDisplayStatusPause, + kDisplayStatusResume, + }; + + 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) { + return kErrorNotSupported; + } + 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 int SetDisplayStatus(DisplayStatus display_status); + virtual int OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level); + virtual int Perform(uint32_t operation, ...); + virtual void SetSecureDisplay(bool secure_display_active); + virtual DisplayError SetMixerResolution(uint32_t width, uint32_t height); + virtual DisplayError GetMixerResolution(uint32_t *width, uint32_t *height); + virtual void GetPanelResolution(uint32_t *width, uint32_t *height); + virtual std::string Dump(); + + // 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; } + + virtual DisplayError SetDetailEnhancerConfig(const DisplayDetailEnhancerData &de_data) { + return kErrorNotSupported; + } + + // Display Configurations + virtual int SetActiveDisplayConfig(uint32_t config); + virtual int GetActiveDisplayConfig(uint32_t *config); + virtual int GetDisplayConfigCount(uint32_t *count); + virtual int GetDisplayAttributesForConfig(int config, + DisplayConfigVariableInfo *display_attributes); + virtual int SetState(bool connected) { + return kErrorNotSupported; + } + int SetPanelBrightness(int level); + int GetPanelBrightness(int *level); + int ToggleScreenUpdates(bool enable); + int ColorSVCRequestRoute(const PPDisplayAPIPayload &in_payload, PPDisplayAPIPayload *out_payload, + PPPendingParams *pending_action); + void SolidFillPrepare(); + void SolidFillCommit(); + DisplayClass GetDisplayClass(); + int GetVisibleDisplayRect(hwc_rect_t *rect); + void BuildLayerStack(void); + void BuildSolidFillStack(void); + HWCLayer *GetHWCLayer(hwc2_layer_t layer); + void ResetValidation() { validated_.reset(); } + uint32_t GetGeometryChanges() { return geometry_changes_; } + + // 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, hwc_region_t damage); + virtual HWC2::Error SetColorMode(android_color_mode_t mode) { + return HWC2::Error::Unsupported; + } + virtual HWC2::Error RestoreColorTransform() { + return HWC2::Error::Unsupported; + } + virtual HWC2::Error SetColorTransform(const float *matrix, android_color_transform_t hint) { + return HWC2::Error::Unsupported; + } + virtual HWC2::Error HandleColorModeTransform(android_color_mode_t mode, + android_color_transform_t hint, + const double *matrix) { + return HWC2::Error::Unsupported; + } + 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 GetColorModes(uint32_t *outNumModes, android_color_mode_t *outModes); + 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; + virtual HWC2::Error GetHdrCapabilities(uint32_t *out_num_types, int32_t* out_types, + float* out_max_luminance, + float* out_max_average_luminance, + float* out_min_luminance); + virtual HWC2::Error SetDisplayAnimating(bool animating) { + animating_ = animating; + validated_ = false; + return HWC2::Error::None; + } + + protected: + // 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, + BufferAllocator *buffer_allocator); + + // DisplayEventHandler methods + virtual DisplayError VSync(const DisplayEventVSync &vsync); + virtual DisplayError Refresh(); + virtual DisplayError CECMessage(char *message); + virtual DisplayError HandleEvent(DisplayEvent event); + 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); + virtual DisplayError DisablePartialUpdateOneFrame() { + return kErrorNotSupported; + } + LayerBufferFormat GetSDMFormat(const int32_t &source, const int flags); + const char *GetDisplayString(); + void MarkLayersForGPUBypass(void); + void MarkLayersForClientComposition(void); + virtual void ApplyScanAdjustment(hwc_rect_t *display_frame); + uint32_t GetUpdatingLayersCount(void); + bool IsSurfaceUpdated(const std::vector<LayerRect> &dirty_regions); + bool IsLayerUpdating(const Layer *layer); + uint32_t SanitizeRefreshRate(uint32_t req_refresh_rate); + virtual void CloseAcquireFds(); + virtual void ClearRequestFlags(); + virtual void GetUnderScanConfig() { } + + enum { + INPUT_LAYER_DUMP, + OUTPUT_LAYER_DUMP, + }; + + static std::bitset<kDisplayMax> validated_; + CoreInterface *core_intf_ = nullptr; + HWCCallbacks *callbacks_ = nullptr; + HWCBufferAllocator *buffer_allocator_ = NULL; + DisplayType type_; + hwc2_display_t id_; + bool needs_blit_ = false; + DisplayInterface *display_intf_ = NULL; + LayerStack layer_stack_; + HWCLayer *client_target_ = nullptr; // 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; + 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; + Layer *solid_fill_layer_ = NULL; + LayerRect solid_fill_rect_ = {}; + uint32_t solid_fill_color_ = 0; + LayerRect display_rect_; + bool color_tranform_failed_ = false; + HWCColorMode *color_mode_ = NULL; + HWCToneMapper *tone_mapper_ = nullptr; + uint32_t num_configs_ = 0; + int disable_hdr_handling_ = 0; // disables HDR handling. + + private: + void DumpInputBuffers(void); + bool CanSkipValidate(); + qService::QService *qservice_ = NULL; + DisplayClass display_class_; + uint32_t geometry_changes_ = GeometryChanges::kNone; + bool skip_validate_ = false; + bool animating_ = false; +}; + +inline int HWCDisplay::Perform(uint32_t operation, ...) { + return 0; +} + +} // namespace sdm + +#endif // __HWC_DISPLAY_H__ diff --git a/msm8909/sdm/libs/hwc2/hwc_display_external.cpp b/msm8909/sdm/libs/hwc2/hwc_display_external.cpp new file mode 100644 index 00000000..440d80a3 --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_display_external.cpp @@ -0,0 +1,280 @@ +/* +* Copyright (c) 2014-2018, 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 <algorithm> + +#include "hwc_display_external.h" +#include "hwc_debugger.h" + +#define __CLASS__ "HWCDisplayExternal" + +namespace sdm { + +int HWCDisplayExternal::Create(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator, + HWCCallbacks *callbacks, qService::QService *qservice, + HWCDisplay **hwc_display) { + return Create(core_intf, buffer_allocator, callbacks, 0, 0, qservice, false, hwc_display); +} + +int HWCDisplayExternal::Create(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator, + 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; + DisplayError error = kErrorNone; + + HWCDisplay *hwc_display_external = new HWCDisplayExternal(core_intf, buffer_allocator, callbacks, + qservice); + int status = hwc_display_external->Init(); + if (status) { + delete hwc_display_external; + return status; + } + + error = hwc_display_external->GetMixerResolution(&external_width, &external_height); + if (error != kErrorNone) { + Destroy(hwc_display_external); + return -EINVAL; + } + + 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(ENABLE_EXTERNAL_DOWNSCALE_PROP, &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, + HWCBufferAllocator *buffer_allocator, + HWCCallbacks *callbacks, + qService::QService *qservice) + : HWCDisplay(core_intf, callbacks, kHDMI, HWC_DISPLAY_EXTERNAL, false, qservice, + DISPLAY_CLASS_EXTERNAL, buffer_allocator) { +} + +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 ((underscan_width_ <= 0) || (underscan_height_ <= 0)) { + return; + } + + float width_ratio = FLOAT(underscan_width_) / 100.0f; + float height_ratio = FLOAT(underscan_height_) / 100.0f; + + uint32_t mixer_width = 0; + uint32_t mixer_height = 0; + GetMixerResolution(&mixer_width, &mixer_height); + + if (mixer_width == 0 || mixer_height == 0) { + DLOGV("Invalid mixer dimensions (%d, %d)", mixer_width, mixer_height); + return; + } + + uint32_t new_mixer_width = UINT32(mixer_width * FLOAT(1.0f - width_ratio)); + uint32_t new_mixer_height = UINT32(mixer_height * FLOAT(1.0f - height_ratio)); + + int x_offset = INT((FLOAT(mixer_width) * width_ratio) / 2.0f); + int y_offset = INT((FLOAT(mixer_height) * height_ratio) / 2.0f); + + display_frame->left = (display_frame->left * INT32(new_mixer_width) / INT32(mixer_width)) + + x_offset; + display_frame->top = (display_frame->top * INT32(new_mixer_height) / INT32(mixer_height)) + + y_offset; + display_frame->right = ((display_frame->right * INT32(new_mixer_width)) / INT32(mixer_width)) + + x_offset; + display_frame->bottom = ((display_frame->bottom * INT32(new_mixer_height)) / INT32(mixer_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(); + validated_.reset(); + 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) { + std::swap(primary_height, primary_width); + } + AdjustSourceResolution(primary_width, primary_height, non_primary_width, non_primary_height); + } +} + +int HWCDisplayExternal::SetState(bool connected) { + DisplayError error = kErrorNone; + DisplayState state = kStateOff; + DisplayConfigVariableInfo fb_config = {}; + + if (connected) { + if (display_null_.IsActive()) { + error = core_intf_->CreateDisplay(type_, this, &display_intf_); + if (error != kErrorNone) { + DLOGE("Display create failed. Error = %d display_type %d event_handler %p disp_intf %p", + error, type_, this, &display_intf_); + return -EINVAL; + } + + // Restore HDMI attributes when display is reconnected. + // This is to ensure that surfaceflinger & sdm are in sync. + display_null_.GetFrameBufferConfig(&fb_config); + int status = SetFrameBufferResolution(fb_config.x_pixels, fb_config.y_pixels); + if (status) { + DLOGW("Set frame buffer config failed. Error = %d", error); + return -1; + } + + display_null_.GetDisplayState(&state); + display_intf_->SetDisplayState(state); + validated_.reset(); + + SetVsyncEnabled(HWC2::Vsync::Enable); + + display_null_.SetActive(false); + DLOGI("Display is connected successfully."); + } else { + DLOGI("Display is already connected."); + } + } else { + if (!display_null_.IsActive()) { + // Preserve required attributes of HDMI display that surfaceflinger sees. + // Restore HDMI attributes when display is reconnected. + display_intf_->GetDisplayState(&state); + display_null_.SetDisplayState(state); + + error = display_intf_->GetFrameBufferConfig(&fb_config); + if (error != kErrorNone) { + DLOGW("Get frame buffer config failed. Error = %d", error); + return -1; + } + display_null_.SetFrameBufferConfig(fb_config); + + SetVsyncEnabled(HWC2::Vsync::Disable); + core_intf_->DestroyDisplay(display_intf_); + display_intf_ = &display_null_; + + display_null_.SetActive(true); + DLOGI("Display is disconnected successfully."); + } else { + DLOGI("Display is already disconnected."); + } + } + + return 0; +} + +void HWCDisplayExternal::GetUnderScanConfig() { + if (!display_intf_->IsUnderscanSupported()) { + // Read user defined underscan width and height + HWCDebugHandler::Get()->GetProperty(EXTERNAL_ACTION_SAFE_WIDTH_PROP, &underscan_width_); + HWCDebugHandler::Get()->GetProperty(EXTERNAL_ACTION_SAFE_HEIGHT_PROP, &underscan_height_); + } +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/hwc2/hwc_display_external.h b/msm8909/sdm/libs/hwc2/hwc_display_external.h new file mode 100644 index 00000000..fbee6a3d --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_display_external.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2014-2017, 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" +#include "display_null.h" + +namespace sdm { + +class HWCDisplayExternal : public HWCDisplay { + public: + static int Create(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator, + 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, HWCBufferAllocator *buffer_allocator, + 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); + virtual int SetState(bool connected); + + private: + HWCDisplayExternal(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator, + HWCCallbacks *callbacks, qService::QService *qservice); + void ApplyScanAdjustment(hwc_rect_t *display_frame); + void GetUnderScanConfig(); + static void GetDownscaleResolution(uint32_t primary_width, uint32_t primary_height, + uint32_t *virtual_width, uint32_t *virtual_height); + + DisplayNull display_null_; + int underscan_width_ = 0; + int underscan_height_ = 0; +}; + +} // namespace sdm + +#endif // __HWC_DISPLAY_EXTERNAL_H__ diff --git a/msm8909/sdm/libs/hwc2/hwc_display_external_test.cpp b/msm8909/sdm/libs/hwc2/hwc_display_external_test.cpp new file mode 100644 index 00000000..fcbe326f --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_display_external_test.cpp @@ -0,0 +1,750 @@ +/* +* Copyright (c) 2017, 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 <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <utils/constants.h> +#include <utils/debug.h> +#include <utils/formats.h> +#include <algorithm> +#include <array> +#include <sstream> +#include <string> +#include <fstream> + +#include "hwc_display_external_test.h" +#include "hwc_debugger.h" + +#define __CLASS__ "HWCDisplayExternalTest" + +namespace sdm { + +using std::array; + +int HWCDisplayExternalTest::Create(CoreInterface *core_intf, + HWCBufferAllocator *buffer_allocator, + HWCCallbacks *callbacks, + qService::QService *qservice, uint32_t panel_bpp, + uint32_t pattern_type, HWCDisplay **hwc_display) { + HWCDisplay *hwc_external_test = new HWCDisplayExternalTest(core_intf, buffer_allocator, + callbacks, qservice, + panel_bpp, pattern_type); + + int status = static_cast<HWCDisplayExternalTest *>(hwc_external_test)->Init(); + if (status) { + delete hwc_external_test; + return status; + } + + *hwc_display = hwc_external_test; + + DLOGE("EXTERNAL panel_bpp %d, pattern_type %d", panel_bpp, pattern_type); + + return status; +} + +void HWCDisplayExternalTest::Destroy(HWCDisplay *hwc_display) { + static_cast<HWCDisplayExternalTest *>(hwc_display)->Deinit(); + + delete hwc_display; +} + +HWCDisplayExternalTest::HWCDisplayExternalTest(CoreInterface *core_intf, + HWCBufferAllocator *buffer_allocator, + HWCCallbacks *callbacks, + qService::QService *qservice, uint32_t panel_bpp, + uint32_t pattern_type) + : HWCDisplay(core_intf, callbacks, kHDMI, HWC_DISPLAY_EXTERNAL, false, qservice, + DISPLAY_CLASS_EXTERNAL, buffer_allocator), panel_bpp_(panel_bpp), + pattern_type_(pattern_type) { +} + +int HWCDisplayExternalTest::Init() { + uint32_t external_width = 0; + uint32_t external_height = 0; + + int status = HWCDisplay::Init(); + if (status) { + DLOGE("HWCDisplayExternalTest::Init status = %d ", status); + return status; + } + + status = CreateLayerStack(); + if (status) { + Deinit(); + return status; + } + + DisplayError error = HWCDisplay::GetMixerResolution(&external_width, &external_height); + if (error != kErrorNone) { + Deinit(); + return -EINVAL; + } + + status = HWCDisplay::SetFrameBufferResolution(external_width, external_height); + if (status) { + Deinit(); + DLOGE("HWCDisplayExternalTest:: set fb resolution status = %d ", status); + return status; + } + + return status; +} + +int HWCDisplayExternalTest::Deinit() { + DestroyLayerStack(); + return HWCDisplay::Deinit(); +} + + +HWC2::Error HWCDisplayExternalTest::Validate(uint32_t *out_num_types, uint32_t *out_num_requests) { + auto status = HWC2::Error::None; + if (secure_display_active_) { + MarkLayersForGPUBypass(); + return status; + } + + if (layer_set_.empty()) { + flush_ = true; + return status; + } + + if (shutdown_pending_) { + return status; + } + DisplayError error = display_intf_->Prepare(&layer_stack_); + if (error != kErrorNone) { + if (error == kErrorShutDown) { + shutdown_pending_ = true; + } else if (error != kErrorPermission) { + DLOGE("Prepare failed. Error = %d", error); + // To prevent surfaceflinger infinite wait, flush the previous frame during Commit() + // so that previous buffer and fences are released, and override the error. + flush_ = true; + } + } + + MarkLayersForGPUBypass(); + + return status; +} + +HWC2::Error HWCDisplayExternalTest::Present(int32_t *out_retire_fence) { + auto status = HWC2::Error::None; + + if (secure_display_active_) { + return status; + } + + if (shutdown_pending_) { + return status; + } + + DumpInputBuffer(); + + if (!flush_) { + DisplayError error = kErrorUndefined; + error = display_intf_->Commit(&layer_stack_); + if (error == kErrorNone) { + // A commit is successfully submitted, start flushing on failure now onwards. + flush_on_error_ = true; + } else { + if (error == kErrorShutDown) { + shutdown_pending_ = true; + return status; + } else if (error != kErrorPermission) { + DLOGE("Commit failed. Error = %d", error); + // To prevent surfaceflinger infinite wait, flush the previous frame during Commit() + // so that previous buffer and fences are released, and override the error. + flush_ = true; + } + } + } + + return PostCommit(out_retire_fence); +} + +void HWCDisplayExternalTest::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; +} + +int HWCDisplayExternalTest::Perform(uint32_t operation, ...) { + return 0; +} + +void HWCDisplayExternalTest::DumpInputBuffer() { + if (!dump_frame_count_ || flush_ || !dump_input_layers_) { + return; + } + + const char *dir_path = "/data/vendor/display/frame_dump_external"; + uint32_t width = buffer_info_.alloc_buffer_info.aligned_width; + uint32_t height = buffer_info_.alloc_buffer_info.aligned_height; + string format_str = GetFormatString(buffer_info_.buffer_config.format); + + char *buffer = reinterpret_cast<char *>(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) { + DLOGW("mmap failed. err = %d", errno); + return; + } + + if (mkdir(dir_path, 0777) != 0 && errno != EEXIST) { + DLOGW("Failed to create %s directory errno = %d, desc = %s", dir_path, errno, strerror(errno)); + return; + } + + // if directory exists already, need to explicitly change the permission. + if (errno == EEXIST && chmod(dir_path, 0777) != 0) { + DLOGW("Failed to change permissions on %s directory", dir_path); + return; + } + + if (buffer) { + std::stringstream dump_file_name; + dump_file_name << dir_path; + dump_file_name << "/input_layer_" << width << "x" << height << "_" << format_str << ".raw"; + + std::fstream fs; + fs.open(dump_file_name.str().c_str(), std::fstream::in | std::fstream::out | std::fstream::app); + if (!fs.is_open()) { + DLOGI("File open failed %s", dump_file_name.str().c_str()); + return; + } + + fs.write(buffer, (std::streamsize)buffer_info_.alloc_buffer_info.size); + fs.close(); + + DLOGI("Frame Dump %s: is successful", dump_file_name.str().c_str()); + } + + // Dump only once as the content is going to be same for all draw cycles + if (dump_frame_count_) { + dump_frame_count_ = 0; + } + + if (munmap(buffer, buffer_info_.alloc_buffer_info.size) != 0) { + DLOGW("munmap failed. err = %d", errno); + return; + } +} + +void HWCDisplayExternalTest::CalcCRC(uint32_t color_val, std::bitset<16> *crc_data) { + std::bitset<16> color = {}; + std::bitset<16> temp_crc = {}; + + switch (panel_bpp_) { + case kDisplayBpp18: + color = (color_val & 0xFC) << 8; + break; + case kDisplayBpp24: + color = color_val << 8; + break; + case kDisplayBpp30: + color = color_val << 6; + break; + default: + return; + } + + temp_crc[15] = (*crc_data)[0] ^ (*crc_data)[1] ^ (*crc_data)[2] ^ (*crc_data)[3] ^ + (*crc_data)[4] ^ (*crc_data)[5] ^ (*crc_data)[6] ^ (*crc_data)[7] ^ + (*crc_data)[8] ^ (*crc_data)[9] ^ (*crc_data)[10] ^ (*crc_data)[11] ^ + (*crc_data)[12] ^ (*crc_data)[14] ^ (*crc_data)[15] ^ color[0] ^ color[1] ^ + color[2] ^ color[3] ^ color[4] ^ color[5] ^ color[6] ^ color[7] ^ color[8] ^ + color[9] ^ color[10] ^ color[11] ^ color[12] ^ color[14] ^ color[15]; + + temp_crc[14] = (*crc_data)[12] ^ (*crc_data)[13] ^ color[12] ^ color[13]; + temp_crc[13] = (*crc_data)[11] ^ (*crc_data)[12] ^ color[11] ^ color[12]; + temp_crc[12] = (*crc_data)[10] ^ (*crc_data)[11] ^ color[10] ^ color[11]; + temp_crc[11] = (*crc_data)[9] ^ (*crc_data)[10] ^ color[9] ^ color[10]; + temp_crc[10] = (*crc_data)[8] ^ (*crc_data)[9] ^ color[8] ^ color[9]; + temp_crc[9] = (*crc_data)[7] ^ (*crc_data)[8] ^ color[7] ^ color[8]; + temp_crc[8] = (*crc_data)[6] ^ (*crc_data)[7] ^ color[6] ^ color[7]; + temp_crc[7] = (*crc_data)[5] ^ (*crc_data)[6] ^ color[5] ^ color[6]; + temp_crc[6] = (*crc_data)[4] ^ (*crc_data)[5] ^ color[4] ^ color[5]; + temp_crc[5] = (*crc_data)[3] ^ (*crc_data)[4] ^ color[3] ^ color[4]; + temp_crc[4] = (*crc_data)[2] ^ (*crc_data)[3] ^ color[2] ^ color[3]; + temp_crc[3] = (*crc_data)[1] ^ (*crc_data)[2] ^ (*crc_data)[15] ^ color[1] ^ color[2] ^ color[15]; + temp_crc[2] = (*crc_data)[0] ^ (*crc_data)[1] ^ (*crc_data)[14] ^ color[0] ^ color[1] ^ color[14]; + + temp_crc[1] = (*crc_data)[1] ^ (*crc_data)[2] ^ (*crc_data)[3] ^ (*crc_data)[4] ^ (*crc_data)[5] ^ + (*crc_data)[6] ^ (*crc_data)[7] ^ (*crc_data)[8] ^ (*crc_data)[9] ^ + (*crc_data)[10] ^ (*crc_data)[11] ^ (*crc_data)[12] ^ (*crc_data)[13] ^ + (*crc_data)[14] ^ color[1] ^ color[2] ^ color[3] ^ color[4] ^ color[5] ^ color[6] ^ + color[7] ^ color[8] ^ color[9] ^ color[10] ^ color[11] ^ color[12] ^ color[13] ^ + color[14]; + + temp_crc[0] = (*crc_data)[0] ^ (*crc_data)[1] ^ (*crc_data)[2] ^ (*crc_data)[3] ^ (*crc_data)[4] ^ + (*crc_data)[5] ^ (*crc_data)[6] ^ (*crc_data)[7] ^ (*crc_data)[8] ^ (*crc_data)[9] ^ + (*crc_data)[10] ^ (*crc_data)[11] ^ (*crc_data)[12] ^ (*crc_data)[13] ^ + (*crc_data)[15] ^ color[0] ^ color[1] ^ color[2] ^ color[3] ^ color[4] ^ color[5] ^ + color[6] ^ color[7] ^ color[8] ^ color[9] ^ color[10] ^ color[11] ^ color[12] ^ + color[13] ^ color[15]; + + (*crc_data) = temp_crc; +} + +int HWCDisplayExternalTest::FillBuffer() { + uint8_t *buffer = reinterpret_cast<uint8_t *>(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); + return -EFAULT; + } + + switch (pattern_type_) { + case kPatternColorRamp: + GenerateColorRamp(buffer); + break; + case kPatternBWVertical: + GenerateBWVertical(buffer); + break; + case kPatternColorSquare: + GenerateColorSquare(buffer); + break; + default: + DLOGW("Invalid Pattern type %d", pattern_type_); + return -EINVAL; + } + + if (munmap(buffer, buffer_info_.alloc_buffer_info.size) != 0) { + DLOGE("munmap failed. err = %d", errno); + return -EFAULT; + } + + return 0; +} + +int HWCDisplayExternalTest::GetStride(LayerBufferFormat format, uint32_t width, uint32_t *stride) { + switch (format) { + case kFormatRGBA8888: + case kFormatRGBA1010102: + *stride = width * 4; + break; + case kFormatRGB888: + *stride = width * 3; + break; + default: + DLOGE("Unsupported format type %d", format); + return -EINVAL; + } + + return 0; +} + +void HWCDisplayExternalTest::PixelCopy(uint32_t red, uint32_t green, uint32_t blue, uint32_t alpha, + uint8_t **buffer) { + LayerBufferFormat format = buffer_info_.buffer_config.format; + + switch (format) { + case kFormatRGBA8888: + *(*buffer)++ = UINT8(red & 0xFF); + *(*buffer)++ = UINT8(green & 0xFF); + *(*buffer)++ = UINT8(blue & 0xFF); + *(*buffer)++ = UINT8(alpha & 0xFF); + break; + case kFormatRGB888: + *(*buffer)++ = UINT8(red & 0xFF); + *(*buffer)++ = UINT8(green & 0xFF); + *(*buffer)++ = UINT8(blue & 0xFF); + break; + case kFormatRGBA1010102: + // Lower 8 bits of red + *(*buffer)++ = UINT8(red & 0xFF); + + // Upper 2 bits of Red + Lower 6 bits of green + *(*buffer)++ = UINT8(((green & 0x3F) << 2) | ((red >> 0x8) & 0x3)); + + // Upper 4 bits of green + Lower 4 bits of blue + *(*buffer)++ = UINT8(((blue & 0xF) << 4) | ((green >> 6) & 0xF)); + + // Upper 6 bits of blue + Lower 2 bits of alpha + *(*buffer)++ = UINT8(((alpha & 0x3) << 6) | ((blue >> 4) & 0x3F)); + break; + default: + DLOGW("format not supported format = %d", format); + break; + } +} + +void HWCDisplayExternalTest::GenerateColorRamp(uint8_t *buffer) { + uint32_t width = buffer_info_.buffer_config.width; + uint32_t height = buffer_info_.buffer_config.height; + LayerBufferFormat format = buffer_info_.buffer_config.format; + uint32_t aligned_width = buffer_info_.alloc_buffer_info.aligned_width; + uint32_t buffer_stride = 0; + + uint32_t color_ramp = 0; + uint32_t start_color_val = 0; + uint32_t step_size = 1; + uint32_t ramp_width = 0; + uint32_t ramp_height = 0; + uint32_t shift_by = 0; + + std::bitset<16> crc_red = {}; + std::bitset<16> crc_green = {}; + std::bitset<16> crc_blue = {}; + + switch (panel_bpp_) { + case kDisplayBpp18: + ramp_height = 64; + ramp_width = 64; + shift_by = 2; + break; + case kDisplayBpp24: + ramp_height = 64; + ramp_width = 256; + break; + case kDisplayBpp30: + ramp_height = 32; + ramp_width = 256; + start_color_val = 0x180; + break; + default: + return; + } + + GetStride(format, aligned_width, &buffer_stride); + + for (uint32_t loop_height = 0; loop_height < height; loop_height++) { + uint32_t color_value = start_color_val; + uint8_t *temp = buffer + (loop_height * buffer_stride); + + for (uint32_t loop_width = 0; loop_width < width; loop_width++) { + if (color_ramp == kColorRedRamp) { + PixelCopy(color_value, 0, 0, 0, &temp); + CalcCRC(color_value, &crc_red); + CalcCRC(0, &crc_green); + CalcCRC(0, &crc_blue); + } + if (color_ramp == kColorGreenRamp) { + PixelCopy(0, color_value, 0, 0, &temp); + CalcCRC(0, &crc_red); + CalcCRC(color_value, &crc_green); + CalcCRC(0, &crc_blue); + } + if (color_ramp == kColorBlueRamp) { + PixelCopy(0, 0, color_value, 0, &temp); + CalcCRC(0, &crc_red); + CalcCRC(0, &crc_green); + CalcCRC(color_value, &crc_blue); + } + if (color_ramp == kColorWhiteRamp) { + PixelCopy(color_value, color_value, color_value, 0, &temp); + CalcCRC(color_value, &crc_red); + CalcCRC(color_value, &crc_green); + CalcCRC(color_value, &crc_blue); + } + + color_value = (start_color_val + (((loop_width + 1) % ramp_width) * step_size)) << shift_by; + } + + if (panel_bpp_ == kDisplayBpp30 && ((loop_height + 1) % ramp_height) == 0) { + if (start_color_val == 0x180) { + start_color_val = 0; + step_size = 4; + } else { + start_color_val = 0x180; + step_size = 1; + color_ramp = (color_ramp + 1) % 4; + } + continue; + } + + if (((loop_height + 1) % ramp_height) == 0) { + color_ramp = (color_ramp + 1) % 4; + } + } + + DLOGI("CRC red %x", crc_red.to_ulong()); + DLOGI("CRC green %x", crc_green.to_ulong()); + DLOGI("CRC blue %x", crc_blue.to_ulong()); +} + +void HWCDisplayExternalTest::GenerateBWVertical(uint8_t *buffer) { + uint32_t width = buffer_info_.buffer_config.width; + uint32_t height = buffer_info_.buffer_config.height; + LayerBufferFormat format = buffer_info_.buffer_config.format; + uint32_t aligned_width = buffer_info_.alloc_buffer_info.aligned_width; + uint32_t buffer_stride = 0; + uint32_t bits_per_component = panel_bpp_ / 3; + uint32_t max_color_val = (1 << bits_per_component) - 1; + + std::bitset<16> crc_red = {}; + std::bitset<16> crc_green = {}; + std::bitset<16> crc_blue = {}; + + if (panel_bpp_ == kDisplayBpp18) { + max_color_val <<= 2; + } + + GetStride(format, aligned_width, &buffer_stride); + + for (uint32_t loop_height = 0; loop_height < height; loop_height++) { + uint32_t color = 0; + uint8_t *temp = buffer + (loop_height * buffer_stride); + + for (uint32_t loop_width = 0; loop_width < width; loop_width++) { + if (color == kColorBlack) { + PixelCopy(0, 0, 0, 0, &temp); + CalcCRC(0, &crc_red); + CalcCRC(0, &crc_green); + CalcCRC(0, &crc_blue); + } + if (color == kColorWhite) { + PixelCopy(max_color_val, max_color_val, max_color_val, 0, &temp); + CalcCRC(max_color_val, &crc_red); + CalcCRC(max_color_val, &crc_green); + CalcCRC(max_color_val, &crc_blue); + } + + color = (color + 1) % 2; + } + } + + DLOGI("CRC red %x", crc_red.to_ulong()); + DLOGI("CRC green %x", crc_green.to_ulong()); + DLOGI("CRC blue %x", crc_blue.to_ulong()); +} + +void HWCDisplayExternalTest::GenerateColorSquare(uint8_t *buffer) { + uint32_t width = buffer_info_.buffer_config.width; + uint32_t height = buffer_info_.buffer_config.height; + LayerBufferFormat format = buffer_info_.buffer_config.format; + uint32_t aligned_width = buffer_info_.alloc_buffer_info.aligned_width; + uint32_t buffer_stride = 0; + uint32_t max_color_val = 0; + uint32_t min_color_val = 0; + + std::bitset<16> crc_red = {}; + std::bitset<16> crc_green = {}; + std::bitset<16> crc_blue = {}; + + switch (panel_bpp_) { + case kDisplayBpp18: + max_color_val = 63 << 2; // CEA Dynamic range for 18bpp 0 - 63 + min_color_val = 0; + break; + case kDisplayBpp24: + max_color_val = 235; // CEA Dynamic range for 24bpp 16 - 235 + min_color_val = 16; + break; + case kDisplayBpp30: + max_color_val = 940; // CEA Dynamic range for 30bpp 64 - 940 + min_color_val = 64; + break; + default: + return; + } + + array<array<uint32_t, 3>, 8> colors = {{ + {{max_color_val, max_color_val, max_color_val}}, // White Color + {{max_color_val, max_color_val, min_color_val}}, // Yellow Color + {{min_color_val, max_color_val, max_color_val}}, // Cyan Color + {{min_color_val, max_color_val, min_color_val}}, // Green Color + {{max_color_val, min_color_val, max_color_val}}, // Megenta Color + {{max_color_val, min_color_val, min_color_val}}, // Red Color + {{min_color_val, min_color_val, max_color_val}}, // Blue Color + {{min_color_val, min_color_val, min_color_val}}, // Black Color + }}; + + GetStride(format, aligned_width, &buffer_stride); + + for (uint32_t loop_height = 0; loop_height < height; loop_height++) { + uint32_t color = 0; + uint8_t *temp = buffer + (loop_height * buffer_stride); + + for (uint32_t loop_width = 0; loop_width < width; loop_width++) { + PixelCopy(colors[color][0], colors[color][1], colors[color][2], 0, &temp); + CalcCRC(colors[color][0], &crc_red); + CalcCRC(colors[color][1], &crc_green); + CalcCRC(colors[color][2], &crc_blue); + + if (((loop_width + 1) % 64) == 0) { + color = (color + 1) % colors.size(); + } + } + + if (((loop_height + 1) % 64) == 0) { + std::reverse(colors.begin(), (colors.end() - 1)); + } + } + + DLOGI("CRC red %x", crc_red.to_ulong()); + DLOGI("CRC green %x", crc_green.to_ulong()); + DLOGI("CRC blue %x", crc_blue.to_ulong()); +} + +int HWCDisplayExternalTest::InitLayer(Layer *layer) { + uint32_t active_config = 0; + DisplayConfigVariableInfo var_info = {}; + + GetActiveDisplayConfig(&active_config); + + GetDisplayAttributesForConfig(INT32(active_config), &var_info); + + layer->flags.updating = 1; + layer->src_rect = LayerRect(0, 0, var_info.x_pixels, var_info.y_pixels); + layer->dst_rect = layer->src_rect; + layer->frame_rate = var_info.fps; + layer->blending = kBlendingPremultiplied; + + layer->input_buffer.unaligned_width = var_info.x_pixels; + layer->input_buffer.unaligned_height = var_info.y_pixels; + buffer_info_.buffer_config.format = kFormatRGBA8888; + + if (layer->composition != kCompositionGPUTarget) { + buffer_info_.buffer_config.width = var_info.x_pixels; + buffer_info_.buffer_config.height = var_info.y_pixels; + switch (panel_bpp_) { + case kDisplayBpp18: + case kDisplayBpp24: + buffer_info_.buffer_config.format = kFormatRGB888; + break; + case kDisplayBpp30: + buffer_info_.buffer_config.format = kFormatRGBA1010102; + break; + default: + DLOGW("panel bpp not supported %d", panel_bpp_); + return -EINVAL; + } + buffer_info_.buffer_config.buffer_count = 1; + + int ret = buffer_allocator_->AllocateBuffer(&buffer_info_); + if (ret != 0) { + DLOGE("Buffer allocation failed. ret: %d", ret); + return -ENOMEM; + } + + ret = FillBuffer(); + if (ret != 0) { + buffer_allocator_->FreeBuffer(&buffer_info_); + return ret; + } + + layer->input_buffer.width = buffer_info_.alloc_buffer_info.aligned_width; + layer->input_buffer.height = buffer_info_.alloc_buffer_info.aligned_height; + layer->input_buffer.size = buffer_info_.alloc_buffer_info.size; + layer->input_buffer.planes[0].fd = buffer_info_.alloc_buffer_info.fd; + layer->input_buffer.planes[0].stride = buffer_info_.alloc_buffer_info.stride; + layer->input_buffer.format = buffer_info_.buffer_config.format; + + DLOGI("Input buffer WxH %dx%d format %s size %d fd %d stride %d", layer->input_buffer.width, + layer->input_buffer.height, GetFormatString(layer->input_buffer.format), + layer->input_buffer.size, layer->input_buffer.planes[0].fd, + layer->input_buffer.planes[0].stride); + } + + return 0; +} + +int HWCDisplayExternalTest::DeinitLayer(Layer *layer) { + if (layer->composition != kCompositionGPUTarget) { + int ret = buffer_allocator_->FreeBuffer(&buffer_info_); + if (ret != 0) { + DLOGE("Buffer deallocation failed. ret: %d", ret); + return -ENOMEM; + } + } + + return 0; +} + +int HWCDisplayExternalTest::CreateLayerStack() { + for (uint32_t i = 0; i < (kTestLayerCnt + 1 /* one dummy gpu_target layer */); i++) { + Layer *layer = new Layer(); + + if (i == kTestLayerCnt) { + layer->composition = kCompositionGPUTarget; + } + DLOGE("External :: CreateLayerStack %d", i); + int ret = InitLayer(layer); + if (ret != 0) { + delete layer; + return ret; + } + layer_stack_.layers.push_back(layer); + } + + return 0; +} + +int HWCDisplayExternalTest::DestroyLayerStack() { + for (uint32_t i = 0; i < UINT32(layer_stack_.layers.size()); i++) { + Layer *layer = layer_stack_.layers.at(i); + int ret = DeinitLayer(layer); + if (ret != 0) { + return ret; + } + delete layer; + } + layer_stack_.layers = {}; + return 0; +} + +HWC2::Error HWCDisplayExternalTest::PostCommit(int32_t *out_retire_fence) { + auto status = HWC2::Error::None; + // Do no call flush on errors, if a successful buffer is never submitted. + if (flush_ && flush_on_error_) { + display_intf_->Flush(); + } + if (!flush_) { + for (size_t i = 0; i < layer_stack_.layers.size(); i++) { + Layer *layer = layer_stack_.layers.at(i); + LayerBuffer &layer_buffer = layer->input_buffer; + + close(layer_buffer.release_fence_fd); + layer_buffer.release_fence_fd = -1; + } + close(layer_stack_.retire_fence_fd); + layer_stack_.retire_fence_fd = -1; + *out_retire_fence = -1; + } + + flush_ = false; + return status; +} + +} // namespace sdm + diff --git a/msm8909/sdm/libs/hwc2/hwc_display_external_test.h b/msm8909/sdm/libs/hwc2/hwc_display_external_test.h new file mode 100644 index 00000000..e2c13f58 --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_display_external_test.h @@ -0,0 +1,102 @@ +/* +* Copyright (c) 2017, 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_TEST_H__ +#define __HWC_DISPLAY_EXTERNAL_TEST_H__ + +#include<bitset> + +#include "hwc_display.h" +#include "hwc_buffer_allocator.h" + +namespace sdm { + +class HWCDisplayExternalTest : public HWCDisplay { + public: + static int Create(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator, + HWCCallbacks *callbacks, qService::QService *qservice, + uint32_t panel_bpp, uint32_t pattern_type, 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); + virtual int Perform(uint32_t operation, ...); + + protected: + BufferInfo buffer_info_ = {}; + uint32_t panel_bpp_ = 0; + uint32_t pattern_type_ = 0; + + enum ColorPatternType { + kPatternNone = 0, + kPatternColorRamp, + kPatternBWVertical, + kPatternColorSquare, + }; + + enum DisplayBpp { + kDisplayBpp18 = 18, + kDisplayBpp24 = 24, + kDisplayBpp30 = 30, + }; + + enum ColorRamp { + kColorRedRamp = 0, + kColorGreenRamp = 1, + kColorBlueRamp = 2, + kColorWhiteRamp = 3, + }; + + enum Colors { + kColorBlack = 0, + kColorWhite = 1, + }; + + private: + HWCDisplayExternalTest(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator, + HWCCallbacks *callbacks, qService::QService *qservice, + uint32_t panel_bpp, uint32_t pattern_type); + int Init(); + int Deinit(); + void DumpInputBuffer(); + void CalcCRC(uint32_t color_value, std::bitset<16> *crc_data); + int FillBuffer(); + int GetStride(LayerBufferFormat format, uint32_t width, uint32_t *stride); + void PixelCopy(uint32_t red, uint32_t green, uint32_t blue, uint32_t alpha, uint8_t **buffer); + void GenerateColorRamp(uint8_t *buffer); + void GenerateBWVertical(uint8_t *buffer); + void GenerateColorSquare(uint8_t *buffer); + int InitLayer(Layer *layer); + int DeinitLayer(Layer *layer); + int CreateLayerStack(); + int DestroyLayerStack(); + HWC2::Error PostCommit(int32_t *out_retire_fence); + + static const uint32_t kTestLayerCnt = 1; +}; + +} // namespace sdm + +#endif // __HWC_DISPLAY_EXTERNAL_TEST_H__ + diff --git a/msm8909/sdm/libs/hwc2/hwc_display_primary.cpp b/msm8909/sdm/libs/hwc2/hwc_display_primary.cpp new file mode 100644 index 00000000..5a6bddd6 --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_display_primary.cpp @@ -0,0 +1,620 @@ +/* +* Copyright (c) 2014 - 2018, 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 <map> +#include <string> +#include <vector> + +#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->GetMixerResolution(&primary_width, &primary_height); + int width = 0, height = 0; + HWCDebugHandler::Get()->GetProperty(FB_WIDTH_PROP, &width); + HWCDebugHandler::Get()->GetProperty(FB_HEIGHT_PROP, &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_(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(DISABLE_METADATA_DYNAMIC_FPS_PROP, &disable_metadata_dynfps); + if (disable_metadata_dynfps) { + use_metadata_refresh_rate_ = false; + } + + int status = HWCDisplay::Init(); + if (status) { + return status; + } + color_mode_ = new HWCColorMode(display_intf_); + color_mode_->Init(); + HWCDebugHandler::Get()->GetProperty(ENABLE_DEFAULT_COLOR_MODE, &default_mode_status_); + + return status; +} + +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 property[PROPERTY_VALUE_MAX]; + bool isEncrypted = false; + bool main_class_services_started = false; + property_get("ro.crypto.state", property, "unencrypted"); + if (!strcmp(property, "encrypted")) { + property_get("ro.crypto.type", property, "block"); + if (!strcmp(property, "block")) { + isEncrypted = true; + property_get("vold.decrypt", property, ""); + if (!strcmp(property, "trigger_restart_framework")) { + main_class_services_started = true; + } + } + } + + if ((!isEncrypted || (isEncrypted && main_class_services_started)) && + (layer_set_.size() > numBootUpLayers)) { + DLOGI("Applying default mode"); + 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(); + RestoreColorTransform(); + } + } +} + +HWC2::Error HWCDisplayPrimary::Validate(uint32_t *out_num_types, uint32_t *out_num_requests) { + auto status = HWC2::Error::None; + DisplayError error = kErrorNone; + + if (default_mode_status_ && !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(); + + if (color_tranform_failed_) { + // Must fall back to client composition + MarkLayersForClientComposition(); + } + + // Checks and replaces layer stack for solid fill + SolidFillPrepare(); + + 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_; + } + + uint32_t num_updating_layers = GetUpdatingLayersCount(); + bool one_updating_layer = (num_updating_layers == 1); + if (num_updating_layers != 0) { + ToggleCPUHint(one_updating_layer); + } + + uint32_t refresh_rate = GetOptimalRefreshRate(one_updating_layer); + if (current_refresh_rate_ != refresh_rate || handle_idle_timeout_) { + 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; + } + + if (layer_set_.empty()) { + // Avoid flush for Command mode panel. + DisplayConfigFixedInfo display_config; + display_intf_->GetConfig(&display_config); + flush_ = !display_config.is_cmdmode; + 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(); + SolidFillCommit(); + status = HWCDisplay::PostCommitLayerStack(out_retire_fence); + } + } + + CloseAcquireFds(); + return status; +} + +HWC2::Error HWCDisplayPrimary::GetColorModes(uint32_t *out_num_modes, + android_color_mode_t *out_modes) { + if (out_modes == nullptr) { + *out_num_modes = color_mode_->GetColorModeCount(); + } else { + color_mode_->GetColorModes(out_num_modes, out_modes); + } + + return HWC2::Error::None; +} + +HWC2::Error HWCDisplayPrimary::SetColorMode(android_color_mode_t mode) { + auto status = color_mode_->SetColorMode(mode); + if (status != HWC2::Error::None) { + DLOGE("failed for mode = %d", mode); + return status; + } + + callbacks_->Refresh(HWC_DISPLAY_PRIMARY); + validated_.reset(); + + return status; +} + +HWC2::Error HWCDisplayPrimary::RestoreColorTransform() { + auto status = color_mode_->RestoreColorTransform(); + if (status != HWC2::Error::None) { + DLOGE("failed to RestoreColorTransform"); + return status; + } + + callbacks_->Refresh(HWC_DISPLAY_PRIMARY); + + return status; +} + +HWC2::Error HWCDisplayPrimary::SetColorTransform(const float *matrix, + android_color_transform_t hint) { + if (!matrix) { + return HWC2::Error::BadParameter; + } + + auto status = color_mode_->SetColorTransform(matrix, hint); + if ((hint != HAL_COLOR_TRANSFORM_IDENTITY) && (status != HWC2::Error::None)) { + DLOGE("failed for hint = %d", hint); + color_tranform_failed_ = true; + return status; + } + + callbacks_->Refresh(HWC_DISPLAY_PRIMARY); + color_tranform_failed_ = false; + validated_.reset(); + + return status; +} + +int HWCDisplayPrimary::Perform(uint32_t operation, ...) { + va_list args; + va_start(args, operation); + int val = 0; + LayerRect *rect = NULL; + + switch (operation) { + case SET_METADATA_DYN_REFRESH_RATE: + val = va_arg(args, int32_t); + SetMetaDataRefreshRateFlag(val); + break; + case SET_BINDER_DYN_REFRESH_RATE: + val = va_arg(args, int32_t); + ForceRefreshRate(UINT32(val)); + break; + case SET_DISPLAY_MODE: + val = va_arg(args, int32_t); + SetDisplayMode(UINT32(val)); + break; + case SET_QDCM_SOLID_FILL_INFO: + val = va_arg(args, int32_t); + SetQDCMSolidFillInfo(true, UINT32(val)); + break; + case UNSET_QDCM_SOLID_FILL_INFO: + val = va_arg(args, int32_t); + SetQDCMSolidFillInfo(false, UINT32(val)); + break; + case SET_QDCM_SOLID_FILL_RECT: + rect = va_arg(args, LayerRect*); + solid_fill_rect_ = *rect; + break; + default: + DLOGW("Invalid operation %d", operation); + va_end(args); + return -EINVAL; + } + va_end(args); + validated_.reset(); + + 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(DISABLE_METADATA_DYNAMIC_FPS_PROP, &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; + + // Avoid flush for Command mode panel. + DisplayConfigFixedInfo display_config; + display_intf_->GetConfig(&display_config); + skip_prepare_ = !display_config.is_cmdmode; + } +} + +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); + validated_.reset(); +} + +static void SetLayerBuffer(const BufferInfo &output_buffer_info, LayerBuffer *output_buffer) { + const BufferConfig& buffer_config = output_buffer_info.buffer_config; + const AllocatedBufferInfo &alloc_buffer_info = output_buffer_info.alloc_buffer_info; + + output_buffer->width = alloc_buffer_info.aligned_width; + output_buffer->height = alloc_buffer_info.aligned_height; + output_buffer->unaligned_width = buffer_config.width; + output_buffer->unaligned_height = buffer_config.height; + output_buffer->format = buffer_config.format; + output_buffer->planes[0].fd = alloc_buffer_info.fd; + output_buffer->planes[0].stride = 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_ = {}; +} + +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; + } +} + +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; + DisablePartialUpdateOneFrame(); + validated_.reset(); +} + +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; + DisablePartialUpdateOneFrame(); + + return 0; +} + +DisplayError HWCDisplayPrimary::SetDetailEnhancerConfig + (const DisplayDetailEnhancerData &de_data) { + DisplayError error = kErrorNotSupported; + + if (display_intf_) { + error = display_intf_->SetDetailEnhancerData(de_data); + validated_.reset(); + } + return error; +} + +DisplayError HWCDisplayPrimary::ControlPartialUpdate(bool enable, uint32_t *pending) { + DisplayError error = kErrorNone; + + if (display_intf_) { + error = display_intf_->ControlPartialUpdate(enable, pending); + validated_.reset(); + } + + return error; +} + +DisplayError HWCDisplayPrimary::DisablePartialUpdateOneFrame() { + DisplayError error = kErrorNone; + + if (display_intf_) { + error = display_intf_->DisablePartialUpdateOneFrame(); + validated_.reset(); + } + + return error; +} + + +DisplayError HWCDisplayPrimary::SetMixerResolution(uint32_t width, uint32_t height) { + DisplayError error = display_intf_->SetMixerResolution(width, height); + validated_.reset(); + return error; +} + +DisplayError HWCDisplayPrimary::GetMixerResolution(uint32_t *width, uint32_t *height) { + return display_intf_->GetMixerResolution(width, height); +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/hwc2/hwc_display_primary.h b/msm8909/sdm/libs/hwc2/hwc_display_primary.h new file mode 100644 index 00000000..b5a522d3 --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_display_primary.h @@ -0,0 +1,110 @@ +/* + * 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 <string> + +#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, + SET_QDCM_SOLID_FILL_RECT, + }; + + 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 HWC2::Error GetColorModes(uint32_t *out_num_modes, android_color_mode_t *out_modes); + virtual HWC2::Error SetColorMode(android_color_mode_t mode); + virtual HWC2::Error SetColorTransform(const float *matrix, android_color_transform_t hint); + virtual HWC2::Error RestoreColorTransform(); + 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_; } + virtual DisplayError SetDetailEnhancerConfig(const DisplayDetailEnhancerData &de_data); + virtual DisplayError ControlPartialUpdate(bool enable, uint32_t *pending); + + private: + HWCDisplayPrimary(CoreInterface *core_intf, BufferAllocator *buffer_allocator, + HWCCallbacks *callbacks, qService::QService *qservice); + void SetMetaDataRefreshRateFlag(bool enable); + virtual DisplayError SetDisplayMode(uint32_t mode); + virtual DisplayError DisablePartialUpdateOneFrame(); + 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(); + DisplayError SetMixerResolution(uint32_t width, uint32_t height); + DisplayError GetMixerResolution(uint32_t *width, uint32_t *height); + + 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; + int default_mode_status_ = 0; +}; + +} // namespace sdm + +#endif // __HWC_DISPLAY_PRIMARY_H__ diff --git a/msm8909/sdm/libs/hwc2/hwc_display_virtual.cpp b/msm8909/sdm/libs/hwc2/hwc_display_virtual.cpp new file mode 100644 index 00000000..232819ea --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_display_virtual.cpp @@ -0,0 +1,263 @@ +/* +* Copyright (c) 2014-2018, 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> +#ifndef USE_GRALLOC1 +#include <gr.h> +#endif + +#include "hwc_display_virtual.h" +#include "hwc_debugger.h" + +#define __CLASS__ "HWCDisplayVirtual" + +namespace sdm { + +int HWCDisplayVirtual::Create(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator, + HWCCallbacks *callbacks, uint32_t width, + uint32_t height, int32_t *format, HWCDisplay **hwc_display) { + int status = 0; + HWCDisplayVirtual *hwc_display_virtual = new HWCDisplayVirtual(core_intf, buffer_allocator, + callbacks); + + // TODO(user): Populate format correctly + DLOGI("Creating virtual display: w: %d h:%d format:0x%x", width, height, *format); + + status = hwc_display_virtual->Init(); + if (status) { + DLOGW("Failed to initialize virtual display"); + delete hwc_display_virtual; + return status; + } + + status = INT32(hwc_display_virtual->SetPowerMode(HWC2::PowerMode::On)); + if (status) { + DLOGW("Failed to set power mode on virtual display"); + Destroy(hwc_display_virtual); + return status; + } + + status = hwc_display_virtual->SetConfig(width, height); + if (status) { + Destroy(hwc_display_virtual); + return status; + } + + // TODO(user): Validate that we support this width/height + status = hwc_display_virtual->SetFrameBufferResolution(width, height); + + if (status) { + DLOGW("Failed to set virtual display FB resolution"); + 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, HWCBufferAllocator *buffer_allocator, + HWCCallbacks *callbacks) + : HWCDisplay(core_intf, callbacks, kVirtual, HWC_DISPLAY_VIRTUAL, false, NULL, + DISPLAY_CLASS_VIRTUAL, buffer_allocator) { +} + +int HWCDisplayVirtual::Init() { + output_buffer_ = new LayerBuffer(); + return HWCDisplay::Init(); +} + +int HWCDisplayVirtual::Deinit() { + int status = 0; + if (output_buffer_) { + if (output_buffer_->acquire_fence_fd >= 0) { + close(output_buffer_->acquire_fence_fd); + output_buffer_->acquire_fence_fd = -1; + } + delete output_buffer_; + output_buffer_ = nullptr; + } + 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(); + layer_stack_.output_buffer = output_buffer_; + + if (layer_set_.empty()) { + DLOGI("Skipping Validate and Commit"); + return status; + } + 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_) { + BufferInfo buffer_info; + const private_handle_t *output_handle = + reinterpret_cast<const private_handle_t *>(output_buffer_->buffer_id); + DisplayError error = kErrorNone; + if (!output_handle->base) { + error = buffer_allocator_->MapBuffer(output_handle, -1); + if (error != kErrorNone) { + DLOGE("Failed to map output buffer, error = %d", error); + return HWC2::Error::BadParameter; + } + } + 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); + + int release_fence = -1; + error = buffer_allocator_->UnmapBuffer(output_handle, &release_fence); + if (error != kErrorNone) { + DLOGE("Failed to unmap buffer, error = %d", error); + return HWC2::Error::BadParameter; + } + } + } + + status = HWCDisplay::PostCommitLayerStack(out_retire_fence); + } + } + CloseAcquireFds(); + if (output_buffer_->acquire_fence_fd >= 0) { + close(output_buffer_->acquire_fence_fd); + output_buffer_->acquire_fence_fd = -1; + } + return status; +} + +int HWCDisplayVirtual::SetConfig(uint32_t width, uint32_t height) { + DisplayConfigVariableInfo variable_info; + variable_info.x_pixels = width; + variable_info.y_pixels = height; + // TODO(user): Need to get the framerate of primary display and update it. + variable_info.fps = 60; + return display_intf_->SetActiveConfig(&variable_info); +} + +HWC2::Error HWCDisplayVirtual::SetOutputBuffer(buffer_handle_t buf, int32_t release_fence) { + if (buf == nullptr || release_fence == 0) { + return HWC2::Error::BadParameter; + } + 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_handle_ = 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 aligned_width, aligned_height; +#ifdef USE_GRALLOC1 + buffer_allocator_->GetCustomWidthAndHeight(output_handle, &aligned_width, &aligned_height); +#else + AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(output_handle, aligned_width, + aligned_height); +#endif + + output_buffer_->width = UINT32(aligned_width); + output_buffer_->height = UINT32(aligned_height); + output_buffer_->unaligned_width = UINT32(output_handle->unaligned_width); + output_buffer_->unaligned_height = UINT32(output_handle->unaligned_height); + output_buffer_->flags.secure = 0; + output_buffer_->flags.video = 0; + + if (sdm::SetCSC(output_handle, &output_buffer_->color_metadata) != kErrorNone) { + return HWC2::Error::BadParameter; + } + + // 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); + } + + 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 diff --git a/msm8909/sdm/libs/hwc2/hwc_display_virtual.h b/msm8909/sdm/libs/hwc2/hwc_display_virtual.h new file mode 100644 index 00000000..36e85091 --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_display_virtual.h @@ -0,0 +1,64 @@ +/* + * 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, HWCBufferAllocator *buffer_allocator, + HWCCallbacks *callbacks, uint32_t width, + uint32_t height, int32_t *format, 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, HWCBufferAllocator *buffer_allocator, + HWCCallbacks *callbacks); + int SetConfig(uint32_t width, uint32_t height); + + bool dump_output_layer_ = false; + LayerBuffer *output_buffer_ = NULL; + const private_handle_t *output_handle_ = nullptr; +}; + +} // namespace sdm + +#endif // __HWC_DISPLAY_VIRTUAL_H__ diff --git a/msm8909/sdm/libs/hwc2/hwc_layers.cpp b/msm8909/sdm/libs/hwc2/hwc_layers.cpp new file mode 100644 index 00000000..23c42aa7 --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_layers.cpp @@ -0,0 +1,827 @@ +/* + * Copyright (c) 2014-2017, 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 <stdint.h> +#include <qdMetaData.h> + +#include "hwc_layers.h" +#ifndef USE_GRALLOC1 +#include <gr.h> +#endif +#include <utils/debug.h> +#include <cmath> + +#define __CLASS__ "HWCLayer" + +namespace sdm { + +std::atomic<hwc2_layer_t> HWCLayer::next_id_(1); + +DisplayError SetCSC(const private_handle_t *pvt_handle, ColorMetaData *color_metadata) { + if (getMetaData(const_cast<private_handle_t *>(pvt_handle), GET_COLOR_METADATA, + color_metadata) != 0) { + ColorSpace_t csc = ITU_R_601; + if (getMetaData(const_cast<private_handle_t *>(pvt_handle), GET_COLOR_SPACE, + &csc) == 0) { + if (csc == ITU_R_601_FR || csc == ITU_R_2020_FR) { + color_metadata->range = Range_Full; + } + + switch (csc) { + case ITU_R_601: + case ITU_R_601_FR: + // video and display driver uses 601_525 + color_metadata->colorPrimaries = ColorPrimaries_BT601_6_525; + break; + case ITU_R_709: + color_metadata->colorPrimaries = ColorPrimaries_BT709_5; + break; + case ITU_R_2020: + case ITU_R_2020_FR: + color_metadata->colorPrimaries = ColorPrimaries_BT2020; + break; + default: + DLOGE("Unsupported CSC: %d", csc); + return kErrorNotSupported; + } + } else { + return kErrorNotSupported; + } + } + + return kErrorNone; +} + +// Returns true when color primary is supported +bool GetColorPrimary(const int32_t &dataspace, ColorPrimaries *color_primary) { + auto standard = dataspace & HAL_DATASPACE_STANDARD_MASK; + bool supported_csc = true; + switch (standard) { + case HAL_DATASPACE_STANDARD_BT709: + *color_primary = ColorPrimaries_BT709_5; + break; + case HAL_DATASPACE_STANDARD_BT601_525: + case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED: + *color_primary = ColorPrimaries_BT601_6_525; + break; + case HAL_DATASPACE_STANDARD_BT601_625: + case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED: + *color_primary = ColorPrimaries_BT601_6_625; + break; + case HAL_DATASPACE_STANDARD_DCI_P3: + *color_primary = ColorPrimaries_DCIP3; + break; + case HAL_DATASPACE_STANDARD_BT2020: + *color_primary = ColorPrimaries_BT2020; + break; + default: + DLOGV_IF(kTagClient, "Unsupported Standard Request = %d", standard); + supported_csc = false; + } + return supported_csc; +} + +bool GetTransfer(const int32_t &dataspace, GammaTransfer *gamma_transfer) { + auto transfer = dataspace & HAL_DATASPACE_TRANSFER_MASK; + bool supported_transfer = true; + switch (transfer) { + case HAL_DATASPACE_TRANSFER_SRGB: + *gamma_transfer = Transfer_sRGB; + break; + case HAL_DATASPACE_TRANSFER_SMPTE_170M: + *gamma_transfer = Transfer_SMPTE_170M; + break; + case HAL_DATASPACE_TRANSFER_ST2084: + *gamma_transfer = Transfer_SMPTE_ST2084; + break; + case HAL_DATASPACE_TRANSFER_HLG: + *gamma_transfer = Transfer_HLG; + break; + case HAL_DATASPACE_TRANSFER_LINEAR: + *gamma_transfer = Transfer_Linear; + break; + case HAL_DATASPACE_TRANSFER_GAMMA2_2: + *gamma_transfer = Transfer_Gamma2_2; + break; + default: + DLOGV_IF(kTagClient, "Unsupported Transfer Request = %d", transfer); + supported_transfer = false; + } + return supported_transfer; +} + +void GetRange(const int32_t &dataspace, ColorRange *color_range) { + auto range = dataspace & HAL_DATASPACE_RANGE_MASK; + switch (range) { + case HAL_DATASPACE_RANGE_FULL: + *color_range = Range_Full; + break; + case HAL_DATASPACE_RANGE_LIMITED: + *color_range = Range_Limited; + break; + default: + DLOGV_IF(kTagClient, "Unsupported Range Request = %d", range); + break; + } +} + +bool IsBT2020(const ColorPrimaries &color_primary) { + switch (color_primary) { + case ColorPrimaries_BT2020: + return true; + break; + default: + return false; + } +} + +// Retrieve ColorMetaData from android_data_space_t (STANDARD|TRANSFER|RANGE) +bool GetSDMColorSpace(const int32_t &dataspace, ColorMetaData *color_metadata) { + bool valid = false; + valid = GetColorPrimary(dataspace, &(color_metadata->colorPrimaries)); + if (!valid) { + return valid; + } + valid = GetTransfer(dataspace, &(color_metadata->transfer)); + if (!valid) { + return valid; + } + GetRange(dataspace, &(color_metadata->range)); + + return true; +} + +// Layer operations +HWCLayer::HWCLayer(hwc2_display_t display_id, HWCBufferAllocator *buf_allocator) + : id_(next_id_++), display_id_(display_id), buffer_allocator_(buf_allocator) { + layer_ = new Layer(); + // 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(); + } + close(ion_fd_); + if (layer_) { + 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; + } + + if (acquire_fence == 0) { + DLOGE("acquire_fence is zero"); + return HWC2::Error::BadParameter; + } + + const private_handle_t *handle = static_cast<const private_handle_t *>(buffer); + + // Validate and dup ion fd from surfaceflinger + // This works around bug 30281222 + if (handle->fd < 0) { + return HWC2::Error::BadParameter; + } else { + close(ion_fd_); + ion_fd_ = dup(handle->fd); + } + + LayerBuffer *layer_buffer = &layer_->input_buffer; + int aligned_width, aligned_height; +#ifdef USE_GRALLOC1 + buffer_allocator_->GetCustomWidthAndHeight(handle, &aligned_width, &aligned_height); +#else + AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(handle, aligned_width, aligned_height); +#endif + + LayerBufferFormat format = GetSDMFormat(handle->format, handle->flags); + if ((format != layer_buffer->format) || (UINT32(aligned_width) != layer_buffer->width) || + (UINT32(aligned_height) != layer_buffer->height)) { + // Layer buffer geometry has changed. + geometry_changes_ |= kBufferGeometry; + } + + layer_buffer->format = format; + layer_buffer->width = UINT32(aligned_width); + layer_buffer->height = UINT32(aligned_height); + layer_buffer->unaligned_width = UINT32(handle->unaligned_width); + layer_buffer->unaligned_height = UINT32(handle->unaligned_height); + + if (SetMetaData(const_cast<private_handle_t *>(handle), layer_) != kErrorNone) { + return HWC2::Error::BadLayer; + } + + layer_buffer->flags.video = (handle->buffer_type == BUFFER_TYPE_VIDEO) ? true : false; + + // TZ Protected Buffer - L1 + bool secure = (handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER); + bool secure_camera = secure && (handle->flags & private_handle_t::PRIV_FLAGS_CAMERA_WRITE); + bool secure_display = (handle->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY); + if (secure != layer_buffer->flags.secure || secure_camera != layer_buffer->flags.secure_camera || + secure_display != layer_buffer->flags.secure_display) { + // Secure attribute of layer buffer has changed. + needs_validate_ = true; + } + + layer_buffer->flags.secure = secure; + layer_buffer->flags.secure_camera = secure_camera; + layer_buffer->flags.secure_display = secure_display; + + layer_buffer->planes[0].fd = ion_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->size = handle->size; + layer_buffer->buffer_id = reinterpret_cast<uint64_t>(handle); + + return HWC2::Error::None; +} + +HWC2::Error HWCLayer::SetLayerSurfaceDamage(hwc_region_t damage) { + // Check if there is an update in SurfaceDamage rects + if (layer_->dirty_regions.size() != damage.numRects) { + needs_validate_ = true; + } else { + for (uint32_t j = 0; j < damage.numRects; j++) { + LayerRect damage_rect; + SetRect(damage.rects[j], &damage_rect); + if (damage_rect != layer_->dirty_regions.at(j)) { + needs_validate_ = true; + break; + } + } + } + + layer_->dirty_regions.clear(); + 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) { + LayerBlending blending = kBlendingPremultiplied; + switch (mode) { + case HWC2::BlendMode::Coverage: + blending = kBlendingCoverage; + break; + case HWC2::BlendMode::Premultiplied: + blending = kBlendingPremultiplied; + break; + case HWC2::BlendMode::None: + blending = kBlendingOpaque; + break; + default: + return HWC2::Error::BadParameter; + } + + if (layer_->blending != blending) { + geometry_changes_ |= kBlendMode; + layer_->blending = blending; + } + return HWC2::Error::None; +} + +HWC2::Error HWCLayer::SetLayerColor(hwc_color_t color) { + if (client_requested_ != HWC2::Composition::SolidColor) { + return HWC2::Error::None; + } + layer_->solid_fill_color = GetUint32Color(color); + layer_->input_buffer.format = kFormatARGB8888; + DLOGV_IF(kTagClient, "[%" PRIu64 "][%" PRIu64 "] Layer color set to %x", display_id_, id_, + layer_->solid_fill_color); + return HWC2::Error::None; +} + +HWC2::Error HWCLayer::SetLayerCompositionType(HWC2::Composition type) { + client_requested_ = type; + switch (type) { + case HWC2::Composition::Client: + break; + case HWC2::Composition::Device: + // We try and default to this in SDM + break; + case HWC2::Composition::SolidColor: + break; + case HWC2::Composition::Cursor: + break; + case HWC2::Composition::Invalid: + return HWC2::Error::BadParameter; + default: + return HWC2::Error::Unsupported; + } + + return HWC2::Error::None; +} + +HWC2::Error HWCLayer::SetLayerDataspace(int32_t dataspace) { + // Map deprecated dataspace values to appropriate + // new enums + if (dataspace & 0xffff) { + switch (dataspace & 0xffff) { + case HAL_DATASPACE_SRGB: + dataspace = HAL_DATASPACE_V0_SRGB; + break; + case HAL_DATASPACE_JFIF: + dataspace = HAL_DATASPACE_V0_JFIF; + break; + case HAL_DATASPACE_SRGB_LINEAR: + dataspace = HAL_DATASPACE_V0_SRGB_LINEAR; + break; + case HAL_DATASPACE_BT601_625: + dataspace = HAL_DATASPACE_V0_BT601_625; + break; + case HAL_DATASPACE_BT601_525: + dataspace = HAL_DATASPACE_V0_BT601_525; + break; + case HAL_DATASPACE_BT709: + dataspace = HAL_DATASPACE_V0_BT709; + break; + default: + // unknown legacy dataspace + DLOGW_IF(kTagClient, "Unsupported dataspace type %d", dataspace); + } + } + + // cache the dataspace, to be used later to update SDM ColorMetaData + if (dataspace_ != dataspace) { + geometry_changes_ |= kDataspace; + dataspace_ = dataspace; + } + return HWC2::Error::None; +} + +HWC2::Error HWCLayer::SetLayerDisplayFrame(hwc_rect_t frame) { + LayerRect dst_rect = {}; + SetRect(frame, &dst_rect); + if (layer_->dst_rect != dst_rect) { + geometry_changes_ |= kDisplayFrame; + layer_->dst_rect = dst_rect; + } + return HWC2::Error::None; +} + +HWC2::Error HWCLayer::SetCursorPosition(int32_t x, int32_t y) { + hwc_rect_t frame = {}; + frame.left = x; + frame.top = y; + frame.right = x + INT(layer_->dst_rect.right - layer_->dst_rect.left); + frame.bottom = y + INT(layer_->dst_rect.bottom - layer_->dst_rect.top); + SetLayerDisplayFrame(frame); + + 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 + uint8_t plane_alpha = static_cast<uint8_t>(std::round(255.0f * alpha)); + if (layer_->plane_alpha != plane_alpha) { + geometry_changes_ |= kPlaneAlpha; + layer_->plane_alpha = plane_alpha; + } + + return HWC2::Error::None; +} + +HWC2::Error HWCLayer::SetLayerSourceCrop(hwc_frect_t crop) { + LayerRect src_rect = {}; + SetRect(crop, &src_rect); + if (layer_->src_rect != src_rect) { + geometry_changes_ |= kSourceCrop; + layer_->src_rect = src_rect; + } + + return HWC2::Error::None; +} + +HWC2::Error HWCLayer::SetLayerTransform(HWC2::Transform transform) { + LayerTransform layer_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.flip_horizontal = true; + layer_transform.flip_vertical = true; + break; + case HWC2::Transform::Rotate270: + layer_transform.rotation = 90.0f; + layer_transform.flip_horizontal = true; + layer_transform.flip_vertical = true; + 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; + case HWC2::Transform::None: + // do nothing + break; + } + + if (layer_->transform != layer_transform) { + geometry_changes_ |= kTransform; + layer_->transform = layer_transform; + } + return HWC2::Error::None; +} + +HWC2::Error HWCLayer::SetLayerVisibleRegion(hwc_region_t visible) { + layer_->visible_regions.clear(); + 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) { + if (z_ != z) { + geometry_changes_ |= kZOrder; + z_ = z; + } + 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; + case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC: + format = kFormatYCbCr420TP10Ubwc; + break; + case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC: + format = kFormatYCbCr420P010Ubwc; + 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_BGR_888: + format = kFormatBGR888; + 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; + case HAL_PIXEL_FORMAT_CbYCrY_422_I: + format = kFormatCbYCrY422H2V1Packed; + break; + case HAL_PIXEL_FORMAT_RGBA_1010102: + format = kFormatRGBA1010102; + break; + case HAL_PIXEL_FORMAT_ARGB_2101010: + format = kFormatARGB2101010; + break; + case HAL_PIXEL_FORMAT_RGBX_1010102: + format = kFormatRGBX1010102; + break; + case HAL_PIXEL_FORMAT_XRGB_2101010: + format = kFormatXRGB2101010; + break; + case HAL_PIXEL_FORMAT_BGRA_1010102: + format = kFormatBGRA1010102; + break; + case HAL_PIXEL_FORMAT_ABGR_2101010: + format = kFormatABGR2101010; + break; + case HAL_PIXEL_FORMAT_BGRX_1010102: + format = kFormatBGRX1010102; + break; + case HAL_PIXEL_FORMAT_XBGR_2101010: + format = kFormatXBGR2101010; + break; + case HAL_PIXEL_FORMAT_YCbCr_420_P010: + format = kFormatYCbCr420P010; + break; + case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC: + format = kFormatYCbCr420TP10Ubwc; + break; + case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC: + format = kFormatYCbCr420P010Ubwc; + 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) { + LayerBuffer *layer_buffer = &layer->input_buffer; + private_handle_t *handle = const_cast<private_handle_t *>(pvt_handle); + IGC_t igc = {}; + LayerIGC layer_igc = layer_buffer->igc; + if (getMetaData(handle, GET_IGC, &igc) == 0) { + if (SetIGC(igc, &layer_igc) != kErrorNone) { + return kErrorNotSupported; + } + } + + float fps = 0; + uint32_t frame_rate = layer->frame_rate; + if (getMetaData(handle, GET_REFRESH_RATE, &fps) == 0) { + frame_rate = RoundToStandardFPS(fps); + } + + int32_t interlaced = 0; + bool interlace = layer_buffer->flags.interlace; + if (getMetaData(handle, GET_PP_PARAM_INTERLACED, &interlaced) == 0) { + interlace = interlaced ? true : false; + } + if (interlace != layer_buffer->flags.interlace) { + DLOGI("Layer buffer interlaced metadata has changed. old=%d, new=%d", + layer_buffer->flags.interlace, interlace); + } + + uint32_t linear_format = 0; + if (getMetaData(handle, GET_LINEAR_FORMAT, &linear_format) == 0) { + layer_buffer->format = GetSDMFormat(INT32(linear_format), 0); + } + + uint32_t s3d = 0; + LayerBufferS3DFormat s3d_format = layer_buffer->s3d_format; + if (getMetaData(handle, GET_S3D_FORMAT, &s3d) == 0) { + s3d_format = GetS3DFormat(s3d); + } + + if ((layer_igc != layer_buffer->igc) || (interlace != layer_buffer->flags.interlace) || + (frame_rate != layer->frame_rate) || (s3d_format != layer_buffer->s3d_format)) { + // Layer buffer metadata has changed. + needs_validate_ = true; + layer_buffer->igc = layer_igc; + layer->frame_rate = frame_rate; + layer_buffer->s3d_format = s3d_format; + layer_buffer->flags.interlace = interlace; + } + + 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; +} + + + +bool HWCLayer::SupportLocalConversion(ColorPrimaries working_primaries) { + if (layer_->input_buffer.color_metadata.colorPrimaries <= ColorPrimaries_BT601_6_525 && + working_primaries <= ColorPrimaries_BT601_6_525) { + return true; + } + return false; +} + +bool HWCLayer::ValidateAndSetCSC() { + if (client_requested_ != HWC2::Composition::Device && + client_requested_ != HWC2::Composition::Cursor) { + // Check the layers which are configured to Device + return true; + } + + LayerBuffer *layer_buffer = &layer_->input_buffer; + bool use_color_metadata = true; +#ifdef FEATURE_WIDE_COLOR + ColorMetaData csc = {}; + if (dataspace_ != HAL_DATASPACE_UNKNOWN) { + use_color_metadata = false; + bool valid_csc = GetSDMColorSpace(dataspace_, &csc); + if (!valid_csc) { + return false; + } + // if we are here here, update the sdm layer csc. + layer_buffer->color_metadata.transfer = csc.transfer; + layer_buffer->color_metadata.colorPrimaries = csc.colorPrimaries; + layer_buffer->color_metadata.range = csc.range; + } +#endif + + if (IsBT2020(layer_buffer->color_metadata.colorPrimaries)) { + // android_dataspace_t doesnt support mastering display and light levels + // so retrieve it from metadata for BT2020(HDR) + use_color_metadata = true; + } + + if (use_color_metadata) { + const private_handle_t *handle = + reinterpret_cast<const private_handle_t *>(layer_buffer->buffer_id); + if (sdm::SetCSC(handle, &layer_buffer->color_metadata) != kErrorNone) { + return false; + } + } + + return true; +} + + +uint32_t HWCLayer::RoundToStandardFPS(float fps) { + static const uint32_t standard_fps[4] = {24, 30, 48, 60}; + uint32_t frame_rate = (uint32_t)(fps); + + int count = INT(sizeof(standard_fps) / sizeof(standard_fps[0])); + for (int i = 0; i < count; i++) { + if ((standard_fps[i] - frame_rate) < 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 frame_rate; +} + +void HWCLayer::SetComposition(const LayerComposition &sdm_composition) { + auto hwc_composition = HWC2::Composition::Invalid; + switch (sdm_composition) { + case kCompositionGPU: + hwc_composition = HWC2::Composition::Client; + break; + case kCompositionHWCursor: + hwc_composition = HWC2::Composition::Cursor; + break; + default: + hwc_composition = HWC2::Composition::Device; + break; + } + // Update solid fill composition + if (sdm_composition == kCompositionSDE && layer_->flags.solid_fill != 0) { + hwc_composition = HWC2::Composition::SolidColor; + } + device_selected_ = hwc_composition; + + return; +} +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 diff --git a/msm8909/sdm/libs/hwc2/hwc_layers.h b/msm8909/sdm/libs/hwc2/hwc_layers.h new file mode 100644 index 00000000..1d71ca8c --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_layers.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2014-2017, 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 <map> +#include <queue> +#include <set> +#include "core/buffer_allocator.h" +#include "hwc_buffer_allocator.h" + +namespace sdm { + +DisplayError SetCSC(const private_handle_t *pvt_handle, ColorMetaData *color_metadata); +bool GetColorPrimary(const int32_t &dataspace, ColorPrimaries *color_primary); +bool GetTransfer(const int32_t &dataspace, GammaTransfer *gamma_transfer); +void GetRange(const int32_t &dataspace, ColorRange *color_range); +bool GetSDMColorSpace(const int32_t &dataspace, ColorMetaData *color_metadata); +bool IsBT2020(const ColorPrimaries &color_primary); +enum GeometryChanges { + kNone = 0x000, + kBlendMode = 0x001, + kDataspace = 0x002, + kDisplayFrame = 0x004, + kPlaneAlpha = 0x008, + kSourceCrop = 0x010, + kTransform = 0x020, + kZOrder = 0x040, + kAdded = 0x080, + kRemoved = 0x100, + kBufferGeometry = 0x200, +}; + +class HWCLayer { + public: + explicit HWCLayer(hwc2_display_t display_id, HWCBufferAllocator *buf_allocator); + ~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 SetCursorPosition(int32_t x, int32_t y); + 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 &sdm_composition); + HWC2::Composition GetClientRequestedCompositionType() { return client_requested_; } + void UpdateClientCompositionType(HWC2::Composition type) { client_requested_ = type; } + HWC2::Composition GetDeviceSelectedCompositionType() { return device_selected_; } + int32_t GetLayerDataspace() { return dataspace_; } + uint32_t GetGeometryChanges() { return geometry_changes_; } + void ResetGeometryChanges() { geometry_changes_ = GeometryChanges::kNone; } + void PushReleaseFence(int32_t fence); + int32_t PopReleaseFence(void); + bool ValidateAndSetCSC(); + bool SupportLocalConversion(ColorPrimaries working_primaries); + void ResetValidation() { needs_validate_ = false; } + bool NeedsValidation() { return (needs_validate_ || geometry_changes_); } + + 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_; + int ion_fd_ = -1; + HWCBufferAllocator *buffer_allocator_ = NULL; + int32_t dataspace_ = HAL_DATASPACE_UNKNOWN; + bool needs_validate_ = true; + + // Composition requested by client(SF) + HWC2::Composition client_requested_ = HWC2::Composition::Device; + // Composition selected by SDM + HWC2::Composition device_selected_ = HWC2::Composition::Device; + 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 SetIGC(IGC_t source, LayerIGC *target); + uint32_t RoundToStandardFPS(float fps); +}; + +struct SortLayersByZ { + bool operator()(const HWCLayer *lhs, const HWCLayer *rhs) const { + return lhs->GetZ() < rhs->GetZ(); + } +}; + +} // namespace sdm +#endif // __HWC_LAYERS_H__ diff --git a/msm8909/sdm/libs/hwc2/hwc_session.cpp b/msm8909/sdm/libs/hwc2/hwc_session.cpp new file mode 100644 index 00000000..b78b1a2b --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_session.cpp @@ -0,0 +1,1631 @@ +/* + * Copyright (c) 2014-2018, 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 <core/buffer_allocator.h> +#include <private/color_params.h> +#include <utils/constants.h> +#include <utils/String16.h> +#include <cutils/properties.h> +#include <hardware_legacy/uevent.h> +#include <sys/resource.h> +#include <sys/prctl.h> +#include <binder/Parcel.h> +#include <QService.h> +#include <display_config.h> +#include <utils/debug.h> +#include <sync/sync.h> +#include <profiler.h> +#include <algorithm> +#include <string> +#include <bitset> +#include <thread> +#include <memory> + +#include "hwc_buffer_allocator.h" +#include "hwc_buffer_sync_handler.h" +#include "hwc_session.h" +#include "hwc_debugger.h" +#include "hwc_display_primary.h" +#include "hwc_display_virtual.h" +#include "hwc_display_external_test.h" +#include "qd_utils.h" + +#define __CLASS__ "HWCSession" + +#define HWC_UEVENT_SWITCH_HDMI "change@/devices/virtual/switch/hdmi" +#define HWC_UEVENT_GRAPHICS_FB0 "change@/devices/virtual/graphics/fb0" + +static sdm::HWCSession::HWCModuleMethods g_hwc_module_methods; + +hwc_module_t HAL_MODULE_INFO_SYM = { + .common = { + .tag = HARDWARE_MODULE_TAG, + .version_major = 3, + .version_minor = 0, + .id = HWC_HARDWARE_MODULE_ID, + .name = "QTI Hardware Composer Module", + .author = "CodeAurora Forum", + .methods = &g_hwc_module_methods, + .dso = 0, + .reserved = {0}, + } +}; + +namespace sdm { + +static HWCUEvent g_hwc_uevent_; +Locker HWCSession::locker_[HWC_NUM_DISPLAY_TYPES]; +bool HWCSession::disable_skip_validate_ = false; + +void HWCUEvent::UEventThread(HWCUEvent *hwc_uevent) { + const char *uevent_thread_name = "HWC_UeventThread"; + + prctl(PR_SET_NAME, uevent_thread_name, 0, 0, 0); + setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY); + + int status = uevent_init(); + if (!status) { + std::unique_lock<std::mutex> caller_lock(hwc_uevent->mutex_); + hwc_uevent->caller_cv_.notify_one(); + DLOGE("Failed to init uevent with err %d", status); + return; + } + + { + // Signal caller thread that worker thread is ready to listen to events. + std::unique_lock<std::mutex> caller_lock(hwc_uevent->mutex_); + hwc_uevent->init_done_ = true; + hwc_uevent->caller_cv_.notify_one(); + } + + while (1) { + char uevent_data[PAGE_SIZE] = {}; + + // keep last 2 zeroes to ensure double 0 termination + int length = uevent_next_event(uevent_data, INT32(sizeof(uevent_data)) - 2); + + // scope of lock to this block only, so that caller is free to set event handler to nullptr; + { + std::lock_guard<std::mutex> guard(hwc_uevent->mutex_); + if (hwc_uevent->uevent_listener_) { + hwc_uevent->uevent_listener_->UEventHandler(uevent_data, length); + } else { + DLOGW("UEvent dropped. No uevent listener."); + } + } + } +} + +HWCUEvent::HWCUEvent() { + std::unique_lock<std::mutex> caller_lock(mutex_); + std::thread thread(HWCUEvent::UEventThread, this); + thread.detach(); + caller_cv_.wait(caller_lock); +} + +void HWCUEvent::Register(HWCUEventListener *uevent_listener) { + DLOGI("Set uevent listener = %p", uevent_listener); + + std::lock_guard<std::mutex> obj(mutex_); + uevent_listener_ = uevent_listener; +} + +HWCSession::HWCSession(const hw_module_t *module) { + hwc2_device_t::common.tag = HARDWARE_DEVICE_TAG; + hwc2_device_t::common.version = HWC_DEVICE_API_VERSION_2_0; + hwc2_device_t::common.module = const_cast<hw_module_t *>(module); + hwc2_device_t::common.close = Close; + hwc2_device_t::getCapabilities = GetCapabilities; + hwc2_device_t::getFunction = GetFunction; +} + +int HWCSession::Init() { + SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]); + + int status = -EINVAL; + const char *qservice_name = "display.qservice"; + + if (!g_hwc_uevent_.InitDone()) { + return status; + } + + // Start QService and connect to it. + qService::QService::init(); + android::sp<qService::IQService> iqservice = android::interface_cast<qService::IQService>( + android::defaultServiceManager()->getService(android::String16(qservice_name))); + + if (iqservice.get()) { + iqservice->connect(android::sp<qClient::IQClient>(this)); + qservice_ = reinterpret_cast<qService::QService *>(iqservice.get()); + } else { + ALOGE("%s::%s: Failed to acquire %s", __CLASS__, __FUNCTION__, qservice_name); + return -EINVAL; + } + + StartServices(); + + DisplayError error = buffer_allocator_.Init(); + if (error != kErrorNone) { + ALOGE("%s::%s: Buffer allocaor initialization failed. Error = %d", + __CLASS__, __FUNCTION__, error); + return -EINVAL; + } + + error = CoreInterface::CreateCore(HWCDebugHandler::Get(), &buffer_allocator_, + &buffer_sync_handler_, &socket_handler_, &core_intf_); + if (error != kErrorNone) { + buffer_allocator_.Deinit(); + ALOGE("%s::%s: Display core initialization failed. Error = %d", __CLASS__, __FUNCTION__, error); + return -EINVAL; + } + + g_hwc_uevent_.Register(this); + + // If HDMI display is primary display, defer display creation until hotplug event is received. + HWDisplayInterfaceInfo hw_disp_info = {}; + error = core_intf_->GetFirstDisplayInterfaceType(&hw_disp_info); + if (error != kErrorNone) { + g_hwc_uevent_.Register(nullptr); + CoreInterface::DestroyCore(); + buffer_allocator_.Deinit(); + DLOGE("Primary display type not recognized. Error = %d", error); + return -EINVAL; + } + + if (hw_disp_info.type == kHDMI) { + status = 0; + hdmi_is_primary_ = true; + // Create display if it is connected, else wait for hotplug connect event. + if (hw_disp_info.is_connected) { + status = CreateExternalDisplay(HWC_DISPLAY_PRIMARY); + } + } else { + // Create and power on primary display + status = HWCDisplayPrimary::Create(core_intf_, &buffer_allocator_, &callbacks_, qservice_, + &hwc_display_[HWC_DISPLAY_PRIMARY]); + color_mgr_ = HWCColorManager::CreateColorManager(&buffer_allocator_); + if (!color_mgr_) { + DLOGW("Failed to load HWCColorManager."); + } + } + + if (status) { + g_hwc_uevent_.Register(nullptr); + CoreInterface::DestroyCore(); + buffer_allocator_.Deinit(); + return status; + } + + struct rlimit fd_limit = {}; + getrlimit(RLIMIT_NOFILE, &fd_limit); + fd_limit.rlim_cur = fd_limit.rlim_cur * 2; + if (fd_limit.rlim_cur < fd_limit.rlim_max) { + auto err = setrlimit(RLIMIT_NOFILE, &fd_limit); + if (err) { + DLOGW("Unable to increase fd limit - err:%d, %s", errno, strerror(errno)); + } + } + + return 0; +} + +int HWCSession::Deinit() { + Locker::SequenceCancelScopeLock lock_v(locker_[HWC_DISPLAY_VIRTUAL]); + Locker::SequenceCancelScopeLock lock_e(locker_[HWC_DISPLAY_EXTERNAL]); + Locker::SequenceCancelScopeLock lock_p(locker_[HWC_DISPLAY_PRIMARY]); + + HWCDisplay *primary_display = hwc_display_[HWC_DISPLAY_PRIMARY]; + if (primary_display) { + if (hdmi_is_primary_) { + HWCDisplayExternal::Destroy(primary_display); + } else { + HWCDisplayPrimary::Destroy(primary_display); + } + } + hwc_display_[HWC_DISPLAY_PRIMARY] = nullptr; + + if (color_mgr_) { + color_mgr_->DestroyColorManager(); + } + + g_hwc_uevent_.Register(nullptr); + + DisplayError error = CoreInterface::DestroyCore(); + if (error != kErrorNone) { + ALOGE("Display core de-initialization failed. Error = %d", error); + } + + return 0; +} + +int HWCSession::Open(const hw_module_t *module, const char *name, hw_device_t **device) { + if (!module || !name || !device) { + ALOGE("%s::%s: Invalid parameters.", __CLASS__, __FUNCTION__); + return -EINVAL; + } + + if (!strcmp(name, HWC_HARDWARE_COMPOSER)) { + HWCSession *hwc_session = new HWCSession(module); + if (!hwc_session) { + return -ENOMEM; + } + + int status = hwc_session->Init(); + if (status != 0) { + return status; + } + + hwc2_device_t *composer_device = hwc_session; + *device = reinterpret_cast<hw_device_t *>(composer_device); + } + + return 0; +} + +int HWCSession::Close(hw_device_t *device) { + if (!device) { + return -EINVAL; + } + + hwc2_device_t *composer_device = reinterpret_cast<hwc2_device_t *>(device); + HWCSession *hwc_session = static_cast<HWCSession *>(composer_device); + + hwc_session->Deinit(); + + return 0; +} + +void HWCSession::GetCapabilities(struct hwc2_device *device, uint32_t *outCount, + int32_t *outCapabilities) { + if (!outCount) { + return; + } + + int value = 0; + uint32_t count = 0; + HWCSession *hwc_session = static_cast<HWCSession *>(device); + bool color_transform_supported = hwc_session->core_intf_->IsColorTransformSupported(); + + if (Debug::Get()->GetProperty(DISABLE_SKIP_VALIDATE_PROP, &value) == kErrorNone) { + disable_skip_validate_ = (value == 1); + } + + count += (color_transform_supported) ? 1 : 0; + count += (!disable_skip_validate_) ? 1 : 0; + + if (outCapabilities != nullptr && (*outCount >= count)) { + int i = 0; + if (color_transform_supported) { + outCapabilities[i++] = HWC2_CAPABILITY_SKIP_CLIENT_COLOR_TRANSFORM; + } + if (!disable_skip_validate_) { + outCapabilities[i++] = HWC2_CAPABILITY_SKIP_VALIDATE; + } + } + *outCount = count; +} + +template <typename PFN, typename T> +static hwc2_function_pointer_t AsFP(T function) { + static_assert(std::is_same<PFN, T>::value, "Incompatible function pointer"); + return reinterpret_cast<hwc2_function_pointer_t>(function); +} + +// HWC2 functions returned in GetFunction +// Defined in the same order as in the HWC2 header + +int32_t HWCSession::AcceptDisplayChanges(hwc2_device_t *device, hwc2_display_t display) { + return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::AcceptDisplayChanges); +} + +int32_t HWCSession::CreateLayer(hwc2_device_t *device, hwc2_display_t display, + hwc2_layer_t *out_layer_id) { + if (!out_layer_id) { + return HWC2_ERROR_BAD_PARAMETER; + } + + return CallDisplayFunction(device, display, &HWCDisplay::CreateLayer, out_layer_id); +} + +int32_t HWCSession::CreateVirtualDisplay(hwc2_device_t *device, uint32_t width, uint32_t height, + int32_t *format, hwc2_display_t *out_display_id) { + // TODO(user): Handle concurrency with HDMI + SCOPE_LOCK(locker_[HWC_DISPLAY_VIRTUAL]); + if (!device) { + return HWC2_ERROR_BAD_DISPLAY; + } + + if (!out_display_id || !width || !height || !format) { + return HWC2_ERROR_BAD_PARAMETER; + } + + HWCSession *hwc_session = static_cast<HWCSession *>(device); + auto status = hwc_session->CreateVirtualDisplayObject(width, height, format); + if (status == HWC2::Error::None) { + *out_display_id = HWC_DISPLAY_VIRTUAL; + DLOGI("Created virtual display id:% " PRIu64 " with res: %dx%d", + *out_display_id, width, height); + } else { + DLOGE("Failed to create virtual display: %s", to_string(status).c_str()); + } + return INT32(status); +} + +int32_t HWCSession::DestroyLayer(hwc2_device_t *device, hwc2_display_t display, + hwc2_layer_t layer) { + return CallDisplayFunction(device, display, &HWCDisplay::DestroyLayer, layer); +} + +int32_t HWCSession::DestroyVirtualDisplay(hwc2_device_t *device, hwc2_display_t display) { + if (!device || display != HWC_DISPLAY_VIRTUAL) { + return HWC2_ERROR_BAD_DISPLAY; + } + + SCOPE_LOCK(locker_[display]); + DLOGI("Destroying virtual display id:%" PRIu64, display); + auto *hwc_session = static_cast<HWCSession *>(device); + + if (hwc_session->hwc_display_[display]) { + HWCDisplayVirtual::Destroy(hwc_session->hwc_display_[display]); + hwc_session->hwc_display_[display] = nullptr; + return HWC2_ERROR_NONE; + } else { + return HWC2_ERROR_BAD_DISPLAY; + } +} + +void HWCSession::Dump(hwc2_device_t *device, uint32_t *out_size, char *out_buffer) { + if (!device || !out_size) { + return; + } + + auto *hwc_session = static_cast<HWCSession *>(device); + const size_t max_dump_size = 8192; + + if (out_buffer == nullptr) { + *out_size = max_dump_size; + } else { + std::string s {}; + for (int id = HWC_DISPLAY_PRIMARY; id <= HWC_DISPLAY_VIRTUAL; id++) { + SCOPE_LOCK(locker_[id]); + if (hwc_session->hwc_display_[id]) { + s += hwc_session->hwc_display_[id]->Dump(); + } + } + auto copied = s.copy(out_buffer, std::min(s.size(), max_dump_size), 0); + *out_size = UINT32(copied); + } +} + +static int32_t GetActiveConfig(hwc2_device_t *device, hwc2_display_t display, + hwc2_config_t *out_config) { + return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::GetActiveConfig, out_config); +} + +static int32_t GetChangedCompositionTypes(hwc2_device_t *device, hwc2_display_t display, + uint32_t *out_num_elements, hwc2_layer_t *out_layers, + int32_t *out_types) { + // null_ptr check only for out_num_elements, as out_layers and out_types can be null. + if (!out_num_elements) { + return HWC2_ERROR_BAD_PARAMETER; + } + return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::GetChangedCompositionTypes, + out_num_elements, out_layers, out_types); +} + +static int32_t GetClientTargetSupport(hwc2_device_t *device, hwc2_display_t display, uint32_t width, + uint32_t height, int32_t format, int32_t dataspace) { + return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::GetClientTargetSupport, + width, height, format, dataspace); +} + +static int32_t GetColorModes(hwc2_device_t *device, hwc2_display_t display, uint32_t *out_num_modes, + int32_t /*android_color_mode_t*/ *int_out_modes) { + auto out_modes = reinterpret_cast<android_color_mode_t *>(int_out_modes); + return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::GetColorModes, out_num_modes, + out_modes); +} + +static int32_t GetDisplayAttribute(hwc2_device_t *device, hwc2_display_t display, + hwc2_config_t config, int32_t int_attribute, + int32_t *out_value) { + auto attribute = static_cast<HWC2::Attribute>(int_attribute); + return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::GetDisplayAttribute, config, + attribute, out_value); +} + +static int32_t GetDisplayConfigs(hwc2_device_t *device, hwc2_display_t display, + uint32_t *out_num_configs, hwc2_config_t *out_configs) { + return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::GetDisplayConfigs, + out_num_configs, out_configs); +} + +static int32_t GetDisplayName(hwc2_device_t *device, hwc2_display_t display, uint32_t *out_size, + char *out_name) { + return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::GetDisplayName, out_size, + out_name); +} + +static int32_t GetDisplayRequests(hwc2_device_t *device, hwc2_display_t display, + int32_t *out_display_requests, uint32_t *out_num_elements, + hwc2_layer_t *out_layers, int32_t *out_layer_requests) { + return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::GetDisplayRequests, + out_display_requests, out_num_elements, out_layers, + out_layer_requests); +} + +static int32_t GetDisplayType(hwc2_device_t *device, hwc2_display_t display, int32_t *out_type) { + return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::GetDisplayType, out_type); +} + +static int32_t GetDozeSupport(hwc2_device_t *device, hwc2_display_t display, int32_t *out_support) { + if (display == HWC_DISPLAY_PRIMARY) { + *out_support = 1; + } else { + // TODO(user): Port over connect_display_ from HWC1 + // Return no error for connected displays + *out_support = 0; + return HWC2_ERROR_BAD_DISPLAY; + } + return HWC2_ERROR_NONE; +} + +static int32_t GetHdrCapabilities(hwc2_device_t* device, hwc2_display_t display, + uint32_t* out_num_types, int32_t* out_types, + float* out_max_luminance, float* out_max_average_luminance, + float* out_min_luminance) { + return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::GetHdrCapabilities, + out_num_types, out_types, out_max_luminance, + out_max_average_luminance, out_min_luminance); +} + +static uint32_t GetMaxVirtualDisplayCount(hwc2_device_t *device) { + char property[PROPERTY_VALUE_MAX]; + property_get(WRITEBACK_SUPPORTED, property, "1"); + return (uint32_t) atoi(property); +} + +static int32_t GetReleaseFences(hwc2_device_t *device, hwc2_display_t display, + uint32_t *out_num_elements, hwc2_layer_t *out_layers, + int32_t *out_fences) { + return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::GetReleaseFences, + out_num_elements, out_layers, out_fences); +} + +int32_t HWCSession::PresentDisplay(hwc2_device_t *device, hwc2_display_t display, + int32_t *out_retire_fence) { + HWCSession *hwc_session = static_cast<HWCSession *>(device); + bool notify_hotplug = false; + auto status = HWC2::Error::BadDisplay; + DTRACE_SCOPED(); + + if (display >= HWC_NUM_DISPLAY_TYPES) { + return HWC2_ERROR_BAD_DISPLAY; + } + + { + SEQUENCE_EXIT_SCOPE_LOCK(locker_[display]); + if (!device) { + return HWC2_ERROR_BAD_DISPLAY; + } + + // TODO(user): Handle virtual display/HDMI concurrency + if (hwc_session->hwc_display_[display]) { + status = hwc_session->hwc_display_[display]->Present(out_retire_fence); + // This is only indicative of how many times SurfaceFlinger posts + // frames to the display. + CALC_FPS(); + } + } + + if (status != HWC2::Error::None && status != HWC2::Error::NotValidated) { + SEQUENCE_CANCEL_SCOPE_LOCK(locker_[display]); + } + + // Handle Pending external display connection + if (hwc_session->external_pending_connect_ && (display == HWC_DISPLAY_PRIMARY)) { + Locker::ScopeLock lock_e(locker_[HWC_DISPLAY_EXTERNAL]); + Locker::ScopeLock lock_v(locker_[HWC_DISPLAY_VIRTUAL]); + + if (!hwc_session->hwc_display_[HWC_DISPLAY_VIRTUAL]) { + DLOGD("Process pending external display connection"); + hwc_session->ConnectDisplay(HWC_DISPLAY_EXTERNAL); + hwc_session->external_pending_connect_ = false; + notify_hotplug = true; + } + } + + if (notify_hotplug) { + hwc_session->HotPlug(HWC_DISPLAY_EXTERNAL, HWC2::Connection::Connected); + } + + return INT32(status); +} + +int32_t HWCSession::RegisterCallback(hwc2_device_t *device, int32_t descriptor, + hwc2_callback_data_t callback_data, + hwc2_function_pointer_t pointer) { + if (!device || pointer == nullptr) { + return HWC2_ERROR_BAD_PARAMETER; + } + HWCSession *hwc_session = static_cast<HWCSession *>(device); + SCOPE_LOCK(hwc_session->callbacks_lock_); + auto desc = static_cast<HWC2::Callback>(descriptor); + auto error = hwc_session->callbacks_.Register(desc, callback_data, pointer); + DLOGD("Registering callback: %s", to_string(desc).c_str()); + if (descriptor == HWC2_CALLBACK_HOTPLUG) { + if (hwc_session->hwc_display_[HWC_DISPLAY_PRIMARY]) { + hwc_session->callbacks_.Hotplug(HWC_DISPLAY_PRIMARY, HWC2::Connection::Connected); + } + } + hwc_session->need_invalidate_ = false; + hwc_session->callbacks_lock_.Broadcast(); + return INT32(error); +} + +static int32_t SetActiveConfig(hwc2_device_t *device, hwc2_display_t display, + hwc2_config_t config) { + return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::SetActiveConfig, config); +} + +static int32_t SetClientTarget(hwc2_device_t *device, hwc2_display_t display, + buffer_handle_t target, int32_t acquire_fence, + int32_t dataspace, hwc_region_t damage) { + return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::SetClientTarget, target, + acquire_fence, dataspace, damage); +} + +int32_t HWCSession::SetColorMode(hwc2_device_t *device, hwc2_display_t display, + int32_t /*android_color_mode_t*/ int_mode) { + if (int_mode < HAL_COLOR_MODE_NATIVE || int_mode > HAL_COLOR_MODE_DISPLAY_P3) { + return HWC2_ERROR_BAD_PARAMETER; + } + auto mode = static_cast<android_color_mode_t>(int_mode); + return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::SetColorMode, mode); +} + +int32_t HWCSession::SetColorTransform(hwc2_device_t *device, hwc2_display_t display, + const float *matrix, + int32_t /*android_color_transform_t*/ hint) { + if (!matrix || hint < HAL_COLOR_TRANSFORM_IDENTITY || + hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA) { + return HWC2_ERROR_BAD_PARAMETER; + } + android_color_transform_t transform_hint = static_cast<android_color_transform_t>(hint); + return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::SetColorTransform, matrix, + transform_hint); +} + +static int32_t SetCursorPosition(hwc2_device_t *device, hwc2_display_t display, hwc2_layer_t layer, + int32_t x, int32_t y) { + auto status = INT32(HWC2::Error::None); + status = HWCSession::CallDisplayFunction(device, display, &HWCDisplay::SetCursorPosition, + layer, x, y); + if (status == INT32(HWC2::Error::None)) { + // Update cursor position + HWCSession::CallLayerFunction(device, display, layer, &HWCLayer::SetCursorPosition, x, y); + } + return status; +} + +static int32_t SetLayerBlendMode(hwc2_device_t *device, hwc2_display_t display, hwc2_layer_t layer, + int32_t int_mode) { + if (int_mode < HWC2_BLEND_MODE_INVALID || int_mode > HWC2_BLEND_MODE_COVERAGE) { + return HWC2_ERROR_BAD_PARAMETER; + } + auto mode = static_cast<HWC2::BlendMode>(int_mode); + return HWCSession::CallLayerFunction(device, display, layer, &HWCLayer::SetLayerBlendMode, mode); +} + +static int32_t SetLayerBuffer(hwc2_device_t *device, hwc2_display_t display, hwc2_layer_t layer, + buffer_handle_t buffer, int32_t acquire_fence) { + return HWCSession::CallLayerFunction(device, display, layer, &HWCLayer::SetLayerBuffer, buffer, + acquire_fence); +} + +static int32_t SetLayerColor(hwc2_device_t *device, hwc2_display_t display, hwc2_layer_t layer, + hwc_color_t color) { + return HWCSession::CallLayerFunction(device, display, layer, &HWCLayer::SetLayerColor, color); +} + +static int32_t SetLayerCompositionType(hwc2_device_t *device, hwc2_display_t display, + hwc2_layer_t layer, int32_t int_type) { + auto type = static_cast<HWC2::Composition>(int_type); + return HWCSession::CallLayerFunction(device, display, layer, &HWCLayer::SetLayerCompositionType, + type); +} + +static int32_t SetLayerDataspace(hwc2_device_t *device, hwc2_display_t display, hwc2_layer_t layer, + int32_t dataspace) { + return HWCSession::CallLayerFunction(device, display, layer, &HWCLayer::SetLayerDataspace, + dataspace); +} + +static int32_t SetLayerDisplayFrame(hwc2_device_t *device, hwc2_display_t display, + hwc2_layer_t layer, hwc_rect_t frame) { + return HWCSession::CallLayerFunction(device, display, layer, &HWCLayer::SetLayerDisplayFrame, + frame); +} + +static int32_t SetLayerPlaneAlpha(hwc2_device_t *device, hwc2_display_t display, hwc2_layer_t layer, + float alpha) { + return HWCSession::CallLayerFunction(device, display, layer, &HWCLayer::SetLayerPlaneAlpha, + alpha); +} + +static int32_t SetLayerSourceCrop(hwc2_device_t *device, hwc2_display_t display, hwc2_layer_t layer, + hwc_frect_t crop) { + return HWCSession::CallLayerFunction(device, display, layer, &HWCLayer::SetLayerSourceCrop, crop); +} + +static int32_t SetLayerSurfaceDamage(hwc2_device_t *device, hwc2_display_t display, + hwc2_layer_t layer, hwc_region_t damage) { + return HWCSession::CallLayerFunction(device, display, layer, &HWCLayer::SetLayerSurfaceDamage, + damage); +} + +static int32_t SetLayerTransform(hwc2_device_t *device, hwc2_display_t display, hwc2_layer_t layer, + int32_t int_transform) { + auto transform = static_cast<HWC2::Transform>(int_transform); + return HWCSession::CallLayerFunction(device, display, layer, &HWCLayer::SetLayerTransform, + transform); +} + +static int32_t SetLayerVisibleRegion(hwc2_device_t *device, hwc2_display_t display, + hwc2_layer_t layer, hwc_region_t visible) { + return HWCSession::CallLayerFunction(device, display, layer, &HWCLayer::SetLayerVisibleRegion, + visible); +} + +static int32_t SetLayerZOrder(hwc2_device_t *device, hwc2_display_t display, hwc2_layer_t layer, + uint32_t z) { + return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::SetLayerZOrder, layer, z); +} + +int32_t HWCSession::SetOutputBuffer(hwc2_device_t *device, hwc2_display_t display, + buffer_handle_t buffer, int32_t releaseFence) { + if (!device) { + return HWC2_ERROR_BAD_DISPLAY; + } + + if (display != HWC_DISPLAY_VIRTUAL) { + return HWC2_ERROR_UNSUPPORTED; + } + + SCOPE_LOCK(locker_[display]); + auto *hwc_session = static_cast<HWCSession *>(device); + if (hwc_session->hwc_display_[display]) { + auto vds = reinterpret_cast<HWCDisplayVirtual *>(hwc_session->hwc_display_[display]); + auto status = vds->SetOutputBuffer(buffer, releaseFence); + return INT32(status); + } else { + return HWC2_ERROR_BAD_DISPLAY; + } +} + +int32_t HWCSession::SetPowerMode(hwc2_device_t *device, hwc2_display_t display, int32_t int_mode) { + auto mode = static_cast<HWC2::PowerMode>(int_mode); + return CallDisplayFunction(device, display, &HWCDisplay::SetPowerMode, mode); +} + +static int32_t SetVsyncEnabled(hwc2_device_t *device, hwc2_display_t display, int32_t int_enabled) { + auto enabled = static_cast<HWC2::Vsync>(int_enabled); + return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::SetVsyncEnabled, enabled); +} + +int32_t HWCSession::ValidateDisplay(hwc2_device_t *device, hwc2_display_t display, + uint32_t *out_num_types, uint32_t *out_num_requests) { + DTRACE_SCOPED(); + HWCSession *hwc_session = static_cast<HWCSession *>(device); + if (!device) { + return HWC2_ERROR_BAD_DISPLAY; + } + + // TODO(user): Handle secure session, handle QDCM solid fill + // Handle external_pending_connect_ in CreateVirtualDisplay + auto status = HWC2::Error::BadDisplay; + { + SEQUENCE_ENTRY_SCOPE_LOCK(locker_[display]); + if (hwc_session->hwc_display_[display]) { + if (display == HWC_DISPLAY_PRIMARY) { + // TODO(user): This can be moved to HWCDisplayPrimary + if (hwc_session->reset_panel_) { + DLOGW("panel is in bad state, resetting the panel"); + hwc_session->ResetPanel(); + } + + if (hwc_session->need_invalidate_) { + hwc_session->Refresh(display); + hwc_session->need_invalidate_ = false; + } + + if (hwc_session->color_mgr_) { + hwc_session->color_mgr_->SetColorModeDetailEnhancer(hwc_session->hwc_display_[display]); + } + } + + status = hwc_session->hwc_display_[display]->Validate(out_num_types, out_num_requests); + } + } + + // Sequence locking currently begins on Validate, so cancel the sequence lock on failures + if (status != HWC2::Error::None && status != HWC2::Error::HasChanges) { + SEQUENCE_CANCEL_SCOPE_LOCK(locker_[display]); + } + + return INT32(status); +} + +hwc2_function_pointer_t HWCSession::GetFunction(struct hwc2_device *device, + int32_t int_descriptor) { + auto descriptor = static_cast<HWC2::FunctionDescriptor>(int_descriptor); + + switch (descriptor) { + case HWC2::FunctionDescriptor::AcceptDisplayChanges: + return AsFP<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>(HWCSession::AcceptDisplayChanges); + case HWC2::FunctionDescriptor::CreateLayer: + return AsFP<HWC2_PFN_CREATE_LAYER>(CreateLayer); + case HWC2::FunctionDescriptor::CreateVirtualDisplay: + return AsFP<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>(HWCSession::CreateVirtualDisplay); + case HWC2::FunctionDescriptor::DestroyLayer: + return AsFP<HWC2_PFN_DESTROY_LAYER>(DestroyLayer); + case HWC2::FunctionDescriptor::DestroyVirtualDisplay: + return AsFP<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>(HWCSession::DestroyVirtualDisplay); + case HWC2::FunctionDescriptor::Dump: + return AsFP<HWC2_PFN_DUMP>(HWCSession::Dump); + case HWC2::FunctionDescriptor::GetActiveConfig: + return AsFP<HWC2_PFN_GET_ACTIVE_CONFIG>(GetActiveConfig); + case HWC2::FunctionDescriptor::GetChangedCompositionTypes: + return AsFP<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>(GetChangedCompositionTypes); + case HWC2::FunctionDescriptor::GetClientTargetSupport: + return AsFP<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(GetClientTargetSupport); + case HWC2::FunctionDescriptor::GetColorModes: + return AsFP<HWC2_PFN_GET_COLOR_MODES>(GetColorModes); + case HWC2::FunctionDescriptor::GetDisplayAttribute: + return AsFP<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(GetDisplayAttribute); + case HWC2::FunctionDescriptor::GetDisplayConfigs: + return AsFP<HWC2_PFN_GET_DISPLAY_CONFIGS>(GetDisplayConfigs); + case HWC2::FunctionDescriptor::GetDisplayName: + return AsFP<HWC2_PFN_GET_DISPLAY_NAME>(GetDisplayName); + case HWC2::FunctionDescriptor::GetDisplayRequests: + return AsFP<HWC2_PFN_GET_DISPLAY_REQUESTS>(GetDisplayRequests); + case HWC2::FunctionDescriptor::GetDisplayType: + return AsFP<HWC2_PFN_GET_DISPLAY_TYPE>(GetDisplayType); + case HWC2::FunctionDescriptor::GetHdrCapabilities: + return AsFP<HWC2_PFN_GET_HDR_CAPABILITIES>(GetHdrCapabilities); + case HWC2::FunctionDescriptor::GetDozeSupport: + return AsFP<HWC2_PFN_GET_DOZE_SUPPORT>(GetDozeSupport); + case HWC2::FunctionDescriptor::GetMaxVirtualDisplayCount: + return AsFP<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>(GetMaxVirtualDisplayCount); + case HWC2::FunctionDescriptor::GetReleaseFences: + return AsFP<HWC2_PFN_GET_RELEASE_FENCES>(GetReleaseFences); + case HWC2::FunctionDescriptor::PresentDisplay: + return AsFP<HWC2_PFN_PRESENT_DISPLAY>(PresentDisplay); + case HWC2::FunctionDescriptor::RegisterCallback: + return AsFP<HWC2_PFN_REGISTER_CALLBACK>(RegisterCallback); + case HWC2::FunctionDescriptor::SetActiveConfig: + return AsFP<HWC2_PFN_SET_ACTIVE_CONFIG>(SetActiveConfig); + case HWC2::FunctionDescriptor::SetClientTarget: + return AsFP<HWC2_PFN_SET_CLIENT_TARGET>(SetClientTarget); + case HWC2::FunctionDescriptor::SetColorMode: + return AsFP<HWC2_PFN_SET_COLOR_MODE>(SetColorMode); + case HWC2::FunctionDescriptor::SetColorTransform: + return AsFP<HWC2_PFN_SET_COLOR_TRANSFORM>(SetColorTransform); + case HWC2::FunctionDescriptor::SetCursorPosition: + return AsFP<HWC2_PFN_SET_CURSOR_POSITION>(SetCursorPosition); + case HWC2::FunctionDescriptor::SetLayerBlendMode: + return AsFP<HWC2_PFN_SET_LAYER_BLEND_MODE>(SetLayerBlendMode); + case HWC2::FunctionDescriptor::SetLayerBuffer: + return AsFP<HWC2_PFN_SET_LAYER_BUFFER>(SetLayerBuffer); + case HWC2::FunctionDescriptor::SetLayerColor: + return AsFP<HWC2_PFN_SET_LAYER_COLOR>(SetLayerColor); + case HWC2::FunctionDescriptor::SetLayerCompositionType: + return AsFP<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>(SetLayerCompositionType); + case HWC2::FunctionDescriptor::SetLayerDataspace: + return AsFP<HWC2_PFN_SET_LAYER_DATASPACE>(SetLayerDataspace); + case HWC2::FunctionDescriptor::SetLayerDisplayFrame: + return AsFP<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>(SetLayerDisplayFrame); + case HWC2::FunctionDescriptor::SetLayerPlaneAlpha: + return AsFP<HWC2_PFN_SET_LAYER_PLANE_ALPHA>(SetLayerPlaneAlpha); + // Sideband stream is not supported + // case HWC2::FunctionDescriptor::SetLayerSidebandStream: + case HWC2::FunctionDescriptor::SetLayerSourceCrop: + return AsFP<HWC2_PFN_SET_LAYER_SOURCE_CROP>(SetLayerSourceCrop); + case HWC2::FunctionDescriptor::SetLayerSurfaceDamage: + return AsFP<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>(SetLayerSurfaceDamage); + case HWC2::FunctionDescriptor::SetLayerTransform: + return AsFP<HWC2_PFN_SET_LAYER_TRANSFORM>(SetLayerTransform); + case HWC2::FunctionDescriptor::SetLayerVisibleRegion: + return AsFP<HWC2_PFN_SET_LAYER_VISIBLE_REGION>(SetLayerVisibleRegion); + case HWC2::FunctionDescriptor::SetLayerZOrder: + return AsFP<HWC2_PFN_SET_LAYER_Z_ORDER>(SetLayerZOrder); + case HWC2::FunctionDescriptor::SetOutputBuffer: + return AsFP<HWC2_PFN_SET_OUTPUT_BUFFER>(SetOutputBuffer); + case HWC2::FunctionDescriptor::SetPowerMode: + return AsFP<HWC2_PFN_SET_POWER_MODE>(SetPowerMode); + case HWC2::FunctionDescriptor::SetVsyncEnabled: + return AsFP<HWC2_PFN_SET_VSYNC_ENABLED>(SetVsyncEnabled); + case HWC2::FunctionDescriptor::ValidateDisplay: + return AsFP<HWC2_PFN_VALIDATE_DISPLAY>(HWCSession::ValidateDisplay); + default: + DLOGD("Unknown/Unimplemented function descriptor: %d (%s)", int_descriptor, + to_string(descriptor).c_str()); + return nullptr; + } + return nullptr; +} + +// TODO(user): handle locking + +HWC2::Error HWCSession::CreateVirtualDisplayObject(uint32_t width, uint32_t height, + int32_t *format) { + if (hwc_display_[HWC_DISPLAY_VIRTUAL]) { + return HWC2::Error::NoResources; + } + auto status = HWCDisplayVirtual::Create(core_intf_, &buffer_allocator_, &callbacks_, width, + height, format, &hwc_display_[HWC_DISPLAY_VIRTUAL]); + // TODO(user): validate width and height support + if (status) + return HWC2::Error::Unsupported; + + return HWC2::Error::None; +} + +int32_t HWCSession::ConnectDisplay(int disp) { + DLOGI("Display = %d", disp); + + int status = 0; + uint32_t primary_width = 0; + uint32_t primary_height = 0; + + hwc_display_[HWC_DISPLAY_PRIMARY]->GetFrameBufferResolution(&primary_width, &primary_height); + + if (disp == HWC_DISPLAY_EXTERNAL) { + status = CreateExternalDisplay(disp, primary_width, primary_height); + } else { + DLOGE("Invalid display type"); + return -1; + } + + if (!status) { + hwc_display_[disp]->SetSecureDisplay(secure_display_active_); + } + + return status; +} + +int HWCSession::DisconnectDisplay(int disp) { + DLOGI("Display = %d", disp); + + if (disp == HWC_DISPLAY_EXTERNAL) { + HWCDisplayExternal::Destroy(hwc_display_[disp]); + } else if (disp == HWC_DISPLAY_VIRTUAL) { + HWCDisplayVirtual::Destroy(hwc_display_[disp]); + } else { + DLOGE("Invalid display type"); + return -1; + } + + hwc_display_[disp] = NULL; + + return 0; +} + +// Qclient methods +android::status_t HWCSession::notifyCallback(uint32_t command, const android::Parcel *input_parcel, + android::Parcel *output_parcel) { + android::status_t status = 0; + + switch (command) { + case qService::IQService::DYNAMIC_DEBUG: + DynamicDebug(input_parcel); + break; + + case qService::IQService::SCREEN_REFRESH: + refreshScreen(); + break; + + case qService::IQService::SET_IDLE_TIMEOUT: + setIdleTimeout(UINT32(input_parcel->readInt32())); + break; + + case qService::IQService::SET_FRAME_DUMP_CONFIG: + SetFrameDumpConfig(input_parcel); + break; + + case qService::IQService::SET_MAX_PIPES_PER_MIXER: + status = SetMaxMixerStages(input_parcel); + break; + + case qService::IQService::SET_DISPLAY_MODE: + status = SetDisplayMode(input_parcel); + break; + + case qService::IQService::SET_SECONDARY_DISPLAY_STATUS: { + int disp_id = INT(input_parcel->readInt32()); + HWCDisplay::DisplayStatus disp_status = + static_cast<HWCDisplay::DisplayStatus>(input_parcel->readInt32()); + status = SetSecondaryDisplayStatus(disp_id, disp_status); + output_parcel->writeInt32(status); + } + break; + + case qService::IQService::CONFIGURE_DYN_REFRESH_RATE: + status = ConfigureRefreshRate(input_parcel); + break; + + case qService::IQService::SET_VIEW_FRAME: + break; + + case qService::IQService::TOGGLE_SCREEN_UPDATES: { + int32_t input = input_parcel->readInt32(); + status = toggleScreenUpdate(input == 1); + output_parcel->writeInt32(status); + } + break; + + case qService::IQService::QDCM_SVC_CMDS: + status = QdcmCMDHandler(input_parcel, output_parcel); + break; + + case qService::IQService::MIN_HDCP_ENCRYPTION_LEVEL_CHANGED: { + int disp_id = input_parcel->readInt32(); + uint32_t min_enc_level = UINT32(input_parcel->readInt32()); + status = MinHdcpEncryptionLevelChanged(disp_id, min_enc_level); + output_parcel->writeInt32(status); + } + break; + + case qService::IQService::CONTROL_PARTIAL_UPDATE: { + int disp_id = input_parcel->readInt32(); + uint32_t enable = UINT32(input_parcel->readInt32()); + status = ControlPartialUpdate(disp_id, enable == 1); + output_parcel->writeInt32(status); + } + break; + + case qService::IQService::SET_ACTIVE_CONFIG: { + uint32_t config = UINT32(input_parcel->readInt32()); + int disp_id = input_parcel->readInt32(); + status = SetActiveConfigIndex(disp_id, config); + } + break; + + case qService::IQService::GET_ACTIVE_CONFIG: { + int disp_id = input_parcel->readInt32(); + uint32_t config = 0; + status = GetActiveConfigIndex(disp_id, &config); + output_parcel->writeInt32(INT(config)); + } + break; + + case qService::IQService::GET_CONFIG_COUNT: { + int disp_id = input_parcel->readInt32(); + uint32_t count = 0; + status = GetConfigCount(disp_id, &count); + output_parcel->writeInt32(INT(count)); + } + break; + + case qService::IQService::GET_DISPLAY_ATTRIBUTES_FOR_CONFIG: + status = HandleGetDisplayAttributesForConfig(input_parcel, output_parcel); + break; + + case qService::IQService::GET_PANEL_BRIGHTNESS: { + int level = 0; + status = GetPanelBrightness(&level); + output_parcel->writeInt32(level); + } + break; + + case qService::IQService::SET_PANEL_BRIGHTNESS: { + uint32_t level = UINT32(input_parcel->readInt32()); + status = setPanelBrightness(level); + output_parcel->writeInt32(status); + } + break; + + case qService::IQService::GET_DISPLAY_VISIBLE_REGION: + status = GetVisibleDisplayRect(input_parcel, output_parcel); + break; + + case qService::IQService::SET_CAMERA_STATUS: { + uint32_t camera_status = UINT32(input_parcel->readInt32()); + status = setCameraLaunchStatus(camera_status); + } + break; + + case qService::IQService::GET_BW_TRANSACTION_STATUS: { + bool state = true; + status = DisplayBWTransactionPending(&state); + output_parcel->writeInt32(state); + } + break; + + case qService::IQService::SET_LAYER_MIXER_RESOLUTION: + status = SetMixerResolution(input_parcel); + break; + + case qService::IQService::SET_COLOR_MODE: + status = SetColorModeOverride(input_parcel); + break; + + default: + DLOGW("QService command = %d is not supported", command); + return -EINVAL; + } + + return status; +} + +android::status_t HWCSession::HandleGetDisplayAttributesForConfig(const android::Parcel + *input_parcel, + android::Parcel *output_parcel) { + int config = input_parcel->readInt32(); + int dpy = input_parcel->readInt32(); + int error = android::BAD_VALUE; + DisplayConfigVariableInfo display_attributes; + + if (dpy < HWC_DISPLAY_PRIMARY || dpy >= HWC_NUM_DISPLAY_TYPES || config < 0) { + return android::BAD_VALUE; + } + + SEQUENCE_WAIT_SCOPE_LOCK(locker_[dpy]); + if (hwc_display_[dpy]) { + error = hwc_display_[dpy]->GetDisplayAttributesForConfig(config, &display_attributes); + if (error == 0) { + output_parcel->writeInt32(INT(display_attributes.vsync_period_ns)); + output_parcel->writeInt32(INT(display_attributes.x_pixels)); + output_parcel->writeInt32(INT(display_attributes.y_pixels)); + output_parcel->writeFloat(display_attributes.x_dpi); + output_parcel->writeFloat(display_attributes.y_dpi); + output_parcel->writeInt32(0); // Panel type, unsupported. + } + } + + return error; +} + +android::status_t HWCSession::ConfigureRefreshRate(const android::Parcel *input_parcel) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]); + + uint32_t operation = UINT32(input_parcel->readInt32()); + HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY]; + + switch (operation) { + case qdutils::DISABLE_METADATA_DYN_REFRESH_RATE: + return hwc_display->Perform(HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, false); + + case qdutils::ENABLE_METADATA_DYN_REFRESH_RATE: + return hwc_display->Perform(HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, true); + + case qdutils::SET_BINDER_DYN_REFRESH_RATE: { + uint32_t refresh_rate = UINT32(input_parcel->readInt32()); + return hwc_display->Perform(HWCDisplayPrimary::SET_BINDER_DYN_REFRESH_RATE, refresh_rate); + } + + default: + DLOGW("Invalid operation %d", operation); + return -EINVAL; + } + + return 0; +} + +android::status_t HWCSession::SetDisplayMode(const android::Parcel *input_parcel) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]); + + uint32_t mode = UINT32(input_parcel->readInt32()); + return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(HWCDisplayPrimary::SET_DISPLAY_MODE, mode); +} + +android::status_t HWCSession::SetMaxMixerStages(const android::Parcel *input_parcel) { + DisplayError error = kErrorNone; + std::bitset<32> bit_mask_display_type = UINT32(input_parcel->readInt32()); + uint32_t max_mixer_stages = UINT32(input_parcel->readInt32()); + + if (bit_mask_display_type[HWC_DISPLAY_PRIMARY]) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]); + if (hwc_display_[HWC_DISPLAY_PRIMARY]) { + error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetMaxMixerStages(max_mixer_stages); + if (error != kErrorNone) { + return -EINVAL; + } + } + } + + if (bit_mask_display_type[HWC_DISPLAY_EXTERNAL]) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_EXTERNAL]); + if (hwc_display_[HWC_DISPLAY_EXTERNAL]) { + error = hwc_display_[HWC_DISPLAY_EXTERNAL]->SetMaxMixerStages(max_mixer_stages); + if (error != kErrorNone) { + return -EINVAL; + } + } + } + + if (bit_mask_display_type[HWC_DISPLAY_VIRTUAL]) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_VIRTUAL]); + if (hwc_display_[HWC_DISPLAY_VIRTUAL]) { + error = hwc_display_[HWC_DISPLAY_VIRTUAL]->SetMaxMixerStages(max_mixer_stages); + if (error != kErrorNone) { + return -EINVAL; + } + } + } + + return 0; +} + +void HWCSession::SetFrameDumpConfig(const android::Parcel *input_parcel) { + uint32_t frame_dump_count = UINT32(input_parcel->readInt32()); + std::bitset<32> bit_mask_display_type = UINT32(input_parcel->readInt32()); + uint32_t bit_mask_layer_type = UINT32(input_parcel->readInt32()); + + if (bit_mask_display_type[HWC_DISPLAY_PRIMARY]) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]); + if (hwc_display_[HWC_DISPLAY_PRIMARY]) { + hwc_display_[HWC_DISPLAY_PRIMARY]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type); + } + } + + if (bit_mask_display_type[HWC_DISPLAY_EXTERNAL]) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_EXTERNAL]); + if (hwc_display_[HWC_DISPLAY_EXTERNAL]) { + hwc_display_[HWC_DISPLAY_EXTERNAL]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type); + } + } + + if (bit_mask_display_type[HWC_DISPLAY_VIRTUAL]) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_VIRTUAL]); + if (hwc_display_[HWC_DISPLAY_VIRTUAL]) { + hwc_display_[HWC_DISPLAY_VIRTUAL]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type); + } + } +} + +android::status_t HWCSession::SetMixerResolution(const android::Parcel *input_parcel) { + DisplayError error = kErrorNone; + uint32_t dpy = UINT32(input_parcel->readInt32()); + + if (dpy != HWC_DISPLAY_PRIMARY) { + DLOGI("Resoulution change not supported for this display %d", dpy); + return -EINVAL; + } + + SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]); + if (!hwc_display_[HWC_DISPLAY_PRIMARY]) { + DLOGI("Primary display is not initialized"); + return -EINVAL; + } + + uint32_t width = UINT32(input_parcel->readInt32()); + uint32_t height = UINT32(input_parcel->readInt32()); + + error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetMixerResolution(width, height); + if (error != kErrorNone) { + return -EINVAL; + } + + return 0; +} + +android::status_t HWCSession::SetColorModeOverride(const android::Parcel *input_parcel) { + auto display = static_cast<hwc2_display_t >(input_parcel->readInt32()); + auto mode = static_cast<android_color_mode_t>(input_parcel->readInt32()); + auto device = static_cast<hwc2_device_t *>(this); + + if (display >= HWC_NUM_DISPLAY_TYPES) { + return -EINVAL; + } + auto err = CallDisplayFunction(device, display, &HWCDisplay::SetColorMode, mode); + if (err != HWC2_ERROR_NONE) + return -EINVAL; + + return 0; +} + +void HWCSession::DynamicDebug(const android::Parcel *input_parcel) { + // TODO(user): Do we really need a lock here? + + int type = input_parcel->readInt32(); + bool enable = (input_parcel->readInt32() > 0); + DLOGI("type = %d enable = %d", type, enable); + int verbose_level = input_parcel->readInt32(); + + switch (type) { + case qService::IQService::DEBUG_ALL: + HWCDebugHandler::DebugAll(enable, verbose_level); + break; + + case qService::IQService::DEBUG_MDPCOMP: + HWCDebugHandler::DebugStrategy(enable, verbose_level); + HWCDebugHandler::DebugCompManager(enable, verbose_level); + break; + + case qService::IQService::DEBUG_PIPE_LIFECYCLE: + HWCDebugHandler::DebugResources(enable, verbose_level); + break; + + case qService::IQService::DEBUG_DRIVER_CONFIG: + HWCDebugHandler::DebugDriverConfig(enable, verbose_level); + break; + + case qService::IQService::DEBUG_ROTATOR: + HWCDebugHandler::DebugResources(enable, verbose_level); + HWCDebugHandler::DebugDriverConfig(enable, verbose_level); + HWCDebugHandler::DebugRotator(enable, verbose_level); + break; + + case qService::IQService::DEBUG_QDCM: + HWCDebugHandler::DebugQdcm(enable, verbose_level); + break; + + case qService::IQService::DEBUG_SCALAR: + HWCDebugHandler::DebugScalar(enable, verbose_level); + break; + + case qService::IQService::DEBUG_CLIENT: + HWCDebugHandler::DebugClient(enable, verbose_level); + break; + + case qService::IQService::DEBUG_DISPLAY: + HWCDebugHandler::DebugDisplay(enable, verbose_level); + break; + + default: + DLOGW("type = %d is not supported", type); + } +} + +android::status_t HWCSession::QdcmCMDHandler(const android::Parcel *input_parcel, + android::Parcel *output_parcel) { + int ret = 0; + int32_t *brightness_value = NULL; + uint32_t display_id(0); + PPPendingParams pending_action; + PPDisplayAPIPayload resp_payload, req_payload; + + if (!color_mgr_) { + return -1; + } + + pending_action.action = kNoAction; + pending_action.params = NULL; + + // Read display_id, payload_size and payload from in_parcel. + ret = HWCColorManager::CreatePayloadFromParcel(*input_parcel, &display_id, &req_payload); + if (!ret) { + if (HWC_DISPLAY_PRIMARY == display_id && hwc_display_[HWC_DISPLAY_PRIMARY]) + ret = hwc_display_[HWC_DISPLAY_PRIMARY]->ColorSVCRequestRoute(req_payload, &resp_payload, + &pending_action); + + if (HWC_DISPLAY_EXTERNAL == display_id && hwc_display_[HWC_DISPLAY_EXTERNAL]) + ret = hwc_display_[HWC_DISPLAY_EXTERNAL]->ColorSVCRequestRoute(req_payload, &resp_payload, + &pending_action); + } + + if (ret) { + output_parcel->writeInt32(ret); // first field in out parcel indicates return code. + req_payload.DestroyPayload(); + resp_payload.DestroyPayload(); + return ret; + } + + + int32_t action = pending_action.action; + int count = -1; + bool reset_validate = true; + while (action > 0) { + count++; + int32_t bit = (action & 1); + action = action >> 1; + + if (!bit) + continue; + + DLOGV_IF(kTagQDCM, "pending action = %d", BITMAP(count)); + switch (BITMAP(count)) { + case kInvalidating: + Refresh(HWC_DISPLAY_PRIMARY); + reset_validate = !disable_skip_validate_; + break; + case kEnterQDCMMode: + ret = color_mgr_->EnableQDCMMode(true, hwc_display_[HWC_DISPLAY_PRIMARY]); + break; + case kExitQDCMMode: + ret = color_mgr_->EnableQDCMMode(false, hwc_display_[HWC_DISPLAY_PRIMARY]); + break; + case kApplySolidFill: + ret = color_mgr_->SetSolidFill(pending_action.params, + true, hwc_display_[HWC_DISPLAY_PRIMARY]); + Refresh(HWC_DISPLAY_PRIMARY); + break; + case kDisableSolidFill: + ret = color_mgr_->SetSolidFill(pending_action.params, + false, hwc_display_[HWC_DISPLAY_PRIMARY]); + Refresh(HWC_DISPLAY_PRIMARY); + break; + case kSetPanelBrightness: + brightness_value = reinterpret_cast<int32_t *>(resp_payload.payload); + if (brightness_value == NULL) { + DLOGE("Brightness value is Null"); + return -EINVAL; + } + if (HWC_DISPLAY_PRIMARY == display_id) + ret = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(*brightness_value); + break; + case kEnableFrameCapture: + ret = color_mgr_->SetFrameCapture(pending_action.params, true, + hwc_display_[HWC_DISPLAY_PRIMARY]); + Refresh(HWC_DISPLAY_PRIMARY); + break; + case kDisableFrameCapture: + ret = color_mgr_->SetFrameCapture(pending_action.params, false, + hwc_display_[HWC_DISPLAY_PRIMARY]); + break; + case kConfigureDetailedEnhancer: + ret = color_mgr_->SetDetailedEnhancer(pending_action.params, + hwc_display_[HWC_DISPLAY_PRIMARY]); + Refresh(HWC_DISPLAY_PRIMARY); + break; + case kModeSet: + ret = static_cast<int> + (hwc_display_[HWC_DISPLAY_PRIMARY]->RestoreColorTransform()); + Refresh(HWC_DISPLAY_PRIMARY); + break; + case kNoAction: + break; + default: + DLOGW("Invalid pending action = %d!", pending_action.action); + break; + } + } + // for display API getter case, marshall returned params into out_parcel. + output_parcel->writeInt32(ret); + HWCColorManager::MarshallStructIntoParcel(resp_payload, output_parcel); + req_payload.DestroyPayload(); + resp_payload.DestroyPayload(); + if (reset_validate) { + hwc_display_[display_id]->ResetValidation(); + } + + return (ret ? -EINVAL : 0); +} + +void HWCSession::UEventHandler(const char *uevent_data, int length) { + if (!strcasecmp(uevent_data, HWC_UEVENT_SWITCH_HDMI)) { + DLOGI("Uevent HDMI = %s", uevent_data); + int connected = GetEventValue(uevent_data, length, "SWITCH_STATE="); + if (connected >= 0) { + DLOGI("HDMI = %s", connected ? "connected" : "disconnected"); + if (HotPlugHandler(connected) == -1) { + DLOGE("Failed handling Hotplug = %s", connected ? "connected" : "disconnected"); + } + } + } else if (!strcasecmp(uevent_data, HWC_UEVENT_GRAPHICS_FB0)) { + DLOGI("Uevent FB0 = %s", uevent_data); + int panel_reset = GetEventValue(uevent_data, length, "PANEL_ALIVE="); + if (panel_reset == 0) { + Refresh(0); + reset_panel_ = true; + } + } +} + +int HWCSession::GetEventValue(const char *uevent_data, int length, const char *event_info) { + const char *iterator_str = uevent_data; + while (((iterator_str - uevent_data) <= length) && (*iterator_str)) { + const char *pstr = strstr(iterator_str, event_info); + if (pstr != NULL) { + return (atoi(iterator_str + strlen(event_info))); + } + iterator_str += strlen(iterator_str) + 1; + } + + return -1; +} + +void HWCSession::ResetPanel() { + HWC2::Error status; + + DLOGI("Powering off primary"); + status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPowerMode(HWC2::PowerMode::Off); + if (status != HWC2::Error::None) { + DLOGE("power-off on primary failed with error = %d", status); + } + + DLOGI("Restoring power mode on primary"); + HWC2::PowerMode mode = hwc_display_[HWC_DISPLAY_PRIMARY]->GetLastPowerMode(); + status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPowerMode(mode); + if (status != HWC2::Error::None) { + DLOGE("Setting power mode = %d on primary failed with error = %d", mode, status); + } + + status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetVsyncEnabled(HWC2::Vsync::Enable); + if (status != HWC2::Error::None) { + DLOGE("enabling vsync failed for primary with error = %d", status); + } + + reset_panel_ = false; +} + +int HWCSession::HotPlugHandler(bool connected) { + int status = 0; + bool notify_hotplug = false; + + // To prevent sending events to client while a lock is held, acquire scope locks only within + // below scope so that those get automatically unlocked after the scope ends. + do { + // If HDMI is primary but not created yet (first time), create it and notify surfaceflinger. + // if it is already created, but got disconnected/connected again, + // just toggle display status and do not notify surfaceflinger. + // If HDMI is not primary, create/destroy external display normally. + if (hdmi_is_primary_) { + SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]); + if (hwc_display_[HWC_DISPLAY_PRIMARY]) { + status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetState(connected); + } else { + status = CreateExternalDisplay(HWC_DISPLAY_PRIMARY); + notify_hotplug = true; + } + + break; + } + + { + SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]); + // Primary display must be connected for HDMI as secondary cases. + if (!hwc_display_[HWC_DISPLAY_PRIMARY]) { + DLOGE("Primary display is not connected."); + return -1; + } + } + + if (connected) { + SCOPE_LOCK(locker_[HWC_DISPLAY_EXTERNAL]); + Locker::ScopeLock lock_v(locker_[HWC_DISPLAY_VIRTUAL]); + // Connect external display if virtual display is not connected. + // Else, defer external display connection and process it when virtual display + // tears down; Do not notify SurfaceFlinger since connection is deferred now. + if (!hwc_display_[HWC_DISPLAY_VIRTUAL]) { + status = ConnectDisplay(HWC_DISPLAY_EXTERNAL); + if (status) { + return status; + } + notify_hotplug = true; + } else { + DLOGI("Virtual display is connected, pending connection"); + external_pending_connect_ = true; + } + } else { + SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_EXTERNAL]); + // Do not return error if external display is not in connected status. + // Due to virtual display concurrency, external display connection might be still pending + // but hdmi got disconnected before pending connection could be processed. + if (hwc_display_[HWC_DISPLAY_EXTERNAL]) { + status = DisconnectDisplay(HWC_DISPLAY_EXTERNAL); + notify_hotplug = true; + } + external_pending_connect_ = false; + } + } while (0); + + if (connected) { + Refresh(0); + + if (!hdmi_is_primary_) { + // wait for sufficient time to ensure sufficient resources are available to process new + // new display connection. + uint32_t vsync_period = UINT32(GetVsyncPeriod(HWC_DISPLAY_PRIMARY)); + usleep(vsync_period * 2 / 1000); + } + } + + // notify client + if (notify_hotplug) { + HotPlug(hdmi_is_primary_ ? HWC_DISPLAY_PRIMARY : HWC_DISPLAY_EXTERNAL, + connected ? HWC2::Connection::Connected : HWC2::Connection::Disconnected); + } + + qservice_->onHdmiHotplug(INT(connected)); + + return 0; +} + +int HWCSession::GetVsyncPeriod(int disp) { + SCOPE_LOCK(locker_[disp]); + // default value + int32_t vsync_period = 1000000000l / 60; + auto attribute = HWC2::Attribute::VsyncPeriod; + + if (hwc_display_[disp]) { + hwc_display_[disp]->GetDisplayAttribute(0, attribute, &vsync_period); + } + + return vsync_period; +} + +android::status_t HWCSession::GetVisibleDisplayRect(const android::Parcel *input_parcel, + android::Parcel *output_parcel) { + int dpy = input_parcel->readInt32(); + if (dpy < HWC_DISPLAY_PRIMARY || dpy >= HWC_NUM_DISPLAY_TYPES) { + return android::BAD_VALUE; + } + + SEQUENCE_WAIT_SCOPE_LOCK(locker_[dpy]); + if (!hwc_display_[dpy]) { + return android::NO_INIT; + } + + hwc_rect_t visible_rect = {0, 0, 0, 0}; + int error = hwc_display_[dpy]->GetVisibleDisplayRect(&visible_rect); + if (error < 0) { + return error; + } + + output_parcel->writeInt32(visible_rect.left); + output_parcel->writeInt32(visible_rect.top); + output_parcel->writeInt32(visible_rect.right); + output_parcel->writeInt32(visible_rect.bottom); + + return android::NO_ERROR; +} + +void HWCSession::Refresh(hwc2_display_t display) { + SCOPE_LOCK(callbacks_lock_); + HWC2::Error err = callbacks_.Refresh(display); + while (err != HWC2::Error::None) { + callbacks_lock_.Wait(); + err = callbacks_.Refresh(display); + } +} + +void HWCSession::HotPlug(hwc2_display_t display, HWC2::Connection state) { + SCOPE_LOCK(callbacks_lock_); + HWC2::Error err = callbacks_.Hotplug(display, state); + while (err != HWC2::Error::None) { + callbacks_lock_.Wait(); + err = callbacks_.Hotplug(display, state); + } +} + +int HWCSession::CreateExternalDisplay(int disp, uint32_t primary_width, + uint32_t primary_height, bool use_primary_res) { + uint32_t panel_bpp = 0; + uint32_t pattern_type = 0; + if (qdutils::isDPConnected()) { + qdutils::getDPTestConfig(&panel_bpp, &pattern_type); + } + if (panel_bpp && pattern_type) { + return HWCDisplayExternalTest::Create(core_intf_, &buffer_allocator_, &callbacks_, + qservice_, panel_bpp, + pattern_type, &hwc_display_[disp]); + } + if (use_primary_res) { + return HWCDisplayExternal::Create(core_intf_, &buffer_allocator_, &callbacks_, + primary_width, primary_height, qservice_, + use_primary_res, &hwc_display_[disp]); + } else { + return HWCDisplayExternal::Create(core_intf_, &buffer_allocator_, &callbacks_, + qservice_, &hwc_display_[disp]); + } +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/hwc2/hwc_session.h b/msm8909/sdm/libs/hwc2/hwc_session.h new file mode 100644 index 00000000..c7941762 --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_session.h @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2014-2017, 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__ + +#ifdef DISPLAY_CONFIG_1_1 +#include <vendor/display/config/1.1/IDisplayConfig.h> +#else +#include <vendor/display/config/1.0/IDisplayConfig.h> +#endif + +#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" +#include "hwc_socket_handler.h" + +namespace sdm { + +#ifdef DISPLAY_CONFIG_1_1 +using vendor::display::config::V1_1::IDisplayConfig; +#else +using ::vendor::display::config::V1_0::IDisplayConfig; +#endif +using ::android::hardware::Return; + +// Create a singleton uevent listener thread valid for life of hardware composer process. +// This thread blocks on uevents poll inside uevent library implementation. This poll exits +// only when there is a valid uevent, it can not be interrupted otherwise. Tieing life cycle +// of this thread with HWC session cause HWC deinitialization to wait infinitely for the +// thread to exit. +class HWCUEventListener { + public: + virtual ~HWCUEventListener() {} + virtual void UEventHandler(const char *uevent_data, int length) = 0; +}; + +class HWCUEvent { + public: + HWCUEvent(); + static void UEventThread(HWCUEvent *hwc_event); + void Register(HWCUEventListener *uevent_listener); + inline bool InitDone() { return init_done_; } + + private: + std::mutex mutex_; + std::condition_variable caller_cv_; + HWCUEventListener *uevent_listener_ = nullptr; + bool init_done_ = false; +}; + +class HWCSession : hwc2_device_t, HWCUEventListener, IDisplayConfig, 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, int32_t *format); + + 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_PARAMETER; + } + + if (display >= HWC_NUM_DISPLAY_TYPES) { + return HWC2_ERROR_BAD_DISPLAY; + } + + SCOPE_LOCK(locker_[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; + } + + SCOPE_LOCK(locker_[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)...); + if (hwc_session->hwc_display_[display]->GetGeometryChanges()) { + hwc_session->hwc_display_[display]->ResetValidation(); + } + } + } + return INT32(status); + } + + // HWC2 Functions that require a concrete implementation in hwc session + // and hence need to be member functions + static int32_t AcceptDisplayChanges(hwc2_device_t *device, hwc2_display_t display); + static int32_t CreateLayer(hwc2_device_t *device, hwc2_display_t display, + hwc2_layer_t *out_layer_id); + static int32_t CreateVirtualDisplay(hwc2_device_t *device, uint32_t width, uint32_t height, + int32_t *format, hwc2_display_t *out_display_id); + static int32_t DestroyLayer(hwc2_device_t *device, hwc2_display_t display, hwc2_layer_t layer); + static int32_t DestroyVirtualDisplay(hwc2_device_t *device, hwc2_display_t display); + static void Dump(hwc2_device_t *device, uint32_t *out_size, char *out_buffer); + 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 SetPowerMode(hwc2_device_t *device, hwc2_display_t display, int32_t int_mode); + static int32_t ValidateDisplay(hwc2_device_t *device, hwc2_display_t display, + uint32_t *out_num_types, uint32_t *out_num_requests); + static int32_t SetColorMode(hwc2_device_t *device, hwc2_display_t display, + int32_t /*android_color_mode_t*/ int_mode); + static int32_t SetColorTransform(hwc2_device_t *device, hwc2_display_t display, + const float *matrix, int32_t /*android_color_transform_t*/ hint); + + private: + static const int kExternalConnectionTimeoutMs = 500; + static const int kPartialUpdateControlTimeoutMs = 100; + static bool disable_skip_validate_; + + // 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 handler + virtual void UEventHandler(const char *uevent_data, int length); + 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); + int32_t GetConfigCount(int disp_id, uint32_t *count); + int32_t GetActiveConfigIndex(int disp_id, uint32_t *config); + int32_t SetActiveConfigIndex(int disp_id, uint32_t config); + int32_t ControlPartialUpdate(int dpy, bool enable); + int32_t DisplayBWTransactionPending(bool *status); + int32_t SetSecondaryDisplayStatus(int disp_id, HWCDisplay::DisplayStatus status); + int32_t GetPanelBrightness(int *level); + int32_t MinHdcpEncryptionLevelChanged(int disp_id, uint32_t min_enc_level); + int32_t CreateExternalDisplay(int disp, uint32_t primary_width = 0, + uint32_t primary_height = 0, + bool use_primary_res = false); + + // service methods + void StartServices(); + + // Methods from ::android::hardware::display::config::V1_0::IDisplayConfig follow. + Return<void> isDisplayConnected(IDisplayConfig::DisplayType dpy, + isDisplayConnected_cb _hidl_cb) override; + Return<int32_t> setSecondayDisplayStatus(IDisplayConfig::DisplayType dpy, + IDisplayConfig::DisplayExternalStatus status) override; + Return<int32_t> configureDynRefeshRate(IDisplayConfig::DisplayDynRefreshRateOp op, + uint32_t refreshRate) override; + Return<void> getConfigCount(IDisplayConfig::DisplayType dpy, + getConfigCount_cb _hidl_cb) override; + Return<void> getActiveConfig(IDisplayConfig::DisplayType dpy, + getActiveConfig_cb _hidl_cb) override; + Return<int32_t> setActiveConfig(IDisplayConfig::DisplayType dpy, uint32_t config) override; + Return<void> getDisplayAttributes(uint32_t configIndex, IDisplayConfig::DisplayType dpy, + getDisplayAttributes_cb _hidl_cb) override; + Return<int32_t> setPanelBrightness(uint32_t level) override; + Return<void> getPanelBrightness(getPanelBrightness_cb _hidl_cb) override; + Return<int32_t> minHdcpEncryptionLevelChanged(IDisplayConfig::DisplayType dpy, + uint32_t min_enc_level) override; + Return<int32_t> refreshScreen() override; + Return<int32_t> controlPartialUpdate(IDisplayConfig::DisplayType dpy, bool enable) override; + Return<int32_t> toggleScreenUpdate(bool on) override; + Return<int32_t> setIdleTimeout(uint32_t value) override; + Return<void> getHDRCapabilities(IDisplayConfig::DisplayType dpy, + getHDRCapabilities_cb _hidl_cb) override; + Return<int32_t> setCameraLaunchStatus(uint32_t on) override; + Return<void> displayBWTransactionPending(displayBWTransactionPending_cb _hidl_cb) override; + + // Methods from ::android::hardware::display::config::V1_1::IDisplayConfig follow. +#ifdef DISPLAY_CONFIG_1_1 + Return<int32_t> setDisplayAnimating(uint64_t display_id, bool animating) override; +#endif + + // 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 ConfigureRefreshRate(const android::Parcel *input_parcel); + android::status_t QdcmCMDHandler(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 SetMixerResolution(const android::Parcel *input_parcel); + android::status_t SetColorModeOverride(const android::Parcel *input_parcel); + + void Refresh(hwc2_display_t display); + void HotPlug(hwc2_display_t display, HWC2::Connection state); + + static Locker locker_[HWC_NUM_DISPLAY_TYPES]; + CoreInterface *core_intf_ = nullptr; + HWCDisplay *hwc_display_[HWC_NUM_DISPLAY_TYPES] = {nullptr}; + HWCCallbacks callbacks_; + HWCBufferAllocator buffer_allocator_; + HWCBufferSyncHandler buffer_sync_handler_; + HWCColorManager *color_mgr_ = nullptr; + 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_ = nullptr; + HWCSocketHandler socket_handler_; + bool hdmi_is_primary_ = false; + Locker callbacks_lock_; +}; + +} // namespace sdm + +#endif // __HWC_SESSION_H__ diff --git a/msm8909/sdm/libs/hwc2/hwc_session_services.cpp b/msm8909/sdm/libs/hwc2/hwc_session_services.cpp new file mode 100644 index 00000000..e8df03e0 --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_session_services.cpp @@ -0,0 +1,494 @@ +/* +* Copyright (c) 2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation. nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <core/buffer_allocator.h> +#include <utils/debug.h> +#include <sync/sync.h> +#include <profiler.h> + +#include "hwc_buffer_sync_handler.h" +#include "hwc_session.h" + +#define __CLASS__ "HWCSession" + +namespace sdm { + +using ::android::hardware::Void; + +void HWCSession::StartServices() { + status_t status = IDisplayConfig::registerAsService(); + if (status != OK) { + ALOGW("%s::%s: Could not register IDisplayConfig as service (%d).", + __CLASS__, __FUNCTION__, status); + } else { + ALOGI("%s::%s: IDisplayConfig service registration completed.", __CLASS__, __FUNCTION__); + } +} + +int MapDisplayType(IDisplayConfig::DisplayType dpy) { + switch (dpy) { + case IDisplayConfig::DisplayType::DISPLAY_PRIMARY: + return HWC_DISPLAY_PRIMARY; + + case IDisplayConfig::DisplayType::DISPLAY_EXTERNAL: + return HWC_DISPLAY_EXTERNAL; + + case IDisplayConfig::DisplayType::DISPLAY_VIRTUAL: + return HWC_DISPLAY_VIRTUAL; + + default: + break; + } + + return -EINVAL; +} + +HWCDisplay::DisplayStatus MapExternalStatus(IDisplayConfig::DisplayExternalStatus status) { + switch (status) { + case IDisplayConfig::DisplayExternalStatus::EXTERNAL_OFFLINE: + return HWCDisplay::kDisplayStatusOffline; + + case IDisplayConfig::DisplayExternalStatus::EXTERNAL_ONLINE: + return HWCDisplay::kDisplayStatusOnline; + + case IDisplayConfig::DisplayExternalStatus::EXTERNAL_PAUSE: + return HWCDisplay::kDisplayStatusPause; + + case IDisplayConfig::DisplayExternalStatus::EXTERNAL_RESUME: + return HWCDisplay::kDisplayStatusResume; + + default: + break; + } + + return HWCDisplay::kDisplayStatusInvalid; +} + +// Methods from ::vendor::hardware::display::config::V1_0::IDisplayConfig follow. +Return<void> HWCSession::isDisplayConnected(IDisplayConfig::DisplayType dpy, + isDisplayConnected_cb _hidl_cb) { + int32_t error = -EINVAL; + bool connected = false; + + int disp_id = MapDisplayType(dpy); + SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]); + + if (disp_id >= 0) { + connected = hwc_display_[disp_id]; + error = 0; + } + + _hidl_cb(error, connected); + + return Void(); +} + +int32_t HWCSession::SetSecondaryDisplayStatus(int disp_id, HWCDisplay::DisplayStatus status) { + if (disp_id < 0) { + return -EINVAL; + } + + SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]); + DLOGI("Display = %d, Status = %d", disp_id, status); + + if (disp_id == HWC_DISPLAY_PRIMARY) { + DLOGE("Not supported for this display"); + } else if (!hwc_display_[disp_id]) { + DLOGW("Display is not connected"); + } else { + return hwc_display_[disp_id]->SetDisplayStatus(status); + } + + return -EINVAL; +} + +Return<int32_t> HWCSession::setSecondayDisplayStatus(IDisplayConfig::DisplayType dpy, + IDisplayConfig::DisplayExternalStatus status) { + return SetSecondaryDisplayStatus(MapDisplayType(dpy), MapExternalStatus(status)); +} + +Return<int32_t> HWCSession::configureDynRefeshRate(IDisplayConfig::DisplayDynRefreshRateOp op, + uint32_t refreshRate) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]); + HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY]; + + switch (op) { + case IDisplayConfig::DisplayDynRefreshRateOp::DISABLE_METADATA_DYN_REFRESH_RATE: + return hwc_display->Perform(HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, false); + + case IDisplayConfig::DisplayDynRefreshRateOp::ENABLE_METADATA_DYN_REFRESH_RATE: + return hwc_display->Perform(HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, true); + + case IDisplayConfig::DisplayDynRefreshRateOp::SET_BINDER_DYN_REFRESH_RATE: + return hwc_display->Perform(HWCDisplayPrimary::SET_BINDER_DYN_REFRESH_RATE, refreshRate); + + default: + DLOGW("Invalid operation %d", op); + return -EINVAL; + } + + return 0; +} + +int32_t HWCSession::GetConfigCount(int disp_id, uint32_t *count) { + if (disp_id < 0) { + return -EINVAL; + } + + SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]); + + if (hwc_display_[disp_id]) { + return hwc_display_[disp_id]->GetDisplayConfigCount(count); + } + + return -EINVAL; +} + +Return<void> HWCSession::getConfigCount(IDisplayConfig::DisplayType dpy, + getConfigCount_cb _hidl_cb) { + uint32_t count = 0; + int32_t error = GetConfigCount(MapDisplayType(dpy), &count); + + _hidl_cb(error, count); + + return Void(); +} + +int32_t HWCSession::GetActiveConfigIndex(int disp_id, uint32_t *config) { + if (disp_id < 0) { + return -EINVAL; + } + + SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]); + + if (hwc_display_[disp_id]) { + return hwc_display_[disp_id]->GetActiveDisplayConfig(config); + } + + return -EINVAL; +} + +Return<void> HWCSession::getActiveConfig(IDisplayConfig::DisplayType dpy, + getActiveConfig_cb _hidl_cb) { + uint32_t config = 0; + int32_t error = GetActiveConfigIndex(MapDisplayType(dpy), &config); + + _hidl_cb(error, config); + + return Void(); +} + +int32_t HWCSession::SetActiveConfigIndex(int disp_id, uint32_t config) { + if (disp_id < 0) { + return -EINVAL; + } + + SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]); + int32_t error = -EINVAL; + if (hwc_display_[disp_id]) { + error = hwc_display_[disp_id]->SetActiveDisplayConfig(config); + if (!error) { + Refresh(0); + } + } + + return error; +} + +Return<int32_t> HWCSession::setActiveConfig(IDisplayConfig::DisplayType dpy, uint32_t config) { + return SetActiveConfigIndex(MapDisplayType(dpy), config); +} + +Return<void> HWCSession::getDisplayAttributes(uint32_t configIndex, + IDisplayConfig::DisplayType dpy, + getDisplayAttributes_cb _hidl_cb) { + int32_t error = -EINVAL; + IDisplayConfig::DisplayAttributes display_attributes = {}; + int disp_id = MapDisplayType(dpy); + + SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]); + if (disp_id >= 0 && hwc_display_[disp_id]) { + DisplayConfigVariableInfo hwc_display_attributes; + error = hwc_display_[disp_id]->GetDisplayAttributesForConfig(static_cast<int>(configIndex), + &hwc_display_attributes); + if (!error) { + display_attributes.vsyncPeriod = hwc_display_attributes.vsync_period_ns; + display_attributes.xRes = hwc_display_attributes.x_pixels; + display_attributes.yRes = hwc_display_attributes.y_pixels; + display_attributes.xDpi = hwc_display_attributes.x_dpi; + display_attributes.yDpi = hwc_display_attributes.y_dpi; + display_attributes.panelType = IDisplayConfig::DisplayPortType::DISPLAY_PORT_DEFAULT; + display_attributes.isYuv = hwc_display_attributes.is_yuv; + } + } + + return Void(); +} + +Return<int32_t> HWCSession::setPanelBrightness(uint32_t level) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]); + int32_t error = -EINVAL; + + if (hwc_display_[HWC_DISPLAY_PRIMARY]) { + error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(static_cast<int>(level)); + if (error) { + DLOGE("Failed to set the panel brightness = %d. Error = %d", level, error); + } + } + + return error; +} + +int32_t HWCSession::GetPanelBrightness(int *level) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]); + int32_t error = -EINVAL; + + if (hwc_display_[HWC_DISPLAY_PRIMARY]) { + error = hwc_display_[HWC_DISPLAY_PRIMARY]->GetPanelBrightness(level); + if (error) { + DLOGE("Failed to get the panel brightness. Error = %d", error); + } + } + + return error; +} + +Return<void> HWCSession::getPanelBrightness(getPanelBrightness_cb _hidl_cb) { + int level = 0; + int32_t error = GetPanelBrightness(&level); + + _hidl_cb(error, static_cast<uint32_t>(level)); + + return Void(); +} + +int32_t HWCSession::MinHdcpEncryptionLevelChanged(int disp_id, uint32_t min_enc_level) { + DLOGI("Display %d", disp_id); + + if (disp_id < 0) { + return -EINVAL; + } + + SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]); + if (disp_id != HWC_DISPLAY_EXTERNAL) { + DLOGE("Not supported for display"); + } else if (!hwc_display_[disp_id]) { + DLOGW("Display is not connected"); + } else { + return hwc_display_[disp_id]->OnMinHdcpEncryptionLevelChange(min_enc_level); + } + + return -EINVAL; +} + +Return<int32_t> HWCSession::minHdcpEncryptionLevelChanged(IDisplayConfig::DisplayType dpy, + uint32_t min_enc_level) { + return MinHdcpEncryptionLevelChanged(MapDisplayType(dpy), min_enc_level); +} + +Return<int32_t> HWCSession::refreshScreen() { + SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]); + Refresh(HWC_DISPLAY_PRIMARY); + + return 0; +} + +int32_t HWCSession::ControlPartialUpdate(int disp_id, bool enable) { + if (disp_id < 0) { + return -EINVAL; + } + + if (disp_id != HWC_DISPLAY_PRIMARY) { + DLOGW("CONTROL_PARTIAL_UPDATE is not applicable for display = %d", disp_id); + return -EINVAL; + } + + SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]); + HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY]; + if (!hwc_display) { + DLOGE("primary display object is not instantiated"); + return -EINVAL; + } + + uint32_t pending = 0; + DisplayError hwc_error = hwc_display->ControlPartialUpdate(enable, &pending); + + if (hwc_error == kErrorNone) { + if (!pending) { + return 0; + } + } else if (hwc_error == kErrorNotSupported) { + return 0; + } else { + return -EINVAL; + } + + // Todo(user): Unlock it before sending events to client. It may cause deadlocks in future. + Refresh(HWC_DISPLAY_PRIMARY); + + // Wait until partial update control is complete + int32_t error = locker_[disp_id].WaitFinite(kPartialUpdateControlTimeoutMs); + + return error; +} + +Return<int32_t> HWCSession::controlPartialUpdate(IDisplayConfig::DisplayType dpy, bool enable) { + return ControlPartialUpdate(MapDisplayType(dpy), enable); +} + +Return<int32_t> HWCSession::toggleScreenUpdate(bool on) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]); + + int32_t error = -EINVAL; + if (hwc_display_[HWC_DISPLAY_PRIMARY]) { + error = hwc_display_[HWC_DISPLAY_PRIMARY]->ToggleScreenUpdates(on); + if (error) { + DLOGE("Failed to toggle screen updates = %d. Error = %d", on, error); + } + } + + return error; +} + +Return<int32_t> HWCSession::setIdleTimeout(uint32_t value) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]); + + if (hwc_display_[HWC_DISPLAY_PRIMARY]) { + hwc_display_[HWC_DISPLAY_PRIMARY]->SetIdleTimeoutMs(value); + return 0; + } + + return -EINVAL; +} + +Return<void> HWCSession::getHDRCapabilities(IDisplayConfig::DisplayType dpy, + getHDRCapabilities_cb _hidl_cb) { + int32_t error = -EINVAL; + IDisplayConfig::DisplayHDRCapabilities hdr_caps = {}; + + do { + int disp_id = MapDisplayType(dpy); + if (disp_id < 0) { + DLOGE("Invalid display id = %d", disp_id); + break; + } + + SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]); + HWCDisplay *hwc_display = hwc_display_[disp_id]; + if (!hwc_display) { + DLOGE("Display = %d is not connected.", disp_id); + break; + } + + // query number of hdr types + uint32_t out_num_types = 0; + if (hwc_display->GetHdrCapabilities(&out_num_types, nullptr, nullptr, nullptr, nullptr) + != HWC2::Error::None) { + break; + } + + if (!out_num_types) { + error = 0; + break; + } + + // query hdr caps + hdr_caps.supportedHdrTypes.resize(out_num_types); + + float out_max_luminance = 0.0f; + float out_max_average_luminance = 0.0f; + float out_min_luminance = 0.0f; + if (hwc_display->GetHdrCapabilities(&out_num_types, hdr_caps.supportedHdrTypes.data(), + &out_max_luminance, &out_max_average_luminance, + &out_min_luminance) + == HWC2::Error::None) { + error = 0; + } + } while (false); + + _hidl_cb(error, hdr_caps); + + return Void(); +} + +Return<int32_t> HWCSession::setCameraLaunchStatus(uint32_t on) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]); + + HWBwModes mode = on > 0 ? kBwCamera : kBwDefault; + + // trigger invalidate to apply new bw caps. + Refresh(HWC_DISPLAY_PRIMARY); + + if (core_intf_->SetMaxBandwidthMode(mode) != kErrorNone) { + return -EINVAL; + } + + new_bw_mode_ = true; + need_invalidate_ = true; + hwc_display_[HWC_DISPLAY_PRIMARY]->ResetValidation(); + + return 0; +} + +int32_t HWCSession::DisplayBWTransactionPending(bool *status) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]); + + if (hwc_display_[HWC_DISPLAY_PRIMARY]) { + if (sync_wait(bw_mode_release_fd_, 0) < 0) { + DLOGI("bw_transaction_release_fd is not yet signaled: err= %s", strerror(errno)); + *status = false; + } + + return 0; + } + + return -EINVAL; +} + +Return<void> HWCSession::displayBWTransactionPending(displayBWTransactionPending_cb _hidl_cb) { + bool status = true; + + int32_t error = DisplayBWTransactionPending(&status); + + _hidl_cb(error, status); + + return Void(); +} + +#ifdef DISPLAY_CONFIG_1_1 +// Methods from ::vendor::hardware::display::config::V1_1::IDisplayConfig follow. +Return<int32_t> HWCSession::setDisplayAnimating(uint64_t display_id, bool animating ) { + SEQUENCE_WAIT_SCOPE_LOCK(locker_[display_id]); + return CallDisplayFunction(static_cast<hwc2_device_t *>(this), display_id, + &HWCDisplay::SetDisplayAnimating, animating); +} +#endif + + +} // namespace sdm diff --git a/msm8909/sdm/libs/hwc2/hwc_tonemapper.cpp b/msm8909/sdm/libs/hwc2/hwc_tonemapper.cpp new file mode 100644 index 00000000..e68741e6 --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_tonemapper.cpp @@ -0,0 +1,386 @@ +/* +* Copyright (c) 2016 - 2018, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <gralloc_priv.h> +#include <sync/sync.h> + +#include <TonemapFactory.h> + +#include <core/buffer_allocator.h> + +#include <utils/constants.h> +#include <utils/debug.h> +#include <utils/formats.h> +#include <utils/rect.h> +#include <utils/utils.h> + +#include <vector> + +#include "hwc_debugger.h" +#include "hwc_tonemapper.h" + +#define __CLASS__ "HWCToneMapper" + +namespace sdm { + +ToneMapSession::ToneMapSession(HWCBufferAllocator *buffer_allocator) + : tone_map_task_(*this), buffer_allocator_(buffer_allocator) { + buffer_info_.resize(kNumIntermediateBuffers); +} + +ToneMapSession::~ToneMapSession() { + tone_map_task_.PerformTask(ToneMapTaskCode::kCodeDestroy, nullptr); + FreeIntermediateBuffers(); + buffer_info_.clear(); +} + +void ToneMapSession::OnTask(const ToneMapTaskCode &task_code, + SyncTask<ToneMapTaskCode>::TaskContext *task_context) { + switch (task_code) { + case ToneMapTaskCode::kCodeGetInstance: { + ToneMapGetInstanceContext *ctx = static_cast<ToneMapGetInstanceContext *>(task_context); + Lut3d &lut_3d = ctx->layer->lut_3d; + Color10Bit *grid_entries = NULL; + int grid_size = 0; + if (lut_3d.validGridEntries) { + grid_entries = lut_3d.gridEntries; + grid_size = INT(lut_3d.gridSize); + } + gpu_tone_mapper_ = TonemapperFactory_GetInstance(tone_map_config_.type, + lut_3d.lutEntries, lut_3d.dim, + grid_entries, grid_size, + tone_map_config_.secure); + } + break; + + case ToneMapTaskCode::kCodeBlit: { + ToneMapBlitContext *ctx = static_cast<ToneMapBlitContext *>(task_context); + uint8_t buffer_index = current_buffer_index_; + const void *dst_hnd = reinterpret_cast<const void *> + (buffer_info_[buffer_index].private_data); + const void *src_hnd = reinterpret_cast<const void *> + (ctx->layer->input_buffer.buffer_id); + ctx->fence_fd = gpu_tone_mapper_->blit(dst_hnd, src_hnd, ctx->merged_fd); + } + break; + + case ToneMapTaskCode::kCodeDestroy: { + delete gpu_tone_mapper_; + } + break; + + default: + break; + } +} + +DisplayError ToneMapSession::AllocateIntermediateBuffers(const Layer *layer) { + DisplayError error = kErrorNone; + for (uint8_t i = 0; i < kNumIntermediateBuffers; i++) { + BufferInfo &buffer_info = buffer_info_[i]; + buffer_info.buffer_config.width = layer->request.width; + buffer_info.buffer_config.height = layer->request.height; + buffer_info.buffer_config.format = layer->request.format; + buffer_info.buffer_config.secure = layer->request.flags.secure; + buffer_info.buffer_config.gfx_client = true; + error = buffer_allocator_->AllocateBuffer(&buffer_info); + if (error != kErrorNone) { + FreeIntermediateBuffers(); + return error; + } + } + + return kErrorNone; +} + +void ToneMapSession::FreeIntermediateBuffers() { + for (uint8_t i = 0; i < kNumIntermediateBuffers; i++) { + // Free the valid fence + if (release_fence_fd_[i] >= 0) { + CloseFd(&release_fence_fd_[i]); + } + BufferInfo &buffer_info = buffer_info_[i]; + if (buffer_info.private_data) { + buffer_allocator_->FreeBuffer(&buffer_info); + } + } +} + +void ToneMapSession::UpdateBuffer(int acquire_fence, LayerBuffer *buffer) { + // Acquire fence will be closed by HWC Display. + // Fence returned by GPU will be closed in PostCommit. + buffer->acquire_fence_fd = acquire_fence; + buffer->size = buffer_info_[current_buffer_index_].alloc_buffer_info.size; + buffer->planes[0].fd = buffer_info_[current_buffer_index_].alloc_buffer_info.fd; +} + +void ToneMapSession::SetReleaseFence(int fd) { + CloseFd(&release_fence_fd_[current_buffer_index_]); + // Used to give to GPU tonemapper along with input layer fd + release_fence_fd_[current_buffer_index_] = dup(fd); +} + +void ToneMapSession::SetToneMapConfig(Layer *layer) { + // HDR -> SDR is FORWARD and SDR - > HDR is INVERSE + tone_map_config_.type = layer->input_buffer.flags.hdr ? TONEMAP_FORWARD : TONEMAP_INVERSE; + tone_map_config_.colorPrimaries = layer->input_buffer.color_metadata.colorPrimaries; + tone_map_config_.transfer = layer->input_buffer.color_metadata.transfer; + tone_map_config_.secure = layer->request.flags.secure; + tone_map_config_.format = layer->request.format; +} + +bool ToneMapSession::IsSameToneMapConfig(Layer *layer) { + LayerBuffer& buffer = layer->input_buffer; + private_handle_t *handle = static_cast<private_handle_t *>(buffer_info_[0].private_data); + int tonemap_type = buffer.flags.hdr ? TONEMAP_FORWARD : TONEMAP_INVERSE; + + return ((tonemap_type == tone_map_config_.type) && + (buffer.color_metadata.colorPrimaries == tone_map_config_.colorPrimaries) && + (buffer.color_metadata.transfer == tone_map_config_.transfer) && + (layer->request.flags.secure == tone_map_config_.secure) && + (layer->request.format == tone_map_config_.format) && + (layer->request.width == UINT32(handle->unaligned_width)) && + (layer->request.height == UINT32(handle->unaligned_height))); +} + +int HWCToneMapper::HandleToneMap(LayerStack *layer_stack) { + uint32_t gpu_count = 0; + DisplayError error = kErrorNone; + + for (uint32_t i = 0; i < layer_stack->layers.size(); i++) { + uint32_t session_index = 0; + Layer *layer = layer_stack->layers.at(i); + if (layer->composition == kCompositionGPU) { + gpu_count++; + } + + if (layer->request.flags.tone_map) { + DLOGV_IF(kTagClient, "Tonemapping for layer at index %d", i); + switch (layer->composition) { + case kCompositionGPUTarget: + if (!gpu_count) { + // When all layers are on FrameBuffer and if they do not update in the next draw cycle, + // then SDM marks them for SDE Composition because the cached FB layer gets displayed. + // GPU count will be 0 in this case. Try to use the existing tone-mapped frame buffer. + // No ToneMap/Blit is required. Just update the buffer & acquire fence fd of FB layer. + if (!tone_map_sessions_.empty() && (fb_session_index_ >= 0)) { + ToneMapSession *fb_tone_map_session = tone_map_sessions_.at(UINT32(fb_session_index_)); + fb_tone_map_session->UpdateBuffer(-1 /* acquire_fence */, &layer->input_buffer); + fb_tone_map_session->layer_index_ = INT(i); + fb_tone_map_session->acquired_ = true; + return 0; + } + } + error = AcquireToneMapSession(layer, &session_index); + fb_session_index_ = INT(session_index); + break; + default: + error = AcquireToneMapSession(layer, &session_index); + break; + } + + if (error != kErrorNone) { + Terminate(); + return -1; + } + + ToneMapSession *session = tone_map_sessions_.at(session_index); + ToneMap(layer, session); + DLOGI_IF(kTagClient, "Layer %d associated with session index %d", i, session_index); + session->layer_index_ = INT(i); + } + } + + return 0; +} + +void HWCToneMapper::ToneMap(Layer* layer, ToneMapSession *session) { + ToneMapBlitContext ctx = {}; + ctx.layer = layer; + + uint8_t buffer_index = session->current_buffer_index_; + int &release_fence_fd = session->release_fence_fd_[buffer_index]; + + // use and close the layer->input_buffer acquire fence fd. + int acquire_fd = layer->input_buffer.acquire_fence_fd; + buffer_sync_handler_.SyncMerge(release_fence_fd, acquire_fd, &ctx.merged_fd); + + if (acquire_fd >= 0) { + CloseFd(&acquire_fd); + } + + if (release_fence_fd >= 0) { + CloseFd(&release_fence_fd); + } + + DTRACE_BEGIN("GPU_TM_BLIT"); + session->tone_map_task_.PerformTask(ToneMapTaskCode::kCodeBlit, &ctx); + DTRACE_END(); + + DumpToneMapOutput(session, &ctx.fence_fd); + session->UpdateBuffer(ctx.fence_fd, &layer->input_buffer); +} + +void HWCToneMapper::PostCommit(LayerStack *layer_stack) { + auto it = tone_map_sessions_.begin(); + while (it != tone_map_sessions_.end()) { + uint32_t session_index = UINT32(std::distance(tone_map_sessions_.begin(), it)); + ToneMapSession *session = tone_map_sessions_.at(session_index); + if (session->acquired_) { + Layer *layer = layer_stack->layers.at(UINT32(session->layer_index_)); + // Close the fd returned by GPU ToneMapper and set release fence. + LayerBuffer &layer_buffer = layer->input_buffer; + CloseFd(&layer_buffer.acquire_fence_fd); + session->SetReleaseFence(layer_buffer.release_fence_fd); + session->acquired_ = false; + it++; + } else { + DLOGI_IF(kTagClient, "Tone map session %d closed.", session_index); + delete session; + it = tone_map_sessions_.erase(it); + int deleted_session = INT(session_index); + // If FB tonemap session gets deleted, reset fb_session_index_, else update it. + if (deleted_session == fb_session_index_) { + fb_session_index_ = -1; + } else if (deleted_session < fb_session_index_) { + fb_session_index_--; + } + } + } +} + +void HWCToneMapper::Terminate() { + if (tone_map_sessions_.size()) { + while (!tone_map_sessions_.empty()) { + delete tone_map_sessions_.back(); + tone_map_sessions_.pop_back(); + } + fb_session_index_ = -1; + } +} + +void HWCToneMapper::SetFrameDumpConfig(uint32_t count) { + DLOGI("Dump FrameConfig count = %d", count); + dump_frame_count_ = count; + dump_frame_index_ = 0; +} + +void HWCToneMapper::DumpToneMapOutput(ToneMapSession *session, int *acquire_fd) { + DisplayError error = kErrorNone; + if (!dump_frame_count_) { + return; + } + + BufferInfo &buffer_info = session->buffer_info_[session->current_buffer_index_]; + private_handle_t *target_buffer = static_cast<private_handle_t *>(buffer_info.private_data); + + if (*acquire_fd >= 0) { + int error = sync_wait(*acquire_fd, 1000); + if (error < 0) { + DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno)); + return; + } + } + + error = buffer_allocator_->MapBuffer(target_buffer, *acquire_fd); + if (error != kErrorNone) { + DLOGE("MapBuffer failed, base addr = %x", target_buffer->base); + return; + } + + size_t result = 0; + char dump_file_name[PATH_MAX]; + snprintf(dump_file_name, sizeof(dump_file_name), "%s/frame_dump_primary" + "/tonemap_%dx%d_frame%d.raw", HWCDebugHandler::DumpDir(), target_buffer->width, + target_buffer->height, dump_frame_index_); + + FILE* fp = fopen(dump_file_name, "w+"); + if (fp) { + DLOGI("base addr = %x", target_buffer->base); + result = fwrite(reinterpret_cast<void *>(target_buffer->base), target_buffer->size, 1, fp); + fclose(fp); + } + dump_frame_count_--; + dump_frame_index_++; + CloseFd(acquire_fd); +} + +DisplayError HWCToneMapper::AcquireToneMapSession(Layer *layer, uint32_t *session_index) { + // When the property vendor.display.disable_hdr_lut_gen is set, the lutEntries and gridEntries in + // the Lut3d will be NULL, clients needs to allocate the memory and set correct 3D Lut + // for Tonemapping. + if (!layer->lut_3d.lutEntries || !layer->lut_3d.dim) { + // Atleast lutEntries must be valid for GPU Tonemapper. + DLOGE("Invalid Lut Entries or lut dimension = %d", layer->lut_3d.dim); + return kErrorParameters; + } + + // Check if we can re-use an existing tone map session. + for (uint32_t i = 0; i < tone_map_sessions_.size(); i++) { + ToneMapSession *tonemap_session = tone_map_sessions_.at(i); + if (!tonemap_session->acquired_ && tonemap_session->IsSameToneMapConfig(layer)) { + tonemap_session->current_buffer_index_ = (tonemap_session->current_buffer_index_ + 1) % + ToneMapSession::kNumIntermediateBuffers; + tonemap_session->acquired_ = true; + *session_index = i; + return kErrorNone; + } + } + + ToneMapSession *session = new ToneMapSession(buffer_allocator_); + if (!session) { + return kErrorMemory; + } + + session->SetToneMapConfig(layer); + + ToneMapGetInstanceContext ctx; + ctx.layer = layer; + session->tone_map_task_.PerformTask(ToneMapTaskCode::kCodeGetInstance, &ctx); + + if (session->gpu_tone_mapper_ == NULL) { + DLOGE("Get Tonemapper failed!"); + delete session; + return kErrorNotSupported; + } + DisplayError error = session->AllocateIntermediateBuffers(layer); + if (error != kErrorNone) { + DLOGE("Allocation of Intermediate Buffers failed!"); + delete session; + return error; + } + + session->acquired_ = true; + tone_map_sessions_.push_back(session); + *session_index = UINT32(tone_map_sessions_.size() - 1); + + return kErrorNone; +} + +} // namespace sdm diff --git a/msm8909/sdm/libs/hwc2/hwc_tonemapper.h b/msm8909/sdm/libs/hwc2/hwc_tonemapper.h new file mode 100644 index 00000000..8bef3b1f --- /dev/null +++ b/msm8909/sdm/libs/hwc2/hwc_tonemapper.h @@ -0,0 +1,125 @@ +/* +* Copyright (c) 2016 - 2017, 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_TONEMAPPER_H__ +#define __HWC_TONEMAPPER_H__ + +#include <fcntl.h> +#include <sys/mman.h> + +#include <hardware/hwcomposer.h> + +#include <core/layer_stack.h> +#include <utils/sys.h> +#include <utils/sync_task.h> +#include <vector> +#include "hwc_buffer_sync_handler.h" +#include "hwc_buffer_allocator.h" + +class Tonemapper; + +namespace sdm { + +enum class ToneMapTaskCode : int32_t { + kCodeGetInstance, + kCodeBlit, + kCodeDestroy, +}; + +struct ToneMapGetInstanceContext : public SyncTask<ToneMapTaskCode>::TaskContext { + Layer *layer = nullptr; +}; + +struct ToneMapBlitContext : public SyncTask<ToneMapTaskCode>::TaskContext { + Layer *layer = nullptr; + int merged_fd = -1; + int fence_fd = -1; +}; + +struct ToneMapConfig { + int type = 0; + ColorPrimaries colorPrimaries = ColorPrimaries_Max; + GammaTransfer transfer = Transfer_Max; + LayerBufferFormat format = kFormatRGBA8888; + bool secure = false; +}; + +class ToneMapSession : public SyncTask<ToneMapTaskCode>::TaskHandler { + public: + explicit ToneMapSession(HWCBufferAllocator *buffer_allocator); + ~ToneMapSession(); + DisplayError AllocateIntermediateBuffers(const Layer *layer); + void FreeIntermediateBuffers(); + void UpdateBuffer(int acquire_fence, LayerBuffer *buffer); + void SetReleaseFence(int fd); + void SetToneMapConfig(Layer *layer); + bool IsSameToneMapConfig(Layer *layer); + + // TaskHandler methods implementation. + virtual void OnTask(const ToneMapTaskCode &task_code, + SyncTask<ToneMapTaskCode>::TaskContext *task_context); + + static const uint8_t kNumIntermediateBuffers = 2; + SyncTask<ToneMapTaskCode> tone_map_task_; + Tonemapper *gpu_tone_mapper_ = nullptr; + HWCBufferAllocator *buffer_allocator_ = nullptr; + ToneMapConfig tone_map_config_ = {}; + uint8_t current_buffer_index_ = 0; + std::vector<BufferInfo> buffer_info_ = {}; + int release_fence_fd_[kNumIntermediateBuffers] = {-1, -1}; + bool acquired_ = false; + int layer_index_ = -1; +}; + +class HWCToneMapper { + public: + explicit HWCToneMapper(HWCBufferAllocator *allocator) : buffer_allocator_(allocator) {} + ~HWCToneMapper() {} + + int HandleToneMap(LayerStack *layer_stack); + bool IsActive() { return !tone_map_sessions_.empty(); } + void PostCommit(LayerStack *layer_stack); + void SetFrameDumpConfig(uint32_t count); + void Terminate(); + + private: + void ToneMap(Layer *layer, ToneMapSession *session); + DisplayError AcquireToneMapSession(Layer *layer, uint32_t *session_index); + void DumpToneMapOutput(ToneMapSession *session, int *acquire_fence); + + std::vector<ToneMapSession*> tone_map_sessions_; + HWCBufferSyncHandler buffer_sync_handler_ = {}; + HWCBufferAllocator *buffer_allocator_ = nullptr; + uint32_t dump_frame_count_ = 0; + uint32_t dump_frame_index_ = 0; + int fb_session_index_ = -1; +}; + +} // namespace sdm +#endif // __HWC_TONEMAPPER_H__ diff --git a/msm8909/sdm/libs/utils/Android.mk b/msm8909/sdm/libs/utils/Android.mk new file mode 100644 index 00000000..09e14146 --- /dev/null +++ b/msm8909/sdm/libs/utils/Android.mk @@ -0,0 +1,32 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +include $(LOCAL_PATH)/../../../common.mk + +LOCAL_MODULE := libsdmutils +LOCAL_VENDOR_MODULE := true +LOCAL_MODULE_TAGS := optional +LOCAL_C_INCLUDES := $(common_includes) +LOCAL_HEADER_LIBRARIES := display_headers +LOCAL_CFLAGS := -DLOG_TAG=\"SDM\" $(common_flags) +LOCAL_SRC_FILES := debug.cpp \ + rect.cpp \ + sys.cpp \ + formats.cpp \ + utils.cpp + +include $(BUILD_SHARED_LIBRARY) + +SDM_HEADER_PATH := ../../include +include $(CLEAR_VARS) +LOCAL_COPY_HEADERS_TO := $(common_header_export_path)/sdm/utils +LOCAL_COPY_HEADERS = $(SDM_HEADER_PATH)/utils/constants.h \ + $(SDM_HEADER_PATH)/utils/debug.h \ + $(SDM_HEADER_PATH)/utils/formats.h \ + $(SDM_HEADER_PATH)/utils/locker.h \ + $(SDM_HEADER_PATH)/utils/rect.h \ + $(SDM_HEADER_PATH)/utils/sys.h \ + $(SDM_HEADER_PATH)/utils/sync_task.h \ + $(SDM_HEADER_PATH)/utils/utils.h \ + $(SDM_HEADER_PATH)/utils/factory.h + +include $(BUILD_COPY_HEADERS) diff --git a/msm8909/sdm/libs/utils/Makefile.am b/msm8909/sdm/libs/utils/Makefile.am new file mode 100644 index 00000000..d8d8dc5a --- /dev/null +++ b/msm8909/sdm/libs/utils/Makefile.am @@ -0,0 +1,12 @@ +cpp_sources = debug.cpp \ + rect.cpp \ + sys.cpp \ + formats.cpp \ + utils.cpp + +lib_LTLIBRARIES = libsdmutils.la +libsdmutils_la_CC = @CC@ +libsdmutils_la_SOURCES = $(cpp_sources) +libsdmutils_la_CFLAGS = $(COMMON_CFLAGS) -DLOG_TAG=\"SDM\" +libsdmutils_la_CPPFLAGS = $(AM_CPPFLAGS) +libsdmutils_la_LDFLAGS = -shared -avoid-version diff --git a/msm8909/sdm/libs/utils/debug.cpp b/msm8909/sdm/libs/utils/debug.cpp new file mode 100644 index 00000000..a012ab4e --- /dev/null +++ b/msm8909/sdm/libs/utils/debug.cpp @@ -0,0 +1,216 @@ +/* +* Copyright (c) 2014 - 2018, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <stdlib.h> +#include <utils/debug.h> +#include <utils/constants.h> +#include <string> +#include <algorithm> + +namespace sdm { + +Debug Debug::debug_; + +Debug::Debug() : debug_handler_(&default_debug_handler_) { +} + +int Debug::GetSimulationFlag() { + int value = 0; + debug_.debug_handler_->GetProperty(COMPOSITION_MASK_PROP, &value); + + return value; +} + +int Debug::GetHDMIResolution() { + int value = 0; + debug_.debug_handler_->GetProperty(HDMI_CONFIG_INDEX_PROP, &value); + return value; +} + +void Debug::GetIdleTimeoutMs(uint32_t *active_ms, uint32_t *inactive_ms) { + int active_val = IDLE_TIMEOUT_ACTIVE_MS; + int inactive_val = IDLE_TIMEOUT_INACTIVE_MS; + + debug_.debug_handler_->GetProperty(IDLE_TIME_PROP, &active_val); + debug_.debug_handler_->GetProperty(IDLE_TIME_INACTIVE_PROP, &inactive_val); + + *active_ms = UINT32(active_val); + *inactive_ms = UINT32(inactive_val); +} + +int Debug::GetBootAnimLayerCount() { + int value = 0; + debug_.debug_handler_->GetProperty(BOOT_ANIMATION_LAYER_COUNT_PROP, &value); + + return value; +} + +bool Debug::IsRotatorDownScaleDisabled() { + int value = 0; + debug_.debug_handler_->GetProperty(DISABLE_ROTATOR_DOWNSCALE_PROP, &value); + + return (value == 1); +} + +bool Debug::IsDecimationDisabled() { + int value = 0; + debug_.debug_handler_->GetProperty(DISABLE_DECIMATION_PROP, &value); + + return (value == 1); +} + +int Debug::GetMaxPipesPerMixer(DisplayType display_type) { + int value = -1; + switch (display_type) { + case kPrimary: + debug_.debug_handler_->GetProperty(PRIMARY_MIXER_STAGES_PROP, &value); + break; + case kHDMI: + debug_.debug_handler_->GetProperty(EXTERNAL_MIXER_STAGES_PROP, &value); + break; + case kVirtual: + debug_.debug_handler_->GetProperty(VIRTUAL_MIXER_STAGES_PROP, &value); + break; + default: + break; + } + + return value; +} + +int Debug::GetMaxUpscale() { + int value = 0; + debug_.debug_handler_->GetProperty(MAX_UPSCALE_PROP, &value); + + return value; +} + +bool Debug::IsVideoModeEnabled() { + int value = 0; + debug_.debug_handler_->GetProperty(VIDEO_MODE_PANEL_PROP, &value); + + return (value == 1); +} + +bool Debug::IsRotatorUbwcDisabled() { + int value = 0; + debug_.debug_handler_->GetProperty(DISABLE_ROTATOR_UBWC_PROP, &value); + + return (value == 1); +} + +bool Debug::IsRotatorSplitDisabled() { + int value = 0; + debug_.debug_handler_->GetProperty(DISABLE_ROTATOR_SPLIT_PROP, &value); + + return (value == 1); +} + +bool Debug::IsScalarDisabled() { + int value = 0; + debug_.debug_handler_->GetProperty(DISABLE_SCALER_PROP, &value); + + return (value == 1); +} + +bool Debug::IsUbwcTiledFrameBuffer() { + int ubwc_disabled = 0; + int ubwc_framebuffer = 0; + + debug_.debug_handler_->GetProperty(DISABLE_UBWC_PROP, &ubwc_disabled); + + if (!ubwc_disabled) { + debug_.debug_handler_->GetProperty(ENABLE_FB_UBWC_PROP, &ubwc_framebuffer); + } + + return (ubwc_framebuffer == 1); +} + +bool Debug::IsAVRDisabled() { + int value = 0; + debug_.debug_handler_->GetProperty(DISABLE_AVR_PROP, &value); + + return (value == 1); +} + +bool Debug::IsExtAnimDisabled() { + int value = 0; + debug_.debug_handler_->GetProperty(DISABLE_EXTERNAL_ANIMATION_PROP, &value); + + return (value == 1); +} + +bool Debug::IsPartialSplitDisabled() { + int value = 0; + debug_.debug_handler_->GetProperty(DISABLE_PARTIAL_SPLIT_PROP, &value); + + return (value == 1); +} + +DisplayError Debug::GetMixerResolution(uint32_t *width, uint32_t *height) { + char value[64] = {}; + + DisplayError error = debug_.debug_handler_->GetProperty(MIXER_RESOLUTION_PROP, value); + if (error !=kErrorNone) { + return error; + } + + std::string str(value); + + *width = UINT32(stoi(str)); + *height = UINT32(stoi(str.substr(str.find('x') + 1))); + + return kErrorNone; +} + +int Debug::GetExtMaxlayers() { + int max_external_layers = 0; + debug_.debug_handler_->GetProperty(MAX_EXTERNAL_LAYERS_PROP, &max_external_layers); + + return std::max(max_external_layers, 2); +} + +bool Debug::GetProperty(const char* property_name, char* value) { + if (debug_.debug_handler_->GetProperty(property_name, value) != kErrorNone) { + return false; + } + + return true; +} + +bool Debug::SetProperty(const char* property_name, const char* value) { + if (debug_.debug_handler_->SetProperty(property_name, value) != kErrorNone) { + return false; + } + + return true; +} + +} // namespace sdm + diff --git a/msm8909/sdm/libs/utils/formats.cpp b/msm8909/sdm/libs/utils/formats.cpp new file mode 100644 index 00000000..b7deb183 --- /dev/null +++ b/msm8909/sdm/libs/utils/formats.cpp @@ -0,0 +1,131 @@ +/* +* Copyright (c) 2016-2017, 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/formats.h> + +#define __CLASS__ "FormatsUtils" + +namespace sdm { + +bool IsUBWCFormat(LayerBufferFormat format) { + switch (format) { + case kFormatRGBA8888Ubwc: + case kFormatRGBX8888Ubwc: + case kFormatBGR565Ubwc: + case kFormatYCbCr420SPVenusUbwc: + case kFormatRGBA1010102Ubwc: + case kFormatRGBX1010102Ubwc: + case kFormatYCbCr420TP10Ubwc: + case kFormatYCbCr420P010Ubwc: + return true; + default: + return false; + } +} + +bool Is10BitFormat(LayerBufferFormat format) { + switch (format) { + case kFormatRGBA1010102: + case kFormatARGB2101010: + case kFormatRGBX1010102: + case kFormatXRGB2101010: + case kFormatBGRA1010102: + case kFormatABGR2101010: + case kFormatBGRX1010102: + case kFormatXBGR2101010: + case kFormatRGBA1010102Ubwc: + case kFormatRGBX1010102Ubwc: + case kFormatYCbCr420P010: + case kFormatYCbCr420TP10Ubwc: + case kFormatYCbCr420P010Ubwc: + return true; + default: + return false; + } +} + +const char *GetFormatString(const LayerBufferFormat &format) { + switch (format) { + case kFormatARGB8888: return "ARGB_8888"; + case kFormatRGBA8888: return "RGBA_8888"; + case kFormatBGRA8888: return "BGRA_8888"; + case kFormatXRGB8888: return "XRGB_8888"; + case kFormatRGBX8888: return "RGBX_8888"; + case kFormatBGRX8888: return "BGRX_8888"; + case kFormatRGBA5551: return "RGBA_5551"; + case kFormatRGBA4444: return "RGBA_4444"; + case kFormatRGB888: return "RGB_888"; + case kFormatBGR888: return "BGR_888"; + case kFormatRGB565: return "RGB_565"; + case kFormatBGR565: return "BGR_565"; + case kFormatRGBA8888Ubwc: return "RGBA_8888_UBWC"; + case kFormatRGBX8888Ubwc: return "RGBX_8888_UBWC"; + case kFormatBGR565Ubwc: return "BGR_565_UBWC"; + case kFormatYCbCr420Planar: return "Y_CB_CR_420"; + case kFormatYCrCb420Planar: return "Y_CR_CB_420"; + case kFormatYCrCb420PlanarStride16: return "Y_CR_CB_420_STRIDE16"; + case kFormatYCbCr420SemiPlanar: return "Y_CBCR_420"; + case kFormatYCrCb420SemiPlanar: return "Y_CRCB_420"; + case kFormatYCbCr420SemiPlanarVenus: return "Y_CBCR_420_VENUS"; + case kFormatYCrCb420SemiPlanarVenus: return "Y_CRCB_420_VENUS"; + case kFormatYCbCr422H1V2SemiPlanar: return "Y_CBCR_422_H1V2"; + case kFormatYCrCb422H1V2SemiPlanar: return "Y_CRCB_422_H1V2"; + case kFormatYCbCr422H2V1SemiPlanar: return "Y_CBCR_422_H2V1"; + case kFormatYCrCb422H2V1SemiPlanar: return "Y_CRCB_422_H2V2"; + case kFormatYCbCr420SPVenusUbwc: return "Y_CBCR_420_VENUS_UBWC"; + case kFormatYCbCr422H2V1Packed: return "YCBYCR_422_H2V1"; + case kFormatCbYCrY422H2V1Packed: return "CBYCRY_422_H2V1"; + case kFormatRGBA1010102: return "RGBA_1010102"; + case kFormatARGB2101010: return "ARGB_2101010"; + case kFormatRGBX1010102: return "RGBX_1010102"; + case kFormatXRGB2101010: return "XRGB_2101010"; + case kFormatBGRA1010102: return "BGRA_1010102"; + case kFormatABGR2101010: return "ABGR_2101010"; + case kFormatBGRX1010102: return "BGRX_1010102"; + case kFormatXBGR2101010: return "XBGR_2101010"; + case kFormatRGBA1010102Ubwc: return "RGBA_1010102_UBWC"; + case kFormatRGBX1010102Ubwc: return "RGBX_1010102_UBWC"; + case kFormatYCbCr420P010: return "Y_CBCR_420_P010"; + case kFormatYCbCr420TP10Ubwc: return "Y_CBCR_420_TP10_UBWC"; + case kFormatYCbCr420P010Ubwc: return "Y_CBCR_420_P010_UBWC"; + default: return "UNKNOWN"; + } +} + +BufferLayout GetBufferLayout(LayerBufferFormat format) { + switch (format) { + case kFormatYCbCr420TP10Ubwc: + return kTPTiled; + default: + return (IsUBWCFormat(format) ? kUBWC : kLinear); + } +} + +} // namespace sdm + diff --git a/msm8909/sdm/libs/utils/rect.cpp b/msm8909/sdm/libs/utils/rect.cpp new file mode 100644 index 00000000..84132574 --- /dev/null +++ b/msm8909/sdm/libs/utils/rect.cpp @@ -0,0 +1,270 @@ +/* +* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <math.h> +#include <utils/rect.h> +#include <utils/constants.h> +#include <algorithm> + +#define __CLASS__ "RectUtils" + +namespace sdm { + +bool IsValid(const LayerRect &rect) { + return ((rect.bottom > rect.top) && (rect.right > rect.left)); +} + +bool IsCongruent(const LayerRect &rect1, const LayerRect &rect2) { + return ((rect1.left == rect2.left) && + (rect1.top == rect2.top) && + (rect1.right == rect2.right) && + (rect1.bottom == rect2.bottom)); +} + +void LogI(DebugTag debug_tag, const char *prefix, const LayerRect &roi) { + DLOGI_IF(debug_tag, "%s: left = %.0f, top = %.0f, right = %.0f, bottom = %.0f", + prefix, roi.left, roi.top, roi.right, roi.bottom); +} + +void Log(DebugTag debug_tag, const char *prefix, const LayerRect &roi) { + DLOGV_IF(debug_tag, "%s: left = %.0f, top = %.0f, right = %.0f, bottom = %.0f", + prefix, roi.left, roi.top, roi.right, roi.bottom); +} + +void Normalize(const uint32_t &align_x, const uint32_t &align_y, LayerRect *rect) { + rect->left = ROUND_UP_ALIGN_UP(rect->left, align_x); + rect->right = ROUND_UP_ALIGN_DOWN(rect->right, align_x); + rect->top = ROUND_UP_ALIGN_UP(rect->top, align_y); + rect->bottom = ROUND_UP_ALIGN_DOWN(rect->bottom, align_y); +} + +LayerRect Intersection(const LayerRect &rect1, const LayerRect &rect2) { + LayerRect res; + + if (!IsValid(rect1) || !IsValid(rect2)) { + return LayerRect(); + } + + res.left = std::max(rect1.left, rect2.left); + res.top = std::max(rect1.top, rect2.top); + res.right = std::min(rect1.right, rect2.right); + res.bottom = std::min(rect1.bottom, rect2.bottom); + + if (!IsValid(res)) { + return LayerRect(); + } + + return res; +} + +LayerRect Reposition(const LayerRect &rect, const int &x_offset, const int &y_offset) { + LayerRect res; + + if (!IsValid(rect)) { + return LayerRect(); + } + + res.left = rect.left + FLOAT(x_offset); + res.top = rect.top + FLOAT(y_offset); + res.right = rect.right + FLOAT(x_offset); + res.bottom = rect.bottom + FLOAT(y_offset); + + return res; +} + +// Not a geometrical rect deduction. Deducts rect2 from rect1 only if it results a single rect +LayerRect Subtract(const LayerRect &rect1, const LayerRect &rect2) { + LayerRect res; + + res = rect1; + + if ((rect1.left == rect2.left) && (rect1.right == rect2.right)) { + if ((rect1.top == rect2.top) && (rect2.bottom <= rect1.bottom)) { + res.top = rect2.bottom; + } else if ((rect1.bottom == rect2.bottom) && (rect2.top >= rect1.top)) { + res.bottom = rect2.top; + } + } else if ((rect1.top == rect2.top) && (rect1.bottom == rect2.bottom)) { + if ((rect1.left == rect2.left) && (rect2.right <= rect1.right)) { + res.left = rect2.right; + } else if ((rect1.right == rect2.right) && (rect2.left >= rect1.left)) { + res.right = rect2.left; + } + } + + return res; +} + +LayerRect Union(const LayerRect &rect1, const LayerRect &rect2) { + LayerRect res; + + if (!IsValid(rect1) && !IsValid(rect2)) { + return LayerRect(); + } + + if (!IsValid(rect1)) { + return rect2; + } + + if (!IsValid(rect2)) { + return rect1; + } + + res.left = std::min(rect1.left, rect2.left); + res.top = std::min(rect1.top, rect2.top); + res.right = std::max(rect1.right, rect2.right); + res.bottom = std::max(rect1.bottom, rect2.bottom); + + return res; +} + +void SplitLeftRight(const LayerRect &in_rect, uint32_t split_count, uint32_t align_x, + bool flip_horizontal, LayerRect *out_rects) { + LayerRect rect_temp = in_rect; + + uint32_t split_width = UINT32(rect_temp.right - rect_temp.left) / split_count; + float aligned_width = FLOAT(CeilToMultipleOf(split_width, align_x)); + + for (uint32_t count = 0; count < split_count; count++) { + float aligned_right = rect_temp.left + aligned_width; + out_rects[count].left = rect_temp.left; + out_rects[count].right = std::min(rect_temp.right, aligned_right); + out_rects[count].top = rect_temp.top; + out_rects[count].bottom = rect_temp.bottom; + + rect_temp.left = out_rects[count].right; + + Log(kTagRotator, "SplitLeftRight", out_rects[count]); + } + + // If we have a horizontal flip, then we should be splitting the source from right to left + // to ensure that the right split will have an aligned width that matches the alignment on the + // destination. + if (flip_horizontal && split_count > 1) { + out_rects[0].right = out_rects[0].left + (out_rects[1].right - out_rects[1].left); + out_rects[1].left = out_rects[0].right; + Log(kTagRotator, "Adjusted Left", out_rects[0]); + Log(kTagRotator, "Adjusted Right", out_rects[1]); + } +} + +void SplitTopBottom(const LayerRect &in_rect, uint32_t split_count, uint32_t align_y, + bool flip_horizontal, LayerRect *out_rects) { + LayerRect rect_temp = in_rect; + + uint32_t split_height = UINT32(rect_temp.bottom - rect_temp.top) / split_count; + float aligned_height = FLOAT(CeilToMultipleOf(split_height, align_y)); + + for (uint32_t count = 0; count < split_count; count++) { + float aligned_bottom = rect_temp.top + aligned_height; + out_rects[count].top = rect_temp.top; + out_rects[count].bottom = std::min(rect_temp.bottom, aligned_bottom); + out_rects[count].left = rect_temp.left; + out_rects[count].right = rect_temp.right; + + rect_temp.top = out_rects[count].bottom; + + Log(kTagRotator, "SplitTopBottom", out_rects[count]); + } + + // If we have a horizontal flip, then we should be splitting the destination from bottom to top + // to ensure that the bottom split's y-offset is aligned correctly after we swap the destinations + // while accounting for the flip. + if (flip_horizontal && split_count > 1) { + out_rects[0].bottom = out_rects[0].top + (out_rects[1].bottom - out_rects[1].top); + out_rects[1].top = out_rects[0].bottom; + Log(kTagRotator, "Adjusted Top", out_rects[0]); + Log(kTagRotator, "Adjusted Bottom", out_rects[1]); + } +} + +void MapRect(const LayerRect &src_domain, const LayerRect &dst_domain, const LayerRect &in_rect, + LayerRect *out_rect) { + if (!IsValid(src_domain) || !IsValid(dst_domain) || !IsValid(in_rect)) { + return; + } + + int x_offset = INT(src_domain.left); + int y_offset = INT(src_domain.top); + + LayerRect modified_in_rect = Reposition(in_rect, -x_offset, -y_offset); + float src_domain_width = src_domain.right - src_domain.left; + float src_domain_height = src_domain.bottom - src_domain.top; + float dst_domain_width = dst_domain.right - dst_domain.left; + float dst_domain_height = dst_domain.bottom - dst_domain.top; + + float width_ratio = dst_domain_width / src_domain_width; + float height_ratio = dst_domain_height / src_domain_height; + + out_rect->left = dst_domain.left + (width_ratio * modified_in_rect.left); + out_rect->top = dst_domain.top + (height_ratio * modified_in_rect.top); + out_rect->right = dst_domain.left + (width_ratio * modified_in_rect.right); + out_rect->bottom = dst_domain.top + (height_ratio * modified_in_rect.bottom); +} + +void TransformHV(const LayerRect &src_domain, const LayerRect &in_rect, + const LayerTransform &transform, LayerRect *out_rect) { + if (!IsValid(src_domain) || !IsValid(in_rect)) { + return; + } + + float in_width = in_rect.right - in_rect.left; + float in_height = in_rect.bottom - in_rect.top; + float x_offset = in_rect.left - src_domain.left; + float y_offset = in_rect.top - src_domain.top; + *out_rect = in_rect; + + if (transform.flip_horizontal) { + out_rect->right = src_domain.right - x_offset; + out_rect->left = out_rect->right - in_width; + } + + if (transform.flip_vertical) { + out_rect->bottom = src_domain.bottom - y_offset; + out_rect->top = out_rect->bottom - in_height; + } +} + +RectOrientation GetOrientation(const LayerRect &in_rect) { + if (!IsValid(in_rect)) { + return kOrientationUnknown; + } + + float input_width = in_rect.right - in_rect.left; + float input_height = in_rect.bottom - in_rect.top; + + if (input_width < input_height) { + return kOrientationPortrait; + } + + return kOrientationLandscape; +} + +} // namespace sdm + diff --git a/msm8909/sdm/libs/utils/sys.cpp b/msm8909/sdm/libs/utils/sys.cpp new file mode 100644 index 00000000..f5e0f291 --- /dev/null +++ b/msm8909/sdm/libs/utils/sys.cpp @@ -0,0 +1,95 @@ +/* +* Copyright (c) 2015, The Linux Foundation. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of The Linux Foundation nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <utils/sys.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <unistd.h> +#include <string> + +#define __CLASS__ "Sys" + +namespace sdm { + +#ifndef SDM_VIRTUAL_DRIVER + +int PthreadCancel(pthread_t /* thread */) { + return 0; +} + +// Pointer to actual driver interfaces. +Sys::ioctl Sys::ioctl_ = ::ioctl; +Sys::access Sys::access_ = ::access; +Sys::open Sys::open_ = ::open; +Sys::close Sys::close_ = ::close; +Sys::poll Sys::poll_ = ::poll; +Sys::pread Sys::pread_ = ::pread; +Sys::pwrite Sys::pwrite_ = ::pwrite; +Sys::pthread_cancel Sys::pthread_cancel_ = PthreadCancel; +Sys::dup Sys::dup_ = ::dup; +Sys::read Sys::read_ = ::read; +Sys::write Sys::write_ = ::write; +Sys::eventfd Sys::eventfd_ = ::eventfd; + +bool Sys::getline_(fstream &fs, std::string &line) { + return std::getline(fs, line) ? true : false; +} + +#endif // SDM_VIRTUAL_DRIVER + +DynLib::~DynLib() { + Close(); +} + +bool DynLib::Open(const char *lib_name) { + Close(); + lib_ = ::dlopen(lib_name, RTLD_NOW); + + return (lib_ != NULL); +} + +bool DynLib::Sym(const char *func_name, void **func_ptr) { + if (lib_) { + *func_ptr = ::dlsym(lib_, func_name); + } else { + *func_ptr = NULL; + } + + return (*func_ptr != NULL); +} + +void DynLib::Close() { + if (lib_) { + ::dlclose(lib_); + lib_ = NULL; + } +} + +} // namespace sdm + diff --git a/msm8909/sdm/libs/utils/utils.cpp b/msm8909/sdm/libs/utils/utils.cpp new file mode 100644 index 00000000..07211a1a --- /dev/null +++ b/msm8909/sdm/libs/utils/utils.cpp @@ -0,0 +1,71 @@ +/* +* Copyright (c) 2016 - 2017, 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 <unistd.h> +#include <math.h> +#include <utils/sys.h> +#include <utils/utils.h> + +#include <algorithm> + +#define __CLASS__ "Utils" + +namespace sdm { + +float gcd(float a, float b) { + if (a < b) { + std::swap(a, b); + } + + while (b != 0) { + float tmp = b; + b = fmodf(a, b); + a = tmp; + } + + return a; +} + +float lcm(float a, float b) { + return (a * b) / gcd(a, b); +} + +void CloseFd(int *fd) { + if (*fd >= 0) { + Sys::close_(*fd); + *fd = -1; + } +} + +DriverType GetDriverType() { + const char *fb_caps = "/sys/devices/virtual/graphics/fb0/mdp/caps"; + // 0 - File exists + return Sys::access_(fb_caps, F_OK) ? DriverType::DRM : DriverType::FB; +} +} // namespace sdm |