diff options
148 files changed, 3240 insertions, 1912 deletions
diff --git a/cmds/bugreportz/Android.mk b/cmds/bugreportz/Android.mk index 880bc75bc3..10dda56b75 100644 --- a/cmds/bugreportz/Android.mk +++ b/cmds/bugreportz/Android.mk @@ -25,6 +25,7 @@ include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) LOCAL_MODULE := bugreportz_test +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_MODULE_TAGS := tests LOCAL_CFLAGS := -Werror -Wall diff --git a/cmds/bugreportz/AndroidTest.xml b/cmds/bugreportz/AndroidTest.xml new file mode 100644 index 0000000000..38b6276b13 --- /dev/null +++ b/cmds/bugreportz/AndroidTest.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2017 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. +--> +<configuration description="Config for bugreportz_test"> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="cleanup" value="true" /> + <option name="push" value="bugreportz_test->/data/local/tmp/bugreportz_test" /> + </target_preparer> + <option name="test-suite-tag" value="apct" /> + <test class="com.android.tradefed.testtype.GTest" > + <option name="native-test-device-path" value="/data/local/tmp" /> + <option name="module-name" value="bugreportz_test" /> + </test> +</configuration> diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk index 18a4078d36..a1b6a51699 100644 --- a/cmds/dumpstate/Android.mk +++ b/cmds/dumpstate/Android.mk @@ -138,7 +138,7 @@ include $(BUILD_NATIVE_TEST) include $(CLEAR_VARS) LOCAL_MODULE := dumpstate_test_fixture - +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_MODULE_TAGS := tests LOCAL_CFLAGS := $(COMMON_LOCAL_CFLAGS) diff --git a/cmds/dumpstate/AndroidTest.xml b/cmds/dumpstate/AndroidTest.xml new file mode 100644 index 0000000000..f189489fde --- /dev/null +++ b/cmds/dumpstate/AndroidTest.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2017 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. +--> +<configuration description="Config for dumpstate_test_fixture"> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="cleanup" value="true" /> + <option name="push" value="dumpstate_test_fixture->/data/local/tmp/dumpstate_test_fixture" /> + </target_preparer> + <option name="test-suite-tag" value="apct" /> + <test class="com.android.tradefed.testtype.GTest" > + <option name="native-test-device-path" value="/data/local/tmp" /> + <option name="module-name" value="dumpstate_test_fixture" /> + </test> +</configuration> diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index f7d73b08cb..b8e56e3ffb 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -1782,6 +1782,16 @@ binder::Status InstalldNativeService::dumpProfiles(int32_t uid, const std::strin return ok(); } +// Copy the contents of a system profile over the data profile. +binder::Status InstalldNativeService::copySystemProfile(const std::string& systemProfile, + int32_t packageUid, const std::string& packageName, bool* _aidl_return) { + ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_PACKAGE_NAME(packageName); + std::lock_guard<std::recursive_mutex> lock(mLock); + *_aidl_return = copy_system_profile(systemProfile, packageUid, packageName); + return ok(); +} + // TODO: Consider returning error codes. binder::Status InstalldNativeService::mergeProfiles(int32_t uid, const std::string& packageName, bool* _aidl_return) { diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index 200fc77341..a94223c7ce 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -91,6 +91,8 @@ public: binder::Status mergeProfiles(int32_t uid, const std::string& packageName, bool* _aidl_return); binder::Status dumpProfiles(int32_t uid, const std::string& packageName, const std::string& codePaths, bool* _aidl_return); + binder::Status copySystemProfile(const std::string& systemProfile, + int32_t uid, const std::string& packageName, bool* _aidl_return); binder::Status clearAppProfiles(const std::string& packageName); binder::Status destroyAppProfiles(const std::string& packageName); diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index 6b99c1dbf9..efcae4f816 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -57,6 +57,8 @@ interface IInstalld { boolean mergeProfiles(int uid, @utf8InCpp String packageName); boolean dumpProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String codePaths); + boolean copySystemProfile(@utf8InCpp String systemProfile, int uid, + @utf8InCpp String packageName); void clearAppProfiles(@utf8InCpp String packageName); void destroyAppProfiles(@utf8InCpp String packageName); diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp index 3bbe3a14e5..5a78d78ec4 100644 --- a/cmds/installd/dexopt.cpp +++ b/cmds/installd/dexopt.cpp @@ -847,6 +847,66 @@ bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_pat return true; } +bool copy_system_profile(const std::string& system_profile, + uid_t packageUid, const std::string& data_profile_location) { + unique_fd in_fd(open(system_profile.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)); + unique_fd out_fd(open_reference_profile(packageUid, + data_profile_location, + /*read_write*/ true, + /*secondary*/ false)); + if (in_fd.get() < 0) { + PLOG(WARNING) << "Could not open profile " << system_profile; + return false; + } + if (out_fd.get() < 0) { + PLOG(WARNING) << "Could not open profile " << data_profile_location; + return false; + } + + pid_t pid = fork(); + if (pid == 0) { + /* child -- drop privileges before continuing */ + drop_capabilities(packageUid); + + if (flock(out_fd.get(), LOCK_EX | LOCK_NB) != 0) { + if (errno != EWOULDBLOCK) { + PLOG(WARNING) << "Error locking profile " << data_profile_location; + } + // This implies that the app owning this profile is running + // (and has acquired the lock). + // + // The app never acquires the lock for the reference profiles of primary apks. + // Only dex2oat from installd will do that. Since installd is single threaded + // we should not see this case. Nevertheless be prepared for it. + PLOG(WARNING) << "Failed to flock " << data_profile_location; + return false; + } + + bool truncated = ftruncate(out_fd.get(), 0) == 0; + if (!truncated) { + PLOG(WARNING) << "Could not truncate " << data_profile_location; + } + + // Copy over data. + static constexpr size_t kBufferSize = 4 * 1024; + char buffer[kBufferSize]; + while (true) { + ssize_t bytes = read(in_fd.get(), buffer, kBufferSize); + if (bytes == 0) { + break; + } + write(out_fd.get(), buffer, bytes); + } + if (flock(out_fd.get(), LOCK_UN) != 0) { + PLOG(WARNING) << "Error unlocking profile " << data_profile_location; + } + exit(0); + } + /* parent */ + int return_code = wait_child(pid); + return return_code == 0; +} + static std::string replace_file_extension(const std::string& oat_path, const std::string& new_ext) { // A standard dalvik-cache entry. Replace ".dex" with `new_ext`. if (EndsWith(oat_path, ".dex")) { diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h index cb8aaeba75..d171ee534e 100644 --- a/cmds/installd/dexopt.h +++ b/cmds/installd/dexopt.h @@ -50,6 +50,10 @@ bool analyze_primary_profiles(uid_t uid, const std::string& pkgname); bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths); +bool copy_system_profile(const std::string& system_profile, + uid_t packageUid, + const std::string& data_profile_location); + bool delete_odex(const char* apk_path, const char* instruction_set, const char* output_path); bool reconcile_secondary_dex_file(const std::string& dex_path, diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index 39d92a7561..d3d396f025 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -46,7 +46,6 @@ cc_binary { cflags: [ "-DVENDORSERVICEMANAGER=1", ], - shared_libs: ["libcutils"], - static_libs: ["libselinux"], + shared_libs: ["libcutils", "libselinux_vendor"], init_rc: ["vndservicemanager.rc"], } diff --git a/cmds/surfacereplayer/Android.bp b/cmds/surfacereplayer/Android.bp new file mode 100644 index 0000000000..d4c037ab7d --- /dev/null +++ b/cmds/surfacereplayer/Android.bp @@ -0,0 +1,4 @@ +subdirs = [ + "proto", + "replayer", +]
\ No newline at end of file diff --git a/cmds/surfacereplayer/proto/Android.bp b/cmds/surfacereplayer/proto/Android.bp new file mode 100644 index 0000000000..dda80bb565 --- /dev/null +++ b/cmds/surfacereplayer/proto/Android.bp @@ -0,0 +1,10 @@ +cc_library_static { + name: "libtrace_proto", + srcs: [ + "src/trace.proto", + ], + proto: { + type: "lite", + export_proto_headers: true, + }, +} diff --git a/cmds/surfacereplayer/proto/Android.mk b/cmds/surfacereplayer/proto/Android.mk deleted file mode 100644 index 3cf1148832..0000000000 --- a/cmds/surfacereplayer/proto/Android.mk +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (C) 2016 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := $(call all-proto-files-under, src) - -LOCAL_PROTOC_OPTIMIZE_TYPE := lite - -LOCAL_MODULE := libtrace_proto -LOCAL_MODULE_CLASS := STATIC_LIBRARIES - -LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) - -include $(BUILD_STATIC_LIBRARY) diff --git a/cmds/surfacereplayer/replayer/Android.bp b/cmds/surfacereplayer/replayer/Android.bp new file mode 100644 index 0000000000..5caceec89f --- /dev/null +++ b/cmds/surfacereplayer/replayer/Android.bp @@ -0,0 +1,66 @@ +cc_library_shared { + name: "libsurfacereplayer", + clang: true, + srcs: [ + "BufferQueueScheduler.cpp", + "Event.cpp", + "Replayer.cpp", + ], + cppflags: [ + "-Werror", + "-Wno-unused-parameter", + "-Wno-format", + "-Wno-c++98-compat-pedantic", + "-Wno-float-conversion", + "-Wno-disabled-macro-expansion", + "-Wno-float-equal", + "-Wno-sign-conversion", + "-Wno-padded", + "-std=c++14", + ], + static_libs: [ + "libtrace_proto", + ], + shared_libs: [ + "libEGL", + "libGLESv2", + "libbinder", + "liblog", + "libcutils", + "libgui", + "libui", + "libutils", + "libprotobuf-cpp-lite", + "libbase", + "libnativewindow", + ], + export_include_dirs: [ + ".", + ], +} + +cc_binary { + name: "surfacereplayer", + clang: true, + srcs: [ + "Main.cpp", + ], + shared_libs: [ + "libprotobuf-cpp-lite", + "libsurfacereplayer", + "libutils", + "libgui", + ], + static_libs: [ + "libtrace_proto", + ], + cppflags: [ + "-Werror", + "-Wno-unused-parameter", + "-Wno-c++98-compat-pedantic", + "-Wno-float-conversion", + "-Wno-disabled-macro-expansion", + "-Wno-float-equal", + "-std=c++14", + ], +} diff --git a/cmds/surfacereplayer/replayer/Android.mk b/cmds/surfacereplayer/replayer/Android.mk deleted file mode 100644 index 1dd926c06b..0000000000 --- a/cmds/surfacereplayer/replayer/Android.mk +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright 2016 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_TARGET_DIR := $(TARGET_OUT_DATA)/local/tmp - -LOCAL_PATH:= $(call my-dir) - -include $(call first-makefiles-under, /frameworks/native/cmds/surfacereplayer/proto) - -include $(CLEAR_VARS) - -LOCAL_CPPFLAGS := -Weverything -Werror -LOCAL_CPPFLAGS := -Wno-unused-parameter -LOCAL_CPPFLAGS := -Wno-format - -LOCAL_MODULE := libsurfacereplayer - -LOCAL_SRC_FILES := \ - BufferQueueScheduler.cpp \ - Event.cpp \ - Replayer.cpp \ - -LOCAL_SHARED_LIBRARIES := \ - libEGL \ - libGLESv2 \ - libbinder \ - liblog \ - libcutils \ - libgui \ - libui \ - libutils \ - libprotobuf-cpp-lite \ - libbase \ - libnativewindow \ - -LOCAL_STATIC_LIBRARIES := \ - libtrace_proto \ - -LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/.. - -include $(BUILD_SHARED_LIBRARY) - -include $(CLEAR_VARS) - -LOCAL_MODULE := surfacereplayer - -LOCAL_SRC_FILES := \ - Main.cpp \ - -LOCAL_SHARED_LIBRARIES := \ - libprotobuf-cpp-lite \ - libsurfacereplayer \ - libutils \ - libgui \ - -LOCAL_STATIC_LIBRARIES := \ - libtrace_proto \ - -LOCAL_CPPFLAGS := -Weverything -Werror -LOCAL_CPPFLAGS := -Wno-unused-parameter - -LOCAL_MODULE_PATH := $(LOCAL_TARGET_DIR) - -include $(BUILD_EXECUTABLE) diff --git a/cmds/surfacereplayer/replayer/Main.cpp b/cmds/surfacereplayer/replayer/Main.cpp index dd1dd7daf1..7090bdb503 100644 --- a/cmds/surfacereplayer/replayer/Main.cpp +++ b/cmds/surfacereplayer/replayer/Main.cpp @@ -24,7 +24,7 @@ * 5. Exit successfully or print error statement */ -#include <replayer/Replayer.h> +#include <Replayer.h> #include <csignal> #include <iostream> diff --git a/data/etc/android.hardware.radio.xml b/data/etc/android.hardware.radio.xml new file mode 100644 index 0000000000..f718c47cab --- /dev/null +++ b/data/etc/android.hardware.radio.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2017 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. +--> + +<!-- This is the standard set of features for a broadcast radio. --> +<permissions> + <feature name="android.hardware.radio" /> +</permissions> diff --git a/data/etc/android.hardware.telephony.euicc.xml b/data/etc/android.hardware.telephony.euicc.xml new file mode 100644 index 0000000000..167ed6a5bf --- /dev/null +++ b/data/etc/android.hardware.telephony.euicc.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2017 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. +--> + +<!-- Feature for devices with an eUICC. --> +<permissions> + <feature name="android.hardware.telephony.euicc" /> +</permissions> diff --git a/data/etc/android.hardware.wifi.passpoint.xml b/data/etc/android.hardware.wifi.passpoint.xml new file mode 100644 index 0000000000..4698bb3a09 --- /dev/null +++ b/data/etc/android.hardware.wifi.passpoint.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2017 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. +--> + +<!-- This is the standard feature indicating that the device includes WiFi Passpoint. --> +<permissions> + <feature name="android.hardware.wifi.passpoint" /> +</permissions> diff --git a/include/gui/Surface.h b/include/gui/Surface.h index 8b1d1069b3..c8c6e99c10 100644 --- a/include/gui/Surface.h +++ b/include/gui/Surface.h @@ -27,7 +27,7 @@ #include <utils/Mutex.h> #include <utils/RefBase.h> -struct ANativeWindow_Buffer; +#include <system/window.h> namespace android { diff --git a/include/media/hardware/HDCPAPI.h b/include/media/hardware/HDCPAPI.h index 30cd5fd9f2..7797bb2ab4 100644 --- a/include/media/hardware/HDCPAPI.h +++ b/include/media/hardware/HDCPAPI.h @@ -15,11 +15,10 @@ */ #ifndef HDCP_API_H_ - #define HDCP_API_H_ #include <utils/Errors.h> -#include <system/window.h> +#include <cutils/native_handle.h> namespace android { diff --git a/include/media/hardware/HardwareAPI.h b/include/media/hardware/HardwareAPI.h index cecf7152f4..6c1ba3de00 100644 --- a/include/media/hardware/HardwareAPI.h +++ b/include/media/hardware/HardwareAPI.h @@ -20,13 +20,15 @@ #include <media/hardware/OMXPluginBase.h> #include <media/hardware/MetadataBufferType.h> -#include <system/window.h> +#include <cutils/native_handle.h> #include <utils/RefBase.h> #include "VideoAPI.h" #include <OMX_Component.h> +struct ANativeWindowBuffer; + namespace android { // This structure is used to enable Android native buffer use for either diff --git a/include/ui/ANativeObjectBase.h b/include/ui/ANativeObjectBase.h index 640e34b509..e9d5d8d40b 100644 --- a/include/ui/ANativeObjectBase.h +++ b/include/ui/ANativeObjectBase.h @@ -19,26 +19,8 @@ #include <sys/types.h> -#include <system/window.h> +#include <nativebase/nativebase.h> -// --------------------------------------------------------------------------- - -/* FIXME: this is legacy for pixmaps */ -typedef struct egl_native_pixmap_t -{ - int32_t version; /* must be 32 */ - int32_t width; - int32_t height; - int32_t stride; - uint8_t* data; - uint8_t format; - uint8_t rfu[3]; - union { - uint32_t compressedFormat; - int32_t vstride; - }; - int32_t reserved; -} egl_native_pixmap_t; /*****************************************************************************/ @@ -52,7 +34,8 @@ namespace android { * This helper class turns a ANativeXXX object type into a C++ * reference-counted object; with proper type conversions. */ -template <typename NATIVE_TYPE, typename TYPE, typename REF> +template <typename NATIVE_TYPE, typename TYPE, typename REF, + typename NATIVE_BASE = android_native_base_t> class ANativeObjectBase : public NATIVE_TYPE, public REF { public: @@ -65,7 +48,7 @@ public: } protected: - typedef ANativeObjectBase<NATIVE_TYPE, TYPE, REF> BASE; + typedef ANativeObjectBase<NATIVE_TYPE, TYPE, REF, NATIVE_BASE> BASE; ANativeObjectBase() : NATIVE_TYPE(), REF() { NATIVE_TYPE::common.incRef = incRef; NATIVE_TYPE::common.decRef = decRef; @@ -76,17 +59,17 @@ protected: static inline TYPE const* getSelf(NATIVE_TYPE const* self) { return static_cast<TYPE const *>(self); } - static inline TYPE* getSelf(android_native_base_t* base) { + static inline TYPE* getSelf(NATIVE_BASE* base) { return getSelf(reinterpret_cast<NATIVE_TYPE*>(base)); } - static inline TYPE const * getSelf(android_native_base_t const* base) { + static inline TYPE const * getSelf(NATIVE_BASE const* base) { return getSelf(reinterpret_cast<NATIVE_TYPE const*>(base)); } - static void incRef(android_native_base_t* base) { + static void incRef(NATIVE_BASE* base) { ANativeObjectBase* self = getSelf(base); self->incStrong(self); } - static void decRef(android_native_base_t* base) { + static void decRef(NATIVE_BASE* base) { ANativeObjectBase* self = getSelf(base); self->decStrong(self); } diff --git a/include/ui/DebugUtils.h b/include/ui/DebugUtils.h index 84838088af..30f4a59fe0 100644 --- a/include/ui/DebugUtils.h +++ b/include/ui/DebugUtils.h @@ -17,6 +17,7 @@ #pragma once #include <system/graphics.h> +#include <ui/PixelFormat.h> #include <string> @@ -25,3 +26,4 @@ std::string decodeTransfer(android_dataspace dataspace); std::string decodeRange(android_dataspace dataspace); std::string dataspaceDetails(android_dataspace dataspace); std::string decodeColorMode(android_color_mode colormode); +std::string decodePixelFormat(android::PixelFormat format); diff --git a/include/ui/Gralloc2.h b/include/ui/Gralloc2.h index f826b92c31..e7b8ca94ed 100644 --- a/include/ui/Gralloc2.h +++ b/include/ui/Gralloc2.h @@ -21,7 +21,6 @@ #include <android/hardware/graphics/allocator/2.0/IAllocator.h> #include <android/hardware/graphics/mapper/2.0/IMapper.h> -#include <system/window.h> #include <utils/StrongPointer.h> namespace android { diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h index 4b82cffb2d..9a5aa6937a 100644 --- a/include/ui/GraphicBuffer.h +++ b/include/ui/GraphicBuffer.h @@ -28,9 +28,9 @@ #include <utils/Flattenable.h> #include <utils/RefBase.h> -#include <hardware/gralloc.h> +#include <nativebase/nativebase.h> -struct ANativeWindowBuffer; +#include <hardware/gralloc.h> namespace android { @@ -41,7 +41,7 @@ class GraphicBufferMapper; // =========================================================================== class GraphicBuffer - : public ANativeObjectBase< ANativeWindowBuffer, GraphicBuffer, RefBase >, + : public ANativeObjectBase<ANativeWindowBuffer, GraphicBuffer, RefBase>, public Flattenable<GraphicBuffer> { friend class Flattenable<GraphicBuffer>; diff --git a/include/ui/GraphicBufferAllocator.h b/include/ui/GraphicBufferAllocator.h index fe99de1dd9..14a865e16c 100644 --- a/include/ui/GraphicBufferAllocator.h +++ b/include/ui/GraphicBufferAllocator.h @@ -25,8 +25,6 @@ #include <cutils/native_handle.h> -#include <system/window.h> - #include <ui/PixelFormat.h> #include <utils/Errors.h> diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp index 0d25176f98..a20154f834 100644 --- a/libs/arect/Android.bp +++ b/libs/arect/Android.bp @@ -23,5 +23,6 @@ ndk_headers { cc_library_static { name: "libarect", host_supported: true, + vendor_available: true, export_include_dirs: ["include"], } diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp new file mode 100644 index 0000000000..f2686d5748 --- /dev/null +++ b/libs/graphicsenv/Android.bp @@ -0,0 +1,28 @@ +// Copyright (C) 2017 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_library_shared { + name: "libgraphicsenv", + + srcs: [ + "GraphicsEnv.cpp", + ], + + shared_libs: [ + "libnativeloader", + "liblog", + ], + + export_include_dirs: ["include"], +} diff --git a/libs/ui/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 8182c07001..39b5829faf 100644 --- a/libs/ui/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -16,7 +16,7 @@ //#define LOG_NDEBUG 1 #define LOG_TAG "GraphicsEnv" -#include <ui/GraphicsEnv.h> +#include <graphicsenv/GraphicsEnv.h> #include <mutex> diff --git a/include/ui/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index 781707694a..781707694a 100644 --- a/include/ui/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 5a127406db..c0ae3d7836 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -117,9 +117,14 @@ cc_library_shared { "android.hardware.configstore-utils", ], + header_libs: [ + "libnativebase_headers", + ], + export_shared_lib_headers: [ "libbinder", "libui", + "libnativewindow", "android.hidl.token@1.0-utils", "android.hardware.graphics.bufferqueue@1.0", ], diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 5e5de443f4..be754c25fc 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -36,6 +36,8 @@ #include <binder/PermissionCache.h> #include <private/android_filesystem_config.h> +#include <system/window.h> + namespace android { BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) : diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index cfb25e0503..bb703da3dd 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -38,6 +38,8 @@ #include <gui/ISurfaceComposer.h> #include <private/gui/ComposerService.h> +#include <system/window.h> + namespace android { static String8 getUniqueName() { @@ -110,54 +112,60 @@ BufferQueueCore::~BufferQueueCore() {} void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const { Mutex::Autolock lock(mMutex); - String8 fifo; + outResult->appendFormat("%s- BufferQueue ", prefix.string()); + outResult->appendFormat("mMaxAcquiredBufferCount=%d mMaxDequeuedBufferCount=%d\n", + mMaxAcquiredBufferCount, mMaxDequeuedBufferCount); + outResult->appendFormat("%s mDequeueBufferCannotBlock=%d mAsyncMode=%d\n", prefix.string(), + mDequeueBufferCannotBlock, mAsyncMode); + outResult->appendFormat("%s default-size=[%dx%d] default-format=%d ", prefix.string(), + mDefaultWidth, mDefaultHeight, mDefaultBufferFormat); + outResult->appendFormat("transform-hint=%02x frame-counter=%" PRIu64, mTransformHint, + mFrameCounter); + + outResult->appendFormat("\n%sFIFO(%zu):\n", prefix.string(), mQueue.size()); Fifo::const_iterator current(mQueue.begin()); while (current != mQueue.end()) { - fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], " - "xform=0x%02x, time=%#" PRIx64 ", scale=%s\n", - current->mSlot, current->mGraphicBuffer.get(), - current->mCrop.left, current->mCrop.top, current->mCrop.right, - current->mCrop.bottom, current->mTransform, current->mTimestamp, - BufferItem::scalingModeName(current->mScalingMode)); + double timestamp = current->mTimestamp / 1e9; + outResult->appendFormat("%s %02d:%p ", prefix.string(), current->mSlot, + current->mGraphicBuffer.get()); + outResult->appendFormat("crop=[%d,%d,%d,%d] ", current->mCrop.left, current->mCrop.top, + current->mCrop.right, current->mCrop.bottom); + outResult->appendFormat("xform=0x%02x time=%.4f scale=%s\n", current->mTransform, timestamp, + BufferItem::scalingModeName(current->mScalingMode)); ++current; } - outResult->appendFormat("%s-BufferQueue mMaxAcquiredBufferCount=%d, " - "mMaxDequeuedBufferCount=%d, mDequeueBufferCannotBlock=%d " - "mAsyncMode=%d, default-size=[%dx%d], default-format=%d, " - "transform-hint=%02x, FIFO(%zu)={%s}\n", prefix.string(), - mMaxAcquiredBufferCount, mMaxDequeuedBufferCount, - mDequeueBufferCannotBlock, mAsyncMode, mDefaultWidth, - mDefaultHeight, mDefaultBufferFormat, mTransformHint, mQueue.size(), - fifo.string()); - + outResult->appendFormat("%sSlots:\n", prefix.string()); for (int s : mActiveBuffers) { const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer); // A dequeued buffer might be null if it's still being allocated if (buffer.get()) { - outResult->appendFormat("%s%s[%02d:%p] state=%-8s, %p " - "[%4ux%4u:%4u,%3X]\n", prefix.string(), - (mSlots[s].mBufferState.isAcquired()) ? ">" : " ", s, - buffer.get(), mSlots[s].mBufferState.string(), - buffer->handle, buffer->width, buffer->height, - buffer->stride, buffer->format); + outResult->appendFormat("%s %s[%02d:%p] ", prefix.string(), + (mSlots[s].mBufferState.isAcquired()) ? ">" : " ", s, + buffer.get()); + outResult->appendFormat("state=%-8s %p frame=%" PRIu64, mSlots[s].mBufferState.string(), + buffer->handle, mSlots[s].mFrameNumber); + outResult->appendFormat(" [%4ux%4u:%4u,%3X]\n", buffer->width, buffer->height, + buffer->stride, buffer->format); } else { - outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.string(), s, - buffer.get(), mSlots[s].mBufferState.string()); + outResult->appendFormat("%s [%02d:%p] ", prefix.string(), s, buffer.get()); + outResult->appendFormat("state=%-8s frame=%" PRIu64 "\n", + mSlots[s].mBufferState.string(), mSlots[s].mFrameNumber); } } for (int s : mFreeBuffers) { const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer); - outResult->appendFormat("%s [%02d:%p] state=%-8s, %p [%4ux%4u:%4u,%3X]\n", - prefix.string(), s, buffer.get(), mSlots[s].mBufferState.string(), - buffer->handle, buffer->width, buffer->height, buffer->stride, - buffer->format); + outResult->appendFormat("%s [%02d:%p] ", prefix.string(), s, buffer.get()); + outResult->appendFormat("state=%-8s %p frame=%" PRIu64, mSlots[s].mBufferState.string(), + buffer->handle, mSlots[s].mFrameNumber); + outResult->appendFormat(" [%4ux%4u:%4u,%3X]\n", buffer->width, buffer->height, + buffer->stride, buffer->format); } for (int s : mFreeSlots) { const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer); - outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.string(), s, - buffer.get(), mSlots[s].mBufferState.string()); + outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.string(), s, buffer.get(), + mSlots[s].mBufferState.string()); } } diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 6a5593cc1c..b76e2c68b5 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -39,6 +39,8 @@ #include <utils/Log.h> #include <utils/Trace.h> +#include <system/window.h> + namespace android { static constexpr uint32_t BQ_LAYER_COUNT = 1; diff --git a/libs/gui/StreamSplitter.cpp b/libs/gui/StreamSplitter.cpp index bafe947efe..52c906775e 100644 --- a/libs/gui/StreamSplitter.cpp +++ b/libs/gui/StreamSplitter.cpp @@ -31,6 +31,8 @@ #include <utils/Trace.h> +#include <system/window.h> + namespace android { status_t StreamSplitter::createSplitter( diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 60c1277db0..4220aafa07 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -32,6 +32,8 @@ #include <utils/String8.h> #include <utils/threads.h> +#include <system/window.h> + #include <gtest/gtest.h> #include <thread> diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp index aa071f68b0..bcfc91c3f5 100644 --- a/libs/gui/tests/IGraphicBufferProducer_test.cpp +++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp @@ -29,6 +29,8 @@ #include <gui/BufferQueue.h> #include <gui/IProducerListener.h> +#include <system/window.h> + #include <vector> #define ASSERT_OK(x) ASSERT_EQ(OK, (x)) diff --git a/libs/gui/tests/StreamSplitter_test.cpp b/libs/gui/tests/StreamSplitter_test.cpp index 80e30da84a..e2f494898e 100644 --- a/libs/gui/tests/StreamSplitter_test.cpp +++ b/libs/gui/tests/StreamSplitter_test.cpp @@ -24,6 +24,8 @@ #include <gui/StreamSplitter.h> #include <private/gui/ComposerService.h> +#include <system/window.h> + #include <gtest/gtest.h> namespace android { diff --git a/libs/hwc2on1adapter/Android.bp b/libs/hwc2on1adapter/Android.bp index 5d7f660a54..ec9cbf8429 100644 --- a/libs/hwc2on1adapter/Android.bp +++ b/libs/hwc2on1adapter/Android.bp @@ -14,7 +14,7 @@ cc_library_shared { name: "libhwc2on1adapter", - vendor_available: true, + vendor: true, clang: true, cppflags: [ diff --git a/libs/hwc2on1adapter/CleanSpec.mk b/libs/hwc2on1adapter/CleanSpec.mk new file mode 100644 index 0000000000..7fc22161fa --- /dev/null +++ b/libs/hwc2on1adapter/CleanSpec.mk @@ -0,0 +1,52 @@ +# Copyright (C) 2017 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. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) + +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libhwc2on1adapter_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libhwc2on1adapter.so) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/libhwc2on1adapter.so) diff --git a/libs/math/Android.bp b/libs/math/Android.bp index 3ef8b4aa05..693bace1f4 100644 --- a/libs/math/Android.bp +++ b/libs/math/Android.bp @@ -15,6 +15,7 @@ cc_library_static { name: "libmath", host_supported: true, + vendor_available: true, export_include_dirs: ["include"], } diff --git a/libs/math/include/math/half.h b/libs/math/include/math/half.h index 615b840b01..76829734a4 100644 --- a/libs/math/include/math/half.h +++ b/libs/math/include/math/half.h @@ -56,8 +56,8 @@ namespace android { */ class half { struct fp16 { - uint16_t bits = 0; - fp16() noexcept = default; + uint16_t bits; + explicit constexpr fp16() noexcept : bits(0) { } explicit constexpr fp16(uint16_t b) noexcept : bits(b) { } void setS(unsigned int s) noexcept { bits = uint16_t((bits & 0x7FFF) | (s<<15)); } void setE(unsigned int s) noexcept { bits = uint16_t((bits & 0xE3FF) | (s<<10)); } @@ -68,11 +68,11 @@ class half { }; struct fp32 { union { - uint32_t bits = 0; + uint32_t bits; float fp; }; - fp32() noexcept = default; - explicit constexpr fp32(float f) : fp(f) { } + explicit constexpr fp32() noexcept : bits(0) { } + explicit constexpr fp32(float f) noexcept : fp(f) { } void setS(unsigned int s) noexcept { bits = uint32_t((bits & 0x7FFFFFFF) | (s<<31)); } void setE(unsigned int s) noexcept { bits = uint32_t((bits & 0x807FFFFF) | (s<<23)); } void setM(unsigned int s) noexcept { bits = uint32_t((bits & 0xFF800000) | (s<< 0)); } diff --git a/libs/nativebase/Android.bp b/libs/nativebase/Android.bp new file mode 100644 index 0000000000..7375a2bc2f --- /dev/null +++ b/libs/nativebase/Android.bp @@ -0,0 +1,29 @@ +// Copyright (C) 2017 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_library_headers { + name: "libnativebase_headers", + vendor_available: true, + host_supported: true, + export_include_dirs: ["include"], + + target: { + linux_bionic: { + enabled: true, + }, + windows: { + enabled: true, + }, + } +} diff --git a/libs/nativebase/MODULE_LICENSE_APACHE2 b/libs/nativebase/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/libs/nativebase/MODULE_LICENSE_APACHE2 diff --git a/libs/nativebase/NOTICE b/libs/nativebase/NOTICE new file mode 100644 index 0000000000..c5b1efa7aa --- /dev/null +++ b/libs/nativebase/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/libs/nativebase/include/nativebase/nativebase.h b/libs/nativebase/include/nativebase/nativebase.h new file mode 100644 index 0000000000..90afb3f637 --- /dev/null +++ b/libs/nativebase/include/nativebase/nativebase.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2017 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. + */ + +#pragma once + +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <sys/cdefs.h> +#include <system/graphics-base.h> +#include <cutils/native_handle.h> + +__BEGIN_DECLS + +#ifdef __cplusplus +#define ANDROID_NATIVE_UNSIGNED_CAST(x) static_cast<unsigned int>(x) +#else +#define ANDROID_NATIVE_UNSIGNED_CAST(x) ((unsigned int)(x)) +#endif + +#define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d) \ + ((ANDROID_NATIVE_UNSIGNED_CAST(a) << 24) | \ + (ANDROID_NATIVE_UNSIGNED_CAST(b) << 16) | \ + (ANDROID_NATIVE_UNSIGNED_CAST(c) << 8) | \ + (ANDROID_NATIVE_UNSIGNED_CAST(d))) + +#define ANDROID_NATIVE_BUFFER_MAGIC ANDROID_NATIVE_MAKE_CONSTANT('_','b','f','r') + + +typedef struct android_native_base_t +{ + /* a magic value defined by the actual EGL native type */ + int magic; + + /* the sizeof() of the actual EGL native type */ + int version; + + void* reserved[4]; + + /* reference-counting interface */ + void (*incRef)(struct android_native_base_t* base); + void (*decRef)(struct android_native_base_t* base); +} android_native_base_t; + +typedef struct android_native_rect_t +{ + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; +} android_native_rect_t; + +typedef struct ANativeWindowBuffer +{ +#ifdef __cplusplus + ANativeWindowBuffer() { + common.magic = ANDROID_NATIVE_BUFFER_MAGIC; + common.version = sizeof(ANativeWindowBuffer); + memset(common.reserved, 0, sizeof(common.reserved)); + } + + // Implement the methods that sp<ANativeWindowBuffer> expects so that it + // can be used to automatically refcount ANativeWindowBuffer's. + void incStrong(const void* /*id*/) const { + common.incRef(const_cast<android_native_base_t*>(&common)); + } + void decStrong(const void* /*id*/) const { + common.decRef(const_cast<android_native_base_t*>(&common)); + } +#endif + + struct android_native_base_t common; + + int width; + int height; + int stride; + int format; + int usage; + uintptr_t layerCount; + + void* reserved[1]; + + const native_handle_t* handle; + + void* reserved_proc[8]; +} ANativeWindowBuffer_t; + +typedef struct ANativeWindowBuffer ANativeWindowBuffer; + +// Old typedef for backwards compatibility. +typedef ANativeWindowBuffer_t android_native_buffer_t; + +__END_DECLS diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index f64bab13f0..9224df604a 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -16,8 +16,6 @@ #define LOG_TAG "ANativeWindow" -#include <android/native_window.h> - #include <grallocusage/GrallocUsageConversion.h> // from nativewindow/includes/system/window.h // (not to be confused with the compatibility-only window.h from system/core/includes) diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp index d759acbbc1..e61fbd6e8b 100644 --- a/libs/nativewindow/Android.bp +++ b/libs/nativewindow/Android.bp @@ -57,10 +57,25 @@ cc_library { "libgrallocusage", ], + header_libs: [ + "libnativebase_headers", + ], + // headers we include in our public headers export_static_lib_headers: [ "libarect", ], + + export_header_lib_headers: [ + "libnativebase_headers", + ], +} + +llndk_library { + name: "libnativewindow", + symbol_file: "libnativewindow.map.txt", + unversioned: true, + export_include_dirs: ["include"], } subdirs = ["tests"] diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 45110c490b..6429c52f61 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -60,25 +60,6 @@ __BEGIN_DECLS // --------------------------------------------------------------------------- -typedef const native_handle_t* buffer_handle_t; - -// --------------------------------------------------------------------------- - -typedef struct android_native_rect_t -{ - int32_t left; - int32_t top; - int32_t right; - int32_t bottom; -} android_native_rect_t; - -// --------------------------------------------------------------------------- - -// Old typedef for backwards compatibility. -typedef ANativeWindowBuffer_t android_native_buffer_t; - -// --------------------------------------------------------------------------- - /* attributes queriable with query() */ enum { NATIVE_WINDOW_WIDTH = 0, @@ -549,7 +530,6 @@ struct ANativeWindow /* Backwards compatibility: use ANativeWindow (struct ANativeWindow in C). * android_native_window_t is deprecated. */ -typedef struct ANativeWindow ANativeWindow; typedef struct ANativeWindow android_native_window_t __deprecated; /* diff --git a/libs/nativewindow/include/vndk/window.h b/libs/nativewindow/include/vndk/window.h index 95618c472d..a7b340aea3 100644 --- a/libs/nativewindow/include/vndk/window.h +++ b/libs/nativewindow/include/vndk/window.h @@ -17,87 +17,13 @@ #ifndef ANDROID_VNDK_NATIVEWINDOW_ANATIVEWINDOW_H #define ANDROID_VNDK_NATIVEWINDOW_ANATIVEWINDOW_H -#include <stdint.h> -#include <stdbool.h> -#include <sys/cdefs.h> -#include <system/graphics-base.h> -#include <cutils/native_handle.h> +#include <nativebase/nativebase.h> // vndk is a superset of the NDK #include <android/native_window.h> -__BEGIN_DECLS - -/*****************************************************************************/ - -#ifdef __cplusplus -#define ANDROID_NATIVE_UNSIGNED_CAST(x) static_cast<unsigned int>(x) -#else -#define ANDROID_NATIVE_UNSIGNED_CAST(x) ((unsigned int)(x)) -#endif - -#define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d) \ - ((ANDROID_NATIVE_UNSIGNED_CAST(a) << 24) | \ - (ANDROID_NATIVE_UNSIGNED_CAST(b) << 16) | \ - (ANDROID_NATIVE_UNSIGNED_CAST(c) << 8) | \ - (ANDROID_NATIVE_UNSIGNED_CAST(d))) -#define ANDROID_NATIVE_BUFFER_MAGIC ANDROID_NATIVE_MAKE_CONSTANT('_','b','f','r') - - -/*****************************************************************************/ - -typedef struct android_native_base_t -{ - /* a magic value defined by the actual EGL native type */ - int magic; - - /* the sizeof() of the actual EGL native type */ - int version; - - void* reserved[4]; - - /* reference-counting interface */ - void (*incRef)(struct android_native_base_t* base); - void (*decRef)(struct android_native_base_t* base); -} android_native_base_t; - -typedef struct ANativeWindowBuffer -{ -#ifdef __cplusplus - ANativeWindowBuffer() { - common.magic = ANDROID_NATIVE_BUFFER_MAGIC; - common.version = sizeof(ANativeWindowBuffer); - memset(common.reserved, 0, sizeof(common.reserved)); - } - - // Implement the methods that sp<ANativeWindowBuffer> expects so that it - // can be used to automatically refcount ANativeWindowBuffer's. - void incStrong(const void* /*id*/) const { - common.incRef(const_cast<android_native_base_t*>(&common)); - } - void decStrong(const void* /*id*/) const { - common.decRef(const_cast<android_native_base_t*>(&common)); - } -#endif - - struct android_native_base_t common; - - int width; - int height; - int stride; - int format; - int usage; - uintptr_t layerCount; - - void* reserved[1]; - - const native_handle_t* handle; - - void* reserved_proc[8]; -} ANativeWindowBuffer_t; - -typedef struct ANativeWindowBuffer ANativeWindowBuffer; +__BEGIN_DECLS /* * Convert this ANativeWindowBuffer into a AHardwareBuffer diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index b1d1a725a1..58045be03e 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -4,22 +4,40 @@ LIBNATIVEWINDOW { AHardwareBuffer_allocate; AHardwareBuffer_describe; AHardwareBuffer_fromHardwareBuffer; + AHardwareBuffer_getNativeHandle; # vndk AHardwareBuffer_lock; AHardwareBuffer_recvHandleFromUnixSocket; AHardwareBuffer_release; AHardwareBuffer_sendHandleToUnixSocket; AHardwareBuffer_toHardwareBuffer; AHardwareBuffer_unlock; + ANativeWindowBuffer_getHardwareBuffer; # vndk + ANativeWindow_OemStorageGet; # vndk + ANativeWindow_OemStorageSet; # vndk ANativeWindow_acquire; + ANativeWindow_cancelBuffer; # vndk + ANativeWindow_dequeueBuffer; # vndk ANativeWindow_fromSurface; ANativeWindow_fromSurfaceTexture; ANativeWindow_getFormat; ANativeWindow_getHeight; ANativeWindow_getWidth; ANativeWindow_lock; + ANativeWindow_query; # vndk + ANativeWindow_queryf; # vndk + ANativeWindow_queueBuffer; # vndk ANativeWindow_release; + ANativeWindow_setAutoRefresh; # vndk + ANativeWindow_setBufferCount; # vndk + ANativeWindow_setBufferDataSpace; # vndk + ANativeWindow_setBuffersDimensions; # vndk + ANativeWindow_setBuffersFormat; # vndk ANativeWindow_setBuffersGeometry; + ANativeWindow_setBuffersTimestamp; # vndk ANativeWindow_setBuffersTransform; + ANativeWindow_setSharedBufferMode; # vndk + ANativeWindow_setSwapInterval; # vndk + ANativeWindow_setUsage; # vndk ANativeWindow_unlockAndPost; local: *; diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 5ccf1788c6..fb553e2c28 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -14,6 +14,7 @@ cc_library_shared { name: "libui", + vendor_available: true, clang: true, cppflags: [ @@ -53,7 +54,6 @@ cc_library_shared { "GraphicBuffer.cpp", "GraphicBufferAllocator.cpp", "GraphicBufferMapper.cpp", - "GraphicsEnv.cpp", "HdrCapabilities.cpp", "PixelFormat.cpp", "Rect.cpp", @@ -61,13 +61,16 @@ cc_library_shared { "UiConfig.cpp", ], + include_dirs: [ + "frameworks/native/include", + ], + shared_libs: [ "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.mapper@2.0", "android.hardware.configstore@1.0", - "android.hardware.configstore-utils", + "android.hardware.configstore-utils", "libbase", - "libnativeloader", "libcutils", "libhardware", "libhidlbase", @@ -83,10 +86,18 @@ cc_library_shared { "libmath", ], + header_libs: [ + "libnativebase_headers", + ], + export_static_lib_headers: [ "libarect", "libmath", ], + + export_header_lib_headers: [ + "libnativebase_headers", + ], } subdirs = ["tests"] diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp index 882bd7c7b2..94b68e7295 100644 --- a/libs/ui/DebugUtils.cpp +++ b/libs/ui/DebugUtils.cpp @@ -15,6 +15,7 @@ */ #include <ui/DebugUtils.h> +#include <ui/PixelFormat.h> #include <android-base/stringprintf.h> #include <string> @@ -145,6 +146,9 @@ std::string decodeRange(android_dataspace dataspace) { } std::string dataspaceDetails(android_dataspace dataspace) { + if (dataspace == 0) { + return "Default (0)"; + } return android::base::StringPrintf("%s %s %s", decodeStandard(dataspace).c_str(), decodeTransfer(dataspace).c_str(), decodeRange(dataspace).c_str()); @@ -185,3 +189,36 @@ std::string decodeColorMode(android_color_mode colorMode) { return android::base::StringPrintf("Unknown color mode %d", colorMode); } + +// Converts a PixelFormat to a human-readable string. Max 11 chars. +// (Could use a table of prefab String8 objects.) +std::string decodePixelFormat(android::PixelFormat format) { + switch (format) { + case android::PIXEL_FORMAT_UNKNOWN: + return std::string("Unknown/None"); + case android::PIXEL_FORMAT_CUSTOM: + return std::string("Custom"); + case android::PIXEL_FORMAT_TRANSLUCENT: + return std::string("Translucent"); + case android::PIXEL_FORMAT_TRANSPARENT: + return std::string("Transparent"); + case android::PIXEL_FORMAT_OPAQUE: + return std::string("Opaque"); + case android::PIXEL_FORMAT_RGBA_8888: + return std::string("RGBA_8888"); + case android::PIXEL_FORMAT_RGBX_8888: + return std::string("RGBx_8888"); + case android::PIXEL_FORMAT_RGBA_FP16: + return std::string("RGBA_FP16"); + case android::PIXEL_FORMAT_RGBA_1010102: + return std::string("RGBA_1010102"); + case android::PIXEL_FORMAT_RGB_888: + return std::string("RGB_888"); + case android::PIXEL_FORMAT_RGB_565: + return std::string("RGB_565"); + case android::PIXEL_FORMAT_BGRA_8888: + return std::string("BGRA_8888"); + default: + return android::base::StringPrintf("Unknown %#08x", format); + } +} diff --git a/libs/vr/libbroadcastring/include/libbroadcastring/broadcast_ring.h b/libs/vr/libbroadcastring/include/libbroadcastring/broadcast_ring.h index 69cb64826e..236e3aab42 100644 --- a/libs/vr/libbroadcastring/include/libbroadcastring/broadcast_ring.h +++ b/libs/vr/libbroadcastring/include/libbroadcastring/broadcast_ring.h @@ -348,6 +348,9 @@ class BroadcastRing { return Get(sequence, record); } + // Returns true if this instance has been created or imported. + bool is_valid() const { return !!data_.mmap; } + uint32_t record_count() const { return record_count_internal(); } uint32_t record_size() const { return record_size_internal(); } static constexpr uint32_t mmap_alignment() { return alignof(Mmap); } diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp index 452bad0bce..da0ea24dab 100644 --- a/libs/vr/libbufferhub/Android.bp +++ b/libs/vr/libbufferhub/Android.bp @@ -34,6 +34,11 @@ sharedLibraries = [ "liblog", "libui", "libutils", + "libnativewindow" +] + +HeaderLibraries = [ + "libnativebase_headers", ] cc_library { @@ -45,7 +50,11 @@ cc_library { export_include_dirs: localIncludeFiles, static_libs: staticLibraries, shared_libs: sharedLibraries, + header_libs: HeaderLibraries, name: "libbufferhub", + export_header_lib_headers: [ + "libnativebase_headers", + ], } cc_test { diff --git a/libs/vr/libbufferhub/include/private/dvr/native_buffer.h b/libs/vr/libbufferhub/include/private/dvr/native_buffer.h index b4ef2f50d7..a54579f032 100644 --- a/libs/vr/libbufferhub/include/private/dvr/native_buffer.h +++ b/libs/vr/libbufferhub/include/private/dvr/native_buffer.h @@ -4,9 +4,9 @@ #include <EGL/egl.h> #include <EGL/eglext.h> #include <log/log.h> -#include <system/window.h> #include <ui/ANativeObjectBase.h> #include <utils/RefBase.h> +#include <nativebase/nativebase.h> #include <private/dvr/buffer_hub_client.h> diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp index a587f95879..0b3b2f0fb9 100644 --- a/libs/vr/libbufferhubqueue/Android.bp +++ b/libs/vr/libbufferhubqueue/Android.bp @@ -21,10 +21,6 @@ includeFiles = [ "include", ] -headerLibraries = [ - "libdvr_headers", -] - staticLibraries = [ "libbufferhub", "libdvrcommon", @@ -42,6 +38,11 @@ sharedLibraries = [ "libgui", ] +headerLibraries = [ + "libdvr_headers", + "libnativebase_headers", +] + cc_library { name: "libbufferhubqueue", cflags: [ @@ -51,9 +52,9 @@ cc_library { srcs: sourceFiles, export_include_dirs: includeFiles, export_static_lib_headers: staticLibraries, - header_libs: headerLibraries, static_libs: staticLibraries, shared_libs: sharedLibraries, + header_libs: headerLibraries, } subdirs = ["tests"] diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp index 012a4e70e4..1978f41983 100644 --- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp +++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp @@ -23,34 +23,61 @@ using android::pdx::ErrorStatus; using android::pdx::LocalChannelHandle; +using android::pdx::LocalHandle; using android::pdx::Status; namespace android { namespace dvr { +namespace { + +// Polls an fd for the given events. +Status<int> PollEvents(int fd, short events) { + const int kTimeoutMs = 0; + pollfd pfd{fd, events, 0}; + const int count = RETRY_EINTR(poll(&pfd, 1, kTimeoutMs)); + if (count < 0) { + return ErrorStatus(errno); + } else if (count == 0) { + return ErrorStatus(ETIMEDOUT); + } else { + return {pfd.revents}; + } +} + +// Polls a buffer for the given events, taking care to do the proper +// translation. +Status<int> PollEvents(const std::shared_ptr<BufferHubBuffer>& buffer, + short events) { + auto poll_status = PollEvents(buffer->event_fd(), events); + if (!poll_status) + return poll_status; + + return buffer->GetEventMask(poll_status.get()); +} + +std::pair<int32_t, int32_t> Unstuff(uint64_t value) { + return {static_cast<int32_t>(value >> 32), + static_cast<int32_t>(value & ((1ull << 32) - 1))}; +} + +uint64_t Stuff(int32_t a, int32_t b) { + const uint32_t ua = static_cast<uint32_t>(a); + const uint32_t ub = static_cast<uint32_t>(b); + return (static_cast<uint64_t>(ua) << 32) | static_cast<uint64_t>(ub); +} + +} // anonymous namespace + BufferHubQueue::BufferHubQueue(LocalChannelHandle channel_handle) : Client{pdx::default_transport::ClientChannel::Create( - std::move(channel_handle))}, - meta_size_(0), - buffers_(BufferHubQueue::kMaxQueueCapacity), - epollhup_pending_(BufferHubQueue::kMaxQueueCapacity, false), - available_buffers_(BufferHubQueue::kMaxQueueCapacity), - fences_(BufferHubQueue::kMaxQueueCapacity), - capacity_(0), - id_(-1) { + std::move(channel_handle))} { Initialize(); } BufferHubQueue::BufferHubQueue(const std::string& endpoint_path) - : Client{pdx::default_transport::ClientChannelFactory::Create( - endpoint_path)}, - meta_size_(0), - buffers_(BufferHubQueue::kMaxQueueCapacity), - epollhup_pending_(BufferHubQueue::kMaxQueueCapacity, false), - available_buffers_(BufferHubQueue::kMaxQueueCapacity), - fences_(BufferHubQueue::kMaxQueueCapacity), - capacity_(0), - id_(-1) { + : Client{ + pdx::default_transport::ClientChannelFactory::Create(endpoint_path)} { Initialize(); } @@ -62,9 +89,9 @@ void BufferHubQueue::Initialize() { return; } - epoll_event event = {.events = EPOLLIN | EPOLLET, - .data = {.u64 = static_cast<uint64_t>( - BufferHubQueue::kEpollQueueEventIndex)}}; + epoll_event event = { + .events = EPOLLIN | EPOLLET, + .data = {.u64 = Stuff(-1, BufferHubQueue::kEpollQueueEventIndex)}}; ret = epoll_fd_.Control(EPOLL_CTL_ADD, event_fd(), &event); if (ret < 0) { ALOGE("BufferHubQueue::Initialize: Failed to add event fd to epoll set: %s", @@ -87,7 +114,6 @@ Status<void> BufferHubQueue::ImportQueue() { void BufferHubQueue::SetupQueue(size_t meta_size_bytes, int id) { meta_size_ = meta_size_bytes; id_ = id; - meta_buffer_tmp_.reset(meta_size_ > 0 ? new uint8_t[meta_size_] : nullptr); } std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateConsumerQueue() { @@ -152,19 +178,24 @@ bool BufferHubQueue::WaitForBuffers(int timeout) { // one for each buffer, in the queue and one extra event for the queue // client itself. for (int i = 0; i < num_events; i++) { - int64_t index = static_cast<int64_t>(events[i].data.u64); + int32_t event_fd; + int32_t index; + std::tie(event_fd, index) = Unstuff(events[i].data.u64); ALOGD_IF(TRACE, - "BufferHubQueue::WaitForBuffers: event %d: index=%" PRId64, i, - index); + "BufferHubQueue::WaitForBuffers: event %d: event_fd=%d index=%d", + i, event_fd, index); if (is_buffer_event_index(index)) { - HandleBufferEvent(static_cast<size_t>(index), events[i].events); + HandleBufferEvent(static_cast<size_t>(index), event_fd, + events[i].events); } else if (is_queue_event_index(index)) { HandleQueueEvent(events[i].events); } else { - ALOGW("BufferHubQueue::WaitForBuffers: Unknown event index: %" PRId64, - index); + ALOGW( + "BufferHubQueue::WaitForBuffers: Unknown event type event_fd=%d " + "index=%d", + event_fd, index); } } } while (count() == 0 && capacity() > 0 && !hung_up()); @@ -172,52 +203,72 @@ bool BufferHubQueue::WaitForBuffers(int timeout) { return count() != 0; } -void BufferHubQueue::HandleBufferEvent(size_t slot, int poll_events) { - auto buffer = buffers_[slot]; - if (!buffer) { +Status<void> BufferHubQueue::HandleBufferEvent(size_t slot, int event_fd, + int poll_events) { + if (!buffers_[slot]) { ALOGW("BufferHubQueue::HandleBufferEvent: Invalid buffer slot: %zu", slot); - return; + return ErrorStatus(ENOENT); } - auto status = buffer->GetEventMask(poll_events); + auto status = buffers_[slot]->GetEventMask(poll_events); if (!status) { ALOGW("BufferHubQueue::HandleBufferEvent: Failed to get event mask: %s", status.GetErrorMessage().c_str()); - return; + return status.error_status(); } const int events = status.get(); if (events & EPOLLIN) { - const int ret = OnBufferReady(buffer, &fences_[slot]); - if (ret == 0 || ret == -EALREADY || ret == -EBUSY) { + auto entry_status = OnBufferReady(buffers_[slot], slot); + if (entry_status.ok() || entry_status.error() == EALREADY) { // Only enqueue the buffer if it moves to or is already in the state - // requested in OnBufferReady(). If the buffer is busy this means that the - // buffer moved from released to posted when a new consumer was created - // before the ProducerQueue had a chance to regain it. This is a valid - // transition that we have to handle because edge triggered poll events - // latch the ready state even if it is later de-asserted -- don't enqueue - // or print an error log in this case. - if (ret != -EBUSY) - Enqueue(buffer, slot); + // requested in OnBufferReady(). + return Enqueue(entry_status.take()); + } else if (entry_status.error() == EBUSY) { + // If the buffer is busy this means that the buffer moved from released to + // posted when a new consumer was created before the ProducerQueue had a + // chance to regain it. This is a valid transition that we have to handle + // because edge triggered poll events latch the ready state even if it is + // later de-asserted -- don't enqueue or print an error log in this case. } else { ALOGE( "BufferHubQueue::HandleBufferEvent: Failed to set buffer ready, " "queue_id=%d buffer_id=%d: %s", - id(), buffer->id(), strerror(-ret)); + id(), buffers_[slot]->id(), entry_status.GetErrorMessage().c_str()); } } else if (events & EPOLLHUP) { - // This might be caused by producer replacing an existing buffer slot, or - // when BufferHubQueue is shutting down. For the first case, currently the - // epoll FD is cleaned up when the replacement consumer client is imported, - // we shouldn't detach again if |epollhub_pending_[slot]| is set. + // Check to see if the current buffer in the slot hung up. This is a bit of + // paranoia to deal with the epoll set getting out of sync with the buffer + // slots. + auto poll_status = PollEvents(buffers_[slot], POLLIN); + if (!poll_status && poll_status.error() != ETIMEDOUT) { + ALOGE("BufferHubQueue::HandleBufferEvent: Failed to poll buffer: %s", + poll_status.GetErrorMessage().c_str()); + return poll_status.error_status(); + } + + const bool hangup_pending = status.ok() && (poll_status.get() & EPOLLHUP); + ALOGW( - "BufferHubQueue::HandleBufferEvent: Received EPOLLHUP at slot: %zu, " - "buffer event fd: %d, EPOLLHUP pending: %d", - slot, buffer->event_fd(), int{epollhup_pending_[slot]}); - if (epollhup_pending_[slot]) { - epollhup_pending_[slot] = false; + "BufferHubQueue::HandleBufferEvent: Received EPOLLHUP event: slot=%zu " + "event_fd=%d buffer_id=%d hangup_pending=%d poll_status=%x", + slot, buffers_[slot]->event_fd(), buffers_[slot]->id(), hangup_pending, + poll_status.get()); + + if (hangup_pending) { + return DetachBuffer(slot); } else { - DetachBuffer(slot); + // Clean up the bookkeeping for the event fd. This is a bit of paranoia to + // deal with the epoll set getting out of sync with the buffer slots. + // Hitting this path should be very unusual. + const int ret = epoll_fd_.Control(EPOLL_CTL_DEL, event_fd, nullptr); + if (ret < 0) { + ALOGE( + "BufferHubQueue::HandleBufferEvent: Failed to remove fd=%d from " + "epoll set: %s", + event_fd, strerror(-ret)); + return ErrorStatus(-ret); + } } } else { ALOGW( @@ -225,14 +276,16 @@ void BufferHubQueue::HandleBufferEvent(size_t slot, int poll_events) { "events=%d", slot, events); } + + return {}; } -void BufferHubQueue::HandleQueueEvent(int poll_event) { +Status<void> BufferHubQueue::HandleQueueEvent(int poll_event) { auto status = GetEventMask(poll_event); if (!status) { ALOGW("BufferHubQueue::HandleQueueEvent: Failed to get event mask: %s", status.GetErrorMessage().c_str()); - return; + return status.error_status(); } const int events = status.get(); @@ -250,111 +303,97 @@ void BufferHubQueue::HandleQueueEvent(int poll_event) { } else { ALOGW("BufferHubQueue::HandleQueueEvent: Unknown epoll events=%x", events); } + + return {}; } -int BufferHubQueue::AddBuffer(const std::shared_ptr<BufferHubBuffer>& buf, - size_t slot) { +Status<void> BufferHubQueue::AddBuffer( + const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) { + ALOGD_IF(TRACE, "BufferHubQueue::AddBuffer: buffer_id=%d slot=%zu", + buffer->id(), slot); + if (is_full()) { - // TODO(jwcai) Move the check into Producer's AllocateBuffer and consumer's - // import buffer. ALOGE("BufferHubQueue::AddBuffer queue is at maximum capacity: %zu", capacity_); - return -E2BIG; + return ErrorStatus(E2BIG); } - if (buffers_[slot] != nullptr) { - // Replace the buffer if the slot is preoccupied. This could happen when the + if (buffers_[slot]) { + // Replace the buffer if the slot is occupied. This could happen when the // producer side replaced the slot with a newly allocated buffer. Detach the // buffer before setting up with the new one. - DetachBuffer(slot); - epollhup_pending_[slot] = true; + auto detach_status = DetachBuffer(slot); + if (!detach_status) + return detach_status.error_status(); } - epoll_event event = {.events = EPOLLIN | EPOLLET, .data = {.u64 = slot}}; - const int ret = epoll_fd_.Control(EPOLL_CTL_ADD, buf->event_fd(), &event); + epoll_event event = {.events = EPOLLIN | EPOLLET, + .data = {.u64 = Stuff(buffer->event_fd(), slot)}}; + const int ret = epoll_fd_.Control(EPOLL_CTL_ADD, buffer->event_fd(), &event); if (ret < 0) { ALOGE("BufferHubQueue::AddBuffer: Failed to add buffer to epoll set: %s", strerror(-ret)); - return ret; + return ErrorStatus(-ret); } - buffers_[slot] = buf; + buffers_[slot] = buffer; capacity_++; - return 0; + return {}; } -int BufferHubQueue::DetachBuffer(size_t slot) { - auto& buf = buffers_[slot]; - if (buf == nullptr) { - ALOGE("BufferHubQueue::DetachBuffer: Invalid slot: %zu", slot); - return -EINVAL; - } +Status<void> BufferHubQueue::DetachBuffer(size_t slot) { + ALOGD_IF(TRACE, "BufferHubQueue::DetachBuffer: slot=%zu", slot); - const int ret = epoll_fd_.Control(EPOLL_CTL_DEL, buf->event_fd(), nullptr); - if (ret < 0) { - ALOGE( - "BufferHubQueue::DetachBuffer: Failed to detach buffer from epoll set: " - "%s", - strerror(-ret)); - return ret; + if (buffers_[slot]) { + const int ret = + epoll_fd_.Control(EPOLL_CTL_DEL, buffers_[slot]->event_fd(), nullptr); + if (ret < 0) { + ALOGE( + "BufferHubQueue::DetachBuffer: Failed to detach buffer from epoll " + "set: " + "%s", + strerror(-ret)); + return ErrorStatus(-ret); + } + + buffers_[slot] = nullptr; + capacity_--; } - buffers_[slot] = nullptr; - capacity_--; - return 0; + return {}; } -void BufferHubQueue::Enqueue(const std::shared_ptr<BufferHubBuffer>& buf, - size_t slot) { - if (count() == capacity_) { +Status<void> BufferHubQueue::Enqueue(Entry entry) { + if (!is_full()) { + available_buffers_.Append(std::move(entry)); + return {}; + } else { ALOGE("BufferHubQueue::Enqueue: Buffer queue is full!"); - return; + return ErrorStatus(E2BIG); } - - // Set slot buffer back to vector. - // TODO(jwcai) Here have to dynamically allocate BufferInfo::metadata due to - // the limitation of the RingBuffer we are using. Would be better to refactor - // that. - BufferInfo buffer_info(slot, meta_size_); - buffer_info.buffer = buf; - // Swap metadata loaded during onBufferReady into vector. - std::swap(buffer_info.metadata, meta_buffer_tmp_); - - available_buffers_.Append(std::move(buffer_info)); } Status<std::shared_ptr<BufferHubBuffer>> BufferHubQueue::Dequeue( int timeout, size_t* slot, void* meta, LocalHandle* fence) { - ALOGD_IF(TRACE, "Dequeue: count=%zu, timeout=%d", count(), timeout); + ALOGD_IF(TRACE, "BufferHubQueue::Dequeue: count=%zu, timeout=%d", count(), + timeout); if (!WaitForBuffers(timeout)) return ErrorStatus(ETIMEDOUT); - std::shared_ptr<BufferHubBuffer> buf; - BufferInfo& buffer_info = available_buffers_.Front(); - - *fence = std::move(fences_[buffer_info.slot]); - - // Report current pos as the output slot. - std::swap(buffer_info.slot, *slot); - // Swap buffer from vector to be returned later. - std::swap(buffer_info.buffer, buf); - // Swap metadata from vector into tmp so that we can write out to |meta|. - std::swap(buffer_info.metadata, meta_buffer_tmp_); + auto& entry = available_buffers_.Front(); - available_buffers_.PopFront(); - - if (!buf) { - ALOGE("BufferHubQueue::Dequeue: Buffer to be dequeued is nullptr"); - return ErrorStatus(ENOBUFS); - } - - if (meta) { - std::copy(meta_buffer_tmp_.get(), meta_buffer_tmp_.get() + meta_size_, + std::shared_ptr<BufferHubBuffer> buffer = std::move(entry.buffer); + *slot = entry.slot; + *fence = std::move(entry.fence); + if (meta && entry.metadata) { + std::copy(entry.metadata.get(), entry.metadata.get() + meta_size_, reinterpret_cast<uint8_t*>(meta)); } - return {std::move(buf)}; + available_buffers_.PopFront(); + + return {std::move(buffer)}; } ProducerQueue::ProducerQueue(size_t meta_size) @@ -388,28 +427,29 @@ ProducerQueue::ProducerQueue(size_t meta_size, uint64_t usage_set_mask, SetupQueue(status.get().meta_size_bytes, status.get().id); } -int ProducerQueue::AllocateBuffer(uint32_t width, uint32_t height, - uint32_t layer_count, uint32_t format, - uint64_t usage, size_t* out_slot) { +Status<void> ProducerQueue::AllocateBuffer(uint32_t width, uint32_t height, + uint32_t layer_count, + uint32_t format, uint64_t usage, + size_t* out_slot) { if (out_slot == nullptr) { ALOGE("ProducerQueue::AllocateBuffer: Parameter out_slot cannot be null."); - return -EINVAL; + return ErrorStatus(EINVAL); } if (is_full()) { ALOGE("ProducerQueue::AllocateBuffer queue is at maximum capacity: %zu", capacity()); - return -E2BIG; + return ErrorStatus(E2BIG); } - const size_t kBufferCount = 1U; + const size_t kBufferCount = 1u; Status<std::vector<std::pair<LocalChannelHandle, size_t>>> status = InvokeRemoteMethod<BufferHubRPC::ProducerQueueAllocateBuffers>( width, height, layer_count, format, usage, kBufferCount); if (!status) { ALOGE("ProducerQueue::AllocateBuffer failed to create producer buffer: %s", status.GetErrorMessage().c_str()); - return -status.error(); + return status.error_status(); } auto buffer_handle_slots = status.take(); @@ -429,27 +469,26 @@ int ProducerQueue::AllocateBuffer(uint32_t width, uint32_t height, buffer_slot); } -int ProducerQueue::AddBuffer(const std::shared_ptr<BufferProducer>& buf, - size_t slot) { +Status<void> ProducerQueue::AddBuffer( + const std::shared_ptr<BufferProducer>& buffer, size_t slot) { ALOGD_IF(TRACE, "ProducerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu", - id(), buf->id(), slot); + id(), buffer->id(), slot); // For producer buffer, we need to enqueue the newly added buffer // immediately. Producer queue starts with all buffers in available state. - const int ret = BufferHubQueue::AddBuffer(buf, slot); - if (ret < 0) - return ret; + auto status = BufferHubQueue::AddBuffer(buffer, slot); + if (!status) + return status; - Enqueue(buf, slot); - return 0; + return Enqueue(buffer, slot); } -int ProducerQueue::DetachBuffer(size_t slot) { +Status<void> ProducerQueue::DetachBuffer(size_t slot) { auto status = InvokeRemoteMethod<BufferHubRPC::ProducerQueueDetachBuffer>(slot); if (!status) { ALOGE("ProducerQueue::DetachBuffer: Failed to detach producer buffer: %s", status.GetErrorMessage().c_str()); - return -status.error(); + return status.error_status(); } return BufferHubQueue::DetachBuffer(slot); @@ -471,12 +510,22 @@ Status<std::shared_ptr<BufferProducer>> ProducerQueue::Dequeue( return {std::static_pointer_cast<BufferProducer>(buffer_status.take())}; } -int ProducerQueue::OnBufferReady(const std::shared_ptr<BufferHubBuffer>& buf, - LocalHandle* release_fence) { - ALOGD_IF(TRACE, "ProducerQueue::OnBufferReady: queue_id=%d buffer_id=%d", - id(), buf->id()); - auto buffer = std::static_pointer_cast<BufferProducer>(buf); - return buffer->Gain(release_fence); +Status<BufferHubQueue::Entry> ProducerQueue::OnBufferReady( + const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) { + ALOGD_IF(TRACE, + "ProducerQueue::OnBufferReady: queue_id=%d buffer_id=%d slot=%zu", + id(), buffer->id(), slot); + + // Avoid taking a transient reference, buffer is valid for the duration of + // this method call. + auto* producer_buffer = static_cast<BufferProducer*>(buffer.get()); + LocalHandle release_fence; + + const int ret = producer_buffer->Gain(&release_fence); + if (ret < 0) + return ErrorStatus(-ret); + else + return {{buffer, nullptr, std::move(release_fence), slot}}; } ConsumerQueue::ConsumerQueue(LocalChannelHandle handle, bool ignore_on_import) @@ -503,12 +552,12 @@ Status<size_t> ConsumerQueue::ImportBuffers() { if (!status) { ALOGE("ConsumerQueue::ImportBuffers: Failed to import consumer buffer: %s", status.GetErrorMessage().c_str()); - return ErrorStatus(status.error()); + return status.error_status(); } int ret; - int last_error = 0; - int imported_buffers = 0; + Status<void> last_error; + size_t imported_buffers_count = 0; auto buffer_handle_slots = status.take(); for (auto& buffer_handle_slot : buffer_handle_slots) { @@ -530,53 +579,52 @@ Status<size_t> ConsumerQueue::ImportBuffers() { "ConsumerQueue::ImportBuffers: Failed to set ignored state on " "imported buffer buffer_id=%d: %s", buffer_consumer->id(), strerror(-ret)); - last_error = ret; + last_error = ErrorStatus(-ret); } } - ret = AddBuffer(std::move(buffer_consumer), buffer_handle_slot.second); - if (ret < 0) { + auto add_status = + AddBuffer(std::move(buffer_consumer), buffer_handle_slot.second); + if (!add_status) { ALOGE("ConsumerQueue::ImportBuffers: Failed to add buffer: %s", - strerror(-ret)); - last_error = ret; - continue; + add_status.GetErrorMessage().c_str()); + last_error = add_status; } else { - imported_buffers++; + imported_buffers_count++; } } - if (imported_buffers > 0) - return {imported_buffers}; + if (imported_buffers_count > 0) + return {imported_buffers_count}; else - return ErrorStatus(-last_error); + return last_error.error_status(); } -int ConsumerQueue::AddBuffer(const std::shared_ptr<BufferConsumer>& buf, - size_t slot) { +Status<void> ConsumerQueue::AddBuffer( + const std::shared_ptr<BufferConsumer>& buffer, size_t slot) { ALOGD_IF(TRACE, "ConsumerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu", - id(), buf->id(), slot); - const int ret = BufferHubQueue::AddBuffer(buf, slot); - if (ret < 0) - return ret; + id(), buffer->id(), slot); + auto status = BufferHubQueue::AddBuffer(buffer, slot); + if (!status) + return status; // Check to see if the buffer is already signaled. This is necessary to catch // cases where buffers are already available; epoll edge triggered mode does // not fire until and edge transition when adding new buffers to the epoll - // set. - const int kTimeoutMs = 0; - pollfd pfd{buf->event_fd(), POLLIN, 0}; - const int count = RETRY_EINTR(poll(&pfd, 1, kTimeoutMs)); - if (count < 0) { - const int error = errno; + // set. Note that we only poll the fd events because HandleBufferEvent() takes + // care of checking the translated buffer events. + auto poll_status = PollEvents(buffer->event_fd(), POLLIN); + if (!poll_status && poll_status.error() != ETIMEDOUT) { ALOGE("ConsumerQueue::AddBuffer: Failed to poll consumer buffer: %s", - strerror(errno)); - return -error; + poll_status.GetErrorMessage().c_str()); + return poll_status.error_status(); } - if (count == 1) - HandleBufferEvent(slot, pfd.revents); - - return 0; + // Update accounting if the buffer is available. + if (poll_status) + return HandleBufferEvent(slot, buffer->event_fd(), poll_status.get()); + else + return {}; } Status<std::shared_ptr<BufferConsumer>> ConsumerQueue::Dequeue( @@ -606,15 +654,30 @@ Status<std::shared_ptr<BufferConsumer>> ConsumerQueue::Dequeue( return {std::static_pointer_cast<BufferConsumer>(buffer_status.take())}; } -int ConsumerQueue::OnBufferReady(const std::shared_ptr<BufferHubBuffer>& buf, - LocalHandle* acquire_fence) { - ALOGD_IF(TRACE, "ConsumerQueue::OnBufferReady: queue_id=%d buffer_id=%d", - id(), buf->id()); - auto buffer = std::static_pointer_cast<BufferConsumer>(buf); - return buffer->Acquire(acquire_fence, meta_buffer_tmp_.get(), meta_size_); +Status<BufferHubQueue::Entry> ConsumerQueue::OnBufferReady( + const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) { + ALOGD_IF(TRACE, + "ConsumerQueue::OnBufferReady: queue_id=%d buffer_id=%d slot=%zu", + id(), buffer->id(), slot); + + // Avoid taking a transient reference, buffer is valid for the duration of + // this method call. + auto* consumer_buffer = static_cast<BufferConsumer*>(buffer.get()); + std::unique_ptr<uint8_t[]> metadata(meta_size_ ? new uint8_t[meta_size_] + : nullptr); + LocalHandle acquire_fence; + + const int ret = + consumer_buffer->Acquire(&acquire_fence, metadata.get(), meta_size_); + if (ret < 0) + return ErrorStatus(-ret); + else + return {{buffer, std::move(metadata), std::move(acquire_fence), slot}}; } Status<void> ConsumerQueue::OnBufferAllocated() { + ALOGD_IF(TRACE, "ConsumerQueue::OnBufferAllocated: queue_id=%d", id()); + auto status = ImportBuffers(); if (!status) { ALOGE("ConsumerQueue::OnBufferAllocated: Failed to import buffers: %s", diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp index 8582bbf3a6..932aa372c9 100644 --- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp +++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp @@ -3,6 +3,7 @@ #include <dvr/dvr_api.h> #include <inttypes.h> #include <log/log.h> +#include <system/window.h> namespace android { namespace dvr { @@ -158,6 +159,8 @@ status_t BufferHubQueueProducer::dequeueBuffer( for (size_t retry = 0; retry < BufferHubQueue::kMaxQueueCapacity; retry++) { LocalHandle fence; auto buffer_status = queue_->Dequeue(dequeue_timeout_ms_, &slot, &fence); + if (!buffer_status) + return NO_MEMORY; buffer_producer = buffer_status.take(); if (!buffer_producer) @@ -607,10 +610,12 @@ status_t BufferHubQueueProducer::AllocateBuffer(uint32_t width, uint32_t height, PixelFormat format, uint64_t usage) { size_t slot; - - if (queue_->AllocateBuffer(width, height, layer_count, format, usage, &slot) < - 0) { - ALOGE("Failed to allocate new buffer in BufferHub."); + auto status = + queue_->AllocateBuffer(width, height, layer_count, format, usage, &slot); + if (!status) { + ALOGE( + "BufferHubQueueProducer::AllocateBuffer: Failed to allocate buffer: %s", + status.GetErrorMessage().c_str()); return NO_MEMORY; } @@ -625,11 +630,11 @@ status_t BufferHubQueueProducer::AllocateBuffer(uint32_t width, uint32_t height, } status_t BufferHubQueueProducer::RemoveBuffer(size_t slot) { - int ret = queue_->DetachBuffer(slot); - if (ret < 0) { - ALOGE("BufferHubQueueProducer::RemoveBuffer failed through RPC, ret=%s", - strerror(-ret)); - return ret; + auto status = queue_->DetachBuffer(slot); + if (!status) { + ALOGE("BufferHubQueueProducer::RemoveBuffer: Failed to detach buffer: %s", + status.GetErrorMessage().c_str()); + return INVALID_OPERATION; } // Reset in memory objects related the the buffer. diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h index ed67f79951..d8d326b654 100644 --- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h +++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h @@ -21,45 +21,39 @@ class ConsumerQueue; // automatically re-requeued when released by the remote side. class BufferHubQueue : public pdx::Client { public: - using LocalHandle = pdx::LocalHandle; - using LocalChannelHandle = pdx::LocalChannelHandle; - template <typename T> - using Status = pdx::Status<T>; - virtual ~BufferHubQueue() {} - void Initialize(); - // Create a new consumer queue that is attached to the producer. Returns + // Creates a new consumer queue that is attached to the producer. Returns // a new consumer queue client or nullptr on failure. std::unique_ptr<ConsumerQueue> CreateConsumerQueue(); - // Create a new consumer queue that is attached to the producer. This queue + // Creates a new consumer queue that is attached to the producer. This queue // sets each of its imported consumer buffers to the ignored state to avoid // participation in lifecycle events. std::unique_ptr<ConsumerQueue> CreateSilentConsumerQueue(); - // Return the default buffer width of this buffer queue. + // Returns the default buffer width of this buffer queue. size_t default_width() const { return default_width_; } - // Return the default buffer height of this buffer queue. + // Returns the default buffer height of this buffer queue. size_t default_height() const { return default_height_; } - // Return the default buffer format of this buffer queue. + // Returns the default buffer format of this buffer queue. int32_t default_format() const { return default_format_; } - // Create a new consumer in handle form for immediate transport over RPC. - Status<LocalChannelHandle> CreateConsumerQueueHandle(); + // Creates a new consumer in handle form for immediate transport over RPC. + pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle(); - // Return the number of buffers avaiable for dequeue. + // Returns the number of buffers avaiable for dequeue. size_t count() const { return available_buffers_.GetSize(); } - // Return the total number of buffers that the queue is tracking. + // Returns the total number of buffers that the queue is tracking. size_t capacity() const { return capacity_; } - // Return the size of metadata structure associated with this BufferBubQueue. + // Returns the size of metadata structure associated with this queue. size_t metadata_size() const { return meta_size_; } - // Return whether the buffer queue is alrady full. + // Returns whether the buffer queue is full. bool is_full() const { return available_buffers_.IsFull(); } explicit operator bool() const { return epoll_fd_.IsValid(); } @@ -68,7 +62,7 @@ class BufferHubQueue : public pdx::Client { return buffers_[slot]; } - Status<int> GetEventMask(int events) { + pdx::Status<int> GetEventMask(int events) { if (auto* client_channel = GetChannel()) { return client_channel->GetEventMask(events); } else { @@ -86,81 +80,95 @@ class BufferHubQueue : public pdx::Client { // occurred. bool HandleQueueEvents() { return WaitForBuffers(0); } - // Enqueue a buffer marks buffer to be available (|Gain|'ed for producer - // and |Acquire|'ed for consumer. This is only used for internal bookkeeping. - void Enqueue(const std::shared_ptr<BufferHubBuffer>& buf, size_t slot); - - // |BufferHubQueue| will keep track of at most this value of buffers. + // The queue tracks at most this many buffers. static constexpr size_t kMaxQueueCapacity = android::BufferQueueDefs::NUM_BUFFER_SLOTS; - // Special epoll data field indicating that the epoll event refers to the - // queue. - static constexpr int64_t kEpollQueueEventIndex = -1; - - // When pass |kNoTimeout| to |Dequeue|, it will block indefinitely without a - // timeout. static constexpr int kNoTimeOut = -1; int id() const { return id_; } bool hung_up() const { return hung_up_; } protected: - BufferHubQueue(LocalChannelHandle channel); + BufferHubQueue(pdx::LocalChannelHandle channel); BufferHubQueue(const std::string& endpoint_path); // Imports the queue parameters by querying BufferHub for the parameters for // this channel. - Status<void> ImportQueue(); + pdx::Status<void> ImportQueue(); // Sets up the queue with the given parameters. void SetupQueue(size_t meta_size_bytes_, int id); - // Called by ProducerQueue::AddBuffer and ConsumerQueue::AddBuffer only. to - // register a buffer for epoll and internal bookkeeping. - int AddBuffer(const std::shared_ptr<BufferHubBuffer>& buf, size_t slot); + // Register a buffer for management by the queue. Used by subclasses to add a + // buffer to internal bookkeeping. + pdx::Status<void> AddBuffer(const std::shared_ptr<BufferHubBuffer>& buffer, + size_t slot); - // Called by ProducerQueue::DetachBuffer and ConsumerQueue::DetachBuffer only. + // Called by ProducerQueue::DetachBuffer and ConsumerQueue::DetachBuffer only // to deregister a buffer for epoll and internal bookkeeping. - virtual int DetachBuffer(size_t slot); + virtual pdx::Status<void> DetachBuffer(size_t slot); // Dequeue a buffer from the free queue, blocking until one is available. The // timeout argument specifies the number of milliseconds that |Dequeue()| will - // block. Specifying a timeout of -1 causes |Dequeue()| to block indefinitely, - // while specifying a timeout equal to zero cause |Dequeue()| to return + // block. Specifying a timeout of -1 causes Dequeue() to block indefinitely, + // while specifying a timeout equal to zero cause Dequeue() to return // immediately, even if no buffers are available. - pdx::Status<std::shared_ptr<BufferHubBuffer>> Dequeue(int timeout, - size_t* slot, - void* meta, - LocalHandle* fence); + pdx::Status<std::shared_ptr<BufferHubBuffer>> Dequeue( + int timeout, size_t* slot, void* meta, pdx::LocalHandle* fence); - // Wait for buffers to be released and re-add them to the queue. + // Waits for buffers to become available and adds them to the available queue. bool WaitForBuffers(int timeout); - void HandleBufferEvent(size_t slot, int poll_events); - void HandleQueueEvent(int poll_events); - virtual int OnBufferReady(const std::shared_ptr<BufferHubBuffer>& buf, - LocalHandle* fence) = 0; + pdx::Status<void> HandleBufferEvent(size_t slot, int event_fd, + int poll_events); + pdx::Status<void> HandleQueueEvent(int poll_events); + + // Entry in the ring buffer of available buffers that stores related + // per-buffer data. + struct Entry { + Entry() : slot(0) {} + Entry(const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) + : buffer(buffer), slot(slot) {} + Entry(const std::shared_ptr<BufferHubBuffer>& buffer, + std::unique_ptr<uint8_t[]> metadata, pdx::LocalHandle fence, + size_t slot) + : buffer(buffer), + metadata(std::move(metadata)), + fence(std::move(fence)), + slot(slot) {} + Entry(Entry&&) = default; + Entry& operator=(Entry&&) = default; - // Called when a buffer is allocated remotely. - virtual Status<void> OnBufferAllocated() { return {}; } + std::shared_ptr<BufferHubBuffer> buffer; + std::unique_ptr<uint8_t[]> metadata; + pdx::LocalHandle fence; + size_t slot; + }; + + // Enqueues a buffer to the available list (Gained for producer or Acquireed + // for consumer). + pdx::Status<void> Enqueue(Entry entry); - // Data members to handle arbitrary metadata passed through BufferHub. It is - // fair to enforce that all buffers in the same queue share the same metadata - // type. |meta_size_| is used to store the size of metadata on queue creation; - // and |meta_buffer_tmp_| is allocated and resized to |meta_size_| on queue - // creation to be later used as temporary space so that we can avoid - // additional dynamic memory allocation in each |Enqueue| and |Dequeue| call. - size_t meta_size_; + virtual pdx::Status<Entry> OnBufferReady( + const std::shared_ptr<BufferHubBuffer>& buf, size_t slot) = 0; + + // Called when a buffer is allocated remotely. + virtual pdx::Status<void> OnBufferAllocated() { return {}; } - // Here we intentionally choose |unique_ptr<uint8_t[]>| over vector<uint8_t> - // to disallow dynamic resizing for stability reasons. - std::unique_ptr<uint8_t[]> meta_buffer_tmp_; + // Size of the metadata that buffers in this queue cary. + size_t meta_size_{0}; private: + void Initialize(); + + // Special epoll data field indicating that the epoll event refers to the + // queue. + static constexpr int64_t kEpollQueueEventIndex = -1; + static constexpr size_t kMaxEvents = 128; - // The |u64| data field of an epoll event is interpreted as int64_t: + // The u64 data field of an epoll event is interpreted as int64_t: // When |index| >= 0 and |index| < kMaxQueueCapacity it refers to a specific // element of |buffers_| as a direct index; static bool is_buffer_event_index(int64_t index) { @@ -168,47 +176,11 @@ class BufferHubQueue : public pdx::Client { index < static_cast<int64_t>(BufferHubQueue::kMaxQueueCapacity); } - // When |index| == kEpollQueueEventIndex, it refers to the queue itself. + // When |index| == kEpollQueueEventIndex it refers to the queue itself. static bool is_queue_event_index(int64_t index) { return index == BufferHubQueue::kEpollQueueEventIndex; } - struct BufferInfo { - // A logical slot number that is assigned to a buffer at allocation time. - // The slot number remains unchanged during the entire life cycle of the - // buffer and should not be confused with the enqueue and dequeue order. - size_t slot; - - // A BufferHubBuffer client. - std::shared_ptr<BufferHubBuffer> buffer; - - // Metadata associated with the buffer. - std::unique_ptr<uint8_t[]> metadata; - - BufferInfo() : BufferInfo(-1, 0) {} - - BufferInfo(size_t slot, size_t metadata_size) - : slot(slot), - buffer(nullptr), - metadata(metadata_size ? new uint8_t[metadata_size] : nullptr) {} - - BufferInfo(BufferInfo&& other) - : slot(other.slot), - buffer(std::move(other.buffer)), - metadata(std::move(other.metadata)) {} - - BufferInfo& operator=(BufferInfo&& other) { - slot = other.slot; - buffer = std::move(other.buffer); - metadata = std::move(other.metadata); - return *this; - } - - private: - BufferInfo(const BufferInfo&) = delete; - void operator=(BufferInfo&) = delete; - }; - // Default buffer width that can be set to override the buffer width when a // width and height of 0 are specified in AllocateBuffer. size_t default_width_{1}; @@ -221,49 +193,18 @@ class BufferHubQueue : public pdx::Client { // isn't specified in AllocateBuffer. int32_t default_format_{PIXEL_FORMAT_RGBA_8888}; - // Buffer queue: - // |buffers_| tracks all |BufferHubBuffer|s created by this |BufferHubQueue|. - std::vector<std::shared_ptr<BufferHubBuffer>> buffers_; - - // |epollhup_pending_| tracks whether a slot of |buffers_| get detached before - // its corresponding EPOLLHUP event got handled. This could happen as the - // following sequence: - // 1. Producer queue's client side allocates a new buffer (at slot 1). - // 2. Producer queue's client side replaces an existing buffer (at slot 0). - // This is implemented by first detaching the buffer and then allocating a - // new buffer. - // 3. During the same epoll_wait, Consumer queue's client side gets EPOLLIN - // event on the queue which indicates a new buffer is available and the - // EPOLLHUP event for slot 0. Consumer handles these two events in order. - // 4. Consumer client calls BufferHubRPC::ConsumerQueueImportBuffers and both - // slot 0 and (the new) slot 1 buffer will be imported. During the import - // of the buffer at slot 1, consumer client detaches the old buffer so that - // the new buffer can be registered. At the same time - // |epollhup_pending_[slot]| is marked to indicate that buffer at this slot - // was detached prior to EPOLLHUP event. - // 5. Consumer client continues to handle the EPOLLHUP. Since - // |epollhup_pending_[slot]| is marked as true, it can safely ignore the - // event without detaching the newly allocated buffer at slot 1. - // - // In normal situations where the previously described sequence doesn't - // happen, an EPOLLHUP event should trigger a regular buffer detach. - std::vector<bool> epollhup_pending_; - - // |available_buffers_| uses |dvr::RingBuffer| to implementation queue - // sematics. When |Dequeue|, we pop the front element from - // |available_buffers_|, and that buffer's reference count will decrease by - // one, while another reference in |buffers_| keeps the last reference to - // prevent the buffer from being deleted. - RingBuffer<BufferInfo> available_buffers_; - - // Fences (acquire fence for consumer and release fence for consumer) , one - // for each buffer slot. - std::vector<LocalHandle> fences_; - - // Keep track with how many buffers have been added into the queue. - size_t capacity_; - - // Epoll fd used to wait for BufferHub events. + // Tracks the buffers belonging to this queue. Buffers are stored according to + // "slot" in this vector. Each slot is a logical id of the buffer within this + // queue regardless of its queue position or presence in the ring buffer. + std::vector<std::shared_ptr<BufferHubBuffer>> buffers_{kMaxQueueCapacity}; + + // Buffers and related data that are available for dequeue. + RingBuffer<Entry> available_buffers_{kMaxQueueCapacity}; + + // Keeps track with how many buffers have been added into the queue. + size_t capacity_{0}; + + // Epoll fd used to manage buffer events. EpollFileDescriptor epoll_fd_; // Flag indicating that the other side hung up. For ProducerQueues this @@ -273,7 +214,7 @@ class BufferHubQueue : public pdx::Client { bool hung_up_{false}; // Global id for the queue that is consistent across processes. - int id_; + int id_{-1}; BufferHubQueue(const BufferHubQueue&) = delete; void operator=(BufferHubQueue&) = delete; @@ -317,15 +258,15 @@ class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> { usage_deny_set_mask, usage_deny_clear_mask); } - // Import a |ProducerQueue| from a channel handle. - static std::unique_ptr<ProducerQueue> Import(LocalChannelHandle handle) { + // Import a ProducerQueue from a channel handle. + static std::unique_ptr<ProducerQueue> Import(pdx::LocalChannelHandle handle) { return BASE::Create(std::move(handle)); } // Get a buffer producer. Note that the method doesn't check whether the // buffer slot has a valid buffer that has been allocated already. When no - // buffer has been imported before it returns |nullptr|; otherwise it returns - // a shared pointer to a |BufferProducer|. + // buffer has been imported before it returns nullptr; otherwise it returns + // a shared pointer to a BufferProducer. std::shared_ptr<BufferProducer> GetBuffer(size_t slot) const { return std::static_pointer_cast<BufferProducer>( BufferHubQueue::GetBuffer(slot)); @@ -333,26 +274,30 @@ class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> { // Allocate producer buffer to populate the queue. Once allocated, a producer // buffer is automatically enqueue'd into the ProducerQueue and available to - // use (i.e. in |Gain|'ed mode). - // Returns Zero on success and negative error code when buffer allocation - // fails. - int AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count, - uint32_t format, uint64_t usage, size_t* out_slot); + // use (i.e. in GAINED state). + pdx::Status<void> AllocateBuffer(uint32_t width, uint32_t height, + uint32_t layer_count, uint32_t format, + uint64_t usage, size_t* out_slot); // Add a producer buffer to populate the queue. Once added, a producer buffer - // is available to use (i.e. in |Gain|'ed mode). - int AddBuffer(const std::shared_ptr<BufferProducer>& buf, size_t slot); + // is available to use (i.e. in GAINED state). + pdx::Status<void> AddBuffer(const std::shared_ptr<BufferProducer>& buffer, + size_t slot); // Detach producer buffer from the queue. - // Returns Zero on success and negative error code when buffer detach - // fails. - int DetachBuffer(size_t slot) override; + pdx::Status<void> DetachBuffer(size_t slot) override; // Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode, // and caller should call Post() once it's done writing to release the buffer // to the consumer side. pdx::Status<std::shared_ptr<BufferProducer>> Dequeue( - int timeout, size_t* slot, LocalHandle* release_fence); + int timeout, size_t* slot, pdx::LocalHandle* release_fence); + + // Enqueues a producer buffer in the queue. + pdx::Status<void> Enqueue(const std::shared_ptr<BufferProducer>& buffer, + size_t slot) { + return BufferHubQueue::Enqueue({buffer, slot}); + } private: friend BASE; @@ -361,13 +306,13 @@ class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> { // static template methods inherited from ClientBase, which take the same // arguments as the constructors. explicit ProducerQueue(size_t meta_size); - ProducerQueue(LocalChannelHandle handle); + explicit ProducerQueue(pdx::LocalChannelHandle handle); ProducerQueue(size_t meta_size, uint64_t usage_set_mask, uint64_t usage_clear_mask, uint64_t usage_deny_set_mask, uint64_t usage_deny_clear_mask); - int OnBufferReady(const std::shared_ptr<BufferHubBuffer>& buf, - LocalHandle* release_fence) override; + pdx::Status<Entry> OnBufferReady( + const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) override; }; // Explicit specializations of ProducerQueue::Create for void metadata type. @@ -399,7 +344,7 @@ class ConsumerQueue : public BufferHubQueue { // used to avoid participation in the buffer lifecycle by a consumer queue // that is only used to spawn other consumer queues, such as in an // intermediate service. - static std::unique_ptr<ConsumerQueue> Import(LocalChannelHandle handle, + static std::unique_ptr<ConsumerQueue> Import(pdx::LocalChannelHandle handle, bool ignore_on_import = false) { return std::unique_ptr<ConsumerQueue>( new ConsumerQueue(std::move(handle), ignore_on_import)); @@ -407,7 +352,7 @@ class ConsumerQueue : public BufferHubQueue { // Import newly created buffers from the service side. // Returns number of buffers successfully imported or an error. - Status<size_t> ImportBuffers(); + pdx::Status<size_t> ImportBuffers(); // Dequeue a consumer buffer to read. The returned buffer in |Acquired|'ed // mode, and caller should call Releasse() once it's done writing to release @@ -417,33 +362,34 @@ class ConsumerQueue : public BufferHubQueue { // when the buffer is orignally created. template <typename Meta> pdx::Status<std::shared_ptr<BufferConsumer>> Dequeue( - int timeout, size_t* slot, Meta* meta, LocalHandle* acquire_fence) { + int timeout, size_t* slot, Meta* meta, pdx::LocalHandle* acquire_fence) { return Dequeue(timeout, slot, meta, sizeof(*meta), acquire_fence); } pdx::Status<std::shared_ptr<BufferConsumer>> Dequeue( - int timeout, size_t* slot, LocalHandle* acquire_fence) { + int timeout, size_t* slot, pdx::LocalHandle* acquire_fence) { return Dequeue(timeout, slot, nullptr, 0, acquire_fence); } pdx::Status<std::shared_ptr<BufferConsumer>> Dequeue( int timeout, size_t* slot, void* meta, size_t meta_size, - LocalHandle* acquire_fence); + pdx::LocalHandle* acquire_fence); private: friend BufferHubQueue; - ConsumerQueue(LocalChannelHandle handle, bool ignore_on_import = false); + ConsumerQueue(pdx::LocalChannelHandle handle, bool ignore_on_import = false); // Add a consumer buffer to populate the queue. Once added, a consumer buffer // is NOT available to use until the producer side |Post| it. |WaitForBuffers| // will catch the |Post| and |Acquire| the buffer to make it available for // consumer. - int AddBuffer(const std::shared_ptr<BufferConsumer>& buf, size_t slot); + pdx::Status<void> AddBuffer(const std::shared_ptr<BufferConsumer>& buffer, + size_t slot); - int OnBufferReady(const std::shared_ptr<BufferHubBuffer>& buf, - LocalHandle* acquire_fence) override; + pdx::Status<Entry> OnBufferReady( + const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) override; - Status<void> OnBufferAllocated() override; + pdx::Status<void> OnBufferAllocated() override; // Flag indicating that imported (consumer) buffers should be ignored when // imported to avoid participating in the buffer ownership flow. diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp index fe0b12aa44..ff2e146908 100644 --- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp +++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp @@ -6,6 +6,9 @@ #include <vector> +// Enable/disable debug logging. +#define TRACE 0 + namespace android { namespace dvr { @@ -51,13 +54,16 @@ class BufferHubQueueTest : public ::testing::Test { CreateConsumerQueue(); } - void AllocateBuffer() { + void AllocateBuffer(size_t* slot_out = nullptr) { // Create producer buffer. size_t slot; - int ret = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight, - kBufferLayerCount, kBufferFormat, - kBufferUsage, &slot); - ASSERT_EQ(ret, 0); + auto status = producer_queue_->AllocateBuffer( + kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat, + kBufferUsage, &slot); + ASSERT_TRUE(status.ok()); + + if (slot_out) + *slot_out = slot; } protected: @@ -94,13 +100,13 @@ TEST_F(BufferHubQueueTest, TestDequeue) { } TEST_F(BufferHubQueueTest, TestProducerConsumer) { - const size_t nb_buffer = 16; + const size_t kBufferCount = 16; size_t slot; uint64_t seq; ASSERT_TRUE(CreateQueues<uint64_t>()); - for (size_t i = 0; i < nb_buffer; i++) { + for (size_t i = 0; i < kBufferCount; i++) { AllocateBuffer(); // Producer queue has all the available buffers on initialize. @@ -120,14 +126,23 @@ TEST_F(BufferHubQueueTest, TestProducerConsumer) { ASSERT_EQ(consumer_queue_->capacity(), i + 1); } - for (size_t i = 0; i < nb_buffer; i++) { + // Use /dev/zero as a stand-in for a fence. As long as BufferHub does not need + // to merge fences, which only happens when multiple consumers release the + // same buffer with release fences, the file object should simply pass + // through. + LocalHandle post_fence("/dev/zero", O_RDONLY); + struct stat post_fence_stat; + ASSERT_EQ(0, fstat(post_fence.Get(), &post_fence_stat)); + + for (size_t i = 0; i < kBufferCount; i++) { LocalHandle fence; - // First time, there is no buffer available to dequeue. + + // First time there is no buffer available to dequeue. auto consumer_status = consumer_queue_->Dequeue(0, &slot, &seq, &fence); ASSERT_FALSE(consumer_status.ok()); ASSERT_EQ(ETIMEDOUT, consumer_status.error()); - // Make sure Producer buffer is Post()'ed so that it's ready to Accquire + // Make sure Producer buffer is POSTED so that it's ready to Accquire // in the consumer's Dequeue() function. auto producer_status = producer_queue_->Dequeue(0, &slot, &fence); ASSERT_TRUE(producer_status.ok()); @@ -135,18 +150,133 @@ TEST_F(BufferHubQueueTest, TestProducerConsumer) { ASSERT_NE(nullptr, producer); uint64_t seq_in = static_cast<uint64_t>(i); - ASSERT_EQ(producer->Post({}, &seq_in, sizeof(seq_in)), 0); + ASSERT_EQ(producer->Post(post_fence, &seq_in, sizeof(seq_in)), 0); - // Second time, the just |Post()|'ed buffer should be dequeued. + // Second time the just the POSTED buffer should be dequeued. uint64_t seq_out = 0; consumer_status = consumer_queue_->Dequeue(0, &slot, &seq_out, &fence); ASSERT_TRUE(consumer_status.ok()); + EXPECT_TRUE(fence.IsValid()); + + struct stat acquire_fence_stat; + ASSERT_EQ(0, fstat(fence.Get(), &acquire_fence_stat)); + + // The file descriptors should refer to the same file object. Testing the + // device id and inode is a proxy for testing that the fds refer to the same + // file object. + EXPECT_NE(post_fence.Get(), fence.Get()); + EXPECT_EQ(post_fence_stat.st_dev, acquire_fence_stat.st_dev); + EXPECT_EQ(post_fence_stat.st_ino, acquire_fence_stat.st_ino); + auto consumer = consumer_status.take(); ASSERT_NE(nullptr, consumer); ASSERT_EQ(seq_in, seq_out); } } +TEST_F(BufferHubQueueTest, TestDetach) { + ASSERT_TRUE(CreateProducerQueue<void>()); + + // Allocate buffers. + const size_t kBufferCount = 4u; + for (size_t i = 0; i < kBufferCount; i++) { + AllocateBuffer(); + } + ASSERT_EQ(kBufferCount, producer_queue_->count()); + ASSERT_EQ(kBufferCount, producer_queue_->capacity()); + + consumer_queue_ = producer_queue_->CreateConsumerQueue(); + ASSERT_NE(nullptr, consumer_queue_); + + // Check that buffers are correctly imported on construction. + EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); + EXPECT_EQ(0u, consumer_queue_->count()); + + // Dequeue all the buffers and keep track of them in an array. This prevents + // the producer queue ring buffer ref counts from interfering with the tests. + struct Entry { + std::shared_ptr<BufferProducer> buffer; + LocalHandle fence; + size_t slot; + }; + std::array<Entry, kBufferCount> buffers; + + for (size_t i = 0; i < kBufferCount; i++) { + Entry* entry = &buffers[i]; + auto producer_status = + producer_queue_->Dequeue(0, &entry->slot, &entry->fence); + ASSERT_TRUE(producer_status.ok()); + entry->buffer = producer_status.take(); + ASSERT_NE(nullptr, entry->buffer); + EXPECT_EQ(i, entry->slot); + } + + // Detach a buffer and make sure both queues reflect the change. + ASSERT_TRUE(producer_queue_->DetachBuffer(buffers[0].slot)); + EXPECT_EQ(kBufferCount - 1, producer_queue_->capacity()); + + // As long as the detached buffer is still alive the consumer queue won't know + // its gone. + EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); + EXPECT_FALSE(consumer_queue_->HandleQueueEvents()); + EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); + + // Release the detached buffer. + buffers[0].buffer = nullptr; + + // Now the consumer queue should know it's gone. + EXPECT_FALSE(consumer_queue_->HandleQueueEvents()); + EXPECT_EQ(kBufferCount - 1, consumer_queue_->capacity()); + + // Allocate a new buffer. This should take the first empty slot. + size_t slot; + AllocateBuffer(&slot); + ALOGE_IF(TRACE, "ALLOCATE %zu", slot); + EXPECT_EQ(buffers[0].slot, slot); + EXPECT_EQ(kBufferCount, producer_queue_->capacity()); + + // The consumer queue should pick up the new buffer. + EXPECT_EQ(kBufferCount - 1, consumer_queue_->capacity()); + EXPECT_FALSE(consumer_queue_->HandleQueueEvents()); + EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); + + // Detach and allocate a buffer. + ASSERT_TRUE(producer_queue_->DetachBuffer(buffers[1].slot)); + EXPECT_EQ(kBufferCount - 1, producer_queue_->capacity()); + buffers[1].buffer = nullptr; + + AllocateBuffer(&slot); + ALOGE_IF(TRACE, "ALLOCATE %zu", slot); + EXPECT_EQ(buffers[1].slot, slot); + EXPECT_EQ(kBufferCount, producer_queue_->capacity()); + + // The consumer queue should pick up the new buffer but the count shouldn't + // change. + EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); + EXPECT_FALSE(consumer_queue_->HandleQueueEvents()); + EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); + + // Detach and allocate a buffer, but don't free the buffer right away. + ASSERT_TRUE(producer_queue_->DetachBuffer(buffers[2].slot)); + EXPECT_EQ(kBufferCount - 1, producer_queue_->capacity()); + + AllocateBuffer(&slot); + ALOGE_IF(TRACE, "ALLOCATE %zu", slot); + EXPECT_EQ(buffers[2].slot, slot); + EXPECT_EQ(kBufferCount, producer_queue_->capacity()); + + EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); + EXPECT_FALSE(consumer_queue_->HandleQueueEvents()); + EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); + + // Release the producer buffer to trigger a POLLHUP event for an already + // detached buffer. + buffers[2].buffer = nullptr; + EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); + EXPECT_FALSE(consumer_queue_->HandleQueueEvents()); + EXPECT_EQ(kBufferCount, consumer_queue_->capacity()); +} + TEST_F(BufferHubQueueTest, TestMultipleConsumers) { ASSERT_TRUE(CreateProducerQueue<void>()); @@ -347,10 +477,10 @@ TEST_F(BufferHubQueueTest, TestUsageSetMask) { // When allocation, leave out |set_mask| from usage bits on purpose. size_t slot; - int ret = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight, - kBufferFormat, kBufferLayerCount, - kBufferUsage & ~set_mask, &slot); - ASSERT_EQ(0, ret); + auto status = producer_queue_->AllocateBuffer( + kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat, + kBufferUsage & ~set_mask, &slot); + ASSERT_TRUE(status.ok()); LocalHandle fence; auto p1_status = producer_queue_->Dequeue(0, &slot, &fence); @@ -365,10 +495,10 @@ TEST_F(BufferHubQueueTest, TestUsageClearMask) { // When allocation, add |clear_mask| into usage bits on purpose. size_t slot; - int ret = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight, - kBufferLayerCount, kBufferFormat, - kBufferUsage | clear_mask, &slot); - ASSERT_EQ(0, ret); + auto status = producer_queue_->AllocateBuffer( + kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat, + kBufferUsage | clear_mask, &slot); + ASSERT_TRUE(status.ok()); LocalHandle fence; auto p1_status = producer_queue_->Dequeue(0, &slot, &fence); @@ -384,16 +514,17 @@ TEST_F(BufferHubQueueTest, TestUsageDenySetMask) { // Now that |deny_set_mask| is illegal, allocation without those bits should // be able to succeed. size_t slot; - int ret = producer_queue_->AllocateBuffer( + auto status = producer_queue_->AllocateBuffer( kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat, kBufferUsage & ~deny_set_mask, &slot); - ASSERT_EQ(ret, 0); + ASSERT_TRUE(status.ok()); // While allocation with those bits should fail. - ret = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight, - kBufferLayerCount, kBufferFormat, - kBufferUsage | deny_set_mask, &slot); - ASSERT_EQ(ret, -EINVAL); + status = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight, + kBufferLayerCount, kBufferFormat, + kBufferUsage | deny_set_mask, &slot); + ASSERT_FALSE(status.ok()); + ASSERT_EQ(EINVAL, status.error()); } TEST_F(BufferHubQueueTest, TestUsageDenyClearMask) { @@ -403,16 +534,17 @@ TEST_F(BufferHubQueueTest, TestUsageDenyClearMask) { // Now that clearing |deny_clear_mask| is illegal (i.e. setting these bits are // mandatory), allocation with those bits should be able to succeed. size_t slot; - int ret = producer_queue_->AllocateBuffer( + auto status = producer_queue_->AllocateBuffer( kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat, kBufferUsage | deny_clear_mask, &slot); - ASSERT_EQ(ret, 0); + ASSERT_TRUE(status.ok()); // While allocation without those bits should fail. - ret = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight, - kBufferLayerCount, kBufferFormat, - kBufferUsage & ~deny_clear_mask, &slot); - ASSERT_EQ(ret, -EINVAL); + status = producer_queue_->AllocateBuffer( + kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat, + kBufferUsage & ~deny_clear_mask, &slot); + ASSERT_FALSE(status.ok()); + ASSERT_EQ(EINVAL, status.error()); } } // namespace diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp index 2b6239f499..c7692d05b0 100644 --- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp +++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp @@ -192,7 +192,7 @@ TEST_F(BufferHubQueueProducerTest, Query_Succeeds) { EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &value)); EXPECT_LE(0, value); - EXPECT_GE(BufferQueueDefs::NUM_BUFFER_SLOTS, static_cast<size_t>(value)); + EXPECT_GE(BufferQueueDefs::NUM_BUFFER_SLOTS, value); EXPECT_EQ(NO_ERROR, mProducer->query(NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &value)); diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp index d90521a810..c0c7e2f3be 100644 --- a/libs/vr/libdisplay/Android.bp +++ b/libs/vr/libdisplay/Android.bp @@ -45,6 +45,7 @@ staticLibraries = [ headerLibraries = [ "vulkan_headers", + "libdvr_headers", ] cc_library { diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp index 935ca2ef81..5a0c3d00db 100644 --- a/libs/vr/libdisplay/display_client.cpp +++ b/libs/vr/libdisplay/display_client.cpp @@ -138,13 +138,13 @@ Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue( ALOGD_IF(TRACE, "Surface::CreateQueue: Allocating %zu buffers...", capacity); for (size_t i = 0; i < capacity; i++) { size_t slot; - const int ret = producer_queue->AllocateBuffer(width, height, layer_count, - format, usage, &slot); - if (ret < 0) { + auto allocate_status = producer_queue->AllocateBuffer( + width, height, layer_count, format, usage, &slot); + if (!allocate_status) { ALOGE( "Surface::CreateQueue: Failed to allocate buffer on queue_id=%d: %s", - producer_queue->id(), strerror(-ret)); - return ErrorStatus(ENOMEM); + producer_queue->id(), allocate_status.GetErrorMessage().c_str()); + return allocate_status.error_status(); } ALOGD_IF( TRACE, @@ -176,14 +176,14 @@ Status<std::unique_ptr<Surface>> DisplayClient::CreateSurface( return ErrorStatus(error); } -Status<std::unique_ptr<IonBuffer>> DisplayClient::GetNamedBuffer( - const std::string& name) { - auto status = InvokeRemoteMethod<DisplayProtocol::GetNamedBuffer>(name); +Status<std::unique_ptr<IonBuffer>> DisplayClient::GetGlobalBuffer( + DvrGlobalBufferKey key) { + auto status = InvokeRemoteMethod<DisplayProtocol::GetGlobalBuffer>(key); if (!status) { ALOGE( - "DisplayClient::GetNamedBuffer: Failed to get named buffer: name=%s; " + "DisplayClient::GetGlobalBuffer: Failed to get named buffer: key=%d; " "error=%s", - name.c_str(), status.GetErrorMessage().c_str()); + key, status.GetErrorMessage().c_str()); return status.error_status(); } @@ -192,9 +192,9 @@ Status<std::unique_ptr<IonBuffer>> DisplayClient::GetNamedBuffer( const int ret = native_buffer_handle.Import(ion_buffer.get()); if (ret < 0) { ALOGE( - "DisplayClient::GetNamedBuffer: Failed to import named buffer: " - "name=%s; error=%s", - name.c_str(), strerror(-ret)); + "DisplayClient::GetGlobalBuffer: Failed to import global buffer: " + "key=%d; error=%s", + key, strerror(-ret)); return ErrorStatus(-ret); } diff --git a/libs/vr/libdisplay/display_manager_client.cpp b/libs/vr/libdisplay/display_manager_client.cpp index 82dacf707d..37d6ff90a7 100644 --- a/libs/vr/libdisplay/display_manager_client.cpp +++ b/libs/vr/libdisplay/display_manager_client.cpp @@ -32,13 +32,13 @@ DisplayManagerClient::GetSurfaceState() { return status; } -pdx::Status<std::unique_ptr<IonBuffer>> DisplayManagerClient::SetupNamedBuffer( - const std::string& name, size_t size, uint64_t usage) { - auto status = InvokeRemoteMethod<DisplayManagerProtocol::SetupNamedBuffer>( - name, size, usage); +pdx::Status<std::unique_ptr<IonBuffer>> DisplayManagerClient::SetupGlobalBuffer( + DvrGlobalBufferKey key, size_t size, uint64_t usage) { + auto status = InvokeRemoteMethod<DisplayManagerProtocol::SetupGlobalBuffer>( + key, size, usage); if (!status) { ALOGE( - "DisplayManagerClient::SetupPoseBuffer: Failed to create the named " + "DisplayManagerClient::SetupGlobalBuffer: Failed to create the global " "buffer %s", status.GetErrorMessage().c_str()); return status.error_status(); @@ -49,15 +49,41 @@ pdx::Status<std::unique_ptr<IonBuffer>> DisplayManagerClient::SetupNamedBuffer( const int ret = native_buffer_handle.Import(ion_buffer.get()); if (ret < 0) { ALOGE( - "DisplayClient::GetNamedBuffer: Failed to import named buffer: " - "name=%s; error=%s", - name.c_str(), strerror(-ret)); + "DisplayManagerClient::GetGlobalBuffer: Failed to import global " + "buffer: key=%d; error=%s", + key, strerror(-ret)); return ErrorStatus(-ret); } return {std::move(ion_buffer)}; } +pdx::Status<void> DisplayManagerClient::DeleteGlobalBuffer( + DvrGlobalBufferKey key) { + auto status = + InvokeRemoteMethod<DisplayManagerProtocol::DeleteGlobalBuffer>(key); + if (!status) { + ALOGE("DisplayManagerClient::DeleteGlobalBuffer Failed: %s", + status.GetErrorMessage().c_str()); + } + + return status; +} + +pdx::Status<std::string> DisplayManagerClient::GetConfigurationData( + ConfigFileType config_type) { + auto status = + InvokeRemoteMethod<DisplayManagerProtocol::GetConfigurationData>( + config_type); + if (!status && status.error() != ENOENT) { + ALOGE( + "DisplayManagerClient::GetConfigurationData: Unable to get " + "configuration data. Error: %s", + status.GetErrorMessage().c_str()); + } + return status; +} + pdx::Status<std::unique_ptr<ConsumerQueue>> DisplayManagerClient::GetSurfaceQueue(int surface_id, int queue_id) { auto status = InvokeRemoteMethod<DisplayManagerProtocol::GetSurfaceQueue>( diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h index 7a7f670ffa..e5b3340e09 100644 --- a/libs/vr/libdisplay/include/private/dvr/display_client.h +++ b/libs/vr/libdisplay/include/private/dvr/display_client.h @@ -1,6 +1,7 @@ #ifndef ANDROID_DVR_DISPLAY_CLIENT_H_ #define ANDROID_DVR_DISPLAY_CLIENT_H_ +#include <dvr/dvr_api.h> #include <hardware/hwcomposer.h> #include <pdx/client.h> #include <pdx/file_handle.h> @@ -67,8 +68,8 @@ class Surface : public pdx::ClientBase<Surface> { class DisplayClient : public pdx::ClientBase<DisplayClient> { public: pdx::Status<Metrics> GetDisplayMetrics(); - pdx::Status<std::unique_ptr<IonBuffer>> GetNamedBuffer( - const std::string& name); + pdx::Status<std::unique_ptr<IonBuffer>> GetGlobalBuffer( + DvrGlobalBufferKey key); pdx::Status<std::unique_ptr<Surface>> CreateSurface( const SurfaceAttributes& attributes); diff --git a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h b/libs/vr/libdisplay/include/private/dvr/display_manager_client.h index fea841595a..c5ec2314cc 100644 --- a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h +++ b/libs/vr/libdisplay/include/private/dvr/display_manager_client.h @@ -21,11 +21,13 @@ class DisplayManagerClient : public pdx::ClientBase<DisplayManagerClient> { ~DisplayManagerClient() override; pdx::Status<std::vector<SurfaceState>> GetSurfaceState(); - pdx::Status<std::unique_ptr<IonBuffer>> SetupNamedBuffer( - const std::string& name, size_t size, uint64_t usage); + pdx::Status<std::unique_ptr<IonBuffer>> SetupGlobalBuffer( + DvrGlobalBufferKey key, size_t size, uint64_t usage); + pdx::Status<void> DeleteGlobalBuffer(DvrGlobalBufferKey key); pdx::Status<std::unique_ptr<ConsumerQueue>> GetSurfaceQueue(int surface_id, int queue_id); + pdx::Status<std::string> GetConfigurationData(ConfigFileType config_type); using Client::event_fd; pdx::Status<int> GetEventMask(int events) { diff --git a/libs/vr/libdisplay/include/private/dvr/display_protocol.h b/libs/vr/libdisplay/include/private/dvr/display_protocol.h index f34d61fe49..b857d48311 100644 --- a/libs/vr/libdisplay/include/private/dvr/display_protocol.h +++ b/libs/vr/libdisplay/include/private/dvr/display_protocol.h @@ -8,6 +8,8 @@ #include <dvr/dvr_display_types.h> +#include <dvr/dvr_api.h> +#include <pdx/rpc/buffer_wrapper.h> #include <pdx/rpc/remote_method.h> #include <pdx/rpc/serializable.h> #include <pdx/rpc/variant.h> @@ -191,7 +193,7 @@ struct DisplayProtocol { // Op codes. enum { kOpGetMetrics = 0, - kOpGetNamedBuffer, + kOpGetGlobalBuffer, kOpIsVrAppRunning, kOpCreateSurface, kOpGetSurfaceInfo, @@ -205,8 +207,8 @@ struct DisplayProtocol { // Methods. PDX_REMOTE_METHOD(GetMetrics, kOpGetMetrics, Metrics(Void)); - PDX_REMOTE_METHOD(GetNamedBuffer, kOpGetNamedBuffer, - LocalNativeBufferHandle(std::string name)); + PDX_REMOTE_METHOD(GetGlobalBuffer, kOpGetGlobalBuffer, + LocalNativeBufferHandle(DvrGlobalBufferKey key)); PDX_REMOTE_METHOD(IsVrAppRunning, kOpIsVrAppRunning, bool(Void)); PDX_REMOTE_METHOD(CreateSurface, kOpCreateSurface, SurfaceInfo(const SurfaceAttributes& attributes)); @@ -217,6 +219,12 @@ struct DisplayProtocol { void(const SurfaceAttributes& attributes)); }; +enum class ConfigFileType : uint32_t { + kLensMetrics, + kDeviceMetrics, + kDeviceConfiguration +}; + struct DisplayManagerProtocol { // Service path. static constexpr char kClientPath[] = "system/vr/display/manager"; @@ -225,7 +233,9 @@ struct DisplayManagerProtocol { enum { kOpGetSurfaceState = 0, kOpGetSurfaceQueue, - kOpSetupNamedBuffer, + kOpSetupGlobalBuffer, + kOpGetConfigurationData, + kOpDeleteGlobalBuffer, }; // Aliases. @@ -237,9 +247,13 @@ struct DisplayManagerProtocol { std::vector<SurfaceState>(Void)); PDX_REMOTE_METHOD(GetSurfaceQueue, kOpGetSurfaceQueue, LocalChannelHandle(int surface_id, int queue_id)); - PDX_REMOTE_METHOD(SetupNamedBuffer, kOpSetupNamedBuffer, - LocalNativeBufferHandle(const std::string& name, - size_t size, uint64_t usage)); + PDX_REMOTE_METHOD(SetupGlobalBuffer, kOpSetupGlobalBuffer, + LocalNativeBufferHandle(DvrGlobalBufferKey key, size_t size, + uint64_t usage)); + PDX_REMOTE_METHOD(GetConfigurationData, kOpGetConfigurationData, + std::string(ConfigFileType config_type)); + PDX_REMOTE_METHOD(DeleteGlobalBuffer, kOpDeleteGlobalBuffer, + void(DvrGlobalBufferKey key)); }; struct VSyncSchedInfo { diff --git a/libs/vr/libdvr/dvr_display_manager.cpp b/libs/vr/libdvr/dvr_display_manager.cpp index 87636ecd91..ffe090dded 100644 --- a/libs/vr/libdvr/dvr_display_manager.cpp +++ b/libs/vr/libdvr/dvr_display_manager.cpp @@ -11,6 +11,7 @@ using android::AHardwareBuffer_convertToGrallocUsageBits; using android::dvr::BufferConsumer; +using android::dvr::display::ConfigFileType; using android::dvr::display::DisplayManagerClient; using android::dvr::display::SurfaceAttributes; using android::dvr::display::SurfaceAttribute; @@ -111,19 +112,20 @@ int dvrDisplayManagerCreate(DvrDisplayManager** client_out) { void dvrDisplayManagerDestroy(DvrDisplayManager* client) { delete client; } -int dvrDisplayManagerSetupNamedBuffer(DvrDisplayManager* client, - const char* name, size_t size, - uint64_t usage, DvrBuffer** buffer_out) { - if (!client || !name || !buffer_out) +int dvrDisplayManagerSetupGlobalBuffer(DvrDisplayManager* client, + DvrGlobalBufferKey key, size_t size, + uint64_t usage, DvrBuffer** buffer_out) { + if (!client || !buffer_out) return -EINVAL; uint64_t gralloc_usage = AHardwareBuffer_convertToGrallocUsageBits(usage); auto buffer_status = - client->client->SetupNamedBuffer(name, size, gralloc_usage); + client->client->SetupGlobalBuffer(key, size, gralloc_usage); if (!buffer_status) { - ALOGE("dvrDisplayManagerSetupPoseBuffer: Failed to setup named buffer: %s", - buffer_status.GetErrorMessage().c_str()); + ALOGE( + "dvrDisplayManagerSetupGlobalBuffer: Failed to setup global buffer: %s", + buffer_status.GetErrorMessage().c_str()); return -buffer_status.error(); } @@ -131,6 +133,47 @@ int dvrDisplayManagerSetupNamedBuffer(DvrDisplayManager* client, return 0; } +int dvrDisplayManagerDeleteGlobalBuffer(DvrDisplayManager* client, + DvrGlobalBufferKey key) { + if (!client) + return -EINVAL; + + auto buffer_status = client->client->DeleteGlobalBuffer(key); + if (!buffer_status) { + ALOGE( + "dvrDisplayManagerDeleteGlobalBuffer: Failed to delete named buffer: " + "%s", + buffer_status.GetErrorMessage().c_str()); + return -buffer_status.error(); + } + + return 0; +} + +int dvrConfigurationDataGet(DvrDisplayManager* client, int config_type, + uint8_t** data, size_t* data_size) { + if (!client || !data || !data_size) { + return -EINVAL; + } + + ConfigFileType config_file_type = static_cast<ConfigFileType>(config_type); + auto config_data_status = + client->client->GetConfigurationData(config_file_type); + + if (!config_data_status) { + return -config_data_status.error(); + } + + *data_size = config_data_status.get().size(); + *data = new uint8_t[*data_size]; + std::copy_n(config_data_status.get().begin(), *data_size, *data); + return 0; +} + +void dvrConfigurationDataDestroy(DvrDisplayManager*, uint8_t* data) { + delete[] data; +} + int dvrDisplayManagerGetEventFd(DvrDisplayManager* client) { if (!client) return -EINVAL; diff --git a/libs/vr/libdvr/dvr_internal.h b/libs/vr/libdvr/dvr_internal.h index 89bef09871..6431f1cfd8 100644 --- a/libs/vr/libdvr/dvr_internal.h +++ b/libs/vr/libdvr/dvr_internal.h @@ -44,6 +44,8 @@ ProducerQueue* GetProducerQueueFromDvrWriteBufferQueue( extern "C" { +struct ANativeWindow; + struct DvrWriteBuffer { std::shared_ptr<android::dvr::BufferProducer> write_buffer; }; diff --git a/libs/vr/libdvr/dvr_surface.cpp b/libs/vr/libdvr/dvr_surface.cpp index 67e2ae88ac..1fe987439c 100644 --- a/libs/vr/libdvr/dvr_surface.cpp +++ b/libs/vr/libdvr/dvr_surface.cpp @@ -156,22 +156,22 @@ int dvrSurfaceCreateWriteBufferQueue(DvrSurface* surface, uint32_t width, return 0; } -int dvrGetNamedBuffer(const char* name, DvrBuffer** out_buffer) { +int dvrGetGlobalBuffer(DvrGlobalBufferKey key, DvrBuffer** out_buffer) { auto client = DisplayClient::Create(); if (!client) { - ALOGE("dvrGetNamedBuffer: Failed to create display client!"); + ALOGE("dvrGetGlobalBuffer: Failed to create display client!"); return -ECOMM; } - if (out_buffer == nullptr || name == nullptr) { - ALOGE("dvrGetNamedBuffer: Invalid inputs: name=%p, out_buffer=%p.", name, + if (out_buffer == nullptr) { + ALOGE("dvrGetGlobalBuffer: Invalid inputs: key=%d, out_buffer=%p.", key, out_buffer); return -EINVAL; } - auto status = client->GetNamedBuffer(name); + auto status = client->GetGlobalBuffer(key); if (!status) { - ALOGE("dvrGetNamedBuffer: Failed to find named buffer name=%s: %s", name, + ALOGE("dvrGetGlobalBuffer: Failed to find named buffer key=%d: %s", key, status.GetErrorMessage().c_str()); return -status.error(); } diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h index 8a203e0694..ef2c9758a1 100644 --- a/libs/vr/libdvr/include/dvr/dvr_api.h +++ b/libs/vr/libdvr/include/dvr/dvr_api.h @@ -33,6 +33,7 @@ typedef struct DvrWriteBufferQueue DvrWriteBufferQueue; typedef struct DvrSurface DvrSurface; typedef uint64_t DvrSurfaceAttributeType; typedef int32_t DvrSurfaceAttributeKey; +typedef int32_t DvrGlobalBufferKey; typedef struct DvrSurfaceAttributeValue DvrSurfaceAttributeValue; typedef struct DvrSurfaceAttribute DvrSurfaceAttribute; @@ -42,10 +43,11 @@ struct native_handle; // dvr_display_manager.h typedef int (*DvrDisplayManagerCreatePtr)(DvrDisplayManager** client_out); typedef void (*DvrDisplayManagerDestroyPtr)(DvrDisplayManager* client); -typedef int (*DvrDisplayManagerSetupNamedBufferPtr)(DvrDisplayManager* client, - const char* name, - size_t size, uint64_t usage, - DvrBuffer** buffer_out); +typedef int (*DvrDisplayManagerSetupGlobalBufferPtr)(DvrDisplayManager* client, + DvrGlobalBufferKey key, + size_t size, + uint64_t usage, + DvrBuffer** buffer_out); typedef int (*DvrDisplayManagerGetEventFdPtr)(DvrDisplayManager* client); typedef int (*DvrDisplayManagerTranslateEpollEventMaskPtr)( DvrDisplayManager* client, int in_events, int* out_events); @@ -54,6 +56,11 @@ typedef int (*DvrDisplayManagerGetSurfaceStatePtr)( typedef int (*DvrDisplayManagerGetReadBufferQueuePtr)( DvrDisplayManager* client, int surface_id, int queue_id, DvrReadBufferQueue** queue_out); +typedef int (*DvrConfigurationDataGetPtr)(DvrDisplayManager* client, + int config_type, uint8_t** data, + size_t* data_size); +typedef void (*DvrConfigurationDataDestroyPtr)(DvrDisplayManager* client, + uint8_t* data); typedef int (*DvrSurfaceStateCreatePtr)(DvrSurfaceState** surface_state); typedef void (*DvrSurfaceStateDestroyPtr)(DvrSurfaceState* surface_state); typedef int (*DvrSurfaceStateGetSurfaceCountPtr)(DvrSurfaceState* surface_state, @@ -151,7 +158,8 @@ typedef int (*DvrReadBufferQueueDequeuePtr)(DvrReadBufferQueue* read_queue, size_t meta_size_bytes); // dvr_surface.h -typedef int (*DvrGetNamedBufferPtr)(const char* name, DvrBuffer** out_buffer); +typedef int (*DvrGetGlobalBufferPtr)(DvrGlobalBufferKey key, + DvrBuffer** out_buffer); typedef int (*DvrSurfaceCreatePtr)(const DvrSurfaceAttribute* attributes, size_t attribute_count, DvrSurface** surface_out); diff --git a/libs/vr/libdvr/include/dvr/dvr_api_entries.h b/libs/vr/libdvr/include/dvr/dvr_api_entries.h index 09568fd9dc..30d0a650f4 100644 --- a/libs/vr/libdvr/include/dvr/dvr_api_entries.h +++ b/libs/vr/libdvr/include/dvr/dvr_api_entries.h @@ -11,11 +11,13 @@ // Display manager client DVR_V1_API_ENTRY(DisplayManagerCreate); DVR_V1_API_ENTRY(DisplayManagerDestroy); -DVR_V1_API_ENTRY(DisplayManagerSetupNamedBuffer); +DVR_V1_API_ENTRY(DisplayManagerSetupGlobalBuffer); DVR_V1_API_ENTRY(DisplayManagerGetEventFd); DVR_V1_API_ENTRY(DisplayManagerTranslateEpollEventMask); DVR_V1_API_ENTRY(DisplayManagerGetSurfaceState); DVR_V1_API_ENTRY(DisplayManagerGetReadBufferQueue); +DVR_V1_API_ENTRY(ConfigurationDataGet); +DVR_V1_API_ENTRY(ConfigurationDataDestroy); DVR_V1_API_ENTRY(SurfaceStateCreate); DVR_V1_API_ENTRY(SurfaceStateDestroy); DVR_V1_API_ENTRY(SurfaceStateGetSurfaceCount); @@ -84,7 +86,7 @@ DVR_V1_API_ENTRY(SurfaceDestroy); DVR_V1_API_ENTRY(SurfaceGetId); DVR_V1_API_ENTRY(SurfaceSetAttributes); DVR_V1_API_ENTRY(SurfaceCreateWriteBufferQueue); -DVR_V1_API_ENTRY(GetNamedBuffer); +DVR_V1_API_ENTRY(GetGlobalBuffer); // Pose client DVR_V1_API_ENTRY(PoseCreate); diff --git a/libs/vr/libdvr/include/dvr/dvr_display_manager.h b/libs/vr/libdvr/include/dvr/dvr_display_manager.h index d5aef8b18b..eb1e711a88 100644 --- a/libs/vr/libdvr/include/dvr/dvr_display_manager.h +++ b/libs/vr/libdvr/include/dvr/dvr_display_manager.h @@ -28,9 +28,32 @@ void dvrDisplayManagerDestroy(DvrDisplayManager* client); // Sets up a named buffer for shared memory data transfer between display // clients and the display manager. // @return 0 on success. Otherwise returns a negative error value. -int dvrDisplayManagerSetupNamedBuffer(DvrDisplayManager* client, - const char* name, size_t size, - uint64_t usage, DvrBuffer** buffer_out); +int dvrDisplayManagerSetupGlobalBuffer(DvrDisplayManager* client, + DvrGlobalBufferKey key, size_t size, + uint64_t usage, DvrBuffer** buffer_out); + +// Deletes a named buffer. WARNING: This is dangerous because any existing +// clients of this buffer will not be notified and will remain attached to +// the old buffer. This is useful for tests, but probably not for production +// code. +// @return 0 on success. Otherwise returns a negative error value. +int dvrDisplayManagerDeleteGlobalBuffer(DvrDisplayManager* client, + DvrGlobalBufferKey key); + +// Device metrics data type enums. +enum { + DVR_CONFIGURATION_DATA_LENS_METRICS = 0, + DVR_CONFIGURATION_DATA_DEVICE_METRICS = 1, + DVR_CONFIGURATION_DATA_DEVICE_CONFIG = 2, +}; + +// Loads device configuration data of DVR_CONFIGURATION_DATA_*. +// @return 0 on success. Otherwise returns a negative error value. +int dvrConfigurationDataGet(DvrDisplayManager* client, int config_type, + uint8_t** data, size_t* data_size); + +// Destroy the configuration data returned from dvrGetConfigurationData. +void dvrConfigurationDataDestroy(DvrDisplayManager* client, uint8_t* data); // Returns an fd used to signal when surface updates occur. Note that depending // on the underlying transport, only a subset of the real event bits may be diff --git a/libs/vr/libdvr/include/dvr/dvr_surface.h b/libs/vr/libdvr/include/dvr/dvr_surface.h index 361488e671..e3ab41b2a6 100644 --- a/libs/vr/libdvr/include/dvr/dvr_surface.h +++ b/libs/vr/libdvr/include/dvr/dvr_surface.h @@ -6,16 +6,13 @@ #include <stdint.h> #include <sys/cdefs.h> +#include <dvr/dvr_api.h> #include <dvr/dvr_buffer.h> #include <dvr/dvr_buffer_queue.h> #include <dvr/dvr_display_types.h> __BEGIN_DECLS -typedef struct DvrBuffer DvrBuffer; -typedef struct DvrSurface DvrSurface; -typedef struct DvrWriteBufferQueue DvrWriteBufferQueue; - // Attribute types. The values are one-hot encoded to support singluar types or // masks of supported types. enum { @@ -82,9 +79,9 @@ int dvrSurfaceCreateWriteBufferQueue(DvrSurface* surface, uint32_t width, size_t capacity, DvrWriteBufferQueue** queue_out); -// Get a named buffer from the display service. +// Get a global buffer from the display service. // @return 0 on success. Otherwise returns a negative error value. -int dvrGetNamedBuffer(const char* name, DvrBuffer** out_buffer); +int dvrGetGlobalBuffer(DvrGlobalBufferKey key, DvrBuffer** out_buffer); __END_DECLS diff --git a/libs/vr/libdvr/include/dvr/dvr_vrflinger_config_buffer.h b/libs/vr/libdvr/include/dvr/dvr_vrflinger_config_buffer.h new file mode 100644 index 0000000000..108c78b5da --- /dev/null +++ b/libs/vr/libdvr/include/dvr/dvr_vrflinger_config_buffer.h @@ -0,0 +1,51 @@ +#ifndef ANDROID_DVR_VRFLINGER_CONFIG_BUFFER_H +#define ANDROID_DVR_VRFLINGER_CONFIG_BUFFER_H + +#include <libbroadcastring/broadcast_ring.h> + +// This header is shared by VrCore and Android and must be kept in sync. + +namespace android { +namespace dvr { + +// Increment when the layout for the buffers change. +constexpr uint32_t kSharedConfigBufferLayoutVersion = 1; + +// This is a shared memory buffer for passing config data from VrCore to +// libvrflinger in SurfaceFlinger. +struct DvrVrFlingerConfigBuffer { + // Offset before vsync to submit frames to hardware composer. + int frame_post_offset_ns{4000000}; + + // If the number of pending fences goes over this count at the point when we + // are about to submit a new frame to HWC, we will drop the frame. This + // should be a signal that the display driver has begun queuing frames. Note + // that with smart displays (with RAM), the fence is signaled earlier than + // the next vsync, at the point when the DMA to the display completes. + // Currently we use a smart display and the EDS timing coincides with zero + // pending fences, so this is 0. + size_t allowed_pending_fence_count{0}; + + // New fields should always be added to the end for backwards compat. +}; + +class DvrVrFlingerConfigBufferTraits { + public: + using Record = DvrVrFlingerConfigBuffer; + static constexpr bool kUseStaticRecordSize = false; + static constexpr uint32_t kStaticRecordCount = 2; + static constexpr int kMaxReservedRecords = 1; + static constexpr int kMinAvailableRecords = 1; +}; + +// The broadcast ring classes that will expose the data. +using DvrVrFlingerConfigRing = + BroadcastRing<DvrVrFlingerConfigBuffer, DvrVrFlingerConfigBufferTraits>; + +// Common buffers. +constexpr int kVrFlingerConfigBufferKey = 5; + +} // namespace dvr +} // namespace android + +#endif // ANDROID_DVR_VRFLINGER_CONFIG_BUFFER_H diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp index ef746e207a..ab2ee75a3e 100644 --- a/libs/vr/libdvr/tests/Android.bp +++ b/libs/vr/libdvr/tests/Android.bp @@ -32,6 +32,7 @@ static_libraries = [ "libdvrcommon", "libdisplay", "libpdx_default_transport", + "libbroadcastring", ] cc_test { diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp index 474e9684c2..5d1202042d 100644 --- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp +++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp @@ -40,10 +40,11 @@ class DvrBufferQueueTest : public ::testing::Test { void AllocateBuffers(size_t buffer_count) { size_t out_slot; for (size_t i = 0; i < buffer_count; i++) { - int ret = GetProducerQueueFromDvrWriteBufferQueue(write_queue_) - ->AllocateBuffer(kBufferWidth, kBufferHeight, kLayerCount, - kBufferFormat, kBufferUsage, &out_slot); - ASSERT_EQ(0, ret); + auto status = + GetProducerQueueFromDvrWriteBufferQueue(write_queue_) + ->AllocateBuffer(kBufferWidth, kBufferHeight, kLayerCount, + kBufferFormat, kBufferUsage, &out_slot); + ASSERT_TRUE(status.ok()); } } diff --git a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp index a2414d65d8..6f11465ad1 100644 --- a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp +++ b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp @@ -1,3 +1,4 @@ +#include <android-base/properties.h> #include <base/logging.h> #include <gtest/gtest.h> #include <poll.h> @@ -200,6 +201,24 @@ class TestDisplayManager { return {std::move(queue_ids)}; } + Status<std::vector<uint8_t>> GetConfigData(int config_type) { + uint8_t* data = nullptr; + size_t data_size = 0; + int error = dvrConfigurationDataGet(display_manager_.get(), config_type, + &data, &data_size); + if (error < 0) { + return ErrorStatus(-error); + } + + if (!data || data_size == 0) { + return ErrorStatus(EINVAL); + } + std::vector<uint8_t> data_result(data, data + data_size); + dvrConfigurationDataDestroy(display_manager_.get(), data); + std::string s(data, data + data_size); + return {std::move(data_result)}; + } + private: UniqueDvrDisplayManager display_manager_; UniqueDvrSurfaceState surface_state_; @@ -573,6 +592,23 @@ TEST_F(DvrDisplayManagerTest, MultiLayerBufferQueue) { dvrWriteBufferDestroy(buffer); } +TEST_F(DvrDisplayManagerTest, ConfigurationData) { + auto data1 = manager_->GetConfigData(-1); + ASSERT_STATUS_ERROR(data1); + + const char kDvrLensMetricsProperty[] = "ro.dvr.lens_metrics"; + + // This should be run on devices with and without built in metrics. + bool has_metric = !base::GetProperty(kDvrLensMetricsProperty, "").empty(); + auto data2 = manager_->GetConfigData(DVR_CONFIGURATION_DATA_LENS_METRICS); + if (has_metric) { + ASSERT_STATUS_OK(data2); + ASSERT_NE(0u, data2.get().size()); + } else { + ASSERT_STATUS_ERROR(data2); + } +} + } // namespace } // namespace dvr diff --git a/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp b/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp index e65f6d5b01..cf04588d21 100644 --- a/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp +++ b/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp @@ -2,6 +2,7 @@ #include <dvr/dvr_buffer.h> #include <dvr/dvr_display_manager.h> #include <dvr/dvr_surface.h> +#include <dvr/dvr_vrflinger_config_buffer.h> #include <system/graphics.h> #include <base/logging.h> @@ -12,7 +13,7 @@ namespace dvr { namespace { -class DvrNamedBufferTest : public ::testing::Test { +class DvrGlobalBufferTest : public ::testing::Test { protected: void SetUp() override { const int ret = dvrDisplayManagerCreate(&client_); @@ -28,17 +29,17 @@ class DvrNamedBufferTest : public ::testing::Test { DvrDisplayManager* client_ = nullptr; }; -TEST_F(DvrNamedBufferTest, TestNamedBuffersSameName) { - const char* buffer_name = "same_name"; +TEST_F(DvrGlobalBufferTest, TestGlobalBuffersSameName) { + const DvrGlobalBufferKey buffer_key = 101; DvrBuffer* buffer1 = nullptr; int ret1 = - dvrDisplayManagerSetupNamedBuffer(client_, buffer_name, 10, 0, &buffer1); + dvrDisplayManagerSetupGlobalBuffer(client_, buffer_key, 10, 0, &buffer1); ASSERT_EQ(0, ret1); ASSERT_NE(nullptr, buffer1); DvrBuffer* buffer2 = nullptr; int ret2 = - dvrDisplayManagerSetupNamedBuffer(client_, buffer_name, 10, 0, &buffer2); + dvrDisplayManagerSetupGlobalBuffer(client_, buffer_key, 10, 0, &buffer2); ASSERT_EQ(0, ret1); ASSERT_NE(nullptr, buffer2); @@ -71,7 +72,7 @@ TEST_F(DvrNamedBufferTest, TestNamedBuffersSameName) { dvrBufferDestroy(buffer2); DvrBuffer* buffer3 = nullptr; - int e3 = dvrGetNamedBuffer(buffer_name, &buffer3); + int e3 = dvrGetGlobalBuffer(buffer_key, &buffer3); ASSERT_NE(nullptr, buffer3); ASSERT_EQ(0, e3); @@ -95,38 +96,38 @@ TEST_F(DvrNamedBufferTest, TestNamedBuffersSameName) { AHardwareBuffer_release(hardware_buffer3); } -TEST_F(DvrNamedBufferTest, TestMultipleNamedBuffers) { - const char* buffer_name1 = "test1"; - const char* buffer_name2 = "test2"; +TEST_F(DvrGlobalBufferTest, TestMultipleGlobalBuffers) { + const DvrGlobalBufferKey buffer_key1 = 102; + const DvrGlobalBufferKey buffer_key2 = 103; DvrBuffer* setup_buffer1 = nullptr; - int ret1 = dvrDisplayManagerSetupNamedBuffer(client_, buffer_name1, 10, 0, - &setup_buffer1); + int ret1 = dvrDisplayManagerSetupGlobalBuffer(client_, buffer_key1, 10, 0, + &setup_buffer1); ASSERT_EQ(0, ret1); ASSERT_NE(nullptr, setup_buffer1); dvrBufferDestroy(setup_buffer1); DvrBuffer* setup_buffer2 = nullptr; - int ret2 = dvrDisplayManagerSetupNamedBuffer(client_, buffer_name2, 10, 0, - &setup_buffer2); + int ret2 = dvrDisplayManagerSetupGlobalBuffer(client_, buffer_key2, 10, 0, + &setup_buffer2); ASSERT_EQ(0, ret2); ASSERT_NE(nullptr, setup_buffer2); dvrBufferDestroy(setup_buffer2); DvrBuffer* buffer1 = nullptr; - int e1 = dvrGetNamedBuffer(buffer_name1, &buffer1); + int e1 = dvrGetGlobalBuffer(buffer_key1, &buffer1); ASSERT_NE(nullptr, buffer1); ASSERT_EQ(0, e1); dvrBufferDestroy(buffer1); DvrBuffer* buffer2 = nullptr; - int e2 = dvrGetNamedBuffer(buffer_name2, &buffer2); + int e2 = dvrGetGlobalBuffer(buffer_key2, &buffer2); ASSERT_NE(nullptr, buffer2); ASSERT_EQ(0, e2); dvrBufferDestroy(buffer2); } -TEST_F(DvrNamedBufferTest, TestNamedBufferUsage) { - const char* buffer_name = "buffer_usage"; +TEST_F(DvrGlobalBufferTest, TestGlobalBufferUsage) { + const DvrGlobalBufferKey buffer_key = 100; // Set usage to AHARDWAREBUFFER_USAGE_VIDEO_ENCODE. We use this because // internally AHARDWAREBUFFER_USAGE_VIDEO_ENCODE is converted to @@ -136,8 +137,8 @@ TEST_F(DvrNamedBufferTest, TestNamedBufferUsage) { const uint64_t usage = AHARDWAREBUFFER_USAGE_VIDEO_ENCODE; DvrBuffer* setup_buffer = nullptr; - int e1 = dvrDisplayManagerSetupNamedBuffer(client_, buffer_name, 10, usage, - &setup_buffer); + int e1 = dvrDisplayManagerSetupGlobalBuffer(client_, buffer_key, 10, usage, + &setup_buffer); ASSERT_NE(nullptr, setup_buffer); ASSERT_EQ(0, e1); @@ -154,6 +155,153 @@ TEST_F(DvrNamedBufferTest, TestNamedBufferUsage) { AHardwareBuffer_release(hardware_buffer); } +TEST_F(DvrGlobalBufferTest, TestGlobalBufferCarriesData) { + const DvrGlobalBufferKey buffer_name = 110; + + uint64_t usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | + AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN; + constexpr size_t size = 1024 * sizeof(uint64_t); + constexpr uint64_t value = 0x123456787654321; + + { + // Allocate some data and set it to something. + DvrBuffer* setup_buffer = nullptr; + int e1 = dvrDisplayManagerSetupGlobalBuffer(client_, buffer_name, size, + usage, &setup_buffer); + ASSERT_NE(nullptr, setup_buffer); + ASSERT_EQ(0, e1); + + AHardwareBuffer* hardware_buffer = nullptr; + int e2 = dvrBufferGetAHardwareBuffer(setup_buffer, &hardware_buffer); + ASSERT_EQ(0, e2); + ASSERT_NE(nullptr, hardware_buffer); + + void* buffer; + int e3 = AHardwareBuffer_lock(hardware_buffer, usage, -1, nullptr, &buffer); + ASSERT_EQ(0, e3); + ASSERT_NE(nullptr, buffer); + // Verify that the buffer pointer is at least 16 byte aligned. + ASSERT_EQ(0, reinterpret_cast<uintptr_t>(buffer) & (16 - 1)); + + uint64_t* data = static_cast<uint64_t*>(buffer); + constexpr size_t num_values = size / sizeof(uint64_t); + for (size_t i = 0; i < num_values; ++i) { + data[i] = value; + } + + int32_t fence = -1; + int e4 = AHardwareBuffer_unlock(hardware_buffer, &fence); + ASSERT_EQ(0, e4); + + dvrBufferDestroy(setup_buffer); + AHardwareBuffer_release(hardware_buffer); + } + + { + // Get the buffer and check that all the data is still present. + DvrBuffer* setup_buffer = nullptr; + int e1 = dvrGetGlobalBuffer(buffer_name, &setup_buffer); + ASSERT_NE(nullptr, setup_buffer); + ASSERT_EQ(0, e1); + + AHardwareBuffer* hardware_buffer = nullptr; + int e2 = dvrBufferGetAHardwareBuffer(setup_buffer, &hardware_buffer); + ASSERT_EQ(0, e2); + ASSERT_NE(nullptr, hardware_buffer); + + void* buffer; + int e3 = AHardwareBuffer_lock(hardware_buffer, usage, -1, nullptr, &buffer); + ASSERT_EQ(0, e3); + ASSERT_NE(nullptr, buffer); + // Verify that the buffer pointer is at least 16 byte aligned. + ASSERT_EQ(0, reinterpret_cast<uintptr_t>(buffer) & (16 - 1)); + + uint64_t* data = static_cast<uint64_t*>(buffer); + constexpr size_t num_values = size / sizeof(uint64_t); + bool is_equal = true; + for (size_t i = 0; i < num_values; ++i) { + is_equal &= (data[i] == value); + } + ASSERT_TRUE(is_equal); + + int32_t fence = -1; + int e4 = AHardwareBuffer_unlock(hardware_buffer, &fence); + ASSERT_EQ(0, e4); + + dvrBufferDestroy(setup_buffer); + AHardwareBuffer_release(hardware_buffer); + } +} + +TEST_F(DvrGlobalBufferTest, TestGlobalBufferZeroed) { + const DvrGlobalBufferKey buffer_name = 120; + + // Allocate 1MB and check that it is all zeros. + uint64_t usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | + AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN; + constexpr size_t size = 1024 * 1024; + DvrBuffer* setup_buffer = nullptr; + int e1 = dvrDisplayManagerSetupGlobalBuffer(client_, buffer_name, size, usage, + &setup_buffer); + ASSERT_NE(nullptr, setup_buffer); + ASSERT_EQ(0, e1); + + AHardwareBuffer* hardware_buffer = nullptr; + int e2 = dvrBufferGetAHardwareBuffer(setup_buffer, &hardware_buffer); + ASSERT_EQ(0, e2); + ASSERT_NE(nullptr, hardware_buffer); + + void* buffer; + int e3 = AHardwareBuffer_lock(hardware_buffer, usage, -1, nullptr, &buffer); + ASSERT_EQ(0, e3); + ASSERT_NE(nullptr, buffer); + // Verify that the buffer pointer is at least 16 byte aligned. + ASSERT_EQ(0, reinterpret_cast<uintptr_t>(buffer) & (16 - 1)); + + uint64_t* data = static_cast<uint64_t*>(buffer); + constexpr size_t num_values = size / sizeof(uint64_t); + uint64_t zero = 0; + for (size_t i = 0; i < num_values; ++i) { + zero |= data[i]; + } + ASSERT_EQ(0, zero); + + int32_t fence = -1; + int e4 = AHardwareBuffer_unlock(hardware_buffer, &fence); + ASSERT_EQ(0, e4); + + dvrBufferDestroy(setup_buffer); + AHardwareBuffer_release(hardware_buffer); +} + +TEST_F(DvrGlobalBufferTest, TestVrflingerConfigBuffer) { + const DvrGlobalBufferKey buffer_name = kVrFlingerConfigBufferKey; + + // First delete any existing buffer so we can test the failure case. + dvrDisplayManagerDeleteGlobalBuffer(client_, buffer_name); + + const uint64_t usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | + AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY; + + size_t correct_size = DvrVrFlingerConfigRing::MemorySize(); + size_t wrong_size = DvrVrFlingerConfigRing::MemorySize(0); + + // Setup an invalid config buffer (too small) and assert that it fails. + DvrBuffer* setup_buffer = nullptr; + int e1 = dvrDisplayManagerSetupGlobalBuffer(client_, buffer_name, wrong_size, + usage, &setup_buffer); + ASSERT_EQ(nullptr, setup_buffer); + ASSERT_GT(0, e1); + + // Setup a correct config buffer. + int e2 = dvrDisplayManagerSetupGlobalBuffer( + client_, buffer_name, correct_size, usage, &setup_buffer); + ASSERT_NE(nullptr, setup_buffer); + ASSERT_EQ(0, e2); + + dvrBufferDestroy(setup_buffer); +} + } // namespace } // namespace dvr diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp index de26a74f48..080479a9c4 100644 --- a/libs/vr/libvrflinger/Android.bp +++ b/libs/vr/libvrflinger/Android.bp @@ -36,6 +36,7 @@ staticLibraries = [ "libvrsensor", "libpdx_default_transport", "libvr_manager", + "libbroadcastring", ] sharedLibraries = [ @@ -61,6 +62,10 @@ sharedLibraries = [ "libfmq", ] +headerLibraries = [ + "libdvr_headers" +] + cc_library_static { srcs: sourceFiles, export_include_dirs: includeFiles, @@ -74,5 +79,6 @@ cc_library_static { ], shared_libs: sharedLibraries, whole_static_libs: staticLibraries, + header_libs: headerLibraries, name: "libvrflinger", } diff --git a/libs/vr/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp index a0b3efea7e..c5b0d888de 100644 --- a/libs/vr/libvrflinger/display_manager_service.cpp +++ b/libs/vr/libvrflinger/display_manager_service.cpp @@ -1,5 +1,7 @@ #include "display_manager_service.h" +#include <android-base/file.h> +#include <android-base/properties.h> #include <pdx/channel_handle.h> #include <pdx/default_transport/service_endpoint.h> #include <private/android_filesystem_config.h> @@ -19,6 +21,14 @@ using android::pdx::rpc::DispatchRemoteMethod; using android::pdx::rpc::IfAnyOf; using android::pdx::rpc::RemoteMethodError; +namespace { + +const char kDvrLensMetricsProperty[] = "ro.dvr.lens_metrics"; +const char kDvrDeviceMetricsProperty[] = "ro.dvr.device_metrics"; +const char kDvrDeviceConfigProperty[] = "ro.dvr.device_configuration"; + +} // namespace + namespace android { namespace dvr { @@ -78,9 +88,19 @@ pdx::Status<void> DisplayManagerService::HandleMessage(pdx::Message& message) { *this, &DisplayManagerService::OnGetSurfaceQueue, message); return {}; - case DisplayManagerProtocol::SetupNamedBuffer::Opcode: - DispatchRemoteMethod<DisplayManagerProtocol::SetupNamedBuffer>( - *this, &DisplayManagerService::OnSetupNamedBuffer, message); + case DisplayManagerProtocol::SetupGlobalBuffer::Opcode: + DispatchRemoteMethod<DisplayManagerProtocol::SetupGlobalBuffer>( + *this, &DisplayManagerService::OnSetupGlobalBuffer, message); + return {}; + + case DisplayManagerProtocol::GetConfigurationData::Opcode: + DispatchRemoteMethod<DisplayManagerProtocol::GetConfigurationData>( + *this, &DisplayManagerService::OnGetConfigurationData, message); + return {}; + + case DisplayManagerProtocol::DeleteGlobalBuffer::Opcode: + DispatchRemoteMethod<DisplayManagerProtocol::DeleteGlobalBuffer>( + *this, &DisplayManagerService::OnDeleteGlobalBuffer, message); return {}; default: @@ -130,20 +150,62 @@ pdx::Status<pdx::LocalChannelHandle> DisplayManagerService::OnGetSurfaceQueue( } pdx::Status<BorrowedNativeBufferHandle> -DisplayManagerService::OnSetupNamedBuffer(pdx::Message& message, - const std::string& name, size_t size, - uint64_t usage) { +DisplayManagerService::OnSetupGlobalBuffer(pdx::Message& message, + DvrGlobalBufferKey key, size_t size, + uint64_t usage) { const int user_id = message.GetEffectiveUserId(); const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id); if (!trusted) { ALOGE( - "DisplayService::SetupNamedBuffer: Named buffers may only be created " + "DisplayService::SetupGlobalBuffer: Global buffers may only be created " "by trusted UIDs: user_id=%d", user_id); return ErrorStatus(EPERM); } - return display_service_->SetupNamedBuffer(name, size, usage); + return display_service_->SetupGlobalBuffer(key, size, usage); +} + +pdx::Status<void> DisplayManagerService::OnDeleteGlobalBuffer( + pdx::Message& message, DvrGlobalBufferKey key) { + const int user_id = message.GetEffectiveUserId(); + const bool trusted = (user_id == AID_ROOT) || IsTrustedUid(user_id); + + if (!trusted) { + ALOGE("DisplayService::DeleteGlobalBuffer: Untrusted user_id (%d)", + user_id); + return ErrorStatus(EPERM); + } + return display_service_->DeleteGlobalBuffer(key); +} + +pdx::Status<std::string> DisplayManagerService::OnGetConfigurationData( + pdx::Message& message, display::ConfigFileType config_type) { + std::string property_name; + switch (config_type) { + case display::ConfigFileType::kLensMetrics: + property_name = kDvrLensMetricsProperty; + break; + case display::ConfigFileType::kDeviceMetrics: + property_name = kDvrDeviceMetricsProperty; + break; + case display::ConfigFileType::kDeviceConfiguration: + property_name = kDvrDeviceConfigProperty; + break; + default: + return ErrorStatus(EINVAL); + } + std::string file_path = base::GetProperty(property_name, ""); + if (file_path.empty()) { + return ErrorStatus(ENOENT); + } + + std::string data; + if (!base::ReadFileToString(file_path, &data)) { + return ErrorStatus(errno); + } + + return std::move(data); } void DisplayManagerService::OnDisplaySurfaceChange() { diff --git a/libs/vr/libvrflinger/display_manager_service.h b/libs/vr/libvrflinger/display_manager_service.h index 0857eb5298..20c5507505 100644 --- a/libs/vr/libvrflinger/display_manager_service.h +++ b/libs/vr/libvrflinger/display_manager_service.h @@ -56,9 +56,13 @@ class DisplayManagerService : public pdx::ServiceBase<DisplayManagerService> { pdx::Status<pdx::LocalChannelHandle> OnGetSurfaceQueue(pdx::Message& message, int surface_id, int queue_id); - pdx::Status<BorrowedNativeBufferHandle> OnSetupNamedBuffer( - pdx::Message& message, const std::string& name, size_t size, + pdx::Status<BorrowedNativeBufferHandle> OnSetupGlobalBuffer( + pdx::Message& message, DvrGlobalBufferKey key, size_t size, uint64_t usage); + pdx::Status<void> OnDeleteGlobalBuffer(pdx::Message& message, + DvrGlobalBufferKey key); + pdx::Status<std::string> OnGetConfigurationData( + pdx::Message& message, display::ConfigFileType config_type); // Called by the display service to indicate changes to display surfaces that // the display manager should evaluate. diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp index 47efa7653d..b1808483de 100644 --- a/libs/vr/libvrflinger/display_service.cpp +++ b/libs/vr/libvrflinger/display_service.cpp @@ -65,9 +65,9 @@ Status<void> DisplayService::HandleMessage(pdx::Message& message) { *this, &DisplayService::OnCreateSurface, message); return {}; - case DisplayProtocol::GetNamedBuffer::Opcode: - DispatchRemoteMethod<DisplayProtocol::GetNamedBuffer>( - *this, &DisplayService::OnGetNamedBuffer, message); + case DisplayProtocol::GetGlobalBuffer::Opcode: + DispatchRemoteMethod<DisplayProtocol::GetGlobalBuffer>( + *this, &DisplayService::OnGetGlobalBuffer, message); return {}; case DisplayProtocol::IsVrAppRunning::Opcode: @@ -155,12 +155,12 @@ void DisplayService::SurfaceUpdated(SurfaceType surface_type, } } -pdx::Status<BorrowedNativeBufferHandle> DisplayService::OnGetNamedBuffer( - pdx::Message& /* message */, const std::string& name) { - ALOGD_IF(TRACE, "displayService::OnGetNamedBuffer: name=%s", name.c_str()); - auto named_buffer = named_buffers_.find(name); - if (named_buffer != named_buffers_.end()) - return {BorrowedNativeBufferHandle(*named_buffer->second, 0)}; +pdx::Status<BorrowedNativeBufferHandle> DisplayService::OnGetGlobalBuffer( + pdx::Message& /* message */, DvrGlobalBufferKey key) { + ALOGD_IF(TRACE, "DisplayService::OnGetGlobalBuffer: key=%d", key); + auto global_buffer = global_buffers_.find(key); + if (global_buffer != global_buffers_.end()) + return {BorrowedNativeBufferHandle(*global_buffer->second, 0)}; else return pdx::ErrorStatus(EINVAL); } @@ -221,18 +221,35 @@ void DisplayService::UpdateActiveDisplaySurfaces() { hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces)); } -pdx::Status<BorrowedNativeBufferHandle> DisplayService::SetupNamedBuffer( - const std::string& name, size_t size, uint64_t usage) { - auto named_buffer = named_buffers_.find(name); - if (named_buffer == named_buffers_.end()) { +pdx::Status<BorrowedNativeBufferHandle> DisplayService::SetupGlobalBuffer( + DvrGlobalBufferKey key, size_t size, uint64_t usage) { + auto global_buffer = global_buffers_.find(key); + if (global_buffer == global_buffers_.end()) { auto ion_buffer = std::make_unique<IonBuffer>(static_cast<int>(size), 1, HAL_PIXEL_FORMAT_BLOB, usage); - named_buffer = - named_buffers_.insert(std::make_pair(name, std::move(ion_buffer))) + + // Some buffers are used internally. If they were configured with an + // invalid size or format, this will fail. + int result = hardware_composer_.OnNewGlobalBuffer(key, *ion_buffer.get()); + if (result < 0) + return ErrorStatus(result); + global_buffer = + global_buffers_.insert(std::make_pair(key, std::move(ion_buffer))) .first; } - return {BorrowedNativeBufferHandle(*named_buffer->second, 0)}; + return {BorrowedNativeBufferHandle(*global_buffer->second, 0)}; +} + +pdx::Status<void> DisplayService::DeleteGlobalBuffer(DvrGlobalBufferKey key) { + auto global_buffer = global_buffers_.find(key); + if (global_buffer != global_buffers_.end()) { + // Some buffers are used internally. + hardware_composer_.OnDeletedGlobalBuffer(key); + global_buffers_.erase(global_buffer); + } + + return {0}; } void DisplayService::OnHardwareComposerRefresh() { diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h index bb4eeef1c6..8ba17289a2 100644 --- a/libs/vr/libvrflinger/display_service.h +++ b/libs/vr/libvrflinger/display_service.h @@ -1,6 +1,7 @@ #ifndef ANDROID_DVR_SERVICES_DISPLAYD_DISPLAY_SERVICE_H_ #define ANDROID_DVR_SERVICES_DISPLAYD_DISPLAY_SERVICE_H_ +#include <dvr/dvr_api.h> #include <pdx/service.h> #include <pdx/status.h> #include <private/dvr/buffer_hub_client.h> @@ -40,8 +41,10 @@ class DisplayService : public pdx::ServiceBase<DisplayService> { // any change to client/manager attributes that affect visibility or z order. void UpdateActiveDisplaySurfaces(); - pdx::Status<BorrowedNativeBufferHandle> SetupNamedBuffer( - const std::string& name, size_t size, uint64_t usage); + pdx::Status<BorrowedNativeBufferHandle> SetupGlobalBuffer( + DvrGlobalBufferKey key, size_t size, uint64_t usage); + + pdx::Status<void> DeleteGlobalBuffer(DvrGlobalBufferKey key); template <class A> void ForEachDisplaySurface(SurfaceType surface_type, A action) const { @@ -82,8 +85,8 @@ class DisplayService : public pdx::ServiceBase<DisplayService> { DisplayService(android::Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback); - pdx::Status<BorrowedNativeBufferHandle> OnGetNamedBuffer( - pdx::Message& message, const std::string& name); + pdx::Status<BorrowedNativeBufferHandle> OnGetGlobalBuffer( + pdx::Message& message, DvrGlobalBufferKey key); pdx::Status<display::Metrics> OnGetMetrics(pdx::Message& message); pdx::Status<display::SurfaceInfo> OnCreateSurface( pdx::Message& message, const display::SurfaceAttributes& attributes); @@ -113,7 +116,8 @@ class DisplayService : public pdx::ServiceBase<DisplayService> { EpollEventDispatcher dispatcher_; DisplayConfigurationUpdateNotifier update_notifier_; - std::unordered_map<std::string, std::unique_ptr<IonBuffer>> named_buffers_; + std::unordered_map<DvrGlobalBufferKey, std::unique_ptr<IonBuffer>> + global_buffers_; DisplayService(const DisplayService&) = delete; void operator=(const DisplayService&) = delete; diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp index 34474d969a..88173cac3e 100644 --- a/libs/vr/libvrflinger/hardware_composer.cpp +++ b/libs/vr/libvrflinger/hardware_composer.cpp @@ -19,6 +19,7 @@ #include <chrono> #include <functional> #include <map> +#include <tuple> #include <dvr/dvr_display_types.h> #include <dvr/performance_client_api.h> @@ -37,17 +38,6 @@ namespace dvr { namespace { -// If the number of pending fences goes over this count at the point when we -// are about to submit a new frame to HWC, we will drop the frame. This should -// be a signal that the display driver has begun queuing frames. Note that with -// smart displays (with RAM), the fence is signaled earlier than the next vsync, -// at the point when the DMA to the display completes. Currently we use a smart -// display and the EDS timing coincides with zero pending fences, so this is 0. -constexpr int kAllowedPendingFenceCount = 0; - -// Offset before vsync to submit frames to hardware composer. -constexpr int64_t kFramePostOffsetNs = 4000000; // 4ms - const char kBacklightBrightnessSysFile[] = "/sys/class/leds/lcd-backlight/brightness"; @@ -397,8 +387,8 @@ void HardwareComposer::PostLayers() { } const bool is_frame_pending = IsFramePendingInDriver(); - const bool is_fence_pending = - retire_fence_fds_.size() > kAllowedPendingFenceCount; + const bool is_fence_pending = retire_fence_fds_.size() > + post_thread_config_.allowed_pending_fence_count; if (is_fence_pending || is_frame_pending) { ATRACE_INT("frame_skip_count", ++frame_skip_count_); @@ -475,6 +465,62 @@ void HardwareComposer::SetDisplaySurfaces( request_display_callback_(!display_idle); } +int HardwareComposer::OnNewGlobalBuffer(DvrGlobalBufferKey key, + IonBuffer& ion_buffer) { + if (key == kVrFlingerConfigBufferKey) { + return MapConfigBuffer(ion_buffer); + } + + return 0; +} + +void HardwareComposer::OnDeletedGlobalBuffer(DvrGlobalBufferKey key) { + if (key == kVrFlingerConfigBufferKey) { + ConfigBufferDeleted(); + } +} + +int HardwareComposer::MapConfigBuffer(IonBuffer& ion_buffer) { + std::lock_guard<std::mutex> lock(shared_config_mutex_); + shared_config_ring_ = DvrVrFlingerConfigRing(); + + if (ion_buffer.width() < DvrVrFlingerConfigRing::MemorySize()) { + ALOGE("HardwareComposer::MapConfigBuffer: invalid buffer size."); + return -EINVAL; + } + + void* buffer_base = 0; + int result = ion_buffer.Lock(ion_buffer.usage(), 0, 0, ion_buffer.width(), + ion_buffer.height(), &buffer_base); + if (result != 0) { + ALOGE("HardwareComposer::MapConfigBuffer: Failed to map vrflinger config " + "buffer."); + return -EPERM; + } + + shared_config_ring_ = + DvrVrFlingerConfigRing::Create(buffer_base, ion_buffer.width()); + ion_buffer.Unlock(); + + return 0; +} + +void HardwareComposer::ConfigBufferDeleted() { + std::lock_guard<std::mutex> lock(shared_config_mutex_); + shared_config_ring_ = DvrVrFlingerConfigRing(); +} + +void HardwareComposer::UpdateConfigBuffer() { + std::lock_guard<std::mutex> lock(shared_config_mutex_); + if (!shared_config_ring_.is_valid()) + return; + // Copy from latest record in shared_config_ring_ to local copy. + DvrVrFlingerConfigBuffer record; + if (shared_config_ring_.GetNewest(&shared_config_ring_sequence_, &record)) { + post_thread_config_ = record; + } +} + int HardwareComposer::PostThreadPollInterruptible( const pdx::LocalHandle& event_fd, int requested_events) { pollfd pfd[2] = { @@ -744,6 +790,9 @@ void HardwareComposer::PostThread() { while (1) { ATRACE_NAME("HardwareComposer::PostThread"); + // Check for updated config once per vsync. + UpdateConfigBuffer(); + while (post_thread_quiescent_) { std::unique_lock<std::mutex> lock(post_thread_mutex_); ALOGI("HardwareComposer::PostThread: Entering quiescent state."); @@ -823,9 +872,10 @@ void HardwareComposer::PostThread() { const int64_t display_time_est_ns = vsync_timestamp + ns_per_frame; const int64_t now_ns = GetSystemClockNs(); - const int64_t sleep_time_ns = - display_time_est_ns - now_ns - kFramePostOffsetNs; - const int64_t wakeup_time_ns = display_time_est_ns - kFramePostOffsetNs; + const int64_t sleep_time_ns = display_time_est_ns - now_ns - + post_thread_config_.frame_post_offset_ns; + const int64_t wakeup_time_ns = + display_time_est_ns - post_thread_config_.frame_post_offset_ns; ATRACE_INT64("sleep_time_ns", sleep_time_ns); if (sleep_time_ns > 0) { diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h index 8ba72ab773..c182bf9290 100644 --- a/libs/vr/libvrflinger/hardware_composer.h +++ b/libs/vr/libvrflinger/hardware_composer.h @@ -16,6 +16,7 @@ #include <tuple> #include <vector> +#include <dvr/dvr_vrflinger_config_buffer.h> #include <dvr/pose_client.h> #include <pdx/file_handle.h> #include <pdx/rpc/variant.h> @@ -284,6 +285,9 @@ class HardwareComposer { void SetDisplaySurfaces( std::vector<std::shared_ptr<DirectDisplaySurface>> surfaces); + int OnNewGlobalBuffer(DvrGlobalBufferKey key, IonBuffer& ion_buffer); + void OnDeletedGlobalBuffer(DvrGlobalBufferKey key); + void OnHardwareComposerRefresh(); private: @@ -365,6 +369,13 @@ class HardwareComposer { // Called on the post thread when the post thread is paused or quits. void OnPostThreadPaused(); + // Map the given shared memory buffer to our broadcast ring to track updates + // to the config parameters. + int MapConfigBuffer(IonBuffer& ion_buffer); + void ConfigBufferDeleted(); + // Poll for config udpates. + void UpdateConfigBuffer(); + bool initialized_; // Hardware composer HAL device from SurfaceFlinger. VrFlinger does not own @@ -439,6 +450,13 @@ class HardwareComposer { // out to display frame boundaries, so we need to tell it about vsyncs. DvrPose* pose_client_ = nullptr; + // Broadcast ring for receiving config data from the DisplayManager. + DvrVrFlingerConfigRing shared_config_ring_; + uint32_t shared_config_ring_sequence_{0}; + // Config buffer for reading from the post thread. + DvrVrFlingerConfigBuffer post_thread_config_; + std::mutex shared_config_mutex_; + static constexpr int kPostThreadInterrupted = 1; static void HwcRefresh(hwc2_callback_data_t data, hwc2_display_t display); diff --git a/libs/vr/libvrsensor/include/dvr/pose_client.h b/libs/vr/libvrsensor/include/dvr/pose_client.h index ed75f84216..6802fa9a51 100644 --- a/libs/vr/libvrsensor/include/dvr/pose_client.h +++ b/libs/vr/libvrsensor/include/dvr/pose_client.h @@ -105,6 +105,8 @@ typedef enum DvrPoseMode { DVR_POSE_MODE_MOCK_ROTATE_MEDIUM, DVR_POSE_MODE_MOCK_ROTATE_FAST, DVR_POSE_MODE_MOCK_CIRCLE_STRAFE, + DVR_POSE_MODE_FLOAT, + DVR_POSE_MODE_MOCK_MOTION_SICKNESS, // Always last. DVR_POSE_MODE_COUNT, diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h index d0996f03f6..7de8c62e2f 100644 --- a/opengl/include/EGL/eglext.h +++ b/opengl/include/EGL/eglext.h @@ -625,6 +625,11 @@ typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETNATIVECLIENTBUFFERANDROID) (const #define EGL_MUTABLE_RENDER_BUFFER_BIT_KHR 0x1000 #endif +#ifndef EGL_KHR_no_config_context +#define EGL_KHR_no_config_context 1 +#define EGL_NO_CONFIG_KHR EGL_CAST(EGLConfig,0) +#endif /* EGL_KHR_no_config_context */ + #ifndef EGL_ANDROID_get_frame_timestamps #define EGL_ANDROID_get_frame_timestamps 1 #define EGL_TIMESTAMPS_ANDROID 0x3430 @@ -667,6 +672,16 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETFRAMETIMESTAMPSUPPORTEDANDROID) (EGLDi #define EGL_GL_COLORSPACE_BT2020_PQ_EXT 0x3340 #endif /* EGL_EXT_gl_colorspace_bt2020_pq */ +#ifndef EGL_EXT_gl_colorspace_display_p3 +#define EGL_EXT_gl_colorspace_display_p3 1 +#define EGL_GL_COLORSPACE_DISPLAY_P3_EXT 0x3363 +#endif /* EGL_EXT_gl_colorspace_display_p3 */ + +#ifndef EGL_EXT_gl_colorspace_display_p3_linear +#define EGL_EXT_gl_colorspace_display_p3_linear 1 +#define EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT 0x3362 +#endif /* EGL_EXT_gl_colorspace_display_p3_linear */ + #ifndef EGL_EXT_gl_colorspace_scrgb_linear #define EGL_EXT_gl_colorspace_scrgb_linear 1 #define EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT 0x3350 diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk index 4b08749b22..c7635e27c7 100644 --- a/opengl/libagl/Android.mk +++ b/opengl/libagl/Android.mk @@ -26,7 +26,7 @@ LOCAL_CFLAGS += -DLOG_TAG=\"libagl\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES LOCAL_CFLAGS += -fvisibility=hidden -LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils liblog libpixelflinger libETC1 libui +LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils liblog libpixelflinger libETC1 libui libnativewindow LOCAL_SRC_FILES_arm += fixed_asm.S iterators.S LOCAL_CFLAGS_arm += -fstrict-aliasing diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp index 04f6d6d1a3..b79051c499 100644 --- a/opengl/libagl/egl.cpp +++ b/opengl/libagl/egl.cpp @@ -56,6 +56,24 @@ EGLBoolean EGLAPI eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height); + +typedef struct egl_native_pixmap_t +{ + int32_t version; /* must be 32 */ + int32_t width; + int32_t height; + int32_t stride; + uint8_t* data; + uint8_t format; + uint8_t rfu[3]; + union { + uint32_t compressedFormat; + int32_t vstride; + }; + int32_t reserved; +} egl_native_pixmap_t; + + // ---------------------------------------------------------------------------- namespace android { diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index a895e63671..bff80cddd8 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -81,7 +81,7 @@ cc_defaults { shared_libs: [ // ***** DO NOT ADD NEW DEPENDENCIES HERE ***** // In particular, DO NOT add libutils nor anything "above" libui - "libui", + "libgraphicsenv", "libnativewindow", "libbacktrace", ], diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 7d20ba1fa8..1116400110 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -28,7 +28,7 @@ #include <cutils/properties.h> #include <log/log.h> -#include <ui/GraphicsEnv.h> +#include <graphicsenv/GraphicsEnv.h> #include "egl_trace.h" #include "egldefs.h" diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index 10f4e6613a..6bff38ac3d 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -79,6 +79,7 @@ struct extention_map_t { extern char const * const gBuiltinExtensionString; extern char const * const gExtensionString; +// clang-format off char const * const gBuiltinExtensionString = "EGL_KHR_get_all_proc_addresses " "EGL_ANDROID_presentation_time " @@ -86,6 +87,9 @@ char const * const gBuiltinExtensionString = "EGL_ANDROID_get_native_client_buffer " "EGL_ANDROID_front_buffer_auto_refresh " "EGL_ANDROID_get_frame_timestamps " + "EGL_EXT_gl_colorspace_scrgb_linear " + "EGL_EXT_gl_colorspace_display_p3_linear " + "EGL_EXT_gl_colorspace_display_p3 " ; char const * const gExtensionString = @@ -123,6 +127,7 @@ char const * const gExtensionString = "EGL_IMG_context_priority " "EGL_KHR_no_config_context " ; +// clang-format on // extensions not exposed to applications but used by the ANDROID system // "EGL_ANDROID_blob_cache " // strongly recommended @@ -458,10 +463,57 @@ static android_dataspace modifyBufferDataspace( android_dataspace dataSpace, return HAL_DATASPACE_SRGB_LINEAR; } else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) { return HAL_DATASPACE_SRGB; + } else if (colorspace == EGL_GL_COLORSPACE_DISPLAY_P3_EXT) { + return HAL_DATASPACE_DISPLAY_P3; + } else if (colorspace == EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT) { + return HAL_DATASPACE_DISPLAY_P3_LINEAR; + } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT) { + return HAL_DATASPACE_V0_SCRGB_LINEAR; } return dataSpace; } +static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, const EGLint* attrib_list, + EGLint& colorSpace, android_dataspace& dataSpace) { + colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR; + dataSpace = HAL_DATASPACE_UNKNOWN; + if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) { + for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) { + if (*attr == EGL_GL_COLORSPACE_KHR) { + colorSpace = attr[1]; + bool found = false; + // Verify that color space is allowed + if (colorSpace == EGL_GL_COLORSPACE_SRGB_KHR || + colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR) { + found = true; + } else if (colorSpace == EGL_EXT_gl_colorspace_bt2020_linear && + dp->haveExtension("EGL_EXT_gl_colorspace_bt2020_linear")) { + found = true; + } else if (colorSpace == EGL_EXT_gl_colorspace_bt2020_pq && + dp->haveExtension("EGL_EXT_gl_colorspace_bt2020_pq")) { + found = true; + } else if (colorSpace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT && + dp->haveExtension("EGL_EXT_gl_colorspace_scrgb_linear")) { + found = true; + } else if (colorSpace == EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT && + dp->haveExtension("EGL_EXT_gl_colorspace_display_p3_linear")) { + found = true; + } else if (colorSpace == EGL_GL_COLORSPACE_DISPLAY_P3_EXT && + dp->haveExtension("EGL_EXT_gl_colorspace_display_p3")) { + found = true; + } + if (!found) { + return false; + } + // Only change the dataSpace from default if the application + // has explicitly set the color space with a EGL_GL_COLORSPACE_KHR attribute. + dataSpace = modifyBufferDataspace(dataSpace, colorSpace); + } + } + } + return true; +} + EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list) @@ -502,7 +554,8 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, &componentType); EGLint format; - android_dataspace dataSpace = HAL_DATASPACE_UNKNOWN; + EGLint colorSpace; + android_dataspace dataSpace; EGLint a = 0; EGLint r, g, b; r = g = b = 0; @@ -539,12 +592,9 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, } // now select a corresponding sRGB format if needed - if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) { - for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) { - if (*attr == EGL_GL_COLORSPACE_KHR) { - dataSpace = modifyBufferDataspace(dataSpace, *(attr+1)); - } - } + if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) { + ALOGE("error invalid colorspace: %d", colorSpace); + return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); } if (format != 0) { @@ -575,8 +625,8 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, EGLSurface surface = cnx->egl.eglCreateWindowSurface( iDpy, config, window, attrib_list); if (surface != EGL_NO_SURFACE) { - egl_surface_t* s = new egl_surface_t(dp.get(), config, window, - surface, cnx); + egl_surface_t* s = + new egl_surface_t(dp.get(), config, window, surface, colorSpace, cnx); return s; } @@ -595,12 +645,19 @@ EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, egl_connection_t* cnx = NULL; egl_display_ptr dp = validate_display_connection(dpy, cnx); + EGLint colorSpace; + android_dataspace dataSpace; if (dp) { + // now select a corresponding sRGB format if needed + if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) { + ALOGE("error invalid colorspace: %d", colorSpace); + return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + EGLSurface surface = cnx->egl.eglCreatePixmapSurface( dp->disp.dpy, config, pixmap, attrib_list); if (surface != EGL_NO_SURFACE) { - egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, - surface, cnx); + egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, colorSpace, cnx); return s; } } @@ -614,12 +671,19 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, egl_connection_t* cnx = NULL; egl_display_ptr dp = validate_display_connection(dpy, cnx); + EGLint colorSpace; + android_dataspace dataSpace; if (dp) { + // now select a corresponding sRGB format if needed + if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) { + ALOGE("error invalid colorspace: %d", colorSpace); + return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + EGLSurface surface = cnx->egl.eglCreatePbufferSurface( dp->disp.dpy, config, attrib_list); if (surface != EGL_NO_SURFACE) { - egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, - surface, cnx); + egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, colorSpace, cnx); return s; } } @@ -658,6 +722,10 @@ EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface, return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); egl_surface_t const * const s = get_surface(surface); + if (attribute == EGL_GL_COLORSPACE_KHR) { + *value = s->getColorSpace(); + return EGL_TRUE; + } return s->cnx->egl.eglQuerySurface( dp->disp.dpy, s->surface, attribute, value); } @@ -1733,13 +1801,22 @@ EGLSurface eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config, egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_SURFACE; + EGLint colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR; + android_dataspace dataSpace = HAL_DATASPACE_UNKNOWN; + // TODO: Probably need to update EGL_KHR_stream_producer_eglsurface to + // indicate support for EGL_GL_COLORSPACE_KHR. + // now select a corresponding sRGB format if needed + if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) { + ALOGE("error invalid colorspace: %d", colorSpace); + return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglCreateStreamProducerSurfaceKHR) { EGLSurface surface = cnx->egl.eglCreateStreamProducerSurfaceKHR( dp->disp.dpy, config, stream, attrib_list); if (surface != EGL_NO_SURFACE) { - egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, - surface, cnx); + egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, colorSpace, cnx); return s; } } diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp index 623878062b..837cfa92ca 100644 --- a/opengl/libs/EGL/egl_object.cpp +++ b/opengl/libs/EGL/egl_object.cpp @@ -55,12 +55,15 @@ bool egl_object_t::get(egl_display_t const* display, egl_object_t* object) { // ---------------------------------------------------------------------------- -egl_surface_t::egl_surface_t(egl_display_t* dpy, EGLConfig config, - EGLNativeWindowType win, EGLSurface surface, - egl_connection_t const* cnx) : - egl_object_t(dpy), surface(surface), config(config), win(win), cnx(cnx), - connected(true) -{ +egl_surface_t::egl_surface_t(egl_display_t* dpy, EGLConfig config, EGLNativeWindowType win, + EGLSurface surface, EGLint colorSpace, egl_connection_t const* cnx) + : egl_object_t(dpy), + surface(surface), + config(config), + win(win), + cnx(cnx), + connected(true), + colorSpace(colorSpace) { if (win) { win->incStrong(this); } diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h index 8988905a25..7c3075c9fc 100644 --- a/opengl/libs/EGL/egl_object.h +++ b/opengl/libs/EGL/egl_object.h @@ -131,12 +131,12 @@ protected: public: typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref; - egl_surface_t(egl_display_t* dpy, EGLConfig config, - EGLNativeWindowType win, EGLSurface surface, - egl_connection_t const* cnx); + egl_surface_t(egl_display_t* dpy, EGLConfig config, EGLNativeWindowType win, EGLSurface surface, + EGLint colorSpace, egl_connection_t const* cnx); ANativeWindow* getNativeWindow() { return win; } ANativeWindow* getNativeWindow() const { return win; } + EGLint getColorSpace() const { return colorSpace; } // Try to keep the order of these fields and size unchanged. It's not public API, but // it's not hard to imagine native games accessing them. @@ -149,6 +149,7 @@ public: private: bool connected; void disconnect(); + EGLint colorSpace; }; class egl_context_t: public egl_object_t { diff --git a/opengl/tests/Android.bp b/opengl/tests/Android.bp new file mode 100644 index 0000000000..bf7aeb117f --- /dev/null +++ b/opengl/tests/Android.bp @@ -0,0 +1,4 @@ +subdirs = [ + "hwc", + "lib", +] diff --git a/opengl/tests/Android.mk b/opengl/tests/Android.mk index 3ae3b4eaef..92d223cc7e 100644 --- a/opengl/tests/Android.mk +++ b/opengl/tests/Android.mk @@ -12,7 +12,6 @@ dirs := \ gl_perf \ gl_yuvtex \ gralloc \ - hwc \ include \ lib \ linetex \ diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp index 24b131539a..62e6bd3055 100644 --- a/opengl/tests/EGLTest/EGL_test.cpp +++ b/opengl/tests/EGLTest/EGL_test.cpp @@ -28,18 +28,17 @@ #include <gui/IGraphicBufferConsumer.h> #include <gui/BufferQueue.h> -#define PIXEL_FORMAT_FLOAT "EGL_EXT_pixel_format_float" - -bool hasEglPixelFormatFloat() { - EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); +bool hasEglExtension(EGLDisplay dpy, const char* extensionName) { const char* exts = eglQueryString(dpy, EGL_EXTENSIONS); - size_t cropExtLen = strlen(PIXEL_FORMAT_FLOAT); + size_t cropExtLen = strlen(extensionName); size_t extsLen = strlen(exts); - bool equal = !strcmp(PIXEL_FORMAT_FLOAT, exts); - bool atStart = !strncmp(PIXEL_FORMAT_FLOAT " ", exts, cropExtLen + 1); + bool equal = !strcmp(extensionName, exts); + android::String8 extString(extensionName); + android::String8 space(" "); + bool atStart = !strncmp(extString + space, exts, cropExtLen + 1); bool atEnd = (cropExtLen + 1) < extsLen && - !strcmp(" " PIXEL_FORMAT_FLOAT, exts + extsLen - (cropExtLen + 1)); - bool inMiddle = strstr(exts, " " PIXEL_FORMAT_FLOAT " "); + !strcmp(space + extString, exts + extsLen - (cropExtLen + 1)); + bool inMiddle = strstr(exts, space + extString + space); return equal || atStart || atEnd || inMiddle; } @@ -194,6 +193,176 @@ TEST_F(EGLTest, EGLConfigRGBA8888First) { EXPECT_GE(components[3], 8); } +TEST_F(EGLTest, EGLDisplayP3) { + EGLint numConfigs; + EGLConfig config; + EGLBoolean success; + + if (!hasWideColorDisplay) { + // skip this test if device does not have wide-color display + return; + } + + // Test that display-p3 extensions exist + ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3")); + ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3_linear")); + + // Use 8-bit to keep forcus on Display-P3 aspect + EGLint attrs[] = { + // clang-format off + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FIXED_EXT, + EGL_NONE, EGL_NONE + // clang-format on + }; + success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(1, numConfigs); + + EGLint components[4]; + EGLint value; + eglGetConfigAttrib(mEglDisplay, config, EGL_CONFIG_ID, &value); + + success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + + EXPECT_EQ(components[0], 8); + EXPECT_EQ(components[1], 8); + EXPECT_EQ(components[2], 8); + EXPECT_EQ(components[3], 8); + + struct DummyConsumer : public BnConsumerListener { + void onFrameAvailable(const BufferItem& /* item */) override {} + void onBuffersReleased() override {} + void onSidebandStreamChanged() override {} + }; + + // Create a EGLSurface + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + consumer->consumerConnect(new DummyConsumer, false); + sp<Surface> mSTC = new Surface(producer); + sp<ANativeWindow> mANW = mSTC; + EGLint winAttrs[] = { + // clang-format off + EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_EXT, + EGL_NONE, EGL_NONE + // clang-format on + }; + + EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + ASSERT_NE(EGL_NO_SURFACE, eglSurface); + + success = eglQuerySurface(mEglDisplay, eglSurface, EGL_GL_COLORSPACE_KHR, &value); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_GL_COLORSPACE_DISPLAY_P3_EXT, value); + + EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface)); +} + +TEST_F(EGLTest, EGLDisplayP31010102) { + EGLint numConfigs; + EGLConfig config; + EGLBoolean success; + + if (!hasWideColorDisplay) { + // skip this test if device does not have wide-color display + return; + } + + // Test that display-p3 extensions exist + ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3")); + ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3_linear")); + + // Use 8-bit to keep forcus on Display-P3 aspect + EGLint attrs[] = { + // clang-format off + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, + EGL_RED_SIZE, 10, + EGL_GREEN_SIZE, 10, + EGL_BLUE_SIZE, 10, + EGL_ALPHA_SIZE, 2, + EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FIXED_EXT, + EGL_NONE, EGL_NONE + // clang-format on + }; + success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(1, numConfigs); + + EGLint components[4]; + EGLint value; + eglGetConfigAttrib(mEglDisplay, config, EGL_CONFIG_ID, &value); + + success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + + EXPECT_EQ(components[0], 10); + EXPECT_EQ(components[1], 10); + EXPECT_EQ(components[2], 10); + EXPECT_EQ(components[3], 2); + + struct DummyConsumer : public BnConsumerListener { + void onFrameAvailable(const BufferItem& /* item */) override {} + void onBuffersReleased() override {} + void onSidebandStreamChanged() override {} + }; + + // Create a EGLSurface + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + consumer->consumerConnect(new DummyConsumer, false); + sp<Surface> mSTC = new Surface(producer); + sp<ANativeWindow> mANW = mSTC; + EGLint winAttrs[] = { + // clang-format off + EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_EXT, + EGL_NONE, EGL_NONE + // clang-format on + }; + + EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + ASSERT_NE(EGL_NO_SURFACE, eglSurface); + + success = eglQuerySurface(mEglDisplay, eglSurface, EGL_GL_COLORSPACE_KHR, &value); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_GL_COLORSPACE_DISPLAY_P3_EXT, value); + + EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface)); +} + TEST_F(EGLTest, EGLConfigFP16) { EGLint numConfigs; EGLConfig config; @@ -204,23 +373,20 @@ TEST_F(EGLTest, EGLConfigFP16) { return; } - ASSERT_TRUE(hasEglPixelFormatFloat()); - - EGLint attrs[] = {EGL_SURFACE_TYPE, - EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, - EGL_OPENGL_ES2_BIT, - EGL_RED_SIZE, - 16, - EGL_GREEN_SIZE, - 16, - EGL_BLUE_SIZE, - 16, - EGL_ALPHA_SIZE, - 16, - EGL_COLOR_COMPONENT_TYPE_EXT, - EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT, - EGL_NONE}; + ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_pixel_format_float")); + + EGLint attrs[] = { + // clang-format off + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, 16, + EGL_GREEN_SIZE, 16, + EGL_BLUE_SIZE, 16, + EGL_ALPHA_SIZE, 16, + EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT, + EGL_NONE, EGL_NONE + // clang-format on + }; success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs); ASSERT_EQ(EGL_UNSIGNED_TRUE, success); ASSERT_EQ(1, numConfigs); @@ -251,6 +417,108 @@ TEST_F(EGLTest, EGLConfigFP16) { void onSidebandStreamChanged() override {} }; + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + consumer->consumerConnect(new DummyConsumer, false); + sp<Surface> mSTC = new Surface(producer); + sp<ANativeWindow> mANW = mSTC; + + EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), NULL); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + ASSERT_NE(EGL_NO_SURFACE, eglSurface); + + EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface)); +} + +TEST_F(EGLTest, EGL_KHR_no_config_context) { + if (!hasWideColorDisplay) { + // skip this test if device does not have wide-color display + return; + } + + ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_KHR_no_config_context")); + + struct DummyConsumer : public BnConsumerListener { + void onFrameAvailable(const BufferItem& /* item */) override {} + void onBuffersReleased() override {} + void onSidebandStreamChanged() override {} + }; + + std::vector<EGLint> contextAttributes; + contextAttributes.reserve(4); + contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION); + contextAttributes.push_back(2); + contextAttributes.push_back(EGL_NONE); + contextAttributes.push_back(EGL_NONE); + + EGLContext eglContext = eglCreateContext(mEglDisplay, EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT, + contextAttributes.data()); + EXPECT_NE(EGL_NO_CONTEXT, eglContext); + EXPECT_EQ(EGL_SUCCESS, eglGetError()); + + if (eglContext != EGL_NO_CONTEXT) { + eglDestroyContext(mEglDisplay, eglContext); + } +} + +// Emulate what a native application would do to create a +// 10:10:10:2 surface. +TEST_F(EGLTest, EGLConfig1010102) { + EGLint numConfigs; + EGLConfig config; + EGLBoolean success; + + if (!hasWideColorDisplay) { + // skip this test if device does not have wide-color display + return; + } + + EGLint attrs[] = { + // clang-format off + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, + EGL_RED_SIZE, 10, + EGL_GREEN_SIZE, 10, + EGL_BLUE_SIZE, 10, + EGL_ALPHA_SIZE, 2, + EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FIXED_EXT, + EGL_NONE, EGL_NONE + // clang-format on + }; + success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(1, numConfigs); + + EGLint components[4]; + EGLint value; + eglGetConfigAttrib(mEglDisplay, config, EGL_CONFIG_ID, &value); + + success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + + EXPECT_EQ(components[0], 10); + EXPECT_EQ(components[1], 10); + EXPECT_EQ(components[2], 10); + EXPECT_EQ(components[3], 2); + + struct DummyConsumer : public BnConsumerListener { + void onFrameAvailable(const BufferItem& /* item */) override {} + void onBuffersReleased() override {} + void onSidebandStreamChanged() override {} + }; + // Create a EGLSurface sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; diff --git a/opengl/tests/configdump/configdump.cpp b/opengl/tests/configdump/configdump.cpp index 2a945982a9..c423105a11 100644 --- a/opengl/tests/configdump/configdump.cpp +++ b/opengl/tests/configdump/configdump.cpp @@ -66,8 +66,7 @@ Attribute attributes[] = { }; // clang-format on -int main(int argc, char** argv) -{ +int main(int /*argc*/, char** /*argv*/) { EGLConfig* configs; EGLint n; diff --git a/opengl/tests/gl2_basic/gl2_basic.cpp b/opengl/tests/gl2_basic/gl2_basic.cpp index 9f8d166c7a..ee88667328 100644 --- a/opengl/tests/gl2_basic/gl2_basic.cpp +++ b/opengl/tests/gl2_basic/gl2_basic.cpp @@ -30,6 +30,7 @@ #include <EGLUtils.h> using namespace android; +EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); static void printGLString(const char *name, GLenum s) { // fprintf(stderr, "printGLString %s, %d\n", name, s); @@ -46,7 +47,8 @@ static void printGLString(const char *name, GLenum s) { static void printEGLString(EGLDisplay dpy, const char *name, GLenum s) { const char *v = (const char *) eglQueryString(dpy, s); - fprintf(stderr, "GL %s = %s\n", name, v); + const char* va = (const char*)eglQueryStringImplementationANDROID(dpy, s); + fprintf(stderr, "GL %s = %s\nImplementationANDROID: %s\n", name, v, va); } static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { @@ -263,7 +265,7 @@ int printEGLConfigurations(EGLDisplay dpy) { return true; } -int main(int argc, char** argv) { +int main(int /*argc*/, char** /*argv*/) { EGLBoolean returnValue; EGLConfig myConfig = {0}; diff --git a/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp b/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp index 98d8aa8cbc..22128ab5ea 100644 --- a/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp +++ b/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp @@ -331,7 +331,7 @@ void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { printf("\n"); } -int main(int argc, char** argv) { +int main(int /*argc*/, char** /*argv*/) { EGLBoolean returnValue; EGLConfig myConfig = {0}; diff --git a/opengl/tests/gl_yuvtex/gl_yuvtex.cpp b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp index c923b07362..fad26a69c7 100644 --- a/opengl/tests/gl_yuvtex/gl_yuvtex.cpp +++ b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp @@ -221,7 +221,7 @@ void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { printf("\n"); } -int main(int argc, char** argv) { +int main(int /*argc*/, char** /*argv*/) { EGLBoolean returnValue; EGLConfig myConfig = {0}; diff --git a/opengl/tests/hwc/Android.bp b/opengl/tests/hwc/Android.bp new file mode 100644 index 0000000000..425f3740e4 --- /dev/null +++ b/opengl/tests/hwc/Android.bp @@ -0,0 +1,107 @@ +// 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. + +cc_defaults { + + name: "hwc_tests_defaults", + cflags: [ + "-DGL_GLEXT_PROTOTYPES", + "-DEGL_EGLEXT_PROTOTYPES", + "-Wall", + "-Wextra", + "-Werror", + ], +} + +cc_library_static { + + name: "libhwcTest", + srcs: ["hwcTestLib.cpp"], + + static_libs: [ + "libarect", + "libglTest", + "libtestUtil", + ], + shared_libs: [ + "libui", + "libnativewindow" + ], + defaults: ["hwc_tests_defaults"], +} + +cc_defaults { + + name: "hwc_lib_defaults", + shared_libs: [ + "libcutils", + "libEGL", + "libGLESv2", + "libhardware", + "liblog", + "libui", + "libutils", + "libnativewindow" + ], + + static_libs: [ + "libglTest", + "libhwcTest", + "libtestUtil", + ], +} + +cc_test { + + name: "hwcStress", + srcs: ["hwcStress.cpp"], + + defaults: [ + "hwc_lib_defaults", + "hwc_tests_defaults", + ], +} + +cc_test { + + name: "hwcRects", + srcs: ["hwcRects.cpp"], + + defaults: [ + "hwc_lib_defaults", + "hwc_tests_defaults", + ], +} + +cc_test { + + name: "hwcColorEquiv", + srcs: ["hwcColorEquiv.cpp"], + + defaults: [ + "hwc_lib_defaults", + "hwc_tests_defaults", + ], +} + +cc_test { + + name: "hwcCommit", + srcs: ["hwcCommit.cpp"], + + defaults: [ + "hwc_lib_defaults", + "hwc_tests_defaults", + ], +} diff --git a/opengl/tests/hwc/Android.mk b/opengl/tests/hwc/Android.mk deleted file mode 100644 index 13337c2753..0000000000 --- a/opengl/tests/hwc/Android.mk +++ /dev/null @@ -1,150 +0,0 @@ -# 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. - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - -LOCAL_MODULE_TAGS := tests -LOCAL_MODULE:= libhwcTest -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror -LOCAL_CXX_STL := libc++ -LOCAL_SRC_FILES:= hwcTestLib.cpp -LOCAL_C_INCLUDES += system/extras/tests/include \ - $(call include-path-for, opengl-tests-includes) \ - -LOCAL_STATIC_LIBRARIES := libarect - -include $(BUILD_STATIC_LIBRARY) - -include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - -LOCAL_MODULE:= hwcStress -LOCAL_MODULE_TAGS := tests -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror -LOCAL_CXX_STL := libc++ -LOCAL_SRC_FILES:= hwcStress.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libEGL \ - libGLESv2 \ - libutils \ - liblog \ - libui \ - libhardware \ - -LOCAL_STATIC_LIBRARIES := \ - libtestUtil \ - libglTest \ - libhwcTest \ - -LOCAL_C_INCLUDES += \ - system/extras/tests/include \ - hardware/libhardware/include \ - $(call include-path-for, opengl-tests-includes) \ - -include $(BUILD_NATIVE_TEST) - -include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - -LOCAL_MODULE:= hwcRects -LOCAL_MODULE_TAGS := tests -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror -LOCAL_CXX_STL := libc++ -LOCAL_SRC_FILES:= hwcRects.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libEGL \ - libGLESv2 \ - libutils \ - liblog \ - libui \ - libhardware \ - -LOCAL_STATIC_LIBRARIES := \ - libtestUtil \ - libglTest \ - libhwcTest \ - -LOCAL_C_INCLUDES += \ - system/extras/tests/include \ - hardware/libhardware/include \ - $(call include-path-for, opengl-tests-includes) \ - -include $(BUILD_NATIVE_TEST) - -include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - -LOCAL_MODULE:= hwcColorEquiv -LOCAL_MODULE_TAGS := tests -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror -LOCAL_CXX_STL := libc++ -LOCAL_SRC_FILES:= hwcColorEquiv.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libEGL \ - libGLESv2 \ - libutils \ - liblog \ - libui \ - libhardware \ - -LOCAL_STATIC_LIBRARIES := \ - libtestUtil \ - libglTest \ - libhwcTest \ - -LOCAL_C_INCLUDES += \ - system/extras/tests/include \ - hardware/libhardware/include \ - $(call include-path-for, opengl-tests-includes) \ - -include $(BUILD_NATIVE_TEST) - -include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk - -LOCAL_MODULE:= hwcCommit -LOCAL_MODULE_TAGS := tests -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror -LOCAL_CXX_STL := libc++ -LOCAL_SRC_FILES:= hwcCommit.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libEGL \ - libGLESv2 \ - libutils \ - liblog \ - libui \ - libhardware \ - -LOCAL_STATIC_LIBRARIES := \ - libtestUtil \ - libglTest \ - libhwcTest \ - -LOCAL_C_INCLUDES += \ - system/extras/tests/include \ - hardware/libhardware/include \ - $(call include-path-for, opengl-tests-includes) \ - -include $(BUILD_NATIVE_TEST) diff --git a/opengl/tests/lib/Android.bp b/opengl/tests/lib/Android.bp new file mode 100644 index 0000000000..2f6095d8e7 --- /dev/null +++ b/opengl/tests/lib/Android.bp @@ -0,0 +1,38 @@ +// 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. + +cc_library_static { + + name: "libglTest", + srcs: [ + "glTestLib.cpp", + "WindowSurface.cpp", + ], + export_include_dirs: ["include"], + + cflags: [ + "-DGL_GLEXT_PROTOTYPES", + "-DEGL_EGLEXT_PROTOTYPES", + "-Wall", + "-Wextra", + "-Werror", + ], + + shared_libs: ["libgui"], + static_libs: [ + "libarect", + "libtestUtil", + ], + +} diff --git a/opengl/tests/lib/Android.mk b/opengl/tests/lib/Android.mk deleted file mode 100644 index ea94bc199f..0000000000 --- a/opengl/tests/lib/Android.mk +++ /dev/null @@ -1,30 +0,0 @@ -# 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. - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -LOCAL_MODULE_TAGS := tests -LOCAL_MODULE:= libglTest -LOCAL_SRC_FILES:= glTestLib.cpp WindowSurface.cpp -LOCAL_C_INCLUDES += system/extras/tests/include \ - $(call include-path-for, opengl-tests-includes) - -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror - -LOCAL_SHARED_LIBRARIES += libgui -LOCAL_STATIC_LIBRARIES := libarect - -include $(BUILD_STATIC_LIBRARY) diff --git a/opengl/tests/include/EGLUtils.h b/opengl/tests/lib/include/EGLUtils.h index 014c2611ae..014c2611ae 100644 --- a/opengl/tests/include/EGLUtils.h +++ b/opengl/tests/lib/include/EGLUtils.h diff --git a/opengl/tests/include/WindowSurface.h b/opengl/tests/lib/include/WindowSurface.h index 0ec1404556..0ec1404556 100644 --- a/opengl/tests/include/WindowSurface.h +++ b/opengl/tests/lib/include/WindowSurface.h diff --git a/opengl/tests/include/glTestLib.h b/opengl/tests/lib/include/glTestLib.h index c91c594882..c91c594882 100644 --- a/opengl/tests/include/glTestLib.h +++ b/opengl/tests/lib/include/glTestLib.h diff --git a/opengl/tools/glgen2/registry/egl.xml b/opengl/tools/glgen2/registry/egl.xml index af13395bb1..c2d3494404 100755 --- a/opengl/tools/glgen2/registry/egl.xml +++ b/opengl/tools/glgen2/registry/egl.xml @@ -191,6 +191,7 @@ <enum value="((EGLSync)0)" name="EGL_NO_SYNC"/> <enum value="((EGLSyncKHR)0)" name="EGL_NO_SYNC_KHR" alias="EGL_NO_SYNC"/> <enum value="((EGLSyncNV)0)" name="EGL_NO_SYNC_NV" alias="EGL_NO_SYNC"/> + <enum value="EGL_CAST(EGLConfig,0)" name="EGL_NO_CONFIG_KHR"/> <enum value="10000" name="EGL_DISPLAY_SCALING"/> <enum value="0xFFFFFFFFFFFFFFFF" name="EGL_FOREVER" type="ull"/> <enum value="0xFFFFFFFFFFFFFFFF" name="EGL_FOREVER_KHR" type="ull" alias="EGL_FOREVER"/> @@ -739,7 +740,10 @@ <enum value="50000" name="EGL_METADATA_SCALING_EXT"/> <unused start="0x334B" end="0x334F"/> <enum value="0x3350" name="EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT"/> - <unused start="0x3351" end="0x339F"/> + <unused start="0x3351" end="0x3361"/> + <enum value="0x3362" name="EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT"/> + <enum value="0x3363" name="EGL_GL_COLORSPACE_DISPLAY_P3_EXT"/> + <unused start="0x3364" end="0x339F"/> </enums> <enums namespace="EGL" start="0x33A0" end="0x33AF" vendor="ANGLE" comment="Reserved for Shannon Woods (Bug 13175)"> @@ -1891,6 +1895,16 @@ <enum name="EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT"/> </require> </extension> + <extension name="EGL_EXT_gl_colorspace_display_p3_linear" supported="egl"> + <require> + <enum name="EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT"/> + </require> + </extension> + <extension name="EGL_EXT_gl_colorspace_display_p3" supported="egl"> + <require> + <enum name="EGL_GL_COLORSPACE_DISPLAY_P3_EXT"/> + </require> + </extension> <extension name="EGL_EXT_image_dma_buf_import" supported="egl"> <require> <enum name="EGL_LINUX_DMA_BUF_EXT"/> diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp index d2f89959e1..50589b484a 100644 --- a/services/inputflinger/EventHub.cpp +++ b/services/inputflinger/EventHub.cpp @@ -150,7 +150,8 @@ EventHub::Device::Device(int fd, int32_t id, const String8& path, fd(fd), id(id), path(path), identifier(identifier), classes(0), configuration(NULL), virtualKeyMap(NULL), ffEffectPlaying(false), ffEffectId(-1), controllerNumber(0), - timestampOverrideSec(0), timestampOverrideUsec(0) { + timestampOverrideSec(0), timestampOverrideUsec(0), enabled(true), + isVirtual(fd < 0) { memset(keyBitmask, 0, sizeof(keyBitmask)); memset(absBitmask, 0, sizeof(absBitmask)); memset(relBitmask, 0, sizeof(relBitmask)); @@ -173,6 +174,25 @@ void EventHub::Device::close() { } } +status_t EventHub::Device::enable() { + fd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK); + if(fd < 0) { + ALOGE("could not open %s, %s\n", path.string(), strerror(errno)); + return -errno; + } + enabled = true; + return OK; +} + +status_t EventHub::Device::disable() { + close(); + enabled = false; + return OK; +} + +bool EventHub::Device::hasValidFd() { + return !isVirtual && enabled; +} // --- EventHub --- @@ -286,7 +306,7 @@ status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis, AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) { + if (device && device->hasValidFd() && test_bit(axis, device->absBitmask)) { struct input_absinfo info; if(ioctl(device->fd, EVIOCGABS(axis), &info)) { ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", @@ -337,7 +357,7 @@ int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && test_bit(scanCode, device->keyBitmask)) { + if (device && device->hasValidFd() && test_bit(scanCode, device->keyBitmask)) { uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)]; memset(keyState, 0, sizeof(keyState)); if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) { @@ -352,7 +372,7 @@ int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && device->keyMap.haveKeyLayout()) { + if (device && device->hasValidFd() && device->keyMap.haveKeyLayout()) { Vector<int32_t> scanCodes; device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode, &scanCodes); if (scanCodes.size() != 0) { @@ -377,7 +397,7 @@ int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && test_bit(sw, device->swBitmask)) { + if (device && device->hasValidFd() && test_bit(sw, device->swBitmask)) { uint8_t swState[sizeof_bit_array(SW_MAX + 1)]; memset(swState, 0, sizeof(swState)); if (ioctl(device->fd, EVIOCGSW(sizeof(swState)), swState) >= 0) { @@ -395,7 +415,7 @@ status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) { + if (device && device->hasValidFd() && test_bit(axis, device->absBitmask)) { struct input_absinfo info; if(ioctl(device->fd, EVIOCGABS(axis), &info)) { ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", @@ -532,7 +552,7 @@ void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) { void EventHub::setLedStateLocked(Device* device, int32_t led, bool on) { int32_t sc; - if (device && !device->isVirtual() && mapLed(device, led, &sc) != NAME_NOT_FOUND) { + if (device && device->hasValidFd() && mapLed(device, led, &sc) != NAME_NOT_FOUND) { struct input_event ev; ev.time.tv_sec = 0; ev.time.tv_usec = 0; @@ -636,7 +656,7 @@ void EventHub::assignDescriptorLocked(InputDeviceIdentifier& identifier) { void EventHub::vibrate(int32_t deviceId, nsecs_t duration) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual()) { + if (device && device->hasValidFd()) { ff_effect effect; memset(&effect, 0, sizeof(effect)); effect.type = FF_RUMBLE; @@ -670,7 +690,7 @@ void EventHub::vibrate(int32_t deviceId, nsecs_t duration) { void EventHub::cancelVibrate(int32_t deviceId) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual()) { + if (device && device->hasValidFd()) { if (device->ffEffectPlaying) { device->ffEffectPlaying = false; @@ -1065,12 +1085,37 @@ static const int32_t GAMEPAD_KEYCODES[] = { AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE, }; +status_t EventHub::registerDeviceForEpollLocked(Device* device) { + struct epoll_event eventItem; + memset(&eventItem, 0, sizeof(eventItem)); + eventItem.events = EPOLLIN; + if (mUsingEpollWakeup) { + eventItem.events |= EPOLLWAKEUP; + } + eventItem.data.u32 = device->id; + if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, device->fd, &eventItem)) { + ALOGE("Could not add device fd to epoll instance. errno=%d", errno); + return -errno; + } + return OK; +} + +status_t EventHub::unregisterDeviceFromEpollLocked(Device* device) { + if (device->hasValidFd()) { + if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) { + ALOGW("Could not remove device fd from epoll instance. errno=%d", errno); + return -errno; + } + } + return OK; +} + status_t EventHub::openDeviceLocked(const char *devicePath) { char buffer[80]; ALOGV("Opening device: %s", devicePath); - int fd = open(devicePath, O_RDWR | O_CLOEXEC); + int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK); if(fd < 0) { ALOGE("could not open %s, %s\n", devicePath, strerror(errno)); return -1; @@ -1135,13 +1180,6 @@ status_t EventHub::openDeviceLocked(const char *devicePath) { // Fill in the descriptor. assignDescriptorLocked(identifier); - // Make file descriptor non-blocking for use with poll(). - if (fcntl(fd, F_SETFL, O_NONBLOCK)) { - ALOGE("Error %d making device file descriptor non-blocking.", errno); - close(fd); - return -1; - } - // Allocate device. (The device object takes ownership of the fd at this point.) int32_t deviceId = mNextDeviceId++; Device* device = new Device(fd, deviceId, String8(devicePath), identifier); @@ -1303,12 +1341,6 @@ status_t EventHub::openDeviceLocked(const char *devicePath) { break; } } - - // Disable kernel key repeat since we handle it ourselves - unsigned int repeatRate[] = {0,0}; - if (ioctl(fd, EVIOCSREP, repeatRate)) { - ALOGW("Unable to disable kernel key repeat for %s: %s", devicePath, strerror(errno)); - } } // If the device isn't recognized as something we handle, don't monitor it. @@ -1332,23 +1364,41 @@ status_t EventHub::openDeviceLocked(const char *devicePath) { if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_DPAD) && device->classes & INPUT_DEVICE_CLASS_GAMEPAD) { device->controllerNumber = getNextControllerNumberLocked(device); - setLedForController(device); + setLedForControllerLocked(device); } - // Register with epoll. - struct epoll_event eventItem; - memset(&eventItem, 0, sizeof(eventItem)); - eventItem.events = EPOLLIN; - if (mUsingEpollWakeup) { - eventItem.events |= EPOLLWAKEUP; - } - eventItem.data.u32 = deviceId; - if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) { - ALOGE("Could not add device fd to epoll instance. errno=%d", errno); + + if (registerDeviceForEpollLocked(device) != OK) { delete device; return -1; } + configureFd(device); + + ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, " + "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ", + deviceId, fd, devicePath, device->identifier.name.string(), + device->classes, + device->configurationFile.string(), + device->keyMap.keyLayoutFile.string(), + device->keyMap.keyCharacterMapFile.string(), + toString(mBuiltInKeyboardId == deviceId)); + + addDeviceLocked(device); + return OK; +} + +void EventHub::configureFd(Device* device) { + // Set fd parameters with ioctl, such as key repeat, suspend block, and clock type + if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) { + // Disable kernel key repeat since we handle it ourselves + unsigned int repeatRate[] = {0, 0}; + if (ioctl(device->fd, EVIOCSREP, repeatRate)) { + ALOGW("Unable to disable kernel key repeat for %s: %s", + device->path.string(), strerror(errno)); + } + } + String8 wakeMechanism("EPOLLWAKEUP"); if (!mUsingEpollWakeup) { #ifndef EVIOCSSUSPENDBLOCK @@ -1357,44 +1407,67 @@ status_t EventHub::openDeviceLocked(const char *devicePath) { // this feature, we need to be prepared to define the ioctl ourselves. #define EVIOCSSUSPENDBLOCK _IOW('E', 0x91, int) #endif - if (ioctl(fd, EVIOCSSUSPENDBLOCK, 1)) { + if (ioctl(device->fd, EVIOCSSUSPENDBLOCK, 1)) { wakeMechanism = "<none>"; } else { wakeMechanism = "EVIOCSSUSPENDBLOCK"; } } - // Tell the kernel that we want to use the monotonic clock for reporting timestamps // associated with input events. This is important because the input system // uses the timestamps extensively and assumes they were recorded using the monotonic // clock. - // - // In older kernel, before Linux 3.4, there was no way to tell the kernel which - // clock to use to input event timestamps. The standard kernel behavior was to - // record a real time timestamp, which isn't what we want. Android kernels therefore - // contained a patch to the evdev_event() function in drivers/input/evdev.c to - // replace the call to do_gettimeofday() with ktime_get_ts() to cause the monotonic - // clock to be used instead of the real time clock. - // - // As of Linux 3.4, there is a new EVIOCSCLOCKID ioctl to set the desired clock. - // Therefore, we no longer require the Android-specific kernel patch described above - // as long as we make sure to set select the monotonic clock. We do that here. int clockId = CLOCK_MONOTONIC; - bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId); + bool usingClockIoctl = !ioctl(device->fd, EVIOCSCLOCKID, &clockId); + ALOGI("wakeMechanism=%s, usingClockIoctl=%s", wakeMechanism.string(), + toString(usingClockIoctl)); +} - ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, " - "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, " - "wakeMechanism=%s, usingClockIoctl=%s", - deviceId, fd, devicePath, device->identifier.name.string(), - device->classes, - device->configurationFile.string(), - device->keyMap.keyLayoutFile.string(), - device->keyMap.keyCharacterMapFile.string(), - toString(mBuiltInKeyboardId == deviceId), - wakeMechanism.string(), toString(usingClockIoctl)); +bool EventHub::isDeviceEnabled(int32_t deviceId) { + AutoMutex _l(mLock); + Device* device = getDeviceLocked(deviceId); + if (device == NULL) { + ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__); + return false; + } + return device->enabled; +} - addDeviceLocked(device); - return 0; +status_t EventHub::enableDevice(int32_t deviceId) { + AutoMutex _l(mLock); + Device* device = getDeviceLocked(deviceId); + if (device == NULL) { + ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__); + return BAD_VALUE; + } + if (device->enabled) { + ALOGW("Duplicate call to %s, input device %" PRId32 " already enabled", __func__, deviceId); + return OK; + } + status_t result = device->enable(); + if (result != OK) { + ALOGE("Failed to enable device %" PRId32, deviceId); + return result; + } + + configureFd(device); + + return registerDeviceForEpollLocked(device); +} + +status_t EventHub::disableDevice(int32_t deviceId) { + AutoMutex _l(mLock); + Device* device = getDeviceLocked(deviceId); + if (device == NULL) { + ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__); + return BAD_VALUE; + } + if (!device->enabled) { + ALOGW("Duplicate call to %s, input device already disabled", __func__); + return OK; + } + unregisterDeviceFromEpollLocked(device); + return device->disable(); } void EventHub::createVirtualKeyboardLocked() { @@ -1490,7 +1563,7 @@ void EventHub::releaseControllerNumberLocked(Device* device) { mControllerNumbers.clearBit(static_cast<uint32_t>(num - 1)); } -void EventHub::setLedForController(Device* device) { +void EventHub::setLedForControllerLocked(Device* device) { for (int i = 0; i < MAX_CONTROLLER_LEDS; i++) { setLedStateLocked(device, ALED_CONTROLLER_1 + i, device->controllerNumber == i + 1); } @@ -1500,7 +1573,7 @@ bool EventHub::hasKeycodeLocked(Device* device, int keycode) const { if (!device->keyMap.haveKeyLayout()) { return false; } - + Vector<int32_t> scanCodes; device->keyMap.keyLayoutMap->findScanCodesForKey(keycode, &scanCodes); const size_t N = scanCodes.size(); @@ -1510,7 +1583,7 @@ bool EventHub::hasKeycodeLocked(Device* device, int keycode) const { return true; } } - + return false; } @@ -1556,11 +1629,7 @@ void EventHub::closeDeviceLocked(Device* device) { mBuiltInKeyboardId = NO_BUILT_IN_KEYBOARD; } - if (!device->isVirtual()) { - if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) { - ALOGW("Could not remove device fd from epoll instance. errno=%d", errno); - } - } + unregisterDeviceFromEpollLocked(device); releaseControllerNumberLocked(device); @@ -1691,6 +1760,7 @@ void EventHub::dump(String8& dump) { } dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes); dump.appendFormat(INDENT3 "Path: %s\n", device->path.string()); + dump.appendFormat(INDENT3 "Enabled: %s\n", toString(device->enabled)); dump.appendFormat(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string()); dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string()); dump.appendFormat(INDENT3 "ControllerNumber: %d\n", device->controllerNumber); diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h index 686925311f..727b73aeb8 100644 --- a/services/inputflinger/EventHub.h +++ b/services/inputflinger/EventHub.h @@ -25,9 +25,8 @@ #include <input/KeyCharacterMap.h> #include <input/VirtualKeyMap.h> #include <utils/String8.h> -#include <utils/threads.h> +#include <utils/Mutex.h> #include <utils/Log.h> -#include <utils/threads.h> #include <utils/List.h> #include <utils/Errors.h> #include <utils/PropertyMap.h> @@ -267,6 +266,15 @@ public: /* Called by the heatbeat to ensures that the reader has not deadlocked. */ virtual void monitor() = 0; + + /* Return true if the device is enabled. */ + virtual bool isDeviceEnabled(int32_t deviceId) = 0; + + /* Enable an input device */ + virtual status_t enableDevice(int32_t deviceId) = 0; + + /* Disable an input device. Closes file descriptor to that device. */ + virtual status_t disableDevice(int32_t deviceId) = 0; }; class EventHub : public EventHubInterface @@ -335,7 +343,7 @@ private: struct Device { Device* next; - int fd; // may be -1 if device is virtual + int fd; // may be -1 if device is closed const int32_t id; const String8 path; const InputDeviceIdentifier identifier; @@ -371,7 +379,11 @@ private: void close(); - inline bool isVirtual() const { return fd < 0; } + bool enabled; // initially true + status_t enable(); + status_t disable(); + bool hasValidFd(); + const bool isVirtual; // set if fd < 0 is passed to constructor const sp<KeyCharacterMap>& getKeyCharacterMap() const { if (combinedKeyMap != NULL) { @@ -390,6 +402,14 @@ private: void closeDeviceLocked(Device* device); void closeAllDevicesLocked(); + void configureFd(Device* device); + + bool isDeviceEnabled(int32_t deviceId); + status_t enableDevice(int32_t deviceId); + status_t disableDevice(int32_t deviceId); + status_t registerDeviceForEpollLocked(Device* device); + status_t unregisterDeviceFromEpollLocked(Device* device); + status_t scanDirLocked(const char *dirname); void scanDevicesLocked(); status_t readNotifyLocked(); @@ -409,7 +429,7 @@ private: int32_t getNextControllerNumberLocked(Device* device); void releaseControllerNumberLocked(Device* device); - void setLedForController(Device* device); + void setLedForControllerLocked(Device* device); status_t mapLed(Device* device, int32_t led, int32_t* outScanCode) const; void setLedStateLocked(Device* device, int32_t led, bool on); diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index 73255dd292..97565aa000 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -835,6 +835,18 @@ void InputReader::cancelVibrate(int32_t deviceId, int32_t token) { } } +bool InputReader::isInputDeviceEnabled(int32_t deviceId) { + AutoMutex _l(mLock); + + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex >= 0) { + InputDevice* device = mDevices.valueAt(deviceIndex); + return device->isEnabled(); + } + ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId); + return false; +} + void InputReader::dump(String8& dump) { AutoMutex _l(mLock); @@ -1011,6 +1023,26 @@ InputDevice::~InputDevice() { mMappers.clear(); } +bool InputDevice::isEnabled() { + return getEventHub()->isDeviceEnabled(mId); +} + +void InputDevice::setEnabled(bool enabled, nsecs_t when) { + if (isEnabled() == enabled) { + return; + } + + if (enabled) { + getEventHub()->enableDevice(mId); + reset(when); + } else { + reset(when); + getEventHub()->disableDevice(mId); + } + // Must change generation to flag this device as changed + bumpGeneration(); +} + void InputDevice::dump(String8& dump) { InputDeviceInfo deviceInfo; getDeviceInfo(& deviceInfo); @@ -1082,6 +1114,12 @@ void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config } } + if (!changes || (changes & InputReaderConfiguration::CHANGE_ENABLED_STATE)) { + ssize_t index = config->disabledDevices.indexOf(mId); + bool enabled = index < 0; + setEnabled(enabled, when); + } + size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h index edb6fcc284..157fa4f9c3 100644 --- a/services/inputflinger/InputReader.h +++ b/services/inputflinger/InputReader.h @@ -27,11 +27,14 @@ #include <input/VelocityTracker.h> #include <ui/DisplayInfo.h> #include <utils/KeyedVector.h> -#include <utils/threads.h> +#include <utils/Condition.h> +#include <utils/Thread.h> +#include <utils/Mutex.h> #include <utils/Timers.h> #include <utils/RefBase.h> #include <utils/String8.h> #include <utils/BitSet.h> +#include <utils/SortedVector.h> #include <stddef.h> #include <unistd.h> @@ -84,6 +87,9 @@ struct InputReaderConfiguration { // The pointer capture mode has changed. CHANGE_POINTER_CAPTURE = 1 << 8, + // The set of disabled input devices (disabledDevices) has changed. + CHANGE_ENABLED_STATE = 1 << 9, + // All devices must be reopened. CHANGE_MUST_REOPEN = 1 << 31, }; @@ -174,6 +180,9 @@ struct InputReaderConfiguration { // True if pointer capture is enabled. bool pointerCapture; + // The set of currently disabled input devices. + SortedVector<int32_t> disabledDevices; + InputReaderConfiguration() : virtualKeyQuietTime(0), pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f, 3.0f), @@ -288,6 +297,9 @@ public: /* Called by the heatbeat to ensures that the reader has not deadlocked. */ virtual void monitor() = 0; + /* Returns true if the input device is enabled. */ + virtual bool isInputDeviceEnabled(int32_t deviceId) = 0; + /* Runs a single iteration of the processing loop. * Nominally reads and processes one incoming message from the EventHub. * @@ -407,6 +419,8 @@ public: virtual void getInputDevices(Vector<InputDeviceInfo>& outInputDevices); + virtual bool isInputDeviceEnabled(int32_t deviceId); + virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, int32_t scanCode); virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, @@ -552,6 +566,9 @@ public: inline bool isIgnored() { return mMappers.isEmpty(); } + bool isEnabled(); + void setEnabled(bool enabled, nsecs_t when); + void dump(String8& dump); void addMapper(InputMapper* mapper); void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index dcfe114203..76291a5786 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -16,6 +16,7 @@ #include "../InputReader.h" +#include <inttypes.h> #include <utils/List.h> #include <gtest/gtest.h> #include <math.h> @@ -159,6 +160,22 @@ public: mConfig.excludedDeviceNames.push(deviceName); } + void addDisabledDevice(int32_t deviceId) { + ssize_t index = mConfig.disabledDevices.indexOf(deviceId); + bool currentlyEnabled = index < 0; + if (currentlyEnabled) { + mConfig.disabledDevices.add(deviceId); + } + } + + void removeDisabledDevice(int32_t deviceId) { + ssize_t index = mConfig.disabledDevices.indexOf(deviceId); + bool currentlyEnabled = index < 0; + if (!currentlyEnabled) { + mConfig.disabledDevices.remove(deviceId); + } + } + void setPointerController(int32_t deviceId, const sp<FakePointerController>& controller) { mPointerControllers.add(deviceId, controller); } @@ -255,6 +272,11 @@ public: mNotifyConfigurationChangedArgsQueue.erase(mNotifyConfigurationChangedArgsQueue.begin()); } + void assertNotifyConfigurationChangedWasNotCalled() { + ASSERT_TRUE(mNotifyConfigurationChangedArgsQueue.empty()) + << "Expected notifyConfigurationChanged() to not have been called."; + } + void assertNotifyDeviceResetWasCalled( NotifyDeviceResetArgs* outEventArgs = NULL) { ASSERT_FALSE(mNotifyDeviceResetArgsQueue.empty()) @@ -265,6 +287,11 @@ public: mNotifyDeviceResetArgsQueue.erase(mNotifyDeviceResetArgsQueue.begin()); } + void assertNotifyDeviceResetWasNotCalled() { + ASSERT_TRUE(mNotifyDeviceResetArgsQueue.empty()) + << "Expected notifyDeviceReset() to not have been called."; + } + void assertNotifyKeyWasCalled(NotifyKeyArgs* outEventArgs = NULL) { ASSERT_FALSE(mNotifyKeyArgsQueue.empty()) << "Expected notifyKey() to have been called."; @@ -347,9 +374,20 @@ class FakeEventHub : public EventHubInterface { KeyedVector<int32_t, KeyInfo> keysByUsageCode; KeyedVector<int32_t, bool> leds; Vector<VirtualKeyDefinition> virtualKeys; + bool enabled; + + status_t enable() { + enabled = true; + return OK; + } + + status_t disable() { + enabled = false; + return OK; + } explicit Device(uint32_t classes) : - classes(classes) { + classes(classes), enabled(true) { } }; @@ -382,6 +420,43 @@ public: enqueueEvent(ARBITRARY_TIME, deviceId, EventHubInterface::DEVICE_REMOVED, 0, 0); } + bool isDeviceEnabled(int32_t deviceId) { + Device* device = getDevice(deviceId); + if (device == NULL) { + ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__); + return false; + } + return device->enabled; + } + + status_t enableDevice(int32_t deviceId) { + status_t result; + Device* device = getDevice(deviceId); + if (device == NULL) { + ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__); + return BAD_VALUE; + } + if (device->enabled) { + ALOGW("Duplicate call to %s, device %" PRId32 " already enabled", __func__, deviceId); + return OK; + } + result = device->enable(); + return result; + } + + status_t disableDevice(int32_t deviceId) { + Device* device = getDevice(deviceId); + if (device == NULL) { + ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__); + return BAD_VALUE; + } + if (!device->enabled) { + ALOGW("Duplicate call to %s, device %" PRId32 " already disabled", __func__, deviceId); + return OK; + } + return device->disable(); + } + void finishDeviceScan() { enqueueEvent(ARBITRARY_TIME, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0); } @@ -1039,6 +1114,20 @@ protected: mFakeEventHub->assertQueueIsEmpty(); } + void disableDevice(int32_t deviceId, InputDevice* device) { + mFakePolicy->addDisabledDevice(deviceId); + configureDevice(InputReaderConfiguration::CHANGE_ENABLED_STATE, device); + } + + void enableDevice(int32_t deviceId, InputDevice* device) { + mFakePolicy->removeDisabledDevice(deviceId); + configureDevice(InputReaderConfiguration::CHANGE_ENABLED_STATE, device); + } + + void configureDevice(uint32_t changes, InputDevice* device) { + device->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes); + } + FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId, int32_t controllerNumber, const String8& name, uint32_t classes, uint32_t sources, const PropertyMap* configuration) { @@ -1077,6 +1166,46 @@ TEST_F(InputReaderTest, GetInputDevices) { ASSERT_EQ(size_t(0), inputDevices[0].getMotionRanges().size()); } +TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) { + constexpr int32_t deviceId = 1; + constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD; + InputDevice* device = mReader->newDevice(deviceId, 0, String8("fake"), deviceClass); + // Must add at least one mapper or the device will be ignored! + FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_KEYBOARD); + device->addMapper(mapper); + mReader->setNextDevice(device); + addDevice(deviceId, String8("fake"), deviceClass, NULL); + + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled(NULL)); + + NotifyDeviceResetArgs resetArgs; + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); + ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime); + ASSERT_EQ(deviceId, resetArgs.deviceId); + + ASSERT_EQ(device->isEnabled(), true); + disableDevice(deviceId, device); + mReader->loopOnce(); + + mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs); + ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime); + ASSERT_EQ(deviceId, resetArgs.deviceId); + ASSERT_EQ(device->isEnabled(), false); + + disableDevice(deviceId, device); + mReader->loopOnce(); + mFakeListener->assertNotifyDeviceResetWasNotCalled(); + mFakeListener->assertNotifyConfigurationChangedWasNotCalled(); + ASSERT_EQ(device->isEnabled(), false); + + enableDevice(deviceId, device); + mReader->loopOnce(); + mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs); + ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime); + ASSERT_EQ(deviceId, resetArgs.deviceId); + ASSERT_EQ(device->isEnabled(), true); +} + TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) { FakeInputMapper* mapper = NULL; ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"), @@ -1274,6 +1403,10 @@ TEST_F(InputDeviceTest, ImmutableProperties) { ASSERT_EQ(DEVICE_CLASSES, mDevice->getClasses()); } +TEST_F(InputDeviceTest, WhenDeviceCreated_EnabledIsTrue) { + ASSERT_EQ(mDevice->isEnabled(), true); +} + TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) { // Configuration. InputReaderConfiguration config; diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp index 8c2300e9d0..8d381b1c31 100644 --- a/services/sensorservice/Android.bp +++ b/services/sensorservice/Android.bp @@ -1,3 +1,73 @@ subdirs = [ "hidl" ] +cc_library_shared { + name: "libsensorservice", + + srcs: [ + "BatteryService.cpp", + "CorrectedGyroSensor.cpp", + "Fusion.cpp", + "GravitySensor.cpp", + "LinearAccelerationSensor.cpp", + "OrientationSensor.cpp", + "RecentEventLogger.cpp", + "RotationVectorSensor.cpp", + "SensorDevice.cpp", + "SensorDirectConnection.cpp", + "SensorEventConnection.cpp", + "SensorFusion.cpp", + "SensorInterface.cpp", + "SensorList.cpp", + "SensorRecord.cpp", + "SensorService.cpp", + "SensorServiceUtils.cpp", + ], + + cflags: [ + "-DLOG_TAG=\"SensorService\"", + "-Wall", + "-Werror", + "-Wextra", + "-fvisibility=hidden" + ], + + shared_libs: [ + "libcutils", + "libhardware", + "libhardware_legacy", + "libutils", + "liblog", + "libbinder", + "libsensor", + "libcrypto", + "libbase", + "libhidlbase", + "libhidltransport", + "libhwbinder", + "android.hardware.sensors@1.0", + ], + + static_libs: ["android.hardware.sensors@1.0-convert"], + + // our public headers depend on libsensor + export_shared_lib_headers: ["libsensor"], +} + +cc_binary { + name: "sensorservice", + + srcs: ["main_sensorservice.cpp"], + + shared_libs: [ + "libsensorservice", + "libbinder", + "libutils", + ], + + cflags: [ + "-Wall", + "-Werror", + "-Wextra", + ], +} diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk deleted file mode 100644 index cfb72310d5..0000000000 --- a/services/sensorservice/Android.mk +++ /dev/null @@ -1,73 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - BatteryService.cpp \ - CorrectedGyroSensor.cpp \ - Fusion.cpp \ - GravitySensor.cpp \ - LinearAccelerationSensor.cpp \ - OrientationSensor.cpp \ - RecentEventLogger.cpp \ - RotationVectorSensor.cpp \ - SensorDevice.cpp \ - SensorDirectConnection.cpp \ - SensorEventConnection.cpp \ - SensorFusion.cpp \ - SensorInterface.cpp \ - SensorList.cpp \ - SensorRecord.cpp \ - SensorService.cpp \ - SensorServiceUtils.cpp \ - -LOCAL_CFLAGS:= -DLOG_TAG=\"SensorService\" - -LOCAL_CFLAGS += -Wall -Werror -Wextra - -LOCAL_CFLAGS += -fvisibility=hidden - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libhardware \ - libhardware_legacy \ - libutils \ - liblog \ - libbinder \ - libsensor \ - libcrypto \ - libbase \ - libhidlbase \ - libhidltransport \ - libhwbinder \ - android.hardware.sensors@1.0 - -LOCAL_STATIC_LIBRARIES := \ - android.hardware.sensors@1.0-convert - -# our public headers depend on libsensor -LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \ - libsensor \ - -LOCAL_MODULE:= libsensorservice - -include $(BUILD_SHARED_LIBRARY) - -##################################################################### -# build executable -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - main_sensorservice.cpp - -LOCAL_SHARED_LIBRARIES := \ - libsensorservice \ - libbinder \ - libutils - -LOCAL_CFLAGS := -Wall -Werror -Wextra - -LOCAL_MODULE_TAGS := optional - -LOCAL_MODULE:= sensorservice - -include $(BUILD_EXECUTABLE) diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp index 91923b36a0..870635bf05 100644 --- a/services/sensorservice/SensorDirectConnection.cpp +++ b/services/sensorservice/SensorDirectConnection.cpp @@ -18,8 +18,6 @@ #include "SensorDirectConnection.h" #include <hardware/sensors.h> -#include <sys/stat.h> - #define UNUSED(x) (void)(x) namespace android { @@ -182,13 +180,12 @@ bool SensorService::SensorDirectConnection::isEquivalent(const sensors_direct_me if (mMem.type == mem->type) { switch (mMem.type) { case SENSOR_DIRECT_MEM_TYPE_ASHMEM: { - struct stat s1, s2; - int fd1, fd2; - fd1 = mMem.handle->data[0]; - fd2 = mem->handle->data[0]; - if (fstat(fd1, &s1) < 0 || fstat(fd2, &s2) < 0 || s1.st_ino == s2.st_ino) { - ret = true; - } + // there is no known method to test if two ashmem fds are equivalent besides + // trivially comparing the fd values (ino number from fstat() are always the + // same, pointing to "/dev/ashmem"). + int fd1 = mMem.handle->data[0]; + int fd2 = mem->handle->data[0]; + ret = (fd1 == fd2); break; } case SENSOR_DIRECT_MEM_TYPE_GRALLOC: diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index d60768c98d..b5baba8bcd 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -394,6 +394,7 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) { } } else if (!mSensors.hasAnySensor()) { result.append("No Sensors on the device\n"); + result.append("devInitCheck : %d\n", SensorDevice::getInstance().initCheck()); } else { // Default dump the sensor list and debugging information. // diff --git a/services/sensorservice/hidl/SensorManager.cpp b/services/sensorservice/hidl/SensorManager.cpp index 06ff95cdc8..991944e8b4 100644 --- a/services/sensorservice/hidl/SensorManager.cpp +++ b/services/sensorservice/hidl/SensorManager.cpp @@ -42,9 +42,7 @@ using ::android::hardware::hidl_vec; using ::android::hardware::Void; using ::android::sp; -SensorManager::SensorManager() - : mInternalManager{::android::SensorManager::getInstanceForPackage( - String16(ISensorManager::descriptor))} { +SensorManager::SensorManager() { } SensorManager::~SensorManager() { @@ -58,7 +56,7 @@ SensorManager::~SensorManager() { // Methods from ::android::frameworks::sensorservice::V1_0::ISensorManager follow. Return<void> SensorManager::getSensorList(getSensorList_cb _hidl_cb) { ::android::Sensor const* const* list; - ssize_t count = mInternalManager.getSensorList(&list); + ssize_t count = getInternalManager().getSensorList(&list); if (count < 0 || !list) { LOG(ERROR) << "::android::SensorManager::getSensorList encounters " << count; _hidl_cb({}, Result::UNKNOWN_ERROR); @@ -74,7 +72,7 @@ Return<void> SensorManager::getSensorList(getSensorList_cb _hidl_cb) { } Return<void> SensorManager::getDefaultSensor(SensorType type, getDefaultSensor_cb _hidl_cb) { - ::android::Sensor const* sensor = mInternalManager.getDefaultSensor(static_cast<int>(type)); + ::android::Sensor const* sensor = getInternalManager().getDefaultSensor(static_cast<int>(type)); if (!sensor) { _hidl_cb({}, Result::NOT_EXIST); return Void(); @@ -110,7 +108,7 @@ Return<void> SensorManager::createAshmemDirectChannel( return Void(); } - createDirectChannel(mInternalManager, size, SENSOR_DIRECT_MEM_TYPE_ASHMEM, + createDirectChannel(getInternalManager(), size, SENSOR_DIRECT_MEM_TYPE_ASHMEM, mem.handle(), _hidl_cb); return Void(); @@ -120,7 +118,7 @@ Return<void> SensorManager::createGrallocDirectChannel( const hidl_handle& buffer, uint64_t size, createGrallocDirectChannel_cb _hidl_cb) { - createDirectChannel(mInternalManager, size, SENSOR_DIRECT_MEM_TYPE_GRALLOC, + createDirectChannel(getInternalManager(), size, SENSOR_DIRECT_MEM_TYPE_GRALLOC, buffer.getNativeHandle(), _hidl_cb); return Void(); @@ -157,6 +155,15 @@ sp<::android::Looper> SensorManager::getLooper() { return mLooper; } +::android::SensorManager& SensorManager::getInternalManager() { + std::lock_guard<std::mutex> lock(mInternalManagerMutex); + if (mInternalManager == nullptr) { + mInternalManager = &::android::SensorManager::getInstanceForPackage( + String16(ISensorManager::descriptor)); + } + return *mInternalManager; +} + Return<void> SensorManager::createEventQueue( const sp<IEventQueueCallback> &callback, createEventQueue_cb _hidl_cb) { if (callback == nullptr) { @@ -165,7 +172,7 @@ Return<void> SensorManager::createEventQueue( } sp<::android::Looper> looper = getLooper(); - sp<::android::SensorEventQueue> internalQueue = mInternalManager.createEventQueue(); + sp<::android::SensorEventQueue> internalQueue = getInternalManager().createEventQueue(); if (internalQueue == nullptr) { LOG(WARNING) << "::android::SensorManager::createEventQueue returns nullptr."; _hidl_cb(nullptr, Result::UNKNOWN_ERROR); diff --git a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h index a2372df3d1..cc044bf73b 100644 --- a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h +++ b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h @@ -50,9 +50,13 @@ struct SensorManager final : public ISensorManager { Return<void> createEventQueue(const sp<IEventQueueCallback> &callback, createEventQueue_cb _hidl_cb); private: + // Block until ::android::SensorManager is initialized. + ::android::SensorManager& getInternalManager(); sp<::android::Looper> getLooper(); - ::android::SensorManager& mInternalManager; + std::mutex mInternalManagerMutex; + ::android::SensorManager* mInternalManager = nullptr; // does not own + std::mutex mLooperMutex; sp<::android::Looper> mLooper; }; diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index 535c93059e..95a522d11c 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -54,11 +54,7 @@ ifeq ($(TARGET_USES_HWC2),true) LOCAL_SRC_FILES += \ SurfaceFlinger.cpp \ DisplayHardware/HWComposer.cpp - ifeq ($(TARGET_USES_HWC2ON1ADAPTER), true) - LOCAL_CFLAGS += -DBYPASS_IHWC - endif else - LOCAL_CFLAGS += -DBYPASS_IHWC LOCAL_SRC_FILES += \ SurfaceFlinger_hwc1.cpp \ DisplayHardware/HWComposer_hwc1.cpp @@ -84,7 +80,6 @@ LOCAL_SHARED_LIBRARIES := \ libdl \ libfmq \ libhardware \ - libhwc2on1adapter \ libhidlbase \ libhidltransport \ libhwbinder \ diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index b5ffc60b55..a0abf12f9a 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -121,7 +121,7 @@ DisplayDevice::DisplayDevice( ANativeWindow* const window = mNativeWindow.get(); #ifdef USE_HWC2 - mActiveColorMode = static_cast<android_color_mode_t>(-1); + mActiveColorMode = HAL_COLOR_MODE_NATIVE; mDisplayHasWideColor = supportWideColor; #else (void) supportWideColor; @@ -610,23 +610,25 @@ uint32_t DisplayDevice::getPrimaryDisplayOrientationTransform() { void DisplayDevice::dump(String8& result) const { const Transform& tr(mGlobalTransform); - result.appendFormat( - "+ DisplayDevice: %s\n" - " type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p, orient=%2d (type=%08x), " - "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n" - " v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d]," - "transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n", - mDisplayName.string(), mType, mHwcDisplayId, - mLayerStack, mDisplayWidth, mDisplayHeight, mNativeWindow.get(), - mOrientation, tr.getType(), getPageFlipCount(), - mIsSecure, mPowerMode, mActiveConfig, - mVisibleLayersSortedByZ.size(), - mViewport.left, mViewport.top, mViewport.right, mViewport.bottom, - mFrame.left, mFrame.top, mFrame.right, mFrame.bottom, - mScissor.left, mScissor.top, mScissor.right, mScissor.bottom, - tr[0][0], tr[1][0], tr[2][0], - tr[0][1], tr[1][1], tr[2][1], - tr[0][2], tr[1][2], tr[2][2]); + EGLint redSize, greenSize, blueSize, alphaSize; + eglGetConfigAttrib(mDisplay, mConfig, EGL_RED_SIZE, &redSize); + eglGetConfigAttrib(mDisplay, mConfig, EGL_GREEN_SIZE, &greenSize); + eglGetConfigAttrib(mDisplay, mConfig, EGL_BLUE_SIZE, &blueSize); + eglGetConfigAttrib(mDisplay, mConfig, EGL_ALPHA_SIZE, &alphaSize); + result.appendFormat("+ DisplayDevice: %s\n", mDisplayName.string()); + result.appendFormat(" type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p " + "(%d:%d:%d:%d), orient=%2d (type=%08x), " + "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n", + mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight, + mNativeWindow.get(), redSize, greenSize, blueSize, alphaSize, mOrientation, + tr.getType(), getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig, + mVisibleLayersSortedByZ.size()); + result.appendFormat(" v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d]," + "transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n", + mViewport.left, mViewport.top, mViewport.right, mViewport.bottom, + mFrame.left, mFrame.top, mFrame.right, mFrame.bottom, mScissor.left, + mScissor.top, mScissor.right, mScissor.bottom, tr[0][0], tr[1][0], tr[2][0], + tr[0][1], tr[1][1], tr[2][1], tr[0][2], tr[1][2], tr[2][2]); String8 surfaceDump; mDisplaySurface->dumpAsString(surfaceDump); diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 15b72c4bb9..0366630d94 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -88,55 +88,8 @@ namespace Hwc2 = android::Hwc2; // Device methods -#ifdef BYPASS_IHWC -Device::Device(hwc2_device_t* device) - : mHwcDevice(device), - mCreateVirtualDisplay(nullptr), - mDestroyVirtualDisplay(nullptr), - mDump(nullptr), - mGetMaxVirtualDisplayCount(nullptr), - mRegisterCallback(nullptr), - mAcceptDisplayChanges(nullptr), - mCreateLayer(nullptr), - mDestroyLayer(nullptr), - mGetActiveConfig(nullptr), - mGetChangedCompositionTypes(nullptr), - mGetColorModes(nullptr), - mGetDisplayAttribute(nullptr), - mGetDisplayConfigs(nullptr), - mGetDisplayName(nullptr), - mGetDisplayRequests(nullptr), - mGetDisplayType(nullptr), - mGetDozeSupport(nullptr), - mGetHdrCapabilities(nullptr), - mGetReleaseFences(nullptr), - mPresentDisplay(nullptr), - mSetActiveConfig(nullptr), - mSetClientTarget(nullptr), - mSetColorMode(nullptr), - mSetColorTransform(nullptr), - mSetOutputBuffer(nullptr), - mSetPowerMode(nullptr), - mSetVsyncEnabled(nullptr), - mValidateDisplay(nullptr), - mSetCursorPosition(nullptr), - mSetLayerBuffer(nullptr), - mSetLayerSurfaceDamage(nullptr), - mSetLayerBlendMode(nullptr), - mSetLayerColor(nullptr), - mSetLayerCompositionType(nullptr), - mSetLayerDataspace(nullptr), - mSetLayerDisplayFrame(nullptr), - mSetLayerPlaneAlpha(nullptr), - mSetLayerSidebandStream(nullptr), - mSetLayerSourceCrop(nullptr), - mSetLayerTransform(nullptr), - mSetLayerVisibleRegion(nullptr), - mSetLayerZOrder(nullptr), -#else Device::Device(bool useVrComposer) : mComposer(std::make_unique<Hwc2::Composer>(useVrComposer)), -#endif // BYPASS_IHWC mCapabilities(), mDisplays(), mHotplug(), @@ -147,18 +100,11 @@ Device::Device(bool useVrComposer) mPendingVsyncs() { loadCapabilities(); - loadFunctionPointers(); registerCallbacks(); } Device::~Device() { -#ifdef BYPASS_IHWC - if (mHwcDevice == nullptr) { - return; - } -#endif - for (auto element : mDisplays) { auto display = element.second.lock(); if (!display) { @@ -185,36 +131,18 @@ Device::~Device() } } } - -#ifdef BYPASS_IHWC - hwc2_close(mHwcDevice); -#endif } // Required by HWC2 device std::string Device::dump() const { -#ifdef BYPASS_IHWC - uint32_t numBytes = 0; - mDump(mHwcDevice, &numBytes, nullptr); - - std::vector<char> buffer(numBytes); - mDump(mHwcDevice, &numBytes, buffer.data()); - - return std::string(buffer.data(), buffer.size()); -#else return mComposer->dumpDebugInfo(); -#endif } uint32_t Device::getMaxVirtualDisplayCount() const { -#ifdef BYPASS_IHWC - return mGetMaxVirtualDisplayCount(mHwcDevice); -#else return mComposer->getMaxVirtualDisplayCount(); -#endif } Error Device::createVirtualDisplay(uint32_t width, uint32_t height, @@ -223,15 +151,9 @@ Error Device::createVirtualDisplay(uint32_t width, uint32_t height, ALOGI("Creating virtual display"); hwc2_display_t displayId = 0; -#ifdef BYPASS_IHWC - int32_t intFormat = static_cast<int32_t>(*format); - int32_t intError = mCreateVirtualDisplay(mHwcDevice, width, height, - &intFormat, &displayId); -#else auto intFormat = static_cast<Hwc2::PixelFormat>(*format); auto intError = mComposer->createVirtualDisplay(width, height, &intFormat, &displayId); -#endif auto error = static_cast<Error>(intError); if (error != Error::None) { return error; @@ -285,9 +207,7 @@ void Device::callHotplug(std::shared_ptr<Display> display, Connection connected) { if (connected == Connection::Connected) { if (!display->isConnected()) { -#ifndef BYPASS_IHWC mComposer->setClientTargetSlotCount(display->getId()); -#endif display->loadConfigs(); display->setConnected(true); } @@ -345,21 +265,10 @@ void Device::loadCapabilities() { static_assert(sizeof(Capability) == sizeof(int32_t), "Capability size has changed"); -#ifdef BYPASS_IHWC - uint32_t numCapabilities = 0; - mHwcDevice->getCapabilities(mHwcDevice, &numCapabilities, nullptr); - std::vector<Capability> capabilities(numCapabilities); - auto asInt = reinterpret_cast<int32_t*>(capabilities.data()); - mHwcDevice->getCapabilities(mHwcDevice, &numCapabilities, asInt); - for (auto capability : capabilities) { - mCapabilities.emplace(capability); - } -#else auto capabilities = mComposer->getCapabilities(); for (auto capability : capabilities) { mCapabilities.emplace(static_cast<Capability>(capability)); } -#endif } bool Device::hasCapability(HWC2::Capability capability) const @@ -368,105 +277,6 @@ bool Device::hasCapability(HWC2::Capability capability) const capability) != mCapabilities.cend(); } -void Device::loadFunctionPointers() -{ -#ifdef BYPASS_IHWC - // For all of these early returns, we log an error message inside - // loadFunctionPointer specifying which function failed to load - - // Display function pointers - if (!loadFunctionPointer(FunctionDescriptor::CreateVirtualDisplay, - mCreateVirtualDisplay)) return; - if (!loadFunctionPointer(FunctionDescriptor::DestroyVirtualDisplay, - mDestroyVirtualDisplay)) return; - if (!loadFunctionPointer(FunctionDescriptor::Dump, mDump)) return; - if (!loadFunctionPointer(FunctionDescriptor::GetMaxVirtualDisplayCount, - mGetMaxVirtualDisplayCount)) return; - if (!loadFunctionPointer(FunctionDescriptor::RegisterCallback, - mRegisterCallback)) return; - - // Device function pointers - if (!loadFunctionPointer(FunctionDescriptor::AcceptDisplayChanges, - mAcceptDisplayChanges)) return; - if (!loadFunctionPointer(FunctionDescriptor::CreateLayer, - mCreateLayer)) return; - if (!loadFunctionPointer(FunctionDescriptor::DestroyLayer, - mDestroyLayer)) return; - if (!loadFunctionPointer(FunctionDescriptor::GetActiveConfig, - mGetActiveConfig)) return; - if (!loadFunctionPointer(FunctionDescriptor::GetChangedCompositionTypes, - mGetChangedCompositionTypes)) return; - if (!loadFunctionPointer(FunctionDescriptor::GetColorModes, - mGetColorModes)) return; - if (!loadFunctionPointer(FunctionDescriptor::GetDisplayAttribute, - mGetDisplayAttribute)) return; - if (!loadFunctionPointer(FunctionDescriptor::GetDisplayConfigs, - mGetDisplayConfigs)) return; - if (!loadFunctionPointer(FunctionDescriptor::GetDisplayName, - mGetDisplayName)) return; - if (!loadFunctionPointer(FunctionDescriptor::GetDisplayRequests, - mGetDisplayRequests)) return; - if (!loadFunctionPointer(FunctionDescriptor::GetDisplayType, - mGetDisplayType)) return; - if (!loadFunctionPointer(FunctionDescriptor::GetDozeSupport, - mGetDozeSupport)) return; - if (!loadFunctionPointer(FunctionDescriptor::GetHdrCapabilities, - mGetHdrCapabilities)) return; - if (!loadFunctionPointer(FunctionDescriptor::GetReleaseFences, - mGetReleaseFences)) return; - if (!loadFunctionPointer(FunctionDescriptor::PresentDisplay, - mPresentDisplay)) return; - if (!loadFunctionPointer(FunctionDescriptor::SetActiveConfig, - mSetActiveConfig)) return; - if (!loadFunctionPointer(FunctionDescriptor::SetClientTarget, - mSetClientTarget)) return; - if (!loadFunctionPointer(FunctionDescriptor::SetColorMode, - mSetColorMode)) return; - if (!loadFunctionPointer(FunctionDescriptor::SetColorTransform, - mSetColorTransform)) return; - if (!loadFunctionPointer(FunctionDescriptor::SetOutputBuffer, - mSetOutputBuffer)) return; - if (!loadFunctionPointer(FunctionDescriptor::SetPowerMode, - mSetPowerMode)) return; - if (!loadFunctionPointer(FunctionDescriptor::SetVsyncEnabled, - mSetVsyncEnabled)) return; - if (!loadFunctionPointer(FunctionDescriptor::ValidateDisplay, - mValidateDisplay)) return; - - // Layer function pointers - if (!loadFunctionPointer(FunctionDescriptor::SetCursorPosition, - mSetCursorPosition)) return; - if (!loadFunctionPointer(FunctionDescriptor::SetLayerBuffer, - mSetLayerBuffer)) return; - if (!loadFunctionPointer(FunctionDescriptor::SetLayerSurfaceDamage, - mSetLayerSurfaceDamage)) return; - if (!loadFunctionPointer(FunctionDescriptor::SetLayerBlendMode, - mSetLayerBlendMode)) return; - if (!loadFunctionPointer(FunctionDescriptor::SetLayerColor, - mSetLayerColor)) return; - if (!loadFunctionPointer(FunctionDescriptor::SetLayerCompositionType, - mSetLayerCompositionType)) return; - if (!loadFunctionPointer(FunctionDescriptor::SetLayerDataspace, - mSetLayerDataspace)) return; - if (!loadFunctionPointer(FunctionDescriptor::SetLayerDisplayFrame, - mSetLayerDisplayFrame)) return; - if (!loadFunctionPointer(FunctionDescriptor::SetLayerPlaneAlpha, - mSetLayerPlaneAlpha)) return; - if (hasCapability(Capability::SidebandStream)) { - if (!loadFunctionPointer(FunctionDescriptor::SetLayerSidebandStream, - mSetLayerSidebandStream)) return; - } - if (!loadFunctionPointer(FunctionDescriptor::SetLayerSourceCrop, - mSetLayerSourceCrop)) return; - if (!loadFunctionPointer(FunctionDescriptor::SetLayerTransform, - mSetLayerTransform)) return; - if (!loadFunctionPointer(FunctionDescriptor::SetLayerVisibleRegion, - mSetLayerVisibleRegion)) return; - if (!loadFunctionPointer(FunctionDescriptor::SetLayerZOrder, - mSetLayerZOrder)) return; -#endif // BYPASS_IHWC -} - namespace { class ComposerCallback : public Hwc2::IComposerCallback { public: @@ -498,14 +308,8 @@ private: void Device::registerCallbacks() { -#ifdef BYPASS_IHWC - registerCallback<HWC2_PFN_HOTPLUG>(Callback::Hotplug, hotplug_hook); - registerCallback<HWC2_PFN_REFRESH>(Callback::Refresh, refresh_hook); - registerCallback<HWC2_PFN_VSYNC>(Callback::Vsync, vsync_hook); -#else sp<ComposerCallback> callback = new ComposerCallback(this); mComposer->registerCallback(callback); -#endif } @@ -514,11 +318,7 @@ void Device::registerCallbacks() void Device::destroyVirtualDisplay(hwc2_display_t display) { ALOGI("Destroying virtual display"); -#ifdef BYPASS_IHWC - int32_t intError = mDestroyVirtualDisplay(mHwcDevice, display); -#else auto intError = mComposer->destroyVirtualDisplay(display); -#endif auto error = static_cast<Error>(intError); ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64 ") failed:" " %s (%d)", display, to_string(error).c_str(), intError); @@ -535,13 +335,8 @@ Display::Display(Device& device, hwc2_display_t id) { ALOGV("Created display %" PRIu64, id); -#ifdef BYPASS_IHWC - int32_t intError = mDevice.mGetDisplayType(mDevice.mHwcDevice, mId, - reinterpret_cast<int32_t *>(&mType)); -#else auto intError = mDevice.mComposer->getDisplayType(mId, reinterpret_cast<Hwc2::IComposerClient::DisplayType *>(&mType)); -#endif auto error = static_cast<Error>(intError); if (error != Error::None) { ALOGE("getDisplayType(%" PRIu64 ") failed: %s (%d)", @@ -588,22 +383,14 @@ float Display::Config::Builder::getDefaultDensity() { Error Display::acceptChanges() { -#ifdef BYPASS_IHWC - int32_t intError = mDevice.mAcceptDisplayChanges(mDevice.mHwcDevice, mId); -#else auto intError = mDevice.mComposer->acceptDisplayChanges(mId); -#endif return static_cast<Error>(intError); } Error Display::createLayer(std::shared_ptr<Layer>* outLayer) { hwc2_layer_t layerId = 0; -#ifdef BYPASS_IHWC - int32_t intError = mDevice.mCreateLayer(mDevice.mHwcDevice, mId, &layerId); -#else auto intError = mDevice.mComposer->createLayer(mId, &layerId); -#endif auto error = static_cast<Error>(intError); if (error != Error::None) { return error; @@ -620,12 +407,7 @@ Error Display::getActiveConfig( { ALOGV("[%" PRIu64 "] getActiveConfig", mId); hwc2_config_t configId = 0; -#ifdef BYPASS_IHWC - int32_t intError = mDevice.mGetActiveConfig(mDevice.mHwcDevice, mId, - &configId); -#else auto intError = mDevice.mComposer->getActiveConfig(mId, &configId); -#endif auto error = static_cast<Error>(intError); if (error != Error::None) { @@ -650,27 +432,12 @@ Error Display::getActiveConfig( Error Display::getChangedCompositionTypes( std::unordered_map<std::shared_ptr<Layer>, Composition>* outTypes) { -#ifdef BYPASS_IHWC - uint32_t numElements = 0; - int32_t intError = mDevice.mGetChangedCompositionTypes(mDevice.mHwcDevice, - mId, &numElements, nullptr, nullptr); - auto error = static_cast<Error>(intError); - if (error != Error::None) { - return error; - } - - std::vector<hwc2_layer_t> layerIds(numElements); - std::vector<int32_t> types(numElements); - intError = mDevice.mGetChangedCompositionTypes(mDevice.mHwcDevice, mId, - &numElements, layerIds.data(), types.data()); -#else std::vector<Hwc2::Layer> layerIds; std::vector<Hwc2::IComposerClient::Composition> types; auto intError = mDevice.mComposer->getChangedCompositionTypes(mId, &layerIds, &types); uint32_t numElements = layerIds.size(); auto error = static_cast<Error>(intError); -#endif error = static_cast<Error>(intError); if (error != Error::None) { return error; @@ -696,25 +463,10 @@ Error Display::getChangedCompositionTypes( Error Display::getColorModes(std::vector<android_color_mode_t>* outModes) const { -#ifdef BYPASS_IHWC - uint32_t numModes = 0; - int32_t intError = mDevice.mGetColorModes(mDevice.mHwcDevice, mId, - &numModes, nullptr); - auto error = static_cast<Error>(intError); - if (error != Error::None) { - return error; - } - - std::vector<int32_t> modes(numModes); - intError = mDevice.mGetColorModes(mDevice.mHwcDevice, mId, &numModes, - modes.data()); - error = static_cast<Error>(intError); -#else std::vector<Hwc2::ColorMode> modes; auto intError = mDevice.mComposer->getColorModes(mId, &modes); uint32_t numModes = modes.size(); auto error = static_cast<Error>(intError); -#endif if (error != Error::None) { return error; } @@ -737,52 +489,14 @@ std::vector<std::shared_ptr<const Display::Config>> Display::getConfigs() const Error Display::getName(std::string* outName) const { -#ifdef BYPASS_IHWC - uint32_t size; - int32_t intError = mDevice.mGetDisplayName(mDevice.mHwcDevice, mId, &size, - nullptr); - auto error = static_cast<Error>(intError); - if (error != Error::None) { - return error; - } - - std::vector<char> rawName(size); - intError = mDevice.mGetDisplayName(mDevice.mHwcDevice, mId, &size, - rawName.data()); - error = static_cast<Error>(intError); - if (error != Error::None) { - return error; - } - - *outName = std::string(rawName.cbegin(), rawName.cend()); - return Error::None; -#else auto intError = mDevice.mComposer->getDisplayName(mId, outName); return static_cast<Error>(intError); -#endif } Error Display::getRequests(HWC2::DisplayRequest* outDisplayRequests, std::unordered_map<std::shared_ptr<Layer>, LayerRequest>* outLayerRequests) { -#ifdef BYPASS_IHWC - int32_t intDisplayRequests = 0; - uint32_t numElements = 0; - int32_t intError = mDevice.mGetDisplayRequests(mDevice.mHwcDevice, mId, - &intDisplayRequests, &numElements, nullptr, nullptr); - auto error = static_cast<Error>(intError); - if (error != Error::None) { - return error; - } - - std::vector<hwc2_layer_t> layerIds(numElements); - std::vector<int32_t> layerRequests(numElements); - intError = mDevice.mGetDisplayRequests(mDevice.mHwcDevice, mId, - &intDisplayRequests, &numElements, layerIds.data(), - layerRequests.data()); - error = static_cast<Error>(intError); -#else uint32_t intDisplayRequests; std::vector<Hwc2::Layer> layerIds; std::vector<uint32_t> layerRequests; @@ -790,7 +504,6 @@ Error Display::getRequests(HWC2::DisplayRequest* outDisplayRequests, &intDisplayRequests, &layerIds, &layerRequests); uint32_t numElements = layerIds.size(); auto error = static_cast<Error>(intError); -#endif if (error != Error::None) { return error; } @@ -821,14 +534,8 @@ Error Display::getType(DisplayType* outType) const Error Display::supportsDoze(bool* outSupport) const { -#ifdef BYPASS_IHWC - int32_t intSupport = 0; - int32_t intError = mDevice.mGetDozeSupport(mDevice.mHwcDevice, mId, - &intSupport); -#else bool intSupport = false; auto intError = mDevice.mComposer->getDozeSupport(mId, &intSupport); -#endif auto error = static_cast<Error>(intError); if (error != Error::None) { return error; @@ -844,20 +551,6 @@ Error Display::getHdrCapabilities( float maxLuminance = -1.0f; float maxAverageLuminance = -1.0f; float minLuminance = -1.0f; -#ifdef BYPASS_IHWC - int32_t intError = mDevice.mGetHdrCapabilities(mDevice.mHwcDevice, mId, - &numTypes, nullptr, &maxLuminance, &maxAverageLuminance, - &minLuminance); - auto error = static_cast<HWC2::Error>(intError); - if (error != Error::None) { - return error; - } - - std::vector<int32_t> types(numTypes); - intError = mDevice.mGetHdrCapabilities(mDevice.mHwcDevice, mId, &numTypes, - types.data(), &maxLuminance, &maxAverageLuminance, &minLuminance); - error = static_cast<HWC2::Error>(intError); -#else std::vector<Hwc2::Hdr> intTypes; auto intError = mDevice.mComposer->getHdrCapabilities(mId, &intTypes, &maxLuminance, &maxAverageLuminance, &minLuminance); @@ -868,7 +561,6 @@ Error Display::getHdrCapabilities( types.push_back(static_cast<int32_t>(type)); } numTypes = types.size(); -#endif if (error != Error::None) { return error; } @@ -881,28 +573,12 @@ Error Display::getHdrCapabilities( Error Display::getReleaseFences( std::unordered_map<std::shared_ptr<Layer>, sp<Fence>>* outFences) const { -#ifdef BYPASS_IHWC - uint32_t numElements = 0; - int32_t intError = mDevice.mGetReleaseFences(mDevice.mHwcDevice, mId, - &numElements, nullptr, nullptr); - auto error = static_cast<Error>(intError); - if (error != Error::None) { - return error; - } - - std::vector<hwc2_layer_t> layerIds(numElements); - std::vector<int32_t> fenceFds(numElements); - intError = mDevice.mGetReleaseFences(mDevice.mHwcDevice, mId, &numElements, - layerIds.data(), fenceFds.data()); - error = static_cast<Error>(intError); -#else std::vector<Hwc2::Layer> layerIds; std::vector<int> fenceFds; auto intError = mDevice.mComposer->getReleaseFences(mId, &layerIds, &fenceFds); auto error = static_cast<Error>(intError); uint32_t numElements = layerIds.size(); -#endif if (error != Error::None) { return error; } @@ -931,12 +607,7 @@ Error Display::getReleaseFences( Error Display::present(sp<Fence>* outPresentFence) { int32_t presentFenceFd = -1; -#ifdef BYPASS_IHWC - int32_t intError = mDevice.mPresentDisplay(mDevice.mHwcDevice, mId, - &presentFenceFd); -#else auto intError = mDevice.mComposer->presentDisplay(mId, &presentFenceFd); -#endif auto error = static_cast<Error>(intError); if (error != Error::None) { return error; @@ -954,12 +625,7 @@ Error Display::setActiveConfig(const std::shared_ptr<const Config>& config) config->getDisplayId(), mId); return Error::BadConfig; } -#ifdef BYPASS_IHWC - int32_t intError = mDevice.mSetActiveConfig(mDevice.mHwcDevice, mId, - config->getId()); -#else auto intError = mDevice.mComposer->setActiveConfig(mId, config->getId()); -#endif return static_cast<Error>(intError); } @@ -968,44 +634,24 @@ Error Display::setClientTarget(uint32_t slot, const sp<GraphicBuffer>& target, { // TODO: Properly encode client target surface damage int32_t fenceFd = acquireFence->dup(); -#ifdef BYPASS_IHWC - (void) slot; - buffer_handle_t handle = nullptr; - if (target.get() && target->getNativeBuffer()) { - handle = target->getNativeBuffer()->handle; - } - - int32_t intError = mDevice.mSetClientTarget(mDevice.mHwcDevice, mId, handle, - fenceFd, static_cast<int32_t>(dataspace), {0, nullptr}); -#else auto intError = mDevice.mComposer->setClientTarget(mId, slot, target, fenceFd, static_cast<Hwc2::Dataspace>(dataspace), std::vector<Hwc2::IComposerClient::Rect>()); -#endif return static_cast<Error>(intError); } Error Display::setColorMode(android_color_mode_t mode) { -#ifdef BYPASS_IHWC - int32_t intError = mDevice.mSetColorMode(mDevice.mHwcDevice, mId, mode); -#else auto intError = mDevice.mComposer->setColorMode(mId, static_cast<Hwc2::ColorMode>(mode)); -#endif return static_cast<Error>(intError); } Error Display::setColorTransform(const android::mat4& matrix, android_color_transform_t hint) { -#ifdef BYPASS_IHWC - int32_t intError = mDevice.mSetColorTransform(mDevice.mHwcDevice, mId, - matrix.asArray(), static_cast<int32_t>(hint)); -#else auto intError = mDevice.mComposer->setColorTransform(mId, matrix.asArray(), static_cast<Hwc2::ColorTransform>(hint)); -#endif return static_cast<Error>(intError); } @@ -1014,38 +660,22 @@ Error Display::setOutputBuffer(const sp<GraphicBuffer>& buffer, { int32_t fenceFd = releaseFence->dup(); auto handle = buffer->getNativeBuffer()->handle; -#ifdef BYPASS_IHWC - int32_t intError = mDevice.mSetOutputBuffer(mDevice.mHwcDevice, mId, handle, - fenceFd); -#else auto intError = mDevice.mComposer->setOutputBuffer(mId, handle, fenceFd); -#endif close(fenceFd); return static_cast<Error>(intError); } Error Display::setPowerMode(PowerMode mode) { -#ifdef BYPASS_IHWC - auto intMode = static_cast<int32_t>(mode); - int32_t intError = mDevice.mSetPowerMode(mDevice.mHwcDevice, mId, intMode); -#else auto intMode = static_cast<Hwc2::IComposerClient::PowerMode>(mode); auto intError = mDevice.mComposer->setPowerMode(mId, intMode); -#endif return static_cast<Error>(intError); } Error Display::setVsyncEnabled(Vsync enabled) { -#ifdef BYPASS_IHWC - auto intEnabled = static_cast<int32_t>(enabled); - int32_t intError = mDevice.mSetVsyncEnabled(mDevice.mHwcDevice, mId, - intEnabled); -#else auto intEnabled = static_cast<Hwc2::IComposerClient::Vsync>(enabled); auto intError = mDevice.mComposer->setVsyncEnabled(mId, intEnabled); -#endif return static_cast<Error>(intError); } @@ -1053,13 +683,8 @@ Error Display::validate(uint32_t* outNumTypes, uint32_t* outNumRequests) { uint32_t numTypes = 0; uint32_t numRequests = 0; -#ifdef BYPASS_IHWC - int32_t intError = mDevice.mValidateDisplay(mDevice.mHwcDevice, mId, - &numTypes, &numRequests); -#else auto intError = mDevice.mComposer->validateDisplay(mId, &numTypes, &numRequests); -#endif auto error = static_cast<Error>(intError); if (error != Error::None && error != Error::HasChanges) { return error; @@ -1075,14 +700,9 @@ Error Display::validate(uint32_t* outNumTypes, uint32_t* outNumRequests) int32_t Display::getAttribute(hwc2_config_t configId, Attribute attribute) { int32_t value = 0; -#ifdef BYPASS_IHWC - int32_t intError = mDevice.mGetDisplayAttribute(mDevice.mHwcDevice, mId, - configId, static_cast<int32_t>(attribute), &value); -#else auto intError = mDevice.mComposer->getDisplayAttribute(mId, configId, static_cast<Hwc2::IComposerClient::Attribute>(attribute), &value); -#endif auto error = static_cast<Error>(intError); if (error != Error::None) { ALOGE("getDisplayAttribute(%" PRIu64 ", %u, %s) failed: %s (%d)", mId, @@ -1111,26 +731,9 @@ void Display::loadConfigs() { ALOGV("[%" PRIu64 "] loadConfigs", mId); -#ifdef BYPASS_IHWC - uint32_t numConfigs = 0; - int32_t intError = mDevice.mGetDisplayConfigs(mDevice.mHwcDevice, mId, - &numConfigs, nullptr); - auto error = static_cast<Error>(intError); - if (error != Error::None) { - ALOGE("[%" PRIu64 "] getDisplayConfigs [1] failed: %s (%d)", mId, - to_string(error).c_str(), intError); - return; - } - - std::vector<hwc2_config_t> configIds(numConfigs); - intError = mDevice.mGetDisplayConfigs(mDevice.mHwcDevice, mId, &numConfigs, - configIds.data()); - error = static_cast<Error>(intError); -#else std::vector<Hwc2::Config> configIds; auto intError = mDevice.mComposer->getDisplayConfigs(mId, &configIds); auto error = static_cast<Error>(intError); -#endif if (error != Error::None) { ALOGE("[%" PRIu64 "] getDisplayConfigs [2] failed: %s (%d)", mId, to_string(error).c_str(), intError); @@ -1146,11 +749,7 @@ void Display::loadConfigs() void Display::destroyLayer(hwc2_layer_t layerId) { -#ifdef BYPASS_IHWC - int32_t intError = mDevice.mDestroyLayer(mDevice.mHwcDevice, mId, layerId); -#else auto intError =mDevice.mComposer->destroyLayer(mId, layerId); -#endif auto error = static_cast<Error>(intError); ALOGE_IF(error != Error::None, "destroyLayer(%" PRIu64 ", %" PRIu64 ")" " failed: %s (%d)", mId, layerId, to_string(error).c_str(), @@ -1192,13 +791,8 @@ Layer::~Layer() Error Layer::setCursorPosition(int32_t x, int32_t y) { -#ifdef BYPASS_IHWC - int32_t intError = mDevice.mSetCursorPosition(mDevice.mHwcDevice, - mDisplayId, mId, x, y); -#else auto intError = mDevice.mComposer->setCursorPosition(mDisplayId, mId, x, y); -#endif return static_cast<Error>(intError); } @@ -1206,19 +800,8 @@ Error Layer::setBuffer(uint32_t slot, const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence) { int32_t fenceFd = acquireFence->dup(); -#ifdef BYPASS_IHWC - (void) slot; - buffer_handle_t handle = nullptr; - if (buffer.get() && buffer->getNativeBuffer()) { - handle = buffer->getNativeBuffer()->handle; - } - - int32_t intError = mDevice.mSetLayerBuffer(mDevice.mHwcDevice, mDisplayId, - mId, handle, fenceFd); -#else auto intError = mDevice.mComposer->setLayerBuffer(mDisplayId, mId, slot, buffer, fenceFd); -#endif return static_cast<Error>(intError); } @@ -1226,44 +809,22 @@ Error Layer::setSurfaceDamage(const Region& damage) { // We encode default full-screen damage as INVALID_RECT upstream, but as 0 // rects for HWC -#ifdef BYPASS_IHWC - int32_t intError = 0; -#else Hwc2::Error intError = Hwc2::Error::NONE; -#endif if (damage.isRect() && damage.getBounds() == Rect::INVALID_RECT) { -#ifdef BYPASS_IHWC - intError = mDevice.mSetLayerSurfaceDamage(mDevice.mHwcDevice, - mDisplayId, mId, {0, nullptr}); -#else intError = mDevice.mComposer->setLayerSurfaceDamage(mDisplayId, mId, std::vector<Hwc2::IComposerClient::Rect>()); -#endif } else { size_t rectCount = 0; auto rectArray = damage.getArray(&rectCount); -#ifdef BYPASS_IHWC - std::vector<hwc_rect_t> hwcRects; -#else std::vector<Hwc2::IComposerClient::Rect> hwcRects; -#endif for (size_t rect = 0; rect < rectCount; ++rect) { hwcRects.push_back({rectArray[rect].left, rectArray[rect].top, rectArray[rect].right, rectArray[rect].bottom}); } -#ifdef BYPASS_IHWC - hwc_region_t hwcRegion = {}; - hwcRegion.numRects = rectCount; - hwcRegion.rects = hwcRects.data(); - - intError = mDevice.mSetLayerSurfaceDamage(mDevice.mHwcDevice, - mDisplayId, mId, hwcRegion); -#else intError = mDevice.mComposer->setLayerSurfaceDamage(mDisplayId, mId, hwcRects); -#endif } return static_cast<Error>(intError); @@ -1271,83 +832,49 @@ Error Layer::setSurfaceDamage(const Region& damage) Error Layer::setBlendMode(BlendMode mode) { -#ifdef BYPASS_IHWC - auto intMode = static_cast<int32_t>(mode); - int32_t intError = mDevice.mSetLayerBlendMode(mDevice.mHwcDevice, - mDisplayId, mId, intMode); -#else auto intMode = static_cast<Hwc2::IComposerClient::BlendMode>(mode); auto intError = mDevice.mComposer->setLayerBlendMode(mDisplayId, mId, intMode); -#endif return static_cast<Error>(intError); } Error Layer::setColor(hwc_color_t color) { -#ifdef BYPASS_IHWC - int32_t intError = mDevice.mSetLayerColor(mDevice.mHwcDevice, mDisplayId, - mId, color); -#else Hwc2::IComposerClient::Color hwcColor{color.r, color.g, color.b, color.a}; auto intError = mDevice.mComposer->setLayerColor(mDisplayId, mId, hwcColor); -#endif return static_cast<Error>(intError); } Error Layer::setCompositionType(Composition type) { -#ifdef BYPASS_IHWC - auto intType = static_cast<int32_t>(type); - int32_t intError = mDevice.mSetLayerCompositionType(mDevice.mHwcDevice, - mDisplayId, mId, intType); -#else auto intType = static_cast<Hwc2::IComposerClient::Composition>(type); auto intError = mDevice.mComposer->setLayerCompositionType(mDisplayId, mId, intType); -#endif return static_cast<Error>(intError); } Error Layer::setDataspace(android_dataspace_t dataspace) { -#ifdef BYPASS_IHWC - auto intDataspace = static_cast<int32_t>(dataspace); - int32_t intError = mDevice.mSetLayerDataspace(mDevice.mHwcDevice, - mDisplayId, mId, intDataspace); -#else auto intDataspace = static_cast<Hwc2::Dataspace>(dataspace); auto intError = mDevice.mComposer->setLayerDataspace(mDisplayId, mId, intDataspace); -#endif return static_cast<Error>(intError); } Error Layer::setDisplayFrame(const Rect& frame) { -#ifdef BYPASS_IHWC - hwc_rect_t hwcRect{frame.left, frame.top, frame.right, frame.bottom}; - int32_t intError = mDevice.mSetLayerDisplayFrame(mDevice.mHwcDevice, - mDisplayId, mId, hwcRect); -#else Hwc2::IComposerClient::Rect hwcRect{frame.left, frame.top, frame.right, frame.bottom}; auto intError = mDevice.mComposer->setLayerDisplayFrame(mDisplayId, mId, hwcRect); -#endif return static_cast<Error>(intError); } Error Layer::setPlaneAlpha(float alpha) { -#ifdef BYPASS_IHWC - int32_t intError = mDevice.mSetLayerPlaneAlpha(mDevice.mHwcDevice, - mDisplayId, mId, alpha); -#else auto intError = mDevice.mComposer->setLayerPlaneAlpha(mDisplayId, mId, alpha); -#endif return static_cast<Error>(intError); } @@ -1358,42 +885,25 @@ Error Layer::setSidebandStream(const native_handle_t* stream) "device supports sideband streams"); return Error::Unsupported; } -#ifdef BYPASS_IHWC - int32_t intError = mDevice.mSetLayerSidebandStream(mDevice.mHwcDevice, - mDisplayId, mId, stream); -#else auto intError = mDevice.mComposer->setLayerSidebandStream(mDisplayId, mId, stream); -#endif return static_cast<Error>(intError); } Error Layer::setSourceCrop(const FloatRect& crop) { -#ifdef BYPASS_IHWC - hwc_frect_t hwcRect{crop.left, crop.top, crop.right, crop.bottom}; - int32_t intError = mDevice.mSetLayerSourceCrop(mDevice.mHwcDevice, - mDisplayId, mId, hwcRect); -#else Hwc2::IComposerClient::FRect hwcRect{ crop.left, crop.top, crop.right, crop.bottom}; auto intError = mDevice.mComposer->setLayerSourceCrop(mDisplayId, mId, hwcRect); -#endif return static_cast<Error>(intError); } Error Layer::setTransform(Transform transform) { -#ifdef BYPASS_IHWC - auto intTransform = static_cast<int32_t>(transform); - int32_t intError = mDevice.mSetLayerTransform(mDevice.mHwcDevice, - mDisplayId, mId, intTransform); -#else auto intTransform = static_cast<Hwc2::Transform>(transform); auto intError = mDevice.mComposer->setLayerTransform(mDisplayId, mId, intTransform); -#endif return static_cast<Error>(intError); } @@ -1402,50 +912,26 @@ Error Layer::setVisibleRegion(const Region& region) size_t rectCount = 0; auto rectArray = region.getArray(&rectCount); -#ifdef BYPASS_IHWC - std::vector<hwc_rect_t> hwcRects; -#else std::vector<Hwc2::IComposerClient::Rect> hwcRects; -#endif for (size_t rect = 0; rect < rectCount; ++rect) { hwcRects.push_back({rectArray[rect].left, rectArray[rect].top, rectArray[rect].right, rectArray[rect].bottom}); } -#ifdef BYPASS_IHWC - hwc_region_t hwcRegion = {}; - hwcRegion.numRects = rectCount; - hwcRegion.rects = hwcRects.data(); - - int32_t intError = mDevice.mSetLayerVisibleRegion(mDevice.mHwcDevice, - mDisplayId, mId, hwcRegion); -#else auto intError = mDevice.mComposer->setLayerVisibleRegion(mDisplayId, mId, hwcRects); -#endif return static_cast<Error>(intError); } Error Layer::setZOrder(uint32_t z) { -#ifdef BYPASS_IHWC - int32_t intError = mDevice.mSetLayerZOrder(mDevice.mHwcDevice, mDisplayId, - mId, z); -#else auto intError = mDevice.mComposer->setLayerZOrder(mDisplayId, mId, z); -#endif return static_cast<Error>(intError); } Error Layer::setInfo(uint32_t type, uint32_t appId) { -#ifdef BYPASS_IHWC - (void)type; - (void)appId; - int32_t intError = 0; -#else auto intError = mDevice.mComposer->setLayerInfo(mDisplayId, mId, type, appId); -#endif return static_cast<Error>(intError); } diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 643b1e00b3..97582a7a99 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -62,14 +62,10 @@ typedef std::function<void(std::shared_ptr<Display>, nsecs_t)> VsyncCallback; class Device { public: -#ifdef BYPASS_IHWC - explicit Device(hwc2_device_t* device); -#else // useVrComposer is passed to the composer HAL. When true, the composer HAL // will use the vr composer service, otherwise it uses the real hardware // composer. Device(bool useVrComposer); -#endif ~Device(); friend class HWC2::Display; @@ -107,43 +103,12 @@ public: bool hasCapability(HWC2::Capability capability) const; -#ifdef BYPASS_IHWC - android::Hwc2::Composer* getComposer() { return nullptr; } -#else android::Hwc2::Composer* getComposer() { return mComposer.get(); } -#endif private: // Initialization methods -#ifdef BYPASS_IHWC - template <typename PFN> - [[clang::warn_unused_result]] bool loadFunctionPointer( - FunctionDescriptor desc, PFN& outPFN) { - auto intDesc = static_cast<int32_t>(desc); - auto pfn = mHwcDevice->getFunction(mHwcDevice, intDesc); - if (pfn != nullptr) { - outPFN = reinterpret_cast<PFN>(pfn); - return true; - } else { - ALOGE("Failed to load function %s", to_string(desc).c_str()); - return false; - } - } - - template <typename PFN, typename HOOK> - void registerCallback(Callback callback, HOOK hook) { - static_assert(std::is_same<PFN, HOOK>::value, - "Incompatible function pointer"); - auto intCallback = static_cast<int32_t>(callback); - auto callbackData = static_cast<hwc2_callback_data_t>(this); - auto pfn = reinterpret_cast<hwc2_function_pointer_t>(hook); - mRegisterCallback(mHwcDevice, intCallback, callbackData, pfn); - } -#endif - void loadCapabilities(); - void loadFunctionPointers(); void registerCallbacks(); // For use by Display @@ -151,60 +116,7 @@ private: void destroyVirtualDisplay(hwc2_display_t display); // Member variables - -#ifdef BYPASS_IHWC - hwc2_device_t* mHwcDevice; - - // Device function pointers - HWC2_PFN_CREATE_VIRTUAL_DISPLAY mCreateVirtualDisplay; - HWC2_PFN_DESTROY_VIRTUAL_DISPLAY mDestroyVirtualDisplay; - HWC2_PFN_DUMP mDump; - HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT mGetMaxVirtualDisplayCount; - HWC2_PFN_REGISTER_CALLBACK mRegisterCallback; - - // Display function pointers - HWC2_PFN_ACCEPT_DISPLAY_CHANGES mAcceptDisplayChanges; - HWC2_PFN_CREATE_LAYER mCreateLayer; - HWC2_PFN_DESTROY_LAYER mDestroyLayer; - HWC2_PFN_GET_ACTIVE_CONFIG mGetActiveConfig; - HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES mGetChangedCompositionTypes; - HWC2_PFN_GET_COLOR_MODES mGetColorModes; - HWC2_PFN_GET_DISPLAY_ATTRIBUTE mGetDisplayAttribute; - HWC2_PFN_GET_DISPLAY_CONFIGS mGetDisplayConfigs; - HWC2_PFN_GET_DISPLAY_NAME mGetDisplayName; - HWC2_PFN_GET_DISPLAY_REQUESTS mGetDisplayRequests; - HWC2_PFN_GET_DISPLAY_TYPE mGetDisplayType; - HWC2_PFN_GET_DOZE_SUPPORT mGetDozeSupport; - HWC2_PFN_GET_HDR_CAPABILITIES mGetHdrCapabilities; - HWC2_PFN_GET_RELEASE_FENCES mGetReleaseFences; - HWC2_PFN_PRESENT_DISPLAY mPresentDisplay; - HWC2_PFN_SET_ACTIVE_CONFIG mSetActiveConfig; - HWC2_PFN_SET_CLIENT_TARGET mSetClientTarget; - HWC2_PFN_SET_COLOR_MODE mSetColorMode; - HWC2_PFN_SET_COLOR_TRANSFORM mSetColorTransform; - HWC2_PFN_SET_OUTPUT_BUFFER mSetOutputBuffer; - HWC2_PFN_SET_POWER_MODE mSetPowerMode; - HWC2_PFN_SET_VSYNC_ENABLED mSetVsyncEnabled; - HWC2_PFN_VALIDATE_DISPLAY mValidateDisplay; - - // Layer function pointers - HWC2_PFN_SET_CURSOR_POSITION mSetCursorPosition; - HWC2_PFN_SET_LAYER_BUFFER mSetLayerBuffer; - HWC2_PFN_SET_LAYER_SURFACE_DAMAGE mSetLayerSurfaceDamage; - HWC2_PFN_SET_LAYER_BLEND_MODE mSetLayerBlendMode; - HWC2_PFN_SET_LAYER_COLOR mSetLayerColor; - HWC2_PFN_SET_LAYER_COMPOSITION_TYPE mSetLayerCompositionType; - HWC2_PFN_SET_LAYER_DATASPACE mSetLayerDataspace; - HWC2_PFN_SET_LAYER_DISPLAY_FRAME mSetLayerDisplayFrame; - HWC2_PFN_SET_LAYER_PLANE_ALPHA mSetLayerPlaneAlpha; - HWC2_PFN_SET_LAYER_SIDEBAND_STREAM mSetLayerSidebandStream; - HWC2_PFN_SET_LAYER_SOURCE_CROP mSetLayerSourceCrop; - HWC2_PFN_SET_LAYER_TRANSFORM mSetLayerTransform; - HWC2_PFN_SET_LAYER_VISIBLE_REGION mSetLayerVisibleRegion; - HWC2_PFN_SET_LAYER_Z_ORDER mSetLayerZOrder; -#else std::unique_ptr<android::Hwc2::Composer> mComposer; -#endif // BYPASS_IHWC std::unordered_set<Capability> mCapabilities; std::unordered_map<hwc2_display_t, std::weak_ptr<Display>> mDisplays; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 04ab78fd00..42be935c71 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -47,7 +47,6 @@ #include <log/log.h> #include "HWComposer.h" -#include "hwc2on1adapter/HWC2On1Adapter.h" #include "HWC2.h" #include "ComposerHal.h" @@ -61,8 +60,7 @@ namespace android { // --------------------------------------------------------------------------- HWComposer::HWComposer(bool useVrComposer) - : mAdapter(), - mHwcDevice(), + : mHwcDevice(), mDisplayData(2), mFreeDisplaySlots(), mHwcDisplaySlots(), @@ -108,45 +106,7 @@ void HWComposer::setEventHandler(EventHandler* handler) void HWComposer::loadHwcModule(bool useVrComposer) { ALOGV("loadHwcModule"); - -#ifdef BYPASS_IHWC - (void)useVrComposer; // Silence unused parameter warning. - - hw_module_t const* module; - - if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) { - ALOGE("%s module not found, aborting", HWC_HARDWARE_MODULE_ID); - abort(); - } - - hw_device_t* device = nullptr; - int error = module->methods->open(module, HWC_HARDWARE_COMPOSER, &device); - if (error != 0) { - ALOGE("Failed to open HWC device (%s), aborting", strerror(-error)); - abort(); - } - - uint32_t majorVersion = (device->version >> 24) & 0xF; - if (majorVersion == 2) { - mHwcDevice = std::make_unique<HWC2::Device>( - reinterpret_cast<hwc2_device_t*>(device)); - } else { - mAdapter = std::make_unique<HWC2On1Adapter>( - reinterpret_cast<hwc_composer_device_1_t*>(device)); - uint8_t minorVersion = mAdapter->getHwc1MinorVersion(); - if (minorVersion < 1) { - ALOGE("Cannot adapt to HWC version %d.%d", - static_cast<int32_t>((minorVersion >> 8) & 0xF), - static_cast<int32_t>(minorVersion & 0xF)); - abort(); - } - mHwcDevice = std::make_unique<HWC2::Device>( - static_cast<hwc2_device_t*>(mAdapter.get())); - } -#else mHwcDevice = std::make_unique<HWC2::Device>(useVrComposer); -#endif - mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount(); } @@ -870,11 +830,7 @@ static String8 getFormatStr(PixelFormat format) { */ bool HWComposer::isUsingVrComposer() const { -#ifdef BYPASS_IHWC - return false; -#else return getComposer()->isUsingVrComposer(); -#endif } void HWComposer::dump(String8& result) const { diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 631af14615..3eb968d7ce 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -58,7 +58,6 @@ class DisplayDevice; class Fence; class FloatRect; class GraphicBuffer; -class HWC2On1Adapter; class NativeHandle; class Region; class String8; @@ -205,7 +204,6 @@ private: HWC2::Vsync vsyncEnabled; }; - std::unique_ptr<HWC2On1Adapter> mAdapter; std::unique_ptr<HWC2::Device> mHwcDevice; std::vector<DisplayData> mDisplayData; std::set<size_t> mFreeDisplaySlots; diff --git a/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.cpp b/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.cpp index 6b9122473f..a234b6315e 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.cpp @@ -29,10 +29,6 @@ void HWComposerBufferCache::getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot, sp<GraphicBuffer>* outBuffer) { -#ifdef BYPASS_IHWC - *outSlot = slot; - *outBuffer = buffer; -#else if (slot == BufferQueue::INVALID_BUFFER_SLOT || slot < 0) { // default to slot 0 slot = 0; @@ -53,7 +49,6 @@ void HWComposerBufferCache::getHwcBuffer(int slot, // update cache mBuffers[slot] = buffer; } -#endif } } // namespace android diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index 8217540215..6e843d9f33 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -22,6 +22,7 @@ #include <gui/BufferItem.h> #include <gui/BufferQueue.h> #include <gui/IProducerListener.h> +#include <system/window.h> // --------------------------------------------------------------------------- namespace android { diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index b43b30d53d..0f93cd7819 100755 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -34,6 +34,7 @@ #include <utils/StopWatch.h> #include <utils/Trace.h> +#include <ui/DebugUtils.h> #include <ui/GraphicBuffer.h> #include <ui/PixelFormat.h> @@ -125,6 +126,7 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, mPremultipliedAlpha = false; mName = name; + mTransactionName = String8("TX - ") + mName; mCurrentState.active.w = w; mCurrentState.active.h = h; @@ -882,9 +884,6 @@ void Layer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) { } } -android_dataspace Layer::getDataSpace() const { - return mCurrentState.dataSpace; -} #else void Layer::setPerFrameData(const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface& layer) { @@ -1493,6 +1492,7 @@ void Layer::pushPendingState() { mFlinger->setTransactionFlags(eTraversalNeeded); } mPendingStates.push_back(mCurrentState); + ATRACE_INT(mTransactionName.string(), mPendingStates.size()); } void Layer::popPendingState(State* stateToCommit) { @@ -1502,6 +1502,7 @@ void Layer::popPendingState(State* stateToCommit) { (stateToCommit->flags & stateToCommit->mask); mPendingStates.removeAt(0); + ATRACE_INT(mTransactionName.string(), mPendingStates.size()); } bool Layer::applyPendingStates(State* stateToCommit) { @@ -1895,6 +1896,10 @@ bool Layer::setDataSpace(android_dataspace dataSpace) { return true; } +android_dataspace Layer::getDataSpace() const { + return mCurrentState.dataSpace; +} + uint32_t Layer::getLayerStack() const { auto p = getParent(); if (p == nullptr) { @@ -2340,11 +2345,17 @@ void Layer::dump(String8& result, Colorizer& colorizer) const visibleRegion.dump(result, "visibleRegion"); surfaceDamageRegion.dump(result, "surfaceDamageRegion"); sp<Client> client(mClientRef.promote()); + PixelFormat pf = PIXEL_FORMAT_UNKNOWN; + const sp<GraphicBuffer>& buffer(getActiveBuffer()); + if (buffer != NULL) { + pf = buffer->getPixelFormat(); + } result.appendFormat( " " "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), " "crop=(%4d,%4d,%4d,%4d), finalCrop=(%4d,%4d,%4d,%4d), " "isOpaque=%1d, invalidate=%1d, " + "dataspace=%s, pixelformat=%s " #ifdef USE_HWC2 "alpha=%.3f, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n" #else @@ -2359,6 +2370,7 @@ void Layer::dump(String8& result, Colorizer& colorizer) const s.finalCrop.left, s.finalCrop.top, s.finalCrop.right, s.finalCrop.bottom, isOpaque(s), contentDirty, + dataspaceDetails(getDataSpace()).c_str(), decodePixelFormat(pf).c_str(), s.alpha, s.flags, s.active.transform[0][0], s.active.transform[0][1], s.active.transform[1][0], s.active.transform[1][1], diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 9f45435327..d1ef57d362 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -192,6 +192,7 @@ public: bool setFlags(uint8_t flags, uint8_t mask); bool setLayerStack(uint32_t layerStack); bool setDataSpace(android_dataspace dataSpace); + android_dataspace getDataSpace() const; uint32_t getLayerStack() const; void deferTransactionUntil(const sp<IBinder>& barrierHandle, uint64_t frameNumber); void deferTransactionUntil(const sp<Layer>& barrierLayer, uint64_t frameNumber); @@ -275,8 +276,6 @@ public: void forceClientComposition(int32_t hwcId); void setPerFrameData(const sp<const DisplayDevice>& displayDevice); - android_dataspace getDataSpace() const; - // callIntoHwc exists so we can update our local state and call // acceptDisplayChanges without unnecessarily updating the device's state void setCompositionType(int32_t hwcId, HWC2::Composition type, @@ -658,6 +657,7 @@ private: uint32_t mTextureName; // from GLES bool mPremultipliedAlpha; String8 mName; + String8 mTransactionName; // A cached version of "TX - " + mName for systraces PixelFormat mFormat; // these are protected by an external lock diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp index 0b302ebe03..f1524956ee 100644 --- a/services/surfaceflinger/LayerRejecter.cpp +++ b/services/surfaceflinger/LayerRejecter.cpp @@ -17,6 +17,7 @@ #include "LayerRejecter.h" #include <gui/BufferItem.h> +#include <system/window.h> #include "clz.h" diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp index 04fe1824b4..18b2e1b30e 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp @@ -143,7 +143,7 @@ GLES20RenderEngine::GLES20RenderEngine() : // Compute sRGB to DisplayP3 color transform // NOTE: For now, we are limiting wide-color support to // Display-P3 only. - mat3 srgbToP3 = ColorSpace::DisplayP3().getXYZtoRGB() * ColorSpace::sRGB().getRGBtoXYZ(); + mat3 srgbToP3 = ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::DisplayP3()).getTransform(); // color transform needs to be transposed and expanded to 4x4 // to be what the shader wants diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp index 75642699c3..f8785dbf76 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp @@ -54,12 +54,16 @@ RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat) { // both a 16-bit primary display framebuffer and a 32-bit virtual display // framebuffer. // + // EGL_KHR_no_config_context is official extension to allow creating a + // context that works with any surface of a display. + // // The code assumes that ES2 or later is available if this extension is // supported. EGLConfig config = EGL_NO_CONFIG; - if (!findExtension( - eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS), - "EGL_ANDROIDX_no_config_context")) { + if (!findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS), + "EGL_ANDROIDX_no_config_context") && + !findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS), + "EGL_KHR_no_config_context")) { config = chooseEglConfig(display, hwcFormat); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 29a8292ff6..12afdf7a3a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2651,6 +2651,8 @@ status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, { Mutex::Autolock _l(mStateLock); if (mNumLayers >= MAX_LAYERS) { + ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers, + MAX_LAYERS); return NO_MEMORY; } if (parent == nullptr) { @@ -3184,7 +3186,8 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, if (currentMode == HWC_POWER_MODE_OFF) { // Turn on the display getHwComposer().setPowerMode(type, mode); - if (type == DisplayDevice::DISPLAY_PRIMARY) { + if (type == DisplayDevice::DISPLAY_PRIMARY && + mode != HWC_POWER_MODE_DOZE_SUSPEND) { // FIXME: eventthread only knows about the main display right now mEventThread->onScreenAcquired(); resyncToHardwareVsync(true); @@ -3216,7 +3219,25 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, getHwComposer().setPowerMode(type, mode); mVisibleRegionsDirty = true; // from this point on, SF will stop drawing on this display + } else if (mode == HWC_POWER_MODE_DOZE || + mode == HWC_POWER_MODE_NORMAL) { + // Update display while dozing + getHwComposer().setPowerMode(type, mode); + if (type == DisplayDevice::DISPLAY_PRIMARY) { + // FIXME: eventthread only knows about the main display right now + mEventThread->onScreenAcquired(); + resyncToHardwareVsync(true); + } + } else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) { + // Leave display going to doze + if (type == DisplayDevice::DISPLAY_PRIMARY) { + disableHardwareVsync(true); // also cancels any in-progress resync + // FIXME: eventthread only knows about the main display right now + mEventThread->onScreenReleased(); + } + getHwComposer().setPowerMode(type, mode); } else { + ALOGE("Attempting to set unknown power mode: %d\n", mode); getHwComposer().setPowerMode(type, mode); } } diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp index 7070b97b1e..f6ee6604e8 100644 --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp @@ -2845,7 +2845,8 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, if (currentMode == HWC_POWER_MODE_OFF) { // Turn on the display getHwComposer().setPowerMode(type, mode); - if (type == DisplayDevice::DISPLAY_PRIMARY) { + if (type == DisplayDevice::DISPLAY_PRIMARY && + mode != HWC_POWER_MODE_DOZE_SUSPEND) { // FIXME: eventthread only knows about the main display right now mEventThread->onScreenAcquired(); resyncToHardwareVsync(true); @@ -2877,7 +2878,25 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, getHwComposer().setPowerMode(type, mode); mVisibleRegionsDirty = true; // from this point on, SF will stop drawing on this display + } else if (mode == HWC_POWER_MODE_DOZE || + mode == HWC_POWER_MODE_NORMAL) { + // Update display while dozing + getHwComposer().setPowerMode(type, mode); + if (type == DisplayDevice::DISPLAY_PRIMARY) { + // FIXME: eventthread only knows about the main display right now + mEventThread->onScreenAcquired(); + resyncToHardwareVsync(true); + } + } else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) { + // Leave display going to doze + if (type == DisplayDevice::DISPLAY_PRIMARY) { + disableHardwareVsync(true); // also cancels any in-progress resync + // FIXME: eventthread only knows about the main display right now + mEventThread->onScreenReleased(); + } + getHwComposer().setPowerMode(type, mode); } else { + ALOGE("Attempting to set unknown power mode: %d\n", mode); getHwComposer().setPowerMode(type, mode); } } diff --git a/services/surfaceflinger/tests/Android.mk b/services/surfaceflinger/tests/Android.mk index 16041da657..43e22a0bd6 100644 --- a/services/surfaceflinger/tests/Android.mk +++ b/services/surfaceflinger/tests/Android.mk @@ -4,7 +4,7 @@ include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := SurfaceFlinger_test - +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := \ diff --git a/services/surfaceflinger/tests/AndroidTest.xml b/services/surfaceflinger/tests/AndroidTest.xml new file mode 100644 index 0000000000..8315037b94 --- /dev/null +++ b/services/surfaceflinger/tests/AndroidTest.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2017 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. +--> +<configuration description="Config for SurfaceFlinger_test"> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="cleanup" value="true" /> + <option name="push" value="SurfaceFlinger_test->/data/local/tmp/SurfaceFlinger_test" /> + </target_preparer> + <option name="test-suite-tag" value="apct" /> + <test class="com.android.tradefed.testtype.GTest" > + <option name="native-test-device-path" value="/data/local/tmp" /> + <option name="module-name" value="SurfaceFlinger_test" /> + </test> +</configuration> diff --git a/services/surfaceflinger/tests/vsync/Android.mk b/services/surfaceflinger/tests/vsync/Android.mk index 9181760453..8e41617f7b 100644 --- a/services/surfaceflinger/tests/vsync/Android.mk +++ b/services/surfaceflinger/tests/vsync/Android.mk @@ -15,4 +15,6 @@ LOCAL_MODULE:= test-vsync-events LOCAL_MODULE_TAGS := tests +LOCAL_CFLAGS := -Werror + include $(BUILD_EXECUTABLE) diff --git a/services/surfaceflinger/tests/vsync/vsync.cpp b/services/surfaceflinger/tests/vsync/vsync.cpp index aa72c79248..a1b45e6adb 100644 --- a/services/surfaceflinger/tests/vsync/vsync.cpp +++ b/services/surfaceflinger/tests/vsync/vsync.cpp @@ -20,7 +20,7 @@ using namespace android; -int receiver(int fd, int events, void* data) +int receiver(int /*fd*/, int /*events*/, void* data) { DisplayEventReceiver* q = (DisplayEventReceiver*)data; @@ -47,7 +47,7 @@ int receiver(int fd, int events, void* data) return 1; } -int main(int argc, char** argv) +int main(int /*argc*/, char** /*argv*/) { DisplayEventReceiver myDisplayEvent; diff --git a/services/surfaceflinger/tests/waitforvsync/Android.mk b/services/surfaceflinger/tests/waitforvsync/Android.mk index c25f5ab083..932d2be133 100644 --- a/services/surfaceflinger/tests/waitforvsync/Android.mk +++ b/services/surfaceflinger/tests/waitforvsync/Android.mk @@ -11,4 +11,6 @@ LOCAL_MODULE:= test-waitforvsync LOCAL_MODULE_TAGS := tests +LOCAL_CFLAGS := -Werror + include $(BUILD_EXECUTABLE) diff --git a/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp b/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp index b88b04a897..65eaae58b7 100644 --- a/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp +++ b/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp @@ -29,7 +29,7 @@ #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) #endif -int main(int argc, char** argv) { +int main(int /*argc*/, char** /*argv*/) { int fd = open("/dev/graphics/fb0", O_RDWR); if (fd >= 0) { do { diff --git a/vulkan/include/vulkan/vk_android_native_buffer.h b/vulkan/include/vulkan/vk_android_native_buffer.h index 43a9a9c20d..d3e5f0f6b1 100644 --- a/vulkan/include/vulkan/vk_android_native_buffer.h +++ b/vulkan/include/vulkan/vk_android_native_buffer.h @@ -17,7 +17,7 @@ #ifndef __VK_ANDROID_NATIVE_BUFFER_H__ #define __VK_ANDROID_NATIVE_BUFFER_H__ -#include <system/window.h> +#include <cutils/native_handle.h> #include <vulkan/vulkan.h> #ifdef __cplusplus diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp index 61498949bb..5f9b357a35 100644 --- a/vulkan/libvulkan/Android.bp +++ b/vulkan/libvulkan/Android.bp @@ -75,6 +75,7 @@ cc_library_shared { "libbase", "liblog", "libui", + "libgraphicsenv", "libutils", "libcutils", "libz", diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index 6f425f50c1..7b985d1a7f 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -28,7 +28,7 @@ #include <android/dlext.h> #include <cutils/properties.h> -#include <ui/GraphicsEnv.h> +#include <graphicsenv/GraphicsEnv.h> #include <utils/Vector.h> #include "driver.h" diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index caa2674d7b..cb893aa912 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -22,6 +22,7 @@ #include <sync/sync.h> #include <utils/StrongPointer.h> #include <utils/Vector.h> +#include <system/window.h> #include "driver.h" |