summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/atrace/atrace.rc91
-rw-r--r--cmds/flatland/GLHelper.cpp2
-rw-r--r--cmds/installd/TEST_MAPPING4
-rw-r--r--include/android/configuration.h1
-rw-r--r--include/android/thermal.h20
-rw-r--r--include/input/DisplayTopologyGraph.h5
-rw-r--r--include/input/InputFlags.h16
-rw-r--r--include/powermanager/PowerHalController.h3
-rw-r--r--include/powermanager/PowerHalWrapper.h70
-rw-r--r--include/powermanager/PowerHintSessionWrapper.h2
-rw-r--r--libs/binder/Android.bp9
-rw-r--r--libs/binder/BackendUnifiedServiceManager.cpp8
-rw-r--r--libs/binder/Binder.cpp3
-rw-r--r--libs/binder/rust/rpcbinder/src/lib.rs2
-rw-r--r--libs/binder/rust/rpcbinder/src/server/trusty.rs4
-rw-r--r--libs/binder/rust/src/binder.rs6
-rw-r--r--libs/binder/tests/binderRpcTest.cpp8
-rw-r--r--libs/binder/trusty/include/binder/RpcServerTrusty.h9
-rw-r--r--libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp9
-rw-r--r--libs/dumputils/dump_utils.cpp1
-rw-r--r--libs/graphicsenv/GraphicsEnv.cpp4
-rw-r--r--libs/graphicsenv/graphicsenv_flags.aconfig6
-rw-r--r--libs/gui/Android.bp5
-rw-r--r--libs/gui/BLASTBufferQueue.cpp15
-rw-r--r--libs/gui/BufferItemConsumer.cpp27
-rw-r--r--libs/gui/BufferQueueConsumer.cpp32
-rw-r--r--libs/gui/BufferQueueProducer.cpp6
-rw-r--r--libs/gui/ConsumerBase.cpp6
-rw-r--r--libs/gui/Surface.cpp34
-rw-r--r--libs/gui/SurfaceComposerClient.cpp1
-rw-r--r--libs/gui/SurfaceControl.cpp4
-rw-r--r--libs/gui/aidl/android/gui/StaticDisplayInfo.aidl1
-rw-r--r--libs/gui/include/gui/BufferItemConsumer.h10
-rw-r--r--libs/gui/include/gui/BufferQueueConsumer.h5
-rw-r--r--libs/gui/include/gui/ConsumerBase.h2
-rw-r--r--libs/gui/include/gui/IGraphicBufferConsumer.h8
-rw-r--r--libs/gui/include/gui/InputTransferToken.h10
-rw-r--r--libs/gui/include/gui/Surface.h3
-rw-r--r--libs/gui/include/gui/SurfaceControl.h6
-rw-r--r--libs/gui/include/gui/mock/GraphicBufferConsumer.h1
-rw-r--r--libs/gui/libgui_flags.aconfig25
-rw-r--r--libs/gui/tests/Android.bp6
-rw-r--r--libs/gui/tests/BLASTBufferQueue_test.cpp2
-rw-r--r--libs/gui/tests/BufferItemConsumer_test.cpp33
-rw-r--r--libs/gui/tests/BufferQueue_test.cpp15
-rw-r--r--libs/gui/tests/DisplayedContentSampling_test.cpp2
-rw-r--r--libs/gui/tests/EndToEndNativeInputTest.cpp10
-rw-r--r--libs/gui/tests/GLTest.cpp2
-rw-r--r--libs/gui/tests/RegionSampling_test.cpp2
-rw-r--r--libs/gui/tests/SamplingDemo.cpp2
-rw-r--r--libs/gui/tests/Surface_test.cpp101
-rw-r--r--libs/input/Android.bp2
-rw-r--r--libs/input/DisplayTopologyGraph.cpp144
-rw-r--r--libs/input/InputFlags.cpp4
-rw-r--r--libs/input/input_flags.aconfig27
-rw-r--r--libs/renderengine/Android.bp6
-rw-r--r--libs/renderengine/benchmark/Android.bp2
-rw-r--r--libs/renderengine/skia/SkiaRenderEngine.cpp11
-rw-r--r--libs/renderengine/skia/filters/LutShader.cpp7
-rw-r--r--libs/ui/Android.bp1
-rw-r--r--libs/ui/DependencyMonitor.cpp144
-rw-r--r--libs/ui/FenceTime.cpp13
-rw-r--r--libs/ui/GraphicBuffer.cpp14
-rw-r--r--libs/ui/include/ui/DependencyMonitor.h104
-rw-r--r--libs/ui/include/ui/DisplayId.h81
-rw-r--r--libs/ui/include/ui/DisplayIdentification.h17
-rw-r--r--libs/ui/include/ui/FenceTime.h11
-rw-r--r--libs/ui/include/ui/GraphicBuffer.h5
-rw-r--r--libs/ui/include/ui/StaticDisplayInfo.h1
-rw-r--r--libs/ui/tests/Android.bp10
-rw-r--r--libs/ui/tests/DisplayId_test.cpp101
-rw-r--r--opengl/libs/EGL/egl_display.cpp2
-rw-r--r--opengl/tests/lib/WindowSurface.cpp2
-rw-r--r--services/automotive/display/AutomotiveDisplayProxyService.cpp2
-rw-r--r--services/gpuservice/GpuService.cpp6
-rw-r--r--services/inputflinger/PointerChoreographer.cpp3
-rw-r--r--services/inputflinger/dispatcher/Entry.h7
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.cpp127
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.h9
-rw-r--r--services/inputflinger/dispatcher/LatencyTracker.cpp9
-rw-r--r--services/inputflinger/dispatcher/LatencyTracker.h9
-rw-r--r--services/inputflinger/dispatcher/TouchState.cpp4
-rw-r--r--services/inputflinger/dispatcher/TouchState.h2
-rw-r--r--services/inputflinger/dispatcher/TouchedWindow.cpp4
-rw-r--r--services/inputflinger/dispatcher/TouchedWindow.h7
-rw-r--r--services/inputflinger/dispatcher/include/InputDispatcherInterface.h2
-rw-r--r--services/inputflinger/reader/mapper/TouchpadInputMapper.cpp23
-rw-r--r--services/inputflinger/tests/Android.bp1
-rw-r--r--services/inputflinger/tests/DisplayTopologyGraph_test.cpp120
-rw-r--r--services/inputflinger/tests/InputDispatcher_test.cpp239
-rw-r--r--services/inputflinger/tests/LatencyTracker_test.cpp19
-rw-r--r--services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp5
-rw-r--r--services/powermanager/Android.bp1
-rw-r--r--services/powermanager/PowerHalController.cpp15
-rw-r--r--services/powermanager/PowerHalWrapper.cpp18
-rw-r--r--services/powermanager/tests/PowerHalWrapperAidlTest.cpp49
-rw-r--r--services/stats/Android.bp32
-rw-r--r--services/stats/StatsAidl.cpp7
-rw-r--r--services/stats/StatsHal.cpp51
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h6
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h2
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h1
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h6
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h1
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h1
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h1
-rw-r--r--services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp4
-rw-r--r--services/surfaceflinger/CompositionEngine/src/Display.cpp63
-rw-r--r--services/surfaceflinger/CompositionEngine/src/Output.cpp18
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp73
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp6
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp48
-rw-r--r--services/surfaceflinger/Display/VirtualDisplaySnapshot.h1
-rw-r--r--services/surfaceflinger/DisplayDevice.cpp5
-rw-r--r--services/surfaceflinger/DisplayDevice.h34
-rw-r--r--services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp5
-rw-r--r--services/surfaceflinger/DisplayHardware/ComposerHal.h5
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.cpp6
-rw-r--r--services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp17
-rw-r--r--services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp53
-rw-r--r--services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h6
-rw-r--r--services/surfaceflinger/FrameTimeline/FrameTimeline.cpp13
-rw-r--r--services/surfaceflinger/FrameTimeline/FrameTimeline.h10
-rw-r--r--services/surfaceflinger/FrontEnd/RequestedLayerState.cpp9
-rw-r--r--services/surfaceflinger/FrontEnd/RequestedLayerState.h1
-rw-r--r--services/surfaceflinger/Layer.cpp10
-rw-r--r--services/surfaceflinger/Layer.h1
-rw-r--r--services/surfaceflinger/LayerFE.cpp13
-rw-r--r--services/surfaceflinger/LayerFE.h3
-rw-r--r--services/surfaceflinger/LayerVector.h3
-rw-r--r--services/surfaceflinger/PowerAdvisor/SessionManager.h5
-rw-r--r--services/surfaceflinger/RegionSamplingThread.cpp2
-rw-r--r--services/surfaceflinger/Scheduler/EventThread.cpp25
-rw-r--r--services/surfaceflinger/Scheduler/EventThread.h11
-rw-r--r--services/surfaceflinger/Scheduler/Scheduler.cpp42
-rw-r--r--services/surfaceflinger/Scheduler/Scheduler.h28
-rw-r--r--services/surfaceflinger/Scheduler/VsyncConfiguration.cpp11
-rw-r--r--services/surfaceflinger/Scheduler/VsyncConfiguration.h2
-rw-r--r--services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h2
-rw-r--r--services/surfaceflinger/ScreenCaptureOutput.cpp24
-rw-r--r--services/surfaceflinger/ScreenCaptureOutput.h6
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp521
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h37
-rw-r--r--services/surfaceflinger/TransactionCallbackInvoker.cpp12
-rw-r--r--services/surfaceflinger/TransactionCallbackInvoker.h2
-rw-r--r--services/surfaceflinger/common/FlagManager.cpp4
-rw-r--r--services/surfaceflinger/common/include/common/FlagManager.h2
-rw-r--r--services/surfaceflinger/surfaceflinger_flags_new.aconfig7
-rw-r--r--services/surfaceflinger/tests/benchmarks/LayerLifecycleManager_benchmarks.cpp41
l---------services/surfaceflinger/tests/end2end/.clang-format1
-rw-r--r--services/surfaceflinger/tests/end2end/.clang-tidy380
-rw-r--r--services/surfaceflinger/tests/end2end/.clangd20
-rw-r--r--services/surfaceflinger/tests/end2end/Android.bp68
-rw-r--r--services/surfaceflinger/tests/end2end/AndroidTest.xml39
-rw-r--r--services/surfaceflinger/tests/end2end/README.md75
-rw-r--r--services/surfaceflinger/tests/end2end/main.cpp55
-rw-r--r--services/surfaceflinger/tests/end2end/test_framework/core/DisplayConfiguration.h29
-rw-r--r--services/surfaceflinger/tests/end2end/test_framework/core/TestService.cpp82
-rw-r--r--services/surfaceflinger/tests/end2end/test_framework/core/TestService.h76
-rw-r--r--services/surfaceflinger/tests/end2end/test_framework/fake_hwc3/Hwc3Composer.cpp123
-rw-r--r--services/surfaceflinger/tests/end2end/test_framework/fake_hwc3/Hwc3Composer.h61
-rw-r--r--services/surfaceflinger/tests/end2end/test_framework/fake_hwc3/Hwc3Controller.cpp106
-rw-r--r--services/surfaceflinger/tests/end2end/test_framework/fake_hwc3/Hwc3Controller.h59
-rw-r--r--services/surfaceflinger/tests/end2end/test_framework/surfaceflinger/SFController.cpp181
-rw-r--r--services/surfaceflinger/tests/end2end/test_framework/surfaceflinger/SFController.h70
-rw-r--r--services/surfaceflinger/tests/end2end/tests/.clang-tidy32
-rw-r--r--services/surfaceflinger/tests/end2end/tests/Placeholder_test.cpp39
-rw-r--r--services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h26
-rw-r--r--services/surfaceflinger/tests/unittests/DualDisplayTransactionTest.h6
-rw-r--r--services/surfaceflinger/tests/unittests/EventThreadTest.cpp69
-rw-r--r--services/surfaceflinger/tests/unittests/FlagManagerTest.cpp4
-rw-r--r--services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp34
-rw-r--r--services/surfaceflinger/tests/unittests/SchedulerTest.cpp26
-rw-r--r--services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp4
-rw-r--r--services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp24
-rw-r--r--services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp45
-rw-r--r--services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp56
-rw-r--r--services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp20
-rw-r--r--services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp (renamed from services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp)68
-rw-r--r--services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp4
-rw-r--r--services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h37
-rw-r--r--services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp35
-rw-r--r--services/surfaceflinger/tests/unittests/mock/MockEventThread.h1
-rw-r--r--services/vibratorservice/Android.bp5
-rw-r--r--services/vibratorservice/VibratorController.cpp196
-rw-r--r--services/vibratorservice/include/vibratorservice/VibratorController.h118
-rw-r--r--services/vibratorservice/include/vibratorservice/VibratorHalController.h2
-rw-r--r--services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h2
-rw-r--r--services/vibratorservice/test/Android.bp5
-rw-r--r--services/vibratorservice/test/VibratorControllerTest.cpp248
-rw-r--r--vulkan/libvulkan/Android.bp40
-rw-r--r--vulkan/libvulkan/allocator.cpp113
-rw-r--r--vulkan/libvulkan/allocator.h25
-rw-r--r--vulkan/libvulkan/driver.cpp75
-rw-r--r--vulkan/libvulkan/driver.h2
-rwxr-xr-xvulkan/scripts/code_generator.py4
-rw-r--r--vulkan/scripts/vk.py968
-rw-r--r--vulkan/scripts/vkjson_generator.py1902
-rw-r--r--vulkan/vkjson/vkjson.cc2020
-rw-r--r--vulkan/vkjson/vkjson.h302
-rw-r--r--vulkan/vkjson/vkjson_instance.cc291
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();