diff options
201 files changed, 9671 insertions, 1950 deletions
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index fdac5db1d1..316f04cb27 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -316,97 +316,6 @@ on late-init && property:ro.boot.fastboot.boottrace= write /sys/kernel/debug/tracing/tracing_on 0 write /sys/kernel/tracing/tracing_on 0 -# Only create the tracing instance if persist.mm_events.enabled -# Attempting to remove the tracing instance after it has been created -# will likely fail with EBUSY as it would be in use by traced_probes. -on mm_events_property_available && property:persist.mm_events.enabled=true -# Create MM Events Tracing Instance for Kmem Activity Trigger - mkdir /sys/kernel/debug/tracing/instances/mm_events 0755 system system - mkdir /sys/kernel/tracing/instances/mm_events 0755 system system - -# Read and set per CPU buffer size - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/buffer_size_kb - chmod 0666 /sys/kernel/tracing/instances/mm_events/buffer_size_kb - -# Set the default buffer size to the minimum - write /sys/kernel/debug/tracing/instances/mm_events/buffer_size_kb 1 - write /sys/kernel/tracing/instances/mm_events/buffer_size_kb 1 - -# Read and enable tracing - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/tracing_on - chmod 0666 /sys/kernel/tracing/instances/mm_events/tracing_on - -# Tracing disabled by default - write /sys/kernel/debug/tracing/instances/mm_events/tracing_on 0 - write /sys/kernel/tracing/instances/mm_events/tracing_on 0 - -# Read and truncate kernel trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/trace - -# Enable trace events - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/events/vmscan/mm_vmscan_direct_reclaim_begin/enable - chmod 0666 /sys/kernel/tracing/instances/mm_events/events/vmscan/mm_vmscan_direct_reclaim_begin/enable - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/events/vmscan/mm_vmscan_kswapd_wake/enable - chmod 0666 /sys/kernel/tracing/instances/mm_events/events/vmscan/mm_vmscan_kswapd_wake/enable - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/events/compaction/mm_compaction_begin/enable - chmod 0666 /sys/kernel/tracing/instances/mm_events/events/compaction/mm_compaction_begin/enable - -# Read and clear per-CPU raw kernel trace -# Cannot use wildcards in .rc files. Update this if there is a phone with -# more CPUs. - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu0/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu0/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu1/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu1/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu2/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu2/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu3/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu3/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu4/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu4/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu5/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu5/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu6/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu6/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu7/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu7/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu8/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu8/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu9/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu9/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu10/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu10/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu11/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu11/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu12/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu12/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu13/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu13/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu14/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu14/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu15/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu15/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu16/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu16/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu17/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu17/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu18/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu18/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu19/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu19/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu20/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu20/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu21/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu21/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu22/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu22/trace - chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu23/trace - chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu23/trace - -on property:ro.persistent_properties.ready=true - trigger mm_events_property_available - # Handle hyp tracing instance on late-init && property:ro.boot.hypervisor.vm.supported=1 diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp index 6e6d27d463..a2e171fa3b 100644 --- a/cmds/flatland/GLHelper.cpp +++ b/cmds/flatland/GLHelper.cpp @@ -241,7 +241,7 @@ bool GLHelper::createWindowSurface(uint32_t w, uint32_t h, status_t err; if (mSurfaceComposerClient == nullptr) { - mSurfaceComposerClient = new SurfaceComposerClient; + mSurfaceComposerClient = sp<SurfaceComposerClient>::make(); } err = mSurfaceComposerClient->initCheck(); if (err != NO_ERROR) { diff --git a/cmds/installd/TEST_MAPPING b/cmds/installd/TEST_MAPPING index fc4cfc98dc..d53c94ba55 100644 --- a/cmds/installd/TEST_MAPPING +++ b/cmds/installd/TEST_MAPPING @@ -18,10 +18,6 @@ { "name": "run_dex2oat_test" }, - // AdoptableHostTest moves packages, part of which is handled by installd - { - "name": "AdoptableHostTest" - }, { "name": "CtsUsesLibraryHostTestCases" }, diff --git a/include/android/configuration.h b/include/android/configuration.h index 46c7dfeceb..a291db0ecd 100644 --- a/include/android/configuration.h +++ b/include/android/configuration.h @@ -26,6 +26,7 @@ #ifndef ANDROID_CONFIGURATION_H #define ANDROID_CONFIGURATION_H +#include <stdint.h> #include <sys/cdefs.h> #include <android/asset_manager.h> diff --git a/include/android/thermal.h b/include/android/thermal.h index e5d46b5b8a..93ae961423 100644 --- a/include/android/thermal.h +++ b/include/android/thermal.h @@ -304,6 +304,26 @@ int AThermal_getThermalHeadroomThresholds(AThermalManager* _Nonnull manager, * Prototype of the function that is called when thermal headroom or thresholds changes. * It's passed the updated thermal headroom and thresholds as parameters, as well as the * pointer provided by the client that registered a callback. + * <p> + * This may not be used to fully replace the {@link AThermal_getThermalHeadroom} API as it will + * only notify on one of the conditions below that will significantly change one or both + * values of current headroom and headroom thresholds since previous callback: + * 1. thermal throttling events: when the skin temperature has cross any of the thresholds + * and there isn't a previous callback in a short time ago with similar values. + * 2. skin temperature threshold change events: note that if the absolute °C threshold + * values change in a way that does not significantly change the current headroom nor + * headroom thresholds, it will not trigger any callback. The client should not + * need to take action in such case since the difference from temperature vs threshold + * hasn't changed. + * <p> + * By API version 36, it provides a forecast in the same call for developer's convenience + * based on a {@code forecastSeconds} defined by the device, which can be static or dynamic + * varied by OEM. Be aware that it will not notify on forecast temperature change but the + * events mentioned above. So periodically polling against {@link AThermal_getThermalHeadroom} + * API should still be used to actively monitor temperature forecast in advance. + * <p> + * This serves as a more advanced option compared to thermal status listener, where the + * latter will only notify on thermal throttling events with status update. * * @param data The data pointer to be passed when callback is called. * @param headroom The current non-negative normalized headroom value, also see diff --git a/include/input/DisplayTopologyGraph.h b/include/input/DisplayTopologyGraph.h index 3ae865a33a..9fc080d6f8 100644 --- a/include/input/DisplayTopologyGraph.h +++ b/include/input/DisplayTopologyGraph.h @@ -46,6 +46,8 @@ struct DisplayTopologyAdjacentDisplay { DisplayTopologyPosition position; // The offset in DP of the adjacent display, relative to the source display. float offsetDp; + + std::string dump() const; }; /** @@ -55,6 +57,9 @@ struct DisplayTopologyGraph { ui::LogicalDisplayId primaryDisplayId = ui::LogicalDisplayId::INVALID; std::unordered_map<ui::LogicalDisplayId, std::vector<DisplayTopologyAdjacentDisplay>> graph; std::unordered_map<ui::LogicalDisplayId, int> displaysDensity; + + bool isValid() const; + std::string dump() const; }; } // namespace android diff --git a/include/input/InputFlags.h b/include/input/InputFlags.h index 4b42f775dd..16e754e210 100644 --- a/include/input/InputFlags.h +++ b/include/input/InputFlags.h @@ -22,7 +22,21 @@ class InputFlags { public: /** * Check if connected displays feature is enabled, either via the feature flag or settings - * override. + * override. Developer setting override allows enabling all the "desktop experiences" features + * including input related connected_displays_cursor flag. + * + * The developer settings override is prioritised over aconfig flags. Any tests that require + * applicable aconfig flags to be disabled with SCOPED_FLAG_OVERRIDE also need this developer + * option to be reset locally. + * + * Also note the developer setting override is only applicable to the desktop experiences + * related features. + * + * To enable only the input flag run: + * adb shell aflags enable com.android.input.flags.connected_displays_cursor + * To override this flag and enable all "desktop experiences" features run: + * adb shell aflags enable com.android.window.flags.enable_desktop_mode_through_dev_option + * adb shell setprop persist.wm.debug.desktop_experience_devopts 1 */ static bool connectedDisplaysCursorEnabled(); diff --git a/include/powermanager/PowerHalController.h b/include/powermanager/PowerHalController.h index f4f4d5e05c..e22481fceb 100644 --- a/include/powermanager/PowerHalController.h +++ b/include/powermanager/PowerHalController.h @@ -73,6 +73,9 @@ public: int tgid, int uid) override; virtual HalResult<void> closeSessionChannel(int tgid, int uid) override; virtual HalResult<aidl::android::hardware::power::SupportInfo> getSupportInfo() override; + virtual HalResult<void> sendCompositionData( + const std::vector<hal::CompositionData>& data) override; + virtual HalResult<void> sendCompositionUpdate(const hal::CompositionUpdate& update) override; private: std::mutex mConnectedHalMutex; diff --git a/include/powermanager/PowerHalWrapper.h b/include/powermanager/PowerHalWrapper.h index 42901821bc..17a4cd4eff 100644 --- a/include/powermanager/PowerHalWrapper.h +++ b/include/powermanager/PowerHalWrapper.h @@ -18,6 +18,8 @@ #include <aidl/android/hardware/power/Boost.h> #include <aidl/android/hardware/power/ChannelConfig.h> +#include <aidl/android/hardware/power/CompositionData.h> +#include <aidl/android/hardware/power/CompositionUpdate.h> #include <aidl/android/hardware/power/IPower.h> #include <aidl/android/hardware/power/IPowerHintSession.h> #include <aidl/android/hardware/power/Mode.h> @@ -37,6 +39,8 @@ namespace android { namespace power { +namespace hal = aidl::android::hardware::power; + // State of Power HAL support for individual apis. enum class HalSupport { UNKNOWN = 0, @@ -49,21 +53,20 @@ class HalWrapper { public: virtual ~HalWrapper() = default; - virtual HalResult<void> setBoost(aidl::android::hardware::power::Boost boost, - int32_t durationMs) = 0; - virtual HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) = 0; + virtual HalResult<void> setBoost(hal::Boost boost, int32_t durationMs) = 0; + virtual HalResult<void> setMode(hal::Mode mode, bool enabled) = 0; virtual HalResult<std::shared_ptr<PowerHintSessionWrapper>> createHintSession( int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos) = 0; virtual HalResult<std::shared_ptr<PowerHintSessionWrapper>> createHintSessionWithConfig( int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos, - aidl::android::hardware::power::SessionTag tag, - aidl::android::hardware::power::SessionConfig* config) = 0; + hal::SessionTag tag, hal::SessionConfig* config) = 0; virtual HalResult<int64_t> getHintSessionPreferredRate() = 0; - virtual HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel(int tgid, - int uid) = 0; + virtual HalResult<hal::ChannelConfig> getSessionChannel(int tgid, int uid) = 0; virtual HalResult<void> closeSessionChannel(int tgid, int uid) = 0; virtual HalResult<aidl::android::hardware::power::SupportInfo> getSupportInfo() = 0; + virtual HalResult<void> sendCompositionData(const std::vector<hal::CompositionData>& data) = 0; + virtual HalResult<void> sendCompositionUpdate(const hal::CompositionUpdate& update) = 0; }; // Empty Power HAL wrapper that ignores all api calls. @@ -72,21 +75,20 @@ public: EmptyHalWrapper() = default; ~EmptyHalWrapper() override = default; - HalResult<void> setBoost(aidl::android::hardware::power::Boost boost, - int32_t durationMs) override; - HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) override; + HalResult<void> setBoost(hal::Boost boost, int32_t durationMs) override; + HalResult<void> setMode(hal::Mode mode, bool enabled) override; HalResult<std::shared_ptr<PowerHintSessionWrapper>> createHintSession( int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos) override; HalResult<std::shared_ptr<PowerHintSessionWrapper>> createHintSessionWithConfig( int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos, - aidl::android::hardware::power::SessionTag tag, - aidl::android::hardware::power::SessionConfig* config) override; + hal::SessionTag tag, hal::SessionConfig* config) override; HalResult<int64_t> getHintSessionPreferredRate() override; - HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel(int tgid, - int uid) override; + HalResult<hal::ChannelConfig> getSessionChannel(int tgid, int uid) override; HalResult<void> closeSessionChannel(int tgid, int uid) override; HalResult<aidl::android::hardware::power::SupportInfo> getSupportInfo() override; + HalResult<void> sendCompositionData(const std::vector<hal::CompositionData>& data) override; + HalResult<void> sendCompositionUpdate(const hal::CompositionUpdate& update) override; protected: virtual const char* getUnsupportedMessage(); @@ -99,9 +101,8 @@ public: : mHandleV1_0(std::move(handleV1_0)) {} ~HidlHalWrapperV1_0() override = default; - HalResult<void> setBoost(aidl::android::hardware::power::Boost boost, - int32_t durationMs) override; - HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) override; + HalResult<void> setBoost(hal::Boost boost, int32_t durationMs) override; + HalResult<void> setMode(hal::Mode mode, bool enabled) override; protected: const sp<hardware::power::V1_0::IPower> mHandleV1_0; @@ -127,9 +128,8 @@ protected: // Wrapper for the HIDL Power HAL v1.2. class HidlHalWrapperV1_2 : public HidlHalWrapperV1_1 { public: - HalResult<void> setBoost(aidl::android::hardware::power::Boost boost, - int32_t durationMs) override; - HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) override; + HalResult<void> setBoost(hal::Boost boost, int32_t durationMs) override; + HalResult<void> setMode(hal::Mode mode, bool enabled) override; explicit HidlHalWrapperV1_2(sp<hardware::power::V1_2::IPower> handleV1_2) : HidlHalWrapperV1_1(std::move(handleV1_2)) {} ~HidlHalWrapperV1_2() override = default; @@ -141,7 +141,7 @@ protected: // Wrapper for the HIDL Power HAL v1.3. class HidlHalWrapperV1_3 : public HidlHalWrapperV1_2 { public: - HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) override; + HalResult<void> setMode(hal::Mode mode, bool enabled) override; explicit HidlHalWrapperV1_3(sp<hardware::power::V1_3::IPower> handleV1_3) : HidlHalWrapperV1_2(std::move(handleV1_3)) {} ~HidlHalWrapperV1_3() override = default; @@ -153,26 +153,24 @@ protected: // Wrapper for the AIDL Power HAL. class AidlHalWrapper : public EmptyHalWrapper { public: - explicit AidlHalWrapper(std::shared_ptr<aidl::android::hardware::power::IPower> handle) - : mHandle(std::move(handle)) {} + explicit AidlHalWrapper(std::shared_ptr<hal::IPower> handle) : mHandle(std::move(handle)) {} ~AidlHalWrapper() override = default; - HalResult<void> setBoost(aidl::android::hardware::power::Boost boost, - int32_t durationMs) override; - HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) override; + HalResult<void> setBoost(hal::Boost boost, int32_t durationMs) override; + HalResult<void> setMode(hal::Mode mode, bool enabled) override; HalResult<std::shared_ptr<PowerHintSessionWrapper>> createHintSession( int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos) override; HalResult<std::shared_ptr<PowerHintSessionWrapper>> createHintSessionWithConfig( int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos, - aidl::android::hardware::power::SessionTag tag, - aidl::android::hardware::power::SessionConfig* config) override; + hal::SessionTag tag, hal::SessionConfig* config) override; HalResult<int64_t> getHintSessionPreferredRate() override; - HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel(int tgid, - int uid) override; + HalResult<hal::ChannelConfig> getSessionChannel(int tgid, int uid) override; HalResult<void> closeSessionChannel(int tgid, int uid) override; HalResult<aidl::android::hardware::power::SupportInfo> getSupportInfo() override; + HalResult<void> sendCompositionData(const std::vector<hal::CompositionData>& data) override; + HalResult<void> sendCompositionUpdate(const hal::CompositionUpdate& update) override; protected: const char* getUnsupportedMessage() override; @@ -181,16 +179,10 @@ private: // Control access to the boost and mode supported arrays. std::mutex mBoostMutex; std::mutex mModeMutex; - std::shared_ptr<aidl::android::hardware::power::IPower> mHandle; - std::array<HalSupport, - static_cast<int32_t>( - *(ndk::enum_range<aidl::android::hardware::power::Boost>().end() - 1)) + - 1> + std::shared_ptr<hal::IPower> mHandle; + std::array<HalSupport, static_cast<int32_t>(*(ndk::enum_range<hal::Boost>().end() - 1)) + 1> mBoostSupportedArray GUARDED_BY(mBoostMutex) = {HalSupport::UNKNOWN}; - std::array<HalSupport, - static_cast<int32_t>( - *(ndk::enum_range<aidl::android::hardware::power::Mode>().end() - 1)) + - 1> + std::array<HalSupport, static_cast<int32_t>(*(ndk::enum_range<hal::Mode>().end() - 1)) + 1> mModeSupportedArray GUARDED_BY(mModeMutex) = {HalSupport::UNKNOWN}; }; diff --git a/include/powermanager/PowerHintSessionWrapper.h b/include/powermanager/PowerHintSessionWrapper.h index ba6fe77c80..0134e02f12 100644 --- a/include/powermanager/PowerHintSessionWrapper.h +++ b/include/powermanager/PowerHintSessionWrapper.h @@ -45,9 +45,11 @@ public: virtual HalResult<void> setMode(::aidl::android::hardware::power::SessionMode in_type, bool in_enabled); virtual HalResult<aidl::android::hardware::power::SessionConfig> getSessionConfig(); + std::optional<int> getSessionId(); private: std::shared_ptr<aidl::android::hardware::power::IPowerHintSession> mSession; + std::optional<int> mSessionId; int32_t mInterfaceVersion; }; diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index ea5343a2a0..a3499c1963 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -277,15 +277,6 @@ cc_defaults { "-fvisibility=hidden", "-DBUILDING_LIBBINDER", ], - - target: { - vendor: { - // Trimming the exported symbols reveals a bug in vendor code, so - // disable it for the vendor variant for now. http://b/349657329 - // TODO: Fix the issue and remove this override. - cflags: ["-fvisibility=default"], - }, - }, } cc_defaults { diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp index 7c0319aead..b1c8994b05 100644 --- a/libs/binder/BackendUnifiedServiceManager.cpp +++ b/libs/binder/BackendUnifiedServiceManager.cpp @@ -130,7 +130,13 @@ os::ServiceWithMetadata createServiceWithMetadata(const sp<IBinder>& service, bo bool BinderCacheWithInvalidation::isClientSideCachingEnabled(const std::string& serviceName) { sp<ProcessState> self = ProcessState::selfOrNull(); - if (!self || self->getThreadPoolMaxTotalThreadCount() <= 0) { + // Should not cache if process state could not be found, or if thread pool + // max could is not greater than zero. + if (!self) { + ALOGW("Service retrieved before binder threads started. If they are to be started, " + "consider starting binder threads earlier."); + return false; + } else if (self->getThreadPoolMaxTotalThreadCount() <= 0) { ALOGW("Thread Pool max thread count is 0. Cannot cache binder as linkToDeath cannot be " "implemented. serviceName: %s", serviceName.c_str()); diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp index bc7ae37ff0..9883eb2672 100644 --- a/libs/binder/Binder.cpp +++ b/libs/binder/Binder.cpp @@ -445,6 +445,9 @@ status_t BBinder::linkToDeath( const sp<DeathRecipient>& /*recipient*/, void* /*cookie*/, uint32_t /*flags*/) { + // BBinder::linkToDeath is invalid because this process owns this binder. + // The DeathRecipient is called on BpBinders when the process owning the + // binder node dies. return INVALID_OPERATION; } diff --git a/libs/binder/rust/rpcbinder/src/lib.rs b/libs/binder/rust/rpcbinder/src/lib.rs index 7e5c9ddc35..774bb21efe 100644 --- a/libs/binder/rust/rpcbinder/src/lib.rs +++ b/libs/binder/rust/rpcbinder/src/lib.rs @@ -20,6 +20,8 @@ mod server; mod session; pub use server::RpcServer; +#[cfg(target_os = "trusty")] +pub use server::RpcServerConnection; #[cfg(not(target_os = "trusty"))] pub use server::RpcServerRef; pub use session::{FileDescriptorTransportMode, RpcSession, RpcSessionRef}; diff --git a/libs/binder/rust/rpcbinder/src/server/trusty.rs b/libs/binder/rust/rpcbinder/src/server/trusty.rs index fe45decf25..54d82d5bd0 100644 --- a/libs/binder/rust/rpcbinder/src/server/trusty.rs +++ b/libs/binder/rust/rpcbinder/src/server/trusty.rs @@ -106,6 +106,10 @@ pub struct RpcServerConnection { ctx: *mut c_void, } +// SAFETY: The opaque handle: `ctx` points into a dynamic allocation, +// and not tied to anything specific to the current thread. +unsafe impl Send for RpcServerConnection {} + impl Drop for RpcServerConnection { fn drop(&mut self) { // We do not need to close handle_fd since we do not own it. diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs index 6a8a69843a..771c65bf92 100644 --- a/libs/binder/rust/src/binder.rs +++ b/libs/binder/rust/src/binder.rs @@ -1160,6 +1160,12 @@ macro_rules! declare_binder_enum { pub const fn enum_values() -> [Self; $size] { [$(Self::$name),*] } + + #[inline(always)] + #[allow(missing_docs)] + pub const fn get(&self) -> $backing { + self.0 + } } impl std::fmt::Debug for $enum { diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 170b2adfbb..7c9c452c01 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -382,7 +382,7 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc( sockaddr_un addr_un{}; addr_un.sun_family = AF_UNIX; strcpy(addr_un.sun_path, serverConfig.addr.c_str()); - addr = *reinterpret_cast<sockaddr_storage*>(&addr_un); + std::memcpy(&addr, &addr_un, sizeof(sockaddr_un)); addrLen = sizeof(sockaddr_un); status = session->setupPreconnectedClient({}, [=]() { @@ -394,7 +394,7 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc( sockaddr_un addr_un{}; addr_un.sun_family = AF_UNIX; strcpy(addr_un.sun_path, serverConfig.addr.c_str()); - addr = *reinterpret_cast<sockaddr_storage*>(&addr_un); + std::memcpy(&addr, &addr_un, sizeof(sockaddr_un)); addrLen = sizeof(sockaddr_un); status = session->setupUnixDomainClient(serverConfig.addr.c_str()); @@ -409,7 +409,7 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc( .svm_port = static_cast<unsigned int>(serverInfo.port), .svm_cid = VMADDR_CID_LOCAL, }; - addr = *reinterpret_cast<sockaddr_storage*>(&addr_vm); + std::memcpy(&addr, &addr_vm, sizeof(sockaddr_vm)); addrLen = sizeof(sockaddr_vm); status = session->setupVsockClient(VMADDR_CID_LOCAL, serverInfo.port); @@ -420,7 +420,7 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc( addr_in.sin_family = AF_INET; addr_in.sin_port = htons(serverInfo.port); inet_aton(ip_addr.c_str(), &addr_in.sin_addr); - addr = *reinterpret_cast<sockaddr_storage*>(&addr_in); + std::memcpy(&addr, &addr_in, sizeof(sockaddr_in)); addrLen = sizeof(sockaddr_in); status = session->setupInetClient(ip_addr.c_str(), serverInfo.port); diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h index 127676bf9a..1ac00ca13f 100644 --- a/libs/binder/trusty/include/binder/RpcServerTrusty.h +++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h @@ -97,6 +97,15 @@ private: // By default we use the latest stable version. LOG_ALWAYS_FATAL_IF(!rpcServer->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION)); + // The default behavior in trusty is to allow handles to be passed with tipc IPC. + // We add mode NONE so that servers do not reject connections from clients who do + // not change their default transport mode. + static const std::vector<RpcSession::FileDescriptorTransportMode> + TRUSTY_SERVER_SUPPORTED_FD_MODES = {RpcSession::FileDescriptorTransportMode::TRUSTY, + RpcSession::FileDescriptorTransportMode::NONE}; + + rpcServer->setSupportedFileDescriptorTransportModes(TRUSTY_SERVER_SUPPORTED_FD_MODES); + return rpcServer; } diff --git a/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp b/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp index 12e347e4f3..451383a90a 100644 --- a/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp +++ b/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp @@ -27,13 +27,6 @@ using android::RpcTransportCtxFactoryTipcTrusty; using android::sp; using android::wp; -// The default behavior in trusty is to allow handles to be passed with tipc IPC. -// We add mode NONE so that servers do not reject connections from clients who do -// not change their default transport mode. -static const std::vector<RpcSession::FileDescriptorTransportMode> TRUSTY_SERVER_SUPPORTED_FD_MODES = - {RpcSession::FileDescriptorTransportMode::TRUSTY, - RpcSession::FileDescriptorTransportMode::NONE}; - struct ARpcServerTrusty { sp<RpcServer> mRpcServer; @@ -60,8 +53,6 @@ ARpcServerTrusty* ARpcServerTrusty_newPerSession(AIBinder* (*cb)(const void*, si return nullptr; } - rpcServer->setSupportedFileDescriptorTransportModes(TRUSTY_SERVER_SUPPORTED_FD_MODES); - rpcServer->setPerSessionRootObject( [cb, cbArgSp](wp<RpcSession> /*session*/, const void* addrPtr, size_t len) { auto* aib = (*cb)(addrPtr, len, cbArgSp.get()); diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp index 43ee33eb86..2d18d80678 100644 --- a/libs/dumputils/dump_utils.cpp +++ b/libs/dumputils/dump_utils.cpp @@ -50,7 +50,6 @@ static const char* native_processes_to_dump[] = { // Native processes to dump on debuggable builds. static const char* debuggable_native_processes_to_dump[] = { - "/system/bin/keystore2", "/system/bin/vold", NULL, }; diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 626581cc2a..03e6456ea6 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -639,7 +639,7 @@ const std::vector<std::string>& GraphicsEnv::getAngleEglFeatures() { // List of ANGLE features to override (enabled or disable). // The list of overrides is loaded and parsed by GpuService. void GraphicsEnv::updateAngleFeatureOverrides() { - if (!graphicsenv_flags::feature_overrides()) { + if (!graphicsenv_flags::angle_feature_overrides()) { return; } @@ -654,7 +654,7 @@ void GraphicsEnv::updateAngleFeatureOverrides() { void GraphicsEnv::getAngleFeatureOverrides(std::vector<const char*>& enabled, std::vector<const char*>& disabled) { - if (!graphicsenv_flags::feature_overrides()) { + if (!graphicsenv_flags::angle_feature_overrides()) { return; } diff --git a/libs/graphicsenv/graphicsenv_flags.aconfig b/libs/graphicsenv/graphicsenv_flags.aconfig index ac66362242..efa4bca892 100644 --- a/libs/graphicsenv/graphicsenv_flags.aconfig +++ b/libs/graphicsenv/graphicsenv_flags.aconfig @@ -2,8 +2,8 @@ package: "com.android.graphics.graphicsenv.flags" container: "system" flag { - name: "feature_overrides" - namespace: "core_graphics" - description: "This flag controls the Feature Overrides in GraphicsEnv." + name: "angle_feature_overrides" + namespace: "gpu" + description: "This flag controls the ANGLE Feature Overrides in GraphicsEnv." bug: "372694741" } diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index b5fa321fc2..158c54886d 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -295,7 +295,6 @@ filegroup { cc_defaults { name: "libgui-defaults", defaults: ["libgui_bufferqueue-defaults"], - srcs: [":libgui-sources"], static_libs: [ "libgui_aidl_static", "libgui_window_info_static", @@ -319,6 +318,10 @@ cc_library_shared { "libgui-defaults", ], + srcs: [ + ":libgui-sources", + ], + export_static_lib_headers: [ "libgui_aidl_static", "libgui_window_info_static", diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index fa971426a7..1aae13c1f4 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -937,15 +937,22 @@ public: : Surface(igbp, controlledByApp, scHandle), mBbq(bbq) {} void allocateBuffers() override { + ATRACE_CALL(); uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth; uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight; auto gbp = getIGraphicBufferProducer(); - std::thread ([reqWidth, reqHeight, gbp=getIGraphicBufferProducer(), - reqFormat=mReqFormat, reqUsage=mReqUsage] () { + std::thread allocateThread([reqWidth, reqHeight, gbp = getIGraphicBufferProducer(), + reqFormat = mReqFormat, reqUsage = mReqUsage]() { + if (com_android_graphics_libgui_flags_allocate_buffer_priority()) { + androidSetThreadName("allocateBuffers"); + pid_t tid = gettid(); + androidSetThreadPriority(tid, ANDROID_PRIORITY_DISPLAY); + } + gbp->allocateBuffers(reqWidth, reqHeight, reqFormat, reqUsage); - - }).detach(); + }); + allocateThread.detach(); } status_t setFrameRate(float frameRate, int8_t compatibility, diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index 1585aae45c..4926ceb619 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -17,6 +17,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "BufferItemConsumer" //#define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include <utils/Errors.h> #include <utils/Log.h> #include <inttypes.h> @@ -132,13 +133,36 @@ status_t BufferItemConsumer::acquireBuffer(BufferItem *item, return OK; } +status_t BufferItemConsumer::attachBuffer(const sp<GraphicBuffer>& buffer) { + if (!buffer) { + BI_LOGE("BufferItemConsumer::attachBuffer no input buffer specified."); + return BAD_VALUE; + } + + Mutex::Autolock _l(mMutex); + + int slot = INVALID_BUFFER_SLOT; + status_t status = mConsumer->attachBuffer(&slot, buffer); + if (status != OK) { + BI_LOGE("BufferItemConsumer::attachBuffer unable to attach buffer %d", status); + return status; + } + + mSlots[slot] = { + .mGraphicBuffer = buffer, + .mFence = nullptr, + .mFrameNumber = 0, + }; + + return OK; +} + status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, const sp<Fence>& releaseFence) { Mutex::Autolock _l(mMutex); return releaseBufferSlotLocked(item.mSlot, item.mGraphicBuffer, releaseFence); } -#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) status_t BufferItemConsumer::releaseBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& releaseFence) { Mutex::Autolock _l(mMutex); @@ -154,7 +178,6 @@ status_t BufferItemConsumer::releaseBuffer(const sp<GraphicBuffer>& buffer, return releaseBufferSlotLocked(slotIndex, buffer, releaseFence); } -#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) status_t BufferItemConsumer::releaseBufferSlotLocked(int slotIndex, const sp<GraphicBuffer>& buffer, const sp<Fence>& releaseFence) { diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 270bfbdc64..4681c9ecbe 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -14,10 +14,6 @@ * limitations under the License. */ -#include <inttypes.h> -#include <pwd.h> -#include <sys/types.h> - #define LOG_TAG "BufferQueueConsumer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 @@ -48,6 +44,11 @@ #include <com_android_graphics_libgui_flags.h> +#include <inttypes.h> +#include <pwd.h> +#include <sys/types.h> +#include <optional> + namespace android { // Macros for include BufferQueueCore information in log messages @@ -767,11 +768,15 @@ status_t BufferQueueConsumer::setMaxBufferCount(int bufferCount) { return NO_ERROR; } +status_t BufferQueueConsumer::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { + return setMaxAcquiredBufferCount(maxAcquiredBuffers, std::nullopt); +} + status_t BufferQueueConsumer::setMaxAcquiredBufferCount( - int maxAcquiredBuffers) { + int maxAcquiredBuffers, std::optional<OnBufferReleasedCallback> onBuffersReleasedCallback) { ATRACE_FORMAT("%s(%d)", __func__, maxAcquiredBuffers); - sp<IConsumerListener> listener; + std::optional<OnBufferReleasedCallback> callback; { // Autolock scope std::unique_lock<std::mutex> lock(mCore->mMutex); @@ -833,13 +838,20 @@ status_t BufferQueueConsumer::setMaxAcquiredBufferCount( BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers); mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers; VALIDATE_CONSISTENCY(); - if (delta < 0 && mCore->mBufferReleasedCbEnabled) { - listener = mCore->mConsumerListener; + if (delta < 0) { + if (onBuffersReleasedCallback) { + callback = std::move(onBuffersReleasedCallback); + } else if (mCore->mBufferReleasedCbEnabled) { + callback = [listener = mCore->mConsumerListener]() { + listener->onBuffersReleased(); + }; + } } } + // Call back without lock held - if (listener != nullptr) { - listener->onBuffersReleased(); + if (callback) { + (*callback)(); } return NO_ERROR; diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 5961b41478..bcf61e45de 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -364,8 +364,10 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller, // Producers are not allowed to dequeue more than // mMaxDequeuedBufferCount buffers. // This check is only done if a buffer has already been queued - if (mCore->mBufferHasBeenQueued && - dequeuedCount >= mCore->mMaxDequeuedBufferCount) { + using namespace com::android::graphics::libgui::flags; + bool flagGatedBufferHasBeenQueued = + bq_always_use_max_dequeued_buffer_count() || mCore->mBufferHasBeenQueued; + if (flagGatedBufferHasBeenQueued && dequeuedCount >= mCore->mMaxDequeuedBufferCount) { // Supress error logs when timeout is non-negative. if (mDequeueTimeout < 0) { BQ_LOGE("%s: attempting to exceed the max dequeued buffer " diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index 117a362661..5b89c6e17e 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -264,7 +264,10 @@ void ConsumerBase::onFrameReplaced(const BufferItem &item) { void ConsumerBase::onBuffersReleased() { Mutex::Autolock lock(mMutex); + onBuffersReleasedLocked(); +} +void ConsumerBase::onBuffersReleasedLocked() { CB_LOGV("onBuffersReleased"); if (mAbandoned) { @@ -481,7 +484,8 @@ status_t ConsumerBase::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { CB_LOGE("setMaxAcquiredBufferCount: ConsumerBase is abandoned!"); return NO_INIT; } - return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers); + return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers, + {[this]() { onBuffersReleasedLocked(); }}); } status_t ConsumerBase::setConsumerIsProtected(bool isProtected) { diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 63dcfbcb9b..83c6b57289 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -2230,17 +2230,47 @@ int Surface::detachNextBuffer(sp<GraphicBuffer>* outBuffer, return NO_ERROR; } +int Surface::isBufferOwned(const sp<GraphicBuffer>& buffer, bool* outIsOwned) const { + ATRACE_CALL(); + + if (buffer == nullptr) { + ALOGE("%s: Bad input, buffer was null", __FUNCTION__); + return BAD_VALUE; + } + if (outIsOwned == nullptr) { + ALOGE("%s: Bad input, output was null", __FUNCTION__); + return BAD_VALUE; + } + + Mutex::Autolock lock(mMutex); + + int slot = this->getSlotFromBufferLocked(buffer->getNativeBuffer()); + if (slot == BAD_VALUE) { + ALOGV("%s: Buffer %" PRIu64 " is not owned", __FUNCTION__, buffer->getId()); + *outIsOwned = false; + return NO_ERROR; + } else if (slot < 0) { + ALOGV("%s: Buffer %" PRIu64 " look up failed (%d)", __FUNCTION__, buffer->getId(), slot); + *outIsOwned = false; + return slot; + } + + *outIsOwned = true; + return NO_ERROR; +} + int Surface::attachBuffer(ANativeWindowBuffer* buffer) { ATRACE_CALL(); - ALOGV("Surface::attachBuffer"); + sp<GraphicBuffer> graphicBuffer(static_cast<GraphicBuffer*>(buffer)); + + ALOGV("Surface::attachBuffer bufferId=%" PRIu64, graphicBuffer->getId()); Mutex::Autolock lock(mMutex); if (mReportRemovedBuffers) { mRemovedBuffers.clear(); } - sp<GraphicBuffer> graphicBuffer(static_cast<GraphicBuffer*>(buffer)); uint32_t priorGeneration = graphicBuffer->mGenerationNumber; graphicBuffer->mGenerationNumber = mGenerationNumber; int32_t attachedSlot = -1; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index e407a63d10..9854274cb1 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2766,6 +2766,7 @@ status_t SurfaceComposerClient::getStaticDisplayInfo(int64_t displayId, if (status.isOk()) { // convert gui::StaticDisplayInfo to ui::StaticDisplayInfo outInfo->connectionType = static_cast<ui::DisplayConnectionType>(ginfo.connectionType); + outInfo->port = ginfo.port; outInfo->density = ginfo.density; outInfo->secure = ginfo.secure; outInfo->installOrientation = static_cast<ui::Rotation>(ginfo.installOrientation); diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 1eb9b87c3c..50877f8c56 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -194,7 +194,7 @@ const std::string& SurfaceControl::getName() const { return mName; } -std::shared_ptr<Choreographer> SurfaceControl::getChoreographer() { +sp<Choreographer> SurfaceControl::getChoreographer() { if (mChoreographer) { return mChoreographer; } @@ -203,7 +203,7 @@ std::shared_ptr<Choreographer> SurfaceControl::getChoreographer() { ALOGE("%s: No looper prepared for thread", __func__); return nullptr; } - mChoreographer = std::make_shared<Choreographer>(looper, getHandle()); + mChoreographer = sp<Choreographer>::make(looper, getHandle()); status_t result = mChoreographer->initialize(); if (result != OK) { ALOGE("Failed to initialize choreographer"); diff --git a/libs/gui/aidl/android/gui/StaticDisplayInfo.aidl b/libs/gui/aidl/android/gui/StaticDisplayInfo.aidl index 0ccda56ef5..7ff332c29e 100644 --- a/libs/gui/aidl/android/gui/StaticDisplayInfo.aidl +++ b/libs/gui/aidl/android/gui/StaticDisplayInfo.aidl @@ -23,6 +23,7 @@ import android.gui.Rotation; /** @hide */ parcelable StaticDisplayInfo { DisplayConnectionType connectionType = DisplayConnectionType.Internal; + int port = -1; float density; boolean secure; @nullable DeviceProductInfo deviceProductInfo; diff --git a/libs/gui/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h index 0bfa7b222e..fc31f4636c 100644 --- a/libs/gui/include/gui/BufferItemConsumer.h +++ b/libs/gui/include/gui/BufferItemConsumer.h @@ -96,6 +96,14 @@ class BufferItemConsumer: public ConsumerBase status_t acquireBuffer(BufferItem* item, nsecs_t presentWhen, bool waitForFence = true); + // Transfer ownership of a buffer to the BufferQueue. On NO_ERROR, the buffer + // is considered as if it were acquired. Buffer must not be null. + // + // Returns + // - BAD_VALUE if buffer is null + // - INVALID_OPERATION if too many buffers have already been acquired + status_t attachBuffer(const sp<GraphicBuffer>& buffer); + // Returns an acquired buffer to the queue, allowing it to be reused. Since // only a fixed number of buffers may be acquired at a time, old buffers // must be released by calling releaseBuffer to ensure new buffers can be @@ -105,10 +113,8 @@ class BufferItemConsumer: public ConsumerBase status_t releaseBuffer(const BufferItem &item, const sp<Fence>& releaseFence = Fence::NO_FENCE); -#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) status_t releaseBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& releaseFence = Fence::NO_FENCE); -#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) protected: #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) diff --git a/libs/gui/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h index ab1231ad6b..ba6a6a73f4 100644 --- a/libs/gui/include/gui/BufferQueueConsumer.h +++ b/libs/gui/include/gui/BufferQueueConsumer.h @@ -122,7 +122,10 @@ public: // setMaxAcquiredBufferCount sets the maximum number of buffers that can // be acquired by the consumer at one time (default 1). This call will // fail if a producer is connected to the BufferQueue. - virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); + virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) override; + virtual status_t setMaxAcquiredBufferCount( + int maxAcquiredBuffers, + std::optional<OnBufferReleasedCallback> onBuffersReleasedCallback) override; // setConsumerName sets the name used in logging status_t setConsumerName(const String8& name) override; diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h index fd67f09a4a..d2215ef7e6 100644 --- a/libs/gui/include/gui/ConsumerBase.h +++ b/libs/gui/include/gui/ConsumerBase.h @@ -191,6 +191,8 @@ protected: #endif virtual int getSlotForBufferLocked(const sp<GraphicBuffer>& buffer); + virtual void onBuffersReleasedLocked(); + virtual status_t detachBufferLocked(int slotIndex); // freeBufferLocked frees up the given buffer slot. If the slot has been diff --git a/libs/gui/include/gui/IGraphicBufferConsumer.h b/libs/gui/include/gui/IGraphicBufferConsumer.h index 8272a591da..8066b070fb 100644 --- a/libs/gui/include/gui/IGraphicBufferConsumer.h +++ b/libs/gui/include/gui/IGraphicBufferConsumer.h @@ -243,6 +243,9 @@ public: // maxAcquiredBuffers must be (inclusive) between 1 and MAX_MAX_ACQUIRED_BUFFERS. It also cannot // cause the maxBufferCount value to be exceeded. // + // If called with onBuffersReleasedCallback, that call back will be called in lieu of + // IConsumerListener::onBuffersReleased. + // // Return of a value other than NO_ERROR means an error has occurred: // * NO_INIT - the BufferQueue has been abandoned // * BAD_VALUE - one of the below conditions occurred: @@ -253,6 +256,11 @@ public: // * INVALID_OPERATION - attempting to call this after a producer connected. virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0; + using OnBufferReleasedCallback = std::function<void(void)>; + virtual status_t setMaxAcquiredBufferCount( + int maxAcquiredBuffers, + std::optional<OnBufferReleasedCallback> onBuffersReleasedCallback) = 0; + // setConsumerName sets the name used in logging virtual status_t setConsumerName(const String8& name) = 0; diff --git a/libs/gui/include/gui/InputTransferToken.h b/libs/gui/include/gui/InputTransferToken.h index fb4aaa73ae..b83f24562b 100644 --- a/libs/gui/include/gui/InputTransferToken.h +++ b/libs/gui/include/gui/InputTransferToken.h @@ -39,15 +39,9 @@ public: return NO_ERROR; }; + bool operator==(const InputTransferToken& other) const { return mToken == other.mToken; } + sp<IBinder> mToken; }; -static inline bool operator==(const sp<InputTransferToken>& token1, - const sp<InputTransferToken>& token2) { - if (token1.get() == token2.get()) { - return true; - } - return token1->mToken == token2->mToken; -} - } // namespace android diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 755674d9e6..3cfbed11bf 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -442,6 +442,9 @@ public: status_t detachBuffer(const sp<GraphicBuffer>& buffer); #endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + // Sets outIsOwned to true if the given buffer is currently known to be owned by this Surface. + status_t isBufferOwned(const sp<GraphicBuffer>& buffer, bool* outIsOwned) const; + // Batch version of dequeueBuffer, cancelBuffer and queueBuffer // Note that these batched operations are not supported when shared buffer mode is being used. struct BatchBuffer { diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h index 344b957ba7..91a422d155 100644 --- a/libs/gui/include/gui/SurfaceControl.h +++ b/libs/gui/include/gui/SurfaceControl.h @@ -26,6 +26,7 @@ #include <android/gui/ISurfaceComposerClient.h> +#include <gui/Choreographer.h> #include <ui/FrameStats.h> #include <ui/PixelFormat.h> #include <ui/Region.h> @@ -36,7 +37,6 @@ namespace android { // --------------------------------------------------------------------------- -class Choreographer; class IGraphicBufferProducer; class Surface; class SurfaceComposerClient; @@ -82,7 +82,7 @@ public: const std::string& getName() const; // TODO(b/267195698): Consider renaming. - std::shared_ptr<Choreographer> getChoreographer(); + sp<Choreographer> getChoreographer(); sp<IGraphicBufferProducer> getIGraphicBufferProducer(); @@ -134,7 +134,7 @@ private: PixelFormat mFormat = PIXEL_FORMAT_NONE; uint32_t mCreateFlags = 0; uint64_t mFallbackFrameNumber = 100; - std::shared_ptr<Choreographer> mChoreographer; + sp<Choreographer> mChoreographer; }; }; // namespace android diff --git a/libs/gui/include/gui/mock/GraphicBufferConsumer.h b/libs/gui/include/gui/mock/GraphicBufferConsumer.h index 24d26b12a1..18a7e12fa7 100644 --- a/libs/gui/include/gui/mock/GraphicBufferConsumer.h +++ b/libs/gui/include/gui/mock/GraphicBufferConsumer.h @@ -47,6 +47,7 @@ public: MOCK_METHOD2(setDefaultBufferSize, status_t(uint32_t, uint32_t)); MOCK_METHOD1(setMaxBufferCount, status_t(int)); MOCK_METHOD1(setMaxAcquiredBufferCount, status_t(int)); + MOCK_METHOD2(setMaxAcquiredBufferCount, status_t(int, std::optional<OnBufferReleasedCallback>)); MOCK_METHOD1(setConsumerName, status_t(const String8&)); MOCK_METHOD1(setDefaultBufferFormat, status_t(PixelFormat)); MOCK_METHOD1(setDefaultBufferDataSpace, status_t(android_dataspace)); diff --git a/libs/gui/libgui_flags.aconfig b/libs/gui/libgui_flags.aconfig index 534f05e987..ce1bc9512c 100644 --- a/libs/gui/libgui_flags.aconfig +++ b/libs/gui/libgui_flags.aconfig @@ -130,9 +130,6 @@ flag { description: "Remove BufferQueueProducer::dequeue's wait on this fence (or the fence entirely) to prevent deadlocks" bug: "339705065" is_fixed_read_only: true - metadata { - purpose: PURPOSE_BUGFIX - } } # bq_gl_fence_cleanup flag { @@ -142,3 +139,25 @@ flag { bug: "340934031" is_fixed_read_only: true } # wb_media_migration + +flag { + name: "allocate_buffer_priority" + namespace: "wear_system_health" + description: "Boost priority for buffer allocation" + bug: "399701430" + metadata { + purpose: PURPOSE_BUGFIX + } + is_fixed_read_only: true +} # allocate_buffer_priority + +flag { + name: "bq_always_use_max_dequeued_buffer_count" + namespace: "core_graphics" + description: "BufferQueueProducer::dequeue's respects setMaxDequeuedBufferCount even before a buffer is dequeued." + bug: "399328309" + metadata { + purpose: PURPOSE_BUGFIX + } + is_fixed_read_only: true +} # bq_always_use_max_dequeued_buffer_count diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index e20345dd1a..bd53031e79 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -51,11 +51,6 @@ cc_test { "-Werror", "-Wextra", "-Wthread-safety", - "-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_BQ_SETFRAMERATE=true", - "-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_BQ_EXTENDEDALLOCATE=true", - "-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_WB_CONSUMER_BASE_OWNS_BQ=true", - "-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_WB_PLATFORM_API_IMPROVEMENTS=true", - "-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_WB_UNLIMITED_SLOTS=true", ], srcs: [ @@ -100,6 +95,7 @@ cc_test { "android.hardware.configstore-utils", "libSurfaceFlingerProp", "libGLESv1_CM", + "libgui", "libgui_test_server_aidl-cpp", "libinput", "libnativedisplay", diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index b861c6d4b7..4e4c8a2b63 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -201,7 +201,7 @@ public: protected: void SetUp() { mComposer = ComposerService::getComposerService(); - mClient = new SurfaceComposerClient(); + mClient = sp<SurfaceComposerClient>::make(); const auto ids = SurfaceComposerClient::getPhysicalDisplayIds(); ASSERT_FALSE(ids.empty()); // display 0 is picked as this test is not much display depedent diff --git a/libs/gui/tests/BufferItemConsumer_test.cpp b/libs/gui/tests/BufferItemConsumer_test.cpp index b980f882ff..80eea267bf 100644 --- a/libs/gui/tests/BufferItemConsumer_test.cpp +++ b/libs/gui/tests/BufferItemConsumer_test.cpp @@ -24,6 +24,7 @@ #include <gui/Surface.h> #include <ui/BufferQueueDefs.h> #include <ui/GraphicBuffer.h> +#include <utils/Errors.h> #include <unordered_set> @@ -235,6 +236,38 @@ TEST_F(BufferItemConsumerTest, TriggerBufferFreed_DeleteBufferItemConsumer) { ASSERT_EQ(1, GetFreedBufferCount()); } +TEST_F(BufferItemConsumerTest, ResizeAcquireCount) { + EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers + 1)); + EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers + 2)); + EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers - 1)); + EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers - 2)); + EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers + 1)); + EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers - 1)); +} + +TEST_F(BufferItemConsumerTest, AttachBuffer) { + ASSERT_EQ(OK, mBIC->setMaxAcquiredBufferCount(1)); + + int slot; + DequeueBuffer(&slot); + QueueBuffer(slot); + AcquireBuffer(&slot); + + sp<GraphicBuffer> newBuffer1 = sp<GraphicBuffer>::make(kWidth, kHeight, kFormat, kUsage); + sp<GraphicBuffer> newBuffer2 = sp<GraphicBuffer>::make(kWidth, kHeight, kFormat, kUsage); + + // For some reason, you can attach an extra buffer? + // b/400973991 to investigate + EXPECT_EQ(OK, mBIC->attachBuffer(newBuffer1)); + EXPECT_EQ(INVALID_OPERATION, mBIC->attachBuffer(newBuffer2)); + + ReleaseBuffer(slot); + + EXPECT_EQ(OK, mBIC->attachBuffer(newBuffer2)); + EXPECT_EQ(OK, mBIC->releaseBuffer(newBuffer1, Fence::NO_FENCE)); + EXPECT_EQ(OK, mBIC->releaseBuffer(newBuffer2, Fence::NO_FENCE)); +} + #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) // Test that delete BufferItemConsumer triggers onBufferFreed. TEST_F(BufferItemConsumerTest, DetachBufferWithBuffer) { diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index cfbb2e7386..e22f57e43e 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -1452,10 +1452,6 @@ TEST_F(BufferQueueTest, TestProducerConnectDisconnect) { ASSERT_EQ(NO_INIT, mProducer->disconnect(NATIVE_WINDOW_API_CPU)); } -TEST_F(BufferQueueTest, TestBqSetFrameRateFlagBuildTimeIsSet) { - ASSERT_EQ(flags::bq_setframerate(), COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE)); -} - struct BufferItemConsumerSetFrameRateListener : public BufferItemConsumer { BufferItemConsumerSetFrameRateListener() : BufferItemConsumer(GRALLOC_USAGE_SW_READ_OFTEN, 1) {} @@ -1561,9 +1557,14 @@ TEST_F(BufferQueueTest, TestAdditionalOptions) { {.name = "android.hardware.graphics.common.Dataspace", ADATASPACE_DISPLAY_P3}, }}; - ASSERT_EQ(NO_INIT, - native_window_set_buffers_additional_options(surface.get(), extras.data(), - extras.size())); + auto status = native_window_set_buffers_additional_options(surface.get(), extras.data(), + extras.size()); + if (flags::bq_extendedallocate()) { + ASSERT_EQ(NO_INIT, status); + } else { + ASSERT_EQ(INVALID_OPERATION, status); + GTEST_SKIP() << "Flag bq_extendedallocate not enabled"; + } if (!IsCuttlefish()) { GTEST_SKIP() << "Not cuttlefish"; diff --git a/libs/gui/tests/DisplayedContentSampling_test.cpp b/libs/gui/tests/DisplayedContentSampling_test.cpp index bffb3f0430..62d73ca752 100644 --- a/libs/gui/tests/DisplayedContentSampling_test.cpp +++ b/libs/gui/tests/DisplayedContentSampling_test.cpp @@ -30,7 +30,7 @@ static constexpr uint32_t INVALID_MASK = 0x10; class DisplayedContentSamplingTest : public ::testing::Test { protected: void SetUp() { - mComposerClient = new SurfaceComposerClient; + mComposerClient = sp<SurfaceComposerClient>::make(); ASSERT_EQ(OK, mComposerClient->initCheck()); const auto ids = SurfaceComposerClient::getPhysicalDisplayIds(); ASSERT_FALSE(ids.empty()); diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index cf05fd4ba5..5a5067b2b9 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -222,8 +222,8 @@ public: ASSERT_EQ(InputEventType::MOTION, ev->getType()); MotionEvent* mev = static_cast<MotionEvent*>(ev); EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, mev->getAction()); - EXPECT_EQ(x, mev->getX(0)); - EXPECT_EQ(y, mev->getY(0)); + EXPECT_NEAR(x, mev->getX(0), EPSILON); + EXPECT_NEAR(y, mev->getY(0), EPSILON); EXPECT_EQ(flags, mev->getFlags() & flags); ev = consumeEvent(); @@ -241,8 +241,8 @@ public: MotionEvent* mev = static_cast<MotionEvent*>(ev); EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, mev->getAction()); const PointerCoords& coords = *mev->getRawPointerCoords(0 /*pointerIndex*/); - EXPECT_EQ(displayX, coords.getX()); - EXPECT_EQ(displayY, coords.getY()); + EXPECT_NEAR(displayX, coords.getX(), EPSILON); + EXPECT_NEAR(displayY, coords.getY(), EPSILON); EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS); ev = consumeEvent(); @@ -398,7 +398,7 @@ public: InputSurfacesTest() { ProcessState::self()->startThreadPool(); } void SetUp() { - mComposerClient = new SurfaceComposerClient; + mComposerClient = sp<SurfaceComposerClient>::make(); ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); const auto ids = SurfaceComposerClient::getPhysicalDisplayIds(); ASSERT_FALSE(ids.empty()); diff --git a/libs/gui/tests/GLTest.cpp b/libs/gui/tests/GLTest.cpp index 40af8e845a..407c18ed0d 100644 --- a/libs/gui/tests/GLTest.cpp +++ b/libs/gui/tests/GLTest.cpp @@ -56,7 +56,7 @@ void GLTest::SetUp() { } if (mDisplaySecs > 0) { - mComposerClient = new SurfaceComposerClient; + mComposerClient = sp<SurfaceComposerClient>::make(); ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); mSurfaceControl = mComposerClient->createSurface( diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp index c35efe28a3..d80d223f49 100644 --- a/libs/gui/tests/RegionSampling_test.cpp +++ b/libs/gui/tests/RegionSampling_test.cpp @@ -180,7 +180,7 @@ protected: } void SetUp() override { - mSurfaceComposerClient = new SurfaceComposerClient; + mSurfaceComposerClient = sp<SurfaceComposerClient>::make(); ASSERT_EQ(NO_ERROR, mSurfaceComposerClient->initCheck()); mBackgroundLayer = diff --git a/libs/gui/tests/SamplingDemo.cpp b/libs/gui/tests/SamplingDemo.cpp index 8fea689c91..a2fe8fd2ec 100644 --- a/libs/gui/tests/SamplingDemo.cpp +++ b/libs/gui/tests/SamplingDemo.cpp @@ -36,7 +36,7 @@ namespace android { class Button : public gui::BnRegionSamplingListener { public: Button(const char* name, const Rect& samplingArea) { - sp<SurfaceComposerClient> client = new SurfaceComposerClient; + sp<SurfaceComposerClient> client = sp<SurfaceComposerClient>::make(); mButton = client->createSurface(String8(name), 0, 0, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index e7690e2530..45cde7f10c 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -134,7 +134,7 @@ protected: } virtual void SetUp() { - mComposerClient = new SurfaceComposerClient; + mComposerClient = sp<SurfaceComposerClient>::make(); ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); // TODO(brianderson): The following sometimes fails and is a source of @@ -2246,6 +2246,52 @@ TEST_F(SurfaceTest, BatchIllegalOperations) { ASSERT_EQ(NO_ERROR, surface->disconnect(NATIVE_WINDOW_API_CPU)); } +TEST_F(SurfaceTest, setMaxDequeuedBufferCount_setMaxAcquiredBufferCount_allocations) { + // + // Set up the consumer and producer--nothing fancy. + // + auto [consumer, surface] = + BufferItemConsumer::create(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER); + sp<SurfaceListener> surfaceListener = sp<StubSurfaceListener>::make(); + surface->connect(NATIVE_WINDOW_API_CPU, surfaceListener); + sp<GraphicBuffer> buffer; + sp<Fence> fence; + + // + // These values are independent. The consumer can dequeue 3 and the consumer can acquire 3 at + // the same time. + // + ASSERT_EQ(OK, consumer->setMaxAcquiredBufferCount(3)); + ASSERT_EQ(OK, surface->setMaxDequeuedBufferCount(3)); + + // + // Take all three buffers out of the queue--a fourth can't be retrieved. Then queue them. + // + std::vector<Surface::BatchBuffer> dequeuedBuffers(3); + EXPECT_EQ(OK, surface->dequeueBuffers(&dequeuedBuffers)); + if (::com::android::graphics::libgui::flags::bq_always_use_max_dequeued_buffer_count()) { + EXPECT_EQ(INVALID_OPERATION, surface->dequeueBuffer(&buffer, &fence)); + } + + for (auto& batchBuffer : dequeuedBuffers) { + EXPECT_EQ(OK, + surface->queueBuffer(GraphicBuffer::from(batchBuffer.buffer), + sp<Fence>::make(batchBuffer.fenceFd))); + } + dequeuedBuffers.assign(3, {}); + + // + // Acquire all three, then we should be able to dequeue 3 more. + // + std::vector<BufferItem> acquiredBuffers(3); + for (auto& bufferItem : acquiredBuffers) { + EXPECT_EQ(OK, consumer->acquireBuffer(&bufferItem, 0)); + } + + EXPECT_EQ(OK, surface->dequeueBuffers(&dequeuedBuffers)); + EXPECT_EQ(INVALID_OPERATION, surface->dequeueBuffer(&buffer, &fence)); +} + #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) TEST_F(SurfaceTest, PlatformBufferMethods) { @@ -2653,4 +2699,57 @@ TEST_F(SurfaceTest, UnlimitedSlots_BatchOperations) { EXPECT_EQ(128u, outputs.size()); } #endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + +TEST_F(SurfaceTest, isBufferOwned) { + const int TEST_USAGE_FLAGS = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER; + auto [bufferItemConsumer, surface] = BufferItemConsumer::create(TEST_USAGE_FLAGS); + + sp<SurfaceListener> listener = sp<StubSurfaceListener>::make(); + ASSERT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, listener)); + + sp<GraphicBuffer> surfaceAttachableBuffer = + sp<GraphicBuffer>::make(10, 10, PIXEL_FORMAT_RGBA_8888, 1, TEST_USAGE_FLAGS); + + // + // Attaching a buffer makes it owned. + // + + bool isOwned; + EXPECT_EQ(OK, surface->isBufferOwned(surfaceAttachableBuffer, &isOwned)); + EXPECT_FALSE(isOwned); + + EXPECT_EQ(OK, surface->attachBuffer(surfaceAttachableBuffer.get())); + EXPECT_EQ(OK, surface->isBufferOwned(surfaceAttachableBuffer, &isOwned)); + EXPECT_TRUE(isOwned); + + // + // A dequeued buffer is always owned. + // + + sp<GraphicBuffer> buffer; + sp<Fence> fence; + EXPECT_EQ(OK, surface->dequeueBuffer(&buffer, &fence)); + EXPECT_EQ(OK, surface->isBufferOwned(buffer, &isOwned)); + EXPECT_TRUE(isOwned); + + // + // A detached buffer is no longer owned. + // + + EXPECT_EQ(OK, surface->detachBuffer(buffer)); + EXPECT_EQ(OK, surface->isBufferOwned(buffer, &isOwned)); + EXPECT_FALSE(isOwned); + + // + // It's not currently possible to verify whether or not a consumer has attached a buffer until + // it shows up on the Surface. + // + + sp<GraphicBuffer> consumerAttachableBuffer = + sp<GraphicBuffer>::make(10, 10, PIXEL_FORMAT_RGBA_8888, 1, TEST_USAGE_FLAGS); + + ASSERT_EQ(OK, bufferItemConsumer->attachBuffer(consumerAttachableBuffer)); + EXPECT_EQ(OK, surface->isBufferOwned(consumerAttachableBuffer, &isOwned)); + EXPECT_FALSE(isOwned); +} } // namespace android diff --git a/libs/input/Android.bp b/libs/input/Android.bp index ff26184a33..52e0276cad 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -225,6 +225,7 @@ cc_library { srcs: [ "AccelerationCurve.cpp", "CoordinateFilter.cpp", + "DisplayTopologyGraph.cpp", "Input.cpp", "InputConsumer.cpp", "InputConsumerNoResampling.cpp", @@ -270,6 +271,7 @@ cc_library { shared_libs: [ "android.companion.virtualdevice.flags-aconfig-cc", + "com.android.window.flags.window-aconfig_flags_c_lib", "libPlatformProperties", "libaconfig_storage_read_api_cc", "libbase", diff --git a/libs/input/DisplayTopologyGraph.cpp b/libs/input/DisplayTopologyGraph.cpp new file mode 100644 index 0000000000..934f2e8135 --- /dev/null +++ b/libs/input/DisplayTopologyGraph.cpp @@ -0,0 +1,144 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "DisplayTopologyValidator" + +#include <android-base/logging.h> +#include <android-base/stringprintf.h> +#include <ftl/enum.h> +#include <input/DisplayTopologyGraph.h> +#include <input/PrintTools.h> +#include <ui/LogicalDisplayId.h> + +#include <algorithm> + +#define INDENT " " + +namespace android { + +namespace { + +DisplayTopologyPosition getOppositePosition(DisplayTopologyPosition position) { + switch (position) { + case DisplayTopologyPosition::LEFT: + return DisplayTopologyPosition::RIGHT; + case DisplayTopologyPosition::TOP: + return DisplayTopologyPosition::BOTTOM; + case DisplayTopologyPosition::RIGHT: + return DisplayTopologyPosition::LEFT; + case DisplayTopologyPosition::BOTTOM: + return DisplayTopologyPosition::TOP; + } +} + +bool validatePrimaryDisplay(const android::DisplayTopologyGraph& displayTopologyGraph) { + return displayTopologyGraph.primaryDisplayId != ui::LogicalDisplayId::INVALID && + displayTopologyGraph.graph.contains(displayTopologyGraph.primaryDisplayId); +} + +bool validateTopologyGraph(const android::DisplayTopologyGraph& displayTopologyGraph) { + for (const auto& [sourceDisplay, adjacentDisplays] : displayTopologyGraph.graph) { + for (const DisplayTopologyAdjacentDisplay& adjacentDisplay : adjacentDisplays) { + const auto adjacentGraphIt = displayTopologyGraph.graph.find(adjacentDisplay.displayId); + if (adjacentGraphIt == displayTopologyGraph.graph.end()) { + LOG(ERROR) << "Missing adjacent display in topology graph: " + << adjacentDisplay.displayId << " for source " << sourceDisplay; + return false; + } + const auto reverseEdgeIt = + std::find_if(adjacentGraphIt->second.begin(), adjacentGraphIt->second.end(), + [sourceDisplay](const DisplayTopologyAdjacentDisplay& + reverseAdjacentDisplay) { + return sourceDisplay == reverseAdjacentDisplay.displayId; + }); + if (reverseEdgeIt == adjacentGraphIt->second.end()) { + LOG(ERROR) << "Missing reverse edge in topology graph for: " << sourceDisplay + << " -> " << adjacentDisplay.displayId; + return false; + } + DisplayTopologyPosition expectedPosition = + getOppositePosition(adjacentDisplay.position); + if (reverseEdgeIt->position != expectedPosition) { + LOG(ERROR) << "Unexpected reverse edge for: " << sourceDisplay << " -> " + << adjacentDisplay.displayId + << " expected position: " << ftl::enum_string(expectedPosition) + << " actual " << ftl::enum_string(reverseEdgeIt->position); + return false; + } + if (reverseEdgeIt->offsetDp != -adjacentDisplay.offsetDp) { + LOG(ERROR) << "Unexpected reverse edge offset: " << sourceDisplay << " -> " + << adjacentDisplay.displayId + << " expected offset: " << -adjacentDisplay.offsetDp << " actual " + << reverseEdgeIt->offsetDp; + return false; + } + } + } + return true; +} + +bool validateDensities(const android::DisplayTopologyGraph& displayTopologyGraph) { + for (const auto& [sourceDisplay, adjacentDisplays] : displayTopologyGraph.graph) { + if (!displayTopologyGraph.displaysDensity.contains(sourceDisplay)) { + LOG(ERROR) << "Missing density value in topology graph for display: " << sourceDisplay; + return false; + } + } + return true; +} + +std::string logicalDisplayIdToString(const ui::LogicalDisplayId& displayId) { + return base::StringPrintf("displayId(%d)", displayId.val()); +} + +std::string adjacentDisplayToString(const DisplayTopologyAdjacentDisplay& adjacentDisplay) { + return adjacentDisplay.dump(); +} + +std::string adjacentDisplayVectorToString( + const std::vector<DisplayTopologyAdjacentDisplay>& adjacentDisplays) { + return dumpVector(adjacentDisplays, adjacentDisplayToString); +} + +} // namespace + +std::string DisplayTopologyAdjacentDisplay::dump() const { + std::string dump; + dump += base::StringPrintf("DisplayTopologyAdjacentDisplay: {displayId: %d, position: %s, " + "offsetDp: %f}", + displayId.val(), ftl::enum_string(position).c_str(), offsetDp); + return dump; +} + +bool DisplayTopologyGraph::isValid() const { + return validatePrimaryDisplay(*this) && validateTopologyGraph(*this) && + validateDensities(*this); +} + +std::string DisplayTopologyGraph::dump() const { + std::string dump; + dump += base::StringPrintf("PrimaryDisplayId: %d\n", primaryDisplayId.val()); + dump += base::StringPrintf("TopologyGraph:\n"); + dump += addLinePrefix(dumpMap(graph, logicalDisplayIdToString, adjacentDisplayVectorToString), + INDENT); + dump += "\n"; + dump += base::StringPrintf("DisplaysDensity:\n"); + dump += addLinePrefix(dumpMap(displaysDensity, logicalDisplayIdToString), INDENT); + dump += "\n"; + return dump; +} + +} // namespace android diff --git a/libs/input/InputFlags.cpp b/libs/input/InputFlags.cpp index f866f9b8f0..6aa9ae6b16 100644 --- a/libs/input/InputFlags.cpp +++ b/libs/input/InputFlags.cpp @@ -18,6 +18,7 @@ #include <android-base/logging.h> #include <com_android_input_flags.h> +#include <com_android_window_flags.h> #include <cutils/properties.h> #include <string> @@ -25,6 +26,9 @@ namespace android { bool InputFlags::connectedDisplaysCursorEnabled() { + if (!com::android::window::flags::enable_desktop_mode_through_dev_option()) { + return com::android::input::flags::connected_displays_cursor(); + } static std::optional<bool> cachedDevOption; if (!cachedDevOption.has_value()) { char value[PROPERTY_VALUE_MAX]; diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig index de5e42875e..9e69b60f93 100644 --- a/libs/input/input_flags.aconfig +++ b/libs/input/input_flags.aconfig @@ -26,13 +26,6 @@ flag { } flag { - name: "remove_input_channel_from_windowstate" - namespace: "input" - description: "Do not store a copy of input channel inside WindowState." - bug: "323450804" -} - -flag { name: "enable_input_event_tracing" namespace: "input" description: "Set to true to enable input event tracing, including always-on tracing on non-user builds" @@ -120,6 +113,16 @@ flag { } flag { + name: "allow_transfer_of_entire_gesture" + namespace: "input" + description: "When calling 'transferTouchGesture', the entire gesture (including new POINTER_DOWN events from the same device) will be automatically transferred to the destination window" + bug: "397979572" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "enable_keyboard_classifier" namespace: "input" description: "Keyboard classifier that classifies all keyboards into alphabetic or non-alphabetic" @@ -246,3 +249,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "enable_display_topology_validation" + namespace: "input" + description: "Set to true to enable display topology validation" + bug: "401219231" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index 7f207f0670..f9b84fa948 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -25,6 +25,7 @@ cc_defaults { defaults: [ "android.hardware.graphics.composer3-ndk_shared", "renderengine_defaults", + "libsurfaceflinger_common_deps", ], cflags: [ "-DGL_GLEXT_PROTOTYPES", @@ -117,7 +118,10 @@ filegroup { // possible if libskia_renderengine is just pulled into librenderengine via whole_static_libs. cc_defaults { name: "librenderengine_deps", - defaults: ["skia_renderengine_deps"], + defaults: [ + "skia_renderengine_deps", + "libsurfaceflinger_common_deps", + ], static_libs: ["libskia_renderengine"], } diff --git a/libs/renderengine/benchmark/Android.bp b/libs/renderengine/benchmark/Android.bp index f84db0b04c..2d18ddb0aa 100644 --- a/libs/renderengine/benchmark/Android.bp +++ b/libs/renderengine/benchmark/Android.bp @@ -28,6 +28,7 @@ cc_benchmark { "android.hardware.graphics.composer3-ndk_shared", "librenderengine_deps", "surfaceflinger_defaults", + "libsurfaceflinger_common_deps", ], srcs: [ "main.cpp", @@ -38,7 +39,6 @@ cc_benchmark { static_libs: [ "librenderengine", "libshaders", - "libsurfaceflinger_common", "libtonemap", ], cflags: [ diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp index 5f2d1b1be6..9e1c226371 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaRenderEngine.cpp @@ -347,6 +347,7 @@ void SkiaRenderEngine::useProtectedContext(bool useProtectedContext) { if (useProtectedContextImpl( useProtectedContext ? GrProtected::kYes : GrProtected::kNo)) { mInProtectedContext = useProtectedContext; + SFTRACE_INT("RE inProtectedContext", mInProtectedContext); // given that we are sharing the same thread between two contexts we need to // make sure that the thread state is reset when switching between the two. if (getActiveContext()) { @@ -1235,6 +1236,16 @@ void SkiaRenderEngine::drawLayersInternal( LOG_ALWAYS_FATAL_IF(activeSurface != dstSurface); auto drawFence = sp<Fence>::make(flushAndSubmit(context, dstSurface)); trace(drawFence); + FenceTimePtr fenceTime = FenceTime::makeValid(drawFence); + for (const auto& layer : layers) { + if (FlagManager::getInstance().monitor_buffer_fences()) { + if (layer.source.buffer.buffer) { + layer.source.buffer.buffer->getBuffer() + ->getDependencyMonitor() + .addAccessCompletion(fenceTime, "RE"); + } + } + } resultPromise->set_value(std::move(drawFence)); } diff --git a/libs/renderengine/skia/filters/LutShader.cpp b/libs/renderengine/skia/filters/LutShader.cpp index f262158f2c..6a577ff41f 100644 --- a/libs/renderengine/skia/filters/LutShader.cpp +++ b/libs/renderengine/skia/filters/LutShader.cpp @@ -24,7 +24,6 @@ #include <ui/ColorSpace.h> #include "include/core/SkColorSpace.h" -#include "src/core/SkColorFilterPriv.h" using aidl::android::hardware::graphics::composer3::LutProperties; @@ -116,7 +115,7 @@ static const SkString kShader = SkString(R"( linear = mix(c0, c1, linear.b); } } - return float4(linear, rgba.a); + return float4(fromLinearSrgb(linear), rgba.a); })"); // same as shader::toColorSpace function @@ -289,9 +288,7 @@ sk_sp<SkShader> LutShader::lutShader(sk_sp<SkShader>& input, lutProperties[i].samplingKey, srcDataspace); } - auto colorXformLutToDst = - SkColorFilterPriv::MakeColorSpaceXform(lutMathColorSpace, outColorSpace); - input = input->makeWithColorFilter(colorXformLutToDst); + input = input->makeWithWorkingColorSpace(outColorSpace); } return input; } diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 87e213e394..10cb992835 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -122,6 +122,7 @@ cc_library_shared { srcs: [ "DebugUtils.cpp", + "DependencyMonitor.cpp", "DeviceProductInfo.cpp", "DisplayIdentification.cpp", "DynamicDisplayInfo.cpp", diff --git a/libs/ui/DependencyMonitor.cpp b/libs/ui/DependencyMonitor.cpp new file mode 100644 index 0000000000..b7e490eba4 --- /dev/null +++ b/libs/ui/DependencyMonitor.cpp @@ -0,0 +1,144 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// #define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "DependencyMonitor" + +#include <ui/DependencyMonitor.h> +#include <ui/Fence.h> +#include <utils/Timers.h> + +#include <inttypes.h> + +namespace android { + +void DependencyMonitor::addIngress(FenceTimePtr fence, std::string annotation) { + std::lock_guard lock(mMutex); + resolveLocked(); + if (mDependencies.isFull() && !mDependencies.front().updateSignalTimes(true)) { + ALOGD("%s: Clobbering unresolved dependencies -- make me bigger!", mToken.c_str()); + } + + auto& entry = mDependencies.next(); + entry.reset(mToken.c_str()); + ALOGV("%" PRId64 "/%s: addIngress at CPU time %" PRId64 " (%s)", mDependencies.back().id, + mToken.c_str(), systemTime(), annotation.c_str()); + + mDependencies.back().ingress = {std::move(fence), std::move(annotation)}; +} + +void DependencyMonitor::addAccessCompletion(FenceTimePtr fence, std::string annotation) { + std::lock_guard lock(mMutex); + if (mDependencies.size() == 0) { + return; + } + ALOGV("%" PRId64 "/%s: addAccessCompletion at CPU time %" PRId64 " (%s)", + mDependencies.back().id, mToken.c_str(), systemTime(), annotation.c_str()); + mDependencies.back().accessCompletions.emplace_back(std::move(fence), std::move(annotation)); +} + +void DependencyMonitor::addEgress(FenceTimePtr fence, std::string annotation) { + std::lock_guard lock(mMutex); + if (mDependencies.size() == 0) { + return; + } + ALOGV("%" PRId64 "/%s: addEgress at CPU time %" PRId64 " (%s)", mDependencies.back().id, + mToken.c_str(), systemTime(), annotation.c_str()); + mDependencies.back().egress = {std::move(fence), std::move(annotation)}; +} + +void DependencyMonitor::resolveLocked() { + if (mDependencies.size() == 0) { + return; + } + + for (size_t i = mDependencies.size(); i > 0; i--) { + auto& dependencyBlock = mDependencies[i - 1]; + + if (dependencyBlock.validated) { + continue; + } + + if (!dependencyBlock.updateSignalTimes(false)) { + break; + } + + dependencyBlock.validated = true; + dependencyBlock.checkUnsafeAccess(); + } +} + +bool DependencyMonitor::DependencyBlock::updateSignalTimes(bool excludeIngress) { + if (egress.fence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) { + return false; + } + + if (!excludeIngress && ingress.fence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) { + return false; + } + + for (auto& accessCompletion : accessCompletions) { + if (accessCompletion.fence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) { + return false; + } + } + + return true; +} + +void DependencyMonitor::DependencyBlock::checkUnsafeAccess() const { + const nsecs_t egressTime = egress.fence->getCachedSignalTime(); + const nsecs_t ingressTime = ingress.fence->getCachedSignalTime(); + + ALOGV_IF(egressTime != Fence::SIGNAL_TIME_INVALID, + "%" PRId64 "/%s: Egress time: %" PRId64 " (%s)", token, id, egressTime, + egress.annotation.c_str()); + ALOGV_IF(Fence::isValidTimestamp(egressTime) && Fence::isValidTimestamp(ingressTime) && + egressTime < ingressTime, + "%" PRId64 "/%s: Detected egress before ingress!: %" PRId64 " (%s) < %" PRId64 " (%s)", + id, token, egressTime, egress.annotation, ingressTime, ingress.annotation.c_str()); + + for (auto& accessCompletion : accessCompletions) { + const nsecs_t accessCompletionTime = accessCompletion.fence->getCachedSignalTime(); + if (!Fence::isValidTimestamp(accessCompletionTime)) { + ALOGI("%" PRId64 "/%s: Detected invalid access completion! <%s>", id, token, + accessCompletion.annotation.c_str()); + continue; + } else { + ALOGV("%" PRId64 "/%s: Access completion time: %" PRId64 " <%s>", id, token, + accessCompletionTime, accessCompletion.annotation.c_str()); + } + + ALOGI_IF(Fence::isValidTimestamp(egressTime) && accessCompletionTime > egressTime, + "%" PRId64 "/%s: Detected access completion after egress!: %" PRId64 + " (%s) > %" PRId64 " (%s)", + id, token, accessCompletionTime, accessCompletion.annotation.c_str(), egressTime, + egress.annotation.c_str()); + + ALOGI_IF(Fence::isValidTimestamp(ingressTime) && accessCompletionTime < ingressTime, + "%" PRId64 "/%s: Detected access completion prior to ingress!: %" PRId64 + " (%s) < %" PRId64 " (%s)", + id, token, accessCompletionTime, accessCompletion.annotation.c_str(), ingressTime, + ingress.annotation.c_str()); + } + + ALOGV_IF(ingressTime != Fence::SIGNAL_TIME_INVALID, + "%" PRId64 "/%s: Ingress time: %" PRId64 " (%s)", id, token, ingressTime, + ingress.annotation.c_str()); +} + +} // namespace android
\ No newline at end of file diff --git a/libs/ui/FenceTime.cpp b/libs/ui/FenceTime.cpp index 4246c40f64..81afe9ef0e 100644 --- a/libs/ui/FenceTime.cpp +++ b/libs/ui/FenceTime.cpp @@ -59,6 +59,14 @@ FenceTime::FenceTime(nsecs_t signalTime) } } +FenceTimePtr FenceTime::makeValid(const sp<Fence>& fence) { + if (fence && fence->isValid()) { + return std::make_shared<FenceTime>(fence); + } else { + return std::make_shared<FenceTime>(systemTime()); + } +} + void FenceTime::applyTrustedSnapshot(const Snapshot& src) { if (CC_UNLIKELY(src.state != Snapshot::State::SIGNAL_TIME)) { // Applying Snapshot::State::FENCE, could change the valid state of the @@ -289,9 +297,10 @@ status_t FenceTime::Snapshot::unflatten( // ============================================================================ void FenceTimeline::push(const std::shared_ptr<FenceTime>& fence) { std::lock_guard<std::mutex> lock(mMutex); - while (mQueue.size() >= MAX_ENTRIES) { + static constexpr size_t MAX_QUEUE_SIZE = 64; + while (mQueue.size() >= MAX_QUEUE_SIZE) { // This is a sanity check to make sure the queue doesn't grow unbounded. - // MAX_ENTRIES should be big enough not to trigger this path. + // MAX_QUEUE_SIZE should be big enough not to trigger this path. // In case this path is taken though, users of FenceTime must make sure // not to rely solely on FenceTimeline to get the final timestamp and // should eventually call Fence::getSignalTime on their own. diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index 18c9a6bc48..f7c94005f1 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -27,6 +27,8 @@ #include <ui/GraphicBufferMapper.h> #include <utils/Trace.h> +#include <string> + namespace android { // =========================================================================== @@ -104,6 +106,7 @@ GraphicBuffer::GraphicBuffer() usage = 0; layerCount = 0; handle = nullptr; + mDependencyMonitor.setToken(std::to_string(mId)); } // deprecated @@ -155,6 +158,8 @@ GraphicBuffer::GraphicBuffer(const GraphicBufferAllocator::AllocationRequest& re layerCount = request.layerCount; usage = request.usage; usage_deprecated = int(usage); + std::string name = request.requestorName; + mDependencyMonitor.setToken(name.append(":").append(std::to_string(mId))); } } @@ -252,6 +257,7 @@ status_t GraphicBuffer::initWithSize(uint32_t inWidth, uint32_t inHeight, usage = inUsage; usage_deprecated = int(usage); stride = static_cast<int>(outStride); + mDependencyMonitor.setToken(requestorName.append(":").append(std::to_string(mId))); } return err; } @@ -609,6 +615,14 @@ status_t GraphicBuffer::unflatten(void const*& buffer, size_t& size, int const*& mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts); } + std::string name; + status_t err = mBufferMapper.getName(handle, &name); + if (err != NO_ERROR) { + name = "<Unknown>"; + } + + mDependencyMonitor.setToken(name.append(":").append(std::to_string(mId))); + buffer = static_cast<void const*>(static_cast<uint8_t const*>(buffer) + sizeNeeded); size -= sizeNeeded; fds += numFds; diff --git a/libs/ui/include/ui/DependencyMonitor.h b/libs/ui/include/ui/DependencyMonitor.h new file mode 100644 index 0000000000..5ad1fd9528 --- /dev/null +++ b/libs/ui/include/ui/DependencyMonitor.h @@ -0,0 +1,104 @@ +/* + * Copyright 2025 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 <ui/FatVector.h> +#include <ui/FenceTime.h> +#include <ui/RingBuffer.h> + +namespace android { + +// Debugging class for that tries to add userspace logging for fence depencencies. +// The model that a DependencyMonitor tries to follow is, for each access of some resource: +// 1. There is a single ingress fence, that guards whether a resource is now safe to read from +// another system. +// 2. There are multiple access fences, that are fired when a resource is read. +// 3. There is a single egress fence, that is fired when a resource is released and sent to another +// system. +// +// Note that there can be repeated ingress and egress of a resource, but the assumption is that +// there is exactly one egress for every ingress, unless the resource is destroyed rather than +// released. +// +// The DependencyMonitor will log if there is an anomaly in the fences tracked for some resource. +// This includes: +// * If (2) happens before (1) +// * If (2) happens after (3) +// +// Note that this class has no knowledge of the "other system". I.e., if the other system ignores +// the fence reported in (3), but still takes a long time to write to the resource and produce (1), +// then nothing will be logged. That other system must have its own DependencyMonitor. Conversely, +// this class has imperfect knowledge of the system it is monitoring. For example, this class does +// not know the precise start times of reading from a resource, the exact time that a read might +// occur from a hardware unit is not known to userspace. +// +// In other words, this class logs specific classes of fence violations, but is not sensitive to +// *all* violations. One property of this is that unless the system tracked by a DependencyMonitor +// is feeding in literally incorrect fences, then there is no chance of a false positive. +// +// This class is thread safe. +class DependencyMonitor { +public: + // Sets a debug token identifying the resource this monitor is tracking. + void setToken(std::string token) { mToken = std::move(token); } + + // Adds a fence that is fired when the resource ready to be ingested by the system using the + // DependencyMonitor. + void addIngress(FenceTimePtr fence, std::string annotation); + // Adds a fence that is fired when the resource is accessed. + void addAccessCompletion(FenceTimePtr fence, std::string annotation); + // Adds a fence that is fired when the resource is released to another system. + void addEgress(FenceTimePtr fence, std::string annotation); + +private: + struct AnnotatedFenceTime { + FenceTimePtr fence; + std::string annotation; + }; + + struct DependencyBlock { + int64_t id = -1; + AnnotatedFenceTime ingress = {FenceTime::NO_FENCE, ""}; + FatVector<AnnotatedFenceTime> accessCompletions; + AnnotatedFenceTime egress = {FenceTime::NO_FENCE, ""}; + bool validated = false; + const char* token = nullptr; + + void reset(const char* newToken) { + static std::atomic<int64_t> counter = 0; + id = counter++; + ingress = {FenceTime::NO_FENCE, ""}; + accessCompletions.clear(); + egress = {FenceTime::NO_FENCE, ""}; + validated = false; + token = newToken; + } + + // Returns true if all fences in this block have valid signal times. + bool updateSignalTimes(bool excludeIngress); + + void checkUnsafeAccess() const; + }; + + void resolveLocked() REQUIRES(mMutex); + + std::string mToken; + std::mutex mMutex; + ui::RingBuffer<DependencyBlock, 10> mDependencies GUARDED_BY(mMutex); +}; + +} // namespace android
\ No newline at end of file diff --git a/libs/ui/include/ui/DisplayId.h b/libs/ui/include/ui/DisplayId.h index 937e3f1486..1e1c77b9fc 100644 --- a/libs/ui/include/ui/DisplayId.h +++ b/libs/ui/include/ui/DisplayId.h @@ -20,6 +20,7 @@ #include <ostream> #include <string> +#include <ftl/match.h> #include <ftl/optional.h> namespace android { @@ -36,7 +37,6 @@ struct DisplayId { DisplayId& operator=(const DisplayId&) = default; static constexpr DisplayId fromValue(uint64_t value) { return DisplayId(value); } - constexpr bool isVirtual() const { return value & FLAG_VIRTUAL; } uint64_t value; @@ -66,13 +66,6 @@ struct PhysicalDisplayId : DisplayId { // TODO: b/162612135 - Remove default constructor. PhysicalDisplayId() = default; - static constexpr ftl::Optional<PhysicalDisplayId> tryCast(DisplayId id) { - if (id.isVirtual()) { - return std::nullopt; - } - return PhysicalDisplayId(id); - } - // Returns a stable ID based on EDID and port information. static constexpr PhysicalDisplayId fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t modelHash) { @@ -90,8 +83,6 @@ struct PhysicalDisplayId : DisplayId { return PhysicalDisplayId(value); } - constexpr uint8_t getPort() const { return static_cast<uint8_t>(value); } - private: // Flag indicating that the ID is stable across reboots. static constexpr uint64_t FLAG_STABLE = 1ULL << 62; @@ -112,13 +103,6 @@ struct VirtualDisplayId : DisplayId { // Flag indicating that this virtual display is backed by the GPU. static constexpr uint64_t FLAG_GPU = 1ULL << 61; - static constexpr std::optional<VirtualDisplayId> tryCast(DisplayId id) { - if (id.isVirtual()) { - return VirtualDisplayId(id); - } - return std::nullopt; - } - static constexpr VirtualDisplayId fromValue(uint64_t value) { return VirtualDisplayId(SkipVirtualFlag{}, value); } @@ -134,13 +118,6 @@ protected: struct HalVirtualDisplayId : VirtualDisplayId { explicit constexpr HalVirtualDisplayId(BaseId baseId) : VirtualDisplayId(baseId) {} - static constexpr std::optional<HalVirtualDisplayId> tryCast(DisplayId id) { - if (id.isVirtual() && !(id.value & FLAG_GPU)) { - return HalVirtualDisplayId(id); - } - return std::nullopt; - } - static constexpr HalVirtualDisplayId fromValue(uint64_t value) { return HalVirtualDisplayId(SkipVirtualFlag{}, value); } @@ -152,13 +129,6 @@ private: struct GpuVirtualDisplayId : VirtualDisplayId { explicit constexpr GpuVirtualDisplayId(BaseId baseId) : VirtualDisplayId(FLAG_GPU | baseId) {} - static constexpr std::optional<GpuVirtualDisplayId> tryCast(DisplayId id) { - if (id.isVirtual() && (id.value & FLAG_GPU)) { - return GpuVirtualDisplayId(id); - } - return std::nullopt; - } - static constexpr GpuVirtualDisplayId fromValue(uint64_t value) { return GpuVirtualDisplayId(SkipVirtualFlag{}, value); } @@ -172,14 +142,6 @@ private: struct HalDisplayId : DisplayId { constexpr HalDisplayId(HalVirtualDisplayId other) : DisplayId(other) {} constexpr HalDisplayId(PhysicalDisplayId other) : DisplayId(other) {} - - static constexpr std::optional<HalDisplayId> tryCast(DisplayId id) { - if (GpuVirtualDisplayId::tryCast(id)) { - return std::nullopt; - } - return HalDisplayId(id); - } - static constexpr HalDisplayId fromValue(uint64_t value) { return HalDisplayId(value); } private: @@ -187,6 +149,47 @@ private: explicit constexpr HalDisplayId(DisplayId other) : DisplayId(other) {} }; +using DisplayIdVariant = std::variant<PhysicalDisplayId, GpuVirtualDisplayId, HalVirtualDisplayId>; +using VirtualDisplayIdVariant = std::variant<GpuVirtualDisplayId, HalVirtualDisplayId>; + +template <typename DisplayIdType> +inline auto asDisplayIdOfType(DisplayIdVariant variant) -> ftl::Optional<DisplayIdType> { + return ftl::match( + variant, + [](DisplayIdType id) -> ftl::Optional<DisplayIdType> { return ftl::Optional(id); }, + [](auto) -> ftl::Optional<DisplayIdType> { return std::nullopt; }); +} + +template <typename Variant> +inline auto asHalDisplayId(Variant variant) -> ftl::Optional<HalDisplayId> { + return ftl::match( + variant, + [](GpuVirtualDisplayId) -> ftl::Optional<HalDisplayId> { return std::nullopt; }, + [](auto id) -> ftl::Optional<HalDisplayId> { + return ftl::Optional(static_cast<HalDisplayId>(id)); + }); +} + +inline auto asPhysicalDisplayId(DisplayIdVariant variant) -> ftl::Optional<PhysicalDisplayId> { + return asDisplayIdOfType<PhysicalDisplayId>(variant); +} + +inline auto asVirtualDisplayId(DisplayIdVariant variant) -> ftl::Optional<VirtualDisplayId> { + return ftl::match( + variant, + [](GpuVirtualDisplayId id) -> ftl::Optional<VirtualDisplayId> { + return ftl::Optional(static_cast<VirtualDisplayId>(id)); + }, + [](HalVirtualDisplayId id) -> ftl::Optional<VirtualDisplayId> { + return ftl::Optional(static_cast<VirtualDisplayId>(id)); + }, + [](auto) -> ftl::Optional<VirtualDisplayId> { return std::nullopt; }); +} + +inline auto asDisplayId(DisplayIdVariant variant) -> DisplayId { + return ftl::match(variant, [](auto id) -> DisplayId { return static_cast<DisplayId>(id); }); +} + static_assert(sizeof(DisplayId) == sizeof(uint64_t)); static_assert(sizeof(HalDisplayId) == sizeof(uint64_t)); static_assert(sizeof(VirtualDisplayId) == sizeof(uint64_t)); diff --git a/libs/ui/include/ui/DisplayIdentification.h b/libs/ui/include/ui/DisplayIdentification.h index 1e3449c004..201d5e9ff5 100644 --- a/libs/ui/include/ui/DisplayIdentification.h +++ b/libs/ui/include/ui/DisplayIdentification.h @@ -39,12 +39,29 @@ struct DetailedTimingDescriptor { ui::Size physicalSizeInMm; }; +// These values must match the ones in ScreenPartStatus.aidl file in the composer HAL +enum class ScreenPartStatus : uint8_t { + /** + * Device cannot differentiate an original screen from a replaced screen. + */ + UNSUPPORTED = 0, + /** + * Device has the original screen it was manufactured with. + */ + ORIGINAL = 1, + /** + * Device has a replaced screen. + */ + REPLACED = 2, +}; + struct DisplayIdentificationInfo { PhysicalDisplayId id; std::string name; uint8_t port; std::optional<DeviceProductInfo> deviceProductInfo; std::optional<DetailedTimingDescriptor> preferredDetailedTimingDescriptor; + ScreenPartStatus screenPartStatus; }; struct ExtensionBlock { diff --git a/libs/ui/include/ui/FenceTime.h b/libs/ui/include/ui/FenceTime.h index 334106f0cf..3560d57cff 100644 --- a/libs/ui/include/ui/FenceTime.h +++ b/libs/ui/include/ui/FenceTime.h @@ -17,6 +17,7 @@ #ifndef ANDROID_FENCE_TIME_H #define ANDROID_FENCE_TIME_H +#include <stddef.h> #include <ui/Fence.h> #include <utils/Flattenable.h> #include <utils/Mutex.h> @@ -30,6 +31,8 @@ namespace android { class FenceToFenceTimeMap; +class FenceTime; +using FenceTimePtr = std::shared_ptr<FenceTime>; // A wrapper around fence that only implements isValid and getSignalTime. // It automatically closes the fence in a thread-safe manner once the signal @@ -95,6 +98,10 @@ public: FenceTime& operator=(const FenceTime&) = delete; FenceTime& operator=(FenceTime&&) = delete; + // Constructs a FenceTime, falling back to a timestamp if the fence is + // invalid. + static FenceTimePtr makeValid(const sp<Fence>& fence); + // This method should only be called when replacing the fence with // a signalTime. Since this is an indirect way of setting the signal time // of a fence, the snapshot should come from a trusted source. @@ -142,8 +149,6 @@ private: std::atomic<nsecs_t> mSignalTime{Fence::SIGNAL_TIME_INVALID}; }; -using FenceTimePtr = std::shared_ptr<FenceTime>; - // A queue of FenceTimes that are expected to signal in FIFO order. // Only maintains a queue of weak pointers so it doesn't keep references // to Fences on its own. @@ -162,8 +167,6 @@ using FenceTimePtr = std::shared_ptr<FenceTime>; // different threads. class FenceTimeline { public: - static constexpr size_t MAX_ENTRIES = 64; - void push(const std::shared_ptr<FenceTime>& fence); void updateSignalTimes(); diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h index 936bf8f862..9305180ecb 100644 --- a/libs/ui/include/ui/GraphicBuffer.h +++ b/libs/ui/include/ui/GraphicBuffer.h @@ -23,6 +23,7 @@ #include <string> #include <utility> #include <vector> +#include "ui/DependencyMonitor.h" #include <android/hardware_buffer.h> #include <ui/ANativeObjectBase.h> @@ -229,6 +230,8 @@ public: void addDeathCallback(GraphicBufferDeathCallback deathCallback, void* context); + DependencyMonitor& getDependencyMonitor() { return mDependencyMonitor; } + private: ~GraphicBuffer(); @@ -295,6 +298,8 @@ private: // and informs SurfaceFlinger that it should drop its strong pointer reference to the buffer. std::vector<std::pair<GraphicBufferDeathCallback, void* /*mDeathCallbackContext*/>> mDeathCallbacks; + + DependencyMonitor mDependencyMonitor; }; } // namespace android diff --git a/libs/ui/include/ui/StaticDisplayInfo.h b/libs/ui/include/ui/StaticDisplayInfo.h index 83da821f37..53164487f3 100644 --- a/libs/ui/include/ui/StaticDisplayInfo.h +++ b/libs/ui/include/ui/StaticDisplayInfo.h @@ -28,6 +28,7 @@ enum class DisplayConnectionType { Internal, External, ftl_last = External }; // Immutable information about physical display. struct StaticDisplayInfo { DisplayConnectionType connectionType = DisplayConnectionType::Internal; + uint8_t port; float density = 0.f; bool secure = false; std::optional<DeviceProductInfo> deviceProductInfo; diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp index 2b11786df3..d950f2a23f 100644 --- a/libs/ui/tests/Android.bp +++ b/libs/ui/tests/Android.bp @@ -45,16 +45,6 @@ cc_test { } cc_test { - name: "DisplayId_test", - shared_libs: ["libui"], - srcs: ["DisplayId_test.cpp"], - cflags: [ - "-Wall", - "-Werror", - ], -} - -cc_test { name: "DisplayIdentification_test", shared_libs: ["libui"], static_libs: ["libgmock"], diff --git a/libs/ui/tests/DisplayId_test.cpp b/libs/ui/tests/DisplayId_test.cpp deleted file mode 100644 index 209acba672..0000000000 --- a/libs/ui/tests/DisplayId_test.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <ui/DisplayId.h> - -#include <gtest/gtest.h> - -namespace android::ui { - -TEST(DisplayIdTest, createPhysicalIdFromEdid) { - constexpr uint8_t port = 1; - constexpr uint16_t manufacturerId = 13; - constexpr uint32_t modelHash = 42; - const PhysicalDisplayId id = PhysicalDisplayId::fromEdid(port, manufacturerId, modelHash); - EXPECT_EQ(port, id.getPort()); - EXPECT_FALSE(VirtualDisplayId::tryCast(id)); - EXPECT_FALSE(HalVirtualDisplayId::tryCast(id)); - EXPECT_FALSE(GpuVirtualDisplayId::tryCast(id)); - EXPECT_TRUE(PhysicalDisplayId::tryCast(id)); - EXPECT_TRUE(HalDisplayId::tryCast(id)); - - EXPECT_EQ(id, DisplayId::fromValue(id.value)); - EXPECT_EQ(id, PhysicalDisplayId::fromValue(id.value)); -} - -TEST(DisplayIdTest, createPhysicalIdFromPort) { - constexpr uint8_t port = 3; - const PhysicalDisplayId id = PhysicalDisplayId::fromPort(port); - EXPECT_EQ(port, id.getPort()); - EXPECT_FALSE(VirtualDisplayId::tryCast(id)); - EXPECT_FALSE(HalVirtualDisplayId::tryCast(id)); - EXPECT_FALSE(GpuVirtualDisplayId::tryCast(id)); - EXPECT_TRUE(PhysicalDisplayId::tryCast(id)); - EXPECT_TRUE(HalDisplayId::tryCast(id)); - - EXPECT_EQ(id, DisplayId::fromValue(id.value)); - EXPECT_EQ(id, PhysicalDisplayId::fromValue(id.value)); -} - -TEST(DisplayIdTest, createGpuVirtualId) { - const GpuVirtualDisplayId id(42); - EXPECT_TRUE(VirtualDisplayId::tryCast(id)); - EXPECT_TRUE(GpuVirtualDisplayId::tryCast(id)); - EXPECT_FALSE(HalVirtualDisplayId::tryCast(id)); - EXPECT_FALSE(PhysicalDisplayId::tryCast(id)); - EXPECT_FALSE(HalDisplayId::tryCast(id)); - - EXPECT_EQ(id, DisplayId::fromValue(id.value)); - EXPECT_EQ(id, GpuVirtualDisplayId::fromValue(id.value)); -} - -TEST(DisplayIdTest, createVirtualIdFromGpuVirtualId) { - const VirtualDisplayId id(GpuVirtualDisplayId(42)); - EXPECT_TRUE(VirtualDisplayId::tryCast(id)); - EXPECT_TRUE(GpuVirtualDisplayId::tryCast(id)); - EXPECT_FALSE(HalVirtualDisplayId::tryCast(id)); - EXPECT_FALSE(PhysicalDisplayId::tryCast(id)); - EXPECT_FALSE(HalDisplayId::tryCast(id)); - - const bool isGpuVirtualId = (id.value & VirtualDisplayId::FLAG_GPU); - EXPECT_EQ((id.isVirtual() && isGpuVirtualId), GpuVirtualDisplayId::tryCast(id).has_value()); -} - -TEST(DisplayIdTest, createHalVirtualId) { - const HalVirtualDisplayId id(42); - EXPECT_TRUE(VirtualDisplayId::tryCast(id)); - EXPECT_TRUE(HalVirtualDisplayId::tryCast(id)); - EXPECT_FALSE(GpuVirtualDisplayId::tryCast(id)); - EXPECT_FALSE(PhysicalDisplayId::tryCast(id)); - EXPECT_TRUE(HalDisplayId::tryCast(id)); - - EXPECT_EQ(id, DisplayId::fromValue(id.value)); - EXPECT_EQ(id, HalVirtualDisplayId::fromValue(id.value)); -} - -TEST(DisplayIdTest, createVirtualIdFromHalVirtualId) { - const VirtualDisplayId id(HalVirtualDisplayId(42)); - EXPECT_TRUE(VirtualDisplayId::tryCast(id)); - EXPECT_TRUE(HalVirtualDisplayId::tryCast(id)); - EXPECT_FALSE(GpuVirtualDisplayId::tryCast(id)); - EXPECT_FALSE(PhysicalDisplayId::tryCast(id)); - EXPECT_TRUE(HalDisplayId::tryCast(id)); - - const bool isGpuVirtualId = (id.value & VirtualDisplayId::FLAG_GPU); - EXPECT_EQ((id.isVirtual() && !isGpuVirtualId), HalVirtualDisplayId::tryCast(id).has_value()); -} - -} // namespace android::ui diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp index 0dd9f198e5..efc34f6aa8 100644 --- a/opengl/libs/EGL/egl_display.cpp +++ b/opengl/libs/EGL/egl_display.cpp @@ -146,7 +146,7 @@ static EGLDisplay getPlatformDisplayAngle(EGLNativeDisplayType display, egl_conn } } - if (graphicsenv_flags::feature_overrides()) { + if (graphicsenv_flags::angle_feature_overrides()) { // Get the list of ANGLE features to enable from Global.Settings. const auto& eglFeatures = GraphicsEnv::getInstance().getAngleEglFeatures(); for (const std::string& eglFeature : eglFeatures) { diff --git a/opengl/tests/lib/WindowSurface.cpp b/opengl/tests/lib/WindowSurface.cpp index e94b565f11..beac9001bc 100644 --- a/opengl/tests/lib/WindowSurface.cpp +++ b/opengl/tests/lib/WindowSurface.cpp @@ -29,7 +29,7 @@ using namespace android; WindowSurface::WindowSurface() { status_t err; - sp<SurfaceComposerClient> surfaceComposerClient = new SurfaceComposerClient; + sp<SurfaceComposerClient> surfaceComposerClient = sp<SurfaceComposerClient>::make(); err = surfaceComposerClient->initCheck(); if (err != NO_ERROR) { fprintf(stderr, "SurfaceComposerClient::initCheck error: %#x\n", err); diff --git a/services/automotive/display/AutomotiveDisplayProxyService.cpp b/services/automotive/display/AutomotiveDisplayProxyService.cpp index afa623352b..56c3b7d31f 100644 --- a/services/automotive/display/AutomotiveDisplayProxyService.cpp +++ b/services/automotive/display/AutomotiveDisplayProxyService.cpp @@ -65,7 +65,7 @@ AutomotiveDisplayProxyService::getIGraphicBufferProducer(uint64_t id) { std::swap(displayWidth, displayHeight); } - sp<android::SurfaceComposerClient> surfaceClient = new SurfaceComposerClient(); + sp<android::SurfaceComposerClient> surfaceClient = sp<SurfaceComposerClient>::make(); err = surfaceClient->initCheck(); if (err != NO_ERROR) { ALOGE("SurfaceComposerClient::initCheck error: %#x", err); diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp index 25ee21fb12..46327dfbe7 100644 --- a/services/gpuservice/GpuService.cpp +++ b/services/gpuservice/GpuService.cpp @@ -147,7 +147,7 @@ void GpuService::toggleAngleAsSystemDriver(bool enabled) { } FeatureOverrides GpuService::getFeatureOverrides() { - if (!graphicsenv_flags::feature_overrides()) { + if (!graphicsenv_flags::angle_feature_overrides()) { FeatureOverrides featureOverrides; return featureOverrides; } @@ -183,7 +183,7 @@ status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector<Stri ALOGV(" arg[%zu]: '%s'", i, String8(args[i]).c_str()); if (!args.empty()) { - if (graphicsenv_flags::feature_overrides()) { + if (graphicsenv_flags::angle_feature_overrides()) { if (args[0] == String16("featureOverrides")) return cmdFeatureOverrides(out, err); } @@ -267,7 +267,7 @@ status_t cmdHelp(int out) { "GPU Service commands:\n" " vkjson dump Vulkan properties as JSON\n" " vkprofiles print support for select Vulkan profiles\n"); - if (graphicsenv_flags::feature_overrides()) { + if (graphicsenv_flags::angle_feature_overrides()) { fprintf(outs, " featureOverrides update and output gpuservice's feature overrides\n"); } diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp index f8ab830d2d..98f0f346df 100644 --- a/services/inputflinger/PointerChoreographer.cpp +++ b/services/inputflinger/PointerChoreographer.cpp @@ -31,6 +31,7 @@ #include "PointerChoreographer.h" #define INDENT " " +#define INDENT2 " " namespace android { @@ -647,6 +648,8 @@ void PointerChoreographer::dump(std::string& dump) { std::string pointerControllerDump = addLinePrefix(drawingTabletController->dump(), INDENT); dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump; } + dump += INDENT "DisplayTopologyGraph:\n"; + dump += addLinePrefix(mTopology.dump(), INDENT2); dump += "\n"; } diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index becfb05f67..9cd76c7d11 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -125,10 +125,17 @@ struct KeyEntry : EventEntry { bool syntheticRepeat; // set to true for synthetic key repeats enum class InterceptKeyResult { + // The interception result is unknown. UNKNOWN, + // The event should be skipped and not sent to the application. SKIP, + // The event should be sent to the application. CONTINUE, + // The event should eventually be sent to the application, after a delay. TRY_AGAIN_LATER, + // The event should not be initially sent to the application, but instead go through + // post-processing to generate a fallback key event and then sent to the application. + FALLBACK, }; // These are special fields that may need to be modified while the event is being dispatched. mutable InterceptKeyResult interceptKeyResult; // set based on the interception result diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index ef50fc0036..2908c61182 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -934,6 +934,7 @@ InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy, mPendingEvent(nullptr), mLastDropReason(DropReason::NOT_DROPPED), mIdGenerator(IdGenerator::Source::INPUT_DISPATCHER), + mWindowInfosVsyncId(-1), mMinTimeBetweenUserActivityPokes(DEFAULT_USER_ACTIVITY_POKE_INTERVAL), mConnectionManager(mLooper), mTouchStates(mWindowInfos, mConnectionManager), @@ -951,7 +952,7 @@ InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy, new LatencyAggregatorWithHistograms())) : std::move(std::unique_ptr<InputEventTimelineProcessor>( new LatencyAggregator()))), - mLatencyTracker(*mInputEventTimelineProcessor) { + mLatencyTracker(*mInputEventTimelineProcessor, mInputDevices) { mReporter = createInputReporter(); mWindowInfoListener = sp<DispatcherWindowListener>::make(*this); @@ -1960,11 +1961,74 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<con } } + if (entry->interceptKeyResult == KeyEntry::InterceptKeyResult::FALLBACK) { + findAndDispatchFallbackEvent(currentTime, entry, inputTargets); + // Drop the key. + return true; + } + // Dispatch the key. dispatchEventLocked(currentTime, entry, inputTargets); return true; } +void InputDispatcher::findAndDispatchFallbackEvent(nsecs_t currentTime, + std::shared_ptr<const KeyEntry> entry, + std::vector<InputTarget>& inputTargets) { + // Find the fallback associated with the incoming key event and dispatch it. + KeyEvent event = createKeyEvent(*entry); + const int32_t originalKeyCode = entry->keyCode; + + // Fetch the fallback event. + KeyCharacterMap::FallbackAction fallback; + for (const InputDeviceInfo& deviceInfo : mInputDevices) { + if (deviceInfo.getId() == entry->deviceId) { + const KeyCharacterMap* map = deviceInfo.getKeyCharacterMap(); + + LOG_ALWAYS_FATAL_IF(map == nullptr, "No KeyCharacterMap for device %d", + entry->deviceId); + map->getFallbackAction(entry->keyCode, entry->metaState, &fallback); + break; + } + } + + if (fallback.keyCode == AKEYCODE_UNKNOWN) { + // No fallback detected. + return; + } + + std::unique_ptr<KeyEntry> fallbackKeyEntry = + std::make_unique<KeyEntry>(mIdGenerator.nextId(), entry->injectionState, + event.getEventTime(), event.getDeviceId(), event.getSource(), + event.getDisplayId(), entry->policyFlags, entry->action, + event.getFlags() | AKEY_EVENT_FLAG_FALLBACK, + fallback.keyCode, event.getScanCode(), /*metaState=*/0, + event.getRepeatCount(), event.getDownTime()); + + if (mTracer) { + fallbackKeyEntry->traceTracker = + mTracer->traceDerivedEvent(*fallbackKeyEntry, *entry->traceTracker); + } + + for (const InputTarget& inputTarget : inputTargets) { + std::shared_ptr<Connection> connection = inputTarget.connection; + if (!connection->responsive || (connection->status != Connection::Status::NORMAL)) { + return; + } + + connection->inputState.setFallbackKey(originalKeyCode, fallback.keyCode); + if (entry->action == AKEY_EVENT_ACTION_UP) { + connection->inputState.removeFallbackKey(originalKeyCode); + } + + if (mTracer) { + mTracer->dispatchToTargetHint(*fallbackKeyEntry->traceTracker, inputTarget); + } + enqueueDispatchEntryAndStartDispatchCycleLocked(currentTime, connection, + std::move(fallbackKeyEntry), inputTarget); + } +} + void InputDispatcher::logOutboundKeyDetails(const char* prefix, const KeyEntry& entry) { LOG_IF(INFO, DEBUG_OUTBOUND_EVENT_DETAILS) << prefix << "eventTime=" << entry.eventTime << ", deviceId=" << entry.deviceId @@ -2446,6 +2510,24 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( return injectionError(InputEventInjectionResult::TARGET_MISMATCH); } + if (newTouchedWindowHandle != nullptr && + maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) { + // Check if this should be redirected to another window, in case this window previously + // called 'transferTouch' for this gesture. + const auto it = + std::find_if(tempTouchState.windows.begin(), tempTouchState.windows.end(), + [&](const TouchedWindow& touchedWindow) { + return touchedWindow.forwardingWindowToken == + newTouchedWindowHandle->getToken() && + touchedWindow.hasTouchingPointers(entry.deviceId); + }); + if (it != tempTouchState.windows.end()) { + LOG(INFO) << "Forwarding pointer from " << newTouchedWindowHandle->getName() + << " to " << it->windowHandle->getName(); + newTouchedWindowHandle = it->windowHandle; + } + } + std::vector<sp<WindowInfoHandle>> newTouchedWindows = findTouchedSpyWindowsAt(displayId, x, y, isStylus, entry.deviceId, mWindowInfos); if (newTouchedWindowHandle != nullptr) { @@ -2486,7 +2568,8 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( isDownOrPointerDown ? std::make_optional( entry.eventTime) - : std::nullopt); + : std::nullopt, + /*forwardingWindowToken=*/nullptr); if (!addResult.ok()) { LOG(ERROR) << "Error while processing " << entry << " for " << windowHandle->getName(); @@ -2513,7 +2596,8 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( tempTouchState.addOrUpdateWindow(wallpaper, InputTarget::DispatchMode::AS_IS, wallpaperFlags, entry.deviceId, {pointer}, - entry.eventTime); + entry.eventTime, + /*forwardingWindowToken=*/nullptr); } } } @@ -2612,7 +2696,8 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, InputTarget::DispatchMode::SLIPPERY_ENTER, targetFlags, entry.deviceId, {pointer}, - entry.eventTime); + entry.eventTime, + /*forwardingWindowToken=*/nullptr); // Check if the wallpaper window should deliver the corresponding event. slipWallpaperTouch(targetFlags, oldTouchedWindowHandle, newTouchedWindowHandle, @@ -4345,7 +4430,7 @@ void InputDispatcher::notifyInputDevicesChanged(const NotifyInputDevicesChangedA std::scoped_lock _l(mLock); // Reset key repeating in case a keyboard device was added or removed or something. resetKeyRepeatLocked(); - mLatencyTracker.setInputDevices(args.inputDeviceInfos); + mInputDevices = args.inputDeviceInfos; } void InputDispatcher::notifyKey(const NotifyKeyArgs& args) { @@ -5222,6 +5307,11 @@ std::string InputDispatcher::DispatcherWindowInfo::dumpDisplayAndWindowInfo() co } else { dump += "Displays: <none>\n"; } + dump += StringPrintf("mMaximumObscuringOpacityForTouch: %f\n", + mMaximumObscuringOpacityForTouch); + dump += "DisplayTopologyGraph:\n"; + dump += addLinePrefix(mTopology.dump(), INDENT); + dump += "\n"; return dump; } @@ -5764,7 +5854,7 @@ void InputDispatcher::setMaximumObscuringOpacityForTouch(float opacity) { } bool InputDispatcher::transferTouchGesture(const sp<IBinder>& fromToken, const sp<IBinder>& toToken, - bool isDragDrop) { + bool isDragDrop, bool transferEntireGesture) { if (fromToken == toToken) { LOG_IF(INFO, DEBUG_FOCUS) << "Trivial transfer to same window."; return true; @@ -5778,7 +5868,7 @@ bool InputDispatcher::transferTouchGesture(const sp<IBinder>& fromToken, const s "transferring touch from this window to another window", traceContext.getTracker()); - auto result = mTouchStates.transferTouchGesture(fromToken, toToken); + auto result = mTouchStates.transferTouchGesture(fromToken, toToken, transferEntireGesture); if (!result.has_value()) { return false; } @@ -5822,7 +5912,8 @@ std::optional<std::tuple<sp<gui::WindowInfoHandle>, DeviceId, std::vector<Pointe std::list<InputDispatcher::DispatcherTouchState::CancellationArgs>, std::list<InputDispatcher::DispatcherTouchState::PointerDownArgs>>> InputDispatcher::DispatcherTouchState::transferTouchGesture(const sp<android::IBinder>& fromToken, - const sp<android::IBinder>& toToken) { + const sp<android::IBinder>& toToken, + bool transferEntireGesture) { // Find the target touch state and touched window by fromToken. auto touchStateWindowAndDisplay = findTouchStateWindowAndDisplay(fromToken); if (!touchStateWindowAndDisplay.has_value()) { @@ -5865,8 +5956,12 @@ InputDispatcher::DispatcherTouchState::transferTouchGesture(const sp<android::IB } // Transferring touch focus using this API should not effect the focused window. newTargetFlags |= InputTarget::Flags::NO_FOCUS_CHANGE; + sp<IBinder> forwardingWindowToken; + if (transferEntireGesture && com::android::input::flags::allow_transfer_of_entire_gesture()) { + forwardingWindowToken = fromToken; + } state.addOrUpdateWindow(toWindowHandle, InputTarget::DispatchMode::AS_IS, newTargetFlags, - deviceId, pointers, downTimeInTarget); + deviceId, pointers, downTimeInTarget, forwardingWindowToken); // Synthesize cancel for old window and down for new window. std::shared_ptr<Connection> fromConnection = mConnectionManager.getConnection(fromToken); @@ -5948,7 +6043,8 @@ bool InputDispatcher::transferTouchOnDisplay(const sp<IBinder>& destChannelToken fromToken = from->getToken(); } // release lock - return transferTouchGesture(fromToken, destChannelToken); + return transferTouchGesture(fromToken, destChannelToken, /*isDragDrop=*/false, + /*transferEntireGesture=*/false); } void InputDispatcher::resetAndDropEverythingLocked(const char* reason) { @@ -7044,11 +7140,6 @@ void InputDispatcher::onWindowInfosChanged(const gui::WindowInfosUpdate& update) setInputWindowsLocked(handles, displayId); } - if (update.vsyncId < mWindowInfosVsyncId) { - ALOGE("Received out of order window infos update. Last update vsync id: %" PRId64 - ", current update vsync id: %" PRId64, - mWindowInfosVsyncId, update.vsyncId); - } mWindowInfosVsyncId = update.vsyncId; } // Wake up poll loop since it may need to make new input dispatching choices. @@ -7131,7 +7222,8 @@ void InputDispatcher::DispatcherTouchState::slipWallpaperTouch( state.addOrUpdateWindow(newWallpaper, InputTarget::DispatchMode::SLIPPERY_ENTER, InputTarget::Flags::WINDOW_IS_OBSCURED | InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED, - deviceId, pointers, entry.eventTime); + deviceId, pointers, entry.eventTime, + /*forwardingWindowToken=*/nullptr); } } @@ -7172,7 +7264,8 @@ InputDispatcher::DispatcherTouchState::transferWallpaperTouch( wallpaperFlags |= InputTarget::Flags::WINDOW_IS_OBSCURED | InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED; state.addOrUpdateWindow(newWallpaper, InputTarget::DispatchMode::AS_IS, wallpaperFlags, - deviceId, pointers, downTimeInTarget); + deviceId, pointers, downTimeInTarget, + /*forwardingWindowToken=*/nullptr); std::shared_ptr<Connection> wallpaperConnection = mConnectionManager.getConnection(newWallpaper->getToken()); if (wallpaperConnection != nullptr) { diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 38f782573a..2e8f2ce04e 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -127,7 +127,7 @@ public: void setMaximumObscuringOpacityForTouch(float opacity) override; bool transferTouchGesture(const sp<IBinder>& fromToken, const sp<IBinder>& toToken, - bool isDragDrop = false) override; + bool isDragDrop, bool transferEntireGesture) override; bool transferTouchOnDisplay(const sp<IBinder>& destChannelToken, ui::LogicalDisplayId displayId) override; @@ -440,7 +440,8 @@ private: std::optional< std::tuple<sp<gui::WindowInfoHandle>, DeviceId, std::vector<PointerProperties>, std::list<CancellationArgs>, std::list<PointerDownArgs>>> - transferTouchGesture(const sp<IBinder>& fromToken, const sp<IBinder>& toToken); + transferTouchGesture(const sp<IBinder>& fromToken, const sp<IBinder>& toToken, + bool transferEntireGesture); base::Result<std::list<CancellationArgs>, status_t> pilferPointers( const sp<IBinder>& token, const Connection& requestingConnection); @@ -918,10 +919,14 @@ private: std::unique_ptr<const KeyEntry> afterKeyEventLockedInterruptable( const std::shared_ptr<Connection>& connection, DispatchEntry* dispatchEntry, bool handled) REQUIRES(mLock); + void findAndDispatchFallbackEvent(nsecs_t currentTime, std::shared_ptr<const KeyEntry> entry, + std::vector<InputTarget>& inputTargets) REQUIRES(mLock); // Statistics gathering. nsecs_t mLastStatisticPushTime = 0; std::unique_ptr<InputEventTimelineProcessor> mInputEventTimelineProcessor GUARDED_BY(mLock); + // Must outlive `mLatencyTracker`. + std::vector<InputDeviceInfo> mInputDevices; LatencyTracker mLatencyTracker GUARDED_BY(mLock); void traceInboundQueueLengthLocked() REQUIRES(mLock); void traceOutboundQueueLength(const Connection& connection); diff --git a/services/inputflinger/dispatcher/LatencyTracker.cpp b/services/inputflinger/dispatcher/LatencyTracker.cpp index 0921e37d03..7c23694fbd 100644 --- a/services/inputflinger/dispatcher/LatencyTracker.cpp +++ b/services/inputflinger/dispatcher/LatencyTracker.cpp @@ -67,8 +67,9 @@ static void eraseByValue(std::multimap<K, V>& map, const V& value) { } // namespace -LatencyTracker::LatencyTracker(InputEventTimelineProcessor& processor) - : mTimelineProcessor(&processor) {} +LatencyTracker::LatencyTracker(InputEventTimelineProcessor& processor, + std::vector<InputDeviceInfo>& inputDevices) + : mTimelineProcessor(&processor), mInputDevices(inputDevices) {} void LatencyTracker::trackListener(const NotifyArgs& args) { if (const NotifyKeyArgs* keyArgs = std::get_if<NotifyKeyArgs>(&args)) { @@ -248,8 +249,4 @@ std::string LatencyTracker::dump(const char* prefix) const { StringPrintf("%s mEventTimes.size() = %zu\n", prefix, mEventTimes.size()); } -void LatencyTracker::setInputDevices(const std::vector<InputDeviceInfo>& inputDevices) { - mInputDevices = inputDevices; -} - } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/LatencyTracker.h b/services/inputflinger/dispatcher/LatencyTracker.h index 79ea14c4fb..7e2cc79249 100644 --- a/services/inputflinger/dispatcher/LatencyTracker.h +++ b/services/inputflinger/dispatcher/LatencyTracker.h @@ -20,9 +20,11 @@ #include <map> #include <unordered_map> +#include <vector> #include <binder/IBinder.h> #include <input/Input.h> +#include <input/InputDevice.h> #include "InputEventTimeline.h" #include "NotifyArgs.h" @@ -41,8 +43,10 @@ public: /** * Create a LatencyTracker. * param reportingFunction: the function that will be called in order to report full latency. + * param inputDevices: input devices relevant for tracking. */ - LatencyTracker(InputEventTimelineProcessor& processor); + LatencyTracker(InputEventTimelineProcessor& processor, + std::vector<InputDeviceInfo>& inputDevices); /** * Start keeping track of an event identified by the args. This must be called first. * If duplicate events are encountered (events that have the same eventId), none of them will be @@ -60,7 +64,6 @@ public: std::array<nsecs_t, GraphicsTimeline::SIZE> timeline); std::string dump(const char* prefix) const; - void setInputDevices(const std::vector<InputDeviceInfo>& inputDevices); private: /** @@ -81,7 +84,7 @@ private: std::multimap<nsecs_t /*eventTime*/, int32_t /*inputEventId*/> mEventTimes; InputEventTimelineProcessor* mTimelineProcessor; - std::vector<InputDeviceInfo> mInputDevices; + std::vector<InputDeviceInfo>& mInputDevices; void trackListener(int32_t inputEventId, nsecs_t eventTime, nsecs_t readTime, DeviceId deviceId, const std::set<InputDeviceUsageSource>& sources, int32_t inputEventAction, diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp index 2bf63beb05..f1fca0c317 100644 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ b/services/inputflinger/dispatcher/TouchState.cpp @@ -74,7 +74,7 @@ android::base::Result<void> TouchState::addOrUpdateWindow( const sp<WindowInfoHandle>& windowHandle, InputTarget::DispatchMode dispatchMode, ftl::Flags<InputTarget::Flags> targetFlags, DeviceId deviceId, const std::vector<PointerProperties>& touchingPointers, - std::optional<nsecs_t> firstDownTimeInTarget) { + std::optional<nsecs_t> firstDownTimeInTarget, sp<IBinder> forwardingWindowToken) { if (touchingPointers.empty()) { LOG(FATAL) << __func__ << "No pointers specified for " << windowHandle->getName(); return android::base::Error(); @@ -88,6 +88,7 @@ android::base::Result<void> TouchState::addOrUpdateWindow( if (touchedWindow.windowHandle == windowHandle) { touchedWindow.dispatchMode = dispatchMode; touchedWindow.targetFlags |= targetFlags; + touchedWindow.forwardingWindowToken = forwardingWindowToken; // For cases like hover enter/exit or DISPATCH_AS_OUTSIDE a touch window might not have // downTime set initially. Need to update existing window when a pointer is down for the // window. @@ -103,6 +104,7 @@ android::base::Result<void> TouchState::addOrUpdateWindow( touchedWindow.windowHandle = windowHandle; touchedWindow.dispatchMode = dispatchMode; touchedWindow.targetFlags = targetFlags; + touchedWindow.forwardingWindowToken = forwardingWindowToken; touchedWindow.addTouchingPointers(deviceId, touchingPointers); if (firstDownTimeInTarget) { touchedWindow.trySetDownTimeInTarget(deviceId, *firstDownTimeInTarget); diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h index 451d91704c..20155f4396 100644 --- a/services/inputflinger/dispatcher/TouchState.h +++ b/services/inputflinger/dispatcher/TouchState.h @@ -47,7 +47,7 @@ struct TouchState { const sp<android::gui::WindowInfoHandle>& windowHandle, InputTarget::DispatchMode dispatchMode, ftl::Flags<InputTarget::Flags> targetFlags, DeviceId deviceId, const std::vector<PointerProperties>& touchingPointers, - std::optional<nsecs_t> firstDownTimeInTarget); + std::optional<nsecs_t> firstDownTimeInTarget, sp<IBinder> forwardingWindowToken); void addHoveringPointerToWindow(const sp<android::gui::WindowInfoHandle>& windowHandle, DeviceId deviceId, const PointerProperties& pointer, float x, float y); diff --git a/services/inputflinger/dispatcher/TouchedWindow.cpp b/services/inputflinger/dispatcher/TouchedWindow.cpp index fa5be1a719..053a2e2441 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.cpp +++ b/services/inputflinger/dispatcher/TouchedWindow.cpp @@ -331,9 +331,9 @@ std::string TouchedWindow::dump() const { std::string out; std::string deviceStates = dumpMap(mDeviceStates, constToString, TouchedWindow::deviceStateToString); - out += StringPrintf("name='%s', targetFlags=%s, mDeviceStates=%s\n", + out += StringPrintf("name='%s', targetFlags=%s, forwardingWindowToken=%p, mDeviceStates=%s\n", windowHandle->getName().c_str(), targetFlags.string().c_str(), - deviceStates.c_str()); + forwardingWindowToken.get(), deviceStates.c_str()); return out; } diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h index c38681eef0..d27c597803 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.h +++ b/services/inputflinger/dispatcher/TouchedWindow.h @@ -34,6 +34,11 @@ struct TouchedWindow { InputTarget::DispatchMode dispatchMode = InputTarget::DispatchMode::AS_IS; ftl::Flags<InputTarget::Flags> targetFlags; + // If another window has transferred touches to this window, and wants to continue sending the + // rest of the gesture to this window, store the token of the originating (transferred-from) + // window here. + sp<IBinder> forwardingWindowToken; + // Hovering bool hasHoveringPointers() const; bool hasHoveringPointers(DeviceId deviceId) const; @@ -76,7 +81,7 @@ struct TouchedWindow { }; std::vector<DeviceId> eraseHoveringPointersIf( - std::function<bool(const PointerProperties&, float /*x*/, float /*y*/)> condition); + std::function<bool(const PointerProperties&, float x, float y)> condition); private: struct DeviceState { diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h index ab039c34ef..b22ddca4e6 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h @@ -148,7 +148,7 @@ public: * Returns true on success. False if the window did not actually have an active touch gesture. */ virtual bool transferTouchGesture(const sp<IBinder>& fromToken, const sp<IBinder>& toToken, - bool isDragDrop) = 0; + bool isDragDrop, bool transferEntireGesture) = 0; /** * Transfer a touch gesture to the provided channel, no matter where the current touch is. diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp index c982dab019..63eb357bdb 100644 --- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp @@ -144,28 +144,39 @@ public: // records it if so. void processGesture(const TouchpadInputMapper::MetricsIdentifier& id, const Gesture& gesture) { std::scoped_lock lock(mLock); + Counters& counters = mCounters[id]; switch (gesture.type) { case kGestureTypeFling: if (gesture.details.fling.fling_state == GESTURES_FLING_START) { // Indicates the end of a two-finger scroll gesture. - mCounters[id].twoFingerSwipeGestures++; + counters.twoFingerSwipeGestures++; } break; case kGestureTypeSwipeLift: - mCounters[id].threeFingerSwipeGestures++; + // The Gestures library occasionally outputs two lift gestures in a row, which can + // cause inaccurate metrics reporting. To work around this, deduplicate successive + // lift gestures. + // TODO(b/404529050): fix the Gestures library, and remove this check. + if (counters.lastGestureType != kGestureTypeSwipeLift) { + counters.threeFingerSwipeGestures++; + } break; case kGestureTypeFourFingerSwipeLift: - mCounters[id].fourFingerSwipeGestures++; + // TODO(b/404529050): fix the Gestures library, and remove this check. + if (counters.lastGestureType != kGestureTypeFourFingerSwipeLift) { + counters.fourFingerSwipeGestures++; + } break; case kGestureTypePinch: if (gesture.details.pinch.zoom_state == GESTURES_ZOOM_END) { - mCounters[id].pinchGestures++; + counters.pinchGestures++; } break; default: // We're not interested in any other gestures. break; } + counters.lastGestureType = gesture.type; } private: @@ -214,6 +225,10 @@ private: int32_t threeFingerSwipeGestures = 0; int32_t fourFingerSwipeGestures = 0; int32_t pinchGestures = 0; + + // Records the last type of gesture received for this device, for deduplication purposes. + // TODO(b/404529050): fix the Gestures library and remove this field. + GestureType lastGestureType = kGestureTypeContactInitiated; }; // Metrics are aggregated by device model and version, so if two devices of the same model and diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index 18d47f648b..677cf1e6c4 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -52,6 +52,7 @@ cc_test { "AnrTracker_test.cpp", "CapturedTouchpadEventConverter_test.cpp", "CursorInputMapper_test.cpp", + "DisplayTopologyGraph_test.cpp", "EventHub_test.cpp", "FakeEventHub.cpp", "FakeInputReaderPolicy.cpp", diff --git a/services/inputflinger/tests/DisplayTopologyGraph_test.cpp b/services/inputflinger/tests/DisplayTopologyGraph_test.cpp new file mode 100644 index 0000000000..fd2f21c4cb --- /dev/null +++ b/services/inputflinger/tests/DisplayTopologyGraph_test.cpp @@ -0,0 +1,120 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gtest/gtest.h> +#include <input/DisplayTopologyGraph.h> + +#include <string> +#include <string_view> +#include <tuple> + +namespace android { + +namespace { + +constexpr ui::LogicalDisplayId DISPLAY_ID_1{1}; +constexpr ui::LogicalDisplayId DISPLAY_ID_2{2}; +constexpr int DENSITY_MEDIUM = 160; + +} // namespace + +using DisplayTopologyGraphTestFixtureParam = + std::tuple<std::string_view /*name*/, DisplayTopologyGraph, bool /*isValid*/>; + +class DisplayTopologyGraphTestFixture + : public testing::Test, + public testing::WithParamInterface<DisplayTopologyGraphTestFixtureParam> {}; + +TEST_P(DisplayTopologyGraphTestFixture, DisplayTopologyGraphTest) { + const auto& [_, displayTopology, isValid] = GetParam(); + EXPECT_EQ(isValid, displayTopology.isValid()); +} + +INSTANTIATE_TEST_SUITE_P( + DisplayTopologyGraphTest, DisplayTopologyGraphTestFixture, + testing::Values( + std::make_tuple( + "InvalidPrimaryDisplay", + DisplayTopologyGraph{.primaryDisplayId = ui::LogicalDisplayId::INVALID, + .graph = {}, + .displaysDensity = {}}, + false), + std::make_tuple("PrimaryDisplayNotInGraph", + DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1, + .graph = {}, + .displaysDensity = {}}, + false), + std::make_tuple("DisplayDensityMissing", + DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1, + .graph = {{DISPLAY_ID_1, {}}}, + .displaysDensity = {}}, + false), + std::make_tuple("ValidSingleDisplayTopology", + DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1, + .graph = {{DISPLAY_ID_1, {}}}, + .displaysDensity = {{DISPLAY_ID_1, + DENSITY_MEDIUM}}}, + true), + std::make_tuple( + "MissingReverseEdge", + DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1, + .graph = {{DISPLAY_ID_1, + {{DISPLAY_ID_2, + DisplayTopologyPosition::TOP, 0}}}}, + .displaysDensity = {{DISPLAY_ID_1, DENSITY_MEDIUM}, + {DISPLAY_ID_2, DENSITY_MEDIUM}}}, + false), + std::make_tuple( + "IncorrectReverseEdgeDirection", + DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1, + .graph = {{DISPLAY_ID_1, + {{DISPLAY_ID_2, + DisplayTopologyPosition::TOP, 0}}}, + {DISPLAY_ID_2, + {{DISPLAY_ID_1, + DisplayTopologyPosition::TOP, 0}}}}, + .displaysDensity = {{DISPLAY_ID_1, DENSITY_MEDIUM}, + {DISPLAY_ID_2, DENSITY_MEDIUM}}}, + false), + std::make_tuple( + "IncorrectReverseEdgeOffset", + DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1, + .graph = {{DISPLAY_ID_1, + {{DISPLAY_ID_2, + DisplayTopologyPosition::TOP, 10}}}, + {DISPLAY_ID_2, + {{DISPLAY_ID_1, + DisplayTopologyPosition::BOTTOM, 20}}}}, + .displaysDensity = {{DISPLAY_ID_1, DENSITY_MEDIUM}, + {DISPLAY_ID_2, DENSITY_MEDIUM}}}, + false), + std::make_tuple( + "ValidMultiDisplayTopology", + DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1, + .graph = {{DISPLAY_ID_1, + {{DISPLAY_ID_2, + DisplayTopologyPosition::TOP, 10}}}, + {DISPLAY_ID_2, + {{DISPLAY_ID_1, + DisplayTopologyPosition::BOTTOM, -10}}}}, + .displaysDensity = {{DISPLAY_ID_1, DENSITY_MEDIUM}, + {DISPLAY_ID_2, DENSITY_MEDIUM}}}, + true)), + [](const testing::TestParamInfo<DisplayTopologyGraphTestFixtureParam>& p) { + return std::string{std::get<0>(p.param)}; + }); + +} // namespace android diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 835b677e1e..298ba4209a 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -37,6 +37,7 @@ #include <input/BlockingQueue.h> #include <input/Input.h> #include <input/InputConsumer.h> +#include <input/KeyCharacterMap.h> #include <input/PrintTools.h> #include <linux/input.h> #include <sys/epoll.h> @@ -139,6 +140,30 @@ static KeyEvent getTestKeyEvent() { return event; } +InputDeviceInfo generateTestDeviceInfo(uint16_t vendorId, uint16_t productId, DeviceId deviceId) { + InputDeviceIdentifier identifier; + identifier.vendor = vendorId; + identifier.product = productId; + auto info = InputDeviceInfo(); + info.initialize(deviceId, /*generation=*/1, /*controllerNumber=*/1, identifier, "Test Device", + /*isExternal=*/false, /*hasMic=*/false, ui::LogicalDisplayId::INVALID); + return info; +} + +std::unique_ptr<KeyCharacterMap> loadKeyCharacterMap(const char* name) { + InputDeviceIdentifier identifier; + identifier.name = name; + std::string path = getInputDeviceConfigurationFilePathByName(identifier.getCanonicalName(), + InputDeviceConfigurationFileType:: + KEY_CHARACTER_MAP); + + if (path.empty()) { + return nullptr; + } + + return *KeyCharacterMap::load(path, KeyCharacterMap::Format::BASE); +} + } // namespace // --- InputDispatcherTest --- @@ -1151,7 +1176,9 @@ TEST_F(InputDispatcherTest, MultiDeviceTouchTransferWithWallpaperWindows) { // Transfer touch from the middle window to the right window. ASSERT_TRUE(mDispatcher->transferTouchGesture(middleForegroundWindow->getToken(), - rightForegroundWindow->getToken())); + rightForegroundWindow->getToken(), + /*isDragDrop=*/false, + /*transferEntireGesture=*/false)); middleForegroundWindow->consumeMotionEvent( AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB))); @@ -1183,6 +1210,148 @@ TEST_F(InputDispatcherTest, MultiDeviceTouchTransferWithWallpaperWindows) { } /** + * If a window has requested touch to be transferred, only the current pointers should be + * transferred. + * + * Subsequent pointers should still go through the normal hit testing. + * + * In this test, we are invoking 'transferTouchGesture' with the parameter 'transferEntireGesture' + * set to true, but that value doesn't make any difference, since the flag is disabled. This test + * will be removed once that flag is fully rolled out. + */ +TEST_F(InputDispatcherTest, TouchTransferDoesNotSendEntireGesture_legacy) { + SCOPED_FLAG_OVERRIDE(allow_transfer_of_entire_gesture, false); + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> topWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Top window", + ui::LogicalDisplayId::DEFAULT); + + sp<FakeWindowHandle> bottomWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Bottom window", + ui::LogicalDisplayId::DEFAULT); + + mDispatcher->onWindowInfosChanged( + {{*topWindow->getInfo(), *bottomWindow->getInfo()}, {}, 0, 0}); + + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) + .build()); + topWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + + // Transfer touch from the top window to the bottom window. + // The actual value of parameter 'transferEntireGesture' doesn't matter, since the flag is off. + ASSERT_TRUE(mDispatcher->transferTouchGesture(topWindow->getToken(), bottomWindow->getToken(), + /*isDragDrop=*/false, + /*transferEntireGesture=*/true)); + topWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL)); + bottomWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + + // When the second pointer goes down, it will hit the top window, and should be delivered there + // as a new pointer. + mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(60).y(60)) + .build()); + topWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + const std::map<int32_t, PointF> expectedPointers{{0, PointF{50, 50}}}; + bottomWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers))); + bottomWindow->assertNoEvents(); +} + +/** + * If a window has requested touch to be transferred, the current pointers should be transferred. + * + * If the window did not request the "entire gesture" to be transferred, subsequent pointers should + * still go through the normal hit testing. + */ +TEST_F(InputDispatcherTest, TouchTransferDoesNotSendEntireGesture) { + SCOPED_FLAG_OVERRIDE(allow_transfer_of_entire_gesture, true); + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> topWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Top window", + ui::LogicalDisplayId::DEFAULT); + + sp<FakeWindowHandle> bottomWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Bottom window", + ui::LogicalDisplayId::DEFAULT); + + mDispatcher->onWindowInfosChanged( + {{*topWindow->getInfo(), *bottomWindow->getInfo()}, {}, 0, 0}); + + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) + .build()); + topWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + + // Transfer touch from the top window to the bottom window. + ASSERT_TRUE(mDispatcher->transferTouchGesture(topWindow->getToken(), bottomWindow->getToken(), + /*isDragDrop=*/false, + /*transferEntireGesture=*/false)); + topWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL)); + bottomWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + + // When the second pointer goes down, it will hit the top window, and should be delivered there + // because "entire gesture" was not requested to be transferred when the original call to + // 'transferTouchGesture' was made. + mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(60).y(60)) + .build()); + topWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + const std::map<int32_t, PointF> expectedPointers{{0, PointF{50, 50}}}; + bottomWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers))); + bottomWindow->assertNoEvents(); +} + +/** + * If a window has requested touch to be transferred, all subsequent pointers from the same gesture + * should be transferred if 'transferEntireGesture' was set to 'true'. + * + * In this test, there are 2 windows - one above and one below. + * First pointer goes to the top window. Then top window calls 'transferTouch' upon receiving + * ACTION_DOWN and transfers touch to the bottom window. + * Subsequent pointers from the same gesture should still be forwarded to the bottom window, + * as long as they first land into the top window. + */ +TEST_F(InputDispatcherTest, TouchTransferSendsEntireGesture) { + SCOPED_FLAG_OVERRIDE(allow_transfer_of_entire_gesture, true); + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> topWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Top window", + ui::LogicalDisplayId::DEFAULT); + + sp<FakeWindowHandle> bottomWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Bottom window", + ui::LogicalDisplayId::DEFAULT); + + mDispatcher->onWindowInfosChanged( + {{*topWindow->getInfo(), *bottomWindow->getInfo()}, {}, 0, 0}); + + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) + .build()); + topWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + + // Transfer touch from the top window to the bottom window. + ASSERT_TRUE(mDispatcher->transferTouchGesture(topWindow->getToken(), bottomWindow->getToken(), + /*isDragDrop=*/false, + /*transferEntireGesture=*/true)); + topWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL)); + bottomWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + + // When the second pointer goes down, it will hit the top window, but since the top window has + // requested the whole gesture to be transferred, it should be redirected to the bottom window. + mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(60).y(60)) + .build()); + + bottomWindow->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); +} + +/** * A single window that receives touch (on top), and a wallpaper window underneath it. * The top window gets a multitouch gesture. * Ensure that wallpaper gets the same gesture. @@ -6583,7 +6752,8 @@ TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeDownWithCorrectCoordinate // The pointer is transferred to the second window, and the second window receives it in the // correct coordinate space. - mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken()); + mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken(), + /*isDragDrop=*/false, /*transferEntireGesture=*/false); firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400))); secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(-100, -400))); } @@ -7119,7 +7289,8 @@ INSTANTIATE_TEST_SUITE_P( [&](const std::unique_ptr<InputDispatcher>& dispatcher, sp<IBinder> from, sp<IBinder> to) { return dispatcher->transferTouchGesture(from, to, - /*isDragAndDrop=*/false); + /*isDragAndDrop=*/false, + /*transferEntireGesture=*/false); })); TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) { @@ -7159,7 +7330,8 @@ TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) { secondWindow->consumeMotionDown(); // Transfer touch to the second window - mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken()); + mDispatcher->transferTouchGesture(firstWindow->getToken(), secondWindow->getToken(), + /*isDragDrop=*/false, /*transferEntireGesture=*/false); // The first window gets cancel and the new gets pointer down (it already saw down) firstWindow->consumeMotionCancel(); secondWindow->consumeMotionPointerDown(1, ui::LogicalDisplayId::DEFAULT, @@ -7293,7 +7465,9 @@ TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) { // Transfer touch ASSERT_TRUE(mDispatcher->transferTouchGesture(firstWindowInPrimary->getToken(), - secondWindowInPrimary->getToken())); + secondWindowInPrimary->getToken(), + /*isDragDrop=*/false, + /*transferEntireGesture=*/false)); // The first window gets cancel. firstWindowInPrimary->consumeMotionCancel(); secondWindowInPrimary->consumeMotionDown(ui::LogicalDisplayId::DEFAULT, @@ -7480,6 +7654,50 @@ TEST_F(InputDispatcherTest, FocusedWindow_PolicyConsumedKeyIgnoresDisableUserAct mFakePolicy->assertUserActivityPoked(); } +TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceivePolicyFallbackKey) { +#if !defined(__ANDROID__) + GTEST_SKIP() << "b/253299089 Generic files are currently read directly from device."; +#endif + InputDeviceInfo testDevice = generateTestDeviceInfo(/*vendorId=*/0, + /*productId=*/0, /*deviceId=*/1); + std::unique_ptr<KeyCharacterMap> kcm = loadKeyCharacterMap("Generic"); + ASSERT_NE(nullptr, kcm); + + testDevice.setKeyCharacterMap(std::move(kcm)); + mDispatcher->notifyInputDevicesChanged(NotifyInputDevicesChangedArgs(/*id=*/1, {testDevice})); + + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> window = + sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window", + ui::LogicalDisplayId::DEFAULT); + + window->setFocusable(true); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); + setFocusedWindow(window); + + window->consumeFocusEvent(true); + + mFakePolicy->setInterceptKeyBeforeDispatchingResult( + inputdispatcher::KeyEntry::InterceptKeyResult::FALLBACK); + + // In the Generic KCM fallbacks, Meta + Space => SEARCH. + mDispatcher->notifyKey(KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD) + .keyCode(AKEYCODE_SPACE) + .metaState(AMETA_META_ON) + .build()); + mDispatcher->waitForIdle(); + + // Should have poked user activity + mFakePolicy->assertUserActivityPoked(); + + // Fallback is generated and sent instead. + std::unique_ptr<KeyEvent> consumedEvent = window->consumeKey(/*handled=*/false); + ASSERT_NE(nullptr, consumedEvent); + ASSERT_THAT(*consumedEvent, + AllOf(WithKeyAction(ACTION_DOWN), WithKeyCode(AKEYCODE_SEARCH), + WithFlags(AKEY_EVENT_FLAG_FALLBACK))); +} + class DisableUserActivityInputDispatcherTest : public InputDispatcherTest, public ::testing::WithParamInterface<bool> {}; @@ -12541,7 +12759,8 @@ protected: // Transfer touch focus to the drag window bool transferred = mDispatcher->transferTouchGesture(targetWindow->getToken(), mDragWindow->getToken(), - /*isDragDrop=*/true); + /*isDragDrop=*/true, + /*transferEntireGesture=*/false); if (transferred) { targetWindow->consumeMotionCancel(dragStartDisplay); mDragWindow->consumeMotionDown(dragStartDisplay, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); @@ -15113,7 +15332,9 @@ TEST_P(TransferOrDontTransferFixture, TouchDownAndMouseHover) { if (GetParam()) { // Call transferTouchGesture const bool transferred = - mDispatcher->transferTouchGesture(mFromWindow->getToken(), mToWindow->getToken()); + mDispatcher->transferTouchGesture(mFromWindow->getToken(), mToWindow->getToken(), + /*isDragDrop=*/false, + /*transferEntireGesture=*/false); ASSERT_TRUE(transferred); mFromWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); @@ -15195,7 +15416,9 @@ TEST_P(TransferOrDontTransferFixture, MouseAndTouchTransferSimultaneousMultiDevi if (GetParam()) { // Call transferTouchGesture const bool transferred = - mDispatcher->transferTouchGesture(mFromWindow->getToken(), mToWindow->getToken()); + mDispatcher->transferTouchGesture(mFromWindow->getToken(), mToWindow->getToken(), + /*isDragDrop=*/false, + /*transferEntireGesture=*/false); ASSERT_TRUE(transferred); mFromWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL)); mFromWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); diff --git a/services/inputflinger/tests/LatencyTracker_test.cpp b/services/inputflinger/tests/LatencyTracker_test.cpp index d8c5eac3c4..b7ca24bb61 100644 --- a/services/inputflinger/tests/LatencyTracker_test.cpp +++ b/services/inputflinger/tests/LatencyTracker_test.cpp @@ -19,10 +19,13 @@ #include "NotifyArgsBuilders.h" #include "android/input.h" +#include <vector> + #include <android-base/logging.h> #include <android-base/properties.h> #include <binder/Binder.h> #include <gtest/gtest.h> +#include <input/InputDevice.h> #include <input/PrintTools.h> #include <inttypes.h> #include <linux/input.h> @@ -51,11 +54,6 @@ static InputDeviceInfo generateTestDeviceInfo(uint16_t vendorId, uint16_t produc return info; } -void setDefaultInputDeviceInfo(LatencyTracker& tracker) { - InputDeviceInfo deviceInfo = generateTestDeviceInfo(/*vendorId=*/0, /*productId=*/0, DEVICE_ID); - tracker.setInputDevices({deviceInfo}); -} - const auto FIRST_TOUCH_POINTER = PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200); const auto FIRST_MOUSE_POINTER = PointerBuilder(/*id=*/1, ToolType::MOUSE); @@ -120,13 +118,14 @@ protected: std::unique_ptr<LatencyTracker> mTracker; sp<IBinder> connection1; sp<IBinder> connection2; + std::vector<InputDeviceInfo> inputDevices; void SetUp() override { connection1 = sp<BBinder>::make(); connection2 = sp<BBinder>::make(); - mTracker = std::make_unique<LatencyTracker>(*this); - setDefaultInputDeviceInfo(*mTracker); + inputDevices.push_back(generateTestDeviceInfo(/*vendorId=*/0, /*productId=*/0, DEVICE_ID)); + mTracker = std::make_unique<LatencyTracker>(*this, inputDevices); } void TearDown() override {} @@ -140,6 +139,10 @@ protected: */ void assertReceivedTimelines(const std::vector<InputEventTimeline>& timelines); + void updateInputDevices(const std::vector<InputDeviceInfo>& inputDevicesUpdated) { + inputDevices = inputDevicesUpdated; + } + private: void processTimeline(const InputEventTimeline& timeline) override { mReceivedTimelines.push_back(timeline); @@ -448,7 +451,7 @@ TEST_F(LatencyTrackerTest, TrackListenerCheck_DeviceInfoFieldsInputEventTimeline deviceInfo2.addSource(AINPUT_SOURCE_TOUCHSCREEN); deviceInfo2.addSource(AINPUT_SOURCE_STYLUS); - mTracker->setInputDevices({deviceInfo1, deviceInfo2}); + updateInputDevices({deviceInfo1, deviceInfo2}); mTracker->trackListener( MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS, inputEventId) diff --git a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp index 157a3338da..9c027fa00c 100644 --- a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp @@ -17,6 +17,8 @@ #include <fuzzer/FuzzedDataProvider.h> #include <linux/input.h> +#include <vector> + #include "../../InputDeviceMetricsSource.h" #include "../InputEventTimeline.h" #include "NotifyArgsBuilders.h" @@ -58,7 +60,8 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { FuzzedDataProvider fdp(data, size); EmptyProcessor emptyProcessor; - LatencyTracker tracker(emptyProcessor); + std::vector<InputDeviceInfo> emptyDevices; + LatencyTracker tracker(emptyProcessor, emptyDevices); // Make some pre-defined tokens to ensure that some timelines are complete. std::array<sp<IBinder> /*token*/, 10> predefinedTokens; diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp index 4f65e77462..78f8f7bd96 100644 --- a/services/powermanager/Android.bp +++ b/services/powermanager/Android.bp @@ -52,6 +52,7 @@ cc_library_shared { ], whole_static_libs: [ + "android.adpf.sessionmanager_aidl-ndk", "android.os.hintmanager_aidl-ndk", ], diff --git a/services/powermanager/PowerHalController.cpp b/services/powermanager/PowerHalController.cpp index 0ba1909a44..a817a7bf2e 100644 --- a/services/powermanager/PowerHalController.cpp +++ b/services/powermanager/PowerHalController.cpp @@ -173,6 +173,21 @@ HalResult<aidl::android::hardware::power::SupportInfo> PowerHalController::getSu return CACHE_SUPPORT(6, processHalResult(handle->getSupportInfo(), "getSupportInfo")); } +HalResult<void> PowerHalController::sendCompositionData( + const std::vector<hal::CompositionData>& data) { + std::shared_ptr<HalWrapper> handle = initHal(); + return CACHE_SUPPORT(6, + processHalResult(handle->sendCompositionData(data), + "sendCompositionData")); +} + +HalResult<void> PowerHalController::sendCompositionUpdate(const hal::CompositionUpdate& update) { + std::shared_ptr<HalWrapper> handle = initHal(); + return CACHE_SUPPORT(6, + processHalResult(handle->sendCompositionUpdate(update), + "sendCompositionUpdate")); +} + } // namespace power } // namespace android diff --git a/services/powermanager/PowerHalWrapper.cpp b/services/powermanager/PowerHalWrapper.cpp index 068c23f94a..9c83bf5af3 100644 --- a/services/powermanager/PowerHalWrapper.cpp +++ b/services/powermanager/PowerHalWrapper.cpp @@ -79,6 +79,16 @@ HalResult<Aidl::SupportInfo> EmptyHalWrapper::getSupportInfo() { return HalResult<Aidl::SupportInfo>::unsupported(); } +HalResult<void> EmptyHalWrapper::sendCompositionData(const std::vector<hal::CompositionData>&) { + ALOGV("Skipped sendCompositionData because %s", getUnsupportedMessage()); + return HalResult<void>::unsupported(); +} + +HalResult<void> EmptyHalWrapper::sendCompositionUpdate(const hal::CompositionUpdate&) { + ALOGV("Skipped sendCompositionUpdate because %s", getUnsupportedMessage()); + return HalResult<void>::unsupported(); +} + const char* EmptyHalWrapper::getUnsupportedMessage() { return "Power HAL is not supported"; } @@ -292,6 +302,14 @@ HalResult<Aidl::SupportInfo> AidlHalWrapper::getSupportInfo() { return HalResult<Aidl::SupportInfo>::fromStatus(result, std::move(support)); } +HalResult<void> AidlHalWrapper::sendCompositionData(const std::vector<hal::CompositionData>& data) { + return HalResult<void>::fromStatus(mHandle->sendCompositionData(data)); +} + +HalResult<void> AidlHalWrapper::sendCompositionUpdate(const hal::CompositionUpdate& update) { + return HalResult<void>::fromStatus(mHandle->sendCompositionUpdate(update)); +} + const char* AidlHalWrapper::getUnsupportedMessage() { return "Power HAL doesn't support it"; } diff --git a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp index 682d1f44dc..1c53496644 100644 --- a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp +++ b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp @@ -26,9 +26,9 @@ #include <utils/Log.h> #include <unistd.h> +#include <memory> #include <thread> - using android::binder::Status; using namespace aidl::android::hardware::power; @@ -347,3 +347,50 @@ TEST_F(PowerHalWrapperAidlTest, TestCreateHintSessionWithConfigUnsupported) { result = mWrapper->createHintSessionWithConfig(tgid, uid, threadIds, durationNanos, tag, &out); ASSERT_TRUE(result.isUnsupported()); } + +TEST_F(PowerHalWrapperAidlTest, TestSendingCompositionData) { + int32_t tgid = 999; + int32_t uid = 1001; + std::vector<hal::CompositionData> dataOut; + dataOut.emplace_back(hal::CompositionData{ + .timestampNanos = 0L, + .scheduledPresentTimestampsNanos = {100}, + .latchTimestampNanos = 50, + .outputIds = {0}, + }); + dataOut.emplace_back(hal::CompositionData{ + .timestampNanos = 200L, + .scheduledPresentTimestampsNanos = {300}, + .latchTimestampNanos = 250, + .outputIds = {0}, + }); + EXPECT_CALL(*mMockHal.get(), sendCompositionData(_)) + .Times(Exactly(1)) + .WillOnce([&](const std::vector<hal::CompositionData>& passedData) { + if (!std::equal(passedData.begin(), passedData.end(), dataOut.begin())) { + ADD_FAILURE() << "Passed composition data not the same"; + } + return ndk::ScopedAStatus::ok(); + }); + + ASSERT_TRUE(mWrapper->sendCompositionData(dataOut).isOk()); +} + +TEST_F(PowerHalWrapperAidlTest, TestSendingCompositionUpdate) { + int32_t tgid = 999; + int32_t uid = 1001; + hal::CompositionUpdate dataOut{ + .timestampNanos = 123, + .deadOutputIds = {1, 2, 3}, + }; + EXPECT_CALL(*mMockHal.get(), sendCompositionUpdate(_)) + .Times(Exactly(1)) + .WillOnce([&](const hal::CompositionUpdate& passedData) { + if (passedData != dataOut) { + ADD_FAILURE() << "Passed composition update data not the same"; + } + return ndk::ScopedAStatus::ok(); + }); + + ASSERT_TRUE(mWrapper->sendCompositionUpdate(dataOut).isOk()); +}
\ No newline at end of file diff --git a/services/stats/Android.bp b/services/stats/Android.bp index f698515545..d588017737 100644 --- a/services/stats/Android.bp +++ b/services/stats/Android.bp @@ -29,10 +29,15 @@ cc_library_shared { "libexpresslog", "libhidlbase", "liblog", - "libstatslog", "libstatssocket", "libutils", ], + generated_sources: [ + "statslog_hidl.cpp", + ], + generated_headers: [ + "statslog_hidl.h", + ], export_include_dirs: [ "include/", ], @@ -47,3 +52,28 @@ cc_library_shared { "android.frameworks.stats-service.xml", ], } + +genrule { + name: "statslog_hidl.h", + tools: ["stats-log-api-gen"], + cmd: "$(location stats-log-api-gen)" + + " --header $(genDir)/statslog_hidl.h" + + " --module statshidl" + + " --namespace android,util,statshidl", + out: [ + "statslog_hidl.h", + ], +} + +genrule { + name: "statslog_hidl.cpp", + tools: ["stats-log-api-gen"], + cmd: "$(location stats-log-api-gen)" + + " --cpp $(genDir)/statslog_hidl.cpp" + + " --module statshidl" + + " --namespace android,util,statshidl" + + " --importHeader statslog_hidl.h", + out: [ + "statslog_hidl.cpp", + ], +} diff --git a/services/stats/StatsAidl.cpp b/services/stats/StatsAidl.cpp index b22f903654..66f7682dd8 100644 --- a/services/stats/StatsAidl.cpp +++ b/services/stats/StatsAidl.cpp @@ -26,9 +26,8 @@ #include <log/log.h> #include <stats_annotations.h> #include <stats_event.h> -#include <statslog.h> -#include <unordered_map> +#include <map> namespace { static const char* g_AtomErrorMetricName = @@ -118,8 +117,8 @@ ndk::ScopedAStatus StatsHal::reportVendorAtom(const VendorAtom& vendorAtom) { } } - // populate map for quickier access for VendorAtomValue associated annotations by value index - std::unordered_map<int, int> fieldIndexToAnnotationSetMap; + // populate map for quicker access for VendorAtomValue associated annotations by value index + std::map<int, int> fieldIndexToAnnotationSetMap; if (vendorAtom.valuesAnnotations) { const std::vector<std::optional<AnnotationSet>>& valuesAnnotations = *vendorAtom.valuesAnnotations; diff --git a/services/stats/StatsHal.cpp b/services/stats/StatsHal.cpp index 19176d9aaf..0ffa4c3947 100644 --- a/services/stats/StatsHal.cpp +++ b/services/stats/StatsHal.cpp @@ -20,7 +20,7 @@ #include "StatsHal.h" #include <log/log.h> -#include <statslog.h> +#include <statslog_hidl.h> namespace android { namespace frameworks { @@ -32,24 +32,27 @@ StatsHal::StatsHal() { } hardware::Return<void> StatsHal::reportSpeakerImpedance(const SpeakerImpedance& speakerImpedance) { - android::util::stats_write(android::util::SPEAKER_IMPEDANCE_REPORTED, - speakerImpedance.speakerLocation, speakerImpedance.milliOhms); + android::util::statshidl::stats_write(android::util::statshidl::SPEAKER_IMPEDANCE_REPORTED, + speakerImpedance.speakerLocation, + speakerImpedance.milliOhms); return hardware::Void(); } hardware::Return<void> StatsHal::reportHardwareFailed(const HardwareFailed& hardwareFailed) { - android::util::stats_write(android::util::HARDWARE_FAILED, int32_t(hardwareFailed.hardwareType), - hardwareFailed.hardwareLocation, int32_t(hardwareFailed.errorCode)); + android::util::statshidl::stats_write( + android::util::statshidl::HARDWARE_FAILED, int32_t(hardwareFailed.hardwareType), + hardwareFailed.hardwareLocation, int32_t(hardwareFailed.errorCode)); return hardware::Void(); } hardware::Return<void> StatsHal::reportPhysicalDropDetected( const PhysicalDropDetected& physicalDropDetected) { - android::util::stats_write( - android::util::PHYSICAL_DROP_DETECTED, int32_t(physicalDropDetected.confidencePctg), - physicalDropDetected.accelPeak, physicalDropDetected.freefallDuration); + android::util::statshidl::stats_write(android::util::statshidl::PHYSICAL_DROP_DETECTED, + int32_t(physicalDropDetected.confidencePctg), + physicalDropDetected.accelPeak, + physicalDropDetected.freefallDuration); return hardware::Void(); } @@ -60,19 +63,19 @@ hardware::Return<void> StatsHal::reportChargeCycles(const ChargeCycles& chargeCy for (int i = 0; i < 10 - initialSize; i++) { buckets.push_back(0); // Push 0 for buckets that do not exist. } - android::util::stats_write(android::util::CHARGE_CYCLES_REPORTED, buckets[0], buckets[1], - buckets[2], buckets[3], buckets[4], buckets[5], buckets[6], - buckets[7], buckets[8], buckets[9]); + android::util::statshidl::stats_write( + android::util::statshidl::CHARGE_CYCLES_REPORTED, buckets[0], buckets[1], buckets[2], + buckets[3], buckets[4], buckets[5], buckets[6], buckets[7], buckets[8], buckets[9]); return hardware::Void(); } hardware::Return<void> StatsHal::reportBatteryHealthSnapshot( const BatteryHealthSnapshotArgs& batteryHealthSnapshotArgs) { - android::util::stats_write( - android::util::BATTERY_HEALTH_SNAPSHOT, int32_t(batteryHealthSnapshotArgs.type), - batteryHealthSnapshotArgs.temperatureDeciC, batteryHealthSnapshotArgs.voltageMicroV, - batteryHealthSnapshotArgs.currentMicroA, + android::util::statshidl::stats_write( + android::util::statshidl::BATTERY_HEALTH_SNAPSHOT, + int32_t(batteryHealthSnapshotArgs.type), batteryHealthSnapshotArgs.temperatureDeciC, + batteryHealthSnapshotArgs.voltageMicroV, batteryHealthSnapshotArgs.currentMicroA, batteryHealthSnapshotArgs.openCircuitVoltageMicroV, batteryHealthSnapshotArgs.resistanceMicroOhm, batteryHealthSnapshotArgs.levelPercent); @@ -80,23 +83,24 @@ hardware::Return<void> StatsHal::reportBatteryHealthSnapshot( } hardware::Return<void> StatsHal::reportSlowIo(const SlowIo& slowIo) { - android::util::stats_write(android::util::SLOW_IO, int32_t(slowIo.operation), slowIo.count); + android::util::statshidl::stats_write(android::util::statshidl::SLOW_IO, + int32_t(slowIo.operation), slowIo.count); return hardware::Void(); } hardware::Return<void> StatsHal::reportBatteryCausedShutdown( const BatteryCausedShutdown& batteryCausedShutdown) { - android::util::stats_write(android::util::BATTERY_CAUSED_SHUTDOWN, - batteryCausedShutdown.voltageMicroV); + android::util::statshidl::stats_write(android::util::statshidl::BATTERY_CAUSED_SHUTDOWN, + batteryCausedShutdown.voltageMicroV); return hardware::Void(); } hardware::Return<void> StatsHal::reportUsbPortOverheatEvent( const UsbPortOverheatEvent& usbPortOverheatEvent) { - android::util::stats_write( - android::util::USB_PORT_OVERHEAT_EVENT_REPORTED, + android::util::statshidl::stats_write( + android::util::statshidl::USB_PORT_OVERHEAT_EVENT_REPORTED, usbPortOverheatEvent.plugTemperatureDeciC, usbPortOverheatEvent.maxTemperatureDeciC, usbPortOverheatEvent.timeToOverheat, usbPortOverheatEvent.timeToHysteresis, usbPortOverheatEvent.timeToInactive); @@ -105,9 +109,10 @@ hardware::Return<void> StatsHal::reportUsbPortOverheatEvent( } hardware::Return<void> StatsHal::reportSpeechDspStat(const SpeechDspStat& speechDspStat) { - android::util::stats_write(android::util::SPEECH_DSP_STAT_REPORTED, - speechDspStat.totalUptimeMillis, speechDspStat.totalDowntimeMillis, - speechDspStat.totalCrashCount, speechDspStat.totalRecoverCount); + android::util::statshidl::stats_write( + android::util::statshidl::SPEECH_DSP_STAT_REPORTED, speechDspStat.totalUptimeMillis, + speechDspStat.totalDowntimeMillis, speechDspStat.totalCrashCount, + speechDspStat.totalRecoverCount); return hardware::Void(); } diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h index 252adaa8e3..2c0a66fac3 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h @@ -34,7 +34,7 @@ class CompositionEngine; * A parameter object for creating Display instances */ struct DisplayCreationArgs { - DisplayId id; + DisplayIdVariant idVariant; // Size of the display in pixels ui::Size pixels = ui::kInvalidSize; @@ -68,8 +68,8 @@ class DisplayCreationArgsBuilder { public: DisplayCreationArgs build() { return std::move(mArgs); } - DisplayCreationArgsBuilder& setId(DisplayId id) { - mArgs.id = id; + DisplayCreationArgsBuilder& setId(DisplayIdVariant idVariant) { + mArgs.idVariant = idVariant; return *this; } diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index 780758e2a3..e2ea0f1397 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -167,6 +167,8 @@ public: // Checks if the buffer's release fence has been set virtual LayerFE::ReleaseFencePromiseStatus getReleaseFencePromiseStatus() = 0; + virtual void setReleasedBuffer(sp<GraphicBuffer> buffer) = 0; + // Indicates that the picture profile request was applied to this layer. virtual void onPictureProfileCommitted() = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index bda7856596..4266da4b07 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -170,6 +170,7 @@ public: // Returns the DisplayId the output represents, if it has one virtual ftl::Optional<DisplayId> getDisplayId() const = 0; + virtual ftl::Optional<DisplayIdVariant> getDisplayIdVariant() const = 0; // Enables (or disables) composition on this output virtual void setCompositionEnabled(bool) = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index 5519aafe11..ec87acc372 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -46,6 +46,7 @@ public: // compositionengine::Output overrides ftl::Optional<DisplayId> getDisplayId() const override; + ftl::Optional<DisplayIdVariant> getDisplayIdVariant() const override; bool isValid() const override; void dump(std::string&) const override; using compositionengine::impl::Output::setReleasedLayers; @@ -104,8 +105,11 @@ private: override; bool hasPictureProcessing() const override; int32_t getMaxLayerPictureProfiles() const override; + bool isGpuVirtualDisplay() const { + return std::holds_alternative<GpuVirtualDisplayId>(mIdVariant); + } - DisplayId mId; + DisplayIdVariant mIdVariant; bool mIsDisconnected = false; adpf::PowerAdvisor* mPowerAdvisor = nullptr; bool mHasPictureProcessing = false; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index 0ccdd22919..873764b065 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -45,6 +45,7 @@ public: // compositionengine::Output overrides bool isValid() const override; ftl::Optional<DisplayId> getDisplayId() const override; + ftl::Optional<DisplayIdVariant> getDisplayIdVariant() const override; void setCompositionEnabled(bool) override; void setLayerCachingEnabled(bool) override; void setLayerCachingTexturePoolEnabled(bool) override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h index d2a5a2066c..f65a9083c5 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -52,6 +52,7 @@ public: MOCK_METHOD0(createReleaseFenceFuture, ftl::Future<FenceResult>()); MOCK_METHOD1(setReleaseFence, void(const FenceResult&)); + MOCK_METHOD1(setReleasedBuffer, void(sp<GraphicBuffer>)); MOCK_METHOD0(getReleaseFencePromiseStatus, LayerFE::ReleaseFencePromiseStatus()); MOCK_CONST_METHOD0(getDebugName, const char*()); MOCK_CONST_METHOD0(getSequence, int32_t()); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index f2c265ad2e..eaa3dd37ec 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -35,6 +35,7 @@ public: MOCK_CONST_METHOD0(isValid, bool()); MOCK_CONST_METHOD0(getDisplayId, ftl::Optional<DisplayId>()); + MOCK_CONST_METHOD0(getDisplayIdVariant, ftl::Optional<DisplayIdVariant>()); MOCK_METHOD1(setCompositionEnabled, void(bool)); MOCK_METHOD1(setLayerCachingEnabled, void(bool)); diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp index 989f8e3c5e..ab2a03cd60 100644 --- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp +++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp @@ -91,13 +91,13 @@ nsecs_t CompositionEngine::getLastFrameRefreshTimestamp() const { namespace { void offloadOutputs(Outputs& outputs) { - if (!FlagManager::getInstance().multithreaded_present() || outputs.size() < 2) { + if (outputs.size() < 2) { return; } ui::PhysicalDisplayVector<compositionengine::Output*> outputsToOffload; for (const auto& output : outputs) { - if (!ftl::Optional(output->getDisplayId()).and_then(HalDisplayId::tryCast)) { + if (!output->getDisplayIdVariant().and_then(asHalDisplayId<DisplayIdVariant>)) { // Not HWC-enabled, so it is always client-composited. No need to offload. continue; } diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 8364f4efa0..5a546777f4 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -52,7 +52,7 @@ std::shared_ptr<Display> createDisplay( Display::~Display() = default; void Display::setConfiguration(const compositionengine::DisplayCreationArgs& args) { - mId = args.id; + mIdVariant = args.idVariant; mPowerAdvisor = args.powerAdvisor; mHasPictureProcessing = args.hasPictureProcessing; mMaxLayerPictureProfiles = args.maxLayerPictureProfiles; @@ -67,7 +67,7 @@ bool Display::isValid() const { } DisplayId Display::getId() const { - return mId; + return asDisplayId(mIdVariant); } bool Display::isSecure() const { @@ -79,11 +79,15 @@ void Display::setSecure(bool secure) { } bool Display::isVirtual() const { - return mId.isVirtual(); + return !std::holds_alternative<PhysicalDisplayId>(mIdVariant); } ftl::Optional<DisplayId> Display::getDisplayId() const { - return mId; + return getId(); +} + +ftl::Optional<DisplayIdVariant> Display::getDisplayIdVariant() const { + return mIdVariant; } void Display::disconnect() { @@ -93,14 +97,14 @@ void Display::disconnect() { mIsDisconnected = true; - if (const auto id = HalDisplayId::tryCast(mId)) { + if (const auto id = getDisplayIdVariant().and_then(asHalDisplayId<DisplayIdVariant>)) { getCompositionEngine().getHwComposer().disconnectDisplay(*id); } } void Display::setColorTransform(const compositionengine::CompositionRefreshArgs& args) { Output::setColorTransform(args); - const auto halDisplayId = HalDisplayId::tryCast(mId); + const auto halDisplayId = getDisplayIdVariant().and_then(asHalDisplayId<DisplayIdVariant>); if (mIsDisconnected || !halDisplayId || CC_LIKELY(!args.colorTransformMatrix)) { return; } @@ -108,7 +112,7 @@ void Display::setColorTransform(const compositionengine::CompositionRefreshArgs& auto& hwc = getCompositionEngine().getHwComposer(); status_t result = hwc.setColorTransform(*halDisplayId, *args.colorTransformMatrix); ALOGE_IF(result != NO_ERROR, "Failed to set color transform on display \"%s\": %d", - to_string(mId).c_str(), result); + to_string(*halDisplayId).c_str(), result); } void Display::setColorProfile(const ColorProfile& colorProfile) { @@ -125,7 +129,7 @@ void Display::setColorProfile(const ColorProfile& colorProfile) { Output::setColorProfile(colorProfile); - const auto physicalId = PhysicalDisplayId::tryCast(mId); + const auto physicalId = getDisplayIdVariant().and_then(asPhysicalDisplayId); LOG_FATAL_IF(!physicalId); getCompositionEngine().getHwComposer().setActiveColorMode(*physicalId, colorProfile.mode, colorProfile.renderIntent); @@ -133,7 +137,7 @@ void Display::setColorProfile(const ColorProfile& colorProfile) { void Display::dump(std::string& out) const { const char* const type = isVirtual() ? "virtual" : "physical"; - base::StringAppendF(&out, "Display %s (%s, \"%s\")", to_string(mId).c_str(), type, + base::StringAppendF(&out, "Display %s (%s, \"%s\")", to_string(getId()).c_str(), type, getName().c_str()); out.append("\n Composition Display State:\n"); @@ -157,7 +161,7 @@ std::unique_ptr<compositionengine::OutputLayer> Display::createOutputLayer( const sp<compositionengine::LayerFE>& layerFE) const { auto outputLayer = impl::createOutputLayer(*this, layerFE); - if (const auto halDisplayId = HalDisplayId::tryCast(mId); + if (const auto halDisplayId = getDisplayIdVariant().and_then(asHalDisplayId<DisplayIdVariant>); outputLayer && !mIsDisconnected && halDisplayId) { auto& hwc = getCompositionEngine().getHwComposer(); auto hwcLayer = hwc.createLayer(*halDisplayId); @@ -171,8 +175,7 @@ std::unique_ptr<compositionengine::OutputLayer> Display::createOutputLayer( void Display::setReleasedLayers(const compositionengine::CompositionRefreshArgs& refreshArgs) { Output::setReleasedLayers(refreshArgs); - if (mIsDisconnected || GpuVirtualDisplayId::tryCast(mId) || - refreshArgs.layersWithQueuedFrames.empty()) { + if (mIsDisconnected || isGpuVirtualDisplay() || refreshArgs.layersWithQueuedFrames.empty()) { return; } @@ -208,7 +211,7 @@ void Display::applyDisplayBrightness(bool applyImmediately) { if (!getState().displayBrightness) { return; } - if (auto displayId = PhysicalDisplayId::tryCast(mId)) { + if (auto displayId = getDisplayIdVariant().and_then(asPhysicalDisplayId)) { auto& hwc = getCompositionEngine().getHwComposer(); status_t result = hwc.setDisplayBrightness(*displayId, *getState().displayBrightness, getState().displayBrightnessNits, @@ -226,7 +229,7 @@ void Display::beginFrame() { Output::beginFrame(); // If we don't have a HWC display, then we are done. - const auto halDisplayId = HalDisplayId::tryCast(mId); + const auto halDisplayId = getDisplayIdVariant().and_then(asHalDisplayId<DisplayIdVariant>); if (!halDisplayId) { return; } @@ -244,7 +247,7 @@ bool Display::chooseCompositionStrategy( } // If we don't have a HWC display, then we are done. - const auto halDisplayId = HalDisplayId::tryCast(mId); + const auto halDisplayId = getDisplayIdVariant().and_then(asHalDisplayId<DisplayIdVariant>); if (!halDisplayId) { return false; } @@ -266,9 +269,9 @@ bool Display::chooseCompositionStrategy( } if (isPowerHintSessionEnabled()) { - mPowerAdvisor->setHwcValidateTiming(mId, hwcValidateStartTime, TimePoint::now()); - if (auto halDisplayId = HalDisplayId::tryCast(mId)) { - mPowerAdvisor->setSkippedValidate(mId, hwc.getValidateSkipped(*halDisplayId)); + mPowerAdvisor->setHwcValidateTiming(getId(), hwcValidateStartTime, TimePoint::now()); + if (auto halDisplayId = getDisplayIdVariant().and_then(asHalDisplayId<DisplayIdVariant>)) { + mPowerAdvisor->setSkippedValidate(*halDisplayId, hwc.getValidateSkipped(*halDisplayId)); } } @@ -292,7 +295,7 @@ void Display::applyCompositionStrategy(const std::optional<DeviceRequestedChange bool Display::getSkipColorTransform() const { auto& hwc = getCompositionEngine().getHwComposer(); - if (auto halDisplayId = HalDisplayId::tryCast(mId)) { + if (auto halDisplayId = getDisplayIdVariant().and_then(asHalDisplayId<DisplayIdVariant>)) { return hwc.hasDisplayCapability(*halDisplayId, DisplayCapability::SKIP_CLIENT_COLOR_TRANSFORM); } @@ -383,7 +386,7 @@ void Display::applyLayerLutsToLayers(const LayerLuts& layerLuts) { } void Display::executeCommands() { - const auto halDisplayIdOpt = HalDisplayId::tryCast(mId); + const auto halDisplayIdOpt = getDisplayIdVariant().and_then(asHalDisplayId<DisplayIdVariant>); if (mIsDisconnected || !halDisplayIdOpt) { return; } @@ -394,7 +397,7 @@ void Display::executeCommands() { compositionengine::Output::FrameFences Display::presentFrame() { auto fences = impl::Output::presentFrame(); - const auto halDisplayIdOpt = HalDisplayId::tryCast(mId); + const auto halDisplayIdOpt = getDisplayIdVariant().and_then(asHalDisplayId<DisplayIdVariant>); if (mIsDisconnected || !halDisplayIdOpt) { return fences; } @@ -404,13 +407,13 @@ compositionengine::Output::FrameFences Display::presentFrame() { const TimePoint startTime = TimePoint::now(); if (isPowerHintSessionEnabled() && getState().earliestPresentTime) { - mPowerAdvisor->setHwcPresentDelayedTime(mId, *getState().earliestPresentTime); + mPowerAdvisor->setHwcPresentDelayedTime(*halDisplayIdOpt, *getState().earliestPresentTime); } hwc.presentAndGetReleaseFences(*halDisplayIdOpt, getState().earliestPresentTime); if (isPowerHintSessionEnabled()) { - mPowerAdvisor->setHwcPresentTiming(mId, startTime, TimePoint::now()); + mPowerAdvisor->setHwcPresentTiming(*halDisplayIdOpt, startTime, TimePoint::now()); } fences.presentFence = hwc.getPresentFence(*halDisplayIdOpt); @@ -433,8 +436,8 @@ compositionengine::Output::FrameFences Display::presentFrame() { void Display::setExpensiveRenderingExpected(bool enabled) { Output::setExpensiveRenderingExpected(enabled); - if (mPowerAdvisor && !GpuVirtualDisplayId::tryCast(mId)) { - mPowerAdvisor->setExpensiveRenderingExpected(mId, enabled); + if (mPowerAdvisor && !isGpuVirtualDisplay()) { + mPowerAdvisor->setExpensiveRenderingExpected(getId(), enabled); } } @@ -449,15 +452,15 @@ bool Display::isPowerHintSessionGpuReportingEnabled() { // For ADPF GPU v0 this is expected to set start time to when the GPU commands are submitted with // fence returned, i.e. when RenderEngine flushes the commands and returns the draw fence. void Display::setHintSessionGpuStart(TimePoint startTime) { - mPowerAdvisor->setGpuStartTime(mId, startTime); + mPowerAdvisor->setGpuStartTime(getId(), startTime); } void Display::setHintSessionGpuFence(std::unique_ptr<FenceTime>&& gpuFence) { - mPowerAdvisor->setGpuFenceTime(mId, std::move(gpuFence)); + mPowerAdvisor->setGpuFenceTime(getId(), std::move(gpuFence)); } void Display::setHintSessionRequiresRenderEngine(bool requiresRenderEngine) { - mPowerAdvisor->setRequiresRenderEngine(mId, requiresRenderEngine); + mPowerAdvisor->setRequiresRenderEngine(getId(), requiresRenderEngine); } const aidl::android::hardware::graphics::composer3::OverlayProperties* @@ -478,7 +481,7 @@ void Display::finishFrame(GpuCompositionResult&& result) { // 1) It is being handled by hardware composer, which may need this to // keep its virtual display state machine in sync, or // 2) There is work to be done (the dirty region isn't empty) - if (GpuVirtualDisplayId::tryCast(mId) && !mustRecompose()) { + if (isGpuVirtualDisplay() && !mustRecompose()) { ALOGV("Skipping display composition"); return; } @@ -487,7 +490,7 @@ void Display::finishFrame(GpuCompositionResult&& result) { } bool Display::supportsOffloadPresent() const { - if (auto halDisplayId = HalDisplayId::tryCast(mId)) { + if (auto halDisplayId = getDisplayIdVariant().and_then(asHalDisplayId<DisplayIdVariant>)) { auto& hwc = getCompositionEngine().getHwComposer(); return hwc.hasDisplayCapability(*halDisplayId, DisplayCapability::MULTI_THREADED_PRESENT); } diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index de1d13a8d1..00a61a5ab6 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -118,6 +118,10 @@ ftl::Optional<DisplayId> Output::getDisplayId() const { return {}; } +ftl::Optional<DisplayIdVariant> Output::getDisplayIdVariant() const { + return {}; +} + const std::string& Output::getName() const { return mName; } @@ -436,8 +440,8 @@ void Output::prepare(const compositionengine::CompositionRefreshArgs& refreshArg ftl::Future<std::monostate> Output::present( const compositionengine::CompositionRefreshArgs& refreshArgs) { const auto stringifyExpectedPresentTime = [this, &refreshArgs]() -> std::string { - return getDisplayId() - .and_then(PhysicalDisplayId::tryCast) + return getDisplayIdVariant() + .and_then(asPhysicalDisplayId) .and_then([&refreshArgs](PhysicalDisplayId id) { return refreshArgs.frameTargets.get(id); }) @@ -890,8 +894,8 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr return; } - if (auto frameTargetPtrOpt = getDisplayId() - .and_then(PhysicalDisplayId::tryCast) + if (auto frameTargetPtrOpt = getDisplayIdVariant() + .and_then(asPhysicalDisplayId) .and_then([&refreshArgs](PhysicalDisplayId id) { return refreshArgs.frameTargets.get(id); })) { @@ -1389,7 +1393,8 @@ std::optional<base::unique_fd> Output::composeSurfaces( // or complex GPU shaders and it's expensive. We boost the GPU frequency so that // GPU composition can finish in time. We must reset GPU frequency afterwards, // because high frequency consumes extra battery. - const bool expensiveRenderingExpected = + const bool expensiveBlurs = mLayerRequestingBackgroundBlur != nullptr; + const bool expensiveRenderingExpected = expensiveBlurs || std::any_of(clientCompositionLayers.begin(), clientCompositionLayers.end(), [outputDataspace = clientCompositionDisplay.outputDataspace](const auto& layer) { @@ -1671,6 +1676,7 @@ void Output::presentFrameAndReleaseLayers(bool flushEvenWhenDisabled) { Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence); } layer->getLayerFE().setReleaseFence(releaseFence); + layer->getLayerFE().setReleasedBuffer(layer->getLayerFE().getCompositionState()->buffer); } // We've got a list of layers needing fences, that are disjoint with @@ -1840,7 +1846,7 @@ void Output::applyPictureProfile() { if (!getDisplayId()) { return; } - if (auto displayId = PhysicalDisplayId::tryCast(*getDisplayId())) { + if (auto displayId = getDisplayIdVariant().and_then(asPhysicalDisplayId)) { auto& hwc = getCompositionEngine().getHwComposer(); const status_t error = hwc.setDisplayPictureProfileHandle(*displayId, getState().pictureProfileHandle); diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp index ad65c4422e..34c09db6f8 100644 --- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp @@ -43,6 +43,10 @@ using ::testing::ReturnRef; using ::testing::SaveArg; using ::testing::StrictMock; +static constexpr PhysicalDisplayId kDisplayId1 = PhysicalDisplayId::fromPort(123u); +static constexpr PhysicalDisplayId kDisplayId2 = PhysicalDisplayId::fromPort(234u); +static constexpr PhysicalDisplayId kDisplayId3 = PhysicalDisplayId::fromPort(567u); + struct CompositionEngineTest : public testing::Test { std::shared_ptr<TimeStats> mTimeStats; @@ -52,6 +56,31 @@ struct CompositionEngineTest : public testing::Test { std::shared_ptr<mock::Output> mOutput1{std::make_shared<StrictMock<mock::Output>>()}; std::shared_ptr<mock::Output> mOutput2{std::make_shared<StrictMock<mock::Output>>()}; std::shared_ptr<mock::Output> mOutput3{std::make_shared<StrictMock<mock::Output>>()}; + + std::array<impl::OutputCompositionState, 3> mOutputStates; + + void SetUp() override { + EXPECT_CALL(*mOutput1, getDisplayId) + .WillRepeatedly(Return(std::make_optional<DisplayId>(kDisplayId1))); + EXPECT_CALL(*mOutput1, getDisplayIdVariant).WillRepeatedly(Return(kDisplayId1)); + + EXPECT_CALL(*mOutput2, getDisplayId) + .WillRepeatedly(Return(std::make_optional<DisplayId>(kDisplayId2))); + EXPECT_CALL(*mOutput2, getDisplayIdVariant).WillRepeatedly(Return(kDisplayId2)); + + EXPECT_CALL(*mOutput3, getDisplayId) + .WillRepeatedly(Return(std::make_optional<DisplayId>(kDisplayId3))); + EXPECT_CALL(*mOutput3, getDisplayIdVariant).WillRepeatedly(Return(kDisplayId3)); + + // Most tests will depend on the outputs being enabled. + for (auto& state : mOutputStates) { + state.isEnabled = true; + } + + EXPECT_CALL(*mOutput1, getState).WillRepeatedly(ReturnRef(mOutputStates[0])); + EXPECT_CALL(*mOutput2, getState).WillRepeatedly(ReturnRef(mOutputStates[1])); + EXPECT_CALL(*mOutput3, getState).WillRepeatedly(ReturnRef(mOutputStates[2])); + } }; TEST_F(CompositionEngineTest, canInstantiateCompositionEngine) { @@ -94,7 +123,7 @@ struct CompositionEnginePresentTest : public CompositionEngineTest { StrictMock<CompositionEnginePartialMock> mEngine; }; -TEST_F(CompositionEnginePresentTest, worksWithEmptyRequest) { +TEST_F(CompositionEnginePresentTest, zeroOutputs) { // present() always calls preComposition() and postComposition() EXPECT_CALL(mEngine, preComposition(Ref(mRefreshArgs))); EXPECT_CALL(mEngine, postComposition(Ref(mRefreshArgs))); @@ -102,7 +131,7 @@ TEST_F(CompositionEnginePresentTest, worksWithEmptyRequest) { mEngine.present(mRefreshArgs); } -TEST_F(CompositionEnginePresentTest, worksAsExpected) { +TEST_F(CompositionEnginePresentTest, threeOutputs) { // Expect calls to in a certain sequence InSequence seq; @@ -114,9 +143,7 @@ TEST_F(CompositionEnginePresentTest, worksAsExpected) { EXPECT_CALL(*mOutput2, prepare(Ref(mRefreshArgs), _)); EXPECT_CALL(*mOutput3, prepare(Ref(mRefreshArgs), _)); - // All of mOutput<i> are StrictMocks. If the flag is true, it will introduce - // calls to getDisplayId, which are not relevant to this test. - SET_FLAG_FOR_TEST(flags::multithreaded_present, false); + EXPECT_CALL(*mOutput1, supportsOffloadPresent).WillOnce(Return(false)); // The last step is to actually present each output. EXPECT_CALL(*mOutput1, present(Ref(mRefreshArgs))) @@ -284,8 +311,6 @@ struct CompositionEngineOffloadTest : public testing::Test { std::shared_ptr<mock::Output> mVirtualDisplay{std::make_shared<StrictMock<mock::Output>>()}; std::shared_ptr<mock::Output> mHalVirtualDisplay{std::make_shared<StrictMock<mock::Output>>()}; - static constexpr PhysicalDisplayId kDisplayId1 = PhysicalDisplayId::fromPort(123u); - static constexpr PhysicalDisplayId kDisplayId2 = PhysicalDisplayId::fromPort(234u); static constexpr GpuVirtualDisplayId kGpuVirtualDisplayId{789u}; static constexpr HalVirtualDisplayId kHalVirtualDisplayId{456u}; @@ -294,12 +319,23 @@ struct CompositionEngineOffloadTest : public testing::Test { void SetUp() override { EXPECT_CALL(*mDisplay1, getDisplayId) .WillRepeatedly(Return(std::make_optional<DisplayId>(kDisplayId1))); + EXPECT_CALL(*mDisplay1, getDisplayIdVariant).WillRepeatedly(Return(kDisplayId1)); + EXPECT_CALL(*mDisplay2, getDisplayId) .WillRepeatedly(Return(std::make_optional<DisplayId>(kDisplayId2))); + EXPECT_CALL(*mDisplay2, getDisplayIdVariant).WillRepeatedly(Return(kDisplayId2)); + EXPECT_CALL(*mVirtualDisplay, getDisplayId) .WillRepeatedly(Return(std::make_optional<DisplayId>(kGpuVirtualDisplayId))); + const DisplayIdVariant gpuVariant = + GpuVirtualDisplayId::fromValue(kGpuVirtualDisplayId.value); + EXPECT_CALL(*mVirtualDisplay, getDisplayIdVariant).WillRepeatedly(Return(gpuVariant)); + EXPECT_CALL(*mHalVirtualDisplay, getDisplayId) .WillRepeatedly(Return(std::make_optional<DisplayId>(kHalVirtualDisplayId))); + const DisplayIdVariant halVariant = + HalVirtualDisplayId::fromValue(kHalVirtualDisplayId.value); + EXPECT_CALL(*mHalVirtualDisplay, getDisplayIdVariant).WillRepeatedly(Return(halVariant)); // Most tests will depend on the outputs being enabled. for (auto& state : mOutputStates) { @@ -332,7 +368,6 @@ TEST_F(CompositionEngineOffloadTest, basic) { EXPECT_CALL(*mDisplay1, offloadPresentNextFrame).Times(1); EXPECT_CALL(*mDisplay2, offloadPresentNextFrame).Times(0); - SET_FLAG_FOR_TEST(flags::multithreaded_present, true); setOutputs({mDisplay1, mDisplay2}); mEngine.present(mRefreshArgs); @@ -345,7 +380,6 @@ TEST_F(CompositionEngineOffloadTest, dependsOnSupport) { EXPECT_CALL(*mDisplay1, offloadPresentNextFrame).Times(0); EXPECT_CALL(*mDisplay2, offloadPresentNextFrame).Times(0); - SET_FLAG_FOR_TEST(flags::multithreaded_present, true); setOutputs({mDisplay1, mDisplay2}); mEngine.present(mRefreshArgs); @@ -358,20 +392,6 @@ TEST_F(CompositionEngineOffloadTest, dependsOnSupport2) { EXPECT_CALL(*mDisplay1, offloadPresentNextFrame).Times(0); EXPECT_CALL(*mDisplay2, offloadPresentNextFrame).Times(0); - SET_FLAG_FOR_TEST(flags::multithreaded_present, true); - setOutputs({mDisplay1, mDisplay2}); - - mEngine.present(mRefreshArgs); -} - -TEST_F(CompositionEngineOffloadTest, dependsOnFlag) { - EXPECT_CALL(*mDisplay1, supportsOffloadPresent).Times(0); - EXPECT_CALL(*mDisplay2, supportsOffloadPresent).Times(0); - - EXPECT_CALL(*mDisplay1, offloadPresentNextFrame).Times(0); - EXPECT_CALL(*mDisplay2, offloadPresentNextFrame).Times(0); - - SET_FLAG_FOR_TEST(flags::multithreaded_present, false); setOutputs({mDisplay1, mDisplay2}); mEngine.present(mRefreshArgs); @@ -382,7 +402,6 @@ TEST_F(CompositionEngineOffloadTest, oneDisplay) { EXPECT_CALL(*mDisplay1, offloadPresentNextFrame).Times(0); - SET_FLAG_FOR_TEST(flags::multithreaded_present, true); setOutputs({mDisplay1}); mEngine.present(mRefreshArgs); @@ -397,7 +416,6 @@ TEST_F(CompositionEngineOffloadTest, virtualDisplay) { EXPECT_CALL(*mDisplay2, offloadPresentNextFrame).Times(0); EXPECT_CALL(*mVirtualDisplay, offloadPresentNextFrame).Times(0); - SET_FLAG_FOR_TEST(flags::multithreaded_present, true); setOutputs({mDisplay1, mDisplay2, mVirtualDisplay}); mEngine.present(mRefreshArgs); @@ -410,7 +428,6 @@ TEST_F(CompositionEngineOffloadTest, virtualDisplay2) { EXPECT_CALL(*mDisplay1, offloadPresentNextFrame).Times(0); EXPECT_CALL(*mVirtualDisplay, offloadPresentNextFrame).Times(0); - SET_FLAG_FOR_TEST(flags::multithreaded_present, true); setOutputs({mDisplay1, mVirtualDisplay}); mEngine.present(mRefreshArgs); @@ -423,7 +440,6 @@ TEST_F(CompositionEngineOffloadTest, halVirtual) { EXPECT_CALL(*mDisplay1, offloadPresentNextFrame).Times(1); EXPECT_CALL(*mHalVirtualDisplay, offloadPresentNextFrame).Times(0); - SET_FLAG_FOR_TEST(flags::multithreaded_present, true); setOutputs({mDisplay1, mHalVirtualDisplay}); mEngine.present(mRefreshArgs); @@ -440,7 +456,6 @@ TEST_F(CompositionEngineOffloadTest, ordering) { EXPECT_CALL(*mDisplay1, offloadPresentNextFrame).Times(1); EXPECT_CALL(*mDisplay2, offloadPresentNextFrame).Times(0); - SET_FLAG_FOR_TEST(flags::multithreaded_present, true); setOutputs({mVirtualDisplay, mHalVirtualDisplay, mDisplay1, mDisplay2}); mEngine.present(mRefreshArgs); @@ -458,7 +473,6 @@ TEST_F(CompositionEngineOffloadTest, dependsOnEnabled) { EXPECT_CALL(*mDisplay1, offloadPresentNextFrame).Times(0); EXPECT_CALL(*mDisplay2, offloadPresentNextFrame).Times(0); - SET_FLAG_FOR_TEST(flags::multithreaded_present, true); setOutputs({mDisplay1, mDisplay2}); mEngine.present(mRefreshArgs); @@ -478,7 +492,6 @@ TEST_F(CompositionEngineOffloadTest, disabledDisplaysDoNotPreventOthersFromOfflo EXPECT_CALL(*mDisplay2, offloadPresentNextFrame).Times(0); EXPECT_CALL(*mHalVirtualDisplay, offloadPresentNextFrame).Times(0); - SET_FLAG_FOR_TEST(flags::multithreaded_present, true); setOutputs({mDisplay1, mDisplay2, mHalVirtualDisplay}); mEngine.present(mRefreshArgs); diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index c1e59d01de..77fd4466ef 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -278,7 +278,7 @@ TEST_F(DisplayCreationTest, createGpuVirtualDisplay) { impl::createDisplay(mCompositionEngine, getDisplayCreationArgsForGpuVirtualDisplay()); EXPECT_FALSE(display->isSecure()); EXPECT_TRUE(display->isVirtual()); - EXPECT_TRUE(GpuVirtualDisplayId::tryCast(display->getId())); + EXPECT_TRUE(display->getDisplayIdVariant().and_then(asDisplayIdOfType<GpuVirtualDisplayId>)); } /* @@ -318,6 +318,7 @@ TEST_F(DisplaySetConfigurationTest, configuresHalVirtualDisplay) { EXPECT_EQ(HAL_VIRTUAL_DISPLAY_ID, mDisplay->getId()); EXPECT_FALSE(mDisplay->isSecure()); EXPECT_TRUE(mDisplay->isVirtual()); + EXPECT_TRUE(mDisplay->getDisplayIdVariant().and_then(asDisplayIdOfType<HalVirtualDisplayId>)); EXPECT_FALSE(mDisplay->isValid()); const auto& filter = mDisplay->getState().layerFilter; @@ -337,6 +338,7 @@ TEST_F(DisplaySetConfigurationTest, configuresGpuVirtualDisplay) { EXPECT_EQ(GPU_VIRTUAL_DISPLAY_ID, mDisplay->getId()); EXPECT_FALSE(mDisplay->isSecure()); EXPECT_TRUE(mDisplay->isVirtual()); + EXPECT_TRUE(mDisplay->getDisplayIdVariant().and_then(asDisplayIdOfType<GpuVirtualDisplayId>)); EXPECT_FALSE(mDisplay->isValid()); const auto& filter = mDisplay->getState().layerFilter; @@ -572,7 +574,7 @@ TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutIfGpuDisplay) { auto args = getDisplayCreationArgsForGpuVirtualDisplay(); std::shared_ptr<Display> gpuDisplay = createPartialMockDisplay<Display>(mCompositionEngine, args); - EXPECT_TRUE(GpuVirtualDisplayId::tryCast(gpuDisplay->getId())); + EXPECT_TRUE(gpuDisplay->getDisplayIdVariant().and_then(asDisplayIdOfType<GpuVirtualDisplayId>)); chooseCompositionStrategy(gpuDisplay.get()); diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 09ad9fa497..590626ace5 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -148,20 +148,23 @@ struct OutputTest : public testing::Test { virtual void injectOutputLayerForTest(std::unique_ptr<compositionengine::OutputLayer>) = 0; virtual ftl::Optional<DisplayId> getDisplayId() const override { return mId; } + virtual ftl::Optional<DisplayIdVariant> getDisplayIdVariant() const override { + return DisplayIdVariant(mId); + } virtual bool hasPictureProcessing() const override { return mHasPictureProcessing; } virtual int32_t getMaxLayerPictureProfiles() const override { return mMaxLayerPictureProfiles; } - void setDisplayIdForTest(DisplayId value) { mId = value; } + void setDisplayIdForTest(PhysicalDisplayId value) { mId = value; } void setHasPictureProcessingForTest(bool value) { mHasPictureProcessing = value; } void setMaxLayerPictureProfilesForTest(int32_t value) { mMaxLayerPictureProfiles = value; } private: - ftl::Optional<DisplayId> mId; + PhysicalDisplayId mId; bool mHasPictureProcessing; int32_t mMaxLayerPictureProfiles; }; @@ -3311,6 +3314,17 @@ TEST_F(OutputPostFramebufferTest, releaseFencesAreSetInLayerFE) { sp<Fence> layer2Fence = sp<Fence>::make(); sp<Fence> layer3Fence = sp<Fence>::make(); + // Set up layerfe buffers + LayerFECompositionState layer1State; + layer1State.buffer = sp<GraphicBuffer>::make(); + LayerFECompositionState layer2State; + layer2State.buffer = sp<GraphicBuffer>::make(); + LayerFECompositionState layer3State; + layer3State.buffer = nullptr; + EXPECT_CALL(*mLayer1.layerFE, getCompositionState()).WillOnce(Return(&layer1State)); + EXPECT_CALL(*mLayer2.layerFE, getCompositionState()).WillOnce(Return(&layer2State)); + EXPECT_CALL(*mLayer3.layerFE, getCompositionState()).WillOnce(Return(&layer3State)); + Output::FrameFences frameFences; frameFences.layerFences.emplace(&mLayer1.hwc2Layer, layer1Fence); frameFences.layerFences.emplace(&mLayer2.hwc2Layer, layer2Fence); @@ -3327,14 +3341,23 @@ TEST_F(OutputPostFramebufferTest, releaseFencesAreSetInLayerFE) { .WillOnce([&layer1Fence](FenceResult releaseFence) { EXPECT_EQ(FenceResult(layer1Fence), releaseFence); }); + EXPECT_CALL(*mLayer1.layerFE, setReleasedBuffer(_)).WillOnce([&](sp<GraphicBuffer> buffer) { + EXPECT_EQ(layer1State.buffer, buffer); + }); EXPECT_CALL(*mLayer2.layerFE, setReleaseFence(_)) .WillOnce([&layer2Fence](FenceResult releaseFence) { EXPECT_EQ(FenceResult(layer2Fence), releaseFence); }); + EXPECT_CALL(*mLayer2.layerFE, setReleasedBuffer(_)).WillOnce([&](sp<GraphicBuffer> buffer) { + EXPECT_EQ(layer2State.buffer, buffer); + }); EXPECT_CALL(*mLayer3.layerFE, setReleaseFence(_)) .WillOnce([&layer3Fence](FenceResult releaseFence) { EXPECT_EQ(FenceResult(layer3Fence), releaseFence); }); + EXPECT_CALL(*mLayer3.layerFE, setReleasedBuffer(_)).WillOnce([&](sp<GraphicBuffer> buffer) { + EXPECT_EQ(layer3State.buffer, buffer); + }); constexpr bool kFlushEvenWhenDisabled = false; mOutput.presentFrameAndReleaseLayers(kFlushEvenWhenDisabled); @@ -3350,6 +3373,17 @@ TEST_F(OutputPostFramebufferTest, setReleaseFencesIncludeClientTargetAcquireFenc frameFences.layerFences.emplace(&mLayer2.hwc2Layer, sp<Fence>::make()); frameFences.layerFences.emplace(&mLayer3.hwc2Layer, sp<Fence>::make()); + // Set up layerfe buffers + LayerFECompositionState layer1State; + layer1State.buffer = sp<GraphicBuffer>::make(); + LayerFECompositionState layer2State; + layer2State.buffer = sp<GraphicBuffer>::make(); + LayerFECompositionState layer3State; + layer3State.buffer = nullptr; + EXPECT_CALL(*mLayer1.layerFE, getCompositionState()).WillOnce(Return(&layer1State)); + EXPECT_CALL(*mLayer2.layerFE, getCompositionState()).WillOnce(Return(&layer2State)); + EXPECT_CALL(*mLayer3.layerFE, getCompositionState()).WillOnce(Return(&layer3State)); + EXPECT_CALL(mOutput, presentFrame()).WillOnce(Return(frameFences)); EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted()); @@ -3359,6 +3393,15 @@ TEST_F(OutputPostFramebufferTest, setReleaseFencesIncludeClientTargetAcquireFenc EXPECT_CALL(*mLayer1.layerFE, setReleaseFence).WillOnce(Return()); EXPECT_CALL(*mLayer2.layerFE, setReleaseFence).WillOnce(Return()); EXPECT_CALL(*mLayer3.layerFE, setReleaseFence).WillOnce(Return()); + EXPECT_CALL(*mLayer1.layerFE, setReleasedBuffer(_)).WillOnce([&](sp<GraphicBuffer> buffer) { + EXPECT_EQ(layer1State.buffer, buffer); + }); + EXPECT_CALL(*mLayer2.layerFE, setReleasedBuffer(_)).WillOnce([&](sp<GraphicBuffer> buffer) { + EXPECT_EQ(layer2State.buffer, buffer); + }); + EXPECT_CALL(*mLayer3.layerFE, setReleasedBuffer(_)).WillOnce([&](sp<GraphicBuffer> buffer) { + EXPECT_EQ(layer3State.buffer, buffer); + }); constexpr bool kFlushEvenWhenDisabled = false; mOutput.presentFrameAndReleaseLayers(kFlushEvenWhenDisabled); } @@ -3401,7 +3444,6 @@ TEST_F(OutputPostFramebufferTest, setReleasedLayersSentPresentFence) { .WillOnce([&presentFence](FenceResult fenceResult) { EXPECT_EQ(FenceResult(presentFence), fenceResult); }); - constexpr bool kFlushEvenWhenDisabled = false; mOutput.presentFrameAndReleaseLayers(kFlushEvenWhenDisabled); diff --git a/services/surfaceflinger/Display/VirtualDisplaySnapshot.h b/services/surfaceflinger/Display/VirtualDisplaySnapshot.h index c68020ce51..71d9f2e468 100644 --- a/services/surfaceflinger/Display/VirtualDisplaySnapshot.h +++ b/services/surfaceflinger/Display/VirtualDisplaySnapshot.h @@ -35,6 +35,7 @@ public: VirtualDisplayId displayId() const { return mVirtualId; } bool isGpu() const { return mIsGpu; } + const std::string& uniqueId() const { return mUniqueId; } void dump(utils::Dumper& dumper) const { using namespace std::string_view_literals; diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index b39654437f..bad5e2e3b5 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -26,7 +26,6 @@ #include <common/trace.h> #include <compositionengine/CompositionEngine.h> -#include <compositionengine/Display.h> #include <compositionengine/DisplayColorProfile.h> #include <compositionengine/DisplayColorProfileCreationArgs.h> #include <compositionengine/DisplayCreationArgs.h> @@ -308,6 +307,10 @@ DisplayId DisplayDevice::getId() const { return mCompositionDisplay->getId(); } +bool DisplayDevice::isVirtual() const { + return mCompositionDisplay->isVirtual(); +} + bool DisplayDevice::isSecure() const { return mCompositionDisplay->isSecure(); } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 02522a3deb..7d7c8adb7b 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -23,6 +23,8 @@ #include <android-base/thread_annotations.h> #include <android/native_window.h> #include <binder/IBinder.h> +#include <compositionengine/Display.h> +#include <compositionengine/DisplaySurface.h> #include <gui/LayerState.h> #include <math/mat4.h> #include <renderengine/RenderEngine.h> @@ -61,11 +63,6 @@ class SurfaceFlinger; struct CompositionInfo; struct DisplayDeviceCreationArgs; -namespace compositionengine { -class Display; -class DisplaySurface; -} // namespace compositionengine - namespace display { class DisplaySnapshot; } // namespace display @@ -85,7 +82,7 @@ public: return mCompositionDisplay; } - bool isVirtual() const { return getId().isVirtual(); } + bool isVirtual() const; bool isPrimary() const { return mIsPrimary; } // isSecure indicates whether this display can be trusted to display @@ -123,17 +120,30 @@ public: DisplayId getId() const; + DisplayIdVariant getDisplayIdVariant() const { + const auto idVariant = mCompositionDisplay->getDisplayIdVariant(); + LOG_FATAL_IF(!idVariant); + return *idVariant; + } + + std::optional<VirtualDisplayIdVariant> getVirtualDisplayIdVariant() const { + return ftl::match( + getDisplayIdVariant(), + [](PhysicalDisplayId) { return std::optional<VirtualDisplayIdVariant>(); }, + [](auto id) { return std::optional<VirtualDisplayIdVariant>(id); }); + } + // Shorthand to upcast the ID of a display whose type is known as a precondition. PhysicalDisplayId getPhysicalId() const { - const auto id = PhysicalDisplayId::tryCast(getId()); - LOG_FATAL_IF(!id); - return *id; + const auto physicalDisplayId = asPhysicalDisplayId(getDisplayIdVariant()); + LOG_FATAL_IF(!physicalDisplayId); + return *physicalDisplayId; } VirtualDisplayId getVirtualId() const { - const auto id = VirtualDisplayId::tryCast(getId()); - LOG_FATAL_IF(!id); - return *id; + const auto virtualDisplayId = asVirtualDisplayId(getDisplayIdVariant()); + LOG_FATAL_IF(!virtualDisplayId); + return *virtualDisplayId; } const wp<IBinder>& getDisplayToken() const { return mDisplayToken; } diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp index bb6bebed8d..27ae18fac9 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp @@ -328,9 +328,7 @@ std::string AidlComposer::dumpDebugInfo() { std::string str; // Use other thread to read pipe to prevent // pipe is full, making HWC be blocked in writing. - std::thread t([&]() { - base::ReadFdToString(pipefds[0], &str); - }); + std::thread t([&]() { base::ReadFdToString(pipefds[0], &str); }); const auto status = mAidlComposer->dump(pipefds[1], /*args*/ nullptr, /*numArgs*/ 0); // Close the write-end of the pipe to make sure that when reading from the // read-end we will get eof instead of blocking forever @@ -1773,7 +1771,6 @@ void AidlComposer::onHotplugDisconnect(Display display) { } bool AidlComposer::hasMultiThreadedPresentSupport(Display display) { - if (!FlagManager::getInstance().multithreaded_present()) return false; const auto displayId = translate<int64_t>(display); std::vector<AidlDisplayCapability> capabilities; const auto status = mAidlComposerClient->getDisplayCapabilities(displayId, &capabilities); diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index 018ee6e461..ab086e4b55 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -229,14 +229,13 @@ public: virtual std::vector<IComposerClient::PerFrameMetadataKey> getPerFrameMetadataKeys( Display display) = 0; virtual Error getRenderIntents(Display display, ColorMode colorMode, - std::vector<RenderIntent>* outRenderIntents) = 0; + std::vector<RenderIntent>* outRenderIntents) = 0; virtual Error getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outMatrix) = 0; // Composer HAL 2.3 virtual Error getDisplayIdentificationData(Display display, uint8_t* outPort, std::vector<uint8_t>* outData) = 0; - virtual Error setLayerColorTransform(Display display, Layer layer, - const float* matrix) = 0; + virtual Error setLayerColorTransform(Display display, Layer layer, const float* matrix) = 0; virtual Error getDisplayedContentSamplingAttributes(Display display, PixelFormat* outFormat, Dataspace* outDataspace, uint8_t* outComponentMask) = 0; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 14088a6428..787a64b089 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -560,7 +560,7 @@ status_t HWComposer::getDeviceCompositionChanges( if (!hasChangesError(error)) { RETURN_IF_HWC_ERROR_FOR("presentOrValidate", error, displayId, UNKNOWN_ERROR); } - if (state == 1) { //Present Succeeded. + if (state == 1) { // Present Succeeded. std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences; error = hwcDisplay->getReleaseFences(&releaseFences); displayData.releaseFences = std::move(releaseFences); @@ -824,8 +824,8 @@ mat4 HWComposer::getDataspaceSaturationMatrix(HalDisplayId displayId, ui::Datasp RETURN_IF_INVALID_DISPLAY(displayId, {}); mat4 matrix; - auto error = mDisplayData[displayId].hwcDisplay->getDataspaceSaturationMatrix(dataspace, - &matrix); + auto error = + mDisplayData[displayId].hwcDisplay->getDataspaceSaturationMatrix(dataspace, &matrix); RETURN_IF_HWC_ERROR(error, displayId, {}); return matrix; } diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp index a010353423..3321f51026 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp @@ -1230,15 +1230,16 @@ Error HidlComposer::getDisplayCapabilities(Display display, translate<DisplayCapability>(tmpCaps); }); } else { - mClient_2_3 - ->getDisplayCapabilities(display, [&](const auto& tmpError, const auto& tmpCaps) { - error = static_cast<V2_4::Error>(tmpError); - if (error != V2_4::Error::NONE) { - return; - } + mClient_2_3->getDisplayCapabilities(display, + [&](const auto& tmpError, const auto& tmpCaps) { + error = static_cast<V2_4::Error>(tmpError); + if (error != V2_4::Error::NONE) { + return; + } - *outCapabilities = translate<DisplayCapability>(tmpCaps); - }); + *outCapabilities = + translate<DisplayCapability>(tmpCaps); + }); } return static_cast<Error>(error); diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index 384f7b22c7..56ed11f07a 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -47,7 +47,8 @@ namespace android { -VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, VirtualDisplayId displayId, +VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, + VirtualDisplayIdVariant virtualIdVariant, const sp<IGraphicBufferProducer>& sink, const sp<IGraphicBufferProducer>& bqProducer, const sp<IGraphicBufferConsumer>& bqConsumer, @@ -58,7 +59,7 @@ VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, VirtualDisplayId d : ConsumerBase(bqConsumer), #endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) mHwc(hwc), - mDisplayId(displayId), + mVirtualIdVariant(virtualIdVariant), mDisplayName(name), mSource{}, mDefaultOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED), @@ -119,7 +120,7 @@ VirtualDisplaySurface::~VirtualDisplaySurface() { } status_t VirtualDisplaySurface::beginFrame(bool mustRecompose) { - if (GpuVirtualDisplayId::tryCast(mDisplayId)) { + if (isBackedByGpu()) { return NO_ERROR; } @@ -133,7 +134,7 @@ status_t VirtualDisplaySurface::beginFrame(bool mustRecompose) { } status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) { - if (GpuVirtualDisplayId::tryCast(mDisplayId)) { + if (isBackedByGpu()) { return NO_ERROR; } @@ -181,7 +182,10 @@ status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) { } status_t VirtualDisplaySurface::advanceFrame(float hdrSdrRatio) { - if (GpuVirtualDisplayId::tryCast(mDisplayId)) { + const auto halVirtualDisplayId = ftl::match( + mVirtualIdVariant, [](HalVirtualDisplayId id) { return ftl::Optional(id); }, + [](auto) { return ftl::Optional<HalVirtualDisplayId>(); }); + if (!halVirtualDisplayId) { return NO_ERROR; } @@ -212,11 +216,8 @@ status_t VirtualDisplaySurface::advanceFrame(float hdrSdrRatio) { VDS_LOGV("%s: fb=%d(%p) out=%d(%p)", __func__, mFbProducerSlot, fbBuffer.get(), mOutputProducerSlot, outBuffer.get()); - const auto halDisplayId = HalVirtualDisplayId::tryCast(mDisplayId); - LOG_FATAL_IF(!halDisplayId); - // At this point we know the output buffer acquire fence, - // so update HWC state with it. - mHwc.setOutputBuffer(*halDisplayId, mOutputFence, outBuffer); + // At this point we know the output buffer acquire fence, so update HWC state with it. + mHwc.setOutputBuffer(*halVirtualDisplayId, mOutputFence, outBuffer); status_t result = NO_ERROR; if (fbBuffer != nullptr) { @@ -227,7 +228,7 @@ status_t VirtualDisplaySurface::advanceFrame(float hdrSdrRatio) { hwcBuffer = fbBuffer; // HWC hasn't previously seen this buffer in this slot } // TODO: Correctly propagate the dataspace from GL composition - result = mHwc.setClientTarget(*halDisplayId, mFbProducerSlot, mFbFence, hwcBuffer, + result = mHwc.setClientTarget(*halVirtualDisplayId, mFbProducerSlot, mFbFence, hwcBuffer, ui::Dataspace::UNKNOWN, hdrSdrRatio); } @@ -235,8 +236,8 @@ status_t VirtualDisplaySurface::advanceFrame(float hdrSdrRatio) { } void VirtualDisplaySurface::onFrameCommitted() { - const auto halDisplayId = HalVirtualDisplayId::tryCast(mDisplayId); - if (!halDisplayId) { + const auto halDisplayId = asHalDisplayId(mVirtualIdVariant); + if (!halDisplayId.has_value()) { return; } @@ -250,8 +251,7 @@ void VirtualDisplaySurface::onFrameCommitted() { Mutex::Autolock lock(mMutex); int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, mFbProducerSlot); VDS_LOGV("%s: release scratch sslot=%d", __func__, sslot); - addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], - retireFence); + addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], retireFence); releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot]); } @@ -299,7 +299,7 @@ const sp<Fence>& VirtualDisplaySurface::getClientTargetAcquireFence() const { status_t VirtualDisplaySurface::requestBuffer(int pslot, sp<GraphicBuffer>* outBuf) { - if (GpuVirtualDisplayId::tryCast(mDisplayId)) { + if (isBackedByGpu()) { return mSource[SOURCE_SINK]->requestBuffer(pslot, outBuf); } @@ -321,7 +321,7 @@ status_t VirtualDisplaySurface::setAsyncMode(bool async) { status_t VirtualDisplaySurface::dequeueBuffer(Source source, PixelFormat format, uint64_t usage, int* sslot, sp<Fence>* fence) { - LOG_ALWAYS_FATAL_IF(GpuVirtualDisplayId::tryCast(mDisplayId).has_value()); + LOG_ALWAYS_FATAL_IF(isBackedByGpu()); status_t result = mSource[source]->dequeueBuffer(sslot, fence, mSinkBufferWidth, mSinkBufferHeight, @@ -373,7 +373,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, uint PixelFormat format, uint64_t usage, uint64_t* outBufferAge, FrameEventHistoryDelta* outTimestamps) { - if (GpuVirtualDisplayId::tryCast(mDisplayId)) { + if (isBackedByGpu()) { return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, w, h, format, usage, outBufferAge, outTimestamps); } @@ -459,7 +459,7 @@ status_t VirtualDisplaySurface::attachBuffer(int*, const sp<GraphicBuffer>&) { status_t VirtualDisplaySurface::queueBuffer(int pslot, const QueueBufferInput& input, QueueBufferOutput* output) { - if (GpuVirtualDisplayId::tryCast(mDisplayId)) { + if (isBackedByGpu()) { return mSource[SOURCE_SINK]->queueBuffer(pslot, input, output); } @@ -517,7 +517,7 @@ status_t VirtualDisplaySurface::queueBuffer(int pslot, status_t VirtualDisplaySurface::cancelBuffer(int pslot, const sp<Fence>& fence) { - if (GpuVirtualDisplayId::tryCast(mDisplayId)) { + if (isBackedByGpu()) { return mSource[SOURCE_SINK]->cancelBuffer(mapProducer2SourceSlot(SOURCE_SINK, pslot), fence); } @@ -621,7 +621,10 @@ void VirtualDisplaySurface::resetPerFrameState() { } status_t VirtualDisplaySurface::refreshOutputBuffer() { - LOG_ALWAYS_FATAL_IF(GpuVirtualDisplayId::tryCast(mDisplayId).has_value()); + const auto halVirtualDisplayId = ftl::match( + mVirtualIdVariant, [](HalVirtualDisplayId id) { return ftl::Optional(id); }, + [](auto) { return ftl::Optional<HalVirtualDisplayId>(); }); + LOG_ALWAYS_FATAL_IF(!halVirtualDisplayId); if (mOutputProducerSlot >= 0) { mSource[SOURCE_SINK]->cancelBuffer( @@ -640,14 +643,16 @@ status_t VirtualDisplaySurface::refreshOutputBuffer() { // until after GPU calls queueBuffer(). So here we just set the buffer // (for use in HWC prepare) but not the fence; we'll call this again with // the proper fence once we have it. - const auto halDisplayId = HalVirtualDisplayId::tryCast(mDisplayId); - LOG_FATAL_IF(!halDisplayId); - result = mHwc.setOutputBuffer(*halDisplayId, Fence::NO_FENCE, + result = mHwc.setOutputBuffer(*halVirtualDisplayId, Fence::NO_FENCE, mProducerBuffers[mOutputProducerSlot]); return result; } +bool VirtualDisplaySurface::isBackedByGpu() const { + return std::holds_alternative<GpuVirtualDisplayId>(mVirtualIdVariant); +} + // This slot mapping function is its own inverse, so two copies are unnecessary. // Both are kept to make the intent clear where the function is called, and for // the (unlikely) chance that we switch to a different mapping function. diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 90426f729a..cb65c79152 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -75,7 +75,8 @@ class VirtualDisplaySurface : public compositionengine::DisplaySurface, public BnGraphicBufferProducer, private ConsumerBase { public: - VirtualDisplaySurface(HWComposer&, VirtualDisplayId, const sp<IGraphicBufferProducer>& sink, + VirtualDisplaySurface(HWComposer&, VirtualDisplayIdVariant, + const sp<IGraphicBufferProducer>& sink, const sp<IGraphicBufferProducer>& bqProducer, const sp<IGraphicBufferConsumer>& bqConsumer, const std::string& name); @@ -145,6 +146,7 @@ private: void updateQueueBufferOutput(QueueBufferOutput&&); void resetPerFrameState(); status_t refreshOutputBuffer(); + bool isBackedByGpu() const; // Both the sink and scratch buffer pools have their own set of slots // ("source slots", or "sslot"). We have to merge these into the single @@ -159,7 +161,7 @@ private: // Immutable after construction // HWComposer& mHwc; - const VirtualDisplayId mDisplayId; + const VirtualDisplayIdVariant mVirtualIdVariant; const std::string mDisplayName; sp<IGraphicBufferProducer> mSource[2]; // indexed by SOURCE_* uint32_t mDefaultOutputFormat; diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index 008b0571c3..51d4078987 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -29,7 +29,6 @@ #include <cinttypes> #include <numeric> #include <unordered_set> -#include <vector> #include "../Jank/JankTracker.h" @@ -1005,11 +1004,6 @@ void FrameTimeline::setSfPresent(nsecs_t sfPresentTime, finalizeCurrentDisplayFrame(); } -const std::vector<std::shared_ptr<frametimeline::SurfaceFrame>>& FrameTimeline::getPresentFrames() - const { - return mPresentFrames; -} - void FrameTimeline::onCommitNotComposited() { SFTRACE_CALL(); std::scoped_lock lock(mMutex); @@ -1530,7 +1524,6 @@ void FrameTimeline::flushPendingPresentFences() { mPendingPresentFences.erase(mPendingPresentFences.begin()); } - mPresentFrames.clear(); for (size_t i = 0; i < mPendingPresentFences.size(); i++) { const auto& pendingPresentFence = mPendingPresentFences[i]; nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID; @@ -1544,12 +1537,6 @@ void FrameTimeline::flushPendingPresentFences() { auto& displayFrame = pendingPresentFence.second; displayFrame->onPresent(signalTime, mPreviousActualPresentTime); - // Surface frames have been jank classified and can be provided to caller - // to detect if buffer stuffing is occurring. - for (const auto& frame : displayFrame->getSurfaceFrames()) { - mPresentFrames.push_back(frame); - } - mPreviousPredictionPresentTime = displayFrame->trace(mSurfaceFlingerPid, monoBootOffset, mPreviousPredictionPresentTime, mFilterFramesBeforeTraceStarts); diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h index 9fedb57aca..fa83cd8523 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h @@ -331,11 +331,6 @@ public: virtual void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence, const std::shared_ptr<FenceTime>& gpuFence) = 0; - // Provides surface frames that have already been jank classified in the most recent - // flush of pending present fences. This allows buffer stuffing detection from SF. - virtual const std::vector<std::shared_ptr<frametimeline::SurfaceFrame>>& getPresentFrames() - const = 0; - // Tells FrameTimeline that a frame was committed but not composited. This is used to flush // all the associated surface frames. virtual void onCommitNotComposited() = 0; @@ -513,8 +508,6 @@ public: void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate, Fps renderRate) override; void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence, const std::shared_ptr<FenceTime>& gpuFence = FenceTime::NO_FENCE) override; - const std::vector<std::shared_ptr<frametimeline::SurfaceFrame>>& getPresentFrames() - const override; void onCommitNotComposited() override; void parseArgs(const Vector<String16>& args, std::string& result) override; void setMaxDisplayFrames(uint32_t size) override; @@ -562,9 +555,6 @@ private: // display frame, this is a good starting size for the vector so that we can avoid the // internal vector resizing that happens with push_back. static constexpr uint32_t kNumSurfaceFramesInitial = 10; - // Presented surface frames that have been jank classified and can - // indicate of potential buffer stuffing. - std::vector<std::shared_ptr<frametimeline::SurfaceFrame>> mPresentFrames; }; } // namespace impl diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index d322a61eb3..621fd6c00e 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -150,6 +150,7 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) } void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerState) { + bool transformWasValid = transformIsValid; const uint32_t oldFlags = flags; const half oldAlpha = color.a; const bool hadBuffer = externalTexture != nullptr; @@ -357,6 +358,14 @@ void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerSta clientDrawnCornerRadius = clientState.clientDrawnCornerRadius; changes |= RequestedLayerState::Changes::Geometry; } + + // We can't just check requestedTransform here because LayerSnapshotBuilder uses + // getTransform which reads destinationFrame or buffer dimensions. + // Display rotation does not affect validity so just use ROT_0. + transformIsValid = LayerSnapshot::isTransformValid(getTransform(ui::Transform::ROT_0)); + if (!transformWasValid && transformIsValid) { + changes |= RequestedLayerState::Changes::Visibility; + } } ui::Size RequestedLayerState::getUnrotatedBufferSize(uint32_t displayRotationFlags) const { diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.h b/services/surfaceflinger/FrontEnd/RequestedLayerState.h index 723237940d..b8310beab5 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.h +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.h @@ -115,6 +115,7 @@ struct RequestedLayerState : layer_state_t { const gui::Pid ownerPid; bool dataspaceRequested; bool hasColorTransform; + bool transformIsValid = true; bool premultipliedAlpha{true}; // This layer can be a cursor on some displays. bool potentialCursor{false}; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 95a7170fbb..2e312827f2 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -722,6 +722,10 @@ void Layer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& l uint32_t currentMaxAcquiredBufferCount = mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid); + if (FlagManager::getInstance().monitor_buffer_fences()) { + buffer->getDependencyMonitor().addEgress(FenceTime::makeValid(fence), "Layer release"); + } + if (listener) { listener->onReleaseBuffer(callbackId, fence, currentMaxAcquiredBufferCount); } @@ -940,6 +944,7 @@ bool Layer::setBuffer(std::shared_ptr<renderengine::ExternalTexture>& buffer, std::max(mDrawingState.frameNumber, mDrawingState.barrierFrameNumber); mDrawingState.releaseBufferListener = bufferData.releaseBufferListener; + mDrawingState.previousBuffer = std::move(mDrawingState.buffer); mDrawingState.buffer = std::move(buffer); mDrawingState.acquireFence = bufferData.flags.test(BufferData::BufferDataChange::fenceChanged) ? bufferData.acquireFence @@ -1122,6 +1127,7 @@ bool Layer::setTransactionCompletedListeners(const std::vector<sp<CallbackHandle handle->acquireTimeOrFence = mCallbackHandleAcquireTimeOrFence; handle->frameNumber = mDrawingState.frameNumber; handle->previousFrameNumber = mDrawingState.previousFrameNumber; + handle->previousBuffer = mDrawingState.previousBuffer; if (mPreviousReleaseBufferEndpoint == handle->listener) { // Add fence from previous screenshot now so that it can be dispatched to the // client. @@ -1433,8 +1439,8 @@ void Layer::onCompositionPresented(const DisplayDevice* display, presentFence, FrameTracer::FrameEvent::PRESENT_FENCE); mDeprecatedFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence)); - } else if (const auto displayId = PhysicalDisplayId::tryCast(display->getId()); - displayId && mFlinger->getHwComposer().isConnected(*displayId)) { + } else if (const auto displayId = asPhysicalDisplayId(display->getDisplayIdVariant()); + displayId.has_value() && mFlinger->getHwComposer().isConnected(*displayId)) { // The HWC doesn't support present fences, so use the present timestamp instead. const nsecs_t presentTimestamp = mFlinger->getHwComposer().getPresentTimestamp(*displayId); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 081bb22246..88754f9fa3 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -117,6 +117,7 @@ public: uint32_t bufferTransform; bool transformToDisplayInverse; Region transparentRegionHint; + std::shared_ptr<renderengine::ExternalTexture> previousBuffer; std::shared_ptr<renderengine::ExternalTexture> buffer; sp<Fence> acquireFence; std::shared_ptr<FenceTime> acquireFenceTime; diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp index b6192685ae..5e076bdae4 100644 --- a/services/surfaceflinger/LayerFE.cpp +++ b/services/surfaceflinger/LayerFE.cpp @@ -410,6 +410,15 @@ void LayerFE::setReleaseFence(const FenceResult& releaseFence) { if (mReleaseFencePromiseStatus == ReleaseFencePromiseStatus::FULFILLED) { return; } + + if (releaseFence.has_value()) { + if (FlagManager::getInstance().monitor_buffer_fences()) { + if (auto strongBuffer = mReleasedBuffer.promote()) { + strongBuffer->getDependencyMonitor() + .addAccessCompletion(FenceTime::makeValid(releaseFence.value()), "HWC"); + } + } + } mReleaseFence.set_value(releaseFence); mReleaseFencePromiseStatus = ReleaseFencePromiseStatus::FULFILLED; } @@ -428,6 +437,10 @@ LayerFE::ReleaseFencePromiseStatus LayerFE::getReleaseFencePromiseStatus() { return mReleaseFencePromiseStatus; } +void LayerFE::setReleasedBuffer(sp<GraphicBuffer> buffer) { + mReleasedBuffer = std::move(buffer); +} + void LayerFE::setLastHwcState(const LayerFE::HwcLayerDebugState &state) { mLastHwcState = state; } diff --git a/services/surfaceflinger/LayerFE.h b/services/surfaceflinger/LayerFE.h index a537456beb..b89b6b4b92 100644 --- a/services/surfaceflinger/LayerFE.h +++ b/services/surfaceflinger/LayerFE.h @@ -18,6 +18,7 @@ #include <android/gui/CachingHint.h> #include <gui/LayerMetadata.h> +#include <ui/GraphicBuffer.h> #include <ui/LayerStack.h> #include <ui/PictureProfileHandle.h> @@ -58,6 +59,7 @@ public: ftl::Future<FenceResult> createReleaseFenceFuture() override; void setReleaseFence(const FenceResult& releaseFence) override; LayerFE::ReleaseFencePromiseStatus getReleaseFencePromiseStatus() override; + void setReleasedBuffer(sp<GraphicBuffer> buffer) override; void onPictureProfileCommitted() override; // Used for debugging purposes, e.g. perfetto tracing, dumpsys. @@ -95,6 +97,7 @@ private: std::promise<FenceResult> mReleaseFence; ReleaseFencePromiseStatus mReleaseFencePromiseStatus = ReleaseFencePromiseStatus::UNINITIALIZED; HwcLayerDebugState mLastHwcState; + wp<GraphicBuffer> mReleasedBuffer; }; } // namespace android diff --git a/services/surfaceflinger/LayerVector.h b/services/surfaceflinger/LayerVector.h index 38dc11d3bc..81155fd697 100644 --- a/services/surfaceflinger/LayerVector.h +++ b/services/surfaceflinger/LayerVector.h @@ -49,7 +49,8 @@ public: using Visitor = std::function<void(Layer*)>; private: - const StateSet mStateSet; + // FIXME: This is set but not used anywhere. + [[maybe_unused]] const StateSet mStateSet; }; } diff --git a/services/surfaceflinger/PowerAdvisor/SessionManager.h b/services/surfaceflinger/PowerAdvisor/SessionManager.h index 93a80b55ab..afa52eb260 100644 --- a/services/surfaceflinger/PowerAdvisor/SessionManager.h +++ b/services/surfaceflinger/PowerAdvisor/SessionManager.h @@ -68,7 +68,8 @@ private: bool isLayerRelevant(int32_t layerId); // The UID of whoever created our ISessionManager connection - const uid_t mUid; + // FIXME: This is set but is not used anywhere. + [[maybe_unused]] const uid_t mUid; // State owned by the main thread @@ -99,4 +100,4 @@ private: }; } // namespace adpf -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 514adac20c..615492a872 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -348,7 +348,7 @@ void RegionSamplingThread::captureSample() { SurfaceFlinger::ScreenshotArgs screenshotArgs; screenshotArgs.captureTypeVariant = displayWeak; - screenshotArgs.displayId = std::nullopt; + screenshotArgs.displayIdVariant = std::nullopt; screenshotArgs.sourceCrop = sampledBounds.isEmpty() ? layerStackSpaceRect : sampledBounds; screenshotArgs.reqSize = sampledBounds.getSize(); screenshotArgs.dataspace = ui::Dataspace::V0_SRGB; diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index c37b9653cb..5390295e9a 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -512,14 +512,6 @@ void EventThread::onModeRejected(PhysicalDisplayId displayId, DisplayModeId mode mCondition.notify_all(); } -// Merge lists of buffer stuffed Uids -void EventThread::addBufferStuffedUids(BufferStuffingMap bufferStuffedUids) { - std::lock_guard<std::mutex> lock(mMutex); - for (auto& [uid, count] : bufferStuffedUids) { - mBufferStuffedUids.emplace_or_replace(uid, count); - } -} - void EventThread::threadMain(std::unique_lock<std::mutex>& lock) { DisplayEventConsumers consumers; @@ -761,10 +753,6 @@ void EventThread::generateFrameTimeline(VsyncEventData& outVsyncEventData, nsecs void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event, const DisplayEventConsumers& consumers) { - // List of Uids that have been sent vsync data with queued buffer count. - // Used to keep track of which Uids can be removed from the map of - // buffer stuffed clients. - ftl::SmallVector<uid_t, 10> uidsPostedQueuedBuffers; for (const auto& consumer : consumers) { DisplayEventReceiver::Event copy = event; if (event.header.type == DisplayEventType::DISPLAY_EVENT_VSYNC) { @@ -774,13 +762,6 @@ void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event, event.vsync.vsyncData.preferredExpectedPresentationTime(), event.vsync.vsyncData.preferredDeadlineTimestamp()); } - auto it = mBufferStuffedUids.find(consumer->mOwnerUid); - if (it != mBufferStuffedUids.end()) { - copy.vsync.vsyncData.numberQueuedBuffers = it->second; - uidsPostedQueuedBuffers.emplace_back(consumer->mOwnerUid); - } else { - copy.vsync.vsyncData.numberQueuedBuffers = 0; - } switch (consumer->postEvent(copy)) { case NO_ERROR: break; @@ -796,12 +777,6 @@ void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event, removeDisplayEventConnectionLocked(consumer); } } - // The clients that have already received the queued buffer count - // can be removed from the buffer stuffed Uid list to avoid - // being sent duplicate messages. - for (auto uid : uidsPostedQueuedBuffers) { - mBufferStuffedUids.erase(uid); - } if (event.header.type == DisplayEventType::DISPLAY_EVENT_VSYNC && FlagManager::getInstance().vrr_config()) { mLastCommittedVsyncTime = diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index a91dde7430..612883a88b 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -56,7 +56,6 @@ using gui::VsyncEventData; // --------------------------------------------------------------------------- using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; -using BufferStuffingMap = ftl::SmallMap<uid_t, uint32_t, 10>; enum class VSyncRequest { None = -2, @@ -141,10 +140,6 @@ public: virtual void onHdcpLevelsChanged(PhysicalDisplayId displayId, int32_t connectedLevel, int32_t maxLevel) = 0; - - // An elevated number of queued buffers in the server is detected. This propagates a - // flag to Choreographer indicating that buffer stuffing recovery should begin. - virtual void addBufferStuffedUids(BufferStuffingMap bufferStuffedUids) = 0; }; struct IEventThreadCallback { @@ -199,8 +194,6 @@ public: void onHdcpLevelsChanged(PhysicalDisplayId displayId, int32_t connectedLevel, int32_t maxLevel) override; - void addBufferStuffedUids(BufferStuffingMap bufferStuffedUids) override; - private: friend EventThreadTest; @@ -241,10 +234,6 @@ private: scheduler::VSyncCallbackRegistration mVsyncRegistration GUARDED_BY(mMutex); frametimeline::TokenManager* const mTokenManager; - // All consumers that need to recover from buffer stuffing and the number - // of their queued buffers. - BufferStuffingMap mBufferStuffedUids GUARDED_BY(mMutex); - IEventThreadCallback& mCallback; std::thread mThread; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index e587178ec2..16266c6b00 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -124,7 +124,10 @@ void Scheduler::setPacesetterDisplay(PhysicalDisplayId pacesetterId) { // Cancel the pending refresh rate change, if any, before updating the phase configuration. mVsyncModulator->cancelRefreshRateChange(); - mVsyncConfiguration->reset(); + { + std::scoped_lock lock{mVsyncConfigLock}; + mVsyncConfiguration->reset(); + } updatePhaseConfiguration(pacesetterId, pacesetterSelectorPtr()->getActiveMode().fps); } @@ -211,7 +214,7 @@ void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId, .vsyncId = vsyncId, .expectedVsyncTime = expectedVsyncTime, .sfWorkDuration = mVsyncModulator->getVsyncConfig().sfWorkDuration, - .hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration, + .hwcMinWorkDuration = getCurrentVsyncConfigs().hwcMinWorkDuration, .debugPresentTimeDelay = debugPresentDelay}; ftl::NonNull<const Display*> pacesetterPtr = pacesetterPtrLocked(); @@ -516,12 +519,26 @@ void Scheduler::updatePhaseConfiguration(PhysicalDisplayId displayId, Fps refres if (!isPacesetter) return; mRefreshRateStats->setRefreshRate(refreshRate); - mVsyncConfiguration->setRefreshRateFps(refreshRate); - setVsyncConfig(mVsyncModulator->setVsyncConfigSet(mVsyncConfiguration->getCurrentConfigs()), - refreshRate.getPeriod()); + const auto currentConfigs = [=, this] { + std::scoped_lock lock{mVsyncConfigLock}; + mVsyncConfiguration->setRefreshRateFps(refreshRate); + return mVsyncConfiguration->getCurrentConfigs(); + }(); + setVsyncConfig(mVsyncModulator->setVsyncConfigSet(currentConfigs), refreshRate.getPeriod()); } #pragma clang diagnostic pop +void Scheduler::reloadPhaseConfiguration(Fps refreshRate, Duration minSfDuration, + Duration maxSfDuration, Duration appDuration) { + const auto currentConfigs = [=, this] { + std::scoped_lock lock{mVsyncConfigLock}; + mVsyncConfiguration = std::make_unique<impl::WorkDuration>(refreshRate, minSfDuration, + maxSfDuration, appDuration); + return mVsyncConfiguration->getCurrentConfigs(); + }(); + setVsyncConfig(mVsyncModulator->setVsyncConfigSet(currentConfigs), refreshRate.getPeriod()); +} + void Scheduler::setActiveDisplayPowerModeForRefreshRateStats(hal::PowerMode powerMode) { mRefreshRateStats->setPowerMode(powerMode); } @@ -554,8 +571,7 @@ void Scheduler::resyncAllToHardwareVsync(bool allowToEnable) { ftl::FakeGuard guard(kMainThreadContext); for (const auto& [id, display] : mDisplays) { - if (display.powerMode != hal::PowerMode::OFF || - !FlagManager::getInstance().multithreaded_present()) { + if (display.powerMode != hal::PowerMode::OFF) { resyncToHardwareVsyncLocked(id, allowToEnable); } } @@ -897,8 +913,11 @@ void Scheduler::dump(utils::Dumper& dumper) const { mFrameRateOverrideMappings.dump(dumper); dumper.eol(); - mVsyncConfiguration->dump(dumper.out()); - dumper.eol(); + { + std::scoped_lock lock{mVsyncConfigLock}; + mVsyncConfiguration->dump(dumper.out()); + dumper.eol(); + } mRefreshRateStats->dump(dumper.out()); dumper.eol(); @@ -961,11 +980,6 @@ bool Scheduler::updateFrameRateOverridesLocked(GlobalSignals consideredSignals, return mFrameRateOverrideMappings.updateFrameRateOverridesByContent(frameRateOverrides); } -void Scheduler::addBufferStuffedUids(BufferStuffingMap bufferStuffedUids) { - if (!mRenderEventThread) return; - mRenderEventThread->addBufferStuffedUids(std::move(bufferStuffedUids)); -} - void Scheduler::promotePacesetterDisplay(PhysicalDisplayId pacesetterId, PromotionParams params) { std::shared_ptr<VsyncSchedule> pacesetterVsyncSchedule; { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 81389e7362..694856e9ce 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -53,6 +53,7 @@ #include "RefreshRateSelector.h" #include "SmallAreaDetectionAllowMappings.h" #include "Utils/Dumper.h" +#include "VsyncConfiguration.h" #include "VsyncModulator.h" #include <FrontEnd/LayerHierarchy.h> @@ -95,7 +96,7 @@ public: // TODO: b/241285191 - Remove this API by promoting pacesetter in onScreen{Acquired,Released}. void setPacesetterDisplay(PhysicalDisplayId) REQUIRES(kMainThreadContext) - EXCLUDES(mDisplayLock); + EXCLUDES(mDisplayLock, mVsyncConfigLock); using RefreshRateSelectorPtr = std::shared_ptr<RefreshRateSelector>; @@ -188,9 +189,19 @@ public: } } - void updatePhaseConfiguration(PhysicalDisplayId, Fps); + void updatePhaseConfiguration(PhysicalDisplayId, Fps) EXCLUDES(mVsyncConfigLock); + void reloadPhaseConfiguration(Fps, Duration minSfDuration, Duration maxSfDuration, + Duration appDuration) EXCLUDES(mVsyncConfigLock); + + VsyncConfigSet getCurrentVsyncConfigs() const EXCLUDES(mVsyncConfigLock) { + std::scoped_lock lock{mVsyncConfigLock}; + return mVsyncConfiguration->getCurrentConfigs(); + } - const VsyncConfiguration& getVsyncConfiguration() const { return *mVsyncConfiguration; } + VsyncConfigSet getVsyncConfigsForRefreshRate(Fps refreshRate) const EXCLUDES(mVsyncConfigLock) { + std::scoped_lock lock{mVsyncConfigLock}; + return mVsyncConfiguration->getConfigsForRefreshRate(refreshRate); + } // Sets the render rate for the scheduler to run at. void setRenderRate(PhysicalDisplayId, Fps, bool applyImmediately); @@ -266,7 +277,7 @@ public: bool isVsyncInPhase(TimePoint expectedVsyncTime, Fps frameRate) const; - void dump(utils::Dumper&) const; + void dump(utils::Dumper&) const EXCLUDES(mVsyncConfigLock); void dump(Cycle, std::string&) const; void dumpVsync(std::string&) const EXCLUDES(mDisplayLock); @@ -337,10 +348,6 @@ public: mPacesetterFrameDurationFractionToSkip = frameDurationFraction; } - // Propagates a flag to the EventThread indicating that buffer stuffing - // recovery should begin. - void addBufferStuffedUids(BufferStuffingMap bufferStuffedUids); - void setDebugPresentDelay(TimePoint delay) { mDebugPresentDelay = delay; } private: @@ -352,7 +359,7 @@ private: // impl::MessageQueue overrides: void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) override - REQUIRES(kMainThreadContext, mDisplayLock); + REQUIRES(kMainThreadContext, mDisplayLock) EXCLUDES(mVsyncConfigLock); // Used to skip event dispatch before EventThread creation during boot. // TODO: b/241285191 - Reorder Scheduler initialization to avoid this. @@ -480,8 +487,9 @@ private: const FeatureFlags mFeatures; + mutable std::mutex mVsyncConfigLock; // Stores phase offsets configured per refresh rate. - const std::unique_ptr<VsyncConfiguration> mVsyncConfiguration; + std::unique_ptr<VsyncConfiguration> mVsyncConfiguration GUARDED_BY(mVsyncConfigLock); // Shifts the VSYNC phase during certain transactions and refresh rate changes. const sp<VsyncModulator> mVsyncModulator; diff --git a/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp b/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp index 6ae10f3d31..8cbb17c06e 100644 --- a/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp +++ b/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp @@ -362,6 +362,17 @@ WorkDuration::WorkDuration(Fps currentRefreshRate) validateSysprops(); } +WorkDuration::WorkDuration(Fps currentRefreshRate, Duration minSfDuration, Duration maxSfDuration, + Duration appDuration) + : WorkDuration(currentRefreshRate, + /*sfDuration*/ minSfDuration.ns(), + /*appDuration*/ appDuration.ns(), + /*sfEarlyDuration*/ maxSfDuration.ns(), + /*appEarlyDuration*/ appDuration.ns(), + /*sfEarlyGpuDuration*/ maxSfDuration.ns(), + /*appEarlyGpuDuration*/ appDuration.ns(), + /*hwcMinWorkDuration*/ 0) {} + WorkDuration::WorkDuration(Fps currentRefreshRate, nsecs_t sfDuration, nsecs_t appDuration, nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration, nsecs_t sfEarlyGpuDuration, nsecs_t appEarlyGpuDuration, diff --git a/services/surfaceflinger/Scheduler/VsyncConfiguration.h b/services/surfaceflinger/Scheduler/VsyncConfiguration.h index b6cb373b7e..3d8ae3e5d4 100644 --- a/services/surfaceflinger/Scheduler/VsyncConfiguration.h +++ b/services/surfaceflinger/Scheduler/VsyncConfiguration.h @@ -144,6 +144,8 @@ private: class WorkDuration : public VsyncConfiguration { public: explicit WorkDuration(Fps currentRefreshRate); + WorkDuration(Fps currentRefreshRate, Duration minSfDuration, Duration maxSfDuration, + Duration appDuration); protected: // Used for unit tests diff --git a/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h index 767462dfce..70ae940b65 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h @@ -36,7 +36,7 @@ enum class CompositionCoverage : std::uint8_t { using CompositionCoverageFlags = ftl::Flags<CompositionCoverage>; -using CompositionCoveragePerDisplay = ui::DisplayMap<DisplayId, CompositionCoverageFlags>; +using CompositionCoveragePerDisplay = ui::DisplayMap<DisplayIdVariant, CompositionCoverageFlags>; inline CompositionCoverageFlags multiDisplayUnion(const CompositionCoveragePerDisplay& displays) { CompositionCoverageFlags coverage; diff --git a/services/surfaceflinger/ScreenCaptureOutput.cpp b/services/surfaceflinger/ScreenCaptureOutput.cpp index af6d4d30e4..2906bbd5b8 100644 --- a/services/surfaceflinger/ScreenCaptureOutput.cpp +++ b/services/surfaceflinger/ScreenCaptureOutput.cpp @@ -30,11 +30,12 @@ namespace android { std::shared_ptr<ScreenCaptureOutput> createScreenCaptureOutput(ScreenCaptureOutputArgs args) { std::shared_ptr<ScreenCaptureOutput> output = compositionengine::impl::createOutputTemplated< ScreenCaptureOutput, compositionengine::CompositionEngine, - /* sourceCrop */ const Rect, std::optional<DisplayId>, + /* sourceCrop */ const Rect, ftl::Optional<DisplayIdVariant>, const compositionengine::Output::ColorProfile&, /* layerAlpha */ float, - /* regionSampling */ bool>(args.compositionEngine, args.sourceCrop, args.displayId, - args.colorProfile, args.layerAlpha, args.regionSampling, + /* regionSampling */ bool>(args.compositionEngine, args.sourceCrop, + args.displayIdVariant, args.colorProfile, args.layerAlpha, + args.regionSampling, args.dimInGammaSpaceForEnhancedScreenshots, args.enableLocalTonemapping); output->editState().isSecure = args.isSecure; @@ -59,8 +60,8 @@ std::shared_ptr<ScreenCaptureOutput> createScreenCaptureOutput(ScreenCaptureOutp { std::string name = args.regionSampling ? "RegionSampling" : "ScreenCaptureOutput"; - if (args.displayId) { - base::StringAppendF(&name, " for %" PRIu64, args.displayId.value().value); + if (const auto id = args.displayIdVariant.and_then(asDisplayIdOfType<DisplayId>)) { + base::StringAppendF(&name, " for %" PRIu64, id->value); } output->setName(name); } @@ -68,12 +69,12 @@ std::shared_ptr<ScreenCaptureOutput> createScreenCaptureOutput(ScreenCaptureOutp } ScreenCaptureOutput::ScreenCaptureOutput( - const Rect sourceCrop, std::optional<DisplayId> displayId, + const Rect sourceCrop, ftl::Optional<DisplayIdVariant> displayIdVariant, const compositionengine::Output::ColorProfile& colorProfile, float layerAlpha, bool regionSampling, bool dimInGammaSpaceForEnhancedScreenshots, bool enableLocalTonemapping) : mSourceCrop(sourceCrop), - mDisplayId(displayId), + mDisplayIdVariant(displayIdVariant), mColorProfile(colorProfile), mLayerAlpha(layerAlpha), mRegionSampling(regionSampling), @@ -137,12 +138,9 @@ ScreenCaptureOutput::generateLuts() { } std::vector<aidl::android::hardware::graphics::composer3::Luts> luts; - if (mDisplayId) { - const auto id = PhysicalDisplayId::tryCast(mDisplayId.value()); - if (id) { - auto& hwc = getCompositionEngine().getHwComposer(); - hwc.getLuts(*id, buffers, &luts); - } + if (const auto physicalDisplayId = mDisplayIdVariant.and_then(asPhysicalDisplayId)) { + auto& hwc = getCompositionEngine().getHwComposer(); + hwc.getLuts(*physicalDisplayId, buffers, &luts); } if (buffers.size() == luts.size()) { diff --git a/services/surfaceflinger/ScreenCaptureOutput.h b/services/surfaceflinger/ScreenCaptureOutput.h index b3e98b1a32..d4e20fc2f3 100644 --- a/services/surfaceflinger/ScreenCaptureOutput.h +++ b/services/surfaceflinger/ScreenCaptureOutput.h @@ -30,7 +30,7 @@ struct ScreenCaptureOutputArgs { ui::LayerStack layerStack; Rect sourceCrop; std::shared_ptr<renderengine::ExternalTexture> buffer; - std::optional<DisplayId> displayId; + ftl::Optional<DisplayIdVariant> displayIdVariant; ui::Size reqBufferSize; float sdrWhitePointNits; float displayBrightnessNits; @@ -51,7 +51,7 @@ struct ScreenCaptureOutputArgs { // SurfaceFlinger::captureLayers and SurfaceFlinger::captureDisplay. class ScreenCaptureOutput : public compositionengine::impl::Output { public: - ScreenCaptureOutput(const Rect sourceCrop, std::optional<DisplayId> displayId, + ScreenCaptureOutput(const Rect sourceCrop, ftl::Optional<DisplayIdVariant> displayIdVariant, const compositionengine::Output::ColorProfile& colorProfile, float layerAlpha, bool regionSampling, bool dimInGammaSpaceForEnhancedScreenshots, bool enableLocalTonemapping); @@ -70,7 +70,7 @@ protected: private: std::unordered_map<int32_t, aidl::android::hardware::graphics::composer3::Luts> generateLuts(); const Rect mSourceCrop; - const std::optional<DisplayId> mDisplayId; + const ftl::Optional<DisplayIdVariant> mDisplayIdVariant; const compositionengine::Output::ColorProfile& mColorProfile; const float mLayerAlpha; const bool mRegionSampling; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 099aa7a865..2fb3500798 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -19,7 +19,7 @@ #pragma clang diagnostic ignored "-Wconversion" #pragma clang diagnostic ignored "-Wextra" -//#define LOG_NDEBUG 0 +// #define LOG_NDEBUG 0 #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "SurfaceFlinger.h" @@ -66,13 +66,11 @@ #include <ftl/concat.h> #include <ftl/fake_guard.h> #include <ftl/future.h> -#include <ftl/small_map.h> #include <ftl/unit.h> #include <gui/AidlUtil.h> #include <gui/BufferQueue.h> #include <gui/DebugEGLImageTracker.h> #include <gui/IProducerListener.h> -#include <gui/JankInfo.h> #include <gui/LayerMetadata.h> #include <gui/LayerState.h> #include <gui/Surface.h> @@ -363,7 +361,7 @@ bool isExpectedPresentWithinTimeout(TimePoint expectedPresentTime, return std::abs(expectedPresentTime.ns() - (lastExpectedPresentTimestamp.ns() + timeoutOpt->ns())) < threshold.ns(); } -} // namespace anonymous +} // namespace // --------------------------------------------------------------------------- @@ -395,7 +393,7 @@ ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::Pixel LatchUnsignaledConfig SurfaceFlinger::enableLatchUnsignaledConfig; std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) { - switch(displayColorSetting) { + switch (displayColorSetting) { case DisplayColorSetting::kManaged: return std::string("Managed"); case DisplayColorSetting::kUnmanaged: @@ -403,8 +401,7 @@ std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) { case DisplayColorSetting::kEnhanced: return std::string("Enhanced"); default: - return std::string("Unknown ") + - std::to_string(static_cast<int>(displayColorSetting)); + return std::string("Unknown ") + std::to_string(static_cast<int>(displayColorSetting)); } } @@ -596,15 +593,14 @@ sp<IBinder> SurfaceFlinger::createVirtualDisplay( class DisplayToken : public BBinder { sp<SurfaceFlinger> flinger; virtual ~DisplayToken() { - // no more references, this display must be terminated - Mutex::Autolock _l(flinger->mStateLock); - flinger->mCurrentState.displays.removeItem(wp<IBinder>::fromExisting(this)); - flinger->setTransactionFlags(eDisplayTransactionNeeded); - } - public: - explicit DisplayToken(const sp<SurfaceFlinger>& flinger) - : flinger(flinger) { + // no more references, this display must be terminated + Mutex::Autolock _l(flinger->mStateLock); + flinger->mCurrentState.displays.removeItem(wp<IBinder>::fromExisting(this)); + flinger->setTransactionFlags(eDisplayTransactionNeeded); } + + public: + explicit DisplayToken(const sp<SurfaceFlinger>& flinger) : flinger(flinger) {} }; sp<BBinder> token = sp<DisplayToken>::make(sp<SurfaceFlinger>::fromExisting(this)); @@ -659,12 +655,14 @@ void SurfaceFlinger::enableHalVirtualDisplays(bool enable) { } } -VirtualDisplayId SurfaceFlinger::acquireVirtualDisplay(ui::Size resolution, ui::PixelFormat format, - const std::string& uniqueId) { +std::optional<VirtualDisplayIdVariant> SurfaceFlinger::acquireVirtualDisplay( + ui::Size resolution, ui::PixelFormat format, const std::string& uniqueId, + compositionengine::DisplayCreationArgsBuilder& builder) { if (auto& generator = mVirtualDisplayIdGenerators.hal) { if (const auto id = generator->generateId()) { if (getHwComposer().allocateVirtualDisplay(*id, resolution, &format)) { acquireVirtualDisplaySnapshot(*id, uniqueId); + builder.setId(*id); return *id; } @@ -679,22 +677,23 @@ VirtualDisplayId SurfaceFlinger::acquireVirtualDisplay(ui::Size resolution, ui:: const auto id = mVirtualDisplayIdGenerators.gpu.generateId(); LOG_ALWAYS_FATAL_IF(!id, "Failed to generate ID for GPU virtual display"); acquireVirtualDisplaySnapshot(*id, uniqueId); + builder.setId(*id); return *id; } -void SurfaceFlinger::releaseVirtualDisplay(VirtualDisplayId displayId) { - if (const auto id = HalVirtualDisplayId::tryCast(displayId)) { - if (auto& generator = mVirtualDisplayIdGenerators.hal) { - generator->releaseId(*id); - releaseVirtualDisplaySnapshot(*id); - } - return; - } - - const auto id = GpuVirtualDisplayId::tryCast(displayId); - LOG_ALWAYS_FATAL_IF(!id); - mVirtualDisplayIdGenerators.gpu.releaseId(*id); - releaseVirtualDisplaySnapshot(*id); +void SurfaceFlinger::releaseVirtualDisplay(VirtualDisplayIdVariant displayId) { + ftl::match( + displayId, + [this](HalVirtualDisplayId halVirtualDisplayId) { + if (auto& generator = mVirtualDisplayIdGenerators.hal) { + generator->releaseId(halVirtualDisplayId); + releaseVirtualDisplaySnapshot(halVirtualDisplayId); + } + }, + [this](GpuVirtualDisplayId gpuVirtualDisplayId) { + mVirtualDisplayIdGenerators.gpu.releaseId(gpuVirtualDisplayId); + releaseVirtualDisplaySnapshot(gpuVirtualDisplayId); + }); } void SurfaceFlinger::releaseVirtualDisplaySnapshot(VirtualDisplayId displayId) { @@ -760,7 +759,7 @@ void SurfaceFlinger::bootFinished() { const nsecs_t now = systemTime(); const nsecs_t duration = now - mBootTime; - ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) ); + ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration))); mFrameTracer->initialize(); mFrameTimeline->onBootFinished(); @@ -779,8 +778,7 @@ void SurfaceFlinger::bootFinished() { property_set("service.bootanim.exit", "1"); const int LOGTAG_SF_STOP_BOOTANIM = 60110; - LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM, - ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); + LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); sp<IBinder> input(defaultServiceManager()->waitForService(String16("inputflinger"))); @@ -900,8 +898,8 @@ renderengine::RenderEngine::BlurAlgorithm chooseBlurAlgorithm(bool supportsBlur) void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) { SFTRACE_CALL(); - ALOGI( "SurfaceFlinger's main thread ready to run. " - "Initializing graphics H/W..."); + ALOGI("SurfaceFlinger's main thread ready to run. " + "Initializing graphics H/W..."); addTransactionReadyFilters(); Mutex::Autolock lock(mStateLock); @@ -1124,17 +1122,16 @@ void SurfaceFlinger::readPersistentProperties() { static_cast<ui::ColorMode>(base::GetIntProperty("persist.sys.sf.color_mode"s, 0)); } -status_t SurfaceFlinger::getSupportedFrameTimestamps( - std::vector<FrameEvent>* outSupported) const { +status_t SurfaceFlinger::getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const { *outSupported = { - FrameEvent::REQUESTED_PRESENT, - FrameEvent::ACQUIRE, - FrameEvent::LATCH, - FrameEvent::FIRST_REFRESH_START, - FrameEvent::LAST_REFRESH_START, - FrameEvent::GPU_COMPOSITION_DONE, - FrameEvent::DEQUEUE_READY, - FrameEvent::RELEASE, + FrameEvent::REQUESTED_PRESENT, + FrameEvent::ACQUIRE, + FrameEvent::LATCH, + FrameEvent::FIRST_REFRESH_START, + FrameEvent::LAST_REFRESH_START, + FrameEvent::GPU_COMPOSITION_DONE, + FrameEvent::DEQUEUE_READY, + FrameEvent::RELEASE, }; if (mHasReliablePresentFences) { @@ -1182,6 +1179,7 @@ status_t SurfaceFlinger::getStaticDisplayInfo(int64_t displayId, ui::StaticDispl const auto& snapshot = snapshotRef.get(); info->connectionType = snapshot.connectionType(); + info->port = snapshot.port(); info->deviceProductInfo = snapshot.deviceProductInfo(); if (mEmulatedDisplayDensity) { @@ -1228,8 +1226,8 @@ void SurfaceFlinger::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo*& info outMode.peakRefreshRate = peakFps.getValue(); outMode.vsyncRate = mode->getVsyncRate().getValue(); - const auto vsyncConfigSet = mScheduler->getVsyncConfiguration().getConfigsForRefreshRate( - Fps::fromValue(outMode.peakRefreshRate)); + const auto vsyncConfigSet = + mScheduler->getVsyncConfigsForRefreshRate(Fps::fromValue(outMode.peakRefreshRate)); outMode.appVsyncOffset = vsyncConfigSet.late.appOffset; outMode.sfVsyncOffset = vsyncConfigSet.late.sfOffset; outMode.group = mode->getGroup(); @@ -1265,7 +1263,17 @@ void SurfaceFlinger::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo*& info ui::FrameRateCategoryRate frameRateCategoryRate(normal.getValue(), high.getValue()); info->frameRateCategoryRate = frameRateCategoryRate; - info->supportedRefreshRates = display->refreshRateSelector().getSupportedFrameRates(); + if (info->hasArrSupport) { + info->supportedRefreshRates = display->refreshRateSelector().getSupportedFrameRates(); + } else { + // On non-ARR devices, list the refresh rates same as the supported display modes. + std::vector<float> supportedFrameRates; + supportedFrameRates.reserve(info->supportedDisplayModes.size()); + std::transform(info->supportedDisplayModes.begin(), info->supportedDisplayModes.end(), + std::back_inserter(supportedFrameRates), + [](ui::DisplayMode mode) { return mode.peakRefreshRate; }); + info->supportedRefreshRates = supportedFrameRates; + } info->activeColorMode = display->getCompositionDisplay()->getState().colorMode; info->hdrCapabilities = filterOut4k30(display->getHdrCapabilities()); @@ -2198,7 +2206,6 @@ status_t SurfaceFlinger::addHdrLayerInfoListener(const sp<IBinder>& displayToken } hdrInfoReporter->addListener(listener); - mAddingHDRLayerInfoListener = true; return OK; } @@ -2259,13 +2266,13 @@ sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection( const auto cycle = [&] { if (FlagManager::getInstance().deprecate_vsync_sf()) { ALOGW_IF(vsyncSource == gui::ISurfaceComposer::VsyncSource::eVsyncSourceSurfaceFlinger, - "requested unsupported config eVsyncSourceSurfaceFlinger"); + "requested unsupported config eVsyncSourceSurfaceFlinger"); return scheduler::Cycle::Render; } return vsyncSource == gui::ISurfaceComposer::VsyncSource::eVsyncSourceSurfaceFlinger - ? scheduler::Cycle::LastComposite - : scheduler::Cycle::Render; + ? scheduler::Cycle::LastComposite + : scheduler::Cycle::Render; }(); return mScheduler->createDisplayEventConnection(cycle, eventRegistration, layerHandle); } @@ -2795,9 +2802,10 @@ bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId, // setTransactionFlags which will schedule another SF frame. This was if the tracker // needs to adjust the vsync timeline, it will be done before the next frame. if (FlagManager::getInstance().vrr_config() && mustComposite) { - mScheduler->getVsyncSchedule()->getTracker().onFrameBegin( - pacesetterFrameTarget.expectedPresentTime(), - pacesetterFrameTarget.lastSignaledFrameTime()); + mScheduler->getVsyncSchedule() + ->getTracker() + .onFrameBegin(pacesetterFrameTarget.expectedPresentTime(), + pacesetterFrameTarget.lastSignaledFrameTime()); } if (transactionFlushNeeded()) { setTransactionFlags(eTransactionFlushNeeded); @@ -2863,9 +2871,9 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( // output. Layer stacks are not tracked in Display when we iterate through // frameTargeters. Cross-referencing layer stacks allows us to filter out displays // by ID with duplicate layer stacks before adding them to CompositionEngine output. - ui::DisplayMap<DisplayId, ui::LayerStack> physicalDisplayLayerStacks; + ui::DisplayMap<PhysicalDisplayId, ui::LayerStack> physicalDisplayLayerStacks; for (auto& [_, display] : displays) { - const auto id = PhysicalDisplayId::tryCast(display->getId()); + const auto id = asPhysicalDisplayId(display->getDisplayIdVariant()); if (id && frameTargeters.contains(*id)) { physicalDisplayLayerStacks.try_emplace(*id, display->getLayerStack()); } @@ -3046,7 +3054,7 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( // This should be interpreted to mean that there are 2 cached sets. // So there are only 2 non skipped layers -- b and s. // The layers rrc and cc are flattened into layers b and s respectively. - const LayerFE::HwcLayerDebugState &hwcState = layerFE->getLastHwcState(); + const LayerFE::HwcLayerDebugState& hwcState = layerFE->getLastHwcState(); if (hwcState.overrideBufferId != prevOverrideBufferId) { // End the existing run. if (prevOverrideBufferId) { @@ -3058,11 +3066,10 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( } } - compositionSummary.push_back( - layerFE->mSnapshot->classifyCompositionForDebug(hwcState)); + compositionSummary.push_back(layerFE->mSnapshot->classifyCompositionForDebug(hwcState)); if (hwcState.overrideBufferId && !hwcState.wasSkipped) { - compositionSummary.push_back(':'); + compositionSummary.push_back(':'); } prevOverrideBufferId = hwcState.overrideBufferId; @@ -3131,7 +3138,7 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( for (const auto& [_, display] : displays) { const auto& state = display->getCompositionDisplay()->getState(); CompositionCoverageFlags& flags = - mCompositionCoverage.try_emplace(display->getId()).first->second; + mCompositionCoverage.try_emplace(display->getDisplayIdVariant()).first->second; if (state.usesDeviceComposition) { flags |= CompositionCoverage::Hwc; @@ -3185,8 +3192,8 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( CompositeResultsPerDisplay resultsPerDisplay; // Filter out virtual displays. - for (const auto& [id, coverage] : mCompositionCoverage) { - if (const auto idOpt = PhysicalDisplayId::tryCast(id)) { + for (const auto& [idVar, coverage] : mCompositionCoverage) { + if (const auto idOpt = asPhysicalDisplayId(idVar)) { resultsPerDisplay.try_emplace(*idOpt, CompositeResult{coverage}); } } @@ -3224,16 +3231,12 @@ bool SurfaceFlinger::isHdrLayer(const frontend::LayerSnapshot& snapshot) const { return false; } -ui::Rotation SurfaceFlinger::getPhysicalDisplayOrientation(DisplayId displayId, +ui::Rotation SurfaceFlinger::getPhysicalDisplayOrientation(PhysicalDisplayId displayId, bool isPrimary) const { - const auto id = PhysicalDisplayId::tryCast(displayId); - if (!id) { - return ui::ROTATION_0; - } if (!mIgnoreHwcPhysicalDisplayOrientation && getHwComposer().getComposer()->isSupported( Hwc2::Composer::OptionalFeature::PhysicalDisplayOrientation)) { - switch (getHwComposer().getPhysicalDisplayOrientation(*id)) { + switch (getHwComposer().getPhysicalDisplayOrientation(displayId)) { case Hwc2::AidlTransform::ROT_90: return ui::ROTATION_90; case Hwc2::AidlTransform::ROT_180: @@ -3305,40 +3308,12 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, const TimePoint presentTime = TimePoint::now(); - // The Uids of layer owners that are in buffer stuffing mode, and their elevated - // buffer counts. Messages to start recovery are sent exclusively to these Uids. - BufferStuffingMap bufferStuffedUids; - // Set presentation information before calling Layer::releasePendingBuffer, such that jank // information from previous' frame classification is already available when sending jank info // to clients, so they get jank classification as early as possible. mFrameTimeline->setSfPresent(presentTime.ns(), pacesetterPresentFenceTime, pacesetterGpuCompositionDoneFenceTime); - // Find and register any layers that are in buffer stuffing mode - const auto& presentFrames = mFrameTimeline->getPresentFrames(); - - for (const auto& frame : presentFrames) { - const auto& layer = mLayerLifecycleManager.getLayerFromId(frame->getLayerId()); - if (!layer) continue; - uint32_t numberQueuedBuffers = layer->pendingBuffers ? layer->pendingBuffers->load() : 0; - int32_t jankType = frame->getJankType().value_or(JankType::None); - if (jankType & JankType::BufferStuffing && - layer->flags & layer_state_t::eRecoverableFromBufferStuffing) { - auto [it, wasEmplaced] = - bufferStuffedUids.try_emplace(layer->ownerUid.val(), numberQueuedBuffers); - // Update with maximum number of queued buffers, allows clients drawing - // multiple windows to account for the most severely stuffed window - if (!wasEmplaced && it->second < numberQueuedBuffers) { - it->second = numberQueuedBuffers; - } - } - } - - if (!bufferStuffedUids.empty()) { - mScheduler->addBufferStuffedUids(std::move(bufferStuffedUids)); - } - // We use the CompositionEngine::getLastFrameRefreshTimestamp() which might // be sampled a little later than when we started doing work for this frame, // but that should be okay since CompositorTiming has snapping logic. @@ -3351,8 +3326,7 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, const auto schedule = mScheduler->getVsyncSchedule(); const TimePoint vsyncDeadline = schedule->vsyncDeadlineAfter(presentTime); const Fps renderRate = pacesetterDisplay->refreshRateSelector().getActiveMode().fps; - const nsecs_t vsyncPhase = - mScheduler->getVsyncConfiguration().getCurrentConfigs().late.sfOffset; + const nsecs_t vsyncPhase = mScheduler->getCurrentVsyncConfigs().late.sfOffset; const CompositorTiming compositorTiming(vsyncDeadline.ns(), renderRate.getPeriodNsecs(), vsyncPhase, presentLatency.ns()); @@ -3881,13 +3855,17 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( creationArgs.hasWideColorGamut = false; creationArgs.supportedPerFrameMetadata = 0; - if (const auto physicalIdOpt = PhysicalDisplayId::tryCast(compositionDisplay->getId())) { + if (const auto physicalIdOpt = + compositionDisplay->getDisplayIdVariant().and_then(asPhysicalDisplayId)) { const auto physicalId = *physicalIdOpt; creationArgs.isPrimary = physicalId == getPrimaryDisplayIdLocked(); creationArgs.refreshRateSelector = FTL_FAKE_GUARD(kMainThreadContext, mDisplayModeController.selectorPtrFor(physicalId)); + creationArgs.physicalOrientation = + getPhysicalDisplayOrientation(physicalId, creationArgs.isPrimary); + ALOGV("Display Orientation: %s", toCString(creationArgs.physicalOrientation)); mPhysicalDisplays.get(physicalId) .transform(&PhysicalDisplay::snapshotRef) @@ -3900,7 +3878,8 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( })); } - if (const auto id = HalDisplayId::tryCast(compositionDisplay->getId())) { + if (const auto id = compositionDisplay->getDisplayIdVariant().and_then( + asHalDisplayId<DisplayIdVariant>)) { getHwComposer().getHdrCapabilities(*id, &creationArgs.hdrCapabilities); creationArgs.supportedPerFrameMetadata = getHwComposer().getSupportedPerFrameMetadata(*id); } @@ -3916,10 +3895,6 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( nativeWindow->setSwapInterval(nativeWindow.get(), 0); } - creationArgs.physicalOrientation = - getPhysicalDisplayOrientation(compositionDisplay->getId(), creationArgs.isPrimary); - ALOGV("Display Orientation: %s", toCString(creationArgs.physicalOrientation)); - if (FlagManager::getInstance().correct_virtual_display_power_state()) { creationArgs.initialPowerMode = state.initialPowerMode; } else { @@ -3949,7 +3924,8 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( mode.getPeakFps()); } - display->setLayerFilter(makeLayerFilterForDisplay(display->getId(), state.layerStack)); + display->setLayerFilter( + makeLayerFilterForDisplay(display->getDisplayIdVariant(), state.layerStack)); display->setProjection(state.orientation, state.layerStackSpaceRect, state.orientedDisplaySpaceRect); display->setDisplayName(state.displayName); @@ -4005,10 +3981,12 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, } compositionengine::DisplayCreationArgsBuilder builder; + std::optional<VirtualDisplayIdVariant> virtualDisplayIdVariantOpt; if (const auto& physical = state.physical) { builder.setId(physical->id); } else { - builder.setId(acquireVirtualDisplay(resolution, pixelFormat, state.uniqueId)); + virtualDisplayIdVariantOpt = + acquireVirtualDisplay(resolution, pixelFormat, state.uniqueId, builder); } builder.setPixels(resolution); @@ -4028,10 +4006,10 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, getFactory().createBufferQueue(&bqProducer, &bqConsumer, /*consumerIsSurfaceFlinger =*/false); if (state.isVirtual()) { - const auto displayId = VirtualDisplayId::tryCast(compositionDisplay->getId()); - LOG_FATAL_IF(!displayId); - auto surface = sp<VirtualDisplaySurface>::make(getHwComposer(), *displayId, state.surface, - bqProducer, bqConsumer, state.displayName); + LOG_FATAL_IF(!virtualDisplayIdVariantOpt); + auto surface = sp<VirtualDisplaySurface>::make(getHwComposer(), *virtualDisplayIdVariantOpt, + state.surface, bqProducer, bqConsumer, + state.displayName); displaySurface = surface; producer = std::move(surface); } else { @@ -4039,18 +4017,17 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, "adding a supported display, but rendering " "surface is provided (%p), ignoring it", state.surface.get()); - const auto displayId = PhysicalDisplayId::tryCast(compositionDisplay->getId()); - LOG_FATAL_IF(!displayId); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) const auto frameBufferSurface = - sp<FramebufferSurface>::make(getHwComposer(), *displayId, bqProducer, bqConsumer, + sp<FramebufferSurface>::make(getHwComposer(), state.physical->id, bqProducer, + bqConsumer, state.physical->activeMode->getResolution(), ui::Size(maxGraphicsWidth, maxGraphicsHeight)); displaySurface = frameBufferSurface; producer = frameBufferSurface->getSurface()->getIGraphicBufferProducer(); #else displaySurface = - sp<FramebufferSurface>::make(getHwComposer(), *displayId, bqConsumer, + sp<FramebufferSurface>::make(getHwComposer(), state.physical->id, bqConsumer, state.physical->activeMode->getResolution(), ui::Size(maxGraphicsWidth, maxGraphicsHeight)); producer = bqProducer; @@ -4075,6 +4052,10 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, incRefreshableDisplays(); } + if (FlagManager::getInstance().correct_virtual_display_power_state()) { + applyOptimizationPolicy(__func__); + } + mDisplays.try_emplace(displayToken, std::move(display)); // For an external display, loadDisplayModes already attempted to select the same mode @@ -4103,8 +4084,8 @@ void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) { if (display) { display->disconnect(); - if (display->isVirtual()) { - releaseVirtualDisplay(display->getVirtualId()); + if (const auto virtualDisplayIdVariant = display->getVirtualDisplayIdVariant()) { + releaseVirtualDisplay(*virtualDisplayIdVariant); } else { mScheduler->unregisterDisplay(display->getPhysicalId(), mActiveDisplayId); } @@ -4131,6 +4112,10 @@ void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) { // not be accessible. })); } + + if (FlagManager::getInstance().correct_virtual_display_power_state()) { + applyOptimizationPolicy(__func__); + } } void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, @@ -4143,8 +4128,8 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, if (currentBinder != drawingBinder || currentState.sequenceId != drawingState.sequenceId) { if (const auto display = getDisplayDeviceLocked(displayToken)) { display->disconnect(); - if (display->isVirtual()) { - releaseVirtualDisplay(display->getVirtualId()); + if (const auto virtualDisplayIdVariant = display->getVirtualDisplayIdVariant()) { + releaseVirtualDisplay(*virtualDisplayIdVariant); } if (display->isRefreshable()) { @@ -4164,7 +4149,7 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, if (currentState.physical) { const auto display = getDisplayDeviceLocked(displayToken); if (!mSkipPowerOnForQuiescent) { - setPowerModeInternal(display, hal::PowerMode::ON); + setPhysicalDisplayPowerMode(display, hal::PowerMode::ON); } if (display->getPhysicalId() == mActiveDisplayId) { @@ -4176,8 +4161,8 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, if (const auto display = getDisplayDeviceLocked(displayToken)) { if (currentState.layerStack != drawingState.layerStack) { - display->setLayerFilter( - makeLayerFilterForDisplay(display->getId(), currentState.layerStack)); + display->setLayerFilter(makeLayerFilterForDisplay(display->getDisplayIdVariant(), + currentState.layerStack)); } if (currentState.flags != drawingState.flags) { display->setFlags(currentState.flags); @@ -4333,37 +4318,35 @@ void SurfaceFlinger::updateInputFlinger(VsyncId vsyncId, TimePoint frameTime) { mVisibleWindowIds = std::move(visibleWindowIds); } - BackgroundExecutor::getInstance().sendCallbacks({[updateWindowInfo, - windowInfos = std::move(windowInfos), - displayInfos = std::move(displayInfos), - inputWindowCommands = - std::move(mInputWindowCommands), - inputFlinger = mInputFlinger, this, - visibleWindowsChanged, vsyncId, - frameTime]() mutable { - SFTRACE_NAME("BackgroundExecutor::updateInputFlinger"); - if (updateWindowInfo) { - mWindowInfosListenerInvoker - ->windowInfosChanged(gui::WindowInfosUpdate{std::move(windowInfos), - std::move(displayInfos), - ftl::to_underlying(vsyncId), - frameTime.ns()}, - std::move(inputWindowCommands.releaseListeners()), - /* forceImmediateCall= */ visibleWindowsChanged || - !inputWindowCommands.getFocusRequests().empty()); - } else { - // If there are listeners but no changes to input windows, call the listeners - // immediately. - for (const auto& listener : inputWindowCommands.getListeners()) { - if (IInterface::asBinder(listener)->isBinderAlive()) { - listener->onWindowInfosReported(); + BackgroundExecutor::getInstance().sendCallbacks( + {[updateWindowInfo, windowInfos = std::move(windowInfos), + displayInfos = std::move(displayInfos), + inputWindowCommands = std::move(mInputWindowCommands), inputFlinger = mInputFlinger, + this, visibleWindowsChanged, vsyncId, frameTime]() mutable { + SFTRACE_NAME("BackgroundExecutor::updateInputFlinger"); + if (updateWindowInfo) { + mWindowInfosListenerInvoker + ->windowInfosChanged(gui::WindowInfosUpdate{std::move(windowInfos), + std::move(displayInfos), + ftl::to_underlying(vsyncId), + frameTime.ns()}, + std::move(inputWindowCommands.releaseListeners()), + /* forceImmediateCall= */ visibleWindowsChanged || + !inputWindowCommands.getFocusRequests() + .empty()); + } else { + // If there are listeners but no changes to input windows, call the listeners + // immediately. + for (const auto& listener : inputWindowCommands.getListeners()) { + if (IInterface::asBinder(listener)->isBinderAlive()) { + listener->onWindowInfosReported(); + } + } } - } - } - for (const auto& focusRequest : inputWindowCommands.getFocusRequests()) { - inputFlinger->setFocusedWindow(focusRequest); - } - }}); + for (const auto& focusRequest : inputWindowCommands.getFocusRequests()) { + inputFlinger->setFocusedWindow(focusRequest); + } + }}); mInputWindowCommands.clear(); } @@ -4419,7 +4402,7 @@ void SurfaceFlinger::buildWindowInfos(std::vector<WindowInfo>& outWindowInfos, void SurfaceFlinger::updateCursorAsync() { compositionengine::CompositionRefreshArgs refreshArgs; for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) { - if (HalDisplayId::tryCast(display->getId())) { + if (asHalDisplayId(display->getDisplayIdVariant())) { refreshArgs.outputs.push_back(display->getCompositionDisplay()); } } @@ -4673,7 +4656,7 @@ void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) { /*applyImmediately*/ true); } - const auto configs = mScheduler->getVsyncConfiguration().getCurrentConfigs(); + const auto configs = mScheduler->getCurrentVsyncConfigs(); mScheduler->createEventThread(scheduler::Cycle::Render, mFrameTimeline->getTokenManager(), /* workDuration */ configs.late.appWorkDuration, @@ -5076,13 +5059,19 @@ status_t SurfaceFlinger::setTransactionState( if (resolvedState.state.hasBufferChanges() && resolvedState.state.hasValidBuffer() && resolvedState.state.surface) { sp<Layer> layer = LayerHandle::getLayer(resolvedState.state.surface); - std::string layerName = (layer) ? - layer->getDebugName() : std::to_string(resolvedState.state.layerId); + std::string layerName = + (layer) ? layer->getDebugName() : std::to_string(resolvedState.state.layerId); resolvedState.externalTexture = getExternalTextureFromBufferData(*resolvedState.state.bufferData, layerName.c_str(), transactionId); if (resolvedState.externalTexture) { resolvedState.state.bufferData->buffer = resolvedState.externalTexture->getBuffer(); + if (FlagManager::getInstance().monitor_buffer_fences()) { + resolvedState.state.bufferData->buffer->getDependencyMonitor() + .addIngress(FenceTime::makeValid( + resolvedState.state.bufferData->acquireFence), + "Incoming txn"); + } } mBufferCountTracker.increment(resolvedState.layerId); } @@ -5655,7 +5644,7 @@ void SurfaceFlinger::initializeDisplays() { // In case of a restart, ensure all displays are off. for (const auto& [id, display] : mPhysicalDisplays) { - setPowerModeInternal(getDisplayDeviceLocked(id), hal::PowerMode::OFF); + setPhysicalDisplayPowerMode(getDisplayDeviceLocked(id), hal::PowerMode::OFF); } // Power on all displays. The primary display is first, so becomes the active display. Also, @@ -5664,13 +5653,14 @@ void SurfaceFlinger::initializeDisplays() { // Additionally, do not turn on displays if the boot should be quiescent. if (!mSkipPowerOnForQuiescent) { for (const auto& [id, display] : mPhysicalDisplays) { - setPowerModeInternal(getDisplayDeviceLocked(id), hal::PowerMode::ON); + setPhysicalDisplayPowerMode(getDisplayDeviceLocked(id), hal::PowerMode::ON); } } } } -void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) { +void SurfaceFlinger::setPhysicalDisplayPowerMode(const sp<DisplayDevice>& display, + hal::PowerMode mode) { if (display->isVirtual()) { // TODO(b/241285876): This code path should not be reachable, so enforce this at compile // time. @@ -5679,7 +5669,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: } const auto displayId = display->getPhysicalId(); - ALOGD("Setting power mode %d on display %s", mode, to_string(displayId).c_str()); + ALOGD("Setting power mode %d on physical display %s", mode, to_string(displayId).c_str()); const auto currentMode = display->getPowerMode(); if (currentMode == mode) { @@ -5722,16 +5712,15 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: } if (displayId == mActiveDisplayId) { - // TODO: b/281692563 - Merge the syscalls. For now, keep uclamp in a separate syscall - // and set it before SCHED_FIFO due to b/190237315. - constexpr const char* kWhence = "setPowerMode(ON)"; - setSchedAttr(true, kWhence); - setSchedFifo(true, kWhence); + if (FlagManager::getInstance().correct_virtual_display_power_state()) { + applyOptimizationPolicy("setPhysicalDisplayPowerMode(ON)"); + } else { + disablePowerOptimizations("setPhysicalDisplayPowerMode(ON)"); + } } getHwComposer().setPowerMode(displayId, mode); - if (mode != hal::PowerMode::DOZE_SUSPEND && - (displayId == mActiveDisplayId || FlagManager::getInstance().multithreaded_present())) { + if (mode != hal::PowerMode::DOZE_SUSPEND) { const bool enable = mScheduler->getVsyncSchedule(displayId)->getPendingHardwareVsyncState(); requestHardwareVsync(displayId, enable); @@ -5753,19 +5742,18 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: if (const auto display = getActivatableDisplay()) { onActiveDisplayChangedLocked(activeDisplay.get(), *display); } else { - constexpr const char* kWhence = "setPowerMode(OFF)"; - setSchedFifo(false, kWhence); - setSchedAttr(false, kWhence); + if (FlagManager::getInstance().correct_virtual_display_power_state()) { + applyOptimizationPolicy("setPhysicalDisplayPowerMode(OFF)"); + } else { + enablePowerOptimizations("setPhysicalDisplayPowerMode(OFF)"); + } if (currentModeNotDozeSuspend) { - if (!FlagManager::getInstance().multithreaded_present()) { - mScheduler->disableHardwareVsync(displayId, true); - } mScheduler->enableSyntheticVsync(); } } } - if (currentModeNotDozeSuspend && FlagManager::getInstance().multithreaded_present()) { + if (currentModeNotDozeSuspend) { constexpr bool kDisallow = true; mScheduler->disableHardwareVsync(displayId, kDisallow); } @@ -5783,8 +5771,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: } else if (mode == hal::PowerMode::DOZE || mode == hal::PowerMode::ON) { // Update display while dozing getHwComposer().setPowerMode(displayId, mode); - if (currentMode == hal::PowerMode::DOZE_SUSPEND && - (displayId == mActiveDisplayId || FlagManager::getInstance().multithreaded_present())) { + if (currentMode == hal::PowerMode::DOZE_SUSPEND) { if (displayId == mActiveDisplayId) { ALOGI("Force repainting for DOZE_SUSPEND -> DOZE or ON."); mVisibleRegionsDirty = true; @@ -5796,10 +5783,9 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: } } else if (mode == hal::PowerMode::DOZE_SUSPEND) { // Leave display going to doze - if (displayId == mActiveDisplayId || FlagManager::getInstance().multithreaded_present()) { - constexpr bool kDisallow = true; - mScheduler->disableHardwareVsync(displayId, kDisallow); - } + constexpr bool kDisallow = true; + mScheduler->disableHardwareVsync(displayId, kDisallow); + if (displayId == mActiveDisplayId) { mScheduler->enableSyntheticVsync(); } @@ -5816,7 +5802,67 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: mScheduler->setDisplayPowerMode(displayId, mode); - ALOGD("Finished setting power mode %d on display %s", mode, to_string(displayId).c_str()); + ALOGD("Finished setting power mode %d on physical display %s", mode, + to_string(displayId).c_str()); +} + +void SurfaceFlinger::setVirtualDisplayPowerMode(const sp<DisplayDevice>& display, + hal::PowerMode mode) { + if (!display->isVirtual()) { + ALOGE("%s: Invalid operation on physical display", __func__); + return; + } + + const auto displayId = display->getVirtualId(); + ALOGD("Setting power mode %d on virtual display %s %s", mode, to_string(displayId).c_str(), + display->getDisplayName().c_str()); + + display->setPowerMode(static_cast<hal::PowerMode>(mode)); + + applyOptimizationPolicy(__func__); + + ALOGD("Finished setting power mode %d on virtual display %s", mode, + to_string(displayId).c_str()); +} + +bool SurfaceFlinger::shouldOptimizeForPerformance() { + for (const auto& [_, display] : mDisplays) { + // Displays that are optimized for power are always powered on and should not influence + // whether there is an active display for the purpose of power optimization, etc. If these + // displays are being shown somewhere, a different (physical or virtual) display that is + // optimized for performance will be powered on in addition. Displays optimized for + // performance will change power mode, so if they are off then they are not active. + if (display->isPoweredOn() && + display->getOptimizationPolicy() == + gui::ISurfaceComposer::OptimizationPolicy::optimizeForPerformance) { + return true; + } + } + return false; +} + +void SurfaceFlinger::enablePowerOptimizations(const char* whence) { + ALOGD("%s: Enabling power optimizations", whence); + + setSchedAttr(false, whence); + setSchedFifo(false, whence); +} + +void SurfaceFlinger::disablePowerOptimizations(const char* whence) { + ALOGD("%s: Disabling power optimizations", whence); + + // TODO: b/281692563 - Merge the syscalls. For now, keep uclamp in a separate syscall + // and set it before SCHED_FIFO due to b/190237315. + setSchedAttr(true, whence); + setSchedFifo(true, whence); +} + +void SurfaceFlinger::applyOptimizationPolicy(const char* whence) { + if (shouldOptimizeForPerformance()) { + disablePowerOptimizations(whence); + } else { + enablePowerOptimizations(whence); + } } void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) { @@ -5838,15 +5884,14 @@ void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) { ALOGE("Failed to set power mode %d for display token %p", mode, displayToken.get()); } else if (display->isVirtual()) { if (FlagManager::getInstance().correct_virtual_display_power_state()) { - ALOGD("Setting power mode %d on virtual display %s", mode, - display->getDisplayName().c_str()); - display->setPowerMode(static_cast<hal::PowerMode>(mode)); + ftl::FakeGuard guard(mStateLock); + setVirtualDisplayPowerMode(display, static_cast<hal::PowerMode>(mode)); } else { ALOGW("Attempt to set power mode %d for virtual display", mode); } } else { ftl::FakeGuard guard(mStateLock); - setPowerModeInternal(display, static_cast<hal::PowerMode>(mode)); + setPhysicalDisplayPowerMode(display, static_cast<hal::PowerMode>(mode)); } }); @@ -5860,8 +5905,7 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); - if ((uid != AID_SHELL) && - !PermissionCache::checkPermission(sDump, pid, uid)) { + if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) { StringAppendF(&result, "Permission Denial: can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid); write(fd, result.c_str(), result.size()); @@ -6040,17 +6084,14 @@ void SurfaceFlinger::dumpDisplays(std::string& result) const { for (const auto& [token, display] : mDisplays) { if (display->isVirtual()) { - const auto displayId = display->getId(); + const VirtualDisplayId virtualId = display->getVirtualId(); utils::Dumper::Section section(dumper, - ftl::Concat("Virtual Display ", displayId.value).str()); + ftl::Concat("Virtual Display ", virtualId.value).str()); display->dump(dumper); - if (const auto virtualIdOpt = VirtualDisplayId::tryCast(displayId)) { - std::lock_guard lock(mVirtualDisplaysMutex); - const auto virtualSnapshotIt = mVirtualDisplays.find(virtualIdOpt.value()); - if (virtualSnapshotIt != mVirtualDisplays.end()) { - virtualSnapshotIt->second.dump(dumper); - } + std::lock_guard lock(mVirtualDisplaysMutex); + if (const auto snapshotOpt = mVirtualDisplays.get(virtualId)) { + snapshotOpt->get().dump(dumper); } } } @@ -6058,10 +6099,11 @@ void SurfaceFlinger::dumpDisplays(std::string& result) const { void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const { for (const auto& [token, display] : mDisplays) { - const auto displayId = PhysicalDisplayId::tryCast(display->getId()); + const auto displayId = asPhysicalDisplayId(display->getDisplayIdVariant()); if (!displayId) { continue; } + const auto hwcDisplayId = getHwComposer().fromPhysicalDisplayId(*displayId); if (!hwcDisplayId) { continue; @@ -6070,6 +6112,7 @@ void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const { StringAppendF(&result, "Display %s (HWC display %" PRIu64 "): ", to_string(*displayId).c_str(), *hwcDisplayId); + uint8_t port; DisplayIdentificationData data; if (!getHwComposer().getDisplayIdentificationData(*hwcDisplayId, &port, &data)) { @@ -6097,6 +6140,19 @@ void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const { result.append(edid->displayName.data(), edid->displayName.length()); result.append("\"\n"); } + + for (const auto& [token, display] : mDisplays) { + const auto virtualDisplayId = asVirtualDisplayId(display->getDisplayIdVariant()); + if (virtualDisplayId) { + StringAppendF(&result, "Display %s (Virtual display): displayName=\"%s\"", + to_string(*virtualDisplayId).c_str(), display->getDisplayName().c_str()); + std::lock_guard lock(mVirtualDisplaysMutex); + if (const auto snapshotOpt = mVirtualDisplays.get(*virtualDisplayId)) { + StringAppendF(&result, " uniqueId=\"%s\"", snapshotOpt->get().uniqueId().c_str()); + } + result.append("\n"); + } + } } void SurfaceFlinger::dumpRawDisplayIdentificationData(const DumpArgs& args, @@ -6267,7 +6323,7 @@ perfetto::protos::LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t t void SurfaceFlinger::dumpHwcLayersMinidump(std::string& result) const { for (const auto& [token, display] : mDisplays) { - const auto displayId = HalDisplayId::tryCast(display->getId()); + const auto displayId = asHalDisplayId(display->getDisplayIdVariant()); if (!displayId) { continue; } @@ -6307,7 +6363,7 @@ void SurfaceFlinger::dumpAll(const DumpArgs& args, const std::string& compositio // figure out if we're stuck somewhere const nsecs_t now = systemTime(); const nsecs_t inTransaction(mDebugInTransaction); - nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0; + nsecs_t inTransactionDuration = (inTransaction) ? now - inTransaction : 0; /* * Dump library configuration. @@ -6487,7 +6543,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { if (!callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) { IPCThreadState* ipc = IPCThreadState::self(); ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d", - ipc->getCallingPid(), ipc->getCallingUid()); + ipc->getCallingPid(), ipc->getCallingUid()); return PERMISSION_DENIED; } return OK; @@ -6581,9 +6637,9 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { code == IBinder::SYSPROPS_TRANSACTION) { return OK; } - // Numbers from 1000 to 1045 are currently used for backdoors. The code + // Numbers from 1000 to 1047 are currently used for backdoors. The code // in onTransact verifies that the user is root, and has access to use SF. - if (code >= 1000 && code <= 1046) { + if (code >= 1000 && code <= 1047) { ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code); return OK; } @@ -6603,11 +6659,12 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r CHECK_INTERFACE(ISurfaceComposer, data, reply); IPCThreadState* ipc = IPCThreadState::self(); const int uid = ipc->getCallingUid(); - if (CC_UNLIKELY(uid != AID_SYSTEM - && !PermissionCache::checkCallingPermission(sHardwareTest))) { + if (CC_UNLIKELY(uid != AID_SYSTEM && + !PermissionCache::checkCallingPermission(sHardwareTest))) { const int pid = ipc->getCallingPid(); ALOGE("Permission Denial: " - "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); + "can't access SurfaceFlinger pid=%d, uid=%d", + pid, uid); return PERMISSION_DENIED; } int n; @@ -6678,7 +6735,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r n = data.readInt32(); if (n) { // color matrix is sent as a column-major mat4 matrix - for (size_t i = 0 ; i < 4; i++) { + for (size_t i = 0; i < 4; i++) { for (size_t j = 0; j < 4; j++) { mClientColorMatrix[i][j] = data.readFloat(); } @@ -7125,6 +7182,34 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r mScheduler->setDebugPresentDelay(TimePoint::fromNs(ms2ns(jankDelayMs))); return NO_ERROR; } + // Update WorkDuration + // parameters: + // - (required) i64 minSfNs, used as the late.sf WorkDuration. + // - (required) i64 maxSfNs, used as the early.sf and earlyGl.sf WorkDuration. + // - (required) i64 appDurationNs, used as the late.app, early.app and earlyGl.app + // WorkDuration. + // Usage: + // adb shell service call SurfaceFlinger 1047 i64 12333333 i64 16666666 i64 16666666 + case 1047: { + if (!property_get_bool("debug.sf.use_phase_offsets_as_durations", false)) { + ALOGE("Not supported when work duration is not enabled"); + return INVALID_OPERATION; + } + int64_t minSfNs = 0; + int64_t maxSfNs = 0; + int64_t appDurationNs = 0; + if (data.readInt64(&minSfNs) != NO_ERROR || data.readInt64(&maxSfNs) != NO_ERROR || + data.readInt64(&appDurationNs) != NO_ERROR) { + return BAD_VALUE; + } + mScheduler->reloadPhaseConfiguration(mDisplayModeController + .getActiveMode(mActiveDisplayId) + .fps, + Duration::fromNs(minSfNs), + Duration::fromNs(maxSfNs), + Duration::fromNs(appDurationNs)); + return NO_ERROR; + } } } return err; @@ -7198,9 +7283,7 @@ auto SurfaceFlinger::getKernelIdleTimerProperties(PhysicalDisplayId displayId) class WindowDisconnector { public: WindowDisconnector(ANativeWindow* window, int api) : mWindow(window), mApi(api) {} - ~WindowDisconnector() { - native_window_api_disconnect(mWindow, mApi); - } + ~WindowDisconnector() { native_window_api_disconnect(mWindow, mApi); } private: ANativeWindow* mWindow; @@ -7334,7 +7417,7 @@ void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, } wp<const DisplayDevice> displayWeak; - DisplayId displayId; + ftl::Optional<DisplayIdVariant> displayIdVariantOpt; ui::LayerStack layerStack; ui::Size reqSize(args.width, args.height); std::unordered_set<uint32_t> excludeLayerIds; @@ -7350,7 +7433,7 @@ void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, return; } displayWeak = display; - displayId = display->getId(); + displayIdVariantOpt = display->getDisplayIdVariant(); layerStack = display->getLayerStack(); displayIsSecure = display->isSecure(); @@ -7378,7 +7461,7 @@ void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, ScreenshotArgs screenshotArgs; screenshotArgs.captureTypeVariant = displayWeak; - screenshotArgs.displayId = displayId; + screenshotArgs.displayIdVariant = displayIdVariantOpt; screenshotArgs.sourceCrop = gui::aidl_utils::fromARect(captureArgs.sourceCrop); if (screenshotArgs.sourceCrop.isEmpty()) { screenshotArgs.sourceCrop = layerStackSpaceRect; @@ -7397,6 +7480,7 @@ void SurfaceFlinger::captureDisplay(DisplayId displayId, const CaptureArgs& args const sp<IScreenCaptureListener>& captureListener) { ui::LayerStack layerStack; wp<const DisplayDevice> displayWeak; + ftl::Optional<DisplayIdVariant> displayIdVariantOpt; ui::Size size; Rect layerStackSpaceRect; bool displayIsSecure; @@ -7412,6 +7496,7 @@ void SurfaceFlinger::captureDisplay(DisplayId displayId, const CaptureArgs& args } displayWeak = display; + displayIdVariantOpt = display->getDisplayIdVariant(); layerStack = display->getLayerStack(); layerStackSpaceRect = display->getLayerStackSpaceRect(); size = display->getLayerStackSpaceRect().getSize(); @@ -7446,7 +7531,7 @@ void SurfaceFlinger::captureDisplay(DisplayId displayId, const CaptureArgs& args ScreenshotArgs screenshotArgs; screenshotArgs.captureTypeVariant = displayWeak; - screenshotArgs.displayId = displayId; + screenshotArgs.displayIdVariant = displayIdVariantOpt; screenshotArgs.sourceCrop = layerStackSpaceRect; screenshotArgs.reqSize = size; screenshotArgs.dataspace = static_cast<ui::Dataspace>(args.dataspace); @@ -7938,7 +8023,7 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( .layerStack = layerStack, .sourceCrop = args.sourceCrop, .buffer = std::move(buffer), - .displayId = args.displayId, + .displayIdVariant = args.displayIdVariant, .reqBufferSize = args.reqSize, .sdrWhitePointNits = args.sdrWhitePointNits, .displayBrightnessNits = args.displayBrightnessNits, @@ -8309,8 +8394,7 @@ uint32_t SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t ui } int SurfaceFlinger::getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const { - const auto vsyncConfig = - mScheduler->getVsyncConfiguration().getConfigsForRefreshRate(refreshRate).late; + const auto vsyncConfig = mScheduler->getVsyncConfigsForRefreshRate(refreshRate).late; const auto presentLatency = vsyncConfig.appWorkDuration + vsyncConfig.sfWorkDuration; return calculateMaxAcquiredBufferCount(refreshRate, presentLatency); } @@ -8338,8 +8422,8 @@ sp<DisplayDevice> SurfaceFlinger::getActivatableDisplay() const { // TODO(b/255635821): Choose the pacesetter display, considering both internal and external // displays. For now, pick the other internal display, assuming a dual-display foldable. return findDisplay([this](const DisplayDevice& display) REQUIRES(mStateLock) { - const auto idOpt = PhysicalDisplayId::tryCast(display.getId()); - return idOpt && *idOpt != mActiveDisplayId && display.isPoweredOn() && + const auto idOpt = asPhysicalDisplayId(display.getDisplayIdVariant()); + return idOpt.has_value() && *idOpt != mActiveDisplayId && display.isPoweredOn() && mPhysicalDisplays.get(*idOpt) .transform(&PhysicalDisplay::isInternal) .value_or(false); @@ -8876,6 +8960,7 @@ binder::Status SurfaceComposerAIDL::getStaticDisplayInfo(int64_t displayId, if (status == NO_ERROR) { // convert ui::StaticDisplayInfo to gui::StaticDisplayInfo outInfo->connectionType = static_cast<gui::DisplayConnectionType>(info.connectionType); + outInfo->port = info.port; outInfo->density = info.density; outInfo->secure = info.secure; outInfo->installOrientation = static_cast<gui::Rotation>(info.installOrientation); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 39e237b1f9..1a09269545 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -160,6 +160,7 @@ class DisplaySurface; class OutputLayer; struct CompositionRefreshArgs; +class DisplayCreationArgsBuilder; } // namespace compositionengine namespace renderengine { @@ -733,8 +734,24 @@ private: void applyActiveMode(PhysicalDisplayId) REQUIRES(kMainThreadContext); // Called on the main thread in response to setPowerMode() - void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) + void setPhysicalDisplayPowerMode(const sp<DisplayDevice>& display, hal::PowerMode mode) REQUIRES(mStateLock, kMainThreadContext); + void setVirtualDisplayPowerMode(const sp<DisplayDevice>& display, hal::PowerMode mode) + REQUIRES(mStateLock, kMainThreadContext); + + // Returns whether to optimize globally for performance instead of power. + bool shouldOptimizeForPerformance() REQUIRES(mStateLock); + + // Turns on power optimizations, for example when there are no displays to be optimized for + // performance. + static void enablePowerOptimizations(const char* whence); + + // Turns off power optimizations. + static void disablePowerOptimizations(const char* whence); + + // Enables or disables power optimizations depending on whether there are displays that should + // be optimized for performance. + void applyOptimizationPolicy(const char* whence) REQUIRES(mStateLock); // Returns the preferred mode for PhysicalDisplayId if the Scheduler has selected one for that // display. Falls back to the display's defaultModeId otherwise. @@ -875,7 +892,7 @@ private: std::variant<int32_t, wp<const DisplayDevice>> captureTypeVariant; // Display ID of the display the result will be on - std::optional<DisplayId> displayId{std::nullopt}; + ftl::Optional<DisplayIdVariant> displayIdVariant{std::nullopt}; // If true, transform is inverted from the parent layer snapshot bool childrenOnly{false}; @@ -1029,10 +1046,10 @@ private: // region of all screens presenting this layer stack. void invalidateLayerStack(const ui::LayerFilter& layerFilter, const Region& dirty); - ui::LayerFilter makeLayerFilterForDisplay(DisplayId displayId, ui::LayerStack layerStack) + ui::LayerFilter makeLayerFilterForDisplay(DisplayIdVariant displayId, ui::LayerStack layerStack) REQUIRES(mStateLock) { return {layerStack, - PhysicalDisplayId::tryCast(displayId) + asPhysicalDisplayId(displayId) .and_then(display::getPhysicalDisplay(mPhysicalDisplays)) .transform(&display::PhysicalDisplay::isInternal) .value_or(false)}; @@ -1125,8 +1142,10 @@ private: void enableHalVirtualDisplays(bool); // Virtual display lifecycle for ID generation and HAL allocation. - VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat, const std::string& uniqueId) - REQUIRES(mStateLock); + std::optional<VirtualDisplayIdVariant> acquireVirtualDisplay( + ui::Size, ui::PixelFormat, const std::string& uniqueId, + compositionengine::DisplayCreationArgsBuilder&) REQUIRES(mStateLock); + template <typename ID> void acquireVirtualDisplaySnapshot(ID displayId, const std::string& uniqueId) { std::lock_guard lock(mVirtualDisplaysMutex); @@ -1137,7 +1156,7 @@ private: } } - void releaseVirtualDisplay(VirtualDisplayId); + void releaseVirtualDisplay(VirtualDisplayIdVariant displayId); void releaseVirtualDisplaySnapshot(VirtualDisplayId displayId); // Returns a display other than `mActiveDisplayId` that can be activated, if any. @@ -1222,7 +1241,7 @@ private: bool isHdrLayer(const frontend::LayerSnapshot& snapshot) const; - ui::Rotation getPhysicalDisplayOrientation(DisplayId, bool isPrimary) const + ui::Rotation getPhysicalDisplayOrientation(PhysicalDisplayId, bool isPrimary) const REQUIRES(mStateLock); void traverseLegacyLayers(const LayerVector::Visitor& visitor) const REQUIRES(kMainThreadContext); @@ -1445,8 +1464,6 @@ private: // Flag used to set override desired display mode from backdoor bool mDebugDisplayModeSetByBackdoor = false; - // Tracks the number of maximum queued buffers by layer owner Uid. - using BufferStuffingMap = ftl::SmallMap<uid_t, uint32_t, 10>; BufferCountTracker mBufferCountTracker; std::unordered_map<DisplayId, sp<HdrLayerInfoReporter>> mHdrLayerInfoListeners diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp index b22ec66819..2e8c8c1111 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.cpp +++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp @@ -18,7 +18,7 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" -//#define LOG_NDEBUG 0 +// #define LOG_NDEBUG 0 #undef LOG_TAG #define LOG_TAG "TransactionCallbackInvoker" #define ATRACE_TAG ATRACE_TAG_GRAPHICS @@ -28,6 +28,7 @@ #include "Utils/FenceUtils.h" #include <binder/IInterface.h> +#include <common/FlagManager.h> #include <common/trace.h> #include <utils/RefBase.h> @@ -142,8 +143,17 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp<CallbackHandle>& handle->transformHint, handle->currentMaxAcquiredBufferCount, eventStats, handle->previousReleaseCallbackId); + if (handle->bufferReleaseChannel && handle->previousReleaseCallbackId != ReleaseCallbackId::INVALID_ID) { + if (FlagManager::getInstance().monitor_buffer_fences()) { + if (auto previousBuffer = handle->previousBuffer.lock()) { + previousBuffer->getBuffer() + ->getDependencyMonitor() + .addEgress(FenceTime::makeValid(handle->previousReleaseFence), + "Txn release"); + } + } mBufferReleases.emplace_back(handle->name, handle->bufferReleaseChannel, handle->previousReleaseCallbackId, handle->previousReleaseFence, diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h index 178ddbbe79..34f6ffc5da 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.h +++ b/services/surfaceflinger/TransactionCallbackInvoker.h @@ -25,6 +25,7 @@ #include <ftl/future.h> #include <gui/BufferReleaseChannel.h> #include <gui/ITransactionCompletedListener.h> +#include <renderengine/ExternalTexture.h> #include <ui/Fence.h> #include <ui/FenceResult.h> @@ -55,6 +56,7 @@ public: uint64_t previousFrameNumber = 0; ReleaseCallbackId previousReleaseCallbackId = ReleaseCallbackId::INVALID_ID; std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> bufferReleaseChannel; + std::weak_ptr<renderengine::ExternalTexture> previousBuffer; }; class TransactionCallbackInvoker { diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp index 42fa436975..bf1035149b 100644 --- a/services/surfaceflinger/common/FlagManager.cpp +++ b/services/surfaceflinger/common/FlagManager.cpp @@ -129,6 +129,7 @@ void FlagManager::dump(std::string& result) const { DUMP_ACONFIG_FLAG(correct_virtual_display_power_state); DUMP_ACONFIG_FLAG(graphite_renderengine_preview_rollout); DUMP_ACONFIG_FLAG(increase_missed_frame_jank_threshold); + DUMP_ACONFIG_FLAG(monitor_buffer_fences); DUMP_ACONFIG_FLAG(refresh_rate_overlay_on_external_display); DUMP_ACONFIG_FLAG(vsync_predictor_recovery); @@ -164,7 +165,6 @@ void FlagManager::dump(std::string& result) const { DUMP_ACONFIG_FLAG(latch_unsignaled_with_auto_refresh_changed); DUMP_ACONFIG_FLAG(local_tonemap_screenshots); DUMP_ACONFIG_FLAG(misc1); - DUMP_ACONFIG_FLAG(multithreaded_present); DUMP_ACONFIG_FLAG(no_vsyncs_on_screen_off); DUMP_ACONFIG_FLAG(override_trusted_overlay); DUMP_ACONFIG_FLAG(protected_if_client); @@ -259,7 +259,6 @@ FLAG_MANAGER_ACONFIG_FLAG(frame_rate_category_mrr, "debug.sf.frame_rate_category FLAG_MANAGER_ACONFIG_FLAG(misc1, "") FLAG_MANAGER_ACONFIG_FLAG(vrr_config, "debug.sf.enable_vrr_config") FLAG_MANAGER_ACONFIG_FLAG(hdcp_level_hal, "") -FLAG_MANAGER_ACONFIG_FLAG(multithreaded_present, "debug.sf.multithreaded_present") FLAG_MANAGER_ACONFIG_FLAG(add_sf_skipped_frames_to_trace, "") FLAG_MANAGER_ACONFIG_FLAG(use_known_refresh_rate_for_fps_consistency, "") FLAG_MANAGER_ACONFIG_FLAG(cache_when_source_crop_layer_only_moved, @@ -305,6 +304,7 @@ FLAG_MANAGER_ACONFIG_FLAG(adpf_gpu_sf, "") FLAG_MANAGER_ACONFIG_FLAG(adpf_native_session_manager, ""); FLAG_MANAGER_ACONFIG_FLAG(graphite_renderengine_preview_rollout, ""); FLAG_MANAGER_ACONFIG_FLAG(increase_missed_frame_jank_threshold, ""); +FLAG_MANAGER_ACONFIG_FLAG(monitor_buffer_fences, ""); FLAG_MANAGER_ACONFIG_FLAG(vsync_predictor_recovery, ""); /// Trunk stable server (R/W) flags from outside SurfaceFlinger /// diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h index dd7042d8cb..8f361ac610 100644 --- a/services/surfaceflinger/common/include/common/FlagManager.h +++ b/services/surfaceflinger/common/include/common/FlagManager.h @@ -63,6 +63,7 @@ public: bool correct_virtual_display_power_state() const; bool graphite_renderengine_preview_rollout() const; bool increase_missed_frame_jank_threshold() const; + bool monitor_buffer_fences() const; bool refresh_rate_overlay_on_external_display() const; bool vsync_predictor_recovery() const; @@ -99,7 +100,6 @@ public: bool local_tonemap_screenshots() const; bool luts_api() const; bool misc1() const; - bool multithreaded_present() const; bool no_vsyncs_on_screen_off() const; bool override_trusted_overlay() const; bool protected_if_client() const; diff --git a/services/surfaceflinger/surfaceflinger_flags_new.aconfig b/services/surfaceflinger/surfaceflinger_flags_new.aconfig index d8f51fe7e4..d412a19f3c 100644 --- a/services/surfaceflinger/surfaceflinger_flags_new.aconfig +++ b/services/surfaceflinger/surfaceflinger_flags_new.aconfig @@ -216,6 +216,13 @@ flag { } # local_tonemap_screenshots flag { + name: "monitor_buffer_fences" + namespace: "core_graphics" + description: "Monitors fences for each buffer" + bug: "360932099" +} # monitor_buffer_fences + +flag { name: "no_vsyncs_on_screen_off" namespace: "core_graphics" description: "Stop vsync / Choreographer callbacks to apps when the screen is off" diff --git a/services/surfaceflinger/tests/benchmarks/LayerLifecycleManager_benchmarks.cpp b/services/surfaceflinger/tests/benchmarks/LayerLifecycleManager_benchmarks.cpp index 0925118f87..fec6242728 100644 --- a/services/surfaceflinger/tests/benchmarks/LayerLifecycleManager_benchmarks.cpp +++ b/services/surfaceflinger/tests/benchmarks/LayerLifecycleManager_benchmarks.cpp @@ -90,5 +90,46 @@ static void updateClientStatesNoChanges(benchmark::State& state) { } BENCHMARK(updateClientStatesNoChanges); +static void propagateManyHiddenChildren(benchmark::State& state) { + LayerLifecycleManager lifecycleManager; + LayerLifecycleManagerHelper helper(lifecycleManager); + + helper.createRootLayer(0); + for (uint32_t i = 1; i < 50; ++i) { + helper.createLayer(i, i - 1); + } + + helper.hideLayer(0); + + LayerHierarchyBuilder hierarchyBuilder; + DisplayInfo info; + info.info.logicalHeight = 100; + info.info.logicalWidth = 100; + DisplayInfos displayInfos; + displayInfos.emplace_or_replace(ui::LayerStack::fromValue(1), info); + ShadowSettings globalShadowSettings; + + LayerSnapshotBuilder snapshotBuilder; + + int i = 1; + for (auto _ : state) { + i++; + helper.setAlpha(0, (1 + (i % 255)) / 255.0f); + + if (lifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)) { + hierarchyBuilder.update(lifecycleManager); + } + LayerSnapshotBuilder::Args args{.root = hierarchyBuilder.getHierarchy(), + .layerLifecycleManager = lifecycleManager, + .displays = displayInfos, + .globalShadowSettings = globalShadowSettings, + .supportedLayerGenericMetadata = {}, + .genericLayerMetadataKeyMap = {}}; + snapshotBuilder.update(args); + lifecycleManager.commitChanges(); + } +} +BENCHMARK(propagateManyHiddenChildren); + } // namespace } // namespace android::surfaceflinger diff --git a/services/surfaceflinger/tests/end2end/.clang-format b/services/surfaceflinger/tests/end2end/.clang-format new file mode 120000 index 0000000000..5e8e20be26 --- /dev/null +++ b/services/surfaceflinger/tests/end2end/.clang-format @@ -0,0 +1 @@ +../../../../../../build/soong/scripts/system-clang-format
\ No newline at end of file diff --git a/services/surfaceflinger/tests/end2end/.clang-tidy b/services/surfaceflinger/tests/end2end/.clang-tidy new file mode 100644 index 0000000000..29f3b4721c --- /dev/null +++ b/services/surfaceflinger/tests/end2end/.clang-tidy @@ -0,0 +1,380 @@ +# Copyright 2025 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. + +FormatStyle: file +InheritParentConfig: true + +# Please add checks explicitly rather than using wildcards like "modernize-*". +# These check names are current as of LLVM 20.0.0, as reported by "clang-tidy --list-checks --checks=*" +# For more information on each check, see https://clang.llvm.org/extra/clang-tidy/checks/list.html. +Checks: + # from android-* + - android-cloexec-accept + - android-cloexec-accept4 + - android-cloexec-creat + - android-cloexec-dup + - android-cloexec-epoll-create + - android-cloexec-epoll-create1 + - android-cloexec-fopen + - android-cloexec-inotify-init + - android-cloexec-inotify-init1 + - android-cloexec-memfd-create + - android-cloexec-open + - android-cloexec-pipe + - android-cloexec-pipe2 + - android-cloexec-socket + - android-comparison-in-temp-failure-retry + + # from bugprone-* + - bugprone-argument-comment + - bugprone-assert-side-effect + - bugprone-assignment-in-if-condition + - bugprone-bad-signal-to-kill-thread + - bugprone-bool-pointer-implicit-conversion + - bugprone-branch-clone + - bugprone-casting-through-void + - bugprone-chained-comparison + - bugprone-compare-pointer-to-member-virtual-function + - bugprone-copy-constructor-init + - bugprone-crtp-constructor-accessibility + - bugprone-dangling-handle + - bugprone-dynamic-static-initializers + - bugprone-easily-swappable-parameters + - bugprone-empty-catch + - bugprone-exception-escape + - bugprone-fold-init-type + - bugprone-forward-declaration-namespace + - bugprone-forwarding-reference-overload + - bugprone-implicit-widening-of-multiplication-result + - bugprone-inaccurate-erase + - bugprone-inc-dec-in-conditions + - bugprone-incorrect-enable-if + - bugprone-incorrect-roundings + - bugprone-infinite-loop + - bugprone-integer-division + - bugprone-lambda-function-name + - bugprone-macro-parentheses + - bugprone-macro-repeated-side-effects + - bugprone-misplaced-operator-in-strlen-in-alloc + - bugprone-misplaced-pointer-arithmetic-in-alloc + - bugprone-misplaced-widening-cast + - bugprone-move-forwarding-reference + - bugprone-multi-level-implicit-pointer-conversion + - bugprone-multiple-new-in-one-expression + - bugprone-multiple-statement-macro + - bugprone-narrowing-conversions + - bugprone-no-escape + - bugprone-non-zero-enum-to-bool-conversion + - bugprone-not-null-terminated-result + - bugprone-optional-value-conversion + - bugprone-parent-virtual-call + - bugprone-pointer-arithmetic-on-polymorphic-object + - bugprone-posix-return + - bugprone-redundant-branch-condition + - bugprone-reserved-identifier + - bugprone-return-const-ref-from-parameter + - bugprone-shared-ptr-array-mismatch + - bugprone-signal-handler + - bugprone-signed-char-misuse + - bugprone-sizeof-container + - bugprone-sizeof-expression + - bugprone-spuriously-wake-up-functions + - bugprone-standalone-empty + - bugprone-string-constructor + - bugprone-string-integer-assignment + - bugprone-string-literal-with-embedded-nul + - bugprone-stringview-nullptr + - bugprone-suspicious-enum-usage + - bugprone-suspicious-include + - bugprone-suspicious-memory-comparison + - bugprone-suspicious-memset-usage + - bugprone-suspicious-missing-comma + - bugprone-suspicious-realloc-usage + - bugprone-suspicious-semicolon + - bugprone-suspicious-string-compare + - bugprone-suspicious-stringview-data-usage + - bugprone-swapped-arguments + - bugprone-switch-missing-default-case + - bugprone-terminating-continue + - bugprone-throw-keyword-missing + - bugprone-too-small-loop-variable + - bugprone-unchecked-optional-access + - bugprone-undefined-memory-manipulation + - bugprone-undelegated-constructor + - bugprone-unhandled-exception-at-new + - bugprone-unhandled-self-assignment + - bugprone-unique-ptr-array-mismatch + - bugprone-unsafe-functions + - bugprone-unused-local-non-trivial-variable + - bugprone-unused-raii + - bugprone-unused-return-value + - bugprone-use-after-move + - bugprone-virtual-near-miss + + # from cert-* + - cert-con36-c + - cert-con54-cpp + - cert-ctr56-cpp + - cert-dcl03-c + - cert-dcl16-c + - cert-dcl37-c + - cert-dcl50-cpp + - cert-dcl51-cpp + - cert-dcl54-cpp + - cert-dcl58-cpp + - cert-dcl59-cpp + - cert-env33-c + - cert-err09-cpp + - cert-err33-c + - cert-err34-c + - cert-err52-cpp + - cert-err58-cpp + - cert-err60-cpp + - cert-err61-cpp + - cert-exp42-c + - cert-fio38-c + - cert-flp30-c + - cert-flp37-c + - cert-int09-c + - cert-mem57-cpp + - cert-msc24-c + - cert-msc30-c + - cert-msc32-c + - cert-msc33-c + - cert-msc50-cpp + - cert-msc51-cpp + - cert-msc54-cpp + - cert-oop11-cpp + - cert-oop54-cpp + - cert-oop57-cpp + - cert-oop58-cpp + - cert-pos44-c + - cert-pos47-c + - cert-sig30-c + - cert-str34-c + + # from concurrency-* + - concurrency-mt-unsafe + - concurrency-thread-canceltype-asynchronous + + # from cppcoreguidelines-* + - cppcoreguidelines-avoid-c-arrays + - cppcoreguidelines-avoid-capturing-lambda-coroutines + - cppcoreguidelines-avoid-const-or-ref-data-members + - cppcoreguidelines-avoid-do-while + - cppcoreguidelines-avoid-goto + - cppcoreguidelines-avoid-magic-numbers + - cppcoreguidelines-avoid-non-const-global-variables + - cppcoreguidelines-avoid-reference-coroutine-parameters + - cppcoreguidelines-c-copy-assignment-signature + - cppcoreguidelines-explicit-virtual-functions + - cppcoreguidelines-init-variables + - cppcoreguidelines-interfaces-global-init + - cppcoreguidelines-macro-to-enum + - cppcoreguidelines-macro-usage + - cppcoreguidelines-misleading-capture-default-by-value + - cppcoreguidelines-missing-std-forward + - cppcoreguidelines-narrowing-conversions + - cppcoreguidelines-no-malloc + - cppcoreguidelines-no-suspend-with-lock + - cppcoreguidelines-noexcept-destructor + - cppcoreguidelines-noexcept-move-operations + - cppcoreguidelines-noexcept-swap + - cppcoreguidelines-non-private-member-variables-in-classes + - cppcoreguidelines-owning-memory + - cppcoreguidelines-prefer-member-initializer + - cppcoreguidelines-pro-bounds-array-to-pointer-decay + - cppcoreguidelines-pro-bounds-constant-array-index + - cppcoreguidelines-pro-bounds-pointer-arithmetic + - cppcoreguidelines-pro-type-const-cast + - cppcoreguidelines-pro-type-cstyle-cast + - cppcoreguidelines-pro-type-member-init + - cppcoreguidelines-pro-type-reinterpret-cast + - cppcoreguidelines-pro-type-static-cast-downcast + - cppcoreguidelines-pro-type-union-access + - cppcoreguidelines-pro-type-vararg + - cppcoreguidelines-rvalue-reference-param-not-moved + - cppcoreguidelines-slicing + - cppcoreguidelines-special-member-functions + - cppcoreguidelines-use-default-member-init + - cppcoreguidelines-virtual-class-destructor + + # from google-* + - google-build-explicit-make-pair + - google-build-namespaces + - google-build-using-namespace + - google-default-arguments + - google-explicit-constructor + - google-global-names-in-headers + - google-objc-avoid-nsobject-new + - google-objc-avoid-throwing-exception + - google-objc-function-naming + - google-objc-global-variable-declaration + - google-readability-avoid-underscore-in-googletest-name + - google-readability-braces-around-statements + - google-readability-casting + - google-readability-function-size + - google-readability-namespace-comments + - google-readability-todo + - google-runtime-int + - google-runtime-operator + - google-upgrade-googletest-case + + # from misc-* + - misc-confusable-identifiers + - misc-const-correctness + - misc-coroutine-hostile-raii + - misc-definitions-in-headers + - misc-header-include-cycle + - misc-include-cleaner + - misc-misleading-bidirectional + - misc-misleading-identifier + - misc-misplaced-const + - misc-new-delete-overloads + - misc-no-recursion + - misc-non-copyable-objects + - misc-non-private-member-variables-in-classes + - misc-redundant-expression + - misc-static-assert + - misc-throw-by-value-catch-by-reference + - misc-unconventional-assign-operator + - misc-uniqueptr-reset-release + - misc-unused-alias-decls + - misc-unused-parameters + - misc-unused-using-decls + - misc-use-anonymous-namespace + - misc-use-internal-linkage + + # from modernize-* + - modernize-avoid-bind + - modernize-avoid-c-arrays + - modernize-concat-nested-namespaces + - modernize-deprecated-headers + - modernize-deprecated-ios-base-aliases + - modernize-loop-convert + - modernize-macro-to-enum + - modernize-make-shared + - modernize-make-unique + - modernize-min-max-use-initializer-list + - modernize-pass-by-value + - modernize-raw-string-literal + - modernize-redundant-void-arg + - modernize-replace-auto-ptr + - modernize-replace-disallow-copy-and-assign-macro + - modernize-replace-random-shuffle + - modernize-return-braced-init-list + - modernize-shrink-to-fit + - modernize-type-traits + - modernize-unary-static-assert + - modernize-use-auto + - modernize-use-bool-literals + - modernize-use-constraints + - modernize-use-default-member-init + - modernize-use-designated-initializers + - modernize-use-emplace + - modernize-use-equals-default + - modernize-use-equals-delete + - modernize-use-nodiscard + - modernize-use-noexcept + - modernize-use-nullptr + - modernize-use-override + - modernize-use-ranges + - modernize-use-starts-ends-with + - modernize-use-std-format + - modernize-use-std-numbers + - modernize-use-std-print + - modernize-use-trailing-return-type + - modernize-use-transparent-functors + - modernize-use-uncaught-exceptions + - modernize-use-using + + # from performance-* + - performance-avoid-endl + - performance-enum-size + - performance-faster-string-find + - performance-for-range-copy + - performance-implicit-conversion-in-loop + - performance-inefficient-algorithm + - performance-inefficient-string-concatenation + - performance-inefficient-vector-operation + - performance-move-const-arg + - performance-move-constructor-init + - performance-no-automatic-move + - performance-no-int-to-ptr + - performance-noexcept-destructor + - performance-noexcept-move-constructor + - performance-noexcept-swap + - performance-trivially-destructible + - performance-type-promotion-in-math-fn + - performance-unnecessary-copy-initialization + - performance-unnecessary-value-param + + # from portability-* + - portability-restrict-system-includes + - portability-simd-intrinsics + - portability-std-allocator-const + + # from readability-* + - readability-avoid-const-params-in-decls + - readability-avoid-nested-conditional-operator + - readability-avoid-return-with-void-value + - readability-avoid-unconditional-preprocessor-if + - readability-braces-around-statements + - readability-const-return-type + - readability-container-contains + - readability-container-data-pointer + - readability-container-size-empty + - readability-convert-member-functions-to-static + - readability-delete-null-pointer + - readability-duplicate-include + - readability-else-after-return + - readability-enum-initial-value + - readability-function-cognitive-complexity + - readability-function-size + - readability-identifier-length + - readability-identifier-naming + - readability-implicit-bool-conversion + - readability-inconsistent-declaration-parameter-name + - readability-isolate-declaration + - readability-magic-numbers + - readability-make-member-function-const + - readability-math-missing-parentheses + - readability-misleading-indentation + - readability-misplaced-array-index + - readability-named-parameter + - readability-non-const-parameter + - readability-operators-representation + - readability-qualified-auto + - readability-redundant-access-specifiers + - readability-redundant-casting + - readability-redundant-control-flow + - readability-redundant-declaration + - readability-redundant-function-ptr-dereference + - readability-redundant-inline-specifier + - readability-redundant-member-init + - readability-redundant-preprocessor + - readability-redundant-smartptr-get + - readability-redundant-string-cstr + - readability-redundant-string-init + - readability-reference-to-constructed-temporary + - readability-simplify-boolean-expr + - readability-simplify-subscript-expr + - readability-static-accessed-through-instance + - readability-static-definition-in-anonymous-namespace + - readability-string-compare + - readability-suspicious-call-argument + - readability-uniqueptr-delete-release + - readability-uppercase-literal-suffix + - readability-use-anyofallof + - readability-use-std-min-max diff --git a/services/surfaceflinger/tests/end2end/.clangd b/services/surfaceflinger/tests/end2end/.clangd new file mode 100644 index 0000000000..d64d2f8a55 --- /dev/null +++ b/services/surfaceflinger/tests/end2end/.clangd @@ -0,0 +1,20 @@ +# Copyright 2025 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. + +Diagnostics: + UnusedIncludes: Strict + MissingIncludes: Strict + ClangTidy: + FastCheckFilter: None + # See the .clang-tidy files for additional configuration diff --git a/services/surfaceflinger/tests/end2end/Android.bp b/services/surfaceflinger/tests/end2end/Android.bp new file mode 100644 index 0000000000..8810330179 --- /dev/null +++ b/services/surfaceflinger/tests/end2end/Android.bp @@ -0,0 +1,68 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + +cc_test { + name: "surfaceflinger_end2end_tests", + test_suites: ["device-tests"], + require_root: true, + + cpp_std: "experimental", + cflags: [ + "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION", + "-DNODISCARD_EXPECTED", + "-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS", + "-Wall", + "-Wconversion", + "-Werror", + "-Wextra", + "-Wformat", + "-Wno-non-virtual-dtor", + "-Wno-sign-compare", + "-Wno-sign-conversion", + "-Wshadow", + "-Wthread-safety", + "-Wunreachable-code", + "-Wunused", + ], + srcs: [ + "main.cpp", + "test_framework/core/TestService.cpp", + "test_framework/fake_hwc3/Hwc3Composer.cpp", + "test_framework/fake_hwc3/Hwc3Controller.cpp", + "test_framework/surfaceflinger/SFController.cpp", + "tests/Placeholder_test.cpp", + ], + tidy: true, + tidy_flags: [ + "--config=", // Use the .clang-tidy closest to each source file for the configuration + ], + tidy_checks_as_errors: [ + "*", + ], + include_dirs: [ + "frameworks/native/include", + ], + local_include_dirs: ["."], + shared_libs: [ + "libbase", + "libbinder", + "libbinder_ndk", + "libcutils", + "libgui", + "libsync", + "libui", + "libutils", + ], + static_libs: [ + "android.hardware.common-V2-ndk", + "android.hardware.graphics.common-V6-ndk", + "android.hardware.graphics.composer3-V3-ndk", + "libgtest", + ], +} diff --git a/services/surfaceflinger/tests/end2end/AndroidTest.xml b/services/surfaceflinger/tests/end2end/AndroidTest.xml new file mode 100644 index 0000000000..99cb7b3fee --- /dev/null +++ b/services/surfaceflinger/tests/end2end/AndroidTest.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2025 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="Configuration for surfaceflinger_end2end_tests"> + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" /> + <target_preparer class="com.android.tradefed.targetprep.DisableSELinuxTargetPreparer" /> + <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> + <!-- Stop everything to run SurfaceFlinger in isolation, with relaxed SELinux permissions --> + <option name="teardown-command" value="stop" /> + <option name="teardown-command" value="setprop debug.sf.nobootanimation 1" /> + + <!-- Restart everything with normal settings after the test finishes. --> + <option name="teardown-command" value="stop" /> + <option name="teardown-command" value="setprop debug.sf.nobootanimation 0" /> + <option name="teardown-command" value="setprop debug.sf.hwc_service_name default" /> + <option name="teardown-command" value="start" /> + </target_preparer> + <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher"> + <option name="cleanup" value="true" /> + <option name="push" value="surfaceflinger_end2end_tests->/data/local/tests/surfaceflinger_end2end_tests" /> + </target_preparer> + <test class="com.android.tradefed.testtype.GTest" > + <option name="native-test-device-path" value="/data/local/tests" /> + <option name="module-name" value="surfaceflinger_end2end_tests" /> + <option name="native-test-timeout" value="15m"/> + </test> +</configuration> diff --git a/services/surfaceflinger/tests/end2end/README.md b/services/surfaceflinger/tests/end2end/README.md new file mode 100644 index 0000000000..2f58cec5c7 --- /dev/null +++ b/services/surfaceflinger/tests/end2end/README.md @@ -0,0 +1,75 @@ +# `surfaceflinger_end2end_tests` + +Tests to cover end to end testing of SurfaceFlinger. + +In particular the test framework allows you to simulate various display +configurations, so the test can confirm displays are handled correctly. + +## Quick Useful info + +### Running the tests + +At present the tests should run on any target, though the typical target would +be a [Cuttlefish](https://source.android.com/docs/devices/cuttlefish) VM +target such as `aosp_cf_x86_64_phone`. + +At some future time the test may be rewritten to require +[`vkms`](https://dri.freedesktop.org/docs/drm/gpu/vkms.html) and +[`drm_hwcomposer`](https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer) + +``` +atest surfaceflinger_end2end_tests +``` + +You can also run the google test binary directly. However you will also need +to run a few other set-up and tear-down commands that are part of the +AndroidTest.xml configuration, so that SurfaceFlinger can be used run isolation +from the rest of the system. + +``` +# Set-up +adb root +adb shell stop +adb shell setenforce 0 +adb shell setprop debug.sf.nobootanimation 1 + +# Sync and run the test +adb sync data +adb shell data/nativetest64/surfaceflinger_end2end_tests/surfaceflinger_end2end_tests + +# Tear-down +adb shell stop +adb shell setenforce 1 +adb shell setprop debug.sf.nobootanimation 0 +adb shell setprop debug.sf.hwc_service_name default +``` + +### Manual clang-tidy checks via Soong + +At present Android does not run the clang-tidy checks as part of its +presubmit checks. + +You can run them through the build system by using phony target that are +automatically created for each source subdirectory. + +For the code under `frameworks/native/services/surfaceflinger/tests/end2end`, +you would build: + +``` +m tidy-frameworks-native-services-surfaceflinger-tests-end2end +``` + +For more information see the build documentation: + +* <https://android.googlesource.com/platform/build/soong/+/main/docs/tidy.md#the-tidy_directory-targets> + +### Seeing clang-tidy checks in your editor + +If your editor supports using [`clangd`](https://clangd.llvm.org/) as a +C++ language server, you can build and export a compilation database using +Soong. With the local `.clangd` configuration file, you should see the same +checks in editor, along with all the other checks `clangd` runs. + +See the build documentation for the compilation database instructions: + +https://android.googlesource.com/platform/build/soong/+/main/docs/compdb.md diff --git a/services/surfaceflinger/tests/end2end/main.cpp b/services/surfaceflinger/tests/end2end/main.cpp new file mode 100644 index 0000000000..ddf690021d --- /dev/null +++ b/services/surfaceflinger/tests/end2end/main.cpp @@ -0,0 +1,55 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <cstdlib> +#include <string_view> + +#include <android-base/logging.h> +#include <android/binder_process.h> +#include <gtest/gtest.h> + +namespace { + +void init(int argc, char** argv) { + using namespace std::string_view_literals; + + ::testing::InitGoogleTest(&argc, argv); + ::android::base::InitLogging(argv, android::base::StderrLogger); + + auto minimumSeverity = android::base::INFO; + for (int i = 1; i < argc; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + const std::string_view arg = argv[i]; + + if (arg == "-v"sv) { + minimumSeverity = android::base::DEBUG; + } else if (arg == "-vv"sv) { + minimumSeverity = android::base::VERBOSE; + } + } + ::android::base::SetMinimumLogSeverity(minimumSeverity); +} + +} // namespace + +auto main(int argc, char** argv) -> int { + init(argc, argv); + + ABinderProcess_setThreadPoolMaxThreadCount(1); + ABinderProcess_startThreadPool(); + + return RUN_ALL_TESTS(); +}
\ No newline at end of file diff --git a/services/surfaceflinger/tests/end2end/test_framework/core/DisplayConfiguration.h b/services/surfaceflinger/tests/end2end/test_framework/core/DisplayConfiguration.h new file mode 100644 index 0000000000..c3a535e10f --- /dev/null +++ b/services/surfaceflinger/tests/end2end/test_framework/core/DisplayConfiguration.h @@ -0,0 +1,29 @@ +/* + * Copyright 2025 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 <cstdint> + +namespace android::surfaceflinger::tests::end2end::test_framework::core { + +struct DisplayConfiguration final { + using Id = int64_t; + + Id id{}; +}; + +} // namespace android::surfaceflinger::tests::end2end::test_framework::core diff --git a/services/surfaceflinger/tests/end2end/test_framework/core/TestService.cpp b/services/surfaceflinger/tests/end2end/test_framework/core/TestService.cpp new file mode 100644 index 0000000000..0531f18527 --- /dev/null +++ b/services/surfaceflinger/tests/end2end/test_framework/core/TestService.cpp @@ -0,0 +1,82 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <memory> +#include <span> +#include <string> +#include <utility> +#include <vector> + +#include <android-base/expected.h> +#include <ftl/ignore.h> + +#include "test_framework/core/DisplayConfiguration.h" +#include "test_framework/core/TestService.h" +#include "test_framework/fake_hwc3/Hwc3Controller.h" +#include "test_framework/surfaceflinger/SFController.h" + +namespace android::surfaceflinger::tests::end2end::test_framework::core { + +struct TestService::Passkey final {}; + +auto TestService::startWithDisplays(const std::vector<DisplayConfiguration>& displays) + -> base::expected<std::unique_ptr<TestService>, std::string> { + using namespace std::string_literals; + + auto service = std::make_unique<TestService>(TestService::Passkey{}); + if (service == nullptr) { + return base::unexpected("Failed to construct the TestService instance."s); + } + + if (auto result = service->init(displays); !result) { + return base::unexpected("Failed to init the TestService instance: "s + result.error()); + } + + return service; +} + +TestService::TestService(Passkey passkey) { + ftl::ignore(passkey); +} + +auto TestService::init(std::span<const DisplayConfiguration> displays) + -> base::expected<void, std::string> { + using namespace std::string_literals; + + auto hwcResult = fake_hwc3::Hwc3Controller::make(displays); + if (!hwcResult) { + return base::unexpected(std::move(hwcResult).error()); + } + auto hwc = *std::move(hwcResult); + + auto flingerResult = surfaceflinger::SFController::make(); + if (!flingerResult) { + return base::unexpected(std::move(flingerResult).error()); + } + auto flinger = *std::move(flingerResult); + + surfaceflinger::SFController::useHwcService(fake_hwc3::Hwc3Controller::getServiceName()); + + if (auto result = flinger->startAndConnect(); !result) { + return base::unexpected(std::move(result).error()); + } + + mHwc = std::move(hwc); + mFlinger = std::move(flinger); + return {}; +} + +} // namespace android::surfaceflinger::tests::end2end::test_framework::core diff --git a/services/surfaceflinger/tests/end2end/test_framework/core/TestService.h b/services/surfaceflinger/tests/end2end/test_framework/core/TestService.h new file mode 100644 index 0000000000..21e6426406 --- /dev/null +++ b/services/surfaceflinger/tests/end2end/test_framework/core/TestService.h @@ -0,0 +1,76 @@ +/* + * Copyright 2025 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 <memory> +#include <span> +#include <string> +#include <vector> + +#include <android-base/expected.h> +#include <android-base/logging.h> + +#include "test_framework/core/DisplayConfiguration.h" + +namespace android::surfaceflinger::tests::end2end::test_framework { + +namespace surfaceflinger { + +class SFController; + +} // namespace surfaceflinger + +namespace fake_hwc3 { + +class Hwc3Controller; + +} // namespace fake_hwc3 + +namespace core { + +class TestService final { + struct Passkey; // Uses the passkey idiom to restrict construction. + + public: + // Constructs the test service, and starts it with the given displays as connected at boot. + [[nodiscard]] static auto startWithDisplays(const std::vector<DisplayConfiguration>& displays) + -> base::expected<std::unique_ptr<TestService>, std::string>; + + explicit TestService(Passkey passkey); + + // Obtains the HWC3 back-end controller + [[nodiscard]] auto hwc() -> fake_hwc3::Hwc3Controller& { + CHECK(mHwc); + return *mHwc; + } + + // Obtains the SurfaceFlinger front-end controller + [[nodiscard]] auto flinger() -> surfaceflinger::SFController& { + CHECK(mFlinger); + return *mFlinger; + } + + private: + [[nodiscard]] auto init(std::span<const DisplayConfiguration> displays) + -> base::expected<void, std::string>; + + std::shared_ptr<fake_hwc3::Hwc3Controller> mHwc; + std::shared_ptr<surfaceflinger::SFController> mFlinger; +}; + +} // namespace core +} // namespace android::surfaceflinger::tests::end2end::test_framework diff --git a/services/surfaceflinger/tests/end2end/test_framework/fake_hwc3/Hwc3Composer.cpp b/services/surfaceflinger/tests/end2end/test_framework/fake_hwc3/Hwc3Composer.cpp new file mode 100644 index 0000000000..5349ef0b58 --- /dev/null +++ b/services/surfaceflinger/tests/end2end/test_framework/fake_hwc3/Hwc3Composer.cpp @@ -0,0 +1,123 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <cstdint> +#include <memory> +#include <string> +#include <string_view> +#include <utility> +#include <vector> + +#include <aidl/android/hardware/graphics/composer3/BnComposer.h> +#include <aidl/android/hardware/graphics/composer3/Capability.h> +#include <aidl/android/hardware/graphics/composer3/IComposer.h> +#include <aidl/android/hardware/graphics/composer3/PowerMode.h> + +#include <android-base/expected.h> +#include <android-base/logging.h> +#include <android/binder_auto_utils.h> +#include <android/binder_interface_utils.h> +#include <android/binder_status.h> +#include <ftl/ignore.h> + +#include "test_framework/core/DisplayConfiguration.h" +#include "test_framework/fake_hwc3/Hwc3Composer.h" + +namespace android::surfaceflinger::tests::end2end::test_framework::fake_hwc3 { + +class Hwc3Composer::Hwc3ComposerImpl final + : public aidl::android::hardware::graphics::composer3::BnComposer { + using Capability = aidl::android::hardware::graphics::composer3::Capability; + using IComposerClient = aidl::android::hardware::graphics::composer3::IComposerClient; + using Hwc3PowerMode = aidl::android::hardware::graphics::composer3::PowerMode; + + // begin IComposer overrides + + auto dump(int dumpFd, const char** args, uint32_t num_args) -> binder_status_t override { + UNIMPLEMENTED(WARNING); + ftl::ignore(dumpFd, args, num_args); + return static_cast<binder_status_t>(STATUS_NO_MEMORY); + } + + auto createClient(std::shared_ptr<IComposerClient>* out_client) -> ndk::ScopedAStatus override { + UNIMPLEMENTED(WARNING); + ftl::ignore(out_client); + return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage( + IComposer::EX_NO_RESOURCES, "Client failed to initialize"); + } + + auto getCapabilities(std::vector<Capability>* out_capabilities) -> ndk::ScopedAStatus override { + UNIMPLEMENTED(WARNING); + ftl::ignore(out_capabilities); + return ndk::ScopedAStatus::ok(); + } + + // end IComposer overrides +}; + +struct Hwc3Composer::Passkey final {}; + +auto Hwc3Composer::getServiceName(std::string_view baseServiceName) -> std::string { + return Hwc3ComposerImpl::makeServiceName(baseServiceName); +} + +auto Hwc3Composer::make() -> base::expected<std::shared_ptr<Hwc3Composer>, std::string> { + using namespace std::string_literals; + + auto composer = std::make_shared<Hwc3Composer>(Passkey{}); + if (composer == nullptr) { + return base::unexpected("Failed to construct the Hwc3Composer instance."s); + } + + if (auto result = composer->init(); !result) { + return base::unexpected("Failed to init the Hwc3Composer instance: "s + result.error()); + } + + return composer; +} + +Hwc3Composer::Hwc3Composer(Hwc3Composer::Passkey passkey) { + ftl::ignore(passkey); +} + +auto Hwc3Composer::init() -> base::expected<void, std::string> { + using namespace std::string_literals; + + auto impl = ndk::SharedRefBase::make<Hwc3ComposerImpl>(); + if (!impl) { + return base::unexpected("Failed to construct the Hwc3ComposerImpl instance."s); + } + + mImpl = std::move(impl); + + return {}; +} + +auto Hwc3Composer::getComposer() -> std::shared_ptr<Hwc3IComposer> { + return mImpl; +} + +void Hwc3Composer::addDisplay(const core::DisplayConfiguration& display) { + UNIMPLEMENTED(WARNING); + ftl::ignore(display, mImpl); +} + +void Hwc3Composer::removeDisplay(core::DisplayConfiguration::Id displayId) { + UNIMPLEMENTED(WARNING); + ftl::ignore(displayId, mImpl); +} + +} // namespace android::surfaceflinger::tests::end2end::test_framework::fake_hwc3 diff --git a/services/surfaceflinger/tests/end2end/test_framework/fake_hwc3/Hwc3Composer.h b/services/surfaceflinger/tests/end2end/test_framework/fake_hwc3/Hwc3Composer.h new file mode 100644 index 0000000000..6d6b7374c6 --- /dev/null +++ b/services/surfaceflinger/tests/end2end/test_framework/fake_hwc3/Hwc3Composer.h @@ -0,0 +1,61 @@ +/* + * Copyright 2025 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 <memory> +#include <string> +#include <string_view> + +#include <aidl/android/hardware/graphics/composer3/IComposer.h> +#include <android-base/expected.h> + +#include "test_framework/core/DisplayConfiguration.h" + +namespace android::surfaceflinger::tests::end2end::test_framework::fake_hwc3 { + +class Hwc3Composer final { + struct Passkey; // Uses the passkey idiom to restrict construction. + + class Hwc3ComposerImpl; // An internal class implements the AIDL interface. + + public: + using Hwc3IComposer = aidl::android::hardware::graphics::composer3::IComposer; + + // Gets the full qualified service name given a base name for the service. + [[nodiscard]] static auto getServiceName(std::string_view baseServiceName) -> std::string; + + // Constructs a Hwc3Composer instance. + [[nodiscard]] static auto make() -> base::expected<std::shared_ptr<Hwc3Composer>, std::string>; + + explicit Hwc3Composer(Passkey passkey); + + // Obtains the AIDL composer3::IComposer interface for the internal instance. + [[nodiscard]] auto getComposer() -> std::shared_ptr<Hwc3IComposer>; + + // Adds a display to the composer. This will sent a hotplug connect event. + void addDisplay(const core::DisplayConfiguration& display); + + // Removes a display from the composer. This will sent a hotplug disconnect event. + void removeDisplay(core::DisplayConfiguration::Id displayId); + + private: + [[nodiscard]] auto init() -> base::expected<void, std::string>; + + std::shared_ptr<Hwc3ComposerImpl> mImpl; +}; + +} // namespace android::surfaceflinger::tests::end2end::test_framework::fake_hwc3 diff --git a/services/surfaceflinger/tests/end2end/test_framework/fake_hwc3/Hwc3Controller.cpp b/services/surfaceflinger/tests/end2end/test_framework/fake_hwc3/Hwc3Controller.cpp new file mode 100644 index 0000000000..ea985c09b4 --- /dev/null +++ b/services/surfaceflinger/tests/end2end/test_framework/fake_hwc3/Hwc3Controller.cpp @@ -0,0 +1,106 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <memory> +#include <span> +#include <string> +#include <utility> + +#include <android-base/expected.h> +#include <android-base/logging.h> +#include <android/binder_manager.h> +#include <android/binder_stability.h> +#include <android/binder_status.h> +#include <fmt/format.h> +#include <ftl/ignore.h> + +#include "test_framework/core/DisplayConfiguration.h" +#include "test_framework/fake_hwc3/Hwc3Composer.h" +#include "test_framework/fake_hwc3/Hwc3Controller.h" + +namespace android::surfaceflinger::tests::end2end::test_framework::fake_hwc3 { + +struct Hwc3Controller::Passkey final {}; + +auto Hwc3Controller::make(std::span<const core::DisplayConfiguration> displays) + -> base::expected<std::shared_ptr<fake_hwc3::Hwc3Controller>, std::string> { + using namespace std::string_literals; + + auto controller = std::make_unique<Hwc3Controller>(Passkey{}); + if (controller == nullptr) { + return base::unexpected("Failed to construct the Hwc3Controller instance"s); + } + + if (auto result = controller->init(displays); !result) { + return base::unexpected("Failed to construct the Hwc3Controller instance: "s + + result.error()); + } + + return controller; +} + +Hwc3Controller::Hwc3Controller(Passkey passkey) { + ftl::ignore(passkey); +} + +auto Hwc3Controller::init(const std::span<const core::DisplayConfiguration> displays) + -> base::expected<void, std::string> { + using namespace std::string_literals; + + auto qualifiedServiceName = Hwc3Composer::getServiceName(baseServiceName); + + auto composerResult = Hwc3Composer::make(); + if (!composerResult) { + return base::unexpected(std::move(composerResult).error()); + } + auto composer = *std::move(composerResult); + + for (const auto& display : displays) { + composer->addDisplay(display); + } + + auto binder = composer->getComposer()->asBinder(); + + // This downgrade allows us to use the fake service name without it being defined in the + // VINTF manifest. + AIBinder_forceDowngradeToLocalStability(binder.get()); + + auto status = AServiceManager_addService(binder.get(), qualifiedServiceName.c_str()); + if (status != STATUS_OK) { + return base::unexpected(fmt::format("Failed to register service {}. Error {}.", + qualifiedServiceName, status)); + } + LOG(INFO) << "Registered service " << qualifiedServiceName << ". Error: " << status; + + mComposer = std::move(composer); + return {}; +} + +auto Hwc3Controller::getServiceName() -> std::string { + return Hwc3Composer::getServiceName(baseServiceName); +} + +void Hwc3Controller::addDisplay(const core::DisplayConfiguration& config) { + CHECK(mComposer); + mComposer->addDisplay(config); +} + +void Hwc3Controller::removeDisplay(core::DisplayConfiguration::Id displayId) { + CHECK(mComposer); + mComposer->removeDisplay(displayId); +} + +} // namespace android::surfaceflinger::tests::end2end::test_framework::fake_hwc3 diff --git a/services/surfaceflinger/tests/end2end/test_framework/fake_hwc3/Hwc3Controller.h b/services/surfaceflinger/tests/end2end/test_framework/fake_hwc3/Hwc3Controller.h new file mode 100644 index 0000000000..e53d2cfc48 --- /dev/null +++ b/services/surfaceflinger/tests/end2end/test_framework/fake_hwc3/Hwc3Controller.h @@ -0,0 +1,59 @@ +/* + * Copyright 2025 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 <memory> +#include <span> +#include <string> + +#include <android-base/expected.h> + +#include "test_framework/core/DisplayConfiguration.h" + +namespace android::surfaceflinger::tests::end2end::test_framework::fake_hwc3 { + +class Hwc3Composer; + +class Hwc3Controller final { + struct Passkey; // Uses the passkey idiom to restrict construction. + + public: + // Gets the service name for the HWC3 instance that will be created and registered + [[nodiscard]] static auto getServiceName() -> std::string; + + // Makes the HWC3 controller instance. + [[nodiscard]] static auto make(std::span<const core::DisplayConfiguration> displays) + -> base::expected<std::shared_ptr<fake_hwc3::Hwc3Controller>, std::string>; + + explicit Hwc3Controller(Passkey passkey); + + // Adds a new display to the HWC3, which will become a hotplug connect event. + void addDisplay(const core::DisplayConfiguration& config); + + // Removes a new display from the HWC3, which will become a hotplug disconnect event. + void removeDisplay(core::DisplayConfiguration::Id displayId); + + private: + static constexpr std::string baseServiceName = "fake"; + + [[nodiscard]] auto init(std::span<const core::DisplayConfiguration> displays) + -> base::expected<void, std::string>; + + std::shared_ptr<Hwc3Composer> mComposer; +}; + +} // namespace android::surfaceflinger::tests::end2end::test_framework::fake_hwc3 diff --git a/services/surfaceflinger/tests/end2end/test_framework/surfaceflinger/SFController.cpp b/services/surfaceflinger/tests/end2end/test_framework/surfaceflinger/SFController.cpp new file mode 100644 index 0000000000..1cf49c5750 --- /dev/null +++ b/services/surfaceflinger/tests/end2end/test_framework/surfaceflinger/SFController.cpp @@ -0,0 +1,181 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <chrono> +#include <cstdlib> +#include <memory> +#include <string> +#include <string_view> +#include <thread> +#include <utility> + +#include <android-base/expected.h> +#include <android-base/logging.h> +#include <android-base/properties.h> +#include <android/gui/ISurfaceComposer.h> +#include <binder/IBinder.h> +#include <binder/IInterface.h> +#include <binder/IServiceManager.h> +#include <binder/Status.h> +#include <ftl/finalizer.h> +#include <ftl/ignore.h> +#include <gui/Surface.h> +#include <gui/SurfaceComposerClient.h> +#include <utils/String16.h> +#include <utils/String8.h> +#include <utils/StrongPointer.h> + +#include "test_framework/surfaceflinger/SFController.h" + +namespace android::surfaceflinger::tests::end2end::test_framework::surfaceflinger { + +namespace { + +auto waitForSurfaceFlingerAIDL() -> sp<gui::ISurfaceComposer> { + constexpr auto kTimeout = std::chrono::seconds(30); + constexpr auto kSurfaceFlingerServiceName = "SurfaceFlingerAIDL"; + const sp<android::IServiceManager> serviceManager(android::defaultServiceManager()); + const auto kTimeoutAfter = std::chrono::steady_clock::now() + kTimeout; + + LOG(INFO) << "Waiting " << kTimeout << " for service manager registration...."; + sp<android::IBinder> flingerService; + while (flingerService == nullptr) { + if (std::chrono::steady_clock::now() > kTimeoutAfter) { + LOG(INFO) << "... Timeout!"; + return nullptr; + } + + constexpr auto sleepTime = std::chrono::milliseconds(10); + std::this_thread::sleep_for(sleepTime); + flingerService = serviceManager->checkService(String16(kSurfaceFlingerServiceName)); + } + LOG(INFO) << "Obtained surfaceflinger interface from service manager."; + + return interface_cast<gui::ISurfaceComposer>(flingerService); +} + +} // namespace + +struct SFController::Passkey final {}; + +void SFController::useHwcService(std::string_view fqn) { + base::SetProperty("debug.sf.hwc_service_name", std::string(fqn)); +} + +auto SFController::make() -> base::expected<std::shared_ptr<SFController>, std::string> { + using namespace std::string_literals; + + auto controller = std::make_unique<SFController>(Passkey{}); + if (controller == nullptr) { + return base::unexpected("Failed to construct the SFController instance."s); + } + + if (auto result = controller->init(); !result) { + return base::unexpected("Failed to init the SFController instance: "s + result.error()); + } + + return controller; +} + +SFController::SFController(Passkey passkey) { + ftl::ignore(passkey); +} + +auto SFController::init() -> base::expected<void, std::string> { + LOG(INFO) << "Stopping everything to prepare for tests"; + // NOLINTBEGIN(cert-env33-c) + system("stop"); + // NOLINTEND(cert-env33-c) + + mCleanup = ftl::Finalizer([this]() { stop(); }); + + return {}; +} + +auto SFController::startAndConnect() -> base::expected<void, std::string> { + using namespace std::string_literals; + + start(); + + LOG(VERBOSE) << "Getting ISurfaceComposer...."; + auto surfaceComposerAidl = waitForSurfaceFlingerAIDL(); + if (surfaceComposerAidl == nullptr) { + return base::unexpected("Failed to obtain the surfaceComposerAidl interface."s); + } + LOG(VERBOSE) << "Getting ISurfaceComposerClient...."; + sp<gui::ISurfaceComposerClient> surfaceComposerClientAidl; + if (!surfaceComposerAidl->createConnection(&surfaceComposerClientAidl).isOk()) { + return base::unexpected("Failed to obtain the surfaceComposerClientAidl interface."s); + } + if (surfaceComposerClientAidl == nullptr) { + return base::unexpected("Failed to obtain a valid surfaceComposerClientAidl interface."s); + } + auto surfaceComposerClient = sp<SurfaceComposerClient>::make(surfaceComposerClientAidl); + if (surfaceComposerClient == nullptr) { + return base::unexpected( + "Failed to construct a surfaceComposerClient around the aidl interface."s); + } + + mSurfaceComposerAidl = std::move(surfaceComposerAidl); + mSurfaceComposerClientAidl = std::move(surfaceComposerClientAidl); + mSurfaceComposerClient = std::move(surfaceComposerClient); + + LOG(INFO) << "Connected to surfaceflinger"; + return {}; +} + +void SFController::start() { + LOG(INFO) << "Starting surfaceflinger"; + // NOLINTBEGIN(cert-env33-c) + system("start surfaceflinger"); + // NOLINTEND(cert-env33-c) +} + +void SFController::stop() { + LOG(INFO) << "Stopping surfaceflinger"; + // NOLINTBEGIN(cert-env33-c) + system("stop surfaceflinger"); + // NOLINTEND(cert-env33-c) + + if (mSurfaceComposerAidl != nullptr) { + LOG(INFO) << "Waiting for SF AIDL interface to die"; + + constexpr auto kTimeout = std::chrono::seconds(30); + const auto binder = android::gui::ISurfaceComposer::asBinder(mSurfaceComposerAidl); + const auto kTimeoutAfter = std::chrono::steady_clock::now() + kTimeout; + + while (binder->isBinderAlive()) { + if (std::chrono::steady_clock::now() > kTimeoutAfter) { + LOG(INFO) << "... Timeout!"; + break; + } + + ftl::ignore = binder->pingBinder(); + + constexpr auto kPollInterval = std::chrono::milliseconds(10); + std::this_thread::sleep_for(kPollInterval); + } + + constexpr auto kShutdownWait = std::chrono::milliseconds(500); + std::this_thread::sleep_for(kShutdownWait); + } + + mSurfaceComposerClient = nullptr; + mSurfaceComposerClientAidl = nullptr; + mSurfaceComposerAidl = nullptr; +} + +} // namespace android::surfaceflinger::tests::end2end::test_framework::surfaceflinger diff --git a/services/surfaceflinger/tests/end2end/test_framework/surfaceflinger/SFController.h b/services/surfaceflinger/tests/end2end/test_framework/surfaceflinger/SFController.h new file mode 100644 index 0000000000..58bac9197f --- /dev/null +++ b/services/surfaceflinger/tests/end2end/test_framework/surfaceflinger/SFController.h @@ -0,0 +1,70 @@ +/* + * Copyright 2025 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 <memory> +#include <string> +#include <string_view> + +#include <android-base/expected.h> +#include <ftl/finalizer.h> +#include <utils/StrongPointer.h> + +namespace android::gui { + +class ISurfaceComposer; +class ISurfaceComposerClient; + +} // namespace android::gui + +namespace android { + +class SurfaceComposerClient; + +} // namespace android + +namespace android::surfaceflinger::tests::end2end::test_framework::surfaceflinger { + +class SFController final { + struct Passkey; // Uses the passkey idiom to restrict construction. + + public: + // Sets a property so that SurfaceFlinger uses the named HWC service. + static void useHwcService(std::string_view fqn); + + // Makes an instance of the SFController. + [[nodiscard]] static auto make() -> base::expected<std::shared_ptr<SFController>, std::string>; + + explicit SFController(Passkey pass); + + // Starts SurfaceFlinger and establishes the AIDL interface connections. + [[nodiscard]] auto startAndConnect() -> base::expected<void, std::string>; + + private: + [[nodiscard]] auto init() -> base::expected<void, std::string>; + static void start(); + void stop(); + + sp<gui::ISurfaceComposer> mSurfaceComposerAidl; + sp<gui::ISurfaceComposerClient> mSurfaceComposerClientAidl; + sp<SurfaceComposerClient> mSurfaceComposerClient; + + // Finalizers should be last so their destructors are invoked first. + ftl::FinalizerFtl mCleanup; +}; + +} // namespace android::surfaceflinger::tests::end2end::test_framework::surfaceflinger diff --git a/services/surfaceflinger/tests/end2end/tests/.clang-tidy b/services/surfaceflinger/tests/end2end/tests/.clang-tidy new file mode 100644 index 0000000000..4924c466c0 --- /dev/null +++ b/services/surfaceflinger/tests/end2end/tests/.clang-tidy @@ -0,0 +1,32 @@ +# Copyright 2025 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. + +FormatStyle: file +InheritParentConfig: true + +# Note: For tests, we are actually turning off certain checks enabled for the +# non-test code in the parent .clang-tidy file. +Checks: + - -cppcoreguidelines-avoid-magic-numbers # Allow tests to use magic numbers. + - -cppcoreguidelines-avoid-goto # Google Test macros use goto. + - -cppcoreguidelines-avoid-non-const-global-variables # Google Test macros define global variables. + - -cppcoreguidelines-macro-usage # Google Benchmark defines function-like macros. + - -cppcoreguidelines-owning-memory # Google Test macros use operator new directly. + - -google-runtime-int # Tests might intentionally use the base "short"/"long" types and not want to use "int16"/"int64". + - -misc-use-anonymous-namespace # Google Test macros declare some static global variables to not export them. + - -modernize-use-trailing-return-type # Google Test macros use non-trailing return types. + - -performance-move-const-arg # Tests might std::move() a trivially copyable value as part of testing that moving works. + - -readability-function-cognitive-complexity # Assertions turn into extra branches, increasing apparent complexity. + - -readability-magic-numbers # Allow tests to use magic numbers + diff --git a/services/surfaceflinger/tests/end2end/tests/Placeholder_test.cpp b/services/surfaceflinger/tests/end2end/tests/Placeholder_test.cpp new file mode 100644 index 0000000000..3c4277f8a0 --- /dev/null +++ b/services/surfaceflinger/tests/end2end/tests/Placeholder_test.cpp @@ -0,0 +1,39 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gtest/gtest.h> + +#include <android-base/logging.h> + +#include "test_framework/core/TestService.h" + +namespace android::surfaceflinger::tests::end2end { +namespace { + +struct Placeholder : public ::testing::Test {}; + +TEST_F(Placeholder, Bringup) { + auto serviceResult = test_framework::core::TestService::startWithDisplays({ + {.id = 123}, + }); + if (!serviceResult) { + LOG(WARNING) << "End2End service not available. " << serviceResult.error(); + GTEST_SKIP() << "End2End service not available. " << serviceResult.error(); + } +} + +} // namespace +} // namespace android::surfaceflinger::tests::end2end diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index 4322af7cef..75182e5fbb 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -183,7 +183,7 @@ struct DisplayIdGetter; template <typename PhysicalDisplay> struct DisplayIdGetter<PhysicalDisplayIdType<PhysicalDisplay>> { - static PhysicalDisplayId get() { + static DisplayIdVariant get() { if (!PhysicalDisplay::HAS_IDENTIFICATION_DATA) { return PhysicalDisplayId::fromPort(static_cast<bool>(PhysicalDisplay::PRIMARY) ? LEGACY_DISPLAY_TYPE_PRIMARY @@ -199,12 +199,12 @@ struct DisplayIdGetter<PhysicalDisplayIdType<PhysicalDisplay>> { template <VirtualDisplayId::BaseId displayId> struct DisplayIdGetter<HalVirtualDisplayIdType<displayId>> { - static HalVirtualDisplayId get() { return HalVirtualDisplayId(displayId); } + static DisplayIdVariant get() { return HalVirtualDisplayId(displayId); } }; template <> struct DisplayIdGetter<GpuVirtualDisplayIdType> { - static GpuVirtualDisplayId get() { return GpuVirtualDisplayId(0); } + static DisplayIdVariant get() { return GpuVirtualDisplayId(0); } }; template <typename> @@ -374,9 +374,8 @@ struct HwcDisplayVariant { // Called by tests to inject a HWC display setup template <hal::PowerMode kPowerMode = hal::PowerMode::ON> static void injectHwcDisplayWithNoDefaultCapabilities(DisplayTransactionTest* test) { - const auto displayId = DisplayVariant::DISPLAY_ID::get(); - ASSERT_FALSE(GpuVirtualDisplayId::tryCast(displayId)); - TestableSurfaceFlinger::FakeHwcDisplayInjector(displayId, HWC_DISPLAY_TYPE, + TestableSurfaceFlinger::FakeHwcDisplayInjector(DisplayVariant::DISPLAY_ID::get(), + HWC_DISPLAY_TYPE, static_cast<bool>(DisplayVariant::PRIMARY)) .setHwcDisplayId(HWC_DISPLAY_ID) .setResolution(DisplayVariant::RESOLUTION) @@ -663,9 +662,8 @@ struct HwcVirtualDisplayVariant const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); - const auto displayId = Base::DISPLAY_ID::get(); auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() - .setId(displayId) + .setId(Base::DISPLAY_ID::get()) .setPixels(Base::RESOLUTION) .setIsSecure(static_cast<bool>(Base::SECURE)) .setPowerAdvisor(&test->mPowerAdvisor) @@ -678,7 +676,12 @@ struct HwcVirtualDisplayVariant ceDisplayArgs); // Insert display data so that the HWC thinks it created the virtual display. - test->mFlinger.mutableHwcDisplayData().try_emplace(displayId); + const auto ceDisplayIdVar = compositionDisplay->getDisplayIdVariant(); + LOG_ALWAYS_FATAL_IF(!ceDisplayIdVar); + EXPECT_EQ(*ceDisplayIdVar, Base::DISPLAY_ID::get()); + const auto displayId = asHalDisplayId(*ceDisplayIdVar); + LOG_ALWAYS_FATAL_IF(!displayId); + test->mFlinger.mutableHwcDisplayData().try_emplace(*displayId); return compositionDisplay; } @@ -816,8 +819,9 @@ using HwcVirtualDisplayCase = inline DisplayModePtr createDisplayMode(DisplayModeId modeId, Fps refreshRate, int32_t group = 0, ui::Size resolution = ui::Size(1920, 1080)) { - return mock::createDisplayMode(modeId, refreshRate, group, resolution, - PrimaryDisplayVariant::DISPLAY_ID::get()); + const auto physicalDisplayId = asPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get()); + LOG_ALWAYS_FATAL_IF(!physicalDisplayId); + return mock::createDisplayMode(modeId, refreshRate, group, resolution, *physicalDisplayId); } } // namespace android diff --git a/services/surfaceflinger/tests/unittests/DualDisplayTransactionTest.h b/services/surfaceflinger/tests/unittests/DualDisplayTransactionTest.h index 90e716ff1f..edcb639f82 100644 --- a/services/surfaceflinger/tests/unittests/DualDisplayTransactionTest.h +++ b/services/surfaceflinger/tests/unittests/DualDisplayTransactionTest.h @@ -48,8 +48,10 @@ struct DualDisplayTransactionTest : DisplayTransactionTest { } } - static inline PhysicalDisplayId kInnerDisplayId = InnerDisplayVariant::DISPLAY_ID::get(); - static inline PhysicalDisplayId kOuterDisplayId = OuterDisplayVariant::DISPLAY_ID::get(); + static inline PhysicalDisplayId kInnerDisplayId = + asPhysicalDisplayId(InnerDisplayVariant::DISPLAY_ID::get()).value(); + static inline PhysicalDisplayId kOuterDisplayId = + asPhysicalDisplayId(OuterDisplayVariant::DISPLAY_ID::get()).value(); sp<DisplayDevice> mInnerDisplay, mOuterDisplay; }; diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index 6f15db8beb..76e01a6e7d 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -23,7 +23,6 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> -#include <gui/DisplayEventReceiver.h> #include <log/log.h> #include <scheduler/VsyncConfig.h> #include <utils/Errors.h> @@ -112,8 +111,6 @@ protected: void expectOnExpectedPresentTimePosted(nsecs_t expectedPresentTime); void expectUidFrameRateMappingEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, std::vector<FrameRateOverride>); - void expectQueuedBufferCountReceivedByConnection( - ConnectionEventRecorder& connectionEventRecorder, uint32_t expectedBufferCount); void onVSyncEvent(nsecs_t timestamp, nsecs_t expectedPresentationTime, nsecs_t deadlineTimestamp) { @@ -147,7 +144,6 @@ protected: sp<MockEventThreadConnection> mConnection; sp<MockEventThreadConnection> mThrottledConnection; std::unique_ptr<frametimeline::impl::TokenManager> mTokenManager; - std::vector<ConnectionEventRecorder*> mBufferStuffedConnectionRecorders; std::chrono::nanoseconds mVsyncPeriod; @@ -380,14 +376,6 @@ void EventThreadTest::expectUidFrameRateMappingEventReceivedByConnection( EXPECT_EQ(expectedDisplayId, event.header.displayId); } -void EventThreadTest::expectQueuedBufferCountReceivedByConnection( - ConnectionEventRecorder& connectionEventRecorder, uint32_t expectedBufferCount) { - auto args = connectionEventRecorder.waitForCall(); - ASSERT_TRUE(args.has_value()); - const auto& event = std::get<0>(args.value()); - EXPECT_EQ(expectedBufferCount, event.vsync.vsyncData.numberQueuedBuffers); -} - namespace { using namespace testing; @@ -880,63 +868,6 @@ TEST_F(EventThreadTest, postHcpLevelsChanged) { EXPECT_EQ(HDCP_V2, event.hdcpLevelsChange.maxLevel); } -TEST_F(EventThreadTest, connectionReceivesBufferStuffing) { - setupEventThread(); - - // Create a connection that will experience buffer stuffing. - ConnectionEventRecorder stuffedConnectionEventRecorder{0}; - sp<MockEventThreadConnection> stuffedConnection = - createConnection(stuffedConnectionEventRecorder, - gui::ISurfaceComposer::EventRegistration::modeChanged | - gui::ISurfaceComposer::EventRegistration::frameRateOverride, - 111); - - // Add a connection and buffer count to the list of stuffed Uids that will receive - // data in the next vsync event. - BufferStuffingMap bufferStuffedUids; - bufferStuffedUids.try_emplace(stuffedConnection->mOwnerUid, 3); - mThread->addBufferStuffedUids(bufferStuffedUids); - mBufferStuffedConnectionRecorders.emplace_back(&stuffedConnectionEventRecorder); - - // Signal that we want the next vsync event to be posted to two connections. - mThread->requestNextVsync(mConnection); - mThread->requestNextVsync(stuffedConnection); - onVSyncEvent(123, 456, 789); - - // Vsync event data contains number of queued buffers. - expectQueuedBufferCountReceivedByConnection(mConnectionEventCallRecorder, 0); - expectQueuedBufferCountReceivedByConnection(stuffedConnectionEventRecorder, 3); -} - -TEST_F(EventThreadTest, connectionsWithSameUidReceiveBufferStuffing) { - setupEventThread(); - - // Create a connection with the same Uid as another connection. - ConnectionEventRecorder secondConnectionEventRecorder{0}; - sp<MockEventThreadConnection> secondConnection = - createConnection(secondConnectionEventRecorder, - gui::ISurfaceComposer::EventRegistration::modeChanged | - gui::ISurfaceComposer::EventRegistration::frameRateOverride, - mConnectionUid); - - // Add connection Uid and buffer count to the list of stuffed Uids that will receive - // data in the next vsync event. - BufferStuffingMap bufferStuffedUids; - bufferStuffedUids.try_emplace(mConnectionUid, 3); - mThread->addBufferStuffedUids(bufferStuffedUids); - mBufferStuffedConnectionRecorders.emplace_back(&mConnectionEventCallRecorder); - mBufferStuffedConnectionRecorders.emplace_back(&secondConnectionEventRecorder); - - // Signal that we want the next vsync event to be posted to two connections. - mThread->requestNextVsync(mConnection); - mThread->requestNextVsync(secondConnection); - onVSyncEvent(123, 456, 789); - - // Vsync event data contains number of queued buffers. - expectQueuedBufferCountReceivedByConnection(mConnectionEventCallRecorder, 3); - expectQueuedBufferCountReceivedByConnection(secondConnectionEventRecorder, 3); -} - } // namespace } // namespace android diff --git a/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp b/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp index a5b347a43c..c6da1a1a79 100644 --- a/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp +++ b/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp @@ -125,13 +125,13 @@ TEST_F(FlagManagerTest, DISABLED_returnsOverrideFalse) { TEST_F(FlagManagerTest, ignoresOverrideInUnitTestMode) { mFlagManager.setUnitTestMode(); - SET_FLAG_FOR_TEST(flags::multithreaded_present, true); + SET_FLAG_FOR_TEST(flags::no_vsyncs_on_screen_off, true); // If this has not been called in this process, it will be called. // Regardless, the result is ignored. EXPECT_CALL(mFlagManager, getBoolProperty).WillRepeatedly(Return(false)); - EXPECT_EQ(true, mFlagManager.multithreaded_present()); + EXPECT_EQ(true, mFlagManager.no_vsyncs_on_screen_off()); } TEST_F(FlagManagerTest, returnsValue) { diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index 3ed038b3b1..07356b9ec9 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -261,6 +261,40 @@ TEST_F(LayerSnapshotTest, AlphaInheritedByChildren) { EXPECT_EQ(getSnapshot(1221)->alpha, 0.25f); } +TEST_F(LayerSnapshotTest, AlphaInheritedByChildWhenParentIsHiddenByInvalidTransform) { + setMatrix(1, 0, 0, 0, 0); + update(mSnapshotBuilder); + mLifecycleManager.commitChanges(); + + setAlpha(1, 0.5); + update(mSnapshotBuilder); + mLifecycleManager.commitChanges(); + + setMatrix(1, 1, 0, 0, 1); + update(mSnapshotBuilder); + mLifecycleManager.commitChanges(); + + EXPECT_EQ(getSnapshot(1)->alpha, 0.5f); + EXPECT_EQ(getSnapshot(11)->alpha, 0.5f); +} + +TEST_F(LayerSnapshotTest, AlphaInheritedByChildWhenParentIsHidden) { + hideLayer(1); + update(mSnapshotBuilder); + mLifecycleManager.commitChanges(); + + setAlpha(1, 0.5); + update(mSnapshotBuilder); + mLifecycleManager.commitChanges(); + + showLayer(1); + update(mSnapshotBuilder); + mLifecycleManager.commitChanges(); + + EXPECT_EQ(getSnapshot(1)->alpha, 0.5f); + EXPECT_EQ(getSnapshot(11)->alpha, 0.5f); +} + // Change states TEST_F(LayerSnapshotTest, UpdateClearsPreviousChangeStates) { setCrop(1, Rect(1, 2, 3, 4)); diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index cbcfe030e7..116fcd9f6d 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -143,7 +143,7 @@ TEST_F(SchedulerTest, registerDisplay) FTL_FAKE_GUARD(kMainThreadContext) { kDisplay1Mode60->getId())); // TODO(b/241285191): Restore once VsyncSchedule::getPendingHardwareVsyncState is called by - // Scheduler::setDisplayPowerMode rather than SF::setPowerModeInternal. + // Scheduler::setDisplayPowerMode rather than SF::setPhysicalDisplayPowerMode. #if 0 // Hardware VSYNC should be disabled for newly registered displays. EXPECT_CALL(mSchedulerCallback, requestHardwareVsync(kDisplayId2, false)).Times(1); @@ -741,8 +741,6 @@ TEST_F(SchedulerTest, resyncAllDoNotAllow) FTL_FAKE_GUARD(kMainThreadContext) { } TEST_F(SchedulerTest, resyncAllSkipsOffDisplays) FTL_FAKE_GUARD(kMainThreadContext) { - SET_FLAG_FOR_TEST(flags::multithreaded_present, true); - // resyncAllToHardwareVsync will result in requesting hardware VSYNC on display 1, which is on, // but not on display 2, which is off. EXPECT_CALL(mScheduler->mockRequestHardwareVsync, Call(kDisplayId1, true)).Times(1); @@ -763,28 +761,6 @@ TEST_F(SchedulerTest, resyncAllSkipsOffDisplays) FTL_FAKE_GUARD(kMainThreadConte mScheduler->resyncAllToHardwareVsync(kAllowToEnable); } -TEST_F(SchedulerTest, resyncAllLegacyAppliesToOffDisplays) FTL_FAKE_GUARD(kMainThreadContext) { - SET_FLAG_FOR_TEST(flags::multithreaded_present, false); - - // In the legacy code, prior to the flag, resync applied to OFF displays. - EXPECT_CALL(mScheduler->mockRequestHardwareVsync, Call(kDisplayId1, true)).Times(1); - EXPECT_CALL(mScheduler->mockRequestHardwareVsync, Call(kDisplayId2, true)).Times(1); - - mScheduler->setDisplayPowerMode(kDisplayId1, hal::PowerMode::ON); - - mScheduler->registerDisplay(kDisplayId2, - std::make_shared<RefreshRateSelector>(kDisplay2Modes, - kDisplay2Mode60->getId())); - ASSERT_EQ(hal::PowerMode::OFF, mScheduler->getDisplayPowerMode(kDisplayId2)); - - static constexpr bool kDisallow = true; - mScheduler->disableHardwareVsync(kDisplayId1, kDisallow); - mScheduler->disableHardwareVsync(kDisplayId2, kDisallow); - - static constexpr bool kAllowToEnable = true; - mScheduler->resyncAllToHardwareVsync(kAllowToEnable); -} - class AttachedChoreographerTest : public SchedulerTest { protected: void frameRateTestScenario(Fps layerFps, int8_t frameRateCompatibility, Fps displayFps, diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp index aa5b7863a9..aa48c1b26a 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp @@ -50,9 +50,9 @@ public: EXPECT_EQ(display.requestedRefreshRate, Fps::fromValue(requestedRefreshRate)); EXPECT_EQ(name.c_str(), display.displayName); - const VirtualDisplayId vid = GpuVirtualDisplayId(baseId); sp<DisplayDevice> device = - mFlinger.createVirtualDisplayDevice(displayToken, vid, requestedRefreshRate); + mFlinger.createVirtualDisplayDevice(displayToken, GpuVirtualDisplayId(baseId), + requestedRefreshRate); EXPECT_TRUE(device->isVirtual()); device->adjustRefreshRate(Fps::fromValue(pacesetterDisplayRefreshRate)); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp index 525a940960..3f710fdf6b 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp @@ -415,8 +415,8 @@ TEST_F(DisplayModeSwitchingTest, innerXorOuterDisplay) { EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60)); EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120)); - mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::OFF); - mFlinger.setPowerModeInternal(innerDisplay, hal::PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(outerDisplay, hal::PowerMode::OFF); + mFlinger.setPhysicalDisplayPowerMode(innerDisplay, hal::PowerMode::ON); EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60)); EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120)); @@ -446,8 +446,8 @@ TEST_F(DisplayModeSwitchingTest, innerXorOuterDisplay) { EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId90)); EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId60)); - mFlinger.setPowerModeInternal(innerDisplay, hal::PowerMode::OFF); - mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(innerDisplay, hal::PowerMode::OFF); + mFlinger.setPhysicalDisplayPowerMode(outerDisplay, hal::PowerMode::ON); EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId90)); EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId60)); @@ -479,8 +479,8 @@ TEST_F(DisplayModeSwitchingTest, innerAndOuterDisplay) { EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60)); EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120)); - mFlinger.setPowerModeInternal(innerDisplay, hal::PowerMode::ON); - mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(innerDisplay, hal::PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(outerDisplay, hal::PowerMode::ON); EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60)); EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120)); @@ -522,7 +522,7 @@ TEST_F(DisplayModeSwitchingTest, powerOffDuringModeSet) { EXPECT_THAT(mDisplay, ModeSwitchingTo(&mFlinger, kModeId90)); // Power off the display before the mode has been set. - mFlinger.setPowerModeInternal(mDisplay, hal::PowerMode::OFF); + mFlinger.setPhysicalDisplayPowerMode(mDisplay, hal::PowerMode::OFF); const VsyncPeriodChangeTimeline timeline{.refreshRequired = true}; EXPECT_SET_ACTIVE_CONFIG(kInnerDisplayHwcId, kModeId90); @@ -547,8 +547,8 @@ TEST_F(DisplayModeSwitchingTest, powerOffDuringConcurrentModeSet) { EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60)); EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120)); - mFlinger.setPowerModeInternal(innerDisplay, hal::PowerMode::ON); - mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(innerDisplay, hal::PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(outerDisplay, hal::PowerMode::ON); EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60)); EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120)); @@ -565,7 +565,7 @@ TEST_F(DisplayModeSwitchingTest, powerOffDuringConcurrentModeSet) { EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60)); // Power off the outer display before the mode has been set. - mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::OFF); + mFlinger.setPhysicalDisplayPowerMode(outerDisplay, hal::PowerMode::OFF); const VsyncPeriodChangeTimeline timeline{.refreshRequired = true}; EXPECT_SET_ACTIVE_CONFIG(kInnerDisplayHwcId, kModeId90); @@ -582,8 +582,8 @@ TEST_F(DisplayModeSwitchingTest, powerOffDuringConcurrentModeSet) { EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId90)); EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId60)); - mFlinger.setPowerModeInternal(innerDisplay, hal::PowerMode::OFF); - mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(innerDisplay, hal::PowerMode::OFF); + mFlinger.setPhysicalDisplayPowerMode(outerDisplay, hal::PowerMode::ON); EXPECT_EQ(NO_ERROR, mFlinger.setDesiredDisplayModeSpecs(outerDisplay->getDisplayToken().promote(), diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp index 1335640342..eac5a8e9c5 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp @@ -68,13 +68,9 @@ void DisplayTransactionCommitTest::setupCommonPreconditions() { template <typename Case, bool connected> void DisplayTransactionCommitTest::expectHotplugReceived(mock::EventThread* eventThread) { - const auto convert = [](auto physicalDisplayId) { - return std::make_optional(DisplayId{physicalDisplayId}); - }; - - EXPECT_CALL(*eventThread, - onHotplugReceived(ResultOf(convert, Case::Display::DISPLAY_ID::get()), connected)) - .Times(1); + const auto physicalDisplayId = asPhysicalDisplayId(Case::Display::DISPLAY_ID::get()); + ASSERT_TRUE(physicalDisplayId); + EXPECT_CALL(*eventThread, onHotplugReceived(*physicalDisplayId, connected)).Times(1); } template <typename Case> @@ -111,7 +107,7 @@ void DisplayTransactionCommitTest::verifyDisplayIsConnected(const sp<IBinder>& d std::optional<DisplayDeviceState::Physical> expectedPhysical; if (Case::Display::CONNECTION_TYPE::value) { - const auto displayId = PhysicalDisplayId::tryCast(Case::Display::DISPLAY_ID::get()); + const auto displayId = asPhysicalDisplayId(Case::Display::DISPLAY_ID::get()); ASSERT_TRUE(displayId); const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value; ASSERT_TRUE(hwcDisplayId); @@ -137,10 +133,10 @@ void DisplayTransactionCommitTest::verifyPhysicalDisplayIsConnected() { EXPECT_TRUE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID)); // SF should have a display token. - const auto displayId = Case::Display::DISPLAY_ID::get(); - ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); + const auto displayIdOpt = asPhysicalDisplayId(Case::Display::DISPLAY_ID::get()); + ASSERT_TRUE(displayIdOpt); - const auto displayOpt = mFlinger.mutablePhysicalDisplays().get(displayId); + const auto displayOpt = mFlinger.mutablePhysicalDisplays().get(*displayIdOpt); ASSERT_TRUE(displayOpt); const auto& display = displayOpt->get(); @@ -246,9 +242,9 @@ void DisplayTransactionCommitTest::processesHotplugDisconnectCommon() { EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID)); // SF should not have a PhysicalDisplay. - const auto displayId = Case::Display::DISPLAY_ID::get(); - ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); - ASSERT_FALSE(mFlinger.mutablePhysicalDisplays().contains(displayId)); + const auto physicalDisplayIdOpt = asPhysicalDisplayId(Case::Display::DISPLAY_ID::get()); + ASSERT_TRUE(physicalDisplayIdOpt); + ASSERT_FALSE(mFlinger.mutablePhysicalDisplays().contains(*physicalDisplayIdOpt)); // The existing token should have been removed. verifyDisplayIsNotConnected(existing.token()); @@ -356,9 +352,10 @@ TEST_F(DisplayTransactionCommitTest, processesHotplugConnectThenDisconnectPrimar EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID)); // SF should not have a PhysicalDisplay. - const auto displayId = Case::Display::DISPLAY_ID::get(); - ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); - ASSERT_FALSE(mFlinger.mutablePhysicalDisplays().contains(displayId)); + const auto physicalDisplayIdOpt = + asPhysicalDisplayId(Case::Display::DISPLAY_ID::get()); + ASSERT_TRUE(physicalDisplayIdOpt); + ASSERT_FALSE(mFlinger.mutablePhysicalDisplays().contains(*physicalDisplayIdOpt)); }(), testing::KilledBySignal(SIGABRT), "Primary display cannot be disconnected."); } @@ -400,10 +397,12 @@ TEST_F(DisplayTransactionCommitTest, processesHotplugDisconnectThenConnectPrimar // The existing token should have been removed. verifyDisplayIsNotConnected(existing.token()); - const auto displayId = Case::Display::DISPLAY_ID::get(); - ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); + const auto physicalDisplayIdOpt = + asPhysicalDisplayId(Case::Display::DISPLAY_ID::get()); + ASSERT_TRUE(physicalDisplayIdOpt); - const auto displayOpt = mFlinger.mutablePhysicalDisplays().get(displayId); + const auto displayOpt = + mFlinger.mutablePhysicalDisplays().get(*physicalDisplayIdOpt); ASSERT_TRUE(displayOpt); EXPECT_NE(existing.token(), displayOpt->get().token()); @@ -540,9 +539,9 @@ TEST_F(DisplayTransactionCommitTest, processesVirtualDisplayRemoval) { // Preconditions // A virtual display is set up but is removed from the current state. - const auto displayId = Case::Display::DISPLAY_ID::get(); - ASSERT_TRUE(HalVirtualDisplayId::tryCast(displayId)); - mFlinger.mutableHwcDisplayData().try_emplace(displayId); + const auto displayId = asHalDisplayId(Case::Display::DISPLAY_ID::get()); + ASSERT_TRUE(displayId); + mFlinger.mutableHwcDisplayData().try_emplace(*displayId); Case::Display::injectHwcDisplay(this); auto existing = Case::Display::makeFakeExistingDisplayInjector(this); existing.inject(); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp index 19f8debe84..8972840c8a 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp @@ -38,30 +38,30 @@ TEST_F(FoldableTest, promotesPacesetterOnBoot) { ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId); // ...and should still be after powering on. - mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId); } TEST_F(FoldableTest, promotesPacesetterOnFoldUnfold) { - mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); // The outer display should become the pacesetter after folding. - mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF); - mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::OFF); + mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId); // The inner display should become the pacesetter after unfolding. - mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::OFF); - mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::OFF); + mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId); } TEST_F(FoldableTest, promotesPacesetterOnConcurrentPowerOn) { - mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); // The inner display should stay the pacesetter if both are powered on. // TODO(b/255635821): The pacesetter should depend on the displays' refresh rates. - mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId); // The outer display should become the pacesetter if designated. @@ -74,20 +74,20 @@ TEST_F(FoldableTest, promotesPacesetterOnConcurrentPowerOn) { } TEST_F(FoldableTest, promotesPacesetterOnConcurrentPowerOff) { - mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON); - mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON); // The outer display should become the pacesetter if the inner display powers off. - mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF); + mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::OFF); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId); // The outer display should stay the pacesetter if both are powered on. // TODO(b/255635821): The pacesetter should depend on the displays' refresh rates. - mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId); // The inner display should become the pacesetter if the outer display powers off. - mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::OFF); + mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::OFF); ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId); } @@ -114,8 +114,8 @@ TEST_F(FoldableTest, requestsHardwareVsyncForInnerDisplay) { .Times(0); // The injected VsyncSchedule uses TestableScheduler::mockRequestHardwareVsync, so no calls to - // ISchedulerCallback::requestHardwareVsync are expected during setPowerModeInternal. - mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON); + // ISchedulerCallback::requestHardwareVsync are expected during setPhysicalDisplayPowerMode. + mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); EXPECT_TRUE(mInnerDisplay->isPoweredOn()); EXPECT_FALSE(mOuterDisplay->isPoweredOn()); @@ -133,10 +133,10 @@ TEST_F(FoldableTest, requestsHardwareVsyncForOuterDisplay) { .Times(1); // The injected VsyncSchedule uses TestableScheduler::mockRequestHardwareVsync, so no calls to - // ISchedulerCallback::requestHardwareVsync are expected during setPowerModeInternal. - mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON); - mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF); - mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON); + // ISchedulerCallback::requestHardwareVsync are expected during setPhysicalDisplayPowerMode. + mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::OFF); + mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON); EXPECT_FALSE(mInnerDisplay->isPoweredOn()); EXPECT_TRUE(mOuterDisplay->isPoweredOn()); @@ -154,9 +154,9 @@ TEST_F(FoldableTest, requestsHardwareVsyncForBothDisplays) { .Times(1); // The injected VsyncSchedule uses TestableScheduler::mockRequestHardwareVsync, so no calls to - // ISchedulerCallback::requestHardwareVsync are expected during setPowerModeInternal. - mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON); - mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON); + // ISchedulerCallback::requestHardwareVsync are expected during setPhysicalDisplayPowerMode. + mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON); EXPECT_TRUE(mInnerDisplay->isPoweredOn()); EXPECT_TRUE(mOuterDisplay->isPoweredOn()); @@ -167,18 +167,16 @@ TEST_F(FoldableTest, requestsHardwareVsyncForBothDisplays) { } TEST_F(FoldableTest, requestVsyncOnPowerOn) { - SET_FLAG_FOR_TEST(flags::multithreaded_present, true); EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kInnerDisplayId, true)) .Times(1); EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kOuterDisplayId, true)) .Times(1); - mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON); - mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON); } TEST_F(FoldableTest, disableVsyncOnPowerOffPacesetter) { - SET_FLAG_FOR_TEST(flags::multithreaded_present, true); // When the device boots, the inner display should be the pacesetter. ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId); @@ -192,10 +190,10 @@ TEST_F(FoldableTest, disableVsyncOnPowerOffPacesetter) { EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kInnerDisplayId, false)) .Times(1); - mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON); - mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON); - mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF); + mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::OFF); // Other display is now the pacesetter. ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp index 49972b03f6..b8b1b9527c 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp @@ -90,7 +90,9 @@ TEST_F(HotplugTest, createsDisplaySnapshotsForDisplaysWithIdentificationData) { mFlinger.configure(); EXPECT_TRUE(hasPhysicalHwcDisplay(PrimaryDisplay::HWC_DISPLAY_ID)); - EXPECT_TRUE(mFlinger.getHwComposer().isConnected(PrimaryDisplay::DISPLAY_ID::get())); + const auto primaryDisplayId = asPhysicalDisplayId(PrimaryDisplay::DISPLAY_ID::get()); + ASSERT_TRUE(primaryDisplayId); + EXPECT_TRUE(mFlinger.getHwComposer().isConnected(*primaryDisplayId)); const auto primaryDisplayIdOpt = mFlinger.getHwComposer().toPhysicalDisplayId(PrimaryDisplay::HWC_DISPLAY_ID); ASSERT_TRUE(primaryDisplayIdOpt.has_value()); @@ -98,13 +100,15 @@ TEST_F(HotplugTest, createsDisplaySnapshotsForDisplaysWithIdentificationData) { mFlinger.physicalDisplays().get(primaryDisplayIdOpt.value()); ASSERT_TRUE(primaryPhysicalDisplayOpt.has_value()); const auto primaryDisplaySnapshotRef = primaryPhysicalDisplayOpt->get().snapshotRef(); - EXPECT_EQ(PrimaryDisplay::DISPLAY_ID::get(), primaryDisplaySnapshotRef.get().displayId()); + EXPECT_EQ(*primaryDisplayId, primaryDisplaySnapshotRef.get().displayId()); EXPECT_EQ(PrimaryDisplay::PORT::value, primaryDisplaySnapshotRef.get().port()); EXPECT_EQ(PrimaryDisplay::CONNECTION_TYPE::value, primaryDisplaySnapshotRef.get().connectionType()); EXPECT_TRUE(hasPhysicalHwcDisplay(ExternalDisplay::HWC_DISPLAY_ID)); - EXPECT_TRUE(mFlinger.getHwComposer().isConnected(ExternalDisplay::DISPLAY_ID::get())); + const auto externalDisplayId = asPhysicalDisplayId(ExternalDisplay::DISPLAY_ID::get()); + ASSERT_TRUE(externalDisplayId); + EXPECT_TRUE(mFlinger.getHwComposer().isConnected(*externalDisplayId)); const auto externalDisplayIdOpt = mFlinger.getHwComposer().toPhysicalDisplayId(ExternalDisplay::HWC_DISPLAY_ID); ASSERT_TRUE(externalDisplayIdOpt.has_value()); @@ -112,7 +116,7 @@ TEST_F(HotplugTest, createsDisplaySnapshotsForDisplaysWithIdentificationData) { mFlinger.physicalDisplays().get(externalDisplayIdOpt.value()); ASSERT_TRUE(externalPhysicalDisplayOpt.has_value()); const auto externalDisplaySnapshotRef = externalPhysicalDisplayOpt->get().snapshotRef(); - EXPECT_EQ(ExternalDisplay::DISPLAY_ID::get(), externalDisplaySnapshotRef.get().displayId()); + EXPECT_EQ(*externalDisplayId, externalDisplaySnapshotRef.get().displayId()); EXPECT_EQ(ExternalDisplay::PORT::value, externalDisplaySnapshotRef.get().port()); EXPECT_EQ(ExternalDisplay::CONNECTION_TYPE::value, externalDisplaySnapshotRef.get().connectionType()); @@ -154,8 +158,8 @@ TEST_F(HotplugTest, createsDisplaySnapshotsForDisplaysWithoutIdentificationData) constexpr PhysicalDisplayId primaryInternalDisplayId = PhysicalDisplayId::fromPort(primaryInternalDisplayPort); EXPECT_TRUE(hasPhysicalHwcDisplay(PrimaryDisplay::HWC_DISPLAY_ID)); - ASSERT_EQ(primaryInternalDisplayId, PrimaryDisplay::DISPLAY_ID::get()); - EXPECT_TRUE(mFlinger.getHwComposer().isConnected(PrimaryDisplay::DISPLAY_ID::get())); + ASSERT_EQ(primaryInternalDisplayId, asPhysicalDisplayId(PrimaryDisplay::DISPLAY_ID::get())); + EXPECT_TRUE(mFlinger.getHwComposer().isConnected(primaryInternalDisplayId)); const auto primaryDisplayIdOpt = mFlinger.getHwComposer().toPhysicalDisplayId(PrimaryDisplay::HWC_DISPLAY_ID); ASSERT_TRUE(primaryDisplayIdOpt.has_value()); @@ -220,7 +224,9 @@ TEST_F(HotplugTest, ignoresDuplicateDisconnection) { // The display should be scheduled for removal during the next commit. At this point, it should // still exist but be marked as disconnected. EXPECT_TRUE(hasPhysicalHwcDisplay(ExternalDisplay::HWC_DISPLAY_ID)); - EXPECT_FALSE(mFlinger.getHwComposer().isConnected(ExternalDisplay::DISPLAY_ID::get())); + const auto externalDisplayId = asPhysicalDisplayId(ExternalDisplay::DISPLAY_ID::get()); + ASSERT_TRUE(externalDisplayId); + EXPECT_FALSE(mFlinger.getHwComposer().isConnected(*externalDisplayId)); } TEST_F(HotplugTest, rejectsHotplugIfFailedToLoadDisplayModes) { diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp index fed7b2e767..d5c22a9601 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp @@ -315,7 +315,7 @@ using ExternalDisplayPowerCase = EventThreadNotSupportedVariant, DispSyncNotSupportedVariant, TransitionVariant>; -class SetPowerModeInternalTest : public DisplayTransactionTest { +class SetPhysicalDisplayPowerModeTest : public DisplayTransactionTest { public: template <typename Case> void transitionDisplayCommon(); @@ -331,15 +331,14 @@ template <> struct PowerModeInitialVSyncEnabled<PowerMode::DOZE> : public std::true_type {}; template <typename Case> -void SetPowerModeInternalTest::transitionDisplayCommon() { +void SetPhysicalDisplayPowerModeTest::transitionDisplayCommon() { // -------------------------------------------------------------------- // Preconditions Case::Doze::setupComposerCallExpectations(this); auto display = Case::injectDisplayWithInitialPowerMode(this, Case::Transition::INITIAL_POWER_MODE); - auto displayId = display->getId(); - if (auto physicalDisplayId = PhysicalDisplayId::tryCast(displayId)) { + if (auto physicalDisplayId = asPhysicalDisplayId(display->getDisplayIdVariant())) { Case::setInitialHwVsyncEnabled(this, *physicalDisplayId, PowerModeInitialVSyncEnabled< Case::Transition::INITIAL_POWER_MODE>::value); @@ -353,7 +352,7 @@ void SetPowerModeInternalTest::transitionDisplayCommon() { // -------------------------------------------------------------------- // Invocation - mFlinger.setPowerModeInternal(display, Case::Transition::TARGET_POWER_MODE); + mFlinger.setPhysicalDisplayPowerMode(display, Case::Transition::TARGET_POWER_MODE); // -------------------------------------------------------------------- // Postconditions @@ -361,7 +360,7 @@ void SetPowerModeInternalTest::transitionDisplayCommon() { Case::Transition::verifyPostconditions(this); } -TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfNoChange) { +TEST_F(SetPhysicalDisplayPowerModeTest, setPhysicalDisplayPowerModeDoesNothingIfNoChange) { using Case = SimplePrimaryDisplayCase; // -------------------------------------------------------------------- @@ -378,7 +377,7 @@ TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfNoChange) { // -------------------------------------------------------------------- // Invocation - mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), PowerMode::ON); + mFlinger.setPhysicalDisplayPowerMode(display.mutableDisplayDevice(), PowerMode::ON); // -------------------------------------------------------------------- // Postconditions @@ -386,16 +385,16 @@ TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfNoChange) { EXPECT_EQ(PowerMode::ON, display.mutableDisplayDevice()->getPowerMode()); } -TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfVirtualDisplay) { +TEST_F(SetPhysicalDisplayPowerModeTest, setPhysicalDisplayPowerModeDoesNothingIfVirtualDisplay) { using Case = HwcVirtualDisplayCase; // -------------------------------------------------------------------- // Preconditions // Insert display data so that the HWC thinks it created the virtual display. - const auto displayId = Case::Display::DISPLAY_ID::get(); - ASSERT_TRUE(HalVirtualDisplayId::tryCast(displayId)); - mFlinger.mutableHwcDisplayData().try_emplace(displayId); + const auto displayId = asHalDisplayId(Case::Display::DISPLAY_ID::get()); + ASSERT_TRUE(displayId); + ASSERT_TRUE(mFlinger.mutableHwcDisplayData().try_emplace(*displayId).second); // A virtual display device is set up Case::Display::injectHwcDisplay(this); @@ -408,7 +407,7 @@ TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfVirtualDisplay // -------------------------------------------------------------------- // Invocation - mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), PowerMode::OFF); + mFlinger.setPhysicalDisplayPowerMode(display.mutableDisplayDevice(), PowerMode::OFF); // -------------------------------------------------------------------- // Postconditions @@ -416,88 +415,83 @@ TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfVirtualDisplay EXPECT_EQ(PowerMode::ON, display.mutableDisplayDevice()->getPowerMode()); } -TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToOnPrimaryDisplay) { +TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOffToOnPrimaryDisplay) { transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOffToOnVariant>>(); } -TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToDozeSuspendPrimaryDisplay) { +TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOffToDozeSuspendPrimaryDisplay) { transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOffToDozeSuspendVariant>>(); } -TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToOffPrimaryDisplay) { +TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToOffPrimaryDisplay) { transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToOffVariant>>(); } -TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOffPrimaryDisplay) { +TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeSuspendToOffPrimaryDisplay) { transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToOffVariant>>(); } -TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozePrimaryDisplay) { +TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToDozePrimaryDisplay) { transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToDozeVariant>>(); } -TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToDozePrimaryDisplay) { +TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeSuspendToDozePrimaryDisplay) { transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToDozeVariant>>(); } -TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeToOnPrimaryDisplay) { +TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeToOnPrimaryDisplay) { transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeToOnVariant>>(); } -TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOnPrimaryDisplay) { +TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeSuspendToOnPrimaryDisplay) { transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToOnVariant>>(); } -TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeSuspendPrimaryDisplay) { +TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToDozeSuspendPrimaryDisplay) { transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToDozeSuspendVariant>>(); } -TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToUnknownPrimaryDisplay) { +TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToUnknownPrimaryDisplay) { transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToUnknownVariant>>(); } -TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToOnExternalDisplay) { - SET_FLAG_FOR_TEST(flags::multithreaded_present, true); +TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOffToOnExternalDisplay) { transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOffToOnVariant>>(); } -TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToDozeSuspendExternalDisplay) { +TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOffToDozeSuspendExternalDisplay) { transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOffToDozeSuspendVariant>>(); } -TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToOffExternalDisplay) { - SET_FLAG_FOR_TEST(flags::multithreaded_present, true); +TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToOffExternalDisplay) { transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToOffVariant>>(); } -TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOffExternalDisplay) { +TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeSuspendToOffExternalDisplay) { transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToOffVariant>>(); } -TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeExternalDisplay) { +TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToDozeExternalDisplay) { transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToDozeVariant>>(); } -TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToDozeExternalDisplay) { - SET_FLAG_FOR_TEST(flags::multithreaded_present, true); +TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeSuspendToDozeExternalDisplay) { transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToDozeVariant>>(); } -TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeToOnExternalDisplay) { +TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeToOnExternalDisplay) { transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeToOnVariant>>(); } -TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOnExternalDisplay) { - SET_FLAG_FOR_TEST(flags::multithreaded_present, true); +TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeSuspendToOnExternalDisplay) { transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToOnVariant>>(); } -TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeSuspendExternalDisplay) { - SET_FLAG_FOR_TEST(flags::multithreaded_present, true); +TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToDozeSuspendExternalDisplay) { transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToDozeSuspendVariant>>(); } -TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToUnknownExternalDisplay) { +TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToUnknownExternalDisplay) { transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToUnknownVariant>>(); } diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp index cd554ea1ec..23e73de660 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp @@ -235,7 +235,7 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { constexpr auto kConnectionTypeOpt = Case::Display::CONNECTION_TYPE::value; if constexpr (kConnectionTypeOpt) { - const auto displayId = PhysicalDisplayId::tryCast(Case::Display::DISPLAY_ID::get()); + const auto displayId = asPhysicalDisplayId(Case::Display::DISPLAY_ID::get()); ASSERT_TRUE(displayId); const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value; ASSERT_TRUE(hwcDisplayId); @@ -282,7 +282,7 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { // Postconditions ASSERT_NE(nullptr, device); - EXPECT_EQ(Case::Display::DISPLAY_ID::get(), device->getId()); + EXPECT_EQ(Case::Display::DISPLAY_ID::get(), device->getDisplayIdVariant()); EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), device->isVirtual()); EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure()); EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary()); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index bb377bad77..c5973db109 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -462,9 +462,9 @@ public: } // Allow reading display state without locking, as if called on the SF main thread. - auto setPowerModeInternal(const sp<DisplayDevice>& display, - hal::PowerMode mode) NO_THREAD_SAFETY_ANALYSIS { - return mFlinger->setPowerModeInternal(display, mode); + auto setPhysicalDisplayPowerMode(const sp<DisplayDevice>& display, + hal::PowerMode mode) NO_THREAD_SAFETY_ANALYSIS { + return mFlinger->setPhysicalDisplayPowerMode(display, mode); } auto renderScreenImpl(const sp<DisplayDevice> display, const Rect sourceCrop, @@ -481,7 +481,7 @@ public: SurfaceFlinger::ScreenshotArgs screenshotArgs; screenshotArgs.captureTypeVariant = display; - screenshotArgs.displayId = std::nullopt; + screenshotArgs.displayIdVariant = std::nullopt; screenshotArgs.sourceCrop = sourceCrop; screenshotArgs.reqSize = sourceCrop.getSize(); screenshotArgs.dataspace = dataspace; @@ -583,7 +583,7 @@ public: } sp<DisplayDevice> createVirtualDisplayDevice(const sp<IBinder> displayToken, - VirtualDisplayId displayId, + GpuVirtualDisplayId displayId, float requestedRefreshRate) { constexpr ui::Size kResolution = {1080, 1920}; auto compositionDisplay = compositionengine::impl:: @@ -827,9 +827,11 @@ public: static constexpr int32_t DEFAULT_DPI = 320; static constexpr hal::HWConfigId DEFAULT_ACTIVE_CONFIG = 0; - FakeHwcDisplayInjector(HalDisplayId displayId, hal::DisplayType hwcDisplayType, + FakeHwcDisplayInjector(DisplayIdVariant displayIdVariant, hal::DisplayType hwcDisplayType, bool isPrimary) - : mDisplayId(displayId), mHwcDisplayType(hwcDisplayType), mIsPrimary(isPrimary) {} + : mDisplayIdVariant(displayIdVariant), + mHwcDisplayType(hwcDisplayType), + mIsPrimary(isPrimary) {} auto& setHwcDisplayId(hal::HWDisplayId displayId) { mHwcDisplayId = displayId; @@ -894,7 +896,9 @@ public: display->setPowerMode(mPowerMode); - flinger->mutableHwcDisplayData()[mDisplayId].hwcDisplay = std::move(display); + const auto halDisplayId = asHalDisplayId(mDisplayIdVariant); + ASSERT_TRUE(halDisplayId); + flinger->mutableHwcDisplayData()[*halDisplayId].hwcDisplay = std::move(display); EXPECT_CALL(*composer, getDisplayConfigs(mHwcDisplayId, _)) .WillRepeatedly( @@ -932,9 +936,10 @@ public: DoAll(SetArgPointee<3>(mConfigGroup), Return(hal::Error::NONE))); if (mHwcDisplayType == hal::DisplayType::PHYSICAL) { - const auto physicalId = PhysicalDisplayId::tryCast(mDisplayId); - LOG_ALWAYS_FATAL_IF(!physicalId); - flinger->mutableHwcPhysicalDisplayIdMap().emplace(mHwcDisplayId, *physicalId); + const auto physicalDisplayId = asPhysicalDisplayId(mDisplayIdVariant); + ASSERT_TRUE(physicalDisplayId); + flinger->mutableHwcPhysicalDisplayIdMap().emplace(mHwcDisplayId, + *physicalDisplayId); if (mIsPrimary) { flinger->mutablePrimaryHwcDisplayId() = mHwcDisplayId; } else { @@ -947,7 +952,7 @@ public: } private: - const HalDisplayId mDisplayId; + const DisplayIdVariant mDisplayIdVariant; const hal::DisplayType mHwcDisplayType; const bool mIsPrimary; @@ -983,8 +988,8 @@ public: sp<IBinder> token() const { return mDisplayToken; } auto physicalDisplay() const { - return ftl::Optional(mCreationArgs.compositionDisplay->getDisplayId()) - .and_then(&PhysicalDisplayId::tryCast) + return mCreationArgs.compositionDisplay->getDisplayIdVariant() + .and_then(asPhysicalDisplayId) .and_then(display::getPhysicalDisplay(mFlinger.physicalDisplays())); } @@ -1082,7 +1087,9 @@ public: DisplayDeviceState state; state.isSecure = mCreationArgs.isSecure; - if (const auto physicalId = PhysicalDisplayId::tryCast(*displayId)) { + if (const auto physicalId = + mCreationArgs.compositionDisplay->getDisplayIdVariant().and_then( + asPhysicalDisplayId)) { LOG_ALWAYS_FATAL_IF(!mConnectionType); LOG_ALWAYS_FATAL_IF(!mHwcDisplayId); diff --git a/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp b/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp index 21ee071f1b..3589553be0 100644 --- a/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp +++ b/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp @@ -22,6 +22,8 @@ #include <chrono> #include <thread> +#include <scheduler/Time.h> + #include "Scheduler/VsyncConfiguration.h" using namespace testing; @@ -39,6 +41,10 @@ public: : impl::WorkDuration(currentFps, sfDuration, appDuration, sfEarlyDuration, appEarlyDuration, sfEarlyGlDuration, appEarlyGlDuration, hwcMinWorkDuration) {} + + TestableWorkDuration(Fps currentFps, Duration minSfDuration, Duration maxSfDuration, + Duration appDuration) + : impl::WorkDuration(currentFps, minSfDuration, maxSfDuration, appDuration) {} }; class WorkDurationTest : public testing::Test { @@ -168,6 +174,35 @@ TEST_F(WorkDurationTest, minHwcWorkDuration) { EXPECT_EQ(mWorkDuration.getCurrentConfigs().hwcMinWorkDuration, 1234ns); } +TEST_F(WorkDurationTest, workDurationIsARange) { + const Duration minSfDuration = Duration::fromNs(10'500'000); + const Duration maxSfDuration = Duration::fromNs(20'500'000); + const Duration appDuration = Duration::fromNs(16'000'000); + const TestableWorkDuration workDuration{60_Hz, minSfDuration, maxSfDuration, appDuration}; + + auto currentOffsets = workDuration.getCurrentConfigs(); + auto offsets = workDuration.getConfigsForRefreshRate(60_Hz); + + EXPECT_EQ(currentOffsets, offsets); + EXPECT_EQ(offsets.late.sfOffset, 6'166'667); + EXPECT_EQ(offsets.late.appOffset, 6'833'334); + + EXPECT_EQ(offsets.late.sfWorkDuration, 10'500'000ns); + EXPECT_EQ(offsets.late.appWorkDuration, 16'000'000ns); + + EXPECT_EQ(offsets.early.sfOffset, -3'833'333); + EXPECT_EQ(offsets.early.appOffset, 13'500'001); + + EXPECT_EQ(offsets.early.sfWorkDuration, 20'500'000ns); + EXPECT_EQ(offsets.early.appWorkDuration, 16'000'000ns); + + EXPECT_EQ(offsets.earlyGpu.sfOffset, -3'833'333); + EXPECT_EQ(offsets.earlyGpu.appOffset, 13'500'001); + + EXPECT_EQ(offsets.earlyGpu.sfWorkDuration, 20'500'000ns); + EXPECT_EQ(offsets.earlyGpu.appWorkDuration, 16'000'000ns); +} + class TestablePhaseOffsets : public impl::PhaseOffsets { public: TestablePhaseOffsets(nsecs_t vsyncPhaseOffsetNs, nsecs_t sfVSyncPhaseOffsetNs, diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index 3036fec456..cce4d2aba8 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -55,7 +55,6 @@ public: MOCK_METHOD(void, onHdcpLevelsChanged, (PhysicalDisplayId displayId, int32_t connectedLevel, int32_t maxLevel), (override)); - MOCK_METHOD(void, addBufferStuffedUids, (BufferStuffingMap), (override)); }; } // namespace android::mock diff --git a/services/vibratorservice/Android.bp b/services/vibratorservice/Android.bp index ed03cfc3f5..4b12cc20a4 100644 --- a/services/vibratorservice/Android.bp +++ b/services/vibratorservice/Android.bp @@ -26,6 +26,7 @@ cc_library_shared { srcs: [ "VibratorCallbackScheduler.cpp", + "VibratorController.cpp", "VibratorHalController.cpp", "VibratorHalWrapper.cpp", "VibratorManagerHalController.cpp", @@ -41,17 +42,17 @@ cc_library_shared { }, shared_libs: [ + "android.hardware.vibrator-V3-ndk", "libbinder_ndk", "liblog", "libutils", - "android.hardware.vibrator-V3-ndk", ], cflags: [ "-Wall", "-Werror", - "-Wunused", "-Wunreachable-code", + "-Wunused", ], local_include_dirs: ["include"], diff --git a/services/vibratorservice/VibratorController.cpp b/services/vibratorservice/VibratorController.cpp new file mode 100644 index 0000000000..21924e9f13 --- /dev/null +++ b/services/vibratorservice/VibratorController.cpp @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "VibratorController" + +#ifndef qDoWithRetries +#define qDoWithRetries(op) doWithRetries(op, __FUNCTION__) +#endif + +#include <aidl/android/hardware/vibrator/IVibrator.h> +#include <android/binder_manager.h> +#include <binder/IServiceManager.h> + +#include <utils/Log.h> + +#include <vibratorservice/VibratorController.h> + +using ::aidl::android::hardware::vibrator::Effect; +using ::aidl::android::hardware::vibrator::EffectStrength; +using ::aidl::android::hardware::vibrator::IVibrator; + +using Status = ::ndk::ScopedAStatus; + +using namespace std::placeholders; + +namespace android { + +namespace vibrator { + +// ------------------------------------------------------------------------------------------------- + +inline bool isStatusUnsupported(const Status& status) { + // STATUS_UNKNOWN_TRANSACTION means the HAL is an older version, so operation is unsupported. + return status.getStatus() == STATUS_UNKNOWN_TRANSACTION || + status.getExceptionCode() == EX_UNSUPPORTED_OPERATION; +} + +inline bool isStatusTransactionFailed(const Status& status) { + // STATUS_UNKNOWN_TRANSACTION means the HAL is an older version, so operation is unsupported. + return status.getStatus() != STATUS_UNKNOWN_TRANSACTION && + status.getExceptionCode() == EX_TRANSACTION_FAILED; +} + +// ------------------------------------------------------------------------------------------------- + +bool VibratorProvider::isDeclared() { + std::lock_guard<std::mutex> lock(mMutex); + if (mIsDeclared.has_value()) { + return *mIsDeclared; + } + + bool isDeclared = AServiceManager_isDeclared(mServiceName.c_str()); + if (!isDeclared) { + ALOGV("Vibrator HAL service not declared."); + } + + mIsDeclared.emplace(isDeclared); + return isDeclared; +} + +std::shared_ptr<IVibrator> VibratorProvider::waitForVibrator() { + if (!isDeclared()) { + return nullptr; + } + + auto vibrator = IVibrator::fromBinder( + ndk::SpAIBinder(AServiceManager_waitForService(mServiceName.c_str()))); + if (vibrator) { + ALOGV("Successfully connected to Vibrator HAL service."); + } else { + ALOGE("Error connecting to declared Vibrator HAL service."); + } + + return vibrator; +} + +std::shared_ptr<IVibrator> VibratorProvider::checkForVibrator() { + if (!isDeclared()) { + return nullptr; + } + + auto vibrator = IVibrator::fromBinder( + ndk::SpAIBinder(AServiceManager_checkService(mServiceName.c_str()))); + if (vibrator) { + ALOGV("Successfully reconnected to Vibrator HAL service."); + } else { + ALOGE("Error reconnecting to declared Vibrator HAL service."); + } + + return vibrator; +} + +// ------------------------------------------------------------------------------------------------- + +bool VibratorController::init() { + if (!mVibratorProvider->isDeclared()) { + return false; + } + std::lock_guard<std::mutex> lock(mMutex); + if (mVibrator == nullptr) { + mVibrator = mVibratorProvider->waitForVibrator(); + } + return mVibratorProvider->isDeclared(); +} + +Status VibratorController::off() { + return qDoWithRetries(std::bind(&IVibrator::off, _1)); +} + +Status VibratorController::setAmplitude(float amplitude) { + return qDoWithRetries(std::bind(&IVibrator::setAmplitude, _1, amplitude)); +} + +Status VibratorController::setExternalControl(bool enabled) { + return qDoWithRetries(std::bind(&IVibrator::setExternalControl, _1, enabled)); +} + +Status VibratorController::alwaysOnEnable(int32_t id, const Effect& effect, + const EffectStrength& strength) { + return qDoWithRetries(std::bind(&IVibrator::alwaysOnEnable, _1, id, effect, strength)); +} + +Status VibratorController::alwaysOnDisable(int32_t id) { + return qDoWithRetries(std::bind(&IVibrator::alwaysOnDisable, _1, id)); +} + +// ------------------------------------------------------------------------------------------------- + +std::shared_ptr<IVibrator> VibratorController::reconnectToVibrator() { + std::lock_guard<std::mutex> lock(mMutex); + mVibrator = mVibratorProvider->checkForVibrator(); + return mVibrator; +} + +Status VibratorController::doWithRetries(const VibratorController::VibratorOp& op, + const char* logLabel) { + if (!init()) { + ALOGV("Skipped %s because Vibrator HAL is not declared", logLabel); + return Status::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE, "IVibrator not declared"); + } + std::shared_ptr<IVibrator> vibrator; + { + std::lock_guard<std::mutex> lock(mMutex); + vibrator = mVibrator; + } + + if (!vibrator) { + ALOGE("Skipped %s because Vibrator HAL is declared but failed to load", logLabel); + return Status::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE, + "IVibrator declared but failed to load"); + } + + auto status = doOnce(vibrator.get(), op, logLabel); + for (int i = 1; i < MAX_ATTEMPTS && isStatusTransactionFailed(status); i++) { + vibrator = reconnectToVibrator(); + if (!vibrator) { + // Failed to reconnect to vibrator HAL after a transaction failed, skip retries. + break; + } + status = doOnce(vibrator.get(), op, logLabel); + } + + return status; +} + +Status VibratorController::doOnce(IVibrator* vibrator, const VibratorController::VibratorOp& op, + const char* logLabel) { + auto status = op(vibrator); + if (!status.isOk()) { + if (isStatusUnsupported(status)) { + ALOGV("Vibrator HAL %s is unsupported: %s", logLabel, status.getMessage()); + } else { + ALOGE("Vibrator HAL %s failed: %s", logLabel, status.getMessage()); + } + } + return status; +} + +// ------------------------------------------------------------------------------------------------- + +}; // namespace vibrator + +}; // namespace android diff --git a/services/vibratorservice/include/vibratorservice/VibratorController.h b/services/vibratorservice/include/vibratorservice/VibratorController.h new file mode 100644 index 0000000000..691c8ae518 --- /dev/null +++ b/services/vibratorservice/include/vibratorservice/VibratorController.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_OS_VIBRATOR_CONTROLLER_H +#define ANDROID_OS_VIBRATOR_CONTROLLER_H + +#include <aidl/android/hardware/vibrator/IVibrator.h> + +#include <android-base/thread_annotations.h> + +namespace android { + +namespace vibrator { + +// ------------------------------------------------------------------------------------------------- + +/* Provider for IVibrator HAL service instances. */ +class VibratorProvider { +public: + using IVibrator = ::aidl::android::hardware::vibrator::IVibrator; + + VibratorProvider() : mServiceName(std::string(IVibrator::descriptor) + "/default") {} + virtual ~VibratorProvider() = default; + + /* Returns true if vibrator HAL service is declared in the device, false otherwise. */ + virtual bool isDeclared(); + + /* Connects to vibrator HAL, possibly waiting for the declared service to become available. */ + virtual std::shared_ptr<IVibrator> waitForVibrator(); + + /* Connects to vibrator HAL if declared and available, without waiting. */ + virtual std::shared_ptr<IVibrator> checkForVibrator(); + +private: + std::mutex mMutex; + const std::string mServiceName; + std::optional<bool> mIsDeclared GUARDED_BY(mMutex); +}; + +// ------------------------------------------------------------------------------------------------- + +/* Controller for Vibrator HAL handle. + * This relies on VibratorProvider to connect to the underlying Vibrator HAL service and reconnects + * after each transaction failed call. This also ensures connecting to the service is thread-safe. + */ +class VibratorController { +public: + using Effect = ::aidl::android::hardware::vibrator::Effect; + using EffectStrength = ::aidl::android::hardware::vibrator::EffectStrength; + using IVibrator = ::aidl::android::hardware::vibrator::IVibrator; + using Status = ::ndk::ScopedAStatus; + using VibratorOp = std::function<Status(IVibrator*)>; + + VibratorController() : VibratorController(std::make_shared<VibratorProvider>()) {} + VibratorController(std::shared_ptr<VibratorProvider> vibratorProvider) + : mVibratorProvider(std::move(vibratorProvider)), mVibrator(nullptr) {} + virtual ~VibratorController() = default; + + /* Connects HAL service, possibly waiting for the declared service to become available. + * This will automatically be called at the first API usage if it was not manually called + * beforehand. Call this manually during the setup phase to avoid slowing the first API call. + * Returns true if HAL service is declared, false otherwise. + */ + bool init(); + + /* Turn vibrator off. */ + Status off(); + + /* Set vibration amplitude in [0,1]. */ + Status setAmplitude(float amplitude); + + /* Enable/disable external control. */ + Status setExternalControl(bool enabled); + + /* Enable always-on for given id, with given effect and strength. */ + Status alwaysOnEnable(int32_t id, const Effect& effect, const EffectStrength& strength); + + /* Disable always-on for given id. */ + Status alwaysOnDisable(int32_t id); + +private: + /* Max number of attempts to perform an operation when it fails with transaction error. */ + static constexpr int MAX_ATTEMPTS = 2; + + std::mutex mMutex; + std::shared_ptr<VibratorProvider> mVibratorProvider; + std::shared_ptr<IVibrator> mVibrator GUARDED_BY(mMutex); + + /* Reconnects HAL service without waiting for the service to become available. */ + std::shared_ptr<IVibrator> reconnectToVibrator(); + + /* Perform given operation on HAL with retries on transaction failures. */ + Status doWithRetries(const VibratorOp& op, const char* logLabel); + + /* Perform given operation on HAL with logs for error/unsupported results. */ + static Status doOnce(IVibrator* vibrator, const VibratorOp& op, const char* logLabel); +}; + +// ------------------------------------------------------------------------------------------------- + +}; // namespace vibrator + +}; // namespace android + +#endif // ANDROID_OS_VIBRATOR_CONTROLLER_H diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalController.h b/services/vibratorservice/include/vibratorservice/VibratorHalController.h index a1cb3fad35..9b3202bc60 100644 --- a/services/vibratorservice/include/vibratorservice/VibratorHalController.h +++ b/services/vibratorservice/include/vibratorservice/VibratorHalController.h @@ -14,6 +14,8 @@ * limitations under the License. */ +// TODO(b/308452413): remove this file once android.os.vibrator.remove_hidl_support is removed + #ifndef ANDROID_OS_VIBRATORHALCONTROLLER_H #define ANDROID_OS_VIBRATORHALCONTROLLER_H diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h index 065227861d..68568d4163 100644 --- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h +++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h @@ -14,6 +14,8 @@ * limitations under the License. */ +// TODO(b/308452413): remove this file once android.os.vibrator.remove_hidl_support is removed + #ifndef ANDROID_OS_VIBRATORHALWRAPPER_H #define ANDROID_OS_VIBRATORHALWRAPPER_H diff --git a/services/vibratorservice/test/Android.bp b/services/vibratorservice/test/Android.bp index 038248e636..92c6286513 100644 --- a/services/vibratorservice/test/Android.bp +++ b/services/vibratorservice/test/Android.bp @@ -27,6 +27,7 @@ cc_test { test_suites: ["device-tests"], srcs: [ "VibratorCallbackSchedulerTest.cpp", + "VibratorControllerTest.cpp", "VibratorHalControllerTest.cpp", "VibratorHalWrapperAidlTest.cpp", "VibratorManagerHalControllerTest.cpp", @@ -39,12 +40,12 @@ cc_test { "-Wextra", ], shared_libs: [ + "android.hardware.vibrator-V3-ndk", "libbase", "libbinder_ndk", "liblog", - "libvibratorservice", "libutils", - "android.hardware.vibrator-V3-ndk", + "libvibratorservice", ], static_libs: [ "libgmock", diff --git a/services/vibratorservice/test/VibratorControllerTest.cpp b/services/vibratorservice/test/VibratorControllerTest.cpp new file mode 100644 index 0000000000..11ec75bc36 --- /dev/null +++ b/services/vibratorservice/test/VibratorControllerTest.cpp @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "VibratorControllerTest" + +#include <aidl/android/hardware/vibrator/IVibrator.h> + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include <utils/Log.h> +#include <thread> + +#include <vibratorservice/VibratorController.h> + +#include "test_mocks.h" +#include "test_utils.h" + +using ::aidl::android::hardware::vibrator::Effect; +using ::aidl::android::hardware::vibrator::EffectStrength; +using ::aidl::android::hardware::vibrator::IVibrator; + +using namespace android; +using namespace testing; + +const auto kReturnOk = []() { return ndk::ScopedAStatus::ok(); }; +const auto kReturnUnsupported = []() { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +}; +const auto kReturnTransactionFailed = []() { + return ndk::ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED); +}; +const auto kReturnUnknownTransaction = []() { + return ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION); +}; +const auto kReturnIllegalArgument = []() { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); +}; + +// ------------------------------------------------------------------------------------------------- + +/* Provides mock IVibrator instance for testing. */ +class FakeVibratorProvider : public vibrator::VibratorProvider { +public: + FakeVibratorProvider() + : mIsDeclared(true), + mMockVibrator(ndk::SharedRefBase::make<StrictMock<vibrator::MockIVibrator>>()), + mConnectCount(0), + mReconnectCount(0) {} + virtual ~FakeVibratorProvider() = default; + + bool isDeclared() override { return mIsDeclared; } + + std::shared_ptr<IVibrator> waitForVibrator() override { + mConnectCount++; + return mIsDeclared ? mMockVibrator : nullptr; + } + + std::shared_ptr<IVibrator> checkForVibrator() override { + mReconnectCount++; + return mIsDeclared ? mMockVibrator : nullptr; + } + + void setDeclared(bool isDeclared) { mIsDeclared = isDeclared; } + + int32_t getConnectCount() { return mConnectCount; } + + int32_t getReconnectCount() { return mReconnectCount; } + + std::shared_ptr<StrictMock<vibrator::MockIVibrator>> getMockVibrator() { return mMockVibrator; } + +private: + bool mIsDeclared; + std::shared_ptr<StrictMock<vibrator::MockIVibrator>> mMockVibrator; + int32_t mConnectCount; + int32_t mReconnectCount; +}; + +// ------------------------------------------------------------------------------------------------- + +class VibratorControllerTest : public Test { +public: + void SetUp() override { + mProvider = std::make_shared<FakeVibratorProvider>(); + mController = std::make_unique<vibrator::VibratorController>(mProvider); + ASSERT_NE(mController, nullptr); + } + +protected: + std::shared_ptr<FakeVibratorProvider> mProvider = nullptr; + std::unique_ptr<vibrator::VibratorController> mController = nullptr; +}; + +// ------------------------------------------------------------------------------------------------- + +TEST_F(VibratorControllerTest, TestInitServiceDeclared) { + ASSERT_TRUE(mController->init()); + ASSERT_EQ(1, mProvider->getConnectCount()); + ASSERT_EQ(0, mProvider->getReconnectCount()); + + // Noop when wrapper was already initialized. + ASSERT_TRUE(mController->init()); + ASSERT_EQ(1, mProvider->getConnectCount()); + ASSERT_EQ(0, mProvider->getReconnectCount()); +} + +TEST_F(VibratorControllerTest, TestInitServiceNotDeclared) { + mProvider->setDeclared(false); + + ASSERT_FALSE(mController->init()); + ASSERT_EQ(0, mProvider->getConnectCount()); + ASSERT_EQ(0, mProvider->getReconnectCount()); + + ASSERT_FALSE(mController->init()); + ASSERT_EQ(0, mProvider->getConnectCount()); + ASSERT_EQ(0, mProvider->getReconnectCount()); +} + +TEST_F(VibratorControllerTest, TestFirstCallTriggersInit) { + EXPECT_CALL(*mProvider->getMockVibrator().get(), off()) + .Times(Exactly(1)) + .WillRepeatedly(kReturnOk); + + auto status = mController->off(); + ASSERT_TRUE(status.isOk()); + ASSERT_EQ(1, mProvider->getConnectCount()); +} + +TEST_F(VibratorControllerTest, TestSuccessfulResultDoesNotRetry) { + EXPECT_CALL(*mProvider->getMockVibrator().get(), off()) + .Times(Exactly(1)) + .WillRepeatedly(kReturnOk); + + auto status = mController->off(); + ASSERT_TRUE(status.isOk()); + ASSERT_EQ(0, mProvider->getReconnectCount()); +} + +TEST_F(VibratorControllerTest, TestUnsupportedOperationResultDoesNotRetry) { + EXPECT_CALL(*mProvider->getMockVibrator().get(), off()) + .Times(Exactly(1)) + .WillRepeatedly(kReturnUnsupported); + + auto status = mController->off(); + ASSERT_FALSE(status.isOk()); + ASSERT_EQ(0, mProvider->getReconnectCount()); +} + +TEST_F(VibratorControllerTest, TestUnknownTransactionResultDoesNotRetry) { + EXPECT_CALL(*mProvider->getMockVibrator().get(), off()) + .Times(Exactly(1)) + .WillRepeatedly(kReturnUnknownTransaction); + + auto status = mController->off(); + ASSERT_FALSE(status.isOk()); + ASSERT_EQ(0, mProvider->getReconnectCount()); +} + +TEST_F(VibratorControllerTest, TestOperationFailedDoesNotRetry) { + EXPECT_CALL(*mProvider->getMockVibrator().get(), off()) + .Times(Exactly(1)) + .WillRepeatedly(kReturnIllegalArgument); + + auto status = mController->off(); + ASSERT_FALSE(status.isOk()); + ASSERT_EQ(0, mProvider->getReconnectCount()); +} + +TEST_F(VibratorControllerTest, TestTransactionFailedRetriesOnlyOnce) { + EXPECT_CALL(*mProvider->getMockVibrator().get(), off()) + .Times(Exactly(2)) + .WillRepeatedly(kReturnTransactionFailed); + + auto status = mController->off(); + ASSERT_FALSE(status.isOk()); + ASSERT_EQ(1, mProvider->getReconnectCount()); +} + +TEST_F(VibratorControllerTest, TestTransactionFailedThenSucceedsReturnsSuccessAfterRetries) { + EXPECT_CALL(*mProvider->getMockVibrator().get(), off()) + .Times(Exactly(2)) + .WillOnce(kReturnTransactionFailed) + .WillRepeatedly(kReturnOk); + + auto status = mController->off(); + ASSERT_TRUE(status.isOk()); + ASSERT_EQ(1, mProvider->getReconnectCount()); +} + +TEST_F(VibratorControllerTest, TestOff) { + EXPECT_CALL(*mProvider->getMockVibrator().get(), off()) + .Times(Exactly(1)) + .WillRepeatedly(kReturnOk); + + auto status = mController->off(); + ASSERT_TRUE(status.isOk()); +} + +TEST_F(VibratorControllerTest, TestSetAmplitude) { + EXPECT_CALL(*mProvider->getMockVibrator().get(), setAmplitude(Eq(0.1f))) + .Times(Exactly(1)) + .WillRepeatedly(kReturnOk); + EXPECT_CALL(*mProvider->getMockVibrator().get(), setAmplitude(Eq(0.2f))) + .Times(Exactly(1)) + .WillRepeatedly(kReturnIllegalArgument); + + ASSERT_TRUE(mController->setAmplitude(0.1f).isOk()); + ASSERT_FALSE(mController->setAmplitude(0.2f).isOk()); +} + +TEST_F(VibratorControllerTest, TestSetExternalControl) { + EXPECT_CALL(*mProvider->getMockVibrator().get(), setExternalControl(Eq(false))) + .Times(Exactly(1)) + .WillRepeatedly(kReturnOk); + EXPECT_CALL(*mProvider->getMockVibrator().get(), setExternalControl(Eq(true))) + .Times(Exactly(1)) + .WillRepeatedly(kReturnIllegalArgument); + + ASSERT_TRUE(mController->setExternalControl(false).isOk()); + ASSERT_FALSE(mController->setExternalControl(true).isOk()); +} + +TEST_F(VibratorControllerTest, TestAlwaysOnEnable) { + EXPECT_CALL(*mProvider->getMockVibrator().get(), + alwaysOnEnable(Eq(1), Eq(Effect::CLICK), Eq(EffectStrength::LIGHT))) + .Times(Exactly(1)) + .WillRepeatedly(kReturnOk); + EXPECT_CALL(*mProvider->getMockVibrator().get(), + alwaysOnEnable(Eq(2), Eq(Effect::TICK), Eq(EffectStrength::MEDIUM))) + .Times(Exactly(1)) + .WillRepeatedly(kReturnIllegalArgument); + + ASSERT_TRUE(mController->alwaysOnEnable(1, Effect::CLICK, EffectStrength::LIGHT).isOk()); + ASSERT_FALSE(mController->alwaysOnEnable(2, Effect::TICK, EffectStrength::MEDIUM).isOk()); +} diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp index be8fb3ea1d..d75058abe3 100644 --- a/vulkan/libvulkan/Android.bp +++ b/vulkan/libvulkan/Android.bp @@ -48,14 +48,9 @@ cc_aconfig_library { aconfig_declarations: "libvulkan_flags", } -cc_library_shared { - name: "libvulkan", - llndk: { - symbol_file: "libvulkan.map.txt", - export_llndk_headers: [ - "vulkan_headers", - ], - }, +cc_defaults { + name: "libvulkan_defaults", + sanitize: { misc_undefined: ["integer"], }, @@ -88,6 +83,34 @@ cc_library_shared { "-Wno-global-constructors", "-Wno-zero-length-array", ], +} + +cc_library { + name: "libvulkanallocator", + defaults: ["libvulkan_defaults"], + cflags: [ + // This code uses malloc_usable_size(), + // and thus can't be built with _FORTIFY_SOURCE=3. + "-U_FORTIFY_SOURCE", + "-D_FORTIFY_SOURCE=2", + ], + srcs: [ + "allocator.cpp", + ], + header_libs: [ + "vulkan_headers", + ], +} + +cc_library_shared { + name: "libvulkan", + defaults: ["libvulkan_defaults"], + llndk: { + symbol_file: "libvulkan.map.txt", + export_llndk_headers: [ + "vulkan_headers", + ], + }, srcs: [ "api.cpp", @@ -131,6 +154,7 @@ cc_library_shared { ], static_libs: [ "libgrallocusage", + "libvulkanallocator", "libvulkanflags", ], } diff --git a/vulkan/libvulkan/allocator.cpp b/vulkan/libvulkan/allocator.cpp new file mode 100644 index 0000000000..2ca0586a14 --- /dev/null +++ b/vulkan/libvulkan/allocator.cpp @@ -0,0 +1,113 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include "allocator.h" + +#include <stdlib.h> + +#include <algorithm> + +#include <log/log.h> + +// #define ENABLE_ALLOC_CALLSTACKS 1 +#if ENABLE_ALLOC_CALLSTACKS +#include <utils/CallStack.h> +#define ALOGD_CALLSTACK(...) \ + do { \ + ALOGD(__VA_ARGS__); \ + android::CallStack callstack; \ + callstack.update(); \ + callstack.log(LOG_TAG, ANDROID_LOG_DEBUG, " "); \ + } while (false) +#else +#define ALOGD_CALLSTACK(...) \ + do { \ + } while (false) +#endif + +namespace vulkan { +namespace driver { + +namespace { + +VKAPI_ATTR void* DefaultAllocate(void*, + size_t size, + size_t alignment, + VkSystemAllocationScope) { + void* ptr = nullptr; + // Vulkan requires 'alignment' to be a power of two, but posix_memalign + // additionally requires that it be at least sizeof(void*). + int ret = posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size); + ALOGD_CALLSTACK("Allocate: size=%zu align=%zu => (%d) %p", size, alignment, + ret, ptr); + return ret == 0 ? ptr : nullptr; +} + +// This function is marked `noinline` so that LLVM can't infer an object size +// for FORTIFY through it, given that it's abusing malloc_usable_size(). +__attribute__((__noinline__)) +VKAPI_ATTR void* DefaultReallocate(void*, + void* ptr, + size_t size, + size_t alignment, + VkSystemAllocationScope) { + if (size == 0) { + free(ptr); + return nullptr; + } + + // TODO(b/143295633): Right now we never shrink allocations; if the new + // request is smaller than the existing chunk, we just continue using it. + // Right now the loader never reallocs, so this doesn't matter. If that + // changes, or if this code is copied into some other project, this should + // probably have a heuristic to allocate-copy-free when doing so will save + // "enough" space. + size_t old_size = ptr ? malloc_usable_size(ptr) : 0; + if (size <= old_size) + return ptr; + + void* new_ptr = nullptr; + if (posix_memalign(&new_ptr, std::max(alignment, sizeof(void*)), size) != 0) + return nullptr; + if (ptr) { + memcpy(new_ptr, ptr, std::min(old_size, size)); + free(ptr); + } + return new_ptr; +} + +VKAPI_ATTR void DefaultFree(void*, void* ptr) { + ALOGD_CALLSTACK("Free: %p", ptr); + free(ptr); +} + +} // anonymous namespace + +const VkAllocationCallbacks& GetDefaultAllocator() { + static const VkAllocationCallbacks kDefaultAllocCallbacks = { + .pUserData = nullptr, + .pfnAllocation = DefaultAllocate, + .pfnReallocation = DefaultReallocate, + .pfnFree = DefaultFree, + }; + + return kDefaultAllocCallbacks; +} + +} // namespace driver +} // namespace vulkan diff --git a/vulkan/libvulkan/allocator.h b/vulkan/libvulkan/allocator.h new file mode 100644 index 0000000000..9095e921c5 --- /dev/null +++ b/vulkan/libvulkan/allocator.h @@ -0,0 +1,25 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <vulkan/vulkan.h> + +namespace vulkan { +namespace driver { + +const VkAllocationCallbacks& GetDefaultAllocator(); + +} // namespace driver +} // namespace vulkan diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index 7d0f545774..28c1b5f663 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -50,22 +50,6 @@ using namespace com::android::graphics::libvulkan; extern "C" android_namespace_t* android_get_exported_namespace(const char*); -// #define ENABLE_ALLOC_CALLSTACKS 1 -#if ENABLE_ALLOC_CALLSTACKS -#include <utils/CallStack.h> -#define ALOGD_CALLSTACK(...) \ - do { \ - ALOGD(__VA_ARGS__); \ - android::CallStack callstack; \ - callstack.update(); \ - callstack.log(LOG_TAG, ANDROID_LOG_DEBUG, " "); \ - } while (false) -#else -#define ALOGD_CALLSTACK(...) \ - do { \ - } while (false) -#endif - namespace vulkan { namespace driver { @@ -829,54 +813,6 @@ void CreateInfoWrapper::FilterExtension(const char* name) { } } -VKAPI_ATTR void* DefaultAllocate(void*, - size_t size, - size_t alignment, - VkSystemAllocationScope) { - void* ptr = nullptr; - // Vulkan requires 'alignment' to be a power of two, but posix_memalign - // additionally requires that it be at least sizeof(void*). - int ret = posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size); - ALOGD_CALLSTACK("Allocate: size=%zu align=%zu => (%d) %p", size, alignment, - ret, ptr); - return ret == 0 ? ptr : nullptr; -} - -VKAPI_ATTR void* DefaultReallocate(void*, - void* ptr, - size_t size, - size_t alignment, - VkSystemAllocationScope) { - if (size == 0) { - free(ptr); - return nullptr; - } - - // TODO(b/143295633): Right now we never shrink allocations; if the new - // request is smaller than the existing chunk, we just continue using it. - // Right now the loader never reallocs, so this doesn't matter. If that - // changes, or if this code is copied into some other project, this should - // probably have a heuristic to allocate-copy-free when doing so will save - // "enough" space. - size_t old_size = ptr ? malloc_usable_size(ptr) : 0; - if (size <= old_size) - return ptr; - - void* new_ptr = nullptr; - if (posix_memalign(&new_ptr, std::max(alignment, sizeof(void*)), size) != 0) - return nullptr; - if (ptr) { - memcpy(new_ptr, ptr, std::min(old_size, size)); - free(ptr); - } - return new_ptr; -} - -VKAPI_ATTR void DefaultFree(void*, void* ptr) { - ALOGD_CALLSTACK("Free: %p", ptr); - free(ptr); -} - InstanceData* AllocateInstanceData(const VkAllocationCallbacks& allocator) { void* data_mem = allocator.pfnAllocation( allocator.pUserData, sizeof(InstanceData), alignof(InstanceData), @@ -916,17 +852,6 @@ bool OpenHAL() { return Hal::Open(); } -const VkAllocationCallbacks& GetDefaultAllocator() { - static const VkAllocationCallbacks kDefaultAllocCallbacks = { - .pUserData = nullptr, - .pfnAllocation = DefaultAllocate, - .pfnReallocation = DefaultReallocate, - .pfnFree = DefaultFree, - }; - - return kDefaultAllocCallbacks; -} - PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName) { const ProcHook* hook = GetProcHook(pName); if (!hook) diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h index 4b855e5999..fa85dd5b55 100644 --- a/vulkan/libvulkan/driver.h +++ b/vulkan/libvulkan/driver.h @@ -27,6 +27,7 @@ #include <vulkan/vulkan.h> #include <hardware/hwvulkan.h> +#include "allocator.h" #include "api_gen.h" #include "driver_gen.h" #include "debug_report.h" @@ -102,7 +103,6 @@ struct DeviceData { }; bool OpenHAL(); -const VkAllocationCallbacks& GetDefaultAllocator(); void QueryPresentationProperties( VkPhysicalDevice physicalDevice, diff --git a/vulkan/scripts/code_generator.py b/vulkan/scripts/code_generator.py index 2a017d2259..051816de87 100755 --- a/vulkan/scripts/code_generator.py +++ b/vulkan/scripts/code_generator.py @@ -21,6 +21,7 @@ import api_generator import driver_generator import generator_common import null_generator +import vkjson_generator if __name__ == '__main__': generator_common.parse_vulkan_registry() @@ -30,3 +31,6 @@ if __name__ == '__main__': driver_generator.gen_cpp() null_generator.gen_h() null_generator.gen_cpp() + vkjson_generator.gen_h() + vkjson_generator.gen_cc() + vkjson_generator.gen_instance_cc() diff --git a/vulkan/scripts/vk.py b/vulkan/scripts/vk.py new file mode 100644 index 0000000000..983e0dc296 --- /dev/null +++ b/vulkan/scripts/vk.py @@ -0,0 +1,968 @@ +import ctypes +import dataclasses +import enum +from typing import List + +dataclass = dataclasses.dataclass +Enum = enum.Enum + +# TODO(b/401184058): Automate this file for generating the vulkan structs graph from vk.xml +VK_UUID_SIZE = 16 +VK_LUID_SIZE = 16 + +VkImageLayout = Enum +uint8_t = ctypes.c_uint8 +uint32_t = ctypes.c_uint32 +VkFlags = uint32_t +VkMemoryPropertyFlags = VkFlags +VkMemoryHeapFlags = VkFlags +int32_t = int +uint64_t = ctypes.c_uint64 +VkBool32 = bool +VkDeviceSize = ctypes.c_uint64 +size_t = int +VkSampleCountFlags = ctypes.c_uint32 +VkFormatFeatureFlags = ctypes.c_uint32 +VkQueueFlags = ctypes.c_uint32 +VkShaderStageFlags = ctypes.c_uint32 +VkSubgroupFeatureFlags = ctypes.c_uint32 +VkResolveModeFlags = ctypes.c_uint32 +float_t = ctypes.c_float +VkShaderFloatControlsIndependence = Enum +VkPointClippingBehavior = Enum +VkPhysicalDeviceType = Enum +VkDriverId = Enum +VkPipelineRobustnessBufferBehavior = Enum + + +@dataclass +class ConformanceVersion: + major: uint8_t + minor: uint8_t + subminor: uint8_t + patch: uint8_t + + +@dataclass +class VkExtent3D: + width: uint32_t + height: uint32_t + depth: uint32_t + + +@dataclass +class VkPhysicalDeviceLimits: + maxImageDimension1D: uint32_t + maxImageDimension2D: uint32_t + maxImageDimension3D: uint32_t + maxImageDimensionCube: uint32_t + maxImageArrayLayers: uint32_t + maxTexelBufferElements: uint32_t + maxUniformBufferRange: uint32_t + maxStorageBufferRange: uint32_t + maxPushConstantsSize: uint32_t + maxMemoryAllocationCount: uint32_t + maxSamplerAllocationCount: uint32_t + bufferImageGranularity: VkDeviceSize + sparseAddressSpaceSize: VkDeviceSize + maxBoundDescriptorSets: uint32_t + maxPerStageDescriptorSamplers: uint32_t + maxPerStageDescriptorUniformBuffers: uint32_t + maxPerStageDescriptorStorageBuffers: uint32_t + maxPerStageDescriptorSampledImages: uint32_t + maxPerStageDescriptorStorageImages: uint32_t + maxPerStageDescriptorInputAttachments: uint32_t + maxPerStageResources: uint32_t + maxDescriptorSetSamplers: uint32_t + maxDescriptorSetUniformBuffers: uint32_t + maxDescriptorSetUniformBuffersDynamic: uint32_t + maxDescriptorSetStorageBuffers: uint32_t + maxDescriptorSetStorageBuffersDynamic: uint32_t + maxDescriptorSetSampledImages: uint32_t + maxDescriptorSetStorageImages: uint32_t + maxDescriptorSetInputAttachments: uint32_t + maxVertexInputAttributes: uint32_t + maxVertexInputBindings: uint32_t + maxVertexInputAttributeOffset: uint32_t + maxVertexInputBindingStride: uint32_t + maxVertexOutputComponents: uint32_t + maxTessellationGenerationLevel: uint32_t + maxTessellationPatchSize: uint32_t + maxTessellationControlPerVertexInputComponents: uint32_t + maxTessellationControlPerVertexOutputComponents: uint32_t + maxTessellationControlPerPatchOutputComponents: uint32_t + maxTessellationControlTotalOutputComponents: uint32_t + maxTessellationEvaluationInputComponents: uint32_t + maxTessellationEvaluationOutputComponents: uint32_t + maxGeometryShaderInvocations: uint32_t + maxGeometryInputComponents: uint32_t + maxGeometryOutputComponents: uint32_t + maxGeometryOutputVertices: uint32_t + maxGeometryTotalOutputComponents: uint32_t + maxFragmentInputComponents: uint32_t + maxFragmentOutputAttachments: uint32_t + maxFragmentDualSrcAttachments: uint32_t + maxFragmentCombinedOutputResources: uint32_t + maxComputeSharedMemorySize: uint32_t + maxComputeWorkGroupCount: uint32_t*3 + maxComputeWorkGroupInvocations: uint32_t + maxComputeWorkGroupSize: uint32_t*3 + subPixelPrecisionBits: uint32_t + subTexelPrecisionBits: uint32_t + mipmapPrecisionBits: uint32_t + maxDrawIndexedIndexValue: uint32_t + maxDrawIndirectCount: uint32_t + maxSamplerLodBias: float + maxSamplerAnisotropy: float + maxViewports: uint32_t + maxViewportDimensions: uint32_t*2 + viewportBoundsRange: float_t*2 + viewportSubPixelBits: uint32_t + minMemoryMapAlignment: size_t + minTexelBufferOffsetAlignment: VkDeviceSize + minUniformBufferOffsetAlignment: VkDeviceSize + minStorageBufferOffsetAlignment: VkDeviceSize + minTexelOffset: int32_t + maxTexelOffset: uint32_t + minTexelGatherOffset: int32_t + maxTexelGatherOffset: uint32_t + minInterpolationOffset: float + maxInterpolationOffset: float + subPixelInterpolationOffsetBits: uint32_t + maxFramebufferWidth: uint32_t + maxFramebufferHeight: uint32_t + maxFramebufferLayers: uint32_t + framebufferColorSampleCounts: VkSampleCountFlags + framebufferDepthSampleCounts: VkSampleCountFlags + framebufferStencilSampleCounts: VkSampleCountFlags + framebufferNoAttachmentsSampleCounts: VkSampleCountFlags + maxColorAttachments: uint32_t + sampledImageColorSampleCounts: VkSampleCountFlags + sampledImageIntegerSampleCounts: VkSampleCountFlags + sampledImageDepthSampleCounts: VkSampleCountFlags + sampledImageStencilSampleCounts: VkSampleCountFlags + storageImageSampleCounts: VkSampleCountFlags + maxSampleMaskWords: uint32_t + timestampComputeAndGraphics: VkBool32 + timestampPeriod: float + maxClipDistances: uint32_t + maxCullDistances: uint32_t + maxCombinedClipAndCullDistances: uint32_t + discreteQueuePriorities: uint32_t + pointSizeRange: float_t*2 + lineWidthRange: float_t*2 + pointSizeGranularity: float + lineWidthGranularity: float + strictLines: VkBool32 + standardSampleLocations: VkBool32 + optimalBufferCopyOffsetAlignment: VkDeviceSize + optimalBufferCopyRowPitchAlignment: VkDeviceSize + nonCoherentAtomSize: VkDeviceSize + + +@dataclass +class VkPhysicalDeviceShaderDrawParameterFeatures: + shaderDrawParameters: VkBool32 + + +@dataclass +class VkExtensionProperties: + extensionName: str + specVersion: uint32_t + + +@dataclass +class VkFormatProperties: + linearTilingFeatures: VkFormatFeatureFlags + optimalTilingFeatures: VkFormatFeatureFlags + bufferFeatures: VkFormatFeatureFlags + + +@dataclass +class VkLayerProperties: + layerName: str + specVersion: uint32_t + implementationVersion: uint32_t + description: str + + +@dataclass +class VkQueueFamilyProperties: + queueFlags: VkQueueFlags + queueCount: uint32_t + timestampValidBits: uint32_t + minImageTransferGranularity: VkExtent3D + + +@dataclass +class VkPhysicalDeviceSparseProperties: + residencyStandard2DBlockShape: VkBool32 + residencyStandard2DMultisampleBlockShape: VkBool32 + residencyStandard3DBlockShape: VkBool32 + residencyAlignedMipSize: VkBool32 + residencyNonResidentStrict: VkBool32 + + +@dataclass +class VkImageFormatProperties: + maxExtent: VkExtent3D + maxMipLevels: uint32_t + maxArrayLayers: uint32_t + sampleCounts: VkSampleCountFlags + maxResourceSize: VkDeviceSize + + +@dataclass +class VkPhysicalDeviceSamplerYcbcrConversionFeatures: + samplerYcbcrConversion: VkBool32 + + +@dataclass +class VkPhysicalDeviceIDProperties: + deviceUUID: uint8_t*VK_UUID_SIZE + driverUUID: uint8_t*VK_UUID_SIZE + deviceLUID: uint8_t*VK_LUID_SIZE + deviceNodeMask: uint32_t + deviceLUIDValid: VkBool32 + + +@dataclass +class VkPhysicalDeviceMaintenance3Properties: + maxPerSetDescriptors: uint32_t + maxMemoryAllocationSize: VkDeviceSize + + +@dataclass +class VkPhysicalDevice16BitStorageFeatures: + storageBuffer16BitAccess: VkBool32 + uniformAndStorageBuffer16BitAccess: VkBool32 + storagePushConstant16: VkBool32 + storageInputOutput16: VkBool32 + + +@dataclass +class VkPhysicalDeviceMultiviewFeatures: + multiview: VkBool32 + multiviewGeometryShader: VkBool32 + multiviewTessellationShader: VkBool32 + + +@dataclass +class VkPhysicalDeviceSubgroupProperties: + subgroupSize: uint32_t + supportedStages: VkShaderStageFlags + supportedOperations: VkSubgroupFeatureFlags + quadOperationsInAllStages: VkBool32 + + +@dataclass +class VkPhysicalDevicePointClippingProperties: + pointClippingBehavior: VkPointClippingBehavior + + +@dataclass +class VkPhysicalDeviceMultiviewProperties: + maxMultiviewViewCount: uint32_t + maxMultiviewInstanceIndex: uint32_t + + +@dataclass +class VkMemoryType: + propertyFlags: VkMemoryPropertyFlags + heapIndex: uint32_t + + +@dataclass +class VkMemoryHeap: + size: VkDeviceSize + flags: VkMemoryHeapFlags + + +@dataclass +class VkPhysicalDeviceMemoryProperties: + memoryTypeCount: uint32_t + memoryTypes: List[VkMemoryType] + memoryHeapCount: uint32_t + memoryHeaps: List[VkMemoryHeap] + + +@dataclass +class VkPhysicalDeviceProperties: + apiVersion: uint32_t + driverVersion: uint32_t + vendorID: uint32_t + deviceID: uint32_t + deviceType: VkPhysicalDeviceType + deviceName: str + pipelineCacheUUID: uint8_t + limits: VkPhysicalDeviceLimits + sparseProperties: VkPhysicalDeviceSparseProperties + + +@dataclass +class VkPhysicalDeviceFeatures: + robustBufferAccess: VkBool32 + fullDrawIndexUint32: VkBool32 + imageCubeArray: VkBool32 + independentBlend: VkBool32 + geometryShader: VkBool32 + tessellationShader: VkBool32 + sampleRateShading: VkBool32 + dualSrcBlend: VkBool32 + logicOp: VkBool32 + multiDrawIndirect: VkBool32 + drawIndirectFirstInstance: VkBool32 + depthClamp: VkBool32 + depthBiasClamp: VkBool32 + fillModeNonSolid: VkBool32 + depthBounds: VkBool32 + wideLines: VkBool32 + largePoints: VkBool32 + alphaToOne: VkBool32 + multiViewport: VkBool32 + samplerAnisotropy: VkBool32 + textureCompressionETC2: VkBool32 + textureCompressionASTC_LDR: VkBool32 + textureCompressionBC: VkBool32 + occlusionQueryPrecise: VkBool32 + pipelineStatisticsQuery: VkBool32 + vertexPipelineStoresAndAtomics: VkBool32 + fragmentStoresAndAtomics: VkBool32 + shaderTessellationAndGeometryPointSize: VkBool32 + shaderImageGatherExtended: VkBool32 + shaderStorageImageExtendedFormats: VkBool32 + shaderStorageImageMultisample: VkBool32 + shaderStorageImageReadWithoutFormat: VkBool32 + shaderStorageImageWriteWithoutFormat: VkBool32 + shaderUniformBufferArrayDynamicIndexing: VkBool32 + shaderSampledImageArrayDynamicIndexing: VkBool32 + shaderStorageBufferArrayDynamicIndexing: VkBool32 + shaderStorageImageArrayDynamicIndexing: VkBool32 + shaderClipDistance: VkBool32 + shaderCullDistance: VkBool32 + shaderFloat64: VkBool32 + shaderInt64: VkBool32 + shaderInt16: VkBool32 + shaderResourceResidency: VkBool32 + shaderResourceMinLod: VkBool32 + sparseBinding: VkBool32 + sparseResidencyBuffer: VkBool32 + sparseResidencyImage2D: VkBool32 + sparseResidencyImage3D: VkBool32 + sparseResidency2Samples: VkBool32 + sparseResidency4Samples: VkBool32 + sparseResidency8Samples: VkBool32 + sparseResidency16Samples: VkBool32 + sparseResidencyAliased: VkBool32 + variableMultisampleRate: VkBool32 + inheritedQueries: VkBool32 + + +@dataclass +class VkPhysicalDeviceShaderFloat16Int8Features: + shaderFloat16: VkBool32 + shaderInt8: VkBool32 + + +@dataclass +class VkPhysicalDeviceProtectedMemoryFeatures: + protectedMemory: VkBool32 + + +@dataclass +class VkPhysicalDeviceVariablePointersFeatures: + variablePointersStorageBuffer: VkBool32 + variablePointers: VkBool32 + + +@dataclass +class VkPhysicalDeviceImage2DViewOf3DFeaturesEXT: + image2DViewOf3D: VkBool32 + sampler2DViewOf3D: VkBool32 + + +@dataclass +class VkPhysicalDeviceCustomBorderColorFeaturesEXT: + customBorderColors: VkBool32 + customBorderColorWithoutFormat: VkBool32 + + +@dataclass +class VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT: + primitiveTopologyListRestart: VkBool32 + primitiveTopologyPatchListRestart: VkBool32 + + +@dataclass +class VkPhysicalDeviceProvokingVertexFeaturesEXT: + provokingVertexLast: VkBool32 + transformFeedbackPreservesProvokingVertex: VkBool32 + + +@dataclass +class VkPhysicalDeviceIndexTypeUint8Features: + indexTypeUint8: VkBool32 + + +@dataclass +class VkPhysicalDeviceVertexAttributeDivisorFeatures: + vertexAttributeInstanceRateDivisor: VkBool32 + vertexAttributeInstanceRateZeroDivisor: VkBool32 + + +@dataclass +class VkPhysicalDeviceTransformFeedbackFeaturesEXT: + transformFeedback: VkBool32 + geometryStreams: VkBool32 + + +@dataclass +class VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR: + shaderSubgroupUniformControlFlow: VkBool32 + + +@dataclass +class VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures: + shaderSubgroupExtendedTypes: VkBool32 + + +@dataclass +class VkPhysicalDevice8BitStorageFeatures: + storageBuffer8BitAccess: VkBool32 + uniformAndStorageBuffer8BitAccess: VkBool32 + storagePushConstant8: VkBool32 + + +@dataclass +class VkPhysicalDeviceShaderIntegerDotProductFeatures: + shaderIntegerDotProduct: VkBool32 + + +@dataclass +class VkPhysicalDeviceRelaxedLineRasterizationFeaturesIMG: + relaxedLineRasterization: VkBool32 + + +@dataclass +class VkPhysicalDeviceLineRasterizationFeatures: + rectangularLines: VkBool32 + bresenhamLines: VkBool32 + smoothLines: VkBool32 + stippledRectangularLines: VkBool32 + stippledBresenhamLines: VkBool32 + stippledSmoothLines: VkBool32 + + +@dataclass +class VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT: + primitivesGeneratedQuery: VkBool32 + primitivesGeneratedQueryWithRasterizerDiscard: VkBool32 + primitivesGeneratedQueryWithNonZeroStreams: VkBool32 + + +@dataclass +class VkPhysicalDeviceFloatControlsProperties: + denormBehaviorIndependence : VkShaderFloatControlsIndependence + roundingModeIndependence : VkShaderFloatControlsIndependence + shaderSignedZeroInfNanPreserveFloat16 : VkBool32 + shaderSignedZeroInfNanPreserveFloat32 : VkBool32 + shaderSignedZeroInfNanPreserveFloat64 : VkBool32 + shaderDenormPreserveFloat16 : VkBool32 + shaderDenormPreserveFloat32 : VkBool32 + shaderDenormPreserveFloat64 : VkBool32 + shaderDenormFlushToZeroFloat16 : VkBool32 + shaderDenormFlushToZeroFloat32 : VkBool32 + shaderDenormFlushToZeroFloat64 : VkBool32 + shaderRoundingModeRTEFloat16 : VkBool32 + shaderRoundingModeRTEFloat32 : VkBool32 + shaderRoundingModeRTEFloat64 :VkBool32 + shaderRoundingModeRTZFloat16 : VkBool32 + shaderRoundingModeRTZFloat32 : VkBool32 + shaderRoundingModeRTZFloat64 : VkBool32 + + +@dataclass +class VkPhysicalDeviceVulkan11Properties: + deviceUUID : uint8_t*VK_UUID_SIZE + driverUUID : uint8_t*VK_UUID_SIZE + deviceLUID : uint8_t*VK_LUID_SIZE + deviceNodeMask : uint32_t + deviceLUIDValid : VkBool32 + subgroupSize : uint32_t + subgroupSupportedStages : VkShaderStageFlags + subgroupSupportedOperations : VkSubgroupFeatureFlags + subgroupQuadOperationsInAllStages : VkBool32 + pointClippingBehavior : VkPointClippingBehavior + maxMultiviewViewCount : uint32_t + maxMultiviewInstanceIndex :uint32_t + protectedNoFault : VkBool32 + maxPerSetDescriptors : uint32_t + maxMemoryAllocationSize : VkDeviceSize + + +@dataclass +class VkPhysicalDeviceVulkan11Features: + storageBuffer16BitAccess: VkBool32 + uniformAndStorageBuffer16BitAccess: VkBool32 + storagePushConstant16: VkBool32 + storageInputOutput16: VkBool32 + multiview: VkBool32 + multiviewGeometryShader: VkBool32 + multiviewTessellationShader: VkBool32 + variablePointersStorageBuffer: VkBool32 + variablePointers: VkBool32 + protectedMemory: VkBool32 + samplerYcbcrConversion: VkBool32 + shaderDrawParameters: VkBool32 + + +@dataclass +class VkPhysicalDeviceVulkan12Properties: + driverID: VkDriverId + driverName: str + driverInfo: str + conformanceVersion: ConformanceVersion + denormBehaviorIndependence: VkShaderFloatControlsIndependence + roundingModeIndependence: VkShaderFloatControlsIndependence + shaderSignedZeroInfNanPreserveFloat16: VkBool32 + shaderSignedZeroInfNanPreserveFloat32: VkBool32 + shaderSignedZeroInfNanPreserveFloat64: VkBool32 + shaderDenormPreserveFloat16: VkBool32 + shaderDenormPreserveFloat32: VkBool32 + shaderDenormPreserveFloat64: VkBool32 + shaderDenormFlushToZeroFloat16: VkBool32 + shaderDenormFlushToZeroFloat32: VkBool32 + shaderDenormFlushToZeroFloat64: VkBool32 + shaderRoundingModeRTEFloat16: VkBool32 + shaderRoundingModeRTEFloat32: VkBool32 + shaderRoundingModeRTEFloat64: VkBool32 + shaderRoundingModeRTZFloat16: VkBool32 + shaderRoundingModeRTZFloat32: VkBool32 + shaderRoundingModeRTZFloat64: VkBool32 + maxUpdateAfterBindDescriptorsInAllPools: uint32_t + shaderUniformBufferArrayNonUniformIndexingNative: VkBool32 + shaderSampledImageArrayNonUniformIndexingNative: VkBool32 + shaderStorageBufferArrayNonUniformIndexingNative: VkBool32 + shaderStorageImageArrayNonUniformIndexingNative: VkBool32 + shaderInputAttachmentArrayNonUniformIndexingNative: VkBool32 + robustBufferAccessUpdateAfterBind: VkBool32 + quadDivergentImplicitLod: VkBool32 + maxPerStageDescriptorUpdateAfterBindSamplers: uint32_t + maxPerStageDescriptorUpdateAfterBindUniformBuffers: uint32_t + maxPerStageDescriptorUpdateAfterBindStorageBuffers: uint32_t + maxPerStageDescriptorUpdateAfterBindSampledImages: uint32_t + maxPerStageDescriptorUpdateAfterBindStorageImages: uint32_t + maxPerStageDescriptorUpdateAfterBindInputAttachments: uint32_t + maxPerStageUpdateAfterBindResources: uint32_t + maxDescriptorSetUpdateAfterBindSamplers: uint32_t + maxDescriptorSetUpdateAfterBindUniformBuffers: uint32_t + maxDescriptorSetUpdateAfterBindUniformBuffersDynamic: uint32_t + maxDescriptorSetUpdateAfterBindStorageBuffers: uint32_t + maxDescriptorSetUpdateAfterBindStorageBuffersDynamic: uint32_t + maxDescriptorSetUpdateAfterBindSampledImages: uint32_t + maxDescriptorSetUpdateAfterBindStorageImages: uint32_t + maxDescriptorSetUpdateAfterBindInputAttachments: uint32_t + supportedDepthResolveModes: VkResolveModeFlags + supportedStencilResolveModes: VkResolveModeFlags + independentResolveNone: VkBool32 + independentResolve: VkBool32 + filterMinmaxSingleComponentFormats: VkBool32 + filterMinmaxImageComponentMapping: VkBool32 + maxTimelineSemaphoreValueDifference: uint64_t + framebufferIntegerColorSampleCounts: VkSampleCountFlags + + +@dataclass +class VkPhysicalDeviceVulkan12Features: + samplerMirrorClampToEdge: VkBool32 + drawIndirectCount: VkBool32 + storageBuffer8BitAccess: VkBool32 + uniformAndStorageBuffer8BitAccess: VkBool32 + storagePushConstant8: VkBool32 + shaderBufferInt64Atomics: VkBool32 + shaderSharedInt64Atomics: VkBool32 + shaderFloat16: VkBool32 + shaderInt8: VkBool32 + descriptorIndexing: VkBool32 + shaderInputAttachmentArrayDynamicIndexing: VkBool32 + shaderUniformTexelBufferArrayDynamicIndexing: VkBool32 + shaderStorageTexelBufferArrayDynamicIndexing: VkBool32 + shaderUniformBufferArrayNonUniformIndexing: VkBool32 + shaderSampledImageArrayNonUniformIndexing: VkBool32 + shaderStorageBufferArrayNonUniformIndexing: VkBool32 + shaderStorageImageArrayNonUniformIndexing: VkBool32 + shaderInputAttachmentArrayNonUniformIndexing: VkBool32 + shaderUniformTexelBufferArrayNonUniformIndexing: VkBool32 + shaderStorageTexelBufferArrayNonUniformIndexing: VkBool32 + descriptorBindingUniformBufferUpdateAfterBind: VkBool32 + descriptorBindingSampledImageUpdateAfterBind: VkBool32 + descriptorBindingStorageImageUpdateAfterBind: VkBool32 + descriptorBindingStorageBufferUpdateAfterBind: VkBool32 + descriptorBindingUniformTexelBufferUpdateAfterBind: VkBool32 + descriptorBindingStorageTexelBufferUpdateAfterBind: VkBool32 + descriptorBindingUpdateUnusedWhilePending: VkBool32 + descriptorBindingPartiallyBound: VkBool32 + descriptorBindingVariableDescriptorCount: VkBool32 + runtimeDescriptorArray: VkBool32 + samplerFilterMinmax: VkBool32 + scalarBlockLayout: VkBool32 + imagelessFramebuffer: VkBool32 + uniformBufferStandardLayout: VkBool32 + shaderSubgroupExtendedTypes: VkBool32 + separateDepthStencilLayouts: VkBool32 + hostQueryReset: VkBool32 + timelineSemaphore: VkBool32 + bufferDeviceAddress: VkBool32 + bufferDeviceAddressCaptureReplay: VkBool32 + bufferDeviceAddressMultiDevice: VkBool32 + vulkanMemoryModel: VkBool32 + vulkanMemoryModelDeviceScope: VkBool32 + vulkanMemoryModelAvailabilityVisibilityChains: VkBool32 + shaderOutputViewportIndex: VkBool32 + shaderOutputLayer: VkBool32 + subgroupBroadcastDynamicId: VkBool32 + + +@dataclass +class VkPhysicalDeviceVulkan13Properties: + minSubgroupSize: uint32_t + maxSubgroupSize: uint32_t + maxComputeWorkgroupSubgroups: uint32_t + requiredSubgroupSizeStages: VkShaderStageFlags + maxInlineUniformBlockSize: uint32_t + maxPerStageDescriptorInlineUniformBlocks: uint32_t + maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks: uint32_t + maxDescriptorSetInlineUniformBlocks: uint32_t + maxDescriptorSetUpdateAfterBindInlineUniformBlocks: uint32_t + maxInlineUniformTotalSize: uint32_t + integerDotProduct8BitUnsignedAccelerated: VkBool32 + integerDotProduct8BitSignedAccelerated: VkBool32 + integerDotProduct8BitMixedSignednessAccelerated: VkBool32 + integerDotProduct4x8BitPackedUnsignedAccelerated: VkBool32 + integerDotProduct4x8BitPackedSignedAccelerated: VkBool32 + integerDotProduct4x8BitPackedMixedSignednessAccelerated: VkBool32 + integerDotProduct16BitUnsignedAccelerated: VkBool32 + integerDotProduct16BitSignedAccelerated: VkBool32 + integerDotProduct16BitMixedSignednessAccelerated: VkBool32 + integerDotProduct32BitUnsignedAccelerated: VkBool32 + integerDotProduct32BitSignedAccelerated: VkBool32 + integerDotProduct32BitMixedSignednessAccelerated: VkBool32 + integerDotProduct64BitUnsignedAccelerated: VkBool32 + integerDotProduct64BitSignedAccelerated: VkBool32 + integerDotProduct64BitMixedSignednessAccelerated: VkBool32 + integerDotProductAccumulatingSaturating8BitUnsignedAccelerated: VkBool32 + integerDotProductAccumulatingSaturating8BitSignedAccelerated: VkBool32 + integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated: VkBool32 + integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated: VkBool32 + integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated: VkBool32 + integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated: VkBool32 + integerDotProductAccumulatingSaturating16BitUnsignedAccelerated: VkBool32 + integerDotProductAccumulatingSaturating16BitSignedAccelerated: VkBool32 + integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated: VkBool32 + integerDotProductAccumulatingSaturating32BitUnsignedAccelerated: VkBool32 + integerDotProductAccumulatingSaturating32BitSignedAccelerated: VkBool32 + integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated: VkBool32 + integerDotProductAccumulatingSaturating64BitUnsignedAccelerated: VkBool32 + integerDotProductAccumulatingSaturating64BitSignedAccelerated: VkBool32 + integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated: VkBool32 + storageTexelBufferOffsetAlignmentBytes: VkDeviceSize + storageTexelBufferOffsetSingleTexelAlignment: VkBool32 + uniformTexelBufferOffsetAlignmentBytes: VkDeviceSize + uniformTexelBufferOffsetSingleTexelAlignment: VkBool32 + maxBufferSize: VkDeviceSize + + +@dataclass +class VkPhysicalDeviceVulkan13Features: + robustImageAccess: VkBool32 + inlineUniformBlock: VkBool32 + descriptorBindingInlineUniformBlockUpdateAfterBind: VkBool32 + pipelineCreationCacheControl: VkBool32 + privateData: VkBool32 + shaderDemoteToHelperInvocation: VkBool32 + shaderTerminateInvocation: VkBool32 + subgroupSizeControl: VkBool32 + computeFullSubgroups: VkBool32 + synchronization2: VkBool32 + textureCompressionASTC_HDR: VkBool32 + shaderZeroInitializeWorkgroupMemory: VkBool32 + dynamicRendering: VkBool32 + shaderIntegerDotProduct: VkBool32 + maintenance4: VkBool32 + + +@dataclass +class VkPhysicalDeviceVulkan14Properties: + lineSubPixelPrecisionBits: uint32_t + maxVertexAttribDivisor: uint32_t + supportsNonZeroFirstInstance: VkBool32 + maxPushDescriptors: uint32_t + dynamicRenderingLocalReadDepthStencilAttachments: VkBool32 + dynamicRenderingLocalReadMultisampledAttachments: VkBool32 + earlyFragmentMultisampleCoverageAfterSampleCounting: VkBool32 + earlyFragmentSampleMaskTestBeforeSampleCounting: VkBool32 + depthStencilSwizzleOneSupport: VkBool32 + polygonModePointSize: VkBool32 + nonStrictSinglePixelWideLinesUseParallelogram: VkBool32 + nonStrictWideLinesUseParallelogram: VkBool32 + blockTexelViewCompatibleMultipleLayers: VkBool32 + maxCombinedImageSamplerDescriptorCount: uint32_t + fragmentShadingRateClampCombinerInputs: VkBool32 + defaultRobustnessStorageBuffers: VkPipelineRobustnessBufferBehavior + defaultRobustnessUniformBuffers: VkPipelineRobustnessBufferBehavior + defaultRobustnessVertexInputs: VkPipelineRobustnessBufferBehavior + defaultRobustnessImages: VkPipelineRobustnessBufferBehavior + copySrcLayoutCount: uint32_t + pCopySrcLayouts: List[VkImageLayout] + copyDstLayoutCount: uint32_t + pCopyDstLayouts: List[VkImageLayout] + optimalTilingLayoutUUID: uint8_t + identicalMemoryTypeRequirements: VkBool32 + + +@dataclass +class VkPhysicalDeviceVulkan14Features: + globalPriorityQuery: VkBool32 + shaderSubgroupRotate: VkBool32 + shaderSubgroupRotateClustered: VkBool32 + shaderFloatControls2: VkBool32 + shaderExpectAssume: VkBool32 + rectangularLines: VkBool32 + bresenhamLines: VkBool32 + smoothLines: VkBool32 + stippledRectangularLines: VkBool32 + stippledBresenhamLines: VkBool32 + stippledSmoothLines: VkBool32 + vertexAttributeInstanceRateDivisor: VkBool32 + vertexAttributeInstanceRateZeroDivisor: VkBool32 + indexTypeUint8: VkBool32 + dynamicRenderingLocalRead: VkBool32 + maintenance5: VkBool32 + maintenance6: VkBool32 + pipelineProtectedAccess: VkBool32 + pipelineRobustness: VkBool32 + hostImageCopy: VkBool32 + # pushDescriptor: bool + + +@dataclass +class VkPhysicalDeviceDriverProperties: + driverID: VkDriverId + driverName: str + driverInfo: str + conformanceVersion: ConformanceVersion + +# Defining alias for structures +VkPhysicalDeviceLineRasterizationFeaturesEXT = VkPhysicalDeviceLineRasterizationFeatures +VkPhysicalDeviceLineRasterizationFeaturesKHR = VkPhysicalDeviceLineRasterizationFeatures +VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR = VkPhysicalDeviceShaderIntegerDotProductFeatures +VkPhysicalDevice8BitStorageFeaturesKHR = VkPhysicalDevice8BitStorageFeatures +VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR = VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures +VkPhysicalDeviceVertexAttributeDivisorFeaturesKHR = VkPhysicalDeviceVertexAttributeDivisorFeatures +VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT = VkPhysicalDeviceVertexAttributeDivisorFeatures +VkPhysicalDeviceIndexTypeUint8FeaturesKHR = VkPhysicalDeviceIndexTypeUint8Features +VkPhysicalDeviceIndexTypeUint8FeaturesEXT = VkPhysicalDeviceIndexTypeUint8Features +VkPhysicalDeviceVariablePointerFeatures = VkPhysicalDeviceVariablePointersFeatures +VkPhysicalDeviceVariablePointersFeaturesKHR = VkPhysicalDeviceVariablePointersFeatures +VkPhysicalDeviceVariablePointerFeaturesKHR = VkPhysicalDeviceVariablePointersFeatures +VkPhysicalDeviceFloat16Int8FeaturesKHR = VkPhysicalDeviceShaderFloat16Int8Features +VkPhysicalDeviceShaderFloat16Int8FeaturesKHR = VkPhysicalDeviceShaderFloat16Int8Features +VkPhysicalDeviceFloatControlsPropertiesKHR = VkPhysicalDeviceFloatControlsProperties +VkPhysicalDeviceShaderDrawParametersFeatures = VkPhysicalDeviceShaderDrawParameterFeatures +VkPhysicalDeviceDriverPropertiesKHR = VkPhysicalDeviceDriverProperties + +# Defining dependency of structures on extensions +VULKAN_EXTENSIONS_AND_STRUCTS_MAPPING = { + "extensions": { + "VK_KHR_variable_pointers": [ + { "VkPhysicalDeviceVariablePointerFeaturesKHR": "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES" }, + { "VkPhysicalDeviceVariablePointersFeaturesKHR" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES"}, + ], + "VK_KHR_shader_float16_int8": [ + { "VkPhysicalDeviceShaderFloat16Int8FeaturesKHR": "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES" }, + {"VkPhysicalDeviceFloat16Int8FeaturesKHR" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES"}, + ], + "VK_EXT_image_2d_view_of_3d" : [ + {"VkPhysicalDeviceImage2DViewOf3DFeaturesEXT" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT"}, + ], + "VK_EXT_custom_border_color" : [ + {"VkPhysicalDeviceCustomBorderColorFeaturesEXT" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT"}, + ], + "VK_EXT_primitive_topology_list_restart": [ + {"VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT"}, + ], + "VK_EXT_provoking_vertex" : [ + {"VkPhysicalDeviceProvokingVertexFeaturesEXT" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT"}, + ], + "VK_KHR_index_type_uint8" : [ + {"VkPhysicalDeviceIndexTypeUint8FeaturesKHR" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES"}, + ], + "VK_EXT_index_type_uint8" : [ + {"VkPhysicalDeviceIndexTypeUint8FeaturesEXT" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES"}, + ], + "VK_KHR_vertex_attribute_divisor" : [ + {"VkPhysicalDeviceVertexAttributeDivisorFeaturesKHR" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES"}, + ], + "VK_EXT_vertex_attribute_divisor" : [ + {"VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES"}, + ], + "VK_EXT_transform_feedback" : [ + {"VkPhysicalDeviceTransformFeedbackFeaturesEXT" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT"}, + ], + "VK_KHR_shader_subgroup_uniform_control_flow" : [ + {"VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR"}, + ], + "VK_KHR_shader_subgroup_extended_types" : [ + {"VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES"}, + ], + "VK_KHR_8bit_storage" : [ + {"VkPhysicalDevice8BitStorageFeaturesKHR" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES"}, + ], + "VK_KHR_shader_integer_dot_product" : [ + {"VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES"}, + ], + "VK_IMG_relaxed_line_rasterization" : [ + {"VkPhysicalDeviceRelaxedLineRasterizationFeaturesIMG" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RELAXED_LINE_RASTERIZATION_FEATURES_IMG"}, + ], + "VK_KHR_line_rasterization" : [ + {"VkPhysicalDeviceLineRasterizationFeaturesKHR" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES"}, + ], + "VK_EXT_line_rasterization" : [ + {"VkPhysicalDeviceLineRasterizationFeaturesEXT" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES"}, + ], + "VK_EXT_primitives_generated_query" : [ + {"VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT"}, + ], + "VK_KHR_shader_float_controls" : [ + {"VkPhysicalDeviceFloatControlsPropertiesKHR" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES"}, + ], + "VK_KHR_driver_properties" : [ + {"VkPhysicalDeviceDriverPropertiesKHR" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES"}, + ] + } +} + +# Defining dependency of structures on vulkan cores +VULKAN_CORES_AND_STRUCTS_MAPPING = { + "versions" : { + "Core11" : [ + {"VkPhysicalDeviceVulkan11Properties" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES"}, + {"VkPhysicalDeviceVulkan11Features" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES"}, + ], + "Core12" : [ + {"VkPhysicalDeviceVulkan12Properties" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES"}, + {"VkPhysicalDeviceVulkan12Features" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES"}, + ], + "Core13" : [ + {"VkPhysicalDeviceVulkan13Properties" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES"}, + {"VkPhysicalDeviceVulkan13Features" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES"}, + ], + "Core14" : [ + {"VkPhysicalDeviceVulkan14Properties" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_PROPERTIES"}, + {"VkPhysicalDeviceVulkan14Features" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES"}, + ] + } +} + +# Defining map for list type members mapped to its size +LIST_TYPE_FIELD_AND_SIZE_MAPPING = { + "pCopySrcLayouts": "copySrcLayoutCount", + "pCopyDstLayouts": "copyDstLayoutCount", + "memoryTypes": "memoryTypeCount", + "memoryHeaps": "memoryHeapCount", +} + +# Defining dependency of structures on vulkan api version +VULKAN_VERSIONS_AND_STRUCTS_MAPPING = { + "VK_VERSION_1_0" : [ + {"VkPhysicalDeviceProperties" : "" }, + {"VkPhysicalDeviceFeatures" : ""}, + {"VkPhysicalDeviceMemoryProperties" : ""}, + ], + "VK_VERSION_1_1" : [ + {"VkPhysicalDeviceSubgroupProperties" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES"}, + {"VkPhysicalDevicePointClippingProperties" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES"}, + {"VkPhysicalDeviceMultiviewProperties" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES"}, + {"VkPhysicalDeviceIDProperties" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES"}, + {"VkPhysicalDeviceMaintenance3Properties" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES"}, + {"VkPhysicalDeviceMultiviewFeatures" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES"}, + {"VkPhysicalDeviceVariablePointersFeatures" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES"}, + {"VkPhysicalDeviceProtectedMemoryFeatures" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES"}, + {"VkPhysicalDeviceSamplerYcbcrConversionFeatures" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES"}, + {"VkPhysicalDeviceShaderDrawParameterFeatures" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES"}, + {"VkPhysicalDevice16BitStorageFeatures" : "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES"}, + ] +} + +# List of structures that are not dependent on extensions +EXTENSION_INDEPENDENT_STRUCTS = [ + VkPhysicalDeviceProperties, + VkPhysicalDeviceFeatures, + VkPhysicalDeviceMemoryProperties, + VkPhysicalDeviceSubgroupProperties, + VkPhysicalDevicePointClippingProperties, + VkPhysicalDeviceMultiviewProperties, + VkPhysicalDeviceIDProperties, + VkPhysicalDeviceMaintenance3Properties, + VkPhysicalDevice16BitStorageFeatures, + VkPhysicalDeviceMultiviewFeatures, + VkPhysicalDeviceVariablePointersFeatures, + VkPhysicalDeviceProtectedMemoryFeatures, + VkPhysicalDeviceSamplerYcbcrConversionFeatures, + VkPhysicalDeviceShaderDrawParameterFeatures, +] + +# List of all the structures for vkjson +ALL_STRUCTS = [ + VkPhysicalDeviceFloatControlsPropertiesKHR, + VkPhysicalDeviceProperties, + VkPhysicalDeviceMemoryProperties, + VkPhysicalDeviceSubgroupProperties, + VkPhysicalDevicePointClippingProperties, + VkPhysicalDeviceMultiviewProperties, + VkPhysicalDeviceIDProperties, + VkPhysicalDeviceMaintenance3Properties, + VkPhysicalDeviceSparseProperties, + VkImageFormatProperties, + VkQueueFamilyProperties, + VkExtensionProperties, + VkLayerProperties, + VkFormatProperties, + VkPhysicalDeviceVariablePointerFeaturesKHR, + VkPhysicalDeviceVariablePointersFeaturesKHR, + VkPhysicalDeviceShaderFloat16Int8FeaturesKHR, + VkPhysicalDeviceFloat16Int8FeaturesKHR, + VkPhysicalDeviceImage2DViewOf3DFeaturesEXT, + VkPhysicalDeviceCustomBorderColorFeaturesEXT, + VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT, + VkPhysicalDeviceProvokingVertexFeaturesEXT, + VkPhysicalDeviceIndexTypeUint8FeaturesKHR, + VkPhysicalDeviceIndexTypeUint8FeaturesEXT, + VkPhysicalDeviceVertexAttributeDivisorFeaturesKHR, + VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT, + VkPhysicalDeviceTransformFeedbackFeaturesEXT, + VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR, + VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR, + VkPhysicalDevice8BitStorageFeaturesKHR, + VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR, + VkPhysicalDeviceRelaxedLineRasterizationFeaturesIMG, + VkPhysicalDeviceLineRasterizationFeaturesKHR, + VkPhysicalDeviceLineRasterizationFeaturesEXT, + VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT, + VkPhysicalDevice16BitStorageFeatures, + VkPhysicalDeviceMultiviewFeatures, + VkPhysicalDeviceProtectedMemoryFeatures, + VkPhysicalDeviceSamplerYcbcrConversionFeatures, + VkPhysicalDeviceShaderDrawParameterFeatures, + VkPhysicalDeviceLimits, + VkPhysicalDeviceFeatures, + VkPhysicalDeviceVulkan11Properties, + VkPhysicalDeviceVulkan11Features, + VkPhysicalDeviceVulkan12Properties, + VkPhysicalDeviceVulkan12Features, + VkPhysicalDeviceVulkan13Properties, + VkPhysicalDeviceVulkan13Features, + VkPhysicalDeviceVulkan14Properties, + VkPhysicalDeviceVulkan14Features, + VkPhysicalDeviceDriverProperties, +] diff --git a/vulkan/scripts/vkjson_generator.py b/vulkan/scripts/vkjson_generator.py new file mode 100644 index 0000000000..6f621a1542 --- /dev/null +++ b/vulkan/scripts/vkjson_generator.py @@ -0,0 +1,1902 @@ +#!/usr/bin/env python3 +# +# Copyright 2025 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. + +"""Generates the vkjson files. +""" +import dataclasses +import os +import re +from typing import get_origin + +import generator_common as gencom +import vk as VK + +dataclass_field = dataclasses.field + + +COPYRIGHT_WARNINGS = """/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2015-2016 The Khronos Group Inc. +// Copyright (c) 2015-2016 Valve Corporation +// Copyright (c) 2015-2016 LunarG, Inc. +// Copyright (c) 2015-2016 Google, Inc. +// +// 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. +/////////////////////////////////////////////////////////////////////////////// +""" + + +def get_copyright_warnings(): + return COPYRIGHT_WARNINGS + + +def get_vkjson_struct_name(extension_name): + """Gets the corresponding structure name from a Vulkan extension name. + Example: "VK_KHR_shader_float16_int8" → "VkJsonKHRShaderFloat16Int8" + """ + prefix_map = { + "VK_KHR": "VkJsonKHR", + "VK_EXT": "VkJsonExt", + "VK_IMG": "VkJsonIMG" + } + + for prefix, replacement in prefix_map.items(): + if extension_name.startswith(prefix): + struct_name = replacement + extension_name[len(prefix):] + break + else: + struct_name = f"VkJsonExt{extension_name}" + + # Convert underscores to camel case + # Example: "VK_KHR_shader_float16_int8" → "VkJsonKHRShaderFloat16Int8" + struct_name = re.sub(r"_(.)", lambda m: m.group(1).upper(), struct_name) + + return struct_name + + +def get_vkjson_struct_variable_name(extension_name): + """Gets corresponding instance name from a Vulkan extension name. + Example: "VK_KHR_shader_float16_int8" → "khr_shader_float16_int8" + """ + prefix_map = { + "VK_KHR_": "khr_", + "VK_EXT_": "ext_", + "VK_IMG_": "img_" + } + + for prefix, replacement in prefix_map.items(): + if extension_name.startswith(prefix): + return replacement + extension_name[len(prefix):] + + return extension_name.lower() # Default case if no known prefix matches + + +def get_struct_name(struct_name): + """Gets corresponding instance name + Example: "VkPhysicalDeviceShaderFloat16Int8FeaturesKHR" → "shader_float16_int8_features_khr" + """ + # Remove "VkPhysicalDevice" prefix and any of the known suffixes + base_name = struct_name.removeprefix("VkPhysicalDevice").removesuffix("KHR").removesuffix("EXT").removesuffix("IMG") + + # Convert CamelCase to snake_case + # Example: "ShaderFloat16Int8Features" → "shader_float16_int8_features" + variable_name = re.sub(r"(?<!^)(?=[A-Z])", "_", base_name).lower() + + # Fix special cases + variable_name = variable_name.replace("2_d_", "_2d_").replace("3_d_", "_3d_") + + # Add back the correct suffix if it was removed + suffix_map = {"KHR": "_khr", "EXT": "_ext", "IMG": "_img"} + for suffix, replacement in suffix_map.items(): + if struct_name.endswith(suffix): + variable_name += replacement + break + + # Handle specific exceptions + special_cases = { + "8_bit_storage_features_khr": "bit8_storage_features_khr", + "memory_properties": "memory", + "16_bit_storage_features": "bit16_storage_features", + "i_d_properties": "id_properties" + } + + return special_cases.get(variable_name, variable_name) + + +def generate_extension_struct_definition(f): + """Generates struct definition code for extension based structs + Example: + struct VkJsonKHRShaderFloatControls { + VkJsonKHRShaderFloatControls() { + reported = false; + memset(&float_controls_properties_khr, 0, + sizeof(VkPhysicalDeviceFloatControlsPropertiesKHR)); + } + bool reported; + VkPhysicalDeviceFloatControlsPropertiesKHR float_controls_properties_khr; + }; + """ + vkJson_entries = [] + + for extension_name, struct_list in VK.VULKAN_EXTENSIONS_AND_STRUCTS_MAPPING["extensions"].items(): + vkjson_struct_name = get_vkjson_struct_name(extension_name) + vkjson_struct_variable_name = get_vkjson_struct_variable_name(extension_name) + vkJson_entries.append(f"{vkjson_struct_name} {vkjson_struct_variable_name}") + + struct_entries = [] + + f.write(f"struct {vkjson_struct_name} {{\n") + f.write(f" {vkjson_struct_name}() {{\n") + f.write(" reported = false;\n") + + for struct_map in struct_list: + for struct_name, _ in struct_map.items(): + variable_name = get_struct_name(struct_name) + f.write(f" memset(&{variable_name}, 0, sizeof({struct_name}));\n") + struct_entries.append(f"{struct_name} {variable_name}") + + f.write(" }\n") # End of constructor + f.write(" bool reported;\n") + + for entry in struct_entries: + f.write(f" {entry};\n") + + f.write("};\n\n") # End of struct + + return vkJson_entries + + +def generate_vk_core_struct_definition(f): + """Generates struct definition code for vulkan cores + Example: + struct VkJsonCore11 { + VkPhysicalDeviceVulkan11Properties properties; + VkPhysicalDeviceVulkan11Features features; + }; + """ + vkJson_core_entries = [] + + for version, items in VK.VULKAN_CORES_AND_STRUCTS_MAPPING["versions"].items(): + struct_name = f"VkJson{version}" + vkJson_core_entries.append(f"{struct_name} {version.lower()}") + + f.write(f"struct {struct_name} {{\n") + f.write(f" {struct_name}() {{\n") # Start of constructor + for item in items: + for struct_type, _ in item.items(): + field_name = "properties" if "Properties" in struct_type else "features" + f.write(f" memset(&{field_name}, 0, sizeof({struct_type}));\n") + f.write(" }\n") # End of constructor + + for item in items: + for struct_type, _ in item.items(): + field_name = "properties" if "Properties" in struct_type else "features" + f.write(f" {struct_type} {field_name};\n") + + if version == "Core14": + f.write(f"std::vector<VkImageLayout> copy_src_layouts;\n") + f.write(f"std::vector<VkImageLayout> copy_dst_layouts;\n") + + f.write("};\n\n") + + return vkJson_core_entries + + +def generate_memset_statements(f): + """Generates memset statements for all independent Vulkan structs and core Vulkan versions. + This initializes struct instances to zero before use. + + Example: + memset(&properties, 0, sizeof(VkPhysicalDeviceProperties)); + VkPhysicalDeviceProperties properties; + """ + entries = [] + + # Process independent structs + for dataclass_type in VK.EXTENSION_INDEPENDENT_STRUCTS: + class_name = dataclass_type.__name__ + variable_name = get_struct_name(class_name) + f.write(f"memset(&{variable_name}, 0, sizeof({class_name}));\n") + entries.append(f"{class_name} {variable_name}") + + return entries + + +def gen_h(): + """Generates vkjson.h file. + """ + genfile = os.path.join(os.path.dirname(__file__), + "..", "vkjson", "vkjson.h") + + with open(genfile, "w") as f: + f.write(f'{get_copyright_warnings()}\n') + + f.write("""\ +#ifndef VKJSON_H_ +#define VKJSON_H_ + +#include <string.h> +#include <vulkan/vulkan.h> + +#include <map> +#include <string> +#include <vector> + +#ifdef WIN32 +#undef min +#undef max +#endif + +/* + * This file is autogenerated by vkjson_generator.py. Do not edit directly. + */ +struct VkJsonLayer { + VkLayerProperties properties; + std::vector<VkExtensionProperties> extensions; +}; + +\n""") + + vkjson_extension_structs = generate_extension_struct_definition(f) + vkjson_core_structs = generate_vk_core_struct_definition(f) + + f.write("""\ +struct VkJsonDevice { + VkJsonDevice() {""") + + feature_property_structs = generate_memset_statements(f) + + f.write("""\ + }\n""") + for struct_entries in (vkjson_extension_structs, vkjson_core_structs, feature_property_structs): + for entry in struct_entries: + f.write(entry + ";\n") + + f.write("""\ + std::vector<VkQueueFamilyProperties> queues; + std::vector<VkExtensionProperties> extensions; + std::vector<VkLayerProperties> layers; + std::map<VkFormat, VkFormatProperties> formats; + std::map<VkExternalFenceHandleTypeFlagBits, VkExternalFenceProperties> + external_fence_properties; + std::map<VkExternalSemaphoreHandleTypeFlagBits, VkExternalSemaphoreProperties> + external_semaphore_properties; +}; + +struct VkJsonDeviceGroup { + VkJsonDeviceGroup() { + memset(&properties, 0, sizeof(VkPhysicalDeviceGroupProperties)); + } + VkPhysicalDeviceGroupProperties properties; + std::vector<uint32_t> device_inds; +}; + +struct VkJsonInstance { + VkJsonInstance() : api_version(0) {} + uint32_t api_version; + std::vector<VkJsonLayer> layers; + std::vector<VkExtensionProperties> extensions; + std::vector<VkJsonDevice> devices; + std::vector<VkJsonDeviceGroup> device_groups; +}; + +VkJsonInstance VkJsonGetInstance(); +std::string VkJsonInstanceToJson(const VkJsonInstance& instance); +bool VkJsonInstanceFromJson(const std::string& json, + VkJsonInstance* instance, + std::string* errors); + +VkJsonDevice VkJsonGetDevice(VkPhysicalDevice device); +std::string VkJsonDeviceToJson(const VkJsonDevice& device); +bool VkJsonDeviceFromJson(const std::string& json, + VkJsonDevice* device, + std::string* errors); + +std::string VkJsonImageFormatPropertiesToJson( + const VkImageFormatProperties& properties); +bool VkJsonImageFormatPropertiesFromJson(const std::string& json, + VkImageFormatProperties* properties, + std::string* errors); + +// Backward-compatibility aliases +typedef VkJsonDevice VkJsonAllProperties; +inline VkJsonAllProperties VkJsonGetAllProperties( + VkPhysicalDevice physicalDevice) { + return VkJsonGetDevice(physicalDevice); +} +inline std::string VkJsonAllPropertiesToJson( + const VkJsonAllProperties& properties) { + return VkJsonDeviceToJson(properties); +} +inline bool VkJsonAllPropertiesFromJson(const std::string& json, + VkJsonAllProperties* properties, + std::string* errors) { + return VkJsonDeviceFromJson(json, properties, errors); +} + +#endif // VKJSON_H_""") + + f.close() + gencom.run_clang_format(genfile) + + +def generate_extension_struct_template(): + """Generates templates for extensions + Example: + template <typename Visitor> + inline bool Iterate(Visitor* visitor, VkJsonKHRVariablePointers* structs) { + return visitor->Visit("variablePointerFeaturesKHR", + &structs->variable_pointer_features_khr) && + visitor->Visit("variablePointersFeaturesKHR", + &structs->variable_pointers_features_khr); + } + """ + template_code = [] + + for extension, struct_mappings in VK.VULKAN_EXTENSIONS_AND_STRUCTS_MAPPING["extensions"].items(): + struct_type = get_vkjson_struct_name(extension) + + template_code.append(f"template <typename Visitor>") + template_code.append(f"inline bool Iterate(Visitor* visitor, {struct_type}* structs) {{") + template_code.append(" return ") + + visitor_calls = [] + for struct_map in struct_mappings: + for struct_name in struct_map: + json_field_name = struct_name.replace("VkPhysicalDevice", "") + json_field_name = json_field_name[0].lower() + json_field_name[1:] + + # Special case renaming + if json_field_name == "8BitStorageFeaturesKHR": + json_field_name = "bit8StorageFeaturesKHR" + + visitor_calls.append( + f'visitor->Visit("{json_field_name}", &structs->{get_struct_name(struct_name)})' + ) + + template_code.append(" &&\n ".join(visitor_calls) + ";") + template_code.append("}\n") + + return "\n".join(template_code) + + +def generate_core_template(): + """Generates templates for vulkan cores. + template <typename Visitor> + inline bool Iterate(Visitor* visitor, VkJsonCore11* core) { + return visitor->Visit("properties", &core->properties) && + visitor->Visit("features", &core->features); + } + """ + template_code = [] + + for version, struct_list in VK.VULKAN_CORES_AND_STRUCTS_MAPPING["versions"].items(): + struct_type = f"VkJson{version}" + + template_code.append(f"template <typename Visitor>") + template_code.append(f"inline bool Iterate(Visitor* visitor, {struct_type}* core) {{") + template_code.append(" return") + + visitor_calls = [] + for struct_map in struct_list: + for struct_name in struct_map: + member_name = "properties" if "Properties" in struct_name else "features" + visitor_calls.append(f'visitor->Visit("{member_name}", &core->{member_name})') + + template_code.append(" &&\n ".join(visitor_calls) + ";") + template_code.append("}\n") + + return "\n".join(template_code) + + +def generate_struct_template(data_classes): + """Generates templates for all the structs + template <typename Visitor> + inline bool Iterate(Visitor* visitor, + VkPhysicalDevicePointClippingProperties* properties) { + return visitor->Visit("pointClippingBehavior", + &properties->pointClippingBehavior); + } + """ + template_code = [] + processed_classes = set() # Track processed class names + + for dataclass_type in data_classes: + struct_name = dataclass_type.__name__ + + if struct_name in processed_classes: + continue # Skip already processed struct + processed_classes.add(struct_name) + + struct_fields = dataclasses.fields(dataclass_type) + template_code.append("template <typename Visitor>") + + # Determine the correct variable name based on the struct type + struct_var = "properties" if "Properties" in struct_name else "features" if "Features" in struct_name else "limits" if "Limits" in struct_name else None + + if not struct_var: + continue # Skip structs that don't match expected patterns + + template_code.append(f"inline bool Iterate(Visitor* visitor, {struct_name}* {struct_var}) {{") + template_code.append(f"return\n") + + visitor_calls = [] + for struct_field in struct_fields: + field_name = struct_field.name + field_type = struct_field.type + + if get_origin(field_type) is list: + # Handle list types (VisitArray) + size_field_name = VK.LIST_TYPE_FIELD_AND_SIZE_MAPPING[field_name] + visitor_calls.append(f'visitor->VisitArray("{field_name}", {struct_var}->{size_field_name}, &{struct_var}->{field_name})') + else: + # Handle other types (Visit) + visitor_calls.append(f'visitor->Visit("{field_name}", &{struct_var}->{field_name})') + + template_code.append(" &&\n ".join(visitor_calls) + ";") + template_code.append("}\n\n") + + return "\n".join(template_code) + + +def emit_struct_visits_by_vk_version(f, version): + """Emits visitor calls for Vulkan version structs + """ + for struct_map in VK.VULKAN_VERSIONS_AND_STRUCTS_MAPPING[version]: + for struct_name, _ in struct_map.items(): + struct_var = get_struct_name(struct_name) + # Converts struct_var from snake_case (e.g., point_clipping_properties) + # to camelCase (e.g., pointClippingProperties) for struct_display_name. + struct_display_name = re.sub(r"_([a-z])", lambda match: match.group(1).upper(), struct_var) + f.write(f'visitor->Visit("{struct_display_name}", &device->{struct_var}) &&\n') + + +def gen_cc(): + """Generates vkjson.cc file. + """ + genfile = os.path.join(os.path.dirname(__file__), + "..", "vkjson", "vkjson.cc") + + with open(genfile, "w") as f: + + f.write(get_copyright_warnings()) + f.write("\n") + + f.write("""\ +#include "vkjson.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include <json/json.h> + +#include <algorithm> +#include <cinttypes> +#include <cmath> +#include <cstdio> +#include <limits> +#include <memory> +#include <sstream> +#include <type_traits> +#include <utility> + +/* + * This file is autogenerated by vkjson_generator.py. Do not edit directly. + */ +namespace { + +/* + * Annotation to tell clang that we intend to fall through from one case to + * another in a switch. Sourced from android-base/macros.h. + */ +#define FALLTHROUGH_INTENDED [[clang::fallthrough]] + +inline bool IsIntegral(double value) { +#if defined(ANDROID) + // Android NDK doesn't provide std::trunc yet + return trunc(value) == value; +#else + return std::trunc(value) == value; +#endif +} + +// Floating point fields of Vulkan structure use single precision. The string +// output of max double value in c++ will be larger than Java double's infinity +// value. Below fake double max/min values are only to serve the safe json text +// parsing in between C++ and Java, because Java json library simply cannot +// handle infinity. +static const double SAFE_DOUBLE_MAX = 0.99 * std::numeric_limits<double>::max(); +static const double SAFE_DOUBLE_MIN = -SAFE_DOUBLE_MAX; + +template <typename T> struct EnumTraits; +template <> struct EnumTraits<VkPhysicalDeviceType> { + static bool exist(uint32_t e) { + switch (e) { + case VK_PHYSICAL_DEVICE_TYPE_OTHER: + case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: + case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: + case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: + case VK_PHYSICAL_DEVICE_TYPE_CPU: + return true; + } + return false; + } +}; + +template <> struct EnumTraits<VkFormat> { + static bool exist(uint32_t e) { + switch (e) { + case VK_FORMAT_UNDEFINED: + case VK_FORMAT_R4G4_UNORM_PACK8: + case VK_FORMAT_R4G4B4A4_UNORM_PACK16: + case VK_FORMAT_B4G4R4A4_UNORM_PACK16: + case VK_FORMAT_R5G6B5_UNORM_PACK16: + case VK_FORMAT_B5G6R5_UNORM_PACK16: + case VK_FORMAT_R5G5B5A1_UNORM_PACK16: + case VK_FORMAT_B5G5R5A1_UNORM_PACK16: + case VK_FORMAT_A1R5G5B5_UNORM_PACK16: + case VK_FORMAT_R8_UNORM: + case VK_FORMAT_R8_SNORM: + case VK_FORMAT_R8_USCALED: + case VK_FORMAT_R8_SSCALED: + case VK_FORMAT_R8_UINT: + case VK_FORMAT_R8_SINT: + case VK_FORMAT_R8_SRGB: + case VK_FORMAT_R8G8_UNORM: + case VK_FORMAT_R8G8_SNORM: + case VK_FORMAT_R8G8_USCALED: + case VK_FORMAT_R8G8_SSCALED: + case VK_FORMAT_R8G8_UINT: + case VK_FORMAT_R8G8_SINT: + case VK_FORMAT_R8G8_SRGB: + case VK_FORMAT_R8G8B8_UNORM: + case VK_FORMAT_R8G8B8_SNORM: + case VK_FORMAT_R8G8B8_USCALED: + case VK_FORMAT_R8G8B8_SSCALED: + case VK_FORMAT_R8G8B8_UINT: + case VK_FORMAT_R8G8B8_SINT: + case VK_FORMAT_R8G8B8_SRGB: + case VK_FORMAT_B8G8R8_UNORM: + case VK_FORMAT_B8G8R8_SNORM: + case VK_FORMAT_B8G8R8_USCALED: + case VK_FORMAT_B8G8R8_SSCALED: + case VK_FORMAT_B8G8R8_UINT: + case VK_FORMAT_B8G8R8_SINT: + case VK_FORMAT_B8G8R8_SRGB: + case VK_FORMAT_R8G8B8A8_UNORM: + case VK_FORMAT_R8G8B8A8_SNORM: + case VK_FORMAT_R8G8B8A8_USCALED: + case VK_FORMAT_R8G8B8A8_SSCALED: + case VK_FORMAT_R8G8B8A8_UINT: + case VK_FORMAT_R8G8B8A8_SINT: + case VK_FORMAT_R8G8B8A8_SRGB: + case VK_FORMAT_B8G8R8A8_UNORM: + case VK_FORMAT_B8G8R8A8_SNORM: + case VK_FORMAT_B8G8R8A8_USCALED: + case VK_FORMAT_B8G8R8A8_SSCALED: + case VK_FORMAT_B8G8R8A8_UINT: + case VK_FORMAT_B8G8R8A8_SINT: + case VK_FORMAT_B8G8R8A8_SRGB: + case VK_FORMAT_A8B8G8R8_UNORM_PACK32: + case VK_FORMAT_A8B8G8R8_SNORM_PACK32: + case VK_FORMAT_A8B8G8R8_USCALED_PACK32: + case VK_FORMAT_A8B8G8R8_SSCALED_PACK32: + case VK_FORMAT_A8B8G8R8_UINT_PACK32: + case VK_FORMAT_A8B8G8R8_SINT_PACK32: + case VK_FORMAT_A8B8G8R8_SRGB_PACK32: + case VK_FORMAT_A2R10G10B10_UNORM_PACK32: + case VK_FORMAT_A2R10G10B10_SNORM_PACK32: + case VK_FORMAT_A2R10G10B10_USCALED_PACK32: + case VK_FORMAT_A2R10G10B10_SSCALED_PACK32: + case VK_FORMAT_A2R10G10B10_UINT_PACK32: + case VK_FORMAT_A2R10G10B10_SINT_PACK32: + case VK_FORMAT_A2B10G10R10_UNORM_PACK32: + case VK_FORMAT_A2B10G10R10_SNORM_PACK32: + case VK_FORMAT_A2B10G10R10_USCALED_PACK32: + case VK_FORMAT_A2B10G10R10_SSCALED_PACK32: + case VK_FORMAT_A2B10G10R10_UINT_PACK32: + case VK_FORMAT_A2B10G10R10_SINT_PACK32: + case VK_FORMAT_R16_UNORM: + case VK_FORMAT_R16_SNORM: + case VK_FORMAT_R16_USCALED: + case VK_FORMAT_R16_SSCALED: + case VK_FORMAT_R16_UINT: + case VK_FORMAT_R16_SINT: + case VK_FORMAT_R16_SFLOAT: + case VK_FORMAT_R16G16_UNORM: + case VK_FORMAT_R16G16_SNORM: + case VK_FORMAT_R16G16_USCALED: + case VK_FORMAT_R16G16_SSCALED: + case VK_FORMAT_R16G16_UINT: + case VK_FORMAT_R16G16_SINT: + case VK_FORMAT_R16G16_SFLOAT: + case VK_FORMAT_R16G16B16_UNORM: + case VK_FORMAT_R16G16B16_SNORM: + case VK_FORMAT_R16G16B16_USCALED: + case VK_FORMAT_R16G16B16_SSCALED: + case VK_FORMAT_R16G16B16_UINT: + case VK_FORMAT_R16G16B16_SINT: + case VK_FORMAT_R16G16B16_SFLOAT: + case VK_FORMAT_R16G16B16A16_UNORM: + case VK_FORMAT_R16G16B16A16_SNORM: + case VK_FORMAT_R16G16B16A16_USCALED: + case VK_FORMAT_R16G16B16A16_SSCALED: + case VK_FORMAT_R16G16B16A16_UINT: + case VK_FORMAT_R16G16B16A16_SINT: + case VK_FORMAT_R16G16B16A16_SFLOAT: + case VK_FORMAT_R32_UINT: + case VK_FORMAT_R32_SINT: + case VK_FORMAT_R32_SFLOAT: + case VK_FORMAT_R32G32_UINT: + case VK_FORMAT_R32G32_SINT: + case VK_FORMAT_R32G32_SFLOAT: + case VK_FORMAT_R32G32B32_UINT: + case VK_FORMAT_R32G32B32_SINT: + case VK_FORMAT_R32G32B32_SFLOAT: + case VK_FORMAT_R32G32B32A32_UINT: + case VK_FORMAT_R32G32B32A32_SINT: + case VK_FORMAT_R32G32B32A32_SFLOAT: + case VK_FORMAT_R64_UINT: + case VK_FORMAT_R64_SINT: + case VK_FORMAT_R64_SFLOAT: + case VK_FORMAT_R64G64_UINT: + case VK_FORMAT_R64G64_SINT: + case VK_FORMAT_R64G64_SFLOAT: + case VK_FORMAT_R64G64B64_UINT: + case VK_FORMAT_R64G64B64_SINT: + case VK_FORMAT_R64G64B64_SFLOAT: + case VK_FORMAT_R64G64B64A64_UINT: + case VK_FORMAT_R64G64B64A64_SINT: + case VK_FORMAT_R64G64B64A64_SFLOAT: + case VK_FORMAT_B10G11R11_UFLOAT_PACK32: + case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: + case VK_FORMAT_D16_UNORM: + case VK_FORMAT_X8_D24_UNORM_PACK32: + case VK_FORMAT_D32_SFLOAT: + case VK_FORMAT_S8_UINT: + case VK_FORMAT_D16_UNORM_S8_UINT: + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + case VK_FORMAT_BC1_RGB_UNORM_BLOCK: + case VK_FORMAT_BC1_RGB_SRGB_BLOCK: + case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: + case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: + case VK_FORMAT_BC2_UNORM_BLOCK: + case VK_FORMAT_BC2_SRGB_BLOCK: + case VK_FORMAT_BC3_UNORM_BLOCK: + case VK_FORMAT_BC3_SRGB_BLOCK: + case VK_FORMAT_BC4_UNORM_BLOCK: + case VK_FORMAT_BC4_SNORM_BLOCK: + case VK_FORMAT_BC5_UNORM_BLOCK: + case VK_FORMAT_BC5_SNORM_BLOCK: + case VK_FORMAT_BC6H_UFLOAT_BLOCK: + case VK_FORMAT_BC6H_SFLOAT_BLOCK: + case VK_FORMAT_BC7_UNORM_BLOCK: + case VK_FORMAT_BC7_SRGB_BLOCK: + case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: + case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: + case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: + case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: + case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: + case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: + case VK_FORMAT_EAC_R11_UNORM_BLOCK: + case VK_FORMAT_EAC_R11_SNORM_BLOCK: + case VK_FORMAT_EAC_R11G11_UNORM_BLOCK: + case VK_FORMAT_EAC_R11G11_SNORM_BLOCK: + case VK_FORMAT_ASTC_4x4_UNORM_BLOCK: + case VK_FORMAT_ASTC_4x4_SRGB_BLOCK: + case VK_FORMAT_ASTC_5x4_UNORM_BLOCK: + case VK_FORMAT_ASTC_5x4_SRGB_BLOCK: + case VK_FORMAT_ASTC_5x5_UNORM_BLOCK: + case VK_FORMAT_ASTC_5x5_SRGB_BLOCK: + case VK_FORMAT_ASTC_6x5_UNORM_BLOCK: + case VK_FORMAT_ASTC_6x5_SRGB_BLOCK: + case VK_FORMAT_ASTC_6x6_UNORM_BLOCK: + case VK_FORMAT_ASTC_6x6_SRGB_BLOCK: + case VK_FORMAT_ASTC_8x5_UNORM_BLOCK: + case VK_FORMAT_ASTC_8x5_SRGB_BLOCK: + case VK_FORMAT_ASTC_8x6_UNORM_BLOCK: + case VK_FORMAT_ASTC_8x6_SRGB_BLOCK: + case VK_FORMAT_ASTC_8x8_UNORM_BLOCK: + case VK_FORMAT_ASTC_8x8_SRGB_BLOCK: + case VK_FORMAT_ASTC_10x5_UNORM_BLOCK: + case VK_FORMAT_ASTC_10x5_SRGB_BLOCK: + case VK_FORMAT_ASTC_10x6_UNORM_BLOCK: + case VK_FORMAT_ASTC_10x6_SRGB_BLOCK: + case VK_FORMAT_ASTC_10x8_UNORM_BLOCK: + case VK_FORMAT_ASTC_10x8_SRGB_BLOCK: + case VK_FORMAT_ASTC_10x10_UNORM_BLOCK: + case VK_FORMAT_ASTC_10x10_SRGB_BLOCK: + case VK_FORMAT_ASTC_12x10_UNORM_BLOCK: + case VK_FORMAT_ASTC_12x10_SRGB_BLOCK: + case VK_FORMAT_ASTC_12x12_UNORM_BLOCK: + case VK_FORMAT_ASTC_12x12_SRGB_BLOCK: + case VK_FORMAT_G8B8G8R8_422_UNORM: + case VK_FORMAT_B8G8R8G8_422_UNORM: + case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: + case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: + case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM: + case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM: + case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM: + case VK_FORMAT_R10X6_UNORM_PACK16: + case VK_FORMAT_R10X6G10X6_UNORM_2PACK16: + case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: + case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16: + case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16: + case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16: + case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16: + case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16: + case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16: + case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16: + case VK_FORMAT_R12X4_UNORM_PACK16: + case VK_FORMAT_R12X4G12X4_UNORM_2PACK16: + case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16: + case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16: + case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16: + case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16: + case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16: + case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16: + case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16: + case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16: + case VK_FORMAT_G16B16G16R16_422_UNORM: + case VK_FORMAT_B16G16R16G16_422_UNORM: + case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM: + case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM: + case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM: + case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM: + case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM: + case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: + case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: + case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: + case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: + case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: + case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: + case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: + case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: + case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT: + case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT: + case VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT: + case VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT: + return true; + } + return false; + } +}; + +template <> +struct EnumTraits<VkPointClippingBehavior> { + static bool exist(uint32_t e) { + switch (e) { + case VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES: + case VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY: + return true; + } + return false; + } +}; + +template <> +struct EnumTraits<VkExternalFenceHandleTypeFlagBits> { + static bool exist(uint32_t e) { + switch (e) { + case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT: + case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT: + case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT: + case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT: + return true; + } + return false; + } +}; + +template <> +struct EnumTraits<VkExternalSemaphoreHandleTypeFlagBits> { + static bool exist(uint32_t e) { + switch (e) { + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT: + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT: + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT: + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT: + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT: + return true; + } + return false; + } +}; + +template <> +struct EnumTraits<VkDriverIdKHR> { + static bool exist(uint32_t e) { + switch (e) { + case VK_DRIVER_ID_AMD_PROPRIETARY: + case VK_DRIVER_ID_AMD_OPEN_SOURCE: + case VK_DRIVER_ID_MESA_RADV: + case VK_DRIVER_ID_NVIDIA_PROPRIETARY: + case VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS: + case VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA: + case VK_DRIVER_ID_IMAGINATION_PROPRIETARY: + case VK_DRIVER_ID_QUALCOMM_PROPRIETARY: + case VK_DRIVER_ID_ARM_PROPRIETARY: + case VK_DRIVER_ID_GOOGLE_SWIFTSHADER: + case VK_DRIVER_ID_GGP_PROPRIETARY: + case VK_DRIVER_ID_BROADCOM_PROPRIETARY: + case VK_DRIVER_ID_MESA_LLVMPIPE: + case VK_DRIVER_ID_MOLTENVK: + return true; + } + return false; + } +}; + +template <> +struct EnumTraits<VkShaderFloatControlsIndependence> { + static bool exist(uint32_t e) { + switch (e) { + case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY: + case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL: + case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE: + return true; + } + return false; + } +}; + +template <> +struct EnumTraits<VkPipelineRobustnessBufferBehavior> { + static bool exist(uint32_t e) { + switch (e) { + case VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DEVICE_DEFAULT: + case VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DISABLED: + case VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS: + case VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2: + return true; + } + return false; + } +}; + +template <> +struct EnumTraits<VkPipelineRobustnessImageBehavior> { + static bool exist(uint32_t e) { + switch (e) { + case VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT: + case VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DISABLED: + case VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS: + case VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_2: + return true; + } + return false; + } +}; + +template <> +struct EnumTraits<VkImageLayout> { + static bool exist(uint32_t e) { + switch (e) { + case VK_IMAGE_LAYOUT_UNDEFINED: + case VK_IMAGE_LAYOUT_GENERAL: + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + case VK_IMAGE_LAYOUT_PREINITIALIZED: + case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: + case VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR: + case VK_IMAGE_LAYOUT_VIDEO_DECODE_SRC_KHR: + case VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR: + case VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR: + case VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT: + case VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR: +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_IMAGE_LAYOUT_VIDEO_ENCODE_DST_KHR: +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_IMAGE_LAYOUT_VIDEO_ENCODE_SRC_KHR: +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_IMAGE_LAYOUT_VIDEO_ENCODE_DPB_KHR: +#endif + case VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT: + return true; + } + return false; + } +}; + +// VkSparseImageFormatProperties + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkExtent3D* extents) { + return + visitor->Visit("width", &extents->width) && + visitor->Visit("height", &extents->height) && + visitor->Visit("depth", &extents->depth); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, + VkConformanceVersionKHR* version) { + return visitor->Visit("major", &version->major) && + visitor->Visit("minor", &version->minor) && + visitor->Visit("subminor", &version->subminor) && + visitor->Visit("patch", &version->patch); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkMemoryType* type) { + return + visitor->Visit("propertyFlags", &type->propertyFlags) && + visitor->Visit("heapIndex", &type->heapIndex); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkMemoryHeap* heap) { + return + visitor->Visit("size", &heap->size) && + visitor->Visit("flags", &heap->flags); +}\n\n""") + + f.write(f"{generate_core_template()}\n\n{generate_extension_struct_template()}\n\n") + f.write(generate_struct_template(VK.ALL_STRUCTS)) + + f.write("""\ +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkExternalFenceProperties* properties) { + return visitor->Visit("exportFromImportedHandleTypes", + &properties->exportFromImportedHandleTypes) && + visitor->Visit("compatibleHandleTypes", + &properties->compatibleHandleTypes) && + visitor->Visit("externalFenceFeatures", + &properties->externalFenceFeatures); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, + VkExternalSemaphoreProperties* properties) { + return visitor->Visit("exportFromImportedHandleTypes", + &properties->exportFromImportedHandleTypes) && + visitor->Visit("compatibleHandleTypes", + &properties->compatibleHandleTypes) && + visitor->Visit("externalSemaphoreFeatures", + &properties->externalSemaphoreFeatures); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonLayer* layer) { + return visitor->Visit("properties", &layer->properties) && + visitor->Visit("extensions", &layer->extensions); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonDeviceGroup* device_group) { + return visitor->Visit("devices", &device_group->device_inds) && + visitor->Visit("subsetAllocation", + &device_group->properties.subsetAllocation); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonDevice* device) { + bool ret = true; + switch (device->properties.apiVersion ^ + VK_API_VERSION_PATCH(device->properties.apiVersion)) { + case VK_API_VERSION_1_4: + ret &= visitor->Visit("core14", &device->core14); + FALLTHROUGH_INTENDED; + case VK_API_VERSION_1_3: + ret &= visitor->Visit("core13", &device->core13); + FALLTHROUGH_INTENDED; + case VK_API_VERSION_1_2: + ret &= visitor->Visit("core11", &device->core11); + ret &= visitor->Visit("core12", &device->core12); + FALLTHROUGH_INTENDED; + case VK_API_VERSION_1_1: + ret &=\n""") + + emit_struct_visits_by_vk_version(f, "VK_VERSION_1_1") + + f.write("""\ + visitor->Visit("externalFenceProperties", + &device->external_fence_properties) && + visitor->Visit("externalSemaphoreProperties", + &device->external_semaphore_properties); + FALLTHROUGH_INTENDED; + case VK_API_VERSION_1_0: + ret &=\n""") + + emit_struct_visits_by_vk_version(f, "VK_VERSION_1_0") + + f.write("""\ + visitor->Visit("queues", &device->queues) && + visitor->Visit("extensions", &device->extensions) && + visitor->Visit("layers", &device->layers) && + visitor->Visit("formats", &device->formats);\n\n""") + + for extension_name, _ in VK.VULKAN_EXTENSIONS_AND_STRUCTS_MAPPING["extensions"].items(): + struct_var = get_vkjson_struct_variable_name(extension_name) + f.write(f" if (device->{struct_var}.reported) {{\n") + f.write(f" ret &= visitor->Visit(\"{extension_name}\", &device->{struct_var});\n") + f.write(" }\n") + + f.write("""\ + } return ret; } + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonInstance* instance) { + bool ret = true; + switch (instance->api_version ^ VK_API_VERSION_PATCH(instance->api_version)) { + case VK_API_VERSION_1_4: + FALLTHROUGH_INTENDED; + case VK_API_VERSION_1_3: + FALLTHROUGH_INTENDED; + case VK_API_VERSION_1_2: + ret &= visitor->Visit("apiVersion", &instance->api_version); + FALLTHROUGH_INTENDED; + case VK_API_VERSION_1_1: + ret &= visitor->Visit("deviceGroups", &instance->device_groups); + FALLTHROUGH_INTENDED; + case VK_API_VERSION_1_0: + char depString[] = + "vkjson is deprecated, and will be replaced in a future release"; + ret &= visitor->Visit("layers", &instance->layers) && + visitor->Visit("extensions", &instance->extensions) && + visitor->Visit("devices", &instance->devices) && + visitor->Visit("_comment", &depString); + } + return ret; +} + +template <typename T> +using EnableForArithmetic = + typename std::enable_if<std::is_arithmetic<T>::value, void>::type; + +template <typename T> +using EnableForStruct = + typename std::enable_if<std::is_class<T>::value, void>::type; + +template <typename T> +using EnableForEnum = + typename std::enable_if<std::is_enum<T>::value, void>::type; + +template <typename T, typename = EnableForStruct<T>, typename = void> +Json::Value ToJsonValue(const T& value); + +template <typename T, typename = EnableForArithmetic<T>> +inline Json::Value ToJsonValue(const T& value) { + return Json::Value( + std::clamp(static_cast<double>(value), SAFE_DOUBLE_MIN, SAFE_DOUBLE_MAX)); +} + +inline Json::Value ToJsonValue(const uint64_t& value) { + char string[19] = {0}; // "0x" + 16 digits + terminal \\0 + snprintf(string, sizeof(string), "0x%016" PRIx64, value); + return Json::Value(string); +} + +template <typename T, typename = EnableForEnum<T>, typename = void, + typename = void> +inline Json::Value ToJsonValue(const T& value) { + return Json::Value(static_cast<double>(value)); +} + +template <typename T> +inline Json::Value ArrayToJsonValue(uint32_t count, const T* values) { + Json::Value array(Json::arrayValue); + for (unsigned int i = 0; i < count; ++i) array.append(ToJsonValue(values[i])); + return array; +} + +template <typename T, size_t N> +inline Json::Value ToJsonValue(const T (&value)[N]) { + return ArrayToJsonValue(N, value); +} + +template <size_t N> +inline Json::Value ToJsonValue(const char (&value)[N]) { + assert(strlen(value) < N); + return Json::Value(value); +} + +template <typename T> +inline Json::Value ToJsonValue(const std::vector<T>& value) { + assert(value.size() <= std::numeric_limits<uint32_t>::max()); + return ArrayToJsonValue(static_cast<uint32_t>(value.size()), value.data()); +} + +template <typename F, typename S> +inline Json::Value ToJsonValue(const std::pair<F, S>& value) { + Json::Value array(Json::arrayValue); + array.append(ToJsonValue(value.first)); + array.append(ToJsonValue(value.second)); + return array; +} + +template <typename F, typename S> +inline Json::Value ToJsonValue(const std::map<F, S>& value) { + Json::Value array(Json::arrayValue); + for (auto& kv : value) array.append(ToJsonValue(kv)); + return array; +} + +class JsonWriterVisitor { + public: + JsonWriterVisitor() : object_(Json::objectValue) {} + + ~JsonWriterVisitor() {} + + template <typename T> bool Visit(const char* key, const T* value) { + object_[key] = ToJsonValue(*value); + return true; + } + + template <typename T, uint32_t N> + bool VisitArray(const char* key, uint32_t count, const T (*value)[N]) { + assert(count <= N); + object_[key] = ArrayToJsonValue(count, *value); + return true; + } + + template <typename T> + bool VisitArray(const char* key, uint32_t count, const T *value) { + object_[key] = ArrayToJsonValue(count, *value); + return true; + } + + Json::Value get_object() const { return object_; } + + private: + Json::Value object_; +}; + +template <typename Visitor, typename T> +inline void VisitForWrite(Visitor* visitor, const T& t) { + Iterate(visitor, const_cast<T*>(&t)); +} + +template <typename T, typename /*= EnableForStruct<T>*/, typename /*= void*/> +Json::Value ToJsonValue(const T& value) { + JsonWriterVisitor visitor; + VisitForWrite(&visitor, value); + return visitor.get_object(); +} + +template <typename T, typename = EnableForStruct<T>> +bool AsValue(Json::Value* json_value, T* t); + +inline bool AsValue(Json::Value* json_value, int32_t* value) { + if (json_value->type() != Json::realValue) return false; + double d = json_value->asDouble(); + if (!IsIntegral(d) || + d < static_cast<double>(std::numeric_limits<int32_t>::min()) || + d > static_cast<double>(std::numeric_limits<int32_t>::max())) + return false; + *value = static_cast<int32_t>(d); + return true; +} + +inline bool AsValue(Json::Value* json_value, uint64_t* value) { + if (json_value->type() != Json::stringValue) return false; + int result = + std::sscanf(json_value->asString().c_str(), "0x%016" PRIx64, value); + return result == 1; +} + +inline bool AsValue(Json::Value* json_value, uint32_t* value) { + if (json_value->type() != Json::realValue) return false; + double d = json_value->asDouble(); + if (!IsIntegral(d) || d < 0.0 || + d > static_cast<double>(std::numeric_limits<uint32_t>::max())) + return false; + *value = static_cast<uint32_t>(d); + return true; +} + +inline bool AsValue(Json::Value* json_value, uint8_t* value) { + uint32_t value32 = 0; + AsValue(json_value, &value32); + if (value32 > std::numeric_limits<uint8_t>::max()) + return false; + *value = static_cast<uint8_t>(value32); + return true; +} + +inline bool AsValue(Json::Value* json_value, float* value) { + if (json_value->type() != Json::realValue) return false; + *value = static_cast<float>(json_value->asDouble()); + return true; +} + +inline bool AsValue(Json::Value* json_value, VkImageLayout* t) { + uint32_t value = 0; + if (!AsValue(json_value, &value)) + return false; + if (!EnumTraits<VkImageLayout>::exist(value)) return false; + *t = static_cast<VkImageLayout>(value); + return true; +} + +template <typename T> +inline bool AsArray(Json::Value* json_value, uint32_t count, T* values) { + if (json_value->type() != Json::arrayValue || json_value->size() != count) + return false; + for (uint32_t i = 0; i < count; ++i) { + if (!AsValue(&(*json_value)[i], values + i)) return false; + } + return true; +} + +template <typename T, size_t N> +inline bool AsValue(Json::Value* json_value, T (*value)[N]) { + return AsArray(json_value, N, *value); +} + +template <size_t N> +inline bool AsValue(Json::Value* json_value, char (*value)[N]) { + if (json_value->type() != Json::stringValue) return false; + size_t len = json_value->asString().length(); + if (len >= N) + return false; + memcpy(*value, json_value->asString().c_str(), len); + memset(*value + len, 0, N-len); + return true; +} + +template <typename T, typename = EnableForEnum<T>, typename = void> +inline bool AsValue(Json::Value* json_value, T* t) { + uint32_t value = 0; + if (!AsValue(json_value, &value)) + return false; + if (!EnumTraits<T>::exist(value)) return false; + *t = static_cast<T>(value); + return true; +} + +template <typename T> +inline bool AsValue(Json::Value* json_value, std::vector<T>* value) { + if (json_value->type() != Json::arrayValue) return false; + int size = json_value->size(); + value->resize(size); + return AsArray(json_value, size, value->data()); +} + +template <typename F, typename S> +inline bool AsValue(Json::Value* json_value, std::pair<F, S>* value) { + if (json_value->type() != Json::arrayValue || json_value->size() != 2) + return false; + return AsValue(&(*json_value)[0], &value->first) && + AsValue(&(*json_value)[1], &value->second); +} + +template <typename F, typename S> +inline bool AsValue(Json::Value* json_value, std::map<F, S>* value) { + if (json_value->type() != Json::arrayValue) return false; + int size = json_value->size(); + for (int i = 0; i < size; ++i) { + std::pair<F, S> elem; + if (!AsValue(&(*json_value)[i], &elem)) return false; + if (!value->insert(elem).second) + return false; + } + return true; +} + +template <typename T> +bool ReadValue(Json::Value* object, const char* key, T* value, + std::string* errors) { + Json::Value json_value = (*object)[key]; + if (!json_value) { + if (errors) + *errors = std::string(key) + " missing."; + return false; + } + if (AsValue(&json_value, value)) return true; + if (errors) + *errors = std::string("Wrong type for ") + std::string(key) + "."; + return false; +} + +template <typename Visitor, typename T> +inline bool VisitForRead(Visitor* visitor, T* t) { + return Iterate(visitor, t); +} + +class JsonReaderVisitor { + public: + JsonReaderVisitor(Json::Value* object, std::string* errors) + : object_(object), errors_(errors) {} + + template <typename T> bool Visit(const char* key, T* value) const { + return ReadValue(object_, key, value, errors_); + } + + template <typename T, uint32_t N> + bool VisitArray(const char* key, uint32_t count, T (*value)[N]) { + if (count > N) + return false; + Json::Value json_value = (*object_)[key]; + if (!json_value) { + if (errors_) + *errors_ = std::string(key) + " missing."; + return false; + } + if (AsArray(&json_value, count, *value)) return true; + if (errors_) + *errors_ = std::string("Wrong type for ") + std::string(key) + "."; + return false; + } + + template <typename T> + bool VisitArray(const char* key, uint32_t count, T *value) { + Json::Value json_value = (*object_)[key]; + if (!json_value) { + if (errors_) + *errors_ = std::string(key) + " missing."; + return false; + } + if (AsArray(&json_value, count, *value)) return true; + if (errors_) + *errors_ = std::string("Wrong type for ") + std::string(key) + "."; + return false; + } + + + private: + Json::Value* object_; + std::string* errors_; +}; + +template <typename T, typename /*= EnableForStruct<T>*/> +bool AsValue(Json::Value* json_value, T* t) { + if (json_value->type() != Json::objectValue) return false; + JsonReaderVisitor visitor(json_value, nullptr); + return VisitForRead(&visitor, t); +} + + +template <typename T> std::string VkTypeToJson(const T& t) { + JsonWriterVisitor visitor; + VisitForWrite(&visitor, t); + return visitor.get_object().toStyledString(); +} + +template <typename T> bool VkTypeFromJson(const std::string& json, + T* t, + std::string* errors) { + *t = T(); + Json::Value object(Json::objectValue); + Json::CharReaderBuilder builder; + builder["collectComments"] = false; + std::unique_ptr<Json::CharReader> reader(builder.newCharReader()); + if (!reader->parse(json.data(), json.data() + json.size(), &object, errors)) { + return false; + } + return AsValue(&object, t); +} + +} // anonymous namespace + +std::string VkJsonInstanceToJson(const VkJsonInstance& instance) { + return VkTypeToJson(instance); +} + +bool VkJsonInstanceFromJson(const std::string& json, + VkJsonInstance* instance, + std::string* errors) { + return VkTypeFromJson(json, instance, errors); +} + +std::string VkJsonDeviceToJson(const VkJsonDevice& device) { + return VkTypeToJson(device); +} + +bool VkJsonDeviceFromJson(const std::string& json, + VkJsonDevice* device, + std::string* errors) { + return VkTypeFromJson(json, device, errors); +}; + +std::string VkJsonImageFormatPropertiesToJson( + const VkImageFormatProperties& properties) { + return VkTypeToJson(properties); +} + +bool VkJsonImageFormatPropertiesFromJson(const std::string& json, + VkImageFormatProperties* properties, + std::string* errors) { + return VkTypeFromJson(json, properties, errors); +}; +""") + f.close() + gencom.run_clang_format(genfile) + + +def generate_vk_core_structs_init_code(version): + """Generates code to initialize properties and features + for structs based on its vulkan API version dependency. + """ + properties_code, features_code = [], [] + + for item in VK.VULKAN_CORES_AND_STRUCTS_MAPPING["versions"].get(version, []): + for struct_name, struct_type in item.items(): + version_lower = version.lower() + + if "Properties" in struct_name: + properties_code.extend([ + f"device.{version_lower}.properties.sType = {struct_type};", + f"device.{version_lower}.properties.pNext = properties.pNext;", + f"properties.pNext = &device.{version_lower}.properties;\n\n" + ]) + + elif "Features" in struct_name: + features_code.extend([ + f"device.{version_lower}.features.sType = {struct_type};", + f"device.{version_lower}.features.pNext = features.pNext;", + f"features.pNext = &device.{version_lower}.features;\n\n" + ]) + + return "\n".join(properties_code), "\n".join(features_code) + + +def generate_vk_extension_structs_init_code(mapping, struct_category, next_pointer): + """Generates Vulkan struct initialization code for given struct category (Properties/Features) + based on its extension dependency. + """ + generated_code = [] + + for extension, struct_mappings in mapping.items(): + struct_var_name = get_vkjson_struct_variable_name(extension) + extension_code = [ + f" if (HasExtension(\"{extension}\", device.extensions)) {{", + f" device.{struct_var_name}.reported = true;" + ] + + struct_count = 0 + for struct_mapping in struct_mappings: + for struct_name, struct_type in struct_mapping.items(): + if struct_category in struct_name: + struct_count += 1 + struct_instance = get_struct_name(struct_name) + extension_code.extend([ + f" device.{struct_var_name}.{struct_instance}.sType = {struct_type};", + f" device.{struct_var_name}.{struct_instance}.pNext = {next_pointer}.pNext;", + f" {next_pointer}.pNext = &device.{struct_var_name}.{struct_instance};" + ]) + + extension_code.append(" }\n") + + if struct_count > 0: + generated_code.extend(extension_code) + + return "\n".join(generated_code) + + +def generate_vk_version_structs_initialization(version_data, struct_type_keyword, next_pointer): + """Generates Vulkan struct initialization code for given struct category (Properties/Features) + of vulkan api version s. + """ + struct_initialization_code = [] + + for struct_mapping in version_data: + for struct_name, struct_type in struct_mapping.items(): + if struct_type_keyword in struct_name: + struct_variable = get_struct_name(struct_name) + struct_initialization_code.extend([ + f"device.{struct_variable}.sType = {struct_type};", + f"device.{struct_variable}.pNext = {next_pointer}.pNext;", + f"{next_pointer}.pNext = &device.{struct_variable};\n" + ]) + + return "\n".join(struct_initialization_code) + + +def gen_instance_cc(): + """Generates vkjson_instance.cc file. + """ + genfile = os.path.join(os.path.dirname(__file__), + "..", "vkjson", "vkjson_instance.cc") + + with open(genfile, "w") as f: + f.write(get_copyright_warnings()) + f.write("\n") + + f.write("""\ +#ifndef VK_PROTOTYPES +#define VK_PROTOTYPES +#endif + +#include "vkjson.h" + +#include <algorithm> +#include <utility> + +/* + * This file is autogenerated by vkjson_generator.py. Do not edit directly. + */ +namespace { + +bool EnumerateExtensions(const char* layer_name, + std::vector<VkExtensionProperties>* extensions) { + VkResult result; + uint32_t count = 0; + result = vkEnumerateInstanceExtensionProperties(layer_name, &count, nullptr); + if (result != VK_SUCCESS) + return false; + extensions->resize(count); + result = vkEnumerateInstanceExtensionProperties(layer_name, &count, + extensions->data()); + if (result != VK_SUCCESS) + return false; + return true; +} + +bool HasExtension(const char* extension_name, + const std::vector<VkExtensionProperties>& extensions) { + return std::find_if(extensions.cbegin(), extensions.cend(), + [extension_name](const VkExtensionProperties& extension) { + return strcmp(extension.extensionName, + extension_name) == 0; + }) != extensions.cend(); +} +} // anonymous namespace + +VkJsonDevice VkJsonGetDevice(VkPhysicalDevice physical_device) { + VkJsonDevice device; + + uint32_t extension_count = 0; + vkEnumerateDeviceExtensionProperties(physical_device, nullptr, + &extension_count, nullptr); + if (extension_count > 0) { + device.extensions.resize(extension_count); + vkEnumerateDeviceExtensionProperties( + physical_device, nullptr, &extension_count, device.extensions.data()); + } + + uint32_t layer_count = 0; + vkEnumerateDeviceLayerProperties(physical_device, &layer_count, nullptr); + if (layer_count > 0) { + device.layers.resize(layer_count); + vkEnumerateDeviceLayerProperties(physical_device, &layer_count, + device.layers.data()); + } + + VkPhysicalDeviceProperties2 properties = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, + nullptr, + {}, + };\n\n""") + + cc_code_properties = generate_vk_extension_structs_init_code( + VK.VULKAN_EXTENSIONS_AND_STRUCTS_MAPPING["extensions"], "Properties", "properties" + ) + f.write(f'{cc_code_properties}\n') + + f.write("""\ + + vkGetPhysicalDeviceProperties2(physical_device, &properties); + device.properties = properties.properties; + + VkPhysicalDeviceFeatures2 features = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, + nullptr, + {}, + };\n\n""") + + cc_code_features = generate_vk_extension_structs_init_code( + VK.VULKAN_EXTENSIONS_AND_STRUCTS_MAPPING["extensions"], "Features", "features" + ) + f.write(f'{cc_code_features}\n') + + f.write("""\ + + vkGetPhysicalDeviceFeatures2(physical_device, &features); + device.features = features.features; + + vkGetPhysicalDeviceMemoryProperties(physical_device, &device.memory); + + uint32_t queue_family_count = 0; + vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, + nullptr); + if (queue_family_count > 0) { + device.queues.resize(queue_family_count); + vkGetPhysicalDeviceQueueFamilyProperties( + physical_device, &queue_family_count, device.queues.data()); + } + + VkFormatProperties format_properties = {}; + for (VkFormat format = VK_FORMAT_R4G4_UNORM_PACK8; + // TODO(http://b/171403054): avoid hard-coding last value in the + // contiguous range + format <= VK_FORMAT_ASTC_12x12_SRGB_BLOCK; + format = static_cast<VkFormat>(format + 1)) { + vkGetPhysicalDeviceFormatProperties(physical_device, format, + &format_properties); + if (format_properties.linearTilingFeatures || + format_properties.optimalTilingFeatures || + format_properties.bufferFeatures) { + device.formats.insert(std::make_pair(format, format_properties)); + } + } + + if (device.properties.apiVersion >= VK_API_VERSION_1_1) { + for (VkFormat format = VK_FORMAT_G8B8G8R8_422_UNORM; + // TODO(http://b/171403054): avoid hard-coding last value in the + // contiguous range + format <= VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM; + format = static_cast<VkFormat>(format + 1)) { + vkGetPhysicalDeviceFormatProperties(physical_device, format, + &format_properties); + if (format_properties.linearTilingFeatures || + format_properties.optimalTilingFeatures || + format_properties.bufferFeatures) { + device.formats.insert(std::make_pair(format, format_properties)); + } + }\n\n""") + + # Vulkan version data for VK_VERSION_1_1 + vk_version_data = VK.VULKAN_VERSIONS_AND_STRUCTS_MAPPING["VK_VERSION_1_1"] + f.write(generate_vk_version_structs_initialization(vk_version_data, "Properties", "properties") + "\n") + + f.write("""\ + vkGetPhysicalDeviceProperties2(physical_device, &properties);\n\n""") + + features_initialization_code = generate_vk_version_structs_initialization(vk_version_data, "Features", "features") + f.write(features_initialization_code) + + f.write("""\ + + vkGetPhysicalDeviceFeatures2(physical_device, &features); + + VkPhysicalDeviceExternalFenceInfo external_fence_info = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, nullptr, + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT}; + VkExternalFenceProperties external_fence_properties = {}; + + for (VkExternalFenceHandleTypeFlagBits handle_type = + VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT; + handle_type <= VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT; + handle_type = + static_cast<VkExternalFenceHandleTypeFlagBits>(handle_type << 1)) { + external_fence_info.handleType = handle_type; + vkGetPhysicalDeviceExternalFenceProperties( + physical_device, &external_fence_info, &external_fence_properties); + if (external_fence_properties.exportFromImportedHandleTypes || + external_fence_properties.compatibleHandleTypes || + external_fence_properties.externalFenceFeatures) { + device.external_fence_properties.insert( + std::make_pair(handle_type, external_fence_properties)); + } + } + + VkPhysicalDeviceExternalSemaphoreInfo external_semaphore_info = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO, nullptr, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT}; + VkExternalSemaphoreProperties external_semaphore_properties = {}; + + for (VkExternalSemaphoreHandleTypeFlagBits handle_type = + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; + handle_type <= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT; + handle_type = static_cast<VkExternalSemaphoreHandleTypeFlagBits>( + handle_type << 1)) { + external_semaphore_info.handleType = handle_type; + vkGetPhysicalDeviceExternalSemaphoreProperties( + physical_device, &external_semaphore_info, + &external_semaphore_properties); + if (external_semaphore_properties.exportFromImportedHandleTypes || + external_semaphore_properties.compatibleHandleTypes || + external_semaphore_properties.externalSemaphoreFeatures) { + device.external_semaphore_properties.insert( + std::make_pair(handle_type, external_semaphore_properties)); + } + } + } + + if (device.properties.apiVersion >= VK_API_VERSION_1_2) {\n""") + + cc_code_properties_11, cc_code_features_11 = generate_vk_core_structs_init_code("Core11") + cc_code_properties_12, cc_code_features_12 = generate_vk_core_structs_init_code("Core12") + cc_code_properties_13, cc_code_features_13 = generate_vk_core_structs_init_code("Core13") + cc_code_properties_14, cc_code_features_14 = generate_vk_core_structs_init_code("Core14") + + f.write(cc_code_properties_11) + f.write(cc_code_properties_12) + f.write(f"vkGetPhysicalDeviceProperties2(physical_device, &properties);\n\n") + f.write(cc_code_features_11) + f.write(cc_code_features_12) + f.write(f"vkGetPhysicalDeviceFeatures2(physical_device, &features);\n\n") + f.write("""\ + } + + if (device.properties.apiVersion >= VK_API_VERSION_1_3) {\n""") + f.write(cc_code_properties_13) + f.write(f"vkGetPhysicalDeviceProperties2(physical_device, &properties);\n\n") + f.write(cc_code_features_13) + f.write(f"vkGetPhysicalDeviceFeatures2(physical_device, &features);\n\n") + f.write("""\ + } + + if (device.properties.apiVersion >= VK_API_VERSION_1_4) {\n""") + f.write(cc_code_properties_14) + f.write(f"vkGetPhysicalDeviceProperties2(physical_device, &properties);\n\n") + + f.write("""\ +if (device.core14.properties.copySrcLayoutCount > 0 || device.core14.properties.copyDstLayoutCount > 0 ) { + if (device.core14.properties.copySrcLayoutCount > 0) { + device.core14.copy_src_layouts.resize(device.core14.properties.copySrcLayoutCount); + device.core14.properties.pCopySrcLayouts = device.core14.copy_src_layouts.data(); + } + if (device.core14.properties.copyDstLayoutCount > 0) { + device.core14.copy_dst_layouts.resize(device.core14.properties.copyDstLayoutCount); + device.core14.properties.pCopyDstLayouts = device.core14.copy_dst_layouts.data(); + } + vkGetPhysicalDeviceProperties2(physical_device, &properties); +} + \n""") + + f.write(cc_code_features_14) + f.write(f"vkGetPhysicalDeviceFeatures2(physical_device, &features);\n\n") + f.write("""\ + } + + return device; +} + +VkJsonInstance VkJsonGetInstance() { + VkJsonInstance instance; + VkResult result; + uint32_t count; + + count = 0; + result = vkEnumerateInstanceLayerProperties(&count, nullptr); + if (result != VK_SUCCESS) + return VkJsonInstance(); + if (count > 0) { + std::vector<VkLayerProperties> layers(count); + result = vkEnumerateInstanceLayerProperties(&count, layers.data()); + if (result != VK_SUCCESS) + return VkJsonInstance(); + instance.layers.reserve(count); + for (auto& layer : layers) { + instance.layers.push_back(VkJsonLayer{layer, std::vector<VkExtensionProperties>()}); + if (!EnumerateExtensions(layer.layerName, + &instance.layers.back().extensions)) + return VkJsonInstance(); + } + } + + if (!EnumerateExtensions(nullptr, &instance.extensions)) + return VkJsonInstance(); + + const VkApplicationInfo app_info = { + VK_STRUCTURE_TYPE_APPLICATION_INFO, + nullptr, + "vkjson_info", + 1, + "", + 0, + VK_API_VERSION_1_1, + }; + VkInstanceCreateInfo instance_info = { + VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + nullptr, + 0, + &app_info, + 0, + nullptr, + 0, + nullptr, + }; + VkInstance vkinstance; + result = vkCreateInstance(&instance_info, nullptr, &vkinstance); + if (result != VK_SUCCESS) + return VkJsonInstance(); + + count = 0; + result = vkEnumeratePhysicalDevices(vkinstance, &count, nullptr); + if (result != VK_SUCCESS) { + vkDestroyInstance(vkinstance, nullptr); + return VkJsonInstance(); + } + + std::vector<VkPhysicalDevice> devices(count, VK_NULL_HANDLE); + result = vkEnumeratePhysicalDevices(vkinstance, &count, devices.data()); + if (result != VK_SUCCESS) { + vkDestroyInstance(vkinstance, nullptr); + return VkJsonInstance(); + } + + std::map<VkPhysicalDevice, uint32_t> device_map; + const uint32_t sz = devices.size(); + instance.devices.reserve(sz); + for (uint32_t i = 0; i < sz; ++i) { + device_map.insert(std::make_pair(devices[i], i)); + instance.devices.emplace_back(VkJsonGetDevice(devices[i])); + } + + result = vkEnumerateInstanceVersion(&instance.api_version); + if (result != VK_SUCCESS) { + vkDestroyInstance(vkinstance, nullptr); + return VkJsonInstance(); + } + + count = 0; + result = vkEnumeratePhysicalDeviceGroups(vkinstance, &count, nullptr); + if (result != VK_SUCCESS) { + vkDestroyInstance(vkinstance, nullptr); + return VkJsonInstance(); + } + + VkJsonDeviceGroup device_group; + std::vector<VkPhysicalDeviceGroupProperties> group_properties; + group_properties.resize(count); + for (auto& properties : group_properties) { + properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES; + properties.pNext = nullptr; + } + result = vkEnumeratePhysicalDeviceGroups(vkinstance, &count, + group_properties.data()); + if (result != VK_SUCCESS) { + vkDestroyInstance(vkinstance, nullptr); + return VkJsonInstance(); + } + for (auto properties : group_properties) { + device_group.properties = properties; + for (uint32_t i = 0; i < properties.physicalDeviceCount; ++i) { + device_group.device_inds.push_back( + device_map[properties.physicalDevices[i]]); + } + instance.device_groups.push_back(device_group); + } + + vkDestroyInstance(vkinstance, nullptr); + return instance; +} + +\n""") + + f.close() + gencom.run_clang_format(genfile)
\ No newline at end of file diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc index 18fef2bf58..517e62d1db 100644 --- a/vulkan/vkjson/vkjson.cc +++ b/vulkan/vkjson/vkjson.cc @@ -36,6 +36,9 @@ #include <type_traits> #include <utility> +/* + * This file is autogenerated by vkjson_generator.py. Do not edit directly. + */ namespace { /* @@ -56,13 +59,15 @@ inline bool IsIntegral(double value) { // Floating point fields of Vulkan structure use single precision. The string // output of max double value in c++ will be larger than Java double's infinity // value. Below fake double max/min values are only to serve the safe json text -// parsing in between C++ and Java, becasue Java json library simply cannot +// parsing in between C++ and Java, because Java json library simply cannot // handle infinity. static const double SAFE_DOUBLE_MAX = 0.99 * std::numeric_limits<double>::max(); static const double SAFE_DOUBLE_MIN = -SAFE_DOUBLE_MAX; -template <typename T> struct EnumTraits; -template <> struct EnumTraits<VkPhysicalDeviceType> { +template <typename T> +struct EnumTraits; +template <> +struct EnumTraits<VkPhysicalDeviceType> { static bool exist(uint32_t e) { switch (e) { case VK_PHYSICAL_DEVICE_TYPE_OTHER: @@ -76,7 +81,8 @@ template <> struct EnumTraits<VkPhysicalDeviceType> { } }; -template <> struct EnumTraits<VkFormat> { +template <> +struct EnumTraits<VkFormat> { static bool exist(uint32_t e) { switch (e) { case VK_FORMAT_UNDEFINED: @@ -482,708 +488,1447 @@ struct EnumTraits<VkImageLayout> { template <typename Visitor> inline bool Iterate(Visitor* visitor, VkExtent3D* extents) { + return visitor->Visit("width", &extents->width) && + visitor->Visit("height", &extents->height) && + visitor->Visit("depth", &extents->depth); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkConformanceVersionKHR* version) { + return visitor->Visit("major", &version->major) && + visitor->Visit("minor", &version->minor) && + visitor->Visit("subminor", &version->subminor) && + visitor->Visit("patch", &version->patch); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkMemoryType* type) { + return visitor->Visit("propertyFlags", &type->propertyFlags) && + visitor->Visit("heapIndex", &type->heapIndex); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkMemoryHeap* heap) { + return visitor->Visit("size", &heap->size) && + visitor->Visit("flags", &heap->flags); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonCore11* core) { + return visitor->Visit("properties", &core->properties) && + visitor->Visit("features", &core->features); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonCore12* core) { + return visitor->Visit("properties", &core->properties) && + visitor->Visit("features", &core->features); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonCore13* core) { + return visitor->Visit("properties", &core->properties) && + visitor->Visit("features", &core->features); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonCore14* core) { + return visitor->Visit("properties", &core->properties) && + visitor->Visit("features", &core->features); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonKHRVariablePointers* structs) { + return visitor->Visit("variablePointerFeaturesKHR", + &structs->variable_pointer_features_khr) && + visitor->Visit("variablePointersFeaturesKHR", + &structs->variable_pointers_features_khr); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonKHRShaderFloat16Int8* structs) { + return visitor->Visit("shaderFloat16Int8FeaturesKHR", + &structs->shader_float16_int8_features_khr) && + visitor->Visit("float16Int8FeaturesKHR", + &structs->float16_int8_features_khr); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonExtImage2dViewOf3d* structs) { + return visitor->Visit("image2DViewOf3DFeaturesEXT", + &structs->image_2d_view_of_3d_features_ext); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonExtCustomBorderColor* structs) { + return visitor->Visit("customBorderColorFeaturesEXT", + &structs->custom_border_color_features_ext); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, + VkJsonExtPrimitiveTopologyListRestart* structs) { + return visitor->Visit("primitiveTopologyListRestartFeaturesEXT", + &structs->primitive_topology_list_restart_features_ext); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonExtProvokingVertex* structs) { + return visitor->Visit("provokingVertexFeaturesEXT", + &structs->provoking_vertex_features_ext); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonKHRIndexTypeUint8* structs) { + return visitor->Visit("indexTypeUint8FeaturesKHR", + &structs->index_type_uint8_features_khr); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonExtIndexTypeUint8* structs) { + return visitor->Visit("indexTypeUint8FeaturesEXT", + &structs->index_type_uint8_features_ext); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, + VkJsonKHRVertexAttributeDivisor* structs) { + return visitor->Visit("vertexAttributeDivisorFeaturesKHR", + &structs->vertex_attribute_divisor_features_khr); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, + VkJsonExtVertexAttributeDivisor* structs) { + return visitor->Visit("vertexAttributeDivisorFeaturesEXT", + &structs->vertex_attribute_divisor_features_ext); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonExtTransformFeedback* structs) { + return visitor->Visit("transformFeedbackFeaturesEXT", + &structs->transform_feedback_features_ext); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, + VkJsonKHRShaderSubgroupUniformControlFlow* structs) { + return visitor->Visit( + "shaderSubgroupUniformControlFlowFeaturesKHR", + &structs->shader_subgroup_uniform_control_flow_features_khr); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, + VkJsonKHRShaderSubgroupExtendedTypes* structs) { + return visitor->Visit("shaderSubgroupExtendedTypesFeaturesKHR", + &structs->shader_subgroup_extended_types_features_khr); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonKHR8bitStorage* structs) { + return visitor->Visit("bit8StorageFeaturesKHR", + &structs->bit8_storage_features_khr); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, + VkJsonKHRShaderIntegerDotProduct* structs) { + return visitor->Visit("shaderIntegerDotProductFeaturesKHR", + &structs->shader_integer_dot_product_features_khr); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, + VkJsonIMGRelaxedLineRasterization* structs) { + return visitor->Visit("relaxedLineRasterizationFeaturesIMG", + &structs->relaxed_line_rasterization_features_img); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonKHRLineRasterization* structs) { + return visitor->Visit("lineRasterizationFeaturesKHR", + &structs->line_rasterization_features_khr); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonExtLineRasterization* structs) { + return visitor->Visit("lineRasterizationFeaturesEXT", + &structs->line_rasterization_features_ext); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, + VkJsonExtPrimitivesGeneratedQuery* structs) { + return visitor->Visit("primitivesGeneratedQueryFeaturesEXT", + &structs->primitives_generated_query_features_ext); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonKHRShaderFloatControls* structs) { + return visitor->Visit("floatControlsPropertiesKHR", + &structs->float_controls_properties_khr); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonKHRDriverProperties* structs) { + return visitor->Visit("driverPropertiesKHR", &structs->driver_properties_khr); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, + VkPhysicalDeviceFloatControlsProperties* properties) { return - visitor->Visit("width", &extents->width) && - visitor->Visit("height", &extents->height) && - visitor->Visit("depth", &extents->depth); + + visitor->Visit("denormBehaviorIndependence", + &properties->denormBehaviorIndependence) && + visitor->Visit("roundingModeIndependence", + &properties->roundingModeIndependence) && + visitor->Visit("shaderSignedZeroInfNanPreserveFloat16", + &properties->shaderSignedZeroInfNanPreserveFloat16) && + visitor->Visit("shaderSignedZeroInfNanPreserveFloat32", + &properties->shaderSignedZeroInfNanPreserveFloat32) && + visitor->Visit("shaderSignedZeroInfNanPreserveFloat64", + &properties->shaderSignedZeroInfNanPreserveFloat64) && + visitor->Visit("shaderDenormPreserveFloat16", + &properties->shaderDenormPreserveFloat16) && + visitor->Visit("shaderDenormPreserveFloat32", + &properties->shaderDenormPreserveFloat32) && + visitor->Visit("shaderDenormPreserveFloat64", + &properties->shaderDenormPreserveFloat64) && + visitor->Visit("shaderDenormFlushToZeroFloat16", + &properties->shaderDenormFlushToZeroFloat16) && + visitor->Visit("shaderDenormFlushToZeroFloat32", + &properties->shaderDenormFlushToZeroFloat32) && + visitor->Visit("shaderDenormFlushToZeroFloat64", + &properties->shaderDenormFlushToZeroFloat64) && + visitor->Visit("shaderRoundingModeRTEFloat16", + &properties->shaderRoundingModeRTEFloat16) && + visitor->Visit("shaderRoundingModeRTEFloat32", + &properties->shaderRoundingModeRTEFloat32) && + visitor->Visit("shaderRoundingModeRTEFloat64", + &properties->shaderRoundingModeRTEFloat64) && + visitor->Visit("shaderRoundingModeRTZFloat16", + &properties->shaderRoundingModeRTZFloat16) && + visitor->Visit("shaderRoundingModeRTZFloat32", + &properties->shaderRoundingModeRTZFloat32) && + visitor->Visit("shaderRoundingModeRTZFloat64", + &properties->shaderRoundingModeRTZFloat64); } template <typename Visitor> -inline bool Iterate(Visitor* visitor, VkImageFormatProperties* properties) { +inline bool Iterate(Visitor* visitor, VkPhysicalDeviceProperties* properties) { return - visitor->Visit("maxExtent", &properties->maxExtent) && - visitor->Visit("maxMipLevels", &properties->maxMipLevels) && - visitor->Visit("maxArrayLayers", &properties->maxArrayLayers) && - visitor->Visit("sampleCounts", &properties->sampleCounts) && - visitor->Visit("maxResourceSize", &properties->maxResourceSize); + + visitor->Visit("apiVersion", &properties->apiVersion) && + visitor->Visit("driverVersion", &properties->driverVersion) && + visitor->Visit("vendorID", &properties->vendorID) && + visitor->Visit("deviceID", &properties->deviceID) && + visitor->Visit("deviceType", &properties->deviceType) && + visitor->Visit("deviceName", &properties->deviceName) && + visitor->Visit("pipelineCacheUUID", &properties->pipelineCacheUUID) && + visitor->Visit("limits", &properties->limits) && + visitor->Visit("sparseProperties", &properties->sparseProperties); } -// clang-format off template <typename Visitor> -inline bool Iterate(Visitor* visitor, VkPhysicalDeviceLimits* limits) { +inline bool Iterate(Visitor* visitor, + VkPhysicalDeviceMemoryProperties* properties) { return - visitor->Visit("maxImageDimension1D", &limits->maxImageDimension1D) && - visitor->Visit("maxImageDimension2D", &limits->maxImageDimension2D) && - visitor->Visit("maxImageDimension3D", &limits->maxImageDimension3D) && - visitor->Visit("maxImageDimensionCube", &limits->maxImageDimensionCube) && - visitor->Visit("maxImageArrayLayers", &limits->maxImageArrayLayers) && - visitor->Visit("maxTexelBufferElements", &limits->maxTexelBufferElements) && - visitor->Visit("maxUniformBufferRange", &limits->maxUniformBufferRange) && - visitor->Visit("maxStorageBufferRange", &limits->maxStorageBufferRange) && - visitor->Visit("maxPushConstantsSize", &limits->maxPushConstantsSize) && - visitor->Visit("maxMemoryAllocationCount", &limits->maxMemoryAllocationCount) && - visitor->Visit("maxSamplerAllocationCount", &limits->maxSamplerAllocationCount) && - visitor->Visit("bufferImageGranularity", &limits->bufferImageGranularity) && - visitor->Visit("sparseAddressSpaceSize", &limits->sparseAddressSpaceSize) && - visitor->Visit("maxBoundDescriptorSets", &limits->maxBoundDescriptorSets) && - visitor->Visit("maxPerStageDescriptorSamplers", &limits->maxPerStageDescriptorSamplers) && - visitor->Visit("maxPerStageDescriptorUniformBuffers", &limits->maxPerStageDescriptorUniformBuffers) && - visitor->Visit("maxPerStageDescriptorStorageBuffers", &limits->maxPerStageDescriptorStorageBuffers) && - visitor->Visit("maxPerStageDescriptorSampledImages", &limits->maxPerStageDescriptorSampledImages) && - visitor->Visit("maxPerStageDescriptorStorageImages", &limits->maxPerStageDescriptorStorageImages) && - visitor->Visit("maxPerStageDescriptorInputAttachments", &limits->maxPerStageDescriptorInputAttachments) && - visitor->Visit("maxPerStageResources", &limits->maxPerStageResources) && - visitor->Visit("maxDescriptorSetSamplers", &limits->maxDescriptorSetSamplers) && - visitor->Visit("maxDescriptorSetUniformBuffers", &limits->maxDescriptorSetUniformBuffers) && - visitor->Visit("maxDescriptorSetUniformBuffersDynamic", &limits->maxDescriptorSetUniformBuffersDynamic) && - visitor->Visit("maxDescriptorSetStorageBuffers", &limits->maxDescriptorSetStorageBuffers) && - visitor->Visit("maxDescriptorSetStorageBuffersDynamic", &limits->maxDescriptorSetStorageBuffersDynamic) && - visitor->Visit("maxDescriptorSetSampledImages", &limits->maxDescriptorSetSampledImages) && - visitor->Visit("maxDescriptorSetStorageImages", &limits->maxDescriptorSetStorageImages) && - visitor->Visit("maxDescriptorSetInputAttachments", &limits->maxDescriptorSetInputAttachments) && - visitor->Visit("maxVertexInputAttributes", &limits->maxVertexInputAttributes) && - visitor->Visit("maxVertexInputBindings", &limits->maxVertexInputBindings) && - visitor->Visit("maxVertexInputAttributeOffset", &limits->maxVertexInputAttributeOffset) && - visitor->Visit("maxVertexInputBindingStride", &limits->maxVertexInputBindingStride) && - visitor->Visit("maxVertexOutputComponents", &limits->maxVertexOutputComponents) && - visitor->Visit("maxTessellationGenerationLevel", &limits->maxTessellationGenerationLevel) && - visitor->Visit("maxTessellationPatchSize", &limits->maxTessellationPatchSize) && - visitor->Visit("maxTessellationControlPerVertexInputComponents", &limits->maxTessellationControlPerVertexInputComponents) && - visitor->Visit("maxTessellationControlPerVertexOutputComponents", &limits->maxTessellationControlPerVertexOutputComponents) && - visitor->Visit("maxTessellationControlPerPatchOutputComponents", &limits->maxTessellationControlPerPatchOutputComponents) && - visitor->Visit("maxTessellationControlTotalOutputComponents", &limits->maxTessellationControlTotalOutputComponents) && - visitor->Visit("maxTessellationEvaluationInputComponents", &limits->maxTessellationEvaluationInputComponents) && - visitor->Visit("maxTessellationEvaluationOutputComponents", &limits->maxTessellationEvaluationOutputComponents) && - visitor->Visit("maxGeometryShaderInvocations", &limits->maxGeometryShaderInvocations) && - visitor->Visit("maxGeometryInputComponents", &limits->maxGeometryInputComponents) && - visitor->Visit("maxGeometryOutputComponents", &limits->maxGeometryOutputComponents) && - visitor->Visit("maxGeometryOutputVertices", &limits->maxGeometryOutputVertices) && - visitor->Visit("maxGeometryTotalOutputComponents", &limits->maxGeometryTotalOutputComponents) && - visitor->Visit("maxFragmentInputComponents", &limits->maxFragmentInputComponents) && - visitor->Visit("maxFragmentOutputAttachments", &limits->maxFragmentOutputAttachments) && - visitor->Visit("maxFragmentDualSrcAttachments", &limits->maxFragmentDualSrcAttachments) && - visitor->Visit("maxFragmentCombinedOutputResources", &limits->maxFragmentCombinedOutputResources) && - visitor->Visit("maxComputeSharedMemorySize", &limits->maxComputeSharedMemorySize) && - visitor->Visit("maxComputeWorkGroupCount", &limits->maxComputeWorkGroupCount) && - visitor->Visit("maxComputeWorkGroupInvocations", &limits->maxComputeWorkGroupInvocations) && - visitor->Visit("maxComputeWorkGroupSize", &limits->maxComputeWorkGroupSize) && - visitor->Visit("subPixelPrecisionBits", &limits->subPixelPrecisionBits) && - visitor->Visit("subTexelPrecisionBits", &limits->subTexelPrecisionBits) && - visitor->Visit("mipmapPrecisionBits", &limits->mipmapPrecisionBits) && - visitor->Visit("maxDrawIndexedIndexValue", &limits->maxDrawIndexedIndexValue) && - visitor->Visit("maxDrawIndirectCount", &limits->maxDrawIndirectCount) && - visitor->Visit("maxSamplerLodBias", &limits->maxSamplerLodBias) && - visitor->Visit("maxSamplerAnisotropy", &limits->maxSamplerAnisotropy) && - visitor->Visit("maxViewports", &limits->maxViewports) && - visitor->Visit("maxViewportDimensions", &limits->maxViewportDimensions) && - visitor->Visit("viewportBoundsRange", &limits->viewportBoundsRange) && - visitor->Visit("viewportSubPixelBits", &limits->viewportSubPixelBits) && - visitor->Visit("minMemoryMapAlignment", &limits->minMemoryMapAlignment) && - visitor->Visit("minTexelBufferOffsetAlignment", &limits->minTexelBufferOffsetAlignment) && - visitor->Visit("minUniformBufferOffsetAlignment", &limits->minUniformBufferOffsetAlignment) && - visitor->Visit("minStorageBufferOffsetAlignment", &limits->minStorageBufferOffsetAlignment) && - visitor->Visit("minTexelOffset", &limits->minTexelOffset) && - visitor->Visit("maxTexelOffset", &limits->maxTexelOffset) && - visitor->Visit("minTexelGatherOffset", &limits->minTexelGatherOffset) && - visitor->Visit("maxTexelGatherOffset", &limits->maxTexelGatherOffset) && - visitor->Visit("minInterpolationOffset", &limits->minInterpolationOffset) && - visitor->Visit("maxInterpolationOffset", &limits->maxInterpolationOffset) && - visitor->Visit("subPixelInterpolationOffsetBits", &limits->subPixelInterpolationOffsetBits) && - visitor->Visit("maxFramebufferWidth", &limits->maxFramebufferWidth) && - visitor->Visit("maxFramebufferHeight", &limits->maxFramebufferHeight) && - visitor->Visit("maxFramebufferLayers", &limits->maxFramebufferLayers) && - visitor->Visit("framebufferColorSampleCounts", &limits->framebufferColorSampleCounts) && - visitor->Visit("framebufferDepthSampleCounts", &limits->framebufferDepthSampleCounts) && - visitor->Visit("framebufferStencilSampleCounts", &limits->framebufferStencilSampleCounts) && - visitor->Visit("framebufferNoAttachmentsSampleCounts", &limits->framebufferNoAttachmentsSampleCounts) && - visitor->Visit("maxColorAttachments", &limits->maxColorAttachments) && - visitor->Visit("sampledImageColorSampleCounts", &limits->sampledImageColorSampleCounts) && - visitor->Visit("sampledImageIntegerSampleCounts", &limits->sampledImageIntegerSampleCounts) && - visitor->Visit("sampledImageDepthSampleCounts", &limits->sampledImageDepthSampleCounts) && - visitor->Visit("sampledImageStencilSampleCounts", &limits->sampledImageStencilSampleCounts) && - visitor->Visit("storageImageSampleCounts", &limits->storageImageSampleCounts) && - visitor->Visit("maxSampleMaskWords", &limits->maxSampleMaskWords) && - visitor->Visit("timestampComputeAndGraphics", &limits->timestampComputeAndGraphics) && - visitor->Visit("timestampPeriod", &limits->timestampPeriod) && - visitor->Visit("maxClipDistances", &limits->maxClipDistances) && - visitor->Visit("maxCullDistances", &limits->maxCullDistances) && - visitor->Visit("maxCombinedClipAndCullDistances", &limits->maxCombinedClipAndCullDistances) && - visitor->Visit("discreteQueuePriorities", &limits->discreteQueuePriorities) && - visitor->Visit("pointSizeRange", &limits->pointSizeRange) && - visitor->Visit("lineWidthRange", &limits->lineWidthRange) && - visitor->Visit("pointSizeGranularity", &limits->pointSizeGranularity) && - visitor->Visit("lineWidthGranularity", &limits->lineWidthGranularity) && - visitor->Visit("strictLines", &limits->strictLines) && - visitor->Visit("standardSampleLocations", &limits->standardSampleLocations) && - visitor->Visit("optimalBufferCopyOffsetAlignment", &limits->optimalBufferCopyOffsetAlignment) && - visitor->Visit("optimalBufferCopyRowPitchAlignment", &limits->optimalBufferCopyRowPitchAlignment) && - visitor->Visit("nonCoherentAtomSize", &limits->nonCoherentAtomSize); + + visitor->Visit("memoryTypeCount", &properties->memoryTypeCount) && + visitor->VisitArray("memoryTypes", properties->memoryTypeCount, + &properties->memoryTypes) && + visitor->Visit("memoryHeapCount", &properties->memoryHeapCount) && + visitor->VisitArray("memoryHeaps", properties->memoryHeapCount, + &properties->memoryHeaps); } template <typename Visitor> inline bool Iterate(Visitor* visitor, - VkPhysicalDeviceSparseProperties* properties) { + VkPhysicalDeviceSubgroupProperties* properties) { return - visitor->Visit("residencyStandard2DBlockShape", &properties->residencyStandard2DBlockShape) && - visitor->Visit("residencyStandard2DMultisampleBlockShape", &properties->residencyStandard2DMultisampleBlockShape) && - visitor->Visit("residencyStandard3DBlockShape", &properties->residencyStandard3DBlockShape) && - visitor->Visit("residencyAlignedMipSize", &properties->residencyAlignedMipSize) && - visitor->Visit("residencyNonResidentStrict", &properties->residencyNonResidentStrict); + + visitor->Visit("subgroupSize", &properties->subgroupSize) && + visitor->Visit("supportedStages", &properties->supportedStages) && + visitor->Visit("supportedOperations", &properties->supportedOperations) && + visitor->Visit("quadOperationsInAllStages", + &properties->quadOperationsInAllStages); } template <typename Visitor> inline bool Iterate(Visitor* visitor, - VkPhysicalDeviceProperties* properties) { + VkPhysicalDevicePointClippingProperties* properties) { return - visitor->Visit("apiVersion", &properties->apiVersion) && - visitor->Visit("driverVersion", &properties->driverVersion) && - visitor->Visit("vendorID", &properties->vendorID) && - visitor->Visit("deviceID", &properties->deviceID) && - visitor->Visit("deviceType", &properties->deviceType) && - visitor->Visit("deviceName", &properties->deviceName) && - visitor->Visit("pipelineCacheUUID", &properties->pipelineCacheUUID) && - visitor->Visit("limits", &properties->limits) && - visitor->Visit("sparseProperties", &properties->sparseProperties); + + visitor->Visit("pointClippingBehavior", + &properties->pointClippingBehavior); } template <typename Visitor> -inline bool Iterate(Visitor* visitor, VkPhysicalDeviceFeatures* features) { +inline bool Iterate(Visitor* visitor, + VkPhysicalDeviceMultiviewProperties* properties) { return - visitor->Visit("robustBufferAccess", &features->robustBufferAccess) && - visitor->Visit("fullDrawIndexUint32", &features->fullDrawIndexUint32) && - visitor->Visit("imageCubeArray", &features->imageCubeArray) && - visitor->Visit("independentBlend", &features->independentBlend) && - visitor->Visit("geometryShader", &features->geometryShader) && - visitor->Visit("tessellationShader", &features->tessellationShader) && - visitor->Visit("sampleRateShading", &features->sampleRateShading) && - visitor->Visit("dualSrcBlend", &features->dualSrcBlend) && - visitor->Visit("logicOp", &features->logicOp) && - visitor->Visit("multiDrawIndirect", &features->multiDrawIndirect) && - visitor->Visit("drawIndirectFirstInstance", &features->drawIndirectFirstInstance) && - visitor->Visit("depthClamp", &features->depthClamp) && - visitor->Visit("depthBiasClamp", &features->depthBiasClamp) && - visitor->Visit("fillModeNonSolid", &features->fillModeNonSolid) && - visitor->Visit("depthBounds", &features->depthBounds) && - visitor->Visit("wideLines", &features->wideLines) && - visitor->Visit("largePoints", &features->largePoints) && - visitor->Visit("alphaToOne", &features->alphaToOne) && - visitor->Visit("multiViewport", &features->multiViewport) && - visitor->Visit("samplerAnisotropy", &features->samplerAnisotropy) && - visitor->Visit("textureCompressionETC2", &features->textureCompressionETC2) && - visitor->Visit("textureCompressionASTC_LDR", &features->textureCompressionASTC_LDR) && - visitor->Visit("textureCompressionBC", &features->textureCompressionBC) && - visitor->Visit("occlusionQueryPrecise", &features->occlusionQueryPrecise) && - visitor->Visit("pipelineStatisticsQuery", &features->pipelineStatisticsQuery) && - visitor->Visit("vertexPipelineStoresAndAtomics", &features->vertexPipelineStoresAndAtomics) && - visitor->Visit("fragmentStoresAndAtomics", &features->fragmentStoresAndAtomics) && - visitor->Visit("shaderTessellationAndGeometryPointSize", &features->shaderTessellationAndGeometryPointSize) && - visitor->Visit("shaderImageGatherExtended", &features->shaderImageGatherExtended) && - visitor->Visit("shaderStorageImageExtendedFormats", &features->shaderStorageImageExtendedFormats) && - visitor->Visit("shaderStorageImageMultisample", &features->shaderStorageImageMultisample) && - visitor->Visit("shaderStorageImageReadWithoutFormat", &features->shaderStorageImageReadWithoutFormat) && - visitor->Visit("shaderStorageImageWriteWithoutFormat", &features->shaderStorageImageWriteWithoutFormat) && - visitor->Visit("shaderUniformBufferArrayDynamicIndexing", &features->shaderUniformBufferArrayDynamicIndexing) && - visitor->Visit("shaderSampledImageArrayDynamicIndexing", &features->shaderSampledImageArrayDynamicIndexing) && - visitor->Visit("shaderStorageBufferArrayDynamicIndexing", &features->shaderStorageBufferArrayDynamicIndexing) && - visitor->Visit("shaderStorageImageArrayDynamicIndexing", &features->shaderStorageImageArrayDynamicIndexing) && - visitor->Visit("shaderClipDistance", &features->shaderClipDistance) && - visitor->Visit("shaderCullDistance", &features->shaderCullDistance) && - visitor->Visit("shaderFloat64", &features->shaderFloat64) && - visitor->Visit("shaderInt64", &features->shaderInt64) && - visitor->Visit("shaderInt16", &features->shaderInt16) && - visitor->Visit("shaderResourceResidency", &features->shaderResourceResidency) && - visitor->Visit("shaderResourceMinLod", &features->shaderResourceMinLod) && - visitor->Visit("sparseBinding", &features->sparseBinding) && - visitor->Visit("sparseResidencyBuffer", &features->sparseResidencyBuffer) && - visitor->Visit("sparseResidencyImage2D", &features->sparseResidencyImage2D) && - visitor->Visit("sparseResidencyImage3D", &features->sparseResidencyImage3D) && - visitor->Visit("sparseResidency2Samples", &features->sparseResidency2Samples) && - visitor->Visit("sparseResidency4Samples", &features->sparseResidency4Samples) && - visitor->Visit("sparseResidency8Samples", &features->sparseResidency8Samples) && - visitor->Visit("sparseResidency16Samples", &features->sparseResidency16Samples) && - visitor->Visit("sparseResidencyAliased", &features->sparseResidencyAliased) && - visitor->Visit("variableMultisampleRate", &features->variableMultisampleRate) && - visitor->Visit("inheritedQueries", &features->inheritedQueries); + + visitor->Visit("maxMultiviewViewCount", + &properties->maxMultiviewViewCount) && + visitor->Visit("maxMultiviewInstanceIndex", + &properties->maxMultiviewInstanceIndex); } template <typename Visitor> -inline bool Iterate(Visitor* visitor, VkJsonCore12* core) { +inline bool Iterate(Visitor* visitor, + VkPhysicalDeviceIDProperties* properties) { return - visitor->Visit("features", &core->features) && - visitor->Visit("properties", &core->properties); + + visitor->Visit("deviceUUID", &properties->deviceUUID) && + visitor->Visit("driverUUID", &properties->driverUUID) && + visitor->Visit("deviceLUID", &properties->deviceLUID) && + visitor->Visit("deviceNodeMask", &properties->deviceNodeMask) && + visitor->Visit("deviceLUIDValid", &properties->deviceLUIDValid); } template <typename Visitor> -inline bool Iterate(Visitor* visitor, VkPhysicalDeviceVulkan12Properties* properties) { +inline bool Iterate(Visitor* visitor, + VkPhysicalDeviceMaintenance3Properties* properties) { return - visitor->Visit("driverID", &properties->driverID) && - visitor->Visit("driverName", &properties->driverName) && - visitor->Visit("driverInfo", &properties->driverInfo) && - visitor->Visit("conformanceVersion", &properties->conformanceVersion) && - visitor->Visit("denormBehaviorIndependence", &properties->denormBehaviorIndependence) && - visitor->Visit("roundingModeIndependence", &properties->roundingModeIndependence) && - visitor->Visit("shaderSignedZeroInfNanPreserveFloat16", &properties->shaderSignedZeroInfNanPreserveFloat16) && - visitor->Visit("shaderSignedZeroInfNanPreserveFloat32", &properties->shaderSignedZeroInfNanPreserveFloat32) && - visitor->Visit("shaderSignedZeroInfNanPreserveFloat64", &properties->shaderSignedZeroInfNanPreserveFloat64) && - visitor->Visit("shaderDenormPreserveFloat16", &properties->shaderDenormPreserveFloat16) && - visitor->Visit("shaderDenormPreserveFloat32", &properties->shaderDenormPreserveFloat32) && - visitor->Visit("shaderDenormPreserveFloat64", &properties->shaderDenormPreserveFloat64) && - visitor->Visit("shaderDenormFlushToZeroFloat16", &properties->shaderDenormFlushToZeroFloat16) && - visitor->Visit("shaderDenormFlushToZeroFloat32", &properties->shaderDenormFlushToZeroFloat32) && - visitor->Visit("shaderDenormFlushToZeroFloat64", &properties->shaderDenormFlushToZeroFloat64) && - visitor->Visit("shaderRoundingModeRTEFloat16", &properties->shaderRoundingModeRTEFloat16) && - visitor->Visit("shaderRoundingModeRTEFloat32", &properties->shaderRoundingModeRTEFloat32) && - visitor->Visit("shaderRoundingModeRTEFloat64", &properties->shaderRoundingModeRTEFloat64) && - visitor->Visit("shaderRoundingModeRTZFloat16", &properties->shaderRoundingModeRTZFloat16) && - visitor->Visit("shaderRoundingModeRTZFloat32", &properties->shaderRoundingModeRTZFloat32) && - visitor->Visit("shaderRoundingModeRTZFloat64", &properties->shaderRoundingModeRTZFloat64) && - visitor->Visit("maxUpdateAfterBindDescriptorsInAllPools", &properties->maxUpdateAfterBindDescriptorsInAllPools) && - visitor->Visit("shaderUniformBufferArrayNonUniformIndexingNative", &properties->shaderUniformBufferArrayNonUniformIndexingNative) && - visitor->Visit("shaderSampledImageArrayNonUniformIndexingNative", &properties->shaderSampledImageArrayNonUniformIndexingNative) && - visitor->Visit("shaderStorageBufferArrayNonUniformIndexingNative", &properties->shaderStorageBufferArrayNonUniformIndexingNative) && - visitor->Visit("shaderStorageImageArrayNonUniformIndexingNative", &properties->shaderStorageImageArrayNonUniformIndexingNative) && - visitor->Visit("shaderInputAttachmentArrayNonUniformIndexingNative", &properties->shaderInputAttachmentArrayNonUniformIndexingNative) && - visitor->Visit("robustBufferAccessUpdateAfterBind", &properties->robustBufferAccessUpdateAfterBind) && - visitor->Visit("quadDivergentImplicitLod", &properties->quadDivergentImplicitLod) && - visitor->Visit("maxPerStageDescriptorUpdateAfterBindSamplers", &properties->maxPerStageDescriptorUpdateAfterBindSamplers) && - visitor->Visit("maxPerStageDescriptorUpdateAfterBindUniformBuffers", &properties->maxPerStageDescriptorUpdateAfterBindUniformBuffers) && - visitor->Visit("maxPerStageDescriptorUpdateAfterBindStorageBuffers", &properties->maxPerStageDescriptorUpdateAfterBindStorageBuffers) && - visitor->Visit("maxPerStageDescriptorUpdateAfterBindSampledImages", &properties->maxPerStageDescriptorUpdateAfterBindSampledImages) && - visitor->Visit("maxPerStageDescriptorUpdateAfterBindStorageImages", &properties->maxPerStageDescriptorUpdateAfterBindStorageImages) && - visitor->Visit("maxPerStageDescriptorUpdateAfterBindInputAttachments", &properties->maxPerStageDescriptorUpdateAfterBindInputAttachments) && - visitor->Visit("maxPerStageUpdateAfterBindResources", &properties->maxPerStageUpdateAfterBindResources) && - visitor->Visit("maxDescriptorSetUpdateAfterBindSamplers", &properties->maxDescriptorSetUpdateAfterBindSamplers) && - visitor->Visit("maxDescriptorSetUpdateAfterBindUniformBuffers", &properties->maxDescriptorSetUpdateAfterBindUniformBuffers) && - visitor->Visit("maxDescriptorSetUpdateAfterBindUniformBuffersDynamic", &properties->maxDescriptorSetUpdateAfterBindUniformBuffersDynamic) && - visitor->Visit("maxDescriptorSetUpdateAfterBindStorageBuffers", &properties->maxDescriptorSetUpdateAfterBindStorageBuffers) && - visitor->Visit("maxDescriptorSetUpdateAfterBindStorageBuffersDynamic", &properties->maxDescriptorSetUpdateAfterBindStorageBuffersDynamic) && - visitor->Visit("maxDescriptorSetUpdateAfterBindSampledImages", &properties->maxDescriptorSetUpdateAfterBindSampledImages) && - visitor->Visit("maxDescriptorSetUpdateAfterBindStorageImages", &properties->maxDescriptorSetUpdateAfterBindStorageImages) && - visitor->Visit("maxDescriptorSetUpdateAfterBindInputAttachments", &properties->maxDescriptorSetUpdateAfterBindInputAttachments) && - visitor->Visit("supportedDepthResolveModes", &properties->supportedDepthResolveModes) && - visitor->Visit("supportedStencilResolveModes", &properties->supportedStencilResolveModes) && - visitor->Visit("independentResolveNone", &properties->independentResolveNone) && - visitor->Visit("independentResolve", &properties->independentResolve) && - visitor->Visit("filterMinmaxSingleComponentFormats", &properties->filterMinmaxSingleComponentFormats) && - visitor->Visit("filterMinmaxImageComponentMapping", &properties->filterMinmaxImageComponentMapping) && - visitor->Visit("maxTimelineSemaphoreValueDifference", &properties->maxTimelineSemaphoreValueDifference) && - visitor->Visit("framebufferIntegerColorSampleCounts", &properties->framebufferIntegerColorSampleCounts); -} - -template <typename Visitor> -inline bool Iterate(Visitor* visitor, VkPhysicalDeviceVulkan12Features* features) { + + visitor->Visit("maxPerSetDescriptors", + &properties->maxPerSetDescriptors) && + visitor->Visit("maxMemoryAllocationSize", + &properties->maxMemoryAllocationSize); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, + VkPhysicalDeviceSparseProperties* properties) { return - visitor->Visit("samplerMirrorClampToEdge", &features->samplerMirrorClampToEdge) && - visitor->Visit("drawIndirectCount", &features->drawIndirectCount) && - visitor->Visit("storageBuffer8BitAccess", &features->storageBuffer8BitAccess) && - visitor->Visit("uniformAndStorageBuffer8BitAccess", &features->uniformAndStorageBuffer8BitAccess) && - visitor->Visit("storagePushConstant8", &features->storagePushConstant8) && - visitor->Visit("shaderBufferInt64Atomics", &features->shaderBufferInt64Atomics) && - visitor->Visit("shaderSharedInt64Atomics", &features->shaderSharedInt64Atomics) && - visitor->Visit("shaderFloat16", &features->shaderFloat16) && - visitor->Visit("shaderInt8", &features->shaderInt8) && - visitor->Visit("descriptorIndexing", &features->descriptorIndexing) && - visitor->Visit("shaderInputAttachmentArrayDynamicIndexing", &features->shaderInputAttachmentArrayDynamicIndexing) && - visitor->Visit("shaderUniformTexelBufferArrayDynamicIndexing", &features->shaderUniformTexelBufferArrayDynamicIndexing) && - visitor->Visit("shaderStorageTexelBufferArrayDynamicIndexing", &features->shaderStorageTexelBufferArrayDynamicIndexing) && - visitor->Visit("shaderUniformBufferArrayNonUniformIndexing", &features->shaderUniformBufferArrayNonUniformIndexing) && - visitor->Visit("shaderSampledImageArrayNonUniformIndexing", &features->shaderSampledImageArrayNonUniformIndexing) && - visitor->Visit("shaderStorageBufferArrayNonUniformIndexing", &features->shaderStorageBufferArrayNonUniformIndexing) && - visitor->Visit("shaderStorageImageArrayNonUniformIndexing", &features->shaderStorageImageArrayNonUniformIndexing) && - visitor->Visit("shaderInputAttachmentArrayNonUniformIndexing", &features->shaderInputAttachmentArrayNonUniformIndexing) && - visitor->Visit("shaderUniformTexelBufferArrayNonUniformIndexing", &features->shaderUniformTexelBufferArrayNonUniformIndexing) && - visitor->Visit("shaderStorageTexelBufferArrayNonUniformIndexing", &features->shaderStorageTexelBufferArrayNonUniformIndexing) && - visitor->Visit("descriptorBindingUniformBufferUpdateAfterBind", &features->descriptorBindingUniformBufferUpdateAfterBind) && - visitor->Visit("descriptorBindingSampledImageUpdateAfterBind", &features->descriptorBindingSampledImageUpdateAfterBind) && - visitor->Visit("descriptorBindingStorageImageUpdateAfterBind", &features->descriptorBindingStorageImageUpdateAfterBind) && - visitor->Visit("descriptorBindingStorageBufferUpdateAfterBind", &features->descriptorBindingStorageBufferUpdateAfterBind) && - visitor->Visit("descriptorBindingUniformTexelBufferUpdateAfterBind", &features->descriptorBindingUniformTexelBufferUpdateAfterBind) && - visitor->Visit("descriptorBindingStorageTexelBufferUpdateAfterBind", &features->descriptorBindingStorageTexelBufferUpdateAfterBind) && - visitor->Visit("descriptorBindingUpdateUnusedWhilePending", &features->descriptorBindingUpdateUnusedWhilePending) && - visitor->Visit("descriptorBindingPartiallyBound", &features->descriptorBindingPartiallyBound) && - visitor->Visit("descriptorBindingVariableDescriptorCount", &features->descriptorBindingVariableDescriptorCount) && - visitor->Visit("runtimeDescriptorArray", &features->runtimeDescriptorArray) && - visitor->Visit("samplerFilterMinmax", &features->samplerFilterMinmax) && - visitor->Visit("scalarBlockLayout", &features->scalarBlockLayout) && - visitor->Visit("imagelessFramebuffer", &features->imagelessFramebuffer) && - visitor->Visit("uniformBufferStandardLayout", &features->uniformBufferStandardLayout) && - visitor->Visit("shaderSubgroupExtendedTypes", &features->shaderSubgroupExtendedTypes) && - visitor->Visit("separateDepthStencilLayouts", &features->separateDepthStencilLayouts) && - visitor->Visit("hostQueryReset", &features->hostQueryReset) && - visitor->Visit("timelineSemaphore", &features->timelineSemaphore) && - visitor->Visit("bufferDeviceAddress", &features->bufferDeviceAddress) && - visitor->Visit("bufferDeviceAddressCaptureReplay", &features->bufferDeviceAddressCaptureReplay) && - visitor->Visit("bufferDeviceAddressMultiDevice", &features->bufferDeviceAddressMultiDevice) && - visitor->Visit("vulkanMemoryModel", &features->vulkanMemoryModel) && - visitor->Visit("vulkanMemoryModelDeviceScope", &features->vulkanMemoryModelDeviceScope) && - visitor->Visit("vulkanMemoryModelAvailabilityVisibilityChains", &features->vulkanMemoryModelAvailabilityVisibilityChains) && - visitor->Visit("shaderOutputViewportIndex", &features->shaderOutputViewportIndex) && - visitor->Visit("shaderOutputLayer", &features->shaderOutputLayer) && - visitor->Visit("subgroupBroadcastDynamicId", &features->subgroupBroadcastDynamicId); + + visitor->Visit("residencyStandard2DBlockShape", + &properties->residencyStandard2DBlockShape) && + visitor->Visit("residencyStandard2DMultisampleBlockShape", + &properties->residencyStandard2DMultisampleBlockShape) && + visitor->Visit("residencyStandard3DBlockShape", + &properties->residencyStandard3DBlockShape) && + visitor->Visit("residencyAlignedMipSize", + &properties->residencyAlignedMipSize) && + visitor->Visit("residencyNonResidentStrict", + &properties->residencyNonResidentStrict); } template <typename Visitor> -inline bool Iterate(Visitor* visitor, VkJsonCore13* core) { +inline bool Iterate(Visitor* visitor, VkImageFormatProperties* properties) { return - visitor->Visit("features", &core->features) && - visitor->Visit("properties", &core->properties); + + visitor->Visit("maxExtent", &properties->maxExtent) && + visitor->Visit("maxMipLevels", &properties->maxMipLevels) && + visitor->Visit("maxArrayLayers", &properties->maxArrayLayers) && + visitor->Visit("sampleCounts", &properties->sampleCounts) && + visitor->Visit("maxResourceSize", &properties->maxResourceSize); } template <typename Visitor> -inline bool Iterate(Visitor* visitor, VkPhysicalDeviceVulkan13Properties* properties) { +inline bool Iterate(Visitor* visitor, VkQueueFamilyProperties* properties) { return - visitor->Visit("minSubgroupSize", &properties->minSubgroupSize) && - visitor->Visit("maxSubgroupSize", &properties->maxSubgroupSize) && - visitor->Visit("maxComputeWorkgroupSubgroups", &properties->maxComputeWorkgroupSubgroups) && - visitor->Visit("requiredSubgroupSizeStages", &properties->requiredSubgroupSizeStages) && - visitor->Visit("maxInlineUniformBlockSize", &properties->maxInlineUniformBlockSize) && - visitor->Visit("maxPerStageDescriptorInlineUniformBlocks", &properties->maxPerStageDescriptorInlineUniformBlocks) && - visitor->Visit("maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks", &properties->maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks) && - visitor->Visit("maxDescriptorSetInlineUniformBlocks", &properties->maxDescriptorSetInlineUniformBlocks) && - visitor->Visit("maxDescriptorSetUpdateAfterBindInlineUniformBlocks", &properties->maxDescriptorSetUpdateAfterBindInlineUniformBlocks) && - visitor->Visit("maxInlineUniformTotalSize", &properties->maxInlineUniformTotalSize) && - visitor->Visit("integerDotProduct8BitUnsignedAccelerated", &properties->integerDotProduct8BitUnsignedAccelerated) && - visitor->Visit("integerDotProduct8BitSignedAccelerated", &properties->integerDotProduct8BitSignedAccelerated) && - visitor->Visit("integerDotProduct8BitMixedSignednessAccelerated", &properties->integerDotProduct8BitMixedSignednessAccelerated) && - visitor->Visit("integerDotProduct4x8BitPackedUnsignedAccelerated", &properties->integerDotProduct4x8BitPackedUnsignedAccelerated) && - visitor->Visit("integerDotProduct4x8BitPackedSignedAccelerated", &properties->integerDotProduct4x8BitPackedSignedAccelerated) && - visitor->Visit("integerDotProduct4x8BitPackedMixedSignednessAccelerated", &properties->integerDotProduct4x8BitPackedMixedSignednessAccelerated) && - visitor->Visit("integerDotProduct16BitUnsignedAccelerated", &properties->integerDotProduct16BitUnsignedAccelerated) && - visitor->Visit("integerDotProduct16BitSignedAccelerated", &properties->integerDotProduct16BitSignedAccelerated) && - visitor->Visit("integerDotProduct16BitMixedSignednessAccelerated", &properties->integerDotProduct16BitMixedSignednessAccelerated) && - visitor->Visit("integerDotProduct32BitUnsignedAccelerated", &properties->integerDotProduct32BitUnsignedAccelerated) && - visitor->Visit("integerDotProduct32BitSignedAccelerated", &properties->integerDotProduct32BitSignedAccelerated) && - visitor->Visit("integerDotProduct32BitMixedSignednessAccelerated", &properties->integerDotProduct32BitMixedSignednessAccelerated) && - visitor->Visit("integerDotProduct64BitUnsignedAccelerated", &properties->integerDotProduct64BitUnsignedAccelerated) && - visitor->Visit("integerDotProduct64BitSignedAccelerated", &properties->integerDotProduct64BitSignedAccelerated) && - visitor->Visit("integerDotProduct64BitMixedSignednessAccelerated", &properties->integerDotProduct64BitMixedSignednessAccelerated) && - visitor->Visit("integerDotProductAccumulatingSaturating8BitUnsignedAccelerated", &properties->integerDotProductAccumulatingSaturating8BitUnsignedAccelerated) && - visitor->Visit("integerDotProductAccumulatingSaturating8BitSignedAccelerated", &properties->integerDotProductAccumulatingSaturating8BitSignedAccelerated) && - visitor->Visit("integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated", &properties->integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated) && - visitor->Visit("integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated", &properties->integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated) && - visitor->Visit("integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated", &properties->integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated) && - visitor->Visit("integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated", &properties->integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated) && - visitor->Visit("integerDotProductAccumulatingSaturating16BitUnsignedAccelerated", &properties->integerDotProductAccumulatingSaturating16BitUnsignedAccelerated) && - visitor->Visit("integerDotProductAccumulatingSaturating16BitSignedAccelerated", &properties->integerDotProductAccumulatingSaturating16BitSignedAccelerated) && - visitor->Visit("integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated", &properties->integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated) && - visitor->Visit("integerDotProductAccumulatingSaturating32BitUnsignedAccelerated", &properties->integerDotProductAccumulatingSaturating32BitUnsignedAccelerated) && - visitor->Visit("integerDotProductAccumulatingSaturating32BitSignedAccelerated", &properties->integerDotProductAccumulatingSaturating32BitSignedAccelerated) && - visitor->Visit("integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated", &properties->integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated) && - visitor->Visit("integerDotProductAccumulatingSaturating64BitUnsignedAccelerated", &properties->integerDotProductAccumulatingSaturating64BitUnsignedAccelerated) && - visitor->Visit("integerDotProductAccumulatingSaturating64BitSignedAccelerated", &properties->integerDotProductAccumulatingSaturating64BitSignedAccelerated) && - visitor->Visit("integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated", &properties->integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated) && - visitor->Visit("storageTexelBufferOffsetAlignmentBytes", &properties->storageTexelBufferOffsetAlignmentBytes) && - visitor->Visit("storageTexelBufferOffsetSingleTexelAlignment", &properties->storageTexelBufferOffsetSingleTexelAlignment) && - visitor->Visit("uniformTexelBufferOffsetAlignmentBytes", &properties->uniformTexelBufferOffsetAlignmentBytes) && - visitor->Visit("uniformTexelBufferOffsetSingleTexelAlignment", &properties->uniformTexelBufferOffsetSingleTexelAlignment) && - visitor->Visit("maxBufferSize", &properties->maxBufferSize); -} - -template <typename Visitor> -inline bool Iterate(Visitor* visitor, VkPhysicalDeviceVulkan13Features* features) { + + visitor->Visit("queueFlags", &properties->queueFlags) && + visitor->Visit("queueCount", &properties->queueCount) && + visitor->Visit("timestampValidBits", &properties->timestampValidBits) && + visitor->Visit("minImageTransferGranularity", + &properties->minImageTransferGranularity); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkExtensionProperties* properties) { return - visitor->Visit("robustImageAccess", &features->robustImageAccess) && - visitor->Visit("inlineUniformBlock", &features->inlineUniformBlock) && - visitor->Visit("descriptorBindingInlineUniformBlockUpdateAfterBind", &features->descriptorBindingInlineUniformBlockUpdateAfterBind) && - visitor->Visit("pipelineCreationCacheControl", &features->pipelineCreationCacheControl) && - visitor->Visit("privateData", &features->privateData) && - visitor->Visit("shaderDemoteToHelperInvocation", &features->shaderDemoteToHelperInvocation) && - visitor->Visit("shaderTerminateInvocation", &features->shaderTerminateInvocation) && - visitor->Visit("subgroupSizeControl", &features->subgroupSizeControl) && - visitor->Visit("computeFullSubgroups", &features->computeFullSubgroups) && - visitor->Visit("synchronization2", &features->synchronization2) && - visitor->Visit("textureCompressionASTC_HDR", &features->textureCompressionASTC_HDR) && - visitor->Visit("shaderZeroInitializeWorkgroupMemory", &features->shaderZeroInitializeWorkgroupMemory) && - visitor->Visit("dynamicRendering", &features->dynamicRendering) && - visitor->Visit("shaderIntegerDotProduct", &features->shaderIntegerDotProduct) && - visitor->Visit("maintenance4", &features->maintenance4); + + visitor->Visit("extensionName", &properties->extensionName) && + visitor->Visit("specVersion", &properties->specVersion); } template <typename Visitor> -inline bool Iterate(Visitor* visitor, VkJsonCore14* core) { +inline bool Iterate(Visitor* visitor, VkLayerProperties* properties) { return - visitor->Visit("features", &core->features) && - visitor->Visit("properties", &core->properties); + + visitor->Visit("layerName", &properties->layerName) && + visitor->Visit("specVersion", &properties->specVersion) && + visitor->Visit("implementationVersion", + &properties->implementationVersion) && + visitor->Visit("description", &properties->description); } template <typename Visitor> -inline bool Iterate(Visitor* visitor, VkPhysicalDeviceVulkan14Properties* properties) { +inline bool Iterate(Visitor* visitor, VkFormatProperties* properties) { return - visitor->Visit("lineSubPixelPrecisionBits", &properties->lineSubPixelPrecisionBits) && - visitor->Visit("maxVertexAttribDivisor", &properties->maxVertexAttribDivisor) && - visitor->Visit("supportsNonZeroFirstInstance", &properties->supportsNonZeroFirstInstance) && - visitor->Visit("maxPushDescriptors", &properties->maxPushDescriptors) && - visitor->Visit("dynamicRenderingLocalReadDepthStencilAttachments", &properties->dynamicRenderingLocalReadDepthStencilAttachments) && - visitor->Visit("dynamicRenderingLocalReadMultisampledAttachments", &properties->dynamicRenderingLocalReadMultisampledAttachments) && - visitor->Visit("earlyFragmentMultisampleCoverageAfterSampleCounting", &properties->earlyFragmentMultisampleCoverageAfterSampleCounting) && - visitor->Visit("earlyFragmentSampleMaskTestBeforeSampleCounting", &properties->earlyFragmentSampleMaskTestBeforeSampleCounting) && - visitor->Visit("depthStencilSwizzleOneSupport", &properties->depthStencilSwizzleOneSupport) && - visitor->Visit("polygonModePointSize", &properties->polygonModePointSize) && - visitor->Visit("nonStrictSinglePixelWideLinesUseParallelogram", &properties->nonStrictSinglePixelWideLinesUseParallelogram) && - visitor->Visit("nonStrictWideLinesUseParallelogram", &properties->nonStrictWideLinesUseParallelogram) && - visitor->Visit("blockTexelViewCompatibleMultipleLayers", &properties->blockTexelViewCompatibleMultipleLayers) && - visitor->Visit("maxCombinedImageSamplerDescriptorCount", &properties->maxCombinedImageSamplerDescriptorCount) && - visitor->Visit("fragmentShadingRateClampCombinerInputs", &properties->fragmentShadingRateClampCombinerInputs) && - visitor->Visit("defaultRobustnessStorageBuffers", &properties->defaultRobustnessStorageBuffers) && - visitor->Visit("defaultRobustnessUniformBuffers", &properties->defaultRobustnessUniformBuffers) && - visitor->Visit("defaultRobustnessVertexInputs", &properties->defaultRobustnessVertexInputs) && - visitor->Visit("defaultRobustnessImages", &properties->defaultRobustnessImages) && - visitor->Visit("copySrcLayoutCount", &properties->copySrcLayoutCount) && - visitor->VisitArray("pCopySrcLayouts", properties->copySrcLayoutCount, &properties->pCopySrcLayouts) && - visitor->Visit("copyDstLayoutCount", &properties->copyDstLayoutCount) && - visitor->VisitArray("pCopyDstLayouts", properties->copyDstLayoutCount, &properties->pCopyDstLayouts) && - visitor->Visit("optimalTilingLayoutUUID", &properties->optimalTilingLayoutUUID) && - visitor->Visit("identicalMemoryTypeRequirements", &properties->identicalMemoryTypeRequirements); -} - -template <typename Visitor> -inline bool Iterate(Visitor* visitor, VkPhysicalDeviceVulkan14Features* features) { + + visitor->Visit("linearTilingFeatures", + &properties->linearTilingFeatures) && + visitor->Visit("optimalTilingFeatures", + &properties->optimalTilingFeatures) && + visitor->Visit("bufferFeatures", &properties->bufferFeatures); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, + VkPhysicalDeviceVariablePointersFeatures* features) { return - visitor->Visit("globalPriorityQuery", &features->globalPriorityQuery) && - visitor->Visit("shaderSubgroupRotate", &features->shaderSubgroupRotate) && - visitor->Visit("shaderSubgroupRotateClustered", &features->shaderSubgroupRotateClustered) && - visitor->Visit("shaderFloatControls2", &features->shaderFloatControls2) && - visitor->Visit("shaderExpectAssume", &features->shaderExpectAssume) && - visitor->Visit("rectangularLines", &features->rectangularLines) && - visitor->Visit("bresenhamLines", &features->bresenhamLines) && - visitor->Visit("smoothLines", &features->smoothLines) && - visitor->Visit("stippledRectangularLines", &features->stippledRectangularLines) && - visitor->Visit("stippledBresenhamLines", &features->stippledBresenhamLines) && - visitor->Visit("stippledSmoothLines", &features->stippledSmoothLines) && - visitor->Visit("vertexAttributeInstanceRateDivisor", &features->vertexAttributeInstanceRateDivisor) && - visitor->Visit("vertexAttributeInstanceRateZeroDivisor", &features->vertexAttributeInstanceRateZeroDivisor) && - visitor->Visit("indexTypeUint8", &features->indexTypeUint8) && - visitor->Visit("dynamicRenderingLocalRead", &features->dynamicRenderingLocalRead) && - visitor->Visit("maintenance5", &features->maintenance5) && - visitor->Visit("maintenance6", &features->maintenance6) && - visitor->Visit("pipelineProtectedAccess", &features->pipelineProtectedAccess) && - visitor->Visit("pipelineRobustness", &features->pipelineRobustness) && - visitor->Visit("hostImageCopy", &features->hostImageCopy); -} -// clang-format on + + visitor->Visit("variablePointersStorageBuffer", + &features->variablePointersStorageBuffer) && + visitor->Visit("variablePointers", &features->variablePointers); +} template <typename Visitor> inline bool Iterate(Visitor* visitor, - VkJsonExtDriverProperties* properties) { - return visitor->Visit("driverPropertiesKHR", - &properties->driver_properties_khr); + VkPhysicalDeviceShaderFloat16Int8Features* features) { + return + + visitor->Visit("shaderFloat16", &features->shaderFloat16) && + visitor->Visit("shaderInt8", &features->shaderInt8); } template <typename Visitor> inline bool Iterate(Visitor* visitor, - VkPhysicalDeviceDriverPropertiesKHR* properties) { - return visitor->Visit("driverID", &properties->driverID) && - visitor->Visit("driverName", &properties->driverName) && - visitor->Visit("driverInfo", &properties->driverInfo) && - visitor->Visit("conformanceVersion", &properties->conformanceVersion); + VkPhysicalDeviceImage2DViewOf3DFeaturesEXT* features) { + return + + visitor->Visit("image2DViewOf3D", &features->image2DViewOf3D) && + visitor->Visit("sampler2DViewOf3D", &features->sampler2DViewOf3D); } template <typename Visitor> inline bool Iterate(Visitor* visitor, - VkConformanceVersionKHR* version) { - return visitor->Visit("major", &version->major) && - visitor->Visit("minor", &version->minor) && - visitor->Visit("subminor", &version->subminor) && - visitor->Visit("patch", &version->patch); + VkPhysicalDeviceCustomBorderColorFeaturesEXT* features) { + return + + visitor->Visit("customBorderColors", &features->customBorderColors) && + visitor->Visit("customBorderColorWithoutFormat", + &features->customBorderColorWithoutFormat); +} + +template <typename Visitor> +inline bool Iterate( + Visitor* visitor, + VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT* features) { + return + + visitor->Visit("primitiveTopologyListRestart", + &features->primitiveTopologyListRestart) && + visitor->Visit("primitiveTopologyPatchListRestart", + &features->primitiveTopologyPatchListRestart); } template <typename Visitor> inline bool Iterate(Visitor* visitor, - VkJsonExtVariablePointerFeatures* features) { - return visitor->Visit("variablePointerFeaturesKHR", - &features->variable_pointer_features_khr); + VkPhysicalDeviceProvokingVertexFeaturesEXT* features) { + return + + visitor->Visit("provokingVertexLast", &features->provokingVertexLast) && + visitor->Visit("transformFeedbackPreservesProvokingVertex", + &features->transformFeedbackPreservesProvokingVertex); } template <typename Visitor> inline bool Iterate(Visitor* visitor, - VkJsonExtImage2DViewOf3DFeatures* features) { - return visitor->Visit("image2DViewOf3DFeaturesEXT", - &features->image_2D_view_of_3D_features_EXT); + VkPhysicalDeviceIndexTypeUint8Features* features) { + return + + visitor->Visit("indexTypeUint8", &features->indexTypeUint8); } template <typename Visitor> inline bool Iterate(Visitor* visitor, - VkJsonExtShaderFloat16Int8Features* features) { - return visitor->Visit("shaderFloat16Int8FeaturesKHR", - &features->shader_float16_int8_features_khr); + VkPhysicalDeviceVertexAttributeDivisorFeatures* features) { + return + + visitor->Visit("vertexAttributeInstanceRateDivisor", + &features->vertexAttributeInstanceRateDivisor) && + visitor->Visit("vertexAttributeInstanceRateZeroDivisor", + &features->vertexAttributeInstanceRateZeroDivisor); } template <typename Visitor> -inline bool Iterate(Visitor* visitor, VkMemoryType* type) { +inline bool Iterate(Visitor* visitor, + VkPhysicalDeviceTransformFeedbackFeaturesEXT* features) { return - visitor->Visit("propertyFlags", &type->propertyFlags) && - visitor->Visit("heapIndex", &type->heapIndex); + + visitor->Visit("transformFeedback", &features->transformFeedback) && + visitor->Visit("geometryStreams", &features->geometryStreams); } template <typename Visitor> -inline bool Iterate(Visitor* visitor, VkMemoryHeap* heap) { +inline bool Iterate( + Visitor* visitor, + VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR* features) { return - visitor->Visit("size", &heap->size) && - visitor->Visit("flags", &heap->flags); + + visitor->Visit("shaderSubgroupUniformControlFlow", + &features->shaderSubgroupUniformControlFlow); } template <typename Visitor> -inline bool Iterate(Visitor* visitor, VkPhysicalDeviceMemoryProperties* properties) { +inline bool Iterate( + Visitor* visitor, + VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures* features) { return - visitor->Visit("memoryTypeCount", &properties->memoryTypeCount) && - visitor->VisitArray("memoryTypes", properties->memoryTypeCount, &properties->memoryTypes) && - visitor->Visit("memoryHeapCount", &properties->memoryHeapCount) && - visitor->VisitArray("memoryHeaps", properties->memoryHeapCount, &properties->memoryHeaps); + + visitor->Visit("shaderSubgroupExtendedTypes", + &features->shaderSubgroupExtendedTypes); } template <typename Visitor> inline bool Iterate(Visitor* visitor, - VkPhysicalDeviceSubgroupProperties* properties) { - return visitor->Visit("subgroupSize", &properties->subgroupSize) && - visitor->Visit("supportedStages", &properties->supportedStages) && - visitor->Visit("supportedOperations", - &properties->supportedOperations) && - visitor->Visit("quadOperationsInAllStages", - &properties->quadOperationsInAllStages); + VkPhysicalDevice8BitStorageFeatures* features) { + return + + visitor->Visit("storageBuffer8BitAccess", + &features->storageBuffer8BitAccess) && + visitor->Visit("uniformAndStorageBuffer8BitAccess", + &features->uniformAndStorageBuffer8BitAccess) && + visitor->Visit("storagePushConstant8", &features->storagePushConstant8); } template <typename Visitor> inline bool Iterate(Visitor* visitor, - VkPhysicalDevicePointClippingProperties* properties) { - return visitor->Visit("pointClippingBehavior", - &properties->pointClippingBehavior); + VkPhysicalDeviceShaderIntegerDotProductFeatures* features) { + return + + visitor->Visit("shaderIntegerDotProduct", + &features->shaderIntegerDotProduct); } template <typename Visitor> -inline bool Iterate(Visitor* visitor, - VkPhysicalDeviceMultiviewProperties* properties) { - return visitor->Visit("maxMultiviewViewCount", - &properties->maxMultiviewViewCount) && - visitor->Visit("maxMultiviewInstanceIndex", - &properties->maxMultiviewInstanceIndex); +inline bool Iterate( + Visitor* visitor, + VkPhysicalDeviceRelaxedLineRasterizationFeaturesIMG* features) { + return + + visitor->Visit("relaxedLineRasterization", + &features->relaxedLineRasterization); } template <typename Visitor> inline bool Iterate(Visitor* visitor, - VkPhysicalDeviceIDProperties* properties) { - return visitor->Visit("deviceUUID", &properties->deviceUUID) && - visitor->Visit("driverUUID", &properties->driverUUID) && - visitor->Visit("deviceLUID", &properties->deviceLUID) && - visitor->Visit("deviceNodeMask", &properties->deviceNodeMask) && - visitor->Visit("deviceLUIDValid", &properties->deviceLUIDValid); + VkPhysicalDeviceLineRasterizationFeatures* features) { + return + + visitor->Visit("rectangularLines", &features->rectangularLines) && + visitor->Visit("bresenhamLines", &features->bresenhamLines) && + visitor->Visit("smoothLines", &features->smoothLines) && + visitor->Visit("stippledRectangularLines", + &features->stippledRectangularLines) && + visitor->Visit("stippledBresenhamLines", + &features->stippledBresenhamLines) && + visitor->Visit("stippledSmoothLines", &features->stippledSmoothLines); } template <typename Visitor> -inline bool Iterate(Visitor* visitor, - VkPhysicalDeviceMaintenance3Properties* properties) { - return visitor->Visit("maxPerSetDescriptors", - &properties->maxPerSetDescriptors) && - visitor->Visit("maxMemoryAllocationSize", - &properties->maxMemoryAllocationSize); +inline bool Iterate( + Visitor* visitor, + VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT* features) { + return + + visitor->Visit("primitivesGeneratedQuery", + &features->primitivesGeneratedQuery) && + visitor->Visit( + "primitivesGeneratedQueryWithRasterizerDiscard", + &features->primitivesGeneratedQueryWithRasterizerDiscard) && + visitor->Visit("primitivesGeneratedQueryWithNonZeroStreams", + &features->primitivesGeneratedQueryWithNonZeroStreams); } template <typename Visitor> inline bool Iterate(Visitor* visitor, VkPhysicalDevice16BitStorageFeatures* features) { - return visitor->Visit("storageBuffer16BitAccess", - &features->storageBuffer16BitAccess) && - visitor->Visit("uniformAndStorageBuffer16BitAccess", - &features->uniformAndStorageBuffer16BitAccess) && - visitor->Visit("storagePushConstant16", - &features->storagePushConstant16) && - visitor->Visit("storageInputOutput16", - &features->storageInputOutput16); + return + + visitor->Visit("storageBuffer16BitAccess", + &features->storageBuffer16BitAccess) && + visitor->Visit("uniformAndStorageBuffer16BitAccess", + &features->uniformAndStorageBuffer16BitAccess) && + visitor->Visit("storagePushConstant16", + &features->storagePushConstant16) && + visitor->Visit("storageInputOutput16", &features->storageInputOutput16); } template <typename Visitor> inline bool Iterate(Visitor* visitor, VkPhysicalDeviceMultiviewFeatures* features) { - return visitor->Visit("multiview", &features->multiview) && - visitor->Visit("multiviewGeometryShader", - &features->multiviewGeometryShader) && - visitor->Visit("multiviewTessellationShader", - &features->multiviewTessellationShader); + return + + visitor->Visit("multiview", &features->multiview) && + visitor->Visit("multiviewGeometryShader", + &features->multiviewGeometryShader) && + visitor->Visit("multiviewTessellationShader", + &features->multiviewTessellationShader); } template <typename Visitor> inline bool Iterate(Visitor* visitor, - VkPhysicalDeviceVariablePointerFeatures* features) { - return visitor->Visit("variablePointersStorageBuffer", - &features->variablePointersStorageBuffer) && - visitor->Visit("variablePointers", &features->variablePointers); + VkPhysicalDeviceProtectedMemoryFeatures* features) { + return + + visitor->Visit("protectedMemory", &features->protectedMemory); } template <typename Visitor> inline bool Iterate(Visitor* visitor, - VkPhysicalDeviceImage2DViewOf3DFeaturesEXT* features) { - return visitor->Visit("image2DViewOf3D", &features->image2DViewOf3D) && - visitor->Visit("sampler2DViewOf3D", &features->sampler2DViewOf3D); + VkPhysicalDeviceSamplerYcbcrConversionFeatures* features) { + return + + visitor->Visit("samplerYcbcrConversion", + &features->samplerYcbcrConversion); } template <typename Visitor> inline bool Iterate(Visitor* visitor, - VkPhysicalDeviceShaderFloat16Int8FeaturesKHR* features) { - return visitor->Visit("shaderFloat16", &features->shaderFloat16) && - visitor->Visit("shaderInt8", &features->shaderInt8); + VkPhysicalDeviceShaderDrawParameterFeatures* features) { + return + + visitor->Visit("shaderDrawParameters", &features->shaderDrawParameters); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkPhysicalDeviceLimits* limits) { + return + + visitor->Visit("maxImageDimension1D", &limits->maxImageDimension1D) && + visitor->Visit("maxImageDimension2D", &limits->maxImageDimension2D) && + visitor->Visit("maxImageDimension3D", &limits->maxImageDimension3D) && + visitor->Visit("maxImageDimensionCube", &limits->maxImageDimensionCube) && + visitor->Visit("maxImageArrayLayers", &limits->maxImageArrayLayers) && + visitor->Visit("maxTexelBufferElements", + &limits->maxTexelBufferElements) && + visitor->Visit("maxUniformBufferRange", &limits->maxUniformBufferRange) && + visitor->Visit("maxStorageBufferRange", &limits->maxStorageBufferRange) && + visitor->Visit("maxPushConstantsSize", &limits->maxPushConstantsSize) && + visitor->Visit("maxMemoryAllocationCount", + &limits->maxMemoryAllocationCount) && + visitor->Visit("maxSamplerAllocationCount", + &limits->maxSamplerAllocationCount) && + visitor->Visit("bufferImageGranularity", + &limits->bufferImageGranularity) && + visitor->Visit("sparseAddressSpaceSize", + &limits->sparseAddressSpaceSize) && + visitor->Visit("maxBoundDescriptorSets", + &limits->maxBoundDescriptorSets) && + visitor->Visit("maxPerStageDescriptorSamplers", + &limits->maxPerStageDescriptorSamplers) && + visitor->Visit("maxPerStageDescriptorUniformBuffers", + &limits->maxPerStageDescriptorUniformBuffers) && + visitor->Visit("maxPerStageDescriptorStorageBuffers", + &limits->maxPerStageDescriptorStorageBuffers) && + visitor->Visit("maxPerStageDescriptorSampledImages", + &limits->maxPerStageDescriptorSampledImages) && + visitor->Visit("maxPerStageDescriptorStorageImages", + &limits->maxPerStageDescriptorStorageImages) && + visitor->Visit("maxPerStageDescriptorInputAttachments", + &limits->maxPerStageDescriptorInputAttachments) && + visitor->Visit("maxPerStageResources", &limits->maxPerStageResources) && + visitor->Visit("maxDescriptorSetSamplers", + &limits->maxDescriptorSetSamplers) && + visitor->Visit("maxDescriptorSetUniformBuffers", + &limits->maxDescriptorSetUniformBuffers) && + visitor->Visit("maxDescriptorSetUniformBuffersDynamic", + &limits->maxDescriptorSetUniformBuffersDynamic) && + visitor->Visit("maxDescriptorSetStorageBuffers", + &limits->maxDescriptorSetStorageBuffers) && + visitor->Visit("maxDescriptorSetStorageBuffersDynamic", + &limits->maxDescriptorSetStorageBuffersDynamic) && + visitor->Visit("maxDescriptorSetSampledImages", + &limits->maxDescriptorSetSampledImages) && + visitor->Visit("maxDescriptorSetStorageImages", + &limits->maxDescriptorSetStorageImages) && + visitor->Visit("maxDescriptorSetInputAttachments", + &limits->maxDescriptorSetInputAttachments) && + visitor->Visit("maxVertexInputAttributes", + &limits->maxVertexInputAttributes) && + visitor->Visit("maxVertexInputBindings", + &limits->maxVertexInputBindings) && + visitor->Visit("maxVertexInputAttributeOffset", + &limits->maxVertexInputAttributeOffset) && + visitor->Visit("maxVertexInputBindingStride", + &limits->maxVertexInputBindingStride) && + visitor->Visit("maxVertexOutputComponents", + &limits->maxVertexOutputComponents) && + visitor->Visit("maxTessellationGenerationLevel", + &limits->maxTessellationGenerationLevel) && + visitor->Visit("maxTessellationPatchSize", + &limits->maxTessellationPatchSize) && + visitor->Visit("maxTessellationControlPerVertexInputComponents", + &limits->maxTessellationControlPerVertexInputComponents) && + visitor->Visit( + "maxTessellationControlPerVertexOutputComponents", + &limits->maxTessellationControlPerVertexOutputComponents) && + visitor->Visit("maxTessellationControlPerPatchOutputComponents", + &limits->maxTessellationControlPerPatchOutputComponents) && + visitor->Visit("maxTessellationControlTotalOutputComponents", + &limits->maxTessellationControlTotalOutputComponents) && + visitor->Visit("maxTessellationEvaluationInputComponents", + &limits->maxTessellationEvaluationInputComponents) && + visitor->Visit("maxTessellationEvaluationOutputComponents", + &limits->maxTessellationEvaluationOutputComponents) && + visitor->Visit("maxGeometryShaderInvocations", + &limits->maxGeometryShaderInvocations) && + visitor->Visit("maxGeometryInputComponents", + &limits->maxGeometryInputComponents) && + visitor->Visit("maxGeometryOutputComponents", + &limits->maxGeometryOutputComponents) && + visitor->Visit("maxGeometryOutputVertices", + &limits->maxGeometryOutputVertices) && + visitor->Visit("maxGeometryTotalOutputComponents", + &limits->maxGeometryTotalOutputComponents) && + visitor->Visit("maxFragmentInputComponents", + &limits->maxFragmentInputComponents) && + visitor->Visit("maxFragmentOutputAttachments", + &limits->maxFragmentOutputAttachments) && + visitor->Visit("maxFragmentDualSrcAttachments", + &limits->maxFragmentDualSrcAttachments) && + visitor->Visit("maxFragmentCombinedOutputResources", + &limits->maxFragmentCombinedOutputResources) && + visitor->Visit("maxComputeSharedMemorySize", + &limits->maxComputeSharedMemorySize) && + visitor->Visit("maxComputeWorkGroupCount", + &limits->maxComputeWorkGroupCount) && + visitor->Visit("maxComputeWorkGroupInvocations", + &limits->maxComputeWorkGroupInvocations) && + visitor->Visit("maxComputeWorkGroupSize", + &limits->maxComputeWorkGroupSize) && + visitor->Visit("subPixelPrecisionBits", &limits->subPixelPrecisionBits) && + visitor->Visit("subTexelPrecisionBits", &limits->subTexelPrecisionBits) && + visitor->Visit("mipmapPrecisionBits", &limits->mipmapPrecisionBits) && + visitor->Visit("maxDrawIndexedIndexValue", + &limits->maxDrawIndexedIndexValue) && + visitor->Visit("maxDrawIndirectCount", &limits->maxDrawIndirectCount) && + visitor->Visit("maxSamplerLodBias", &limits->maxSamplerLodBias) && + visitor->Visit("maxSamplerAnisotropy", &limits->maxSamplerAnisotropy) && + visitor->Visit("maxViewports", &limits->maxViewports) && + visitor->Visit("maxViewportDimensions", &limits->maxViewportDimensions) && + visitor->Visit("viewportBoundsRange", &limits->viewportBoundsRange) && + visitor->Visit("viewportSubPixelBits", &limits->viewportSubPixelBits) && + visitor->Visit("minMemoryMapAlignment", &limits->minMemoryMapAlignment) && + visitor->Visit("minTexelBufferOffsetAlignment", + &limits->minTexelBufferOffsetAlignment) && + visitor->Visit("minUniformBufferOffsetAlignment", + &limits->minUniformBufferOffsetAlignment) && + visitor->Visit("minStorageBufferOffsetAlignment", + &limits->minStorageBufferOffsetAlignment) && + visitor->Visit("minTexelOffset", &limits->minTexelOffset) && + visitor->Visit("maxTexelOffset", &limits->maxTexelOffset) && + visitor->Visit("minTexelGatherOffset", &limits->minTexelGatherOffset) && + visitor->Visit("maxTexelGatherOffset", &limits->maxTexelGatherOffset) && + visitor->Visit("minInterpolationOffset", + &limits->minInterpolationOffset) && + visitor->Visit("maxInterpolationOffset", + &limits->maxInterpolationOffset) && + visitor->Visit("subPixelInterpolationOffsetBits", + &limits->subPixelInterpolationOffsetBits) && + visitor->Visit("maxFramebufferWidth", &limits->maxFramebufferWidth) && + visitor->Visit("maxFramebufferHeight", &limits->maxFramebufferHeight) && + visitor->Visit("maxFramebufferLayers", &limits->maxFramebufferLayers) && + visitor->Visit("framebufferColorSampleCounts", + &limits->framebufferColorSampleCounts) && + visitor->Visit("framebufferDepthSampleCounts", + &limits->framebufferDepthSampleCounts) && + visitor->Visit("framebufferStencilSampleCounts", + &limits->framebufferStencilSampleCounts) && + visitor->Visit("framebufferNoAttachmentsSampleCounts", + &limits->framebufferNoAttachmentsSampleCounts) && + visitor->Visit("maxColorAttachments", &limits->maxColorAttachments) && + visitor->Visit("sampledImageColorSampleCounts", + &limits->sampledImageColorSampleCounts) && + visitor->Visit("sampledImageIntegerSampleCounts", + &limits->sampledImageIntegerSampleCounts) && + visitor->Visit("sampledImageDepthSampleCounts", + &limits->sampledImageDepthSampleCounts) && + visitor->Visit("sampledImageStencilSampleCounts", + &limits->sampledImageStencilSampleCounts) && + visitor->Visit("storageImageSampleCounts", + &limits->storageImageSampleCounts) && + visitor->Visit("maxSampleMaskWords", &limits->maxSampleMaskWords) && + visitor->Visit("timestampComputeAndGraphics", + &limits->timestampComputeAndGraphics) && + visitor->Visit("timestampPeriod", &limits->timestampPeriod) && + visitor->Visit("maxClipDistances", &limits->maxClipDistances) && + visitor->Visit("maxCullDistances", &limits->maxCullDistances) && + visitor->Visit("maxCombinedClipAndCullDistances", + &limits->maxCombinedClipAndCullDistances) && + visitor->Visit("discreteQueuePriorities", + &limits->discreteQueuePriorities) && + visitor->Visit("pointSizeRange", &limits->pointSizeRange) && + visitor->Visit("lineWidthRange", &limits->lineWidthRange) && + visitor->Visit("pointSizeGranularity", &limits->pointSizeGranularity) && + visitor->Visit("lineWidthGranularity", &limits->lineWidthGranularity) && + visitor->Visit("strictLines", &limits->strictLines) && + visitor->Visit("standardSampleLocations", + &limits->standardSampleLocations) && + visitor->Visit("optimalBufferCopyOffsetAlignment", + &limits->optimalBufferCopyOffsetAlignment) && + visitor->Visit("optimalBufferCopyRowPitchAlignment", + &limits->optimalBufferCopyRowPitchAlignment) && + visitor->Visit("nonCoherentAtomSize", &limits->nonCoherentAtomSize); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkPhysicalDeviceFeatures* features) { + return + + visitor->Visit("robustBufferAccess", &features->robustBufferAccess) && + visitor->Visit("fullDrawIndexUint32", &features->fullDrawIndexUint32) && + visitor->Visit("imageCubeArray", &features->imageCubeArray) && + visitor->Visit("independentBlend", &features->independentBlend) && + visitor->Visit("geometryShader", &features->geometryShader) && + visitor->Visit("tessellationShader", &features->tessellationShader) && + visitor->Visit("sampleRateShading", &features->sampleRateShading) && + visitor->Visit("dualSrcBlend", &features->dualSrcBlend) && + visitor->Visit("logicOp", &features->logicOp) && + visitor->Visit("multiDrawIndirect", &features->multiDrawIndirect) && + visitor->Visit("drawIndirectFirstInstance", + &features->drawIndirectFirstInstance) && + visitor->Visit("depthClamp", &features->depthClamp) && + visitor->Visit("depthBiasClamp", &features->depthBiasClamp) && + visitor->Visit("fillModeNonSolid", &features->fillModeNonSolid) && + visitor->Visit("depthBounds", &features->depthBounds) && + visitor->Visit("wideLines", &features->wideLines) && + visitor->Visit("largePoints", &features->largePoints) && + visitor->Visit("alphaToOne", &features->alphaToOne) && + visitor->Visit("multiViewport", &features->multiViewport) && + visitor->Visit("samplerAnisotropy", &features->samplerAnisotropy) && + visitor->Visit("textureCompressionETC2", + &features->textureCompressionETC2) && + visitor->Visit("textureCompressionASTC_LDR", + &features->textureCompressionASTC_LDR) && + visitor->Visit("textureCompressionBC", &features->textureCompressionBC) && + visitor->Visit("occlusionQueryPrecise", + &features->occlusionQueryPrecise) && + visitor->Visit("pipelineStatisticsQuery", + &features->pipelineStatisticsQuery) && + visitor->Visit("vertexPipelineStoresAndAtomics", + &features->vertexPipelineStoresAndAtomics) && + visitor->Visit("fragmentStoresAndAtomics", + &features->fragmentStoresAndAtomics) && + visitor->Visit("shaderTessellationAndGeometryPointSize", + &features->shaderTessellationAndGeometryPointSize) && + visitor->Visit("shaderImageGatherExtended", + &features->shaderImageGatherExtended) && + visitor->Visit("shaderStorageImageExtendedFormats", + &features->shaderStorageImageExtendedFormats) && + visitor->Visit("shaderStorageImageMultisample", + &features->shaderStorageImageMultisample) && + visitor->Visit("shaderStorageImageReadWithoutFormat", + &features->shaderStorageImageReadWithoutFormat) && + visitor->Visit("shaderStorageImageWriteWithoutFormat", + &features->shaderStorageImageWriteWithoutFormat) && + visitor->Visit("shaderUniformBufferArrayDynamicIndexing", + &features->shaderUniformBufferArrayDynamicIndexing) && + visitor->Visit("shaderSampledImageArrayDynamicIndexing", + &features->shaderSampledImageArrayDynamicIndexing) && + visitor->Visit("shaderStorageBufferArrayDynamicIndexing", + &features->shaderStorageBufferArrayDynamicIndexing) && + visitor->Visit("shaderStorageImageArrayDynamicIndexing", + &features->shaderStorageImageArrayDynamicIndexing) && + visitor->Visit("shaderClipDistance", &features->shaderClipDistance) && + visitor->Visit("shaderCullDistance", &features->shaderCullDistance) && + visitor->Visit("shaderFloat64", &features->shaderFloat64) && + visitor->Visit("shaderInt64", &features->shaderInt64) && + visitor->Visit("shaderInt16", &features->shaderInt16) && + visitor->Visit("shaderResourceResidency", + &features->shaderResourceResidency) && + visitor->Visit("shaderResourceMinLod", &features->shaderResourceMinLod) && + visitor->Visit("sparseBinding", &features->sparseBinding) && + visitor->Visit("sparseResidencyBuffer", + &features->sparseResidencyBuffer) && + visitor->Visit("sparseResidencyImage2D", + &features->sparseResidencyImage2D) && + visitor->Visit("sparseResidencyImage3D", + &features->sparseResidencyImage3D) && + visitor->Visit("sparseResidency2Samples", + &features->sparseResidency2Samples) && + visitor->Visit("sparseResidency4Samples", + &features->sparseResidency4Samples) && + visitor->Visit("sparseResidency8Samples", + &features->sparseResidency8Samples) && + visitor->Visit("sparseResidency16Samples", + &features->sparseResidency16Samples) && + visitor->Visit("sparseResidencyAliased", + &features->sparseResidencyAliased) && + visitor->Visit("variableMultisampleRate", + &features->variableMultisampleRate) && + visitor->Visit("inheritedQueries", &features->inheritedQueries); } template <typename Visitor> inline bool Iterate(Visitor* visitor, - VkPhysicalDeviceProtectedMemoryFeatures* features) { - return visitor->Visit("protectedMemory", &features->protectedMemory); + VkPhysicalDeviceVulkan11Properties* properties) { + return + + visitor->Visit("deviceUUID", &properties->deviceUUID) && + visitor->Visit("driverUUID", &properties->driverUUID) && + visitor->Visit("deviceLUID", &properties->deviceLUID) && + visitor->Visit("deviceNodeMask", &properties->deviceNodeMask) && + visitor->Visit("deviceLUIDValid", &properties->deviceLUIDValid) && + visitor->Visit("subgroupSize", &properties->subgroupSize) && + visitor->Visit("subgroupSupportedStages", + &properties->subgroupSupportedStages) && + visitor->Visit("subgroupSupportedOperations", + &properties->subgroupSupportedOperations) && + visitor->Visit("subgroupQuadOperationsInAllStages", + &properties->subgroupQuadOperationsInAllStages) && + visitor->Visit("pointClippingBehavior", + &properties->pointClippingBehavior) && + visitor->Visit("maxMultiviewViewCount", + &properties->maxMultiviewViewCount) && + visitor->Visit("maxMultiviewInstanceIndex", + &properties->maxMultiviewInstanceIndex) && + visitor->Visit("protectedNoFault", &properties->protectedNoFault) && + visitor->Visit("maxPerSetDescriptors", + &properties->maxPerSetDescriptors) && + visitor->Visit("maxMemoryAllocationSize", + &properties->maxMemoryAllocationSize); } template <typename Visitor> inline bool Iterate(Visitor* visitor, - VkPhysicalDeviceSamplerYcbcrConversionFeatures* features) { - return visitor->Visit("samplerYcbcrConversion", - &features->samplerYcbcrConversion); + VkPhysicalDeviceVulkan11Features* features) { + return + + visitor->Visit("storageBuffer16BitAccess", + &features->storageBuffer16BitAccess) && + visitor->Visit("uniformAndStorageBuffer16BitAccess", + &features->uniformAndStorageBuffer16BitAccess) && + visitor->Visit("storagePushConstant16", + &features->storagePushConstant16) && + visitor->Visit("storageInputOutput16", &features->storageInputOutput16) && + visitor->Visit("multiview", &features->multiview) && + visitor->Visit("multiviewGeometryShader", + &features->multiviewGeometryShader) && + visitor->Visit("multiviewTessellationShader", + &features->multiviewTessellationShader) && + visitor->Visit("variablePointersStorageBuffer", + &features->variablePointersStorageBuffer) && + visitor->Visit("variablePointers", &features->variablePointers) && + visitor->Visit("protectedMemory", &features->protectedMemory) && + visitor->Visit("samplerYcbcrConversion", + &features->samplerYcbcrConversion) && + visitor->Visit("shaderDrawParameters", &features->shaderDrawParameters); } template <typename Visitor> inline bool Iterate(Visitor* visitor, - VkPhysicalDeviceShaderDrawParameterFeatures* features) { - return visitor->Visit("shaderDrawParameters", - &features->shaderDrawParameters); + VkPhysicalDeviceVulkan12Properties* properties) { + return + + visitor->Visit("driverID", &properties->driverID) && + visitor->Visit("driverName", &properties->driverName) && + visitor->Visit("driverInfo", &properties->driverInfo) && + visitor->Visit("conformanceVersion", &properties->conformanceVersion) && + visitor->Visit("denormBehaviorIndependence", + &properties->denormBehaviorIndependence) && + visitor->Visit("roundingModeIndependence", + &properties->roundingModeIndependence) && + visitor->Visit("shaderSignedZeroInfNanPreserveFloat16", + &properties->shaderSignedZeroInfNanPreserveFloat16) && + visitor->Visit("shaderSignedZeroInfNanPreserveFloat32", + &properties->shaderSignedZeroInfNanPreserveFloat32) && + visitor->Visit("shaderSignedZeroInfNanPreserveFloat64", + &properties->shaderSignedZeroInfNanPreserveFloat64) && + visitor->Visit("shaderDenormPreserveFloat16", + &properties->shaderDenormPreserveFloat16) && + visitor->Visit("shaderDenormPreserveFloat32", + &properties->shaderDenormPreserveFloat32) && + visitor->Visit("shaderDenormPreserveFloat64", + &properties->shaderDenormPreserveFloat64) && + visitor->Visit("shaderDenormFlushToZeroFloat16", + &properties->shaderDenormFlushToZeroFloat16) && + visitor->Visit("shaderDenormFlushToZeroFloat32", + &properties->shaderDenormFlushToZeroFloat32) && + visitor->Visit("shaderDenormFlushToZeroFloat64", + &properties->shaderDenormFlushToZeroFloat64) && + visitor->Visit("shaderRoundingModeRTEFloat16", + &properties->shaderRoundingModeRTEFloat16) && + visitor->Visit("shaderRoundingModeRTEFloat32", + &properties->shaderRoundingModeRTEFloat32) && + visitor->Visit("shaderRoundingModeRTEFloat64", + &properties->shaderRoundingModeRTEFloat64) && + visitor->Visit("shaderRoundingModeRTZFloat16", + &properties->shaderRoundingModeRTZFloat16) && + visitor->Visit("shaderRoundingModeRTZFloat32", + &properties->shaderRoundingModeRTZFloat32) && + visitor->Visit("shaderRoundingModeRTZFloat64", + &properties->shaderRoundingModeRTZFloat64) && + visitor->Visit("maxUpdateAfterBindDescriptorsInAllPools", + &properties->maxUpdateAfterBindDescriptorsInAllPools) && + visitor->Visit( + "shaderUniformBufferArrayNonUniformIndexingNative", + &properties->shaderUniformBufferArrayNonUniformIndexingNative) && + visitor->Visit( + "shaderSampledImageArrayNonUniformIndexingNative", + &properties->shaderSampledImageArrayNonUniformIndexingNative) && + visitor->Visit( + "shaderStorageBufferArrayNonUniformIndexingNative", + &properties->shaderStorageBufferArrayNonUniformIndexingNative) && + visitor->Visit( + "shaderStorageImageArrayNonUniformIndexingNative", + &properties->shaderStorageImageArrayNonUniformIndexingNative) && + visitor->Visit( + "shaderInputAttachmentArrayNonUniformIndexingNative", + &properties->shaderInputAttachmentArrayNonUniformIndexingNative) && + visitor->Visit("robustBufferAccessUpdateAfterBind", + &properties->robustBufferAccessUpdateAfterBind) && + visitor->Visit("quadDivergentImplicitLod", + &properties->quadDivergentImplicitLod) && + visitor->Visit( + "maxPerStageDescriptorUpdateAfterBindSamplers", + &properties->maxPerStageDescriptorUpdateAfterBindSamplers) && + visitor->Visit( + "maxPerStageDescriptorUpdateAfterBindUniformBuffers", + &properties->maxPerStageDescriptorUpdateAfterBindUniformBuffers) && + visitor->Visit( + "maxPerStageDescriptorUpdateAfterBindStorageBuffers", + &properties->maxPerStageDescriptorUpdateAfterBindStorageBuffers) && + visitor->Visit( + "maxPerStageDescriptorUpdateAfterBindSampledImages", + &properties->maxPerStageDescriptorUpdateAfterBindSampledImages) && + visitor->Visit( + "maxPerStageDescriptorUpdateAfterBindStorageImages", + &properties->maxPerStageDescriptorUpdateAfterBindStorageImages) && + visitor->Visit( + "maxPerStageDescriptorUpdateAfterBindInputAttachments", + &properties->maxPerStageDescriptorUpdateAfterBindInputAttachments) && + visitor->Visit("maxPerStageUpdateAfterBindResources", + &properties->maxPerStageUpdateAfterBindResources) && + visitor->Visit("maxDescriptorSetUpdateAfterBindSamplers", + &properties->maxDescriptorSetUpdateAfterBindSamplers) && + visitor->Visit( + "maxDescriptorSetUpdateAfterBindUniformBuffers", + &properties->maxDescriptorSetUpdateAfterBindUniformBuffers) && + visitor->Visit( + "maxDescriptorSetUpdateAfterBindUniformBuffersDynamic", + &properties->maxDescriptorSetUpdateAfterBindUniformBuffersDynamic) && + visitor->Visit( + "maxDescriptorSetUpdateAfterBindStorageBuffers", + &properties->maxDescriptorSetUpdateAfterBindStorageBuffers) && + visitor->Visit( + "maxDescriptorSetUpdateAfterBindStorageBuffersDynamic", + &properties->maxDescriptorSetUpdateAfterBindStorageBuffersDynamic) && + visitor->Visit( + "maxDescriptorSetUpdateAfterBindSampledImages", + &properties->maxDescriptorSetUpdateAfterBindSampledImages) && + visitor->Visit( + "maxDescriptorSetUpdateAfterBindStorageImages", + &properties->maxDescriptorSetUpdateAfterBindStorageImages) && + visitor->Visit( + "maxDescriptorSetUpdateAfterBindInputAttachments", + &properties->maxDescriptorSetUpdateAfterBindInputAttachments) && + visitor->Visit("supportedDepthResolveModes", + &properties->supportedDepthResolveModes) && + visitor->Visit("supportedStencilResolveModes", + &properties->supportedStencilResolveModes) && + visitor->Visit("independentResolveNone", + &properties->independentResolveNone) && + visitor->Visit("independentResolve", &properties->independentResolve) && + visitor->Visit("filterMinmaxSingleComponentFormats", + &properties->filterMinmaxSingleComponentFormats) && + visitor->Visit("filterMinmaxImageComponentMapping", + &properties->filterMinmaxImageComponentMapping) && + visitor->Visit("maxTimelineSemaphoreValueDifference", + &properties->maxTimelineSemaphoreValueDifference) && + visitor->Visit("framebufferIntegerColorSampleCounts", + &properties->framebufferIntegerColorSampleCounts); } template <typename Visitor> -inline bool Iterate(Visitor* visitor, VkExternalFenceProperties* properties) { - return visitor->Visit("exportFromImportedHandleTypes", - &properties->exportFromImportedHandleTypes) && - visitor->Visit("compatibleHandleTypes", - &properties->compatibleHandleTypes) && - visitor->Visit("externalFenceFeatures", - &properties->externalFenceFeatures); +inline bool Iterate(Visitor* visitor, + VkPhysicalDeviceVulkan12Features* features) { + return + + visitor->Visit("samplerMirrorClampToEdge", + &features->samplerMirrorClampToEdge) && + visitor->Visit("drawIndirectCount", &features->drawIndirectCount) && + visitor->Visit("storageBuffer8BitAccess", + &features->storageBuffer8BitAccess) && + visitor->Visit("uniformAndStorageBuffer8BitAccess", + &features->uniformAndStorageBuffer8BitAccess) && + visitor->Visit("storagePushConstant8", &features->storagePushConstant8) && + visitor->Visit("shaderBufferInt64Atomics", + &features->shaderBufferInt64Atomics) && + visitor->Visit("shaderSharedInt64Atomics", + &features->shaderSharedInt64Atomics) && + visitor->Visit("shaderFloat16", &features->shaderFloat16) && + visitor->Visit("shaderInt8", &features->shaderInt8) && + visitor->Visit("descriptorIndexing", &features->descriptorIndexing) && + visitor->Visit("shaderInputAttachmentArrayDynamicIndexing", + &features->shaderInputAttachmentArrayDynamicIndexing) && + visitor->Visit("shaderUniformTexelBufferArrayDynamicIndexing", + &features->shaderUniformTexelBufferArrayDynamicIndexing) && + visitor->Visit("shaderStorageTexelBufferArrayDynamicIndexing", + &features->shaderStorageTexelBufferArrayDynamicIndexing) && + visitor->Visit("shaderUniformBufferArrayNonUniformIndexing", + &features->shaderUniformBufferArrayNonUniformIndexing) && + visitor->Visit("shaderSampledImageArrayNonUniformIndexing", + &features->shaderSampledImageArrayNonUniformIndexing) && + visitor->Visit("shaderStorageBufferArrayNonUniformIndexing", + &features->shaderStorageBufferArrayNonUniformIndexing) && + visitor->Visit("shaderStorageImageArrayNonUniformIndexing", + &features->shaderStorageImageArrayNonUniformIndexing) && + visitor->Visit("shaderInputAttachmentArrayNonUniformIndexing", + &features->shaderInputAttachmentArrayNonUniformIndexing) && + visitor->Visit( + "shaderUniformTexelBufferArrayNonUniformIndexing", + &features->shaderUniformTexelBufferArrayNonUniformIndexing) && + visitor->Visit( + "shaderStorageTexelBufferArrayNonUniformIndexing", + &features->shaderStorageTexelBufferArrayNonUniformIndexing) && + visitor->Visit( + "descriptorBindingUniformBufferUpdateAfterBind", + &features->descriptorBindingUniformBufferUpdateAfterBind) && + visitor->Visit("descriptorBindingSampledImageUpdateAfterBind", + &features->descriptorBindingSampledImageUpdateAfterBind) && + visitor->Visit("descriptorBindingStorageImageUpdateAfterBind", + &features->descriptorBindingStorageImageUpdateAfterBind) && + visitor->Visit( + "descriptorBindingStorageBufferUpdateAfterBind", + &features->descriptorBindingStorageBufferUpdateAfterBind) && + visitor->Visit( + "descriptorBindingUniformTexelBufferUpdateAfterBind", + &features->descriptorBindingUniformTexelBufferUpdateAfterBind) && + visitor->Visit( + "descriptorBindingStorageTexelBufferUpdateAfterBind", + &features->descriptorBindingStorageTexelBufferUpdateAfterBind) && + visitor->Visit("descriptorBindingUpdateUnusedWhilePending", + &features->descriptorBindingUpdateUnusedWhilePending) && + visitor->Visit("descriptorBindingPartiallyBound", + &features->descriptorBindingPartiallyBound) && + visitor->Visit("descriptorBindingVariableDescriptorCount", + &features->descriptorBindingVariableDescriptorCount) && + visitor->Visit("runtimeDescriptorArray", + &features->runtimeDescriptorArray) && + visitor->Visit("samplerFilterMinmax", &features->samplerFilterMinmax) && + visitor->Visit("scalarBlockLayout", &features->scalarBlockLayout) && + visitor->Visit("imagelessFramebuffer", &features->imagelessFramebuffer) && + visitor->Visit("uniformBufferStandardLayout", + &features->uniformBufferStandardLayout) && + visitor->Visit("shaderSubgroupExtendedTypes", + &features->shaderSubgroupExtendedTypes) && + visitor->Visit("separateDepthStencilLayouts", + &features->separateDepthStencilLayouts) && + visitor->Visit("hostQueryReset", &features->hostQueryReset) && + visitor->Visit("timelineSemaphore", &features->timelineSemaphore) && + visitor->Visit("bufferDeviceAddress", &features->bufferDeviceAddress) && + visitor->Visit("bufferDeviceAddressCaptureReplay", + &features->bufferDeviceAddressCaptureReplay) && + visitor->Visit("bufferDeviceAddressMultiDevice", + &features->bufferDeviceAddressMultiDevice) && + visitor->Visit("vulkanMemoryModel", &features->vulkanMemoryModel) && + visitor->Visit("vulkanMemoryModelDeviceScope", + &features->vulkanMemoryModelDeviceScope) && + visitor->Visit( + "vulkanMemoryModelAvailabilityVisibilityChains", + &features->vulkanMemoryModelAvailabilityVisibilityChains) && + visitor->Visit("shaderOutputViewportIndex", + &features->shaderOutputViewportIndex) && + visitor->Visit("shaderOutputLayer", &features->shaderOutputLayer) && + visitor->Visit("subgroupBroadcastDynamicId", + &features->subgroupBroadcastDynamicId); } template <typename Visitor> inline bool Iterate(Visitor* visitor, - VkExternalSemaphoreProperties* properties) { - return visitor->Visit("exportFromImportedHandleTypes", - &properties->exportFromImportedHandleTypes) && - visitor->Visit("compatibleHandleTypes", - &properties->compatibleHandleTypes) && - visitor->Visit("externalSemaphoreFeatures", - &properties->externalSemaphoreFeatures); + VkPhysicalDeviceVulkan13Properties* properties) { + return + + visitor->Visit("minSubgroupSize", &properties->minSubgroupSize) && + visitor->Visit("maxSubgroupSize", &properties->maxSubgroupSize) && + visitor->Visit("maxComputeWorkgroupSubgroups", + &properties->maxComputeWorkgroupSubgroups) && + visitor->Visit("requiredSubgroupSizeStages", + &properties->requiredSubgroupSizeStages) && + visitor->Visit("maxInlineUniformBlockSize", + &properties->maxInlineUniformBlockSize) && + visitor->Visit("maxPerStageDescriptorInlineUniformBlocks", + &properties->maxPerStageDescriptorInlineUniformBlocks) && + visitor->Visit( + "maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks", + &properties + ->maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks) && + visitor->Visit("maxDescriptorSetInlineUniformBlocks", + &properties->maxDescriptorSetInlineUniformBlocks) && + visitor->Visit( + "maxDescriptorSetUpdateAfterBindInlineUniformBlocks", + &properties->maxDescriptorSetUpdateAfterBindInlineUniformBlocks) && + visitor->Visit("maxInlineUniformTotalSize", + &properties->maxInlineUniformTotalSize) && + visitor->Visit("integerDotProduct8BitUnsignedAccelerated", + &properties->integerDotProduct8BitUnsignedAccelerated) && + visitor->Visit("integerDotProduct8BitSignedAccelerated", + &properties->integerDotProduct8BitSignedAccelerated) && + visitor->Visit( + "integerDotProduct8BitMixedSignednessAccelerated", + &properties->integerDotProduct8BitMixedSignednessAccelerated) && + visitor->Visit( + "integerDotProduct4x8BitPackedUnsignedAccelerated", + &properties->integerDotProduct4x8BitPackedUnsignedAccelerated) && + visitor->Visit( + "integerDotProduct4x8BitPackedSignedAccelerated", + &properties->integerDotProduct4x8BitPackedSignedAccelerated) && + visitor->Visit( + "integerDotProduct4x8BitPackedMixedSignednessAccelerated", + &properties + ->integerDotProduct4x8BitPackedMixedSignednessAccelerated) && + visitor->Visit("integerDotProduct16BitUnsignedAccelerated", + &properties->integerDotProduct16BitUnsignedAccelerated) && + visitor->Visit("integerDotProduct16BitSignedAccelerated", + &properties->integerDotProduct16BitSignedAccelerated) && + visitor->Visit( + "integerDotProduct16BitMixedSignednessAccelerated", + &properties->integerDotProduct16BitMixedSignednessAccelerated) && + visitor->Visit("integerDotProduct32BitUnsignedAccelerated", + &properties->integerDotProduct32BitUnsignedAccelerated) && + visitor->Visit("integerDotProduct32BitSignedAccelerated", + &properties->integerDotProduct32BitSignedAccelerated) && + visitor->Visit( + "integerDotProduct32BitMixedSignednessAccelerated", + &properties->integerDotProduct32BitMixedSignednessAccelerated) && + visitor->Visit("integerDotProduct64BitUnsignedAccelerated", + &properties->integerDotProduct64BitUnsignedAccelerated) && + visitor->Visit("integerDotProduct64BitSignedAccelerated", + &properties->integerDotProduct64BitSignedAccelerated) && + visitor->Visit( + "integerDotProduct64BitMixedSignednessAccelerated", + &properties->integerDotProduct64BitMixedSignednessAccelerated) && + visitor->Visit( + "integerDotProductAccumulatingSaturating8BitUnsignedAccelerated", + &properties + ->integerDotProductAccumulatingSaturating8BitUnsignedAccelerated) && + visitor->Visit( + "integerDotProductAccumulatingSaturating8BitSignedAccelerated", + &properties + ->integerDotProductAccumulatingSaturating8BitSignedAccelerated) && + visitor->Visit( + "integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerate" + "d", + &properties + ->integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated) && + visitor->Visit( + "integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerat" + "ed", + &properties + ->integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated) && + visitor->Visit( + "integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerate" + "d", + &properties + ->integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated) && + visitor->Visit( + "integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAc" + "celerated", + &properties + ->integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated) && + visitor->Visit( + "integerDotProductAccumulatingSaturating16BitUnsignedAccelerated", + &properties + ->integerDotProductAccumulatingSaturating16BitUnsignedAccelerated) && + visitor->Visit( + "integerDotProductAccumulatingSaturating16BitSignedAccelerated", + &properties + ->integerDotProductAccumulatingSaturating16BitSignedAccelerated) && + visitor->Visit( + "integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerat" + "ed", + &properties + ->integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated) && + visitor->Visit( + "integerDotProductAccumulatingSaturating32BitUnsignedAccelerated", + &properties + ->integerDotProductAccumulatingSaturating32BitUnsignedAccelerated) && + visitor->Visit( + "integerDotProductAccumulatingSaturating32BitSignedAccelerated", + &properties + ->integerDotProductAccumulatingSaturating32BitSignedAccelerated) && + visitor->Visit( + "integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerat" + "ed", + &properties + ->integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated) && + visitor->Visit( + "integerDotProductAccumulatingSaturating64BitUnsignedAccelerated", + &properties + ->integerDotProductAccumulatingSaturating64BitUnsignedAccelerated) && + visitor->Visit( + "integerDotProductAccumulatingSaturating64BitSignedAccelerated", + &properties + ->integerDotProductAccumulatingSaturating64BitSignedAccelerated) && + visitor->Visit( + "integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerat" + "ed", + &properties + ->integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated) && + visitor->Visit("storageTexelBufferOffsetAlignmentBytes", + &properties->storageTexelBufferOffsetAlignmentBytes) && + visitor->Visit( + "storageTexelBufferOffsetSingleTexelAlignment", + &properties->storageTexelBufferOffsetSingleTexelAlignment) && + visitor->Visit("uniformTexelBufferOffsetAlignmentBytes", + &properties->uniformTexelBufferOffsetAlignmentBytes) && + visitor->Visit( + "uniformTexelBufferOffsetSingleTexelAlignment", + &properties->uniformTexelBufferOffsetSingleTexelAlignment) && + visitor->Visit("maxBufferSize", &properties->maxBufferSize); } template <typename Visitor> -inline bool Iterate(Visitor* visitor, VkQueueFamilyProperties* properties) { +inline bool Iterate(Visitor* visitor, + VkPhysicalDeviceVulkan13Features* features) { return - visitor->Visit("queueFlags", &properties->queueFlags) && - visitor->Visit("queueCount", &properties->queueCount) && - visitor->Visit("timestampValidBits", &properties->timestampValidBits) && - visitor->Visit("minImageTransferGranularity", &properties->minImageTransferGranularity); + + visitor->Visit("robustImageAccess", &features->robustImageAccess) && + visitor->Visit("inlineUniformBlock", &features->inlineUniformBlock) && + visitor->Visit( + "descriptorBindingInlineUniformBlockUpdateAfterBind", + &features->descriptorBindingInlineUniformBlockUpdateAfterBind) && + visitor->Visit("pipelineCreationCacheControl", + &features->pipelineCreationCacheControl) && + visitor->Visit("privateData", &features->privateData) && + visitor->Visit("shaderDemoteToHelperInvocation", + &features->shaderDemoteToHelperInvocation) && + visitor->Visit("shaderTerminateInvocation", + &features->shaderTerminateInvocation) && + visitor->Visit("subgroupSizeControl", &features->subgroupSizeControl) && + visitor->Visit("computeFullSubgroups", &features->computeFullSubgroups) && + visitor->Visit("synchronization2", &features->synchronization2) && + visitor->Visit("textureCompressionASTC_HDR", + &features->textureCompressionASTC_HDR) && + visitor->Visit("shaderZeroInitializeWorkgroupMemory", + &features->shaderZeroInitializeWorkgroupMemory) && + visitor->Visit("dynamicRendering", &features->dynamicRendering) && + visitor->Visit("shaderIntegerDotProduct", + &features->shaderIntegerDotProduct) && + visitor->Visit("maintenance4", &features->maintenance4); } template <typename Visitor> -inline bool Iterate(Visitor* visitor, VkExtensionProperties* properties) { +inline bool Iterate(Visitor* visitor, + VkPhysicalDeviceVulkan14Properties* properties) { return - visitor->Visit("extensionName", &properties->extensionName) && - visitor->Visit("specVersion", &properties->specVersion); + + visitor->Visit("lineSubPixelPrecisionBits", + &properties->lineSubPixelPrecisionBits) && + visitor->Visit("maxVertexAttribDivisor", + &properties->maxVertexAttribDivisor) && + visitor->Visit("supportsNonZeroFirstInstance", + &properties->supportsNonZeroFirstInstance) && + visitor->Visit("maxPushDescriptors", &properties->maxPushDescriptors) && + visitor->Visit( + "dynamicRenderingLocalReadDepthStencilAttachments", + &properties->dynamicRenderingLocalReadDepthStencilAttachments) && + visitor->Visit( + "dynamicRenderingLocalReadMultisampledAttachments", + &properties->dynamicRenderingLocalReadMultisampledAttachments) && + visitor->Visit( + "earlyFragmentMultisampleCoverageAfterSampleCounting", + &properties->earlyFragmentMultisampleCoverageAfterSampleCounting) && + visitor->Visit( + "earlyFragmentSampleMaskTestBeforeSampleCounting", + &properties->earlyFragmentSampleMaskTestBeforeSampleCounting) && + visitor->Visit("depthStencilSwizzleOneSupport", + &properties->depthStencilSwizzleOneSupport) && + visitor->Visit("polygonModePointSize", + &properties->polygonModePointSize) && + visitor->Visit( + "nonStrictSinglePixelWideLinesUseParallelogram", + &properties->nonStrictSinglePixelWideLinesUseParallelogram) && + visitor->Visit("nonStrictWideLinesUseParallelogram", + &properties->nonStrictWideLinesUseParallelogram) && + visitor->Visit("blockTexelViewCompatibleMultipleLayers", + &properties->blockTexelViewCompatibleMultipleLayers) && + visitor->Visit("maxCombinedImageSamplerDescriptorCount", + &properties->maxCombinedImageSamplerDescriptorCount) && + visitor->Visit("fragmentShadingRateClampCombinerInputs", + &properties->fragmentShadingRateClampCombinerInputs) && + visitor->Visit("defaultRobustnessStorageBuffers", + &properties->defaultRobustnessStorageBuffers) && + visitor->Visit("defaultRobustnessUniformBuffers", + &properties->defaultRobustnessUniformBuffers) && + visitor->Visit("defaultRobustnessVertexInputs", + &properties->defaultRobustnessVertexInputs) && + visitor->Visit("defaultRobustnessImages", + &properties->defaultRobustnessImages) && + visitor->Visit("copySrcLayoutCount", &properties->copySrcLayoutCount) && + visitor->VisitArray("pCopySrcLayouts", properties->copySrcLayoutCount, + &properties->pCopySrcLayouts) && + visitor->Visit("copyDstLayoutCount", &properties->copyDstLayoutCount) && + visitor->VisitArray("pCopyDstLayouts", properties->copyDstLayoutCount, + &properties->pCopyDstLayouts) && + visitor->Visit("optimalTilingLayoutUUID", + &properties->optimalTilingLayoutUUID) && + visitor->Visit("identicalMemoryTypeRequirements", + &properties->identicalMemoryTypeRequirements); } template <typename Visitor> -inline bool Iterate(Visitor* visitor, VkLayerProperties* properties) { +inline bool Iterate(Visitor* visitor, + VkPhysicalDeviceVulkan14Features* features) { return - visitor->Visit("layerName", &properties->layerName) && - visitor->Visit("specVersion", &properties->specVersion) && - visitor->Visit("implementationVersion", &properties->implementationVersion) && - visitor->Visit("description", &properties->description); + + visitor->Visit("globalPriorityQuery", &features->globalPriorityQuery) && + visitor->Visit("shaderSubgroupRotate", &features->shaderSubgroupRotate) && + visitor->Visit("shaderSubgroupRotateClustered", + &features->shaderSubgroupRotateClustered) && + visitor->Visit("shaderFloatControls2", &features->shaderFloatControls2) && + visitor->Visit("shaderExpectAssume", &features->shaderExpectAssume) && + visitor->Visit("rectangularLines", &features->rectangularLines) && + visitor->Visit("bresenhamLines", &features->bresenhamLines) && + visitor->Visit("smoothLines", &features->smoothLines) && + visitor->Visit("stippledRectangularLines", + &features->stippledRectangularLines) && + visitor->Visit("stippledBresenhamLines", + &features->stippledBresenhamLines) && + visitor->Visit("stippledSmoothLines", &features->stippledSmoothLines) && + visitor->Visit("vertexAttributeInstanceRateDivisor", + &features->vertexAttributeInstanceRateDivisor) && + visitor->Visit("vertexAttributeInstanceRateZeroDivisor", + &features->vertexAttributeInstanceRateZeroDivisor) && + visitor->Visit("indexTypeUint8", &features->indexTypeUint8) && + visitor->Visit("dynamicRenderingLocalRead", + &features->dynamicRenderingLocalRead) && + visitor->Visit("maintenance5", &features->maintenance5) && + visitor->Visit("maintenance6", &features->maintenance6) && + visitor->Visit("pipelineProtectedAccess", + &features->pipelineProtectedAccess) && + visitor->Visit("pipelineRobustness", &features->pipelineRobustness) && + visitor->Visit("hostImageCopy", &features->hostImageCopy); } template <typename Visitor> -inline bool Iterate(Visitor* visitor, VkFormatProperties* properties) { +inline bool Iterate(Visitor* visitor, + VkPhysicalDeviceDriverProperties* properties) { return - visitor->Visit("linearTilingFeatures", &properties->linearTilingFeatures) && - visitor->Visit("optimalTilingFeatures", &properties->optimalTilingFeatures) && - visitor->Visit("bufferFeatures", &properties->bufferFeatures); + + visitor->Visit("driverID", &properties->driverID) && + visitor->Visit("driverName", &properties->driverName) && + visitor->Visit("driverInfo", &properties->driverInfo) && + visitor->Visit("conformanceVersion", &properties->conformanceVersion); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkExternalFenceProperties* properties) { + return visitor->Visit("exportFromImportedHandleTypes", + &properties->exportFromImportedHandleTypes) && + visitor->Visit("compatibleHandleTypes", + &properties->compatibleHandleTypes) && + visitor->Visit("externalFenceFeatures", + &properties->externalFenceFeatures); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, + VkExternalSemaphoreProperties* properties) { + return visitor->Visit("exportFromImportedHandleTypes", + &properties->exportFromImportedHandleTypes) && + visitor->Visit("compatibleHandleTypes", + &properties->compatibleHandleTypes) && + visitor->Visit("externalSemaphoreFeatures", + &properties->externalSemaphoreFeatures); } template <typename Visitor> @@ -1211,6 +1956,7 @@ inline bool Iterate(Visitor* visitor, VkJsonDevice* device) { ret &= visitor->Visit("core13", &device->core13); FALLTHROUGH_INTENDED; case VK_API_VERSION_1_2: + ret &= visitor->Visit("core11", &device->core11); ret &= visitor->Visit("core12", &device->core12); FALLTHROUGH_INTENDED; case VK_API_VERSION_1_1: @@ -1223,17 +1969,17 @@ inline bool Iterate(Visitor* visitor, VkJsonDevice* device) { visitor->Visit("idProperties", &device->id_properties) && visitor->Visit("maintenance3Properties", &device->maintenance3_properties) && - visitor->Visit("16bitStorageFeatures", - &device->bit16_storage_features) && visitor->Visit("multiviewFeatures", &device->multiview_features) && - visitor->Visit("variablePointerFeatures", - &device->variable_pointer_features) && + visitor->Visit("variablePointersFeatures", + &device->variable_pointers_features) && visitor->Visit("protectedMemoryFeatures", &device->protected_memory_features) && visitor->Visit("samplerYcbcrConversionFeatures", &device->sampler_ycbcr_conversion_features) && visitor->Visit("shaderDrawParameterFeatures", &device->shader_draw_parameter_features) && + visitor->Visit("bit16StorageFeatures", + &device->bit16_storage_features) && visitor->Visit("externalFenceProperties", &device->external_fence_properties) && visitor->Visit("externalSemaphoreProperties", @@ -1247,21 +1993,90 @@ inline bool Iterate(Visitor* visitor, VkJsonDevice* device) { visitor->Visit("extensions", &device->extensions) && visitor->Visit("layers", &device->layers) && visitor->Visit("formats", &device->formats); - if (device->ext_driver_properties.reported) { - ret &= visitor->Visit("VK_KHR_driver_properties", - &device->ext_driver_properties); - } - if (device->ext_variable_pointer_features.reported) { + + if (device->khr_variable_pointers.reported) { ret &= visitor->Visit("VK_KHR_variable_pointers", - &device->ext_variable_pointer_features); + &device->khr_variable_pointers); + } + if (device->khr_shader_float16_int8.reported) { + ret &= visitor->Visit("VK_KHR_shader_float16_int8", + &device->khr_shader_float16_int8); } - if (device->ext_image_2d_view_of_3d_features.reported) { + if (device->ext_image_2d_view_of_3d.reported) { ret &= visitor->Visit("VK_EXT_image_2d_view_of_3d", - &device->ext_image_2d_view_of_3d_features); + &device->ext_image_2d_view_of_3d); } - if (device->ext_shader_float16_int8_features.reported) { - ret &= visitor->Visit("VK_KHR_shader_float16_int8", - &device->ext_shader_float16_int8_features); + if (device->ext_custom_border_color.reported) { + ret &= visitor->Visit("VK_EXT_custom_border_color", + &device->ext_custom_border_color); + } + if (device->ext_primitive_topology_list_restart.reported) { + ret &= visitor->Visit("VK_EXT_primitive_topology_list_restart", + &device->ext_primitive_topology_list_restart); + } + if (device->ext_provoking_vertex.reported) { + ret &= visitor->Visit("VK_EXT_provoking_vertex", + &device->ext_provoking_vertex); + } + if (device->khr_index_type_uint8.reported) { + ret &= visitor->Visit("VK_KHR_index_type_uint8", + &device->khr_index_type_uint8); + } + if (device->ext_index_type_uint8.reported) { + ret &= visitor->Visit("VK_EXT_index_type_uint8", + &device->ext_index_type_uint8); + } + if (device->khr_vertex_attribute_divisor.reported) { + ret &= visitor->Visit("VK_KHR_vertex_attribute_divisor", + &device->khr_vertex_attribute_divisor); + } + if (device->ext_vertex_attribute_divisor.reported) { + ret &= visitor->Visit("VK_EXT_vertex_attribute_divisor", + &device->ext_vertex_attribute_divisor); + } + if (device->ext_transform_feedback.reported) { + ret &= visitor->Visit("VK_EXT_transform_feedback", + &device->ext_transform_feedback); + } + if (device->khr_shader_subgroup_uniform_control_flow.reported) { + ret &= + visitor->Visit("VK_KHR_shader_subgroup_uniform_control_flow", + &device->khr_shader_subgroup_uniform_control_flow); + } + if (device->khr_shader_subgroup_extended_types.reported) { + ret &= visitor->Visit("VK_KHR_shader_subgroup_extended_types", + &device->khr_shader_subgroup_extended_types); + } + if (device->khr_8bit_storage.reported) { + ret &= visitor->Visit("VK_KHR_8bit_storage", &device->khr_8bit_storage); + } + if (device->khr_shader_integer_dot_product.reported) { + ret &= visitor->Visit("VK_KHR_shader_integer_dot_product", + &device->khr_shader_integer_dot_product); + } + if (device->img_relaxed_line_rasterization.reported) { + ret &= visitor->Visit("VK_IMG_relaxed_line_rasterization", + &device->img_relaxed_line_rasterization); + } + if (device->khr_line_rasterization.reported) { + ret &= visitor->Visit("VK_KHR_line_rasterization", + &device->khr_line_rasterization); + } + if (device->ext_line_rasterization.reported) { + ret &= visitor->Visit("VK_EXT_line_rasterization", + &device->ext_line_rasterization); + } + if (device->ext_primitives_generated_query.reported) { + ret &= visitor->Visit("VK_EXT_primitives_generated_query", + &device->ext_primitives_generated_query); + } + if (device->khr_shader_float_controls.reported) { + ret &= visitor->Visit("VK_KHR_shader_float_controls", + &device->khr_shader_float_controls); + } + if (device->khr_driver_properties.reported) { + ret &= visitor->Visit("VK_KHR_driver_properties", + &device->khr_driver_properties); } } return ret; @@ -1319,7 +2134,9 @@ inline Json::Value ToJsonValue(const uint64_t& value) { return Json::Value(string); } -template <typename T, typename = EnableForEnum<T>, typename = void, +template <typename T, + typename = EnableForEnum<T>, + typename = void, typename = void> inline Json::Value ToJsonValue(const T& value) { return Json::Value(static_cast<double>(value)); @@ -1328,7 +2145,8 @@ inline Json::Value ToJsonValue(const T& value) { template <typename T> inline Json::Value ArrayToJsonValue(uint32_t count, const T* values) { Json::Value array(Json::arrayValue); - for (unsigned int i = 0; i < count; ++i) array.append(ToJsonValue(values[i])); + for (unsigned int i = 0; i < count; ++i) + array.append(ToJsonValue(values[i])); return array; } @@ -1360,7 +2178,8 @@ inline Json::Value ToJsonValue(const std::pair<F, S>& value) { template <typename F, typename S> inline Json::Value ToJsonValue(const std::map<F, S>& value) { Json::Value array(Json::arrayValue); - for (auto& kv : value) array.append(ToJsonValue(kv)); + for (auto& kv : value) + array.append(ToJsonValue(kv)); return array; } @@ -1370,7 +2189,8 @@ class JsonWriterVisitor { ~JsonWriterVisitor() {} - template <typename T> bool Visit(const char* key, const T* value) { + template <typename T> + bool Visit(const char* key, const T* value) { object_[key] = ToJsonValue(*value); return true; } @@ -1383,7 +2203,7 @@ class JsonWriterVisitor { } template <typename T> - bool VisitArray(const char* key, uint32_t count, const T *value) { + bool VisitArray(const char* key, uint32_t count, const T* value) { object_[key] = ArrayToJsonValue(count, *value); return true; } @@ -1410,7 +2230,8 @@ template <typename T, typename = EnableForStruct<T>> bool AsValue(Json::Value* json_value, T* t); inline bool AsValue(Json::Value* json_value, int32_t* value) { - if (json_value->type() != Json::realValue) return false; + if (json_value->type() != Json::realValue) + return false; double d = json_value->asDouble(); if (!IsIntegral(d) || d < static_cast<double>(std::numeric_limits<int32_t>::min()) || @@ -1421,14 +2242,16 @@ inline bool AsValue(Json::Value* json_value, int32_t* value) { } inline bool AsValue(Json::Value* json_value, uint64_t* value) { - if (json_value->type() != Json::stringValue) return false; + if (json_value->type() != Json::stringValue) + return false; int result = std::sscanf(json_value->asString().c_str(), "0x%016" PRIx64, value); return result == 1; } inline bool AsValue(Json::Value* json_value, uint32_t* value) { - if (json_value->type() != Json::realValue) return false; + if (json_value->type() != Json::realValue) + return false; double d = json_value->asDouble(); if (!IsIntegral(d) || d < 0.0 || d > static_cast<double>(std::numeric_limits<uint32_t>::max())) @@ -1447,7 +2270,8 @@ inline bool AsValue(Json::Value* json_value, uint8_t* value) { } inline bool AsValue(Json::Value* json_value, float* value) { - if (json_value->type() != Json::realValue) return false; + if (json_value->type() != Json::realValue) + return false; *value = static_cast<float>(json_value->asDouble()); return true; } @@ -1456,7 +2280,8 @@ inline bool AsValue(Json::Value* json_value, VkImageLayout* t) { uint32_t value = 0; if (!AsValue(json_value, &value)) return false; - if (!EnumTraits<VkImageLayout>::exist(value)) return false; + if (!EnumTraits<VkImageLayout>::exist(value)) + return false; *t = static_cast<VkImageLayout>(value); return true; } @@ -1466,7 +2291,8 @@ inline bool AsArray(Json::Value* json_value, uint32_t count, T* values) { if (json_value->type() != Json::arrayValue || json_value->size() != count) return false; for (uint32_t i = 0; i < count; ++i) { - if (!AsValue(&(*json_value)[i], values + i)) return false; + if (!AsValue(&(*json_value)[i], values + i)) + return false; } return true; } @@ -1478,12 +2304,13 @@ inline bool AsValue(Json::Value* json_value, T (*value)[N]) { template <size_t N> inline bool AsValue(Json::Value* json_value, char (*value)[N]) { - if (json_value->type() != Json::stringValue) return false; + if (json_value->type() != Json::stringValue) + return false; size_t len = json_value->asString().length(); if (len >= N) return false; memcpy(*value, json_value->asString().c_str(), len); - memset(*value + len, 0, N-len); + memset(*value + len, 0, N - len); return true; } @@ -1491,15 +2318,17 @@ template <typename T, typename = EnableForEnum<T>, typename = void> inline bool AsValue(Json::Value* json_value, T* t) { uint32_t value = 0; if (!AsValue(json_value, &value)) - return false; - if (!EnumTraits<T>::exist(value)) return false; + return false; + if (!EnumTraits<T>::exist(value)) + return false; *t = static_cast<T>(value); return true; } template <typename T> inline bool AsValue(Json::Value* json_value, std::vector<T>* value) { - if (json_value->type() != Json::arrayValue) return false; + if (json_value->type() != Json::arrayValue) + return false; int size = json_value->size(); value->resize(size); return AsArray(json_value, size, value->data()); @@ -1515,11 +2344,13 @@ inline bool AsValue(Json::Value* json_value, std::pair<F, S>* value) { template <typename F, typename S> inline bool AsValue(Json::Value* json_value, std::map<F, S>* value) { - if (json_value->type() != Json::arrayValue) return false; + if (json_value->type() != Json::arrayValue) + return false; int size = json_value->size(); for (int i = 0; i < size; ++i) { std::pair<F, S> elem; - if (!AsValue(&(*json_value)[i], &elem)) return false; + if (!AsValue(&(*json_value)[i], &elem)) + return false; if (!value->insert(elem).second) return false; } @@ -1527,7 +2358,9 @@ inline bool AsValue(Json::Value* json_value, std::map<F, S>* value) { } template <typename T> -bool ReadValue(Json::Value* object, const char* key, T* value, +bool ReadValue(Json::Value* object, + const char* key, + T* value, std::string* errors) { Json::Value json_value = (*object)[key]; if (!json_value) { @@ -1535,7 +2368,8 @@ bool ReadValue(Json::Value* object, const char* key, T* value, *errors = std::string(key) + " missing."; return false; } - if (AsValue(&json_value, value)) return true; + if (AsValue(&json_value, value)) + return true; if (errors) *errors = std::string("Wrong type for ") + std::string(key) + "."; return false; @@ -1551,7 +2385,8 @@ class JsonReaderVisitor { JsonReaderVisitor(Json::Value* object, std::string* errors) : object_(object), errors_(errors) {} - template <typename T> bool Visit(const char* key, T* value) const { + template <typename T> + bool Visit(const char* key, T* value) const { return ReadValue(object_, key, value, errors_); } @@ -1565,27 +2400,28 @@ class JsonReaderVisitor { *errors_ = std::string(key) + " missing."; return false; } - if (AsArray(&json_value, count, *value)) return true; + if (AsArray(&json_value, count, *value)) + return true; if (errors_) *errors_ = std::string("Wrong type for ") + std::string(key) + "."; return false; } template <typename T> - bool VisitArray(const char* key, uint32_t count, T *value) { + bool VisitArray(const char* key, uint32_t count, T* value) { Json::Value json_value = (*object_)[key]; if (!json_value) { if (errors_) *errors_ = std::string(key) + " missing."; return false; } - if (AsArray(&json_value, count, *value)) return true; + if (AsArray(&json_value, count, *value)) + return true; if (errors_) *errors_ = std::string("Wrong type for ") + std::string(key) + "."; return false; } - private: Json::Value* object_; std::string* errors_; @@ -1593,21 +2429,21 @@ class JsonReaderVisitor { template <typename T, typename /*= EnableForStruct<T>*/> bool AsValue(Json::Value* json_value, T* t) { - if (json_value->type() != Json::objectValue) return false; + if (json_value->type() != Json::objectValue) + return false; JsonReaderVisitor visitor(json_value, nullptr); return VisitForRead(&visitor, t); } - -template <typename T> std::string VkTypeToJson(const T& t) { +template <typename T> +std::string VkTypeToJson(const T& t) { JsonWriterVisitor visitor; VisitForWrite(&visitor, t); return visitor.get_object().toStyledString(); } -template <typename T> bool VkTypeFromJson(const std::string& json, - T* t, - std::string* errors) { +template <typename T> +bool VkTypeFromJson(const std::string& json, T* t, std::string* errors) { *t = T(); Json::Value object(Json::objectValue); Json::CharReaderBuilder builder; diff --git a/vulkan/vkjson/vkjson.h b/vulkan/vkjson/vkjson.h index 87a76c1ac9..cfba8c58d9 100644 --- a/vulkan/vkjson/vkjson.h +++ b/vulkan/vkjson/vkjson.h @@ -21,8 +21,8 @@ #ifndef VKJSON_H_ #define VKJSON_H_ -#include <vulkan/vulkan.h> #include <string.h> +#include <vulkan/vulkan.h> #include <map> #include <string> @@ -33,64 +33,274 @@ #undef max #endif +/* + * This file is autogenerated by vkjson_generator.py. Do not edit directly. + */ struct VkJsonLayer { VkLayerProperties properties; std::vector<VkExtensionProperties> extensions; }; -struct VkJsonExtDriverProperties { - VkJsonExtDriverProperties() { +struct VkJsonKHRVariablePointers { + VkJsonKHRVariablePointers() { reported = false; - memset(&driver_properties_khr, 0, - sizeof(VkPhysicalDeviceDriverPropertiesKHR)); + memset(&variable_pointer_features_khr, 0, + sizeof(VkPhysicalDeviceVariablePointerFeaturesKHR)); + memset(&variable_pointers_features_khr, 0, + sizeof(VkPhysicalDeviceVariablePointersFeaturesKHR)); } bool reported; - VkPhysicalDeviceDriverPropertiesKHR driver_properties_khr; + VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointer_features_khr; + VkPhysicalDeviceVariablePointersFeaturesKHR variable_pointers_features_khr; }; -struct VkJsonExtVariablePointerFeatures { - VkJsonExtVariablePointerFeatures() { +struct VkJsonKHRShaderFloat16Int8 { + VkJsonKHRShaderFloat16Int8() { reported = false; - memset(&variable_pointer_features_khr, 0, - sizeof(VkPhysicalDeviceVariablePointerFeaturesKHR)); + memset(&shader_float16_int8_features_khr, 0, + sizeof(VkPhysicalDeviceShaderFloat16Int8FeaturesKHR)); + memset(&float16_int8_features_khr, 0, + sizeof(VkPhysicalDeviceFloat16Int8FeaturesKHR)); } bool reported; - VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointer_features_khr; + VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_float16_int8_features_khr; + VkPhysicalDeviceFloat16Int8FeaturesKHR float16_int8_features_khr; }; -struct VkJsonExtImage2DViewOf3DFeatures { - VkJsonExtImage2DViewOf3DFeatures() { +struct VkJsonExtImage2dViewOf3d { + VkJsonExtImage2dViewOf3d() { reported = false; - memset(&image_2D_view_of_3D_features_EXT, 0, + memset(&image_2d_view_of_3d_features_ext, 0, sizeof(VkPhysicalDeviceImage2DViewOf3DFeaturesEXT)); } bool reported; - VkPhysicalDeviceImage2DViewOf3DFeaturesEXT image_2D_view_of_3D_features_EXT; + VkPhysicalDeviceImage2DViewOf3DFeaturesEXT image_2d_view_of_3d_features_ext; }; -struct VkJsonExtShaderFloat16Int8Features { - VkJsonExtShaderFloat16Int8Features() { +struct VkJsonExtCustomBorderColor { + VkJsonExtCustomBorderColor() { reported = false; - memset(&shader_float16_int8_features_khr, 0, - sizeof(VkPhysicalDeviceShaderFloat16Int8FeaturesKHR)); + memset(&custom_border_color_features_ext, 0, + sizeof(VkPhysicalDeviceCustomBorderColorFeaturesEXT)); } bool reported; - VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_float16_int8_features_khr; + VkPhysicalDeviceCustomBorderColorFeaturesEXT custom_border_color_features_ext; +}; + +struct VkJsonExtPrimitiveTopologyListRestart { + VkJsonExtPrimitiveTopologyListRestart() { + reported = false; + memset(&primitive_topology_list_restart_features_ext, 0, + sizeof(VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT)); + } + bool reported; + VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT + primitive_topology_list_restart_features_ext; +}; + +struct VkJsonExtProvokingVertex { + VkJsonExtProvokingVertex() { + reported = false; + memset(&provoking_vertex_features_ext, 0, + sizeof(VkPhysicalDeviceProvokingVertexFeaturesEXT)); + } + bool reported; + VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex_features_ext; +}; + +struct VkJsonKHRIndexTypeUint8 { + VkJsonKHRIndexTypeUint8() { + reported = false; + memset(&index_type_uint8_features_khr, 0, + sizeof(VkPhysicalDeviceIndexTypeUint8FeaturesKHR)); + } + bool reported; + VkPhysicalDeviceIndexTypeUint8FeaturesKHR index_type_uint8_features_khr; +}; + +struct VkJsonExtIndexTypeUint8 { + VkJsonExtIndexTypeUint8() { + reported = false; + memset(&index_type_uint8_features_ext, 0, + sizeof(VkPhysicalDeviceIndexTypeUint8FeaturesEXT)); + } + bool reported; + VkPhysicalDeviceIndexTypeUint8FeaturesEXT index_type_uint8_features_ext; +}; + +struct VkJsonKHRVertexAttributeDivisor { + VkJsonKHRVertexAttributeDivisor() { + reported = false; + memset(&vertex_attribute_divisor_features_khr, 0, + sizeof(VkPhysicalDeviceVertexAttributeDivisorFeaturesKHR)); + } + bool reported; + VkPhysicalDeviceVertexAttributeDivisorFeaturesKHR + vertex_attribute_divisor_features_khr; +}; + +struct VkJsonExtVertexAttributeDivisor { + VkJsonExtVertexAttributeDivisor() { + reported = false; + memset(&vertex_attribute_divisor_features_ext, 0, + sizeof(VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT)); + } + bool reported; + VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT + vertex_attribute_divisor_features_ext; +}; + +struct VkJsonExtTransformFeedback { + VkJsonExtTransformFeedback() { + reported = false; + memset(&transform_feedback_features_ext, 0, + sizeof(VkPhysicalDeviceTransformFeedbackFeaturesEXT)); + } + bool reported; + VkPhysicalDeviceTransformFeedbackFeaturesEXT transform_feedback_features_ext; +}; + +struct VkJsonKHRShaderSubgroupUniformControlFlow { + VkJsonKHRShaderSubgroupUniformControlFlow() { + reported = false; + memset(&shader_subgroup_uniform_control_flow_features_khr, 0, + sizeof(VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR)); + } + bool reported; + VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR + shader_subgroup_uniform_control_flow_features_khr; +}; + +struct VkJsonKHRShaderSubgroupExtendedTypes { + VkJsonKHRShaderSubgroupExtendedTypes() { + reported = false; + memset(&shader_subgroup_extended_types_features_khr, 0, + sizeof(VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR)); + } + bool reported; + VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR + shader_subgroup_extended_types_features_khr; +}; + +struct VkJsonKHR8bitStorage { + VkJsonKHR8bitStorage() { + reported = false; + memset(&bit8_storage_features_khr, 0, + sizeof(VkPhysicalDevice8BitStorageFeaturesKHR)); + } + bool reported; + VkPhysicalDevice8BitStorageFeaturesKHR bit8_storage_features_khr; +}; + +struct VkJsonKHRShaderIntegerDotProduct { + VkJsonKHRShaderIntegerDotProduct() { + reported = false; + memset(&shader_integer_dot_product_features_khr, 0, + sizeof(VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR)); + } + bool reported; + VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR + shader_integer_dot_product_features_khr; +}; + +struct VkJsonIMGRelaxedLineRasterization { + VkJsonIMGRelaxedLineRasterization() { + reported = false; + memset(&relaxed_line_rasterization_features_img, 0, + sizeof(VkPhysicalDeviceRelaxedLineRasterizationFeaturesIMG)); + } + bool reported; + VkPhysicalDeviceRelaxedLineRasterizationFeaturesIMG + relaxed_line_rasterization_features_img; +}; + +struct VkJsonKHRLineRasterization { + VkJsonKHRLineRasterization() { + reported = false; + memset(&line_rasterization_features_khr, 0, + sizeof(VkPhysicalDeviceLineRasterizationFeaturesKHR)); + } + bool reported; + VkPhysicalDeviceLineRasterizationFeaturesKHR line_rasterization_features_khr; +}; + +struct VkJsonExtLineRasterization { + VkJsonExtLineRasterization() { + reported = false; + memset(&line_rasterization_features_ext, 0, + sizeof(VkPhysicalDeviceLineRasterizationFeaturesEXT)); + } + bool reported; + VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization_features_ext; +}; + +struct VkJsonExtPrimitivesGeneratedQuery { + VkJsonExtPrimitivesGeneratedQuery() { + reported = false; + memset(&primitives_generated_query_features_ext, 0, + sizeof(VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT)); + } + bool reported; + VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT + primitives_generated_query_features_ext; +}; + +struct VkJsonKHRShaderFloatControls { + VkJsonKHRShaderFloatControls() { + reported = false; + memset(&float_controls_properties_khr, 0, + sizeof(VkPhysicalDeviceFloatControlsPropertiesKHR)); + } + bool reported; + VkPhysicalDeviceFloatControlsPropertiesKHR float_controls_properties_khr; +}; + +struct VkJsonKHRDriverProperties { + VkJsonKHRDriverProperties() { + reported = false; + memset(&driver_properties_khr, 0, + sizeof(VkPhysicalDeviceDriverPropertiesKHR)); + } + bool reported; + VkPhysicalDeviceDriverPropertiesKHR driver_properties_khr; +}; + +struct VkJsonCore11 { + VkJsonCore11() { + memset(&properties, 0, sizeof(VkPhysicalDeviceVulkan11Properties)); + memset(&features, 0, sizeof(VkPhysicalDeviceVulkan11Features)); + } + VkPhysicalDeviceVulkan11Properties properties; + VkPhysicalDeviceVulkan11Features features; }; struct VkJsonCore12 { + VkJsonCore12() { + memset(&properties, 0, sizeof(VkPhysicalDeviceVulkan12Properties)); + memset(&features, 0, sizeof(VkPhysicalDeviceVulkan12Features)); + } VkPhysicalDeviceVulkan12Properties properties; VkPhysicalDeviceVulkan12Features features; }; struct VkJsonCore13 { + VkJsonCore13() { + memset(&properties, 0, sizeof(VkPhysicalDeviceVulkan13Properties)); + memset(&features, 0, sizeof(VkPhysicalDeviceVulkan13Features)); + } VkPhysicalDeviceVulkan13Properties properties; VkPhysicalDeviceVulkan13Features features; }; struct VkJsonCore14 { + VkJsonCore14() { + memset(&properties, 0, sizeof(VkPhysicalDeviceVulkan14Properties)); + memset(&features, 0, sizeof(VkPhysicalDeviceVulkan14Features)); + } VkPhysicalDeviceVulkan14Properties properties; VkPhysicalDeviceVulkan14Features features; + std::vector<VkImageLayout> copy_src_layouts; + std::vector<VkImageLayout> copy_dst_layouts; }; struct VkJsonDevice { @@ -109,29 +319,44 @@ struct VkJsonDevice { memset(&bit16_storage_features, 0, sizeof(VkPhysicalDevice16BitStorageFeatures)); memset(&multiview_features, 0, sizeof(VkPhysicalDeviceMultiviewFeatures)); - memset(&variable_pointer_features, 0, - sizeof(VkPhysicalDeviceVariablePointerFeatures)); + memset(&variable_pointers_features, 0, + sizeof(VkPhysicalDeviceVariablePointersFeatures)); memset(&protected_memory_features, 0, sizeof(VkPhysicalDeviceProtectedMemoryFeatures)); memset(&sampler_ycbcr_conversion_features, 0, sizeof(VkPhysicalDeviceSamplerYcbcrConversionFeatures)); memset(&shader_draw_parameter_features, 0, sizeof(VkPhysicalDeviceShaderDrawParameterFeatures)); - memset(&core12, 0, sizeof(VkJsonCore12)); - memset(&core13, 0, sizeof(VkJsonCore13)); - memset(&core14, 0, sizeof(VkJsonCore14)); } + VkJsonKHRVariablePointers khr_variable_pointers; + VkJsonKHRShaderFloat16Int8 khr_shader_float16_int8; + VkJsonExtImage2dViewOf3d ext_image_2d_view_of_3d; + VkJsonExtCustomBorderColor ext_custom_border_color; + VkJsonExtPrimitiveTopologyListRestart ext_primitive_topology_list_restart; + VkJsonExtProvokingVertex ext_provoking_vertex; + VkJsonKHRIndexTypeUint8 khr_index_type_uint8; + VkJsonExtIndexTypeUint8 ext_index_type_uint8; + VkJsonKHRVertexAttributeDivisor khr_vertex_attribute_divisor; + VkJsonExtVertexAttributeDivisor ext_vertex_attribute_divisor; + VkJsonExtTransformFeedback ext_transform_feedback; + VkJsonKHRShaderSubgroupUniformControlFlow + khr_shader_subgroup_uniform_control_flow; + VkJsonKHRShaderSubgroupExtendedTypes khr_shader_subgroup_extended_types; + VkJsonKHR8bitStorage khr_8bit_storage; + VkJsonKHRShaderIntegerDotProduct khr_shader_integer_dot_product; + VkJsonIMGRelaxedLineRasterization img_relaxed_line_rasterization; + VkJsonKHRLineRasterization khr_line_rasterization; + VkJsonExtLineRasterization ext_line_rasterization; + VkJsonExtPrimitivesGeneratedQuery ext_primitives_generated_query; + VkJsonKHRShaderFloatControls khr_shader_float_controls; + VkJsonKHRDriverProperties khr_driver_properties; + VkJsonCore11 core11; + VkJsonCore12 core12; + VkJsonCore13 core13; + VkJsonCore14 core14; VkPhysicalDeviceProperties properties; VkPhysicalDeviceFeatures features; - VkJsonExtDriverProperties ext_driver_properties; - VkJsonExtVariablePointerFeatures ext_variable_pointer_features; - VkJsonExtImage2DViewOf3DFeatures ext_image_2d_view_of_3d_features; - VkJsonExtShaderFloat16Int8Features ext_shader_float16_int8_features; VkPhysicalDeviceMemoryProperties memory; - std::vector<VkQueueFamilyProperties> queues; - std::vector<VkExtensionProperties> extensions; - std::vector<VkLayerProperties> layers; - std::map<VkFormat, VkFormatProperties> formats; VkPhysicalDeviceSubgroupProperties subgroup_properties; VkPhysicalDevicePointClippingProperties point_clipping_properties; VkPhysicalDeviceMultiviewProperties multiview_properties; @@ -139,18 +364,19 @@ struct VkJsonDevice { VkPhysicalDeviceMaintenance3Properties maintenance3_properties; VkPhysicalDevice16BitStorageFeatures bit16_storage_features; VkPhysicalDeviceMultiviewFeatures multiview_features; - VkPhysicalDeviceVariablePointerFeatures variable_pointer_features; + VkPhysicalDeviceVariablePointersFeatures variable_pointers_features; VkPhysicalDeviceProtectedMemoryFeatures protected_memory_features; VkPhysicalDeviceSamplerYcbcrConversionFeatures sampler_ycbcr_conversion_features; VkPhysicalDeviceShaderDrawParameterFeatures shader_draw_parameter_features; + std::vector<VkQueueFamilyProperties> queues; + std::vector<VkExtensionProperties> extensions; + std::vector<VkLayerProperties> layers; + std::map<VkFormat, VkFormatProperties> formats; std::map<VkExternalFenceHandleTypeFlagBits, VkExternalFenceProperties> external_fence_properties; std::map<VkExternalSemaphoreHandleTypeFlagBits, VkExternalSemaphoreProperties> external_semaphore_properties; - VkJsonCore12 core12; - VkJsonCore13 core13; - VkJsonCore14 core14; }; struct VkJsonDeviceGroup { @@ -204,4 +430,4 @@ inline bool VkJsonAllPropertiesFromJson(const std::string& json, return VkJsonDeviceFromJson(json, properties, errors); } -#endif // VKJSON_H_ +#endif // VKJSON_H_
\ No newline at end of file diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc index 04bb446e40..636c11933a 100644 --- a/vulkan/vkjson/vkjson_instance.cc +++ b/vulkan/vkjson/vkjson_instance.cc @@ -27,6 +27,9 @@ #include <algorithm> #include <utility> +/* + * This file is autogenerated by vkjson_generator.py. Do not edit directly. + */ namespace { bool EnumerateExtensions(const char* layer_name, @@ -79,13 +82,25 @@ VkJsonDevice VkJsonGetDevice(VkPhysicalDevice physical_device) { nullptr, {}, }; + + if (HasExtension("VK_KHR_shader_float_controls", device.extensions)) { + device.khr_shader_float_controls.reported = true; + device.khr_shader_float_controls.float_controls_properties_khr.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES; + device.khr_shader_float_controls.float_controls_properties_khr.pNext = + properties.pNext; + properties.pNext = + &device.khr_shader_float_controls.float_controls_properties_khr; + } + if (HasExtension("VK_KHR_driver_properties", device.extensions)) { - device.ext_driver_properties.reported = true; - device.ext_driver_properties.driver_properties_khr.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR; - device.ext_driver_properties.driver_properties_khr.pNext = properties.pNext; - properties.pNext = &device.ext_driver_properties.driver_properties_khr; + device.khr_driver_properties.reported = true; + device.khr_driver_properties.driver_properties_khr.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; + device.khr_driver_properties.driver_properties_khr.pNext = properties.pNext; + properties.pNext = &device.khr_driver_properties.driver_properties_khr; } + vkGetPhysicalDeviceProperties2(physical_device, &properties); device.properties = properties.properties; @@ -94,35 +109,215 @@ VkJsonDevice VkJsonGetDevice(VkPhysicalDevice physical_device) { nullptr, {}, }; + if (HasExtension("VK_KHR_variable_pointers", device.extensions)) { - device.ext_variable_pointer_features.reported = true; - device.ext_variable_pointer_features.variable_pointer_features_khr.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR; - device.ext_variable_pointer_features.variable_pointer_features_khr.pNext = + device.khr_variable_pointers.reported = true; + device.khr_variable_pointers.variable_pointer_features_khr.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES; + device.khr_variable_pointers.variable_pointer_features_khr.pNext = features.pNext; features.pNext = - &device.ext_variable_pointer_features.variable_pointer_features_khr; + &device.khr_variable_pointers.variable_pointer_features_khr; + device.khr_variable_pointers.variable_pointers_features_khr.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES; + device.khr_variable_pointers.variable_pointers_features_khr.pNext = + features.pNext; + features.pNext = + &device.khr_variable_pointers.variable_pointers_features_khr; } + + if (HasExtension("VK_KHR_shader_float16_int8", device.extensions)) { + device.khr_shader_float16_int8.reported = true; + device.khr_shader_float16_int8.shader_float16_int8_features_khr.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES; + device.khr_shader_float16_int8.shader_float16_int8_features_khr.pNext = + features.pNext; + features.pNext = + &device.khr_shader_float16_int8.shader_float16_int8_features_khr; + device.khr_shader_float16_int8.float16_int8_features_khr.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES; + device.khr_shader_float16_int8.float16_int8_features_khr.pNext = + features.pNext; + features.pNext = &device.khr_shader_float16_int8.float16_int8_features_khr; + } + if (HasExtension("VK_EXT_image_2d_view_of_3d", device.extensions)) { - device.ext_image_2d_view_of_3d_features.reported = true; - device.ext_image_2d_view_of_3d_features.image_2D_view_of_3D_features_EXT - .sType = + device.ext_image_2d_view_of_3d.reported = true; + device.ext_image_2d_view_of_3d.image_2d_view_of_3d_features_ext.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT; - device.ext_image_2d_view_of_3d_features.image_2D_view_of_3D_features_EXT + device.ext_image_2d_view_of_3d.image_2d_view_of_3d_features_ext.pNext = + features.pNext; + features.pNext = + &device.ext_image_2d_view_of_3d.image_2d_view_of_3d_features_ext; + } + + if (HasExtension("VK_EXT_custom_border_color", device.extensions)) { + device.ext_custom_border_color.reported = true; + device.ext_custom_border_color.custom_border_color_features_ext.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT; + device.ext_custom_border_color.custom_border_color_features_ext.pNext = + features.pNext; + features.pNext = + &device.ext_custom_border_color.custom_border_color_features_ext; + } + + if (HasExtension("VK_EXT_primitive_topology_list_restart", + device.extensions)) { + device.ext_primitive_topology_list_restart.reported = true; + device.ext_primitive_topology_list_restart + .primitive_topology_list_restart_features_ext.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT; + device.ext_primitive_topology_list_restart + .primitive_topology_list_restart_features_ext.pNext = features.pNext; + features.pNext = &device.ext_primitive_topology_list_restart + .primitive_topology_list_restart_features_ext; + } + + if (HasExtension("VK_EXT_provoking_vertex", device.extensions)) { + device.ext_provoking_vertex.reported = true; + device.ext_provoking_vertex.provoking_vertex_features_ext.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT; + device.ext_provoking_vertex.provoking_vertex_features_ext.pNext = + features.pNext; + features.pNext = &device.ext_provoking_vertex.provoking_vertex_features_ext; + } + + if (HasExtension("VK_KHR_index_type_uint8", device.extensions)) { + device.khr_index_type_uint8.reported = true; + device.khr_index_type_uint8.index_type_uint8_features_khr.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES; + device.khr_index_type_uint8.index_type_uint8_features_khr.pNext = + features.pNext; + features.pNext = &device.khr_index_type_uint8.index_type_uint8_features_khr; + } + + if (HasExtension("VK_EXT_index_type_uint8", device.extensions)) { + device.ext_index_type_uint8.reported = true; + device.ext_index_type_uint8.index_type_uint8_features_ext.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES; + device.ext_index_type_uint8.index_type_uint8_features_ext.pNext = + features.pNext; + features.pNext = &device.ext_index_type_uint8.index_type_uint8_features_ext; + } + + if (HasExtension("VK_KHR_vertex_attribute_divisor", device.extensions)) { + device.khr_vertex_attribute_divisor.reported = true; + device.khr_vertex_attribute_divisor.vertex_attribute_divisor_features_khr + .sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES; + device.khr_vertex_attribute_divisor.vertex_attribute_divisor_features_khr .pNext = features.pNext; - features.pNext = &device.ext_image_2d_view_of_3d_features - .image_2D_view_of_3D_features_EXT; + features.pNext = &device.khr_vertex_attribute_divisor + .vertex_attribute_divisor_features_khr; } - if (HasExtension("VK_KHR_shader_float16_int8", device.extensions)) { - device.ext_shader_float16_int8_features.reported = true; - device.ext_shader_float16_int8_features.shader_float16_int8_features_khr + + if (HasExtension("VK_EXT_vertex_attribute_divisor", device.extensions)) { + device.ext_vertex_attribute_divisor.reported = true; + device.ext_vertex_attribute_divisor.vertex_attribute_divisor_features_ext .sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR; - device.ext_shader_float16_int8_features.shader_float16_int8_features_khr + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES; + device.ext_vertex_attribute_divisor.vertex_attribute_divisor_features_ext .pNext = features.pNext; - features.pNext = &device.ext_shader_float16_int8_features - .shader_float16_int8_features_khr; + features.pNext = &device.ext_vertex_attribute_divisor + .vertex_attribute_divisor_features_ext; + } + + if (HasExtension("VK_EXT_transform_feedback", device.extensions)) { + device.ext_transform_feedback.reported = true; + device.ext_transform_feedback.transform_feedback_features_ext.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT; + device.ext_transform_feedback.transform_feedback_features_ext.pNext = + features.pNext; + features.pNext = + &device.ext_transform_feedback.transform_feedback_features_ext; + } + + if (HasExtension("VK_KHR_shader_subgroup_uniform_control_flow", + device.extensions)) { + device.khr_shader_subgroup_uniform_control_flow.reported = true; + device.khr_shader_subgroup_uniform_control_flow + .shader_subgroup_uniform_control_flow_features_khr.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR; + device.khr_shader_subgroup_uniform_control_flow + .shader_subgroup_uniform_control_flow_features_khr.pNext = + features.pNext; + features.pNext = &device.khr_shader_subgroup_uniform_control_flow + .shader_subgroup_uniform_control_flow_features_khr; + } + + if (HasExtension("VK_KHR_shader_subgroup_extended_types", + device.extensions)) { + device.khr_shader_subgroup_extended_types.reported = true; + device.khr_shader_subgroup_extended_types + .shader_subgroup_extended_types_features_khr.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES; + device.khr_shader_subgroup_extended_types + .shader_subgroup_extended_types_features_khr.pNext = features.pNext; + features.pNext = &device.khr_shader_subgroup_extended_types + .shader_subgroup_extended_types_features_khr; + } + + if (HasExtension("VK_KHR_8bit_storage", device.extensions)) { + device.khr_8bit_storage.reported = true; + device.khr_8bit_storage.bit8_storage_features_khr.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES; + device.khr_8bit_storage.bit8_storage_features_khr.pNext = features.pNext; + features.pNext = &device.khr_8bit_storage.bit8_storage_features_khr; + } + + if (HasExtension("VK_KHR_shader_integer_dot_product", device.extensions)) { + device.khr_shader_integer_dot_product.reported = true; + device.khr_shader_integer_dot_product + .shader_integer_dot_product_features_khr.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES; + device.khr_shader_integer_dot_product + .shader_integer_dot_product_features_khr.pNext = features.pNext; + features.pNext = &device.khr_shader_integer_dot_product + .shader_integer_dot_product_features_khr; + } + + if (HasExtension("VK_IMG_relaxed_line_rasterization", device.extensions)) { + device.img_relaxed_line_rasterization.reported = true; + device.img_relaxed_line_rasterization + .relaxed_line_rasterization_features_img.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RELAXED_LINE_RASTERIZATION_FEATURES_IMG; + device.img_relaxed_line_rasterization + .relaxed_line_rasterization_features_img.pNext = features.pNext; + features.pNext = &device.img_relaxed_line_rasterization + .relaxed_line_rasterization_features_img; + } + + if (HasExtension("VK_KHR_line_rasterization", device.extensions)) { + device.khr_line_rasterization.reported = true; + device.khr_line_rasterization.line_rasterization_features_khr.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES; + device.khr_line_rasterization.line_rasterization_features_khr.pNext = + features.pNext; + features.pNext = + &device.khr_line_rasterization.line_rasterization_features_khr; + } + + if (HasExtension("VK_EXT_line_rasterization", device.extensions)) { + device.ext_line_rasterization.reported = true; + device.ext_line_rasterization.line_rasterization_features_ext.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES; + device.ext_line_rasterization.line_rasterization_features_ext.pNext = + features.pNext; + features.pNext = + &device.ext_line_rasterization.line_rasterization_features_ext; } + + if (HasExtension("VK_EXT_primitives_generated_query", device.extensions)) { + device.ext_primitives_generated_query.reported = true; + device.ext_primitives_generated_query + .primitives_generated_query_features_ext.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT; + device.ext_primitives_generated_query + .primitives_generated_query_features_ext.pNext = features.pNext; + features.pNext = &device.ext_primitives_generated_query + .primitives_generated_query_features_ext; + } + vkGetPhysicalDeviceFeatures2(physical_device, &features); device.features = features.features; @@ -194,20 +389,15 @@ VkJsonDevice VkJsonGetDevice(VkPhysicalDevice physical_device) { vkGetPhysicalDeviceProperties2(physical_device, &properties); - device.bit16_storage_features.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES; - device.bit16_storage_features.pNext = features.pNext; - features.pNext = &device.bit16_storage_features; - device.multiview_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; device.multiview_features.pNext = features.pNext; features.pNext = &device.multiview_features; - device.variable_pointer_features.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES; - device.variable_pointer_features.pNext = features.pNext; - features.pNext = &device.variable_pointer_features; + device.variable_pointers_features.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES; + device.variable_pointers_features.pNext = features.pNext; + features.pNext = &device.variable_pointers_features; device.protected_memory_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES; @@ -220,10 +410,15 @@ VkJsonDevice VkJsonGetDevice(VkPhysicalDevice physical_device) { features.pNext = &device.sampler_ycbcr_conversion_features; device.shader_draw_parameter_features.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES; + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES; device.shader_draw_parameter_features.pNext = features.pNext; features.pNext = &device.shader_draw_parameter_features; + device.bit16_storage_features.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES; + device.bit16_storage_features.pNext = features.pNext; + features.pNext = &device.bit16_storage_features; + vkGetPhysicalDeviceFeatures2(physical_device, &features); VkPhysicalDeviceExternalFenceInfo external_fence_info = { @@ -271,6 +466,11 @@ VkJsonDevice VkJsonGetDevice(VkPhysicalDevice physical_device) { } if (device.properties.apiVersion >= VK_API_VERSION_1_2) { + device.core11.properties.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES; + device.core11.properties.pNext = properties.pNext; + properties.pNext = &device.core11.properties; + device.core12.properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES; device.core12.properties.pNext = properties.pNext; @@ -278,6 +478,11 @@ VkJsonDevice VkJsonGetDevice(VkPhysicalDevice physical_device) { vkGetPhysicalDeviceProperties2(physical_device, &properties); + device.core11.features.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; + device.core11.features.pNext = features.pNext; + features.pNext = &device.core11.features; + device.core12.features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; device.core12.features.pNext = features.pNext; @@ -310,6 +515,23 @@ VkJsonDevice VkJsonGetDevice(VkPhysicalDevice physical_device) { vkGetPhysicalDeviceProperties2(physical_device, &properties); + if (device.core14.properties.copySrcLayoutCount > 0 || + device.core14.properties.copyDstLayoutCount > 0) { + if (device.core14.properties.copySrcLayoutCount > 0) { + device.core14.copy_src_layouts.resize( + device.core14.properties.copySrcLayoutCount); + device.core14.properties.pCopySrcLayouts = + device.core14.copy_src_layouts.data(); + } + if (device.core14.properties.copyDstLayoutCount > 0) { + device.core14.copy_dst_layouts.resize( + device.core14.properties.copyDstLayoutCount); + device.core14.properties.pCopyDstLayouts = + device.core14.copy_dst_layouts.data(); + } + vkGetPhysicalDeviceProperties2(physical_device, &properties); + } + device.core14.features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES; device.core14.features.pNext = features.pNext; @@ -337,7 +559,8 @@ VkJsonInstance VkJsonGetInstance() { return VkJsonInstance(); instance.layers.reserve(count); for (auto& layer : layers) { - instance.layers.push_back(VkJsonLayer{layer, std::vector<VkExtensionProperties>()}); + instance.layers.push_back( + VkJsonLayer{layer, std::vector<VkExtensionProperties>()}); if (!EnumerateExtensions(layer.layerName, &instance.layers.back().extensions)) return VkJsonInstance(); |