From ac9b007b67597247e2b34a893d5b8bddb16f3df4 Mon Sep 17 00:00:00 2001 From: Rylie Pavlik Date: Wed, 8 May 2024 17:02:25 -0500 Subject: [PATCH] OpenXR CTS 1.1.36.0 (2024-04-25) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This new release supports testing both OpenXR 1.0 and OpenXR 1.1 runtimes, and defaults to OpenXR 1.1 mode. See the README for more details. - Conformance Tests - Fix: In multithreading test, only verify written portion of string buffer is UTF-8. (internal MR 3232) - Fix: Increase eps for hand-tracking conformance tests. (internal MR 3233) - Fix: Remove invalid interpretation of XrInstanceProperties::runtimeVersion. (internal MR 3275) - Fix: Correct typo in CLI help text. (internal MR 3302) - Fix: Correct typo in sample command lines in README. (internal MR 3326) - Improvement: Update Android compile SDK version (to 33), NDK version (to 23.2), and build tools version (to 34.0.0). (internal MR 2992) - Improvement: Reduce duplication of environment variable getters and setters. (internal MR 3039) - Improvement: Enhancements to existing test of XR_EXT_local_floor. (internal MR 3154, internal issue 2150, internal MR 3318, internal MR 3327) - Improvement: Use generated data from the XML in existing action tests rather than hardcoded tables. (internal MR 3224, internal issue 2063, internal MR 3306, internal MR 3318, internal MR 3321) - Improvement: Automatically enabled extension(s) needed for the interaction profile specified on the command line. (internal MR 3224, internal issue 2063, internal MR 3306, internal MR 3318, internal MR 3321) - Improvement: Code cleanup. (internal MR 3257, internal MR 3273, internal MR 3208, internal MR 3241) - Improvement: Allow VK_FORMAT_R8G8_SRGB in swapchains test (internal MR 3258) - Improvement: Support specifying API version (1.0 or 1.1) - defaults to 1.1. (internal MR 3274, internal issue 2205, internal MR 3296, internal MR 3297, internal issue 2236, internal MR 3298, internal MR 3318) - Improvement: Use spec-provided constants for inspecting enums for core vs extension origination. (internal MR 3275) - New test: Automated test of core OpenXR 1.1 feature LOCAL_FLOOR reference space. (internal MR 3154, internal issue 2150, internal MR 3318, internal MR 3327) - New test: Interactive test of LOCAL_FLOOR reference space (in both extension and promoted to core). (internal MR 3154, internal issue 2150, internal MR 3318, internal MR 3327) - New test: Test for xrLocateSpacesKHR (from XR_KHR_locate_spaces) and xrLocateSpaces (promoted to core OpenXR 1.1). (internal MR 3208, internal issue 2149) - New test: Verify correct handling of all interaction profile paths and their input component paths (accept vs reject suggested binding), in the “default” configuration of the instance, using generated data from the XML. (internal MR 3224, internal issue 2063, internal MR 3306, internal MR 3318, internal MR 3321) - New test: Created ProjectionDepth interactive test to visually verify behavior of XR_FB_composition_layer_depth_test extension. (internal MR 3229) - New test: Automated and interactive tests for the “stereo with foveated inset” view configuration type (promoted to core OpenXR 1.1), as well as its extension predecessor XR_VARJO_quad_views. (internal MR 3241, internal issue 2152, internal MR 3310, internal MR 3318) - New test: Additional test for grip_surface pose identifier (promoted to core OpenXR 1.1), as well as extension XR_EXT_palm_pose. (internal MR 3245, internal issue 2151, internal MR 3318, internal MR 3328) - New test: Created non-interactive test for XR_FB_space_warp extension. (internal MR 3278) GitOrigin-RevId: 4b0241e33f68af30c8c1b9539285953ca8619ed3 --- .proclamation.json | 4 - CHANGELOG.CTS.md | 102 +++++++ README.md | 8 +- changes/conformance/mr.2992.gl.md | 1 - changes/conformance/mr.3039.gl.md | 1 - changes/conformance/mr.3154.gl.md | 7 - changes/conformance/mr.3208.gl.md | 4 - changes/conformance/mr.3224.gl.md | 8 - changes/conformance/mr.3229.gl.md | 1 - changes/conformance/mr.3232.gl.md | 1 - changes/conformance/mr.3233.gl.md | 1 - changes/conformance/mr.3241.gl.md | 6 - changes/conformance/mr.3245.gl.md | 5 - changes/conformance/mr.3257.gl.md | 7 - changes/conformance/mr.3258.gl.md | 1 - changes/conformance/mr.3274.gl.md | 9 - changes/conformance/mr.3275.gl.md | 2 - changes/conformance/mr.3302.gl.md | 1 - src/conformance/conformance_test/readme.md | 8 +- .../test_XR_EXT_local_floor.cpp | 4 +- .../test_XR_EXT_palm_pose.cpp | 271 ++++++++++-------- .../test_XR_FB_space_warp.cpp | 172 +++++++++++ .../conformance_test/test_actions.cpp | 45 ++- .../framework/conformance_utils.cpp | 43 +++ src/conformance/framework/conformance_utils.h | 4 + src/conformance/framework/graphics_plugin.h | 3 + .../framework/graphics_plugin_d3d11.cpp | 19 ++ .../framework/graphics_plugin_d3d12.cpp | 19 ++ .../framework/graphics_plugin_opengl.cpp | 21 ++ .../framework/graphics_plugin_opengles.cpp | 20 ++ .../framework/graphics_plugin_vulkan.cpp | 19 ++ .../framework/input_testinputdevice.cpp | 8 +- src/conformance/utilities/CMakeLists.txt | 1 + src/conformance/utilities/string_utils.cpp | 66 +++++ src/conformance/utilities/string_utils.h | 48 ++++ 35 files changed, 725 insertions(+), 215 deletions(-) delete mode 100644 changes/conformance/mr.2992.gl.md delete mode 100644 changes/conformance/mr.3039.gl.md delete mode 100644 changes/conformance/mr.3154.gl.md delete mode 100644 changes/conformance/mr.3208.gl.md delete mode 100644 changes/conformance/mr.3224.gl.md delete mode 100644 changes/conformance/mr.3229.gl.md delete mode 100644 changes/conformance/mr.3232.gl.md delete mode 100644 changes/conformance/mr.3233.gl.md delete mode 100644 changes/conformance/mr.3241.gl.md delete mode 100644 changes/conformance/mr.3245.gl.md delete mode 100644 changes/conformance/mr.3257.gl.md delete mode 100644 changes/conformance/mr.3258.gl.md delete mode 100644 changes/conformance/mr.3274.gl.md delete mode 100644 changes/conformance/mr.3275.gl.md delete mode 100644 changes/conformance/mr.3302.gl.md create mode 100644 src/conformance/conformance_test/test_XR_FB_space_warp.cpp create mode 100644 src/conformance/utilities/string_utils.cpp create mode 100644 src/conformance/utilities/string_utils.h diff --git a/.proclamation.json b/.proclamation.json index fd221cee..3514b224 100644 --- a/.proclamation.json +++ b/.proclamation.json @@ -22,10 +22,6 @@ "news_filename": "CHANGELOG.Docs.md", "template": "changes/template.md", "sections": { - "Major Update": { - "directory": "changes/major", - "sort_by_prefix": true - }, "Registry": { "directory": "changes/registry", "sort_by_prefix": true diff --git a/CHANGELOG.CTS.md b/CHANGELOG.CTS.md index c1191599..6a354453 100644 --- a/CHANGELOG.CTS.md +++ b/CHANGELOG.CTS.md @@ -17,6 +17,108 @@ particular, since it is primarily software, pull requests may be integrated as they are accepted even between periodic updates. However, versions that are not signed tags on the `approved` branch are not valid for conformance submission. +## OpenXR CTS 1.1.36.0 (2024-04-25) + +This new release supports testing both OpenXR 1.0 and OpenXR 1.1 runtimes, and +defaults to OpenXR 1.1 mode. See the README for more details. + +- Conformance Tests + - Fix: In multithreading test, only verify written portion of string buffer is + UTF-8. + ([internal MR 3232](https://gitlab.khronos.org/openxr/openxr/merge_requests/3232)) + - Fix: Increase `eps` for hand-tracking conformance tests. + ([internal MR 3233](https://gitlab.khronos.org/openxr/openxr/merge_requests/3233)) + - Fix: Remove invalid interpretation of `XrInstanceProperties::runtimeVersion`. + ([internal MR 3275](https://gitlab.khronos.org/openxr/openxr/merge_requests/3275)) + - Fix: Correct typo in CLI help text. + ([internal MR 3302](https://gitlab.khronos.org/openxr/openxr/merge_requests/3302)) + - Fix: Correct typo in sample command lines in README. + ([internal MR 3326](https://gitlab.khronos.org/openxr/openxr/merge_requests/3326)) + - Improvement: Update Android compile SDK version (to 33), NDK version (to 23.2), + and build tools version (to 34.0.0). + ([internal MR 2992](https://gitlab.khronos.org/openxr/openxr/merge_requests/2992)) + - Improvement: Reduce duplication of environment variable getters and setters. + ([internal MR 3039](https://gitlab.khronos.org/openxr/openxr/merge_requests/3039)) + - Improvement: Enhancements to existing test of `XR_EXT_local_floor`. + ([internal MR 3154](https://gitlab.khronos.org/openxr/openxr/merge_requests/3154), + [internal issue 2150](https://gitlab.khronos.org/openxr/openxr/issues/2150), + [internal MR 3318](https://gitlab.khronos.org/openxr/openxr/merge_requests/3318), + [internal MR 3327](https://gitlab.khronos.org/openxr/openxr/merge_requests/3327)) + - Improvement: Use generated data from the XML in existing action tests rather + than hardcoded tables. + ([internal MR 3224](https://gitlab.khronos.org/openxr/openxr/merge_requests/3224), + [internal issue 2063](https://gitlab.khronos.org/openxr/openxr/issues/2063), + [internal MR 3306](https://gitlab.khronos.org/openxr/openxr/merge_requests/3306), + [internal MR 3318](https://gitlab.khronos.org/openxr/openxr/merge_requests/3318), + [internal MR 3321](https://gitlab.khronos.org/openxr/openxr/merge_requests/3321)) + - Improvement: Automatically enabled extension(s) needed for the interaction + profile specified on the command line. + ([internal MR 3224](https://gitlab.khronos.org/openxr/openxr/merge_requests/3224), + [internal issue 2063](https://gitlab.khronos.org/openxr/openxr/issues/2063), + [internal MR 3306](https://gitlab.khronos.org/openxr/openxr/merge_requests/3306), + [internal MR 3318](https://gitlab.khronos.org/openxr/openxr/merge_requests/3318), + [internal MR 3321](https://gitlab.khronos.org/openxr/openxr/merge_requests/3321)) + - Improvement: Code cleanup. + ([internal MR 3257](https://gitlab.khronos.org/openxr/openxr/merge_requests/3257), + [internal MR 3273](https://gitlab.khronos.org/openxr/openxr/merge_requests/3273), + [internal MR 3208](https://gitlab.khronos.org/openxr/openxr/merge_requests/3208), + [internal MR 3241](https://gitlab.khronos.org/openxr/openxr/merge_requests/3241)) + - Improvement: Allow `VK_FORMAT_R8G8_SRGB` in swapchains test + ([internal MR 3258](https://gitlab.khronos.org/openxr/openxr/merge_requests/3258)) + - Improvement: Support specifying API version (1.0 or 1.1) - defaults to 1.1. + ([internal MR 3274](https://gitlab.khronos.org/openxr/openxr/merge_requests/3274), + [internal issue 2205](https://gitlab.khronos.org/openxr/openxr/issues/2205), + [internal MR 3296](https://gitlab.khronos.org/openxr/openxr/merge_requests/3296), + [internal MR 3297](https://gitlab.khronos.org/openxr/openxr/merge_requests/3297), + [internal issue 2236](https://gitlab.khronos.org/openxr/openxr/issues/2236), + [internal MR 3298](https://gitlab.khronos.org/openxr/openxr/merge_requests/3298), + [internal MR 3318](https://gitlab.khronos.org/openxr/openxr/merge_requests/3318)) + - Improvement: Use spec-provided constants for inspecting enums for core vs + extension origination. + ([internal MR 3275](https://gitlab.khronos.org/openxr/openxr/merge_requests/3275)) + - New test: Automated test of core OpenXR 1.1 feature `LOCAL_FLOOR` reference + space. + ([internal MR 3154](https://gitlab.khronos.org/openxr/openxr/merge_requests/3154), + [internal issue 2150](https://gitlab.khronos.org/openxr/openxr/issues/2150), + [internal MR 3318](https://gitlab.khronos.org/openxr/openxr/merge_requests/3318), + [internal MR 3327](https://gitlab.khronos.org/openxr/openxr/merge_requests/3327)) + - New test: Interactive test of `LOCAL_FLOOR` reference space (in both extension + and promoted to core). + ([internal MR 3154](https://gitlab.khronos.org/openxr/openxr/merge_requests/3154), + [internal issue 2150](https://gitlab.khronos.org/openxr/openxr/issues/2150), + [internal MR 3318](https://gitlab.khronos.org/openxr/openxr/merge_requests/3318), + [internal MR 3327](https://gitlab.khronos.org/openxr/openxr/merge_requests/3327)) + - New test: Test for `xrLocateSpacesKHR` (from `XR_KHR_locate_spaces`) and + `xrLocateSpaces` (promoted to core OpenXR 1.1). + ([internal MR 3208](https://gitlab.khronos.org/openxr/openxr/merge_requests/3208), + [internal issue 2149](https://gitlab.khronos.org/openxr/openxr/issues/2149)) + - New test: Verify correct handling of all interaction profile paths and their + input component paths (accept vs reject suggested binding), in the "default" + configuration of the instance, using generated data from the XML. + ([internal MR 3224](https://gitlab.khronos.org/openxr/openxr/merge_requests/3224), + [internal issue 2063](https://gitlab.khronos.org/openxr/openxr/issues/2063), + [internal MR 3306](https://gitlab.khronos.org/openxr/openxr/merge_requests/3306), + [internal MR 3318](https://gitlab.khronos.org/openxr/openxr/merge_requests/3318), + [internal MR 3321](https://gitlab.khronos.org/openxr/openxr/merge_requests/3321)) + - New test: Created ProjectionDepth interactive test to visually verify behavior + of `XR_FB_composition_layer_depth_test` extension. + ([internal MR 3229](https://gitlab.khronos.org/openxr/openxr/merge_requests/3229)) + - New test: Automated and interactive tests for the "stereo with foveated inset" + view configuration type (promoted to core OpenXR 1.1), as well as its extension + predecessor `XR_VARJO_quad_views`. + ([internal MR 3241](https://gitlab.khronos.org/openxr/openxr/merge_requests/3241), + [internal issue 2152](https://gitlab.khronos.org/openxr/openxr/issues/2152), + [internal MR 3310](https://gitlab.khronos.org/openxr/openxr/merge_requests/3310), + [internal MR 3318](https://gitlab.khronos.org/openxr/openxr/merge_requests/3318)) + - New test: Additional test for grip_surface pose identifier (promoted to core + OpenXR 1.1), as well as extension `XR_EXT_palm_pose`. + ([internal MR 3245](https://gitlab.khronos.org/openxr/openxr/merge_requests/3245), + [internal issue 2151](https://gitlab.khronos.org/openxr/openxr/issues/2151), + [internal MR 3318](https://gitlab.khronos.org/openxr/openxr/merge_requests/3318), + [internal MR 3328](https://gitlab.khronos.org/openxr/openxr/merge_requests/3328)) + - New test: Created non-interactive test for `XR_FB_space_warp` extension. + ([internal MR 3278](https://gitlab.khronos.org/openxr/openxr/merge_requests/3278)) + ## OpenXR CTS 1.0.34.0 (2024-02-29) - Conformance Tests diff --git a/README.md b/README.md index f746bb11..45dfcbd0 100644 --- a/README.md +++ b/README.md @@ -219,9 +219,9 @@ those intents. Samples translated include: adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[actions][interactive],-I,khr/simple_controller" -e apiVersion 1.0 -e xmlFilename interactive_action_simple_controller_1_0.xml adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[actions][interactive],-I,microsoft/motion_controller" -e apiVersion 1.0 -e xmlFilename interactive_action_microsoft_motion_controller_1_0.xml adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[actions][interactive],-I,oculus/touch_controller" -e apiVersion 1.0 -e xmlFilename interactive_action_oculus_touch_controller_1_0.xml - adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[gamepad],-I,htc/vive_controller" -e apiVersion 1.0 -e xmlFilename interactive_action_htc_vive_controller_1_0.xml + adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[actions][interactive],-I,htc/vive_controller" -e apiVersion 1.0 -e xmlFilename interactive_action_htc_vive_controller_1_0.xml - adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[actions][interactive],-I,microsoft/xbox_controller" -e apiVersion 1.0 -e xmlFilename interactive_action_microsoft_xbox_controller_1_0.xml + adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[gamepad],-I,microsoft/xbox_controller" -e apiVersion 1.0 -e xmlFilename interactive_action_microsoft_xbox_controller_1_0.xml Example for OpenXR 1.1: @@ -238,9 +238,9 @@ those intents. Samples translated include: adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[actions][interactive],-I,khr/simple_controller" -e apiVersion 1.1 -e xmlFilename interactive_action_simple_controller_1_1.xml adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[actions][interactive],-I,microsoft/motion_controller" -e apiVersion 1.1 -e xmlFilename interactive_action_microsoft_motion_controller_1_1.xml adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[actions][interactive],-I,oculus/touch_controller" -e apiVersion 1.1 -e xmlFilename interactive_action_oculus_touch_controller_1_1.xml - adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[gamepad],-I,htc/vive_controller" -e apiVersion 1.1 -e xmlFilename interactive_action_htc_vive_controller_1_1.xml + adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[actions][interactive],-I,htc/vive_controller" -e apiVersion 1.1 -e xmlFilename interactive_action_htc_vive_controller_1_1.xml - adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[actions][interactive],-I,microsoft/xbox_controller" -e apiVersion 1.1 -e xmlFilename interactive_action_microsoft_xbox_controller_1_1.xml + adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[gamepad],-I,microsoft/xbox_controller" -e apiVersion 1.1 -e xmlFilename interactive_action_microsoft_xbox_controller_1_1.xml If you need to specify a different environment blend mode than `XR_ENVIRONMENT_BLEND_MODE_OPAQUE`, pass something like the following diff --git a/changes/conformance/mr.2992.gl.md b/changes/conformance/mr.2992.gl.md deleted file mode 100644 index d4176f9c..00000000 --- a/changes/conformance/mr.2992.gl.md +++ /dev/null @@ -1 +0,0 @@ -Improvement: Update Android compile SDK version (to 33), NDK version (to 23.2), and build tools version (to 34.0.0). diff --git a/changes/conformance/mr.3039.gl.md b/changes/conformance/mr.3039.gl.md deleted file mode 100644 index e0601176..00000000 --- a/changes/conformance/mr.3039.gl.md +++ /dev/null @@ -1 +0,0 @@ -Improvement: Reduce duplication of environment variable getters and setters. diff --git a/changes/conformance/mr.3154.gl.md b/changes/conformance/mr.3154.gl.md deleted file mode 100644 index f23263d0..00000000 --- a/changes/conformance/mr.3154.gl.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -- issue.2150.gl -- mr.3318.gl ---- -- New test: Automated test of core OpenXR 1.1 feature `LOCAL_FLOOR` reference space. -- New test: Interactive test of `LOCAL_FLOOR` reference space (in both extension and promoted to core). -- Improvement: Enhancements to existing test of `XR_EXT_local_floor`. diff --git a/changes/conformance/mr.3208.gl.md b/changes/conformance/mr.3208.gl.md deleted file mode 100644 index 33f51fa9..00000000 --- a/changes/conformance/mr.3208.gl.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -- issue.2149.gl ---- -New test: Test for `xrLocateSpacesKHR` (from `XR_KHR_locate_spaces`) and `xrLocateSpaces` (promoted to core OpenXR 1.1). diff --git a/changes/conformance/mr.3224.gl.md b/changes/conformance/mr.3224.gl.md deleted file mode 100644 index bcb6e19a..00000000 --- a/changes/conformance/mr.3224.gl.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -- issue.2063.gl -- mr.3306.gl -- mr.3318.gl ---- -- New test: Verify correct handling of all interaction profile paths and their input component paths (accept vs reject suggested binding), in the "default" configuration of the instance, using generated data from the XML. -- Improvement: Use generated data from the XML in existing action tests rather than hardcoded tables. -- Improvement: Automatically enabled extension(s) needed for the interaction profile specified on the command line. diff --git a/changes/conformance/mr.3229.gl.md b/changes/conformance/mr.3229.gl.md deleted file mode 100644 index 15288014..00000000 --- a/changes/conformance/mr.3229.gl.md +++ /dev/null @@ -1 +0,0 @@ -New test: Created ProjectionDepth interactive test to visually verify behavior of `XR_FB_composition_layer_depth_test` extension. diff --git a/changes/conformance/mr.3232.gl.md b/changes/conformance/mr.3232.gl.md deleted file mode 100644 index 07728e78..00000000 --- a/changes/conformance/mr.3232.gl.md +++ /dev/null @@ -1 +0,0 @@ -Fix: In multithreading test, only verify written portion of string buffer is UTF-8. diff --git a/changes/conformance/mr.3233.gl.md b/changes/conformance/mr.3233.gl.md deleted file mode 100644 index f2138b26..00000000 --- a/changes/conformance/mr.3233.gl.md +++ /dev/null @@ -1 +0,0 @@ -Fix: Increase `eps` for hand-tracking conformance tests. diff --git a/changes/conformance/mr.3241.gl.md b/changes/conformance/mr.3241.gl.md deleted file mode 100644 index 0ab592a7..00000000 --- a/changes/conformance/mr.3241.gl.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -- issue.2152.gl -- mr.3310.gl -- mr.3318.gl ---- -New test: Automated and interactive tests for the "stereo with foveated inset" view configuration type (promoted to core OpenXR 1.1), as well as its extension predecessor `XR_VARJO_quad_views`. diff --git a/changes/conformance/mr.3245.gl.md b/changes/conformance/mr.3245.gl.md deleted file mode 100644 index 810f9ab8..00000000 --- a/changes/conformance/mr.3245.gl.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -- issue.2151.gl -- mr.3318.gl ---- -- New test: Automated test for grip_surface pose identifier (promoted to core OpenXR 1.1), as well as extension `XR_EXT_palm_pose`. diff --git a/changes/conformance/mr.3257.gl.md b/changes/conformance/mr.3257.gl.md deleted file mode 100644 index f97b2604..00000000 --- a/changes/conformance/mr.3257.gl.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -- mr.3257.gl -- mr.3273.gl -- mr.3208.gl -- mr.3241.gl ---- -Improvement: Code cleanup. diff --git a/changes/conformance/mr.3258.gl.md b/changes/conformance/mr.3258.gl.md deleted file mode 100644 index 753f244c..00000000 --- a/changes/conformance/mr.3258.gl.md +++ /dev/null @@ -1 +0,0 @@ -Improvement: Allow `VK_FORMAT_R8G8_SRGB` in swapchains test diff --git a/changes/conformance/mr.3274.gl.md b/changes/conformance/mr.3274.gl.md deleted file mode 100644 index 594e9215..00000000 --- a/changes/conformance/mr.3274.gl.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -- issue.2205.gl -- mr.3296.gl -- mr.3297.gl -- issue.2236.gl -- mr.3298.gl -- mr.3318.gl ---- -- Improvement: Support specifying API version (1.0 or 1.1) - defaults to 1.1. diff --git a/changes/conformance/mr.3275.gl.md b/changes/conformance/mr.3275.gl.md deleted file mode 100644 index c304ae05..00000000 --- a/changes/conformance/mr.3275.gl.md +++ /dev/null @@ -1,2 +0,0 @@ -- Fix: Remove invalid interpretation of `XrInstanceProperties::runtimeVersion`. -- Improvement: Use spec-provided constants for inspecting enums for core vs extension origination. diff --git a/changes/conformance/mr.3302.gl.md b/changes/conformance/mr.3302.gl.md deleted file mode 100644 index ddfa23ec..00000000 --- a/changes/conformance/mr.3302.gl.md +++ /dev/null @@ -1 +0,0 @@ -Fix: Correct typo in CLI help text. diff --git a/src/conformance/conformance_test/readme.md b/src/conformance/conformance_test/readme.md index f746bb11..45dfcbd0 100644 --- a/src/conformance/conformance_test/readme.md +++ b/src/conformance/conformance_test/readme.md @@ -219,9 +219,9 @@ those intents. Samples translated include: adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[actions][interactive],-I,khr/simple_controller" -e apiVersion 1.0 -e xmlFilename interactive_action_simple_controller_1_0.xml adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[actions][interactive],-I,microsoft/motion_controller" -e apiVersion 1.0 -e xmlFilename interactive_action_microsoft_motion_controller_1_0.xml adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[actions][interactive],-I,oculus/touch_controller" -e apiVersion 1.0 -e xmlFilename interactive_action_oculus_touch_controller_1_0.xml - adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[gamepad],-I,htc/vive_controller" -e apiVersion 1.0 -e xmlFilename interactive_action_htc_vive_controller_1_0.xml + adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[actions][interactive],-I,htc/vive_controller" -e apiVersion 1.0 -e xmlFilename interactive_action_htc_vive_controller_1_0.xml - adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[actions][interactive],-I,microsoft/xbox_controller" -e apiVersion 1.0 -e xmlFilename interactive_action_microsoft_xbox_controller_1_0.xml + adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[gamepad],-I,microsoft/xbox_controller" -e apiVersion 1.0 -e xmlFilename interactive_action_microsoft_xbox_controller_1_0.xml Example for OpenXR 1.1: @@ -238,9 +238,9 @@ those intents. Samples translated include: adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[actions][interactive],-I,khr/simple_controller" -e apiVersion 1.1 -e xmlFilename interactive_action_simple_controller_1_1.xml adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[actions][interactive],-I,microsoft/motion_controller" -e apiVersion 1.1 -e xmlFilename interactive_action_microsoft_motion_controller_1_1.xml adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[actions][interactive],-I,oculus/touch_controller" -e apiVersion 1.1 -e xmlFilename interactive_action_oculus_touch_controller_1_1.xml - adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[gamepad],-I,htc/vive_controller" -e apiVersion 1.1 -e xmlFilename interactive_action_htc_vive_controller_1_1.xml + adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[actions][interactive],-I,htc/vive_controller" -e apiVersion 1.1 -e xmlFilename interactive_action_htc_vive_controller_1_1.xml - adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[actions][interactive],-I,microsoft/xbox_controller" -e apiVersion 1.1 -e xmlFilename interactive_action_microsoft_xbox_controller_1_1.xml + adb shell am start-activity -S -n org.khronos.openxr.cts/android.app.NativeActivity --esa args "[gamepad],-I,microsoft/xbox_controller" -e apiVersion 1.1 -e xmlFilename interactive_action_microsoft_xbox_controller_1_1.xml If you need to specify a different environment blend mode than `XR_ENVIRONMENT_BLEND_MODE_OPAQUE`, pass something like the following diff --git a/src/conformance/conformance_test/test_XR_EXT_local_floor.cpp b/src/conformance/conformance_test/test_XR_EXT_local_floor.cpp index 1e1ef6f7..799fe897 100644 --- a/src/conformance/conformance_test/test_XR_EXT_local_floor.cpp +++ b/src/conformance/conformance_test/test_XR_EXT_local_floor.cpp @@ -306,12 +306,12 @@ namespace Conformance } } } - TEST_CASE("XR_EXT_local_floor", "") + TEST_CASE("XR_EXT_local_floor", "[XR_EXT_local_floor]") { SharedLocalFloorAutomated(kExtensionRequirements); } - TEST_CASE("XR_VERSION_1_1-local_floor", "") + TEST_CASE("XR_VERSION_1_1-local_floor", "[XR_VERSION_1_1]") { SharedLocalFloorAutomated(kPromotedCoreRequirements); } diff --git a/src/conformance/conformance_test/test_XR_EXT_palm_pose.cpp b/src/conformance/conformance_test/test_XR_EXT_palm_pose.cpp index 12f8686d..14e4c267 100644 --- a/src/conformance/conformance_test/test_XR_EXT_palm_pose.cpp +++ b/src/conformance/conformance_test/test_XR_EXT_palm_pose.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -600,142 +601,178 @@ namespace Conformance REQUIRE_RESULT(xrSyncActions(session, &syncInfo), XR_SUCCESS); - // Test keeps running until all grip surface spaces that are tested have VALID location flags. - bool handTested[2] = {false, false}; - while ((!handTested[0] && globalData.leftHandUnderTest) || (!handTested[1] && globalData.rightHandUnderTest)) { - for (uint32_t i = 0; i < 2; i++) { - if ((i == 0 && !globalData.leftHandUnderTest) || (i == 1 && !globalData.rightHandUnderTest)) { - continue; - } + enum class TestState + { + Untested, + Inactive, + Invalid, + Passed, + }; - XrActionStateGetInfo getInfo{XR_TYPE_ACTION_STATE_GET_INFO}; - getInfo.action = gripPoseAction; - getInfo.subactionPath = handPaths[i]; + // Test keeps running until all grip surface spaces that are tested have VALID location flags. + TestState maxTestStates[2] = {TestState::Untested, TestState::Untested}; + bool testPassed = WaitUntilPredicateWithTimeout( + [&]() -> bool { + frameIterator.SubmitFrame(); + REQUIRE_RESULT_SUCCEEDED(xrSyncActions(session, &syncInfo)); + + for (uint32_t i = 0; i < 2; i++) { + if ((i == 0 && !globalData.leftHandUnderTest) || (i == 1 && !globalData.rightHandUnderTest)) { + continue; + } - XrActionStatePose gripState{XR_TYPE_ACTION_STATE_POSE}; - REQUIRE_RESULT(xrGetActionStatePose(session, &getInfo, &gripState), XR_SUCCESS); + XrActionStateGetInfo getInfo{XR_TYPE_ACTION_STATE_GET_INFO}; + getInfo.action = gripPoseAction; + getInfo.subactionPath = handPaths[i]; - getInfo.action = gripSurfacePoseAction; + XrActionStatePose gripState{XR_TYPE_ACTION_STATE_POSE}; + REQUIRE_RESULT(xrGetActionStatePose(session, &getInfo, &gripState), XR_SUCCESS); - XrActionStatePose gripSurfaceState{XR_TYPE_ACTION_STATE_POSE}; - REQUIRE_RESULT(xrGetActionStatePose(session, &getInfo, &gripSurfaceState), XR_SUCCESS); + getInfo.action = gripSurfacePoseAction; - // grip pose is not actually required to be provided (e.g. wrist controller) - if (!gripState.isActive && gripSurfaceState.isActive) { - SKIP( - "Grip Surface pose without Grip pose detected. Skipping pose relation tests between Grip Surface and Grip pose"); - } + XrActionStatePose gripSurfaceState{XR_TYPE_ACTION_STATE_POSE}; + REQUIRE_RESULT(xrGetActionStatePose(session, &getInfo, &gripSurfaceState), XR_SUCCESS); - if (!gripState.isActive && !gripSurfaceState.isActive) { - continue; - } + // grip pose is not actually required to be provided (e.g. wrist controller) + if (!gripState.isActive && gripSurfaceState.isActive) { + SKIP( + "Grip Surface pose without Grip pose detected. Skipping pose relation tests between Grip Surface and Grip pose"); + } - XrSpaceVelocity gripVelocity{XR_TYPE_SPACE_VELOCITY}; - XrSpaceLocation gripLocation{XR_TYPE_SPACE_LOCATION, &gripVelocity}; - XRC_CHECK_THROW_XRCMD( - xrLocateSpace(gripPoseSpace[i], localSpace, frameIterator.frameState.predictedDisplayTime, &gripLocation)); + if (!gripState.isActive || !gripSurfaceState.isActive) { + maxTestStates[i] = std::max(maxTestStates[i], TestState::Inactive); + continue; + } - // VALID is usually enough here because the palm pose / grip surface is a usually a static offset that should be available for non TRACKED grip pose. - if (!(gripLocation.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT && - gripLocation.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT)) { - continue; - } + XrSpaceVelocity gripVelocity{XR_TYPE_SPACE_VELOCITY}; + XrSpaceLocation gripLocation{XR_TYPE_SPACE_LOCATION, &gripVelocity}; + XRC_CHECK_THROW_XRCMD( + xrLocateSpace(gripPoseSpace[i], localSpace, frameIterator.frameState.predictedDisplayTime, &gripLocation)); - // Locate grip surface space in grip space to make checks simpler - XrSpaceVelocity gripSurfaceVelocity{XR_TYPE_SPACE_VELOCITY}; - XrSpaceLocation gripSurfaceLocation{XR_TYPE_SPACE_LOCATION, &gripSurfaceVelocity}; - XRC_CHECK_THROW_XRCMD(xrLocateSpace(gripSurfacePoseSpace[i], gripPoseSpace[i], - frameIterator.frameState.predictedDisplayTime, &gripSurfaceLocation)); + // VALID is usually enough here because the palm pose / grip surface is a usually a static offset that should be available for non TRACKED grip pose. + if (!(gripLocation.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT && + gripLocation.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT)) { + maxTestStates[i] = std::max(maxTestStates[i], TestState::Invalid); + continue; + } - // grip is valid, which means grip surface should be valid too as a static offset - REQUIRE((gripSurfaceLocation.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT && - gripSurfaceLocation.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT)); + // Locate grip surface space in grip space to make checks simpler + XrSpaceVelocity gripSurfaceVelocity{XR_TYPE_SPACE_VELOCITY}; + XrSpaceLocation gripSurfaceLocation{XR_TYPE_SPACE_LOCATION, &gripSurfaceVelocity}; + XRC_CHECK_THROW_XRCMD(xrLocateSpace(gripSurfacePoseSpace[i], gripPoseSpace[i], + frameIterator.frameState.predictedDisplayTime, &gripSurfaceLocation)); - const float epsilon = 0.0001f; - XrVector3f position = gripSurfaceLocation.pose.position; + // grip is valid, which means grip surface should be valid too as a static offset + REQUIRE((gripSurfaceLocation.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT && + gripSurfaceLocation.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT)); - // The following test test the offsets of grip surface to grip for common controllers. - // Special configurations such as "fist grips", backhanded grips, push daggers, pens, etc. will require modifications to these tests or a waiver. + const float epsilon = 0.0001f; + XrVector3f position = gripSurfaceLocation.pose.position; - if (i == 0) { - // For tracked hands: grip surface may be arbitrarily close to grip pose - // For controllers: grip surface must be to the left of the grip pose, which is inside the controller. - REQUIRE(position.x <= epsilon); - } - else { - // For tracked hands: grip surface may be arbitrarily close to grip pose - // For controllers: grip surface must be to the right of the grip pose, which is inside the controller. - REQUIRE(position.x >= -epsilon); - } + // The following test test the offsets of grip surface to grip for common controllers. + // Special configurations such as "fist grips", backhanded grips, push daggers, pens, etc. will require modifications to these tests or a waiver. - { - // Grip: +X axis: When you completely open your hand to form a flat 5-finger pose, the ray that is normal to the user's palm (away from the palm in the left hand, into the palm in the right hand). - // Grip Surface: +X axis: When a user is holding the controller and straightens their index fingers pointing forward, the ray that is normal (perpendicular) to the user's palm (away from the palm in the left hand, into the palm in the right hand). - // In other words, the x axis is normal to the palm for both poses and should "roughly" point in the same direction (away from the palm in the left hand, into the palm in the right hand). - XrVector3f xAxis = {1, 0, 0}; - XrVector3f gripSurfaceXDirection{}; - XrQuaternionf_RotateVector3f(&gripSurfaceXDirection, &gripSurfaceLocation.pose.orientation, &xAxis); - double xAngleDiff = angleDeg(xAxis, gripSurfaceXDirection); - REQUIRE(xAngleDiff < 45.0f); - } + if (i == 0) { + // For tracked hands: grip surface may be arbitrarily close to grip pose + // For controllers: grip surface must be to the left of the grip pose, which is inside the controller. + REQUIRE(position.x <= epsilon); + } + else { + // For tracked hands: grip surface may be arbitrarily close to grip pose + // For controllers: grip surface must be to the right of the grip pose, which is inside the controller. + REQUIRE(position.x >= -epsilon); + } - { - // Grip: -Z axis: When you close your hand partially (as if holding the controller), the ray that goes through the center of the tube formed by your non-thumb fingers, in the direction of little finger to thumb. - // Grip Surface: -Z axis: When a user is holding the controller and straightens their index finger, the ray that is parallel to their finger's pointing direction. - // In other words, the wrist (according to the grip surface pose) should not be tilted more than 90° away from the grip pose's z axis, i.e. the controller handle. - XrVector3f zAxis = {0, 0, 1}; - XrVector3f gripSurfaceZDirection{}; - XrQuaternionf_RotateVector3f(&gripSurfaceZDirection, &gripSurfaceLocation.pose.orientation, &zAxis); - double zAngleDiff = angleDeg(zAxis, gripSurfaceZDirection); - REQUIRE(std::abs(zAngleDiff) < 90.0f); - } + { + // Grip: +X axis: When you completely open your hand to form a flat 5-finger pose, the ray that is normal to the user's palm (away from the palm in the left hand, into the palm in the right hand). + // Grip Surface: +X axis: When a user is holding the controller and straightens their index fingers pointing forward, the ray that is normal (perpendicular) to the user's palm (away from the palm in the left hand, into the palm in the right hand). + // In other words, the x axis is normal to the palm for both poses and should "roughly" point in the same direction (away from the palm in the left hand, into the palm in the right hand). + XrVector3f xAxis = {1, 0, 0}; + XrVector3f gripSurfaceXDirection{}; + XrQuaternionf_RotateVector3f(&gripSurfaceXDirection, &gripSurfaceLocation.pose.orientation, &xAxis); + double xAngleDiff = angleDeg(xAxis, gripSurfaceXDirection); + REQUIRE(xAngleDiff < 45.0f); + } - { - // Grip: +Y axis: orthogonal to +Z and +X using the right-hand rule. - // Grip Surface: +Y axis: orthogonal to +Z and +X using the right-hand rule. - // When the hand grips a cylindrical controller handle, the grip surface y axis pointing from the palm center "up" to the thumb should align roughly with the controller handle's forward (z = -1) axis. - XrVector3f yAxis = {0, 1, 0}; - XrVector3f zMAxis = {0, 0, -1}; - XrVector3f gripSurfaceYDirection{}; - XrQuaternionf_RotateVector3f(&gripSurfaceYDirection, &gripSurfaceLocation.pose.orientation, &yAxis); - double yAngleDiff = angleDeg(zMAxis, gripSurfaceYDirection); - REQUIRE(std::abs(yAngleDiff) < 45.0f); - } + { + // Grip: -Z axis: When you close your hand partially (as if holding the controller), the ray that goes through the center of the tube formed by your non-thumb fingers, in the direction of little finger to thumb. + // Grip Surface: -Z axis: When a user is holding the controller and straightens their index finger, the ray that is parallel to their finger's pointing direction. + // In other words, the wrist (according to the grip surface pose) should not be tilted more than 90° away from the grip pose's z axis, i.e. the controller handle. + XrVector3f zAxis = {0, 0, 1}; + XrVector3f gripSurfaceZDirection{}; + XrQuaternionf_RotateVector3f(&gripSurfaceZDirection, &gripSurfaceLocation.pose.orientation, &zAxis); + double zAngleDiff = angleDeg(zAxis, gripSurfaceZDirection); + REQUIRE(std::abs(zAngleDiff) < 90.0f); + } - if (i == 0) { - // Test that the z axis (direction from the palm center to the wrist) of grip surface points "to the left" in grip space. - // This should be true for all usual controllers. If this is not true for your controller, you may need to adapt or discard this test. - XrVector3f zAxis = {0, 0, 1}; - XrVector3f gripSurfaceZDirection{}; - XrQuaternionf_RotateVector3f(&gripSurfaceZDirection, &gripSurfaceLocation.pose.orientation, &zAxis); - REQUIRE(gripSurfaceZDirection.x < 0); - } - else { - // Test that the z axis (direction from the palm center to the wrist) of grip surface points "to the right" in grip space. - // This should be true for all usual controllers. If this is not true for your controller, you may need to adapt or discard this test. - XrVector3f zAxis = {0, 0, 1}; - XrVector3f gripSurfaceZDirection{}; - XrQuaternionf_RotateVector3f(&gripSurfaceZDirection, &gripSurfaceLocation.pose.orientation, &zAxis); - REQUIRE(gripSurfaceZDirection.x > 0); - } + { + // Grip: +Y axis: orthogonal to +Z and +X using the right-hand rule. + // Grip Surface: +Y axis: orthogonal to +Z and +X using the right-hand rule. + // When the hand grips a cylindrical controller handle, the grip surface y axis pointing from the palm center "up" to the thumb should align roughly with the controller handle's forward (z = -1) axis. + XrVector3f yAxis = {0, 1, 0}; + XrVector3f zMAxis = {0, 0, -1}; + XrVector3f gripSurfaceYDirection{}; + XrQuaternionf_RotateVector3f(&gripSurfaceYDirection, &gripSurfaceLocation.pose.orientation, &yAxis); + double yAngleDiff = angleDeg(zMAxis, gripSurfaceYDirection); + REQUIRE(std::abs(yAngleDiff) < 45.0f); + } - { - // Test that the z axis (direction from the palm center to the wrist) of grip surface points "upwards" in grip space, meaning that the controller cylinder is grabbed with the wrist angled towards the user and not somehow away. - // This should be true for all usual controllers. If this is not true for your controller, you may need to adapt or discard this test. - XrVector3f zAxis = {0, 0, 1}; - XrVector3f gripSurfaceZDirection{}; - XrQuaternionf_RotateVector3f(&gripSurfaceZDirection, &gripSurfaceLocation.pose.orientation, &zAxis); - REQUIRE(gripSurfaceZDirection.y > 0); - } + if (i == 0) { + // Test that the z axis (direction from the palm center to the wrist) of grip surface points "to the left" in grip space. + // This should be true for all usual controllers. If this is not true for your controller, you may need to adapt or discard this test. + XrVector3f zAxis = {0, 0, 1}; + XrVector3f gripSurfaceZDirection{}; + XrQuaternionf_RotateVector3f(&gripSurfaceZDirection, &gripSurfaceLocation.pose.orientation, &zAxis); + REQUIRE(gripSurfaceZDirection.x < 0); + } + else { + // Test that the z axis (direction from the palm center to the wrist) of grip surface points "to the right" in grip space. + // This should be true for all usual controllers. If this is not true for your controller, you may need to adapt or discard this test. + XrVector3f zAxis = {0, 0, 1}; + XrVector3f gripSurfaceZDirection{}; + XrQuaternionf_RotateVector3f(&gripSurfaceZDirection, &gripSurfaceLocation.pose.orientation, &zAxis); + REQUIRE(gripSurfaceZDirection.x > 0); + } - handTested[i] = true; - } + { + // Test that the z axis (direction from the palm center to the wrist) of grip surface points "upwards" in grip space, meaning that the controller cylinder is grabbed with the wrist angled towards the user and not somehow away. + // This should be true for all usual controllers. If this is not true for your controller, you may need to adapt or discard this test. + XrVector3f zAxis = {0, 0, 1}; + XrVector3f gripSurfaceZDirection{}; + XrQuaternionf_RotateVector3f(&gripSurfaceZDirection, &gripSurfaceLocation.pose.orientation, &zAxis); + REQUIRE(gripSurfaceZDirection.y > 0); + } - SleepMs(50); - } + maxTestStates[i] = std::max(maxTestStates[i], TestState::Passed); + } + return (maxTestStates[0] == TestState::Passed || !globalData.leftHandUnderTest) && + (maxTestStates[1] == TestState::Passed || !globalData.rightHandUnderTest); + }, + 30s, 50ms); + auto testStateMessage = [](TestState state, bool testExtension) -> std::string { + switch (state) { + case TestState::Untested: + return "was not tested"; + case TestState::Inactive: + return std::string(testExtension ? "palm pose" : "grip surface") + + " was never observed as active at the same time as grip"; + case TestState::Invalid: + return "grip was never observed with a fully valid pose"; + case TestState::Passed: + return "passed"; + default: + FAIL("unexpected enum value " << static_cast(state)); + return "test state was [unexpected enum value]"; + }; + }; + INFO("left hand " << testStateMessage(maxTestStates[0], testExtension)); + INFO("right hand " << testStateMessage(maxTestStates[1], testExtension)); + REQUIRE(testPassed); } } // namespace + // TODO make these use the specified interaction profile rather than simple controller? + // TODO is [scenario] the best sub-category of [interactive] for this test? TEST_CASE("XR_EXT_palm_pose", "[XR_EXT_palm_pose][scenario][interactive][no_auto]") { SharedGripSurface(kExtensionRequirements); @@ -747,12 +784,16 @@ namespace Conformance SharedGripSurface(kPromotedCoreRequirements); } - TEST_CASE("XR_EXT_palm_pose-noninteractive", "[XR_EXT_palm_pose]") + // These two "objective" tests automatically evaluate their results, but because they require controllers, + // they are marked as "interactive", and they currently lack conformance automation support + + // TODO make these use the specified interaction profile rather than simple controller? + TEST_CASE("XR_EXT_palm_pose-objective", "[XR_EXT_palm_pose][actions][interactive][no_auto]") { SharedGripSurfaceAutomated(kExtensionRequirements); } - TEST_CASE("GripSurface-noninteractive", "[XR_VERSION_1_1]") + TEST_CASE("GripSurface-objective", "[XR_VERSION_1_1][actions][interactive][no_auto]") { SharedGripSurfaceAutomated(kPromotedCoreRequirements); } diff --git a/src/conformance/conformance_test/test_XR_FB_space_warp.cpp b/src/conformance/conformance_test/test_XR_FB_space_warp.cpp new file mode 100644 index 00000000..11d9e275 --- /dev/null +++ b/src/conformance/conformance_test/test_XR_FB_space_warp.cpp @@ -0,0 +1,172 @@ +// Copyright (c) 2019-2024, The Khronos Group Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// 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 "conformance_framework.h" +#include "conformance_utils.h" +#include "utilities/bitmask_generator.h" +#include "utilities/xrduration_literals.h" + +#include +#include + +#include +#include +#include + +namespace Conformance +{ + TEST_CASE("XR_FB_space_warp", "[XR_FB_space_warp]") + { + GlobalData& globalData = GetGlobalData(); + if (!globalData.IsInstanceExtensionSupported(XR_FB_SPACE_WARP_EXTENSION_NAME)) { + SKIP(XR_FB_SPACE_WARP_EXTENSION_NAME " not supported"); + } + + if (!globalData.IsUsingGraphicsPlugin()) { + SKIP("Test run not using graphics plugin"); + } + + auto graphicsPlugin = globalData.GetGraphicsPlugin(); + + AutoBasicInstance instance({XR_FB_SPACE_WARP_EXTENSION_NAME}); + AutoBasicSession session(AutoBasicSession::createSession | AutoBasicSession::beginSession | AutoBasicSession::createSwapchains | + AutoBasicSession::createSpaces, + instance); + + XrSystemSpaceWarpPropertiesFB spaceWarpProperties = {XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB}; + + XrSystemProperties systemProperties = {XR_TYPE_SYSTEM_PROPERTIES}; + systemProperties.next = &spaceWarpProperties; + REQUIRE(xrGetSystemProperties(instance, session.GetSystemId(), &systemProperties) == XR_SUCCESS); + + FrameIterator frameIterator(&session); + frameIterator.RunToSessionState(XR_SESSION_STATE_FOCUSED); + + // At this point we have a session ready for us to generate custom frames for. + // The current XrSessionState is XR_SESSION_STATE_FOCUSED. + + XrExtent2Di mvSwapchainExtent{(int32_t)spaceWarpProperties.recommendedMotionVectorImageRectWidth, + (int32_t)spaceWarpProperties.recommendedMotionVectorImageRectHeight}; + + const uint32_t viewCount = frameIterator.compositionLayerProjection.viewCount; + + // Create motion vector and depth buffer swapchains. + std::vector motionVectorSwapchains(viewCount); + for (XrSwapchain& motionVectorSwapchain : motionVectorSwapchains) { + REQUIRE(CreateMotionVectorSwapchain(session.GetSession(), graphicsPlugin.get(), &motionVectorSwapchain, &mvSwapchainExtent) == + XR_SUCCESS); + } + + std::vector depthSwapchains(viewCount); + for (XrSwapchain& depthSwapchain : depthSwapchains) { + REQUIRE(CreateDepthSwapchain(session.GetSession(), graphicsPlugin.get(), &depthSwapchain, &mvSwapchainExtent) == XR_SUCCESS); + } + + auto&& layerFlagsGenerator = bitmaskGeneratorIncluding0({XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT, + XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT, + XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT}); + while (layerFlagsGenerator.next()) { + // minDepth and maxDepth are the range of depth values the depthSwapchain could have, + // in the range of [0.0,1.0]. This is akin to min and max values of OpenGL's glDepthRange, + // but with the requirement here that maxDepth >= minDepth. + // nearZ is the positive distance in meters of the minDepth value in the depth swapchain. + // Apps may use a nearZ that is greater than farZ to indicate depth values + // are reversed. nearZ can be infinite. + // farZ is the positive distance in meters of the maxDepth value in the depth swapchain. + // farZ can be infinite. Apps must not use the same value as nearZ. + + struct SpaceWarpVaryingInfo + { // This is a subset of XrCompositionLayerSpaceWarpInfoFB. + uint64_t layerFlags; + float minDepth; + float maxDepth; + float nearZ; + float farZ; + }; + + constexpr float minimum_useful_z = 0.01f; + std::vector varyingInfoTestArray{ + SpaceWarpVaryingInfo{0, 0.0f, 1.0f, minimum_useful_z, 100.0f}, + SpaceWarpVaryingInfo{0, 0.5f, 0.6f, minimum_useful_z, 100.0f}, + SpaceWarpVaryingInfo{0, 0.0f, 1.0f, minimum_useful_z, std::numeric_limits::infinity()}, + SpaceWarpVaryingInfo{0, 0.0f, 1.0f, 100.0f, minimum_useful_z}, + SpaceWarpVaryingInfo{0, 0.0f, 1.0f, std::numeric_limits::infinity(), minimum_useful_z}, + SpaceWarpVaryingInfo{0, 0.0f, 1.0f, std::numeric_limits::max(), minimum_useful_z}, + SpaceWarpVaryingInfo{0, 0.0f, 1.0f, std::numeric_limits::max(), minimum_useful_z}, + SpaceWarpVaryingInfo{XR_COMPOSITION_LAYER_SPACE_WARP_INFO_FRAME_SKIP_BIT_FB, 0.0f, 1.0f, minimum_useful_z, 100.0f}, + SpaceWarpVaryingInfo{XR_COMPOSITION_LAYER_SPACE_WARP_INFO_FRAME_SKIP_BIT_FB, 0.5f, 0.6f, minimum_useful_z, 100.0f}, + SpaceWarpVaryingInfo{XR_COMPOSITION_LAYER_SPACE_WARP_INFO_FRAME_SKIP_BIT_FB, 0.0f, 1.0f, minimum_useful_z, + std::numeric_limits::infinity()}, + SpaceWarpVaryingInfo{XR_COMPOSITION_LAYER_SPACE_WARP_INFO_FRAME_SKIP_BIT_FB, 0.0f, 1.0f, 100.0f, minimum_useful_z}, + SpaceWarpVaryingInfo{XR_COMPOSITION_LAYER_SPACE_WARP_INFO_FRAME_SKIP_BIT_FB, 0.0f, 1.0f, + std::numeric_limits::infinity(), minimum_useful_z}, + SpaceWarpVaryingInfo{XR_COMPOSITION_LAYER_SPACE_WARP_INFO_FRAME_SKIP_BIT_FB, 0.0f, 1.0f, std::numeric_limits::max(), + minimum_useful_z}, + SpaceWarpVaryingInfo{XR_COMPOSITION_LAYER_SPACE_WARP_INFO_FRAME_SKIP_BIT_FB, 0.0f, 1.0f, std::numeric_limits::max(), + minimum_useful_z}}; + + for (const SpaceWarpVaryingInfo& varyingInfo : varyingInfoTestArray) { + REQUIRE(frameIterator.PrepareSubmitFrame() == FrameIterator::RunResult::Success); + + { + REQUIRE(CycleToNextSwapchainImage(motionVectorSwapchains.data(), 2, 3_xrSeconds) == XR_SUCCESS); + REQUIRE(CycleToNextSwapchainImage(depthSwapchains.data(), 2, 3_xrSeconds) == XR_SUCCESS); + } + + // Set up our XrCompositionLayerSpaceWarpInfoFB + XrCompositionLayerSpaceWarpInfoFB spaceWarpInfo{XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB}; + spaceWarpInfo.motionVectorSubImage.imageArrayIndex = 0; + spaceWarpInfo.motionVectorSubImage.imageRect = { + {0, 0}, + {(int32_t)mvSwapchainExtent.width, (int32_t)mvSwapchainExtent.height}, + }; + spaceWarpInfo.depthSubImage.imageArrayIndex = 0; + spaceWarpInfo.depthSubImage.imageRect = { + {0, 0}, + {(int32_t)mvSwapchainExtent.width, (int32_t)mvSwapchainExtent.height}, + }; + spaceWarpInfo.layerFlags = varyingInfo.layerFlags; + spaceWarpInfo.minDepth = varyingInfo.minDepth; + spaceWarpInfo.maxDepth = varyingInfo.maxDepth; + spaceWarpInfo.nearZ = varyingInfo.nearZ; + spaceWarpInfo.farZ = varyingInfo.farZ; + spaceWarpInfo.appSpaceDeltaPose = {}; + + std::vector spaceWarpInfos(viewCount, spaceWarpInfo); + for (size_t i = 0; i < viewCount; ++i) { + spaceWarpInfos[i].motionVectorSubImage.swapchain = motionVectorSwapchains[i]; + spaceWarpInfos[i].depthSubImage.swapchain = depthSwapchains[i]; + frameIterator.projectionViewVector[i].next = &spaceWarpInfos[i]; + } + + const XrCompositionLayerBaseHeader* headerPtrArray[1] = { + reinterpret_cast(&frameIterator.compositionLayerProjection)}; + frameIterator.frameEndInfo.layerCount = 1; + frameIterator.frameEndInfo.layers = headerPtrArray; + + // xrEndFrame requires the XR_FB_space_warp extension to be + // enabled or else it must return XR_ERROR_LAYER_INVALID. + XrResult result = xrEndFrame(session.GetSession(), &frameIterator.frameEndInfo); + CHECK(result == XR_SUCCESS); + } + } + + // Remove pointers to the now deleted spaceWarpInfos + for (size_t i = 0; i < viewCount; ++i) { + frameIterator.projectionViewVector[i].next = nullptr; + } + } +} // namespace Conformance diff --git a/src/conformance/conformance_test/test_actions.cpp b/src/conformance/conformance_test/test_actions.cpp index e39b118b..f4a8a93e 100644 --- a/src/conformance/conformance_test/test_actions.cpp +++ b/src/conformance/conformance_test/test_actions.cpp @@ -26,7 +26,7 @@ #include "utilities/bitmask_to_string.h" #include "utilities/event_reader.h" #include "utilities/types_and_constants.h" -#include "utilities/utils.h" +#include "utilities/string_utils.h" #include #include @@ -2033,16 +2033,25 @@ namespace Conformance "state query test action " + std::to_string(uniqueActionNameCounter)}; }; - auto prefixedByTopLevelPath = [&topLevelPathString](std::string binding) { - return (binding.length() > topLevelPathString.size()) && - (std::mismatch(topLevelPathString.begin(), topLevelPathString.end(), binding.begin()).first == - topLevelPathString.end()); + auto shouldExercisePath = [&ipMetadata](const InputSourcePathAvailData& inputSourceData) -> bool { + if (inputSourceData.systemOnly) { + return false; + } + if (strcmp(ipMetadata.InteractionProfileShortname, "oculus/touch_controller") == 0 && + ends_with(inputSourceData.Path, "/input/thumbrest/touch")) { + // Rift S and Quest 1 controllers lack thumbrests. + return false; + } + if (!SatisfiedByDefault(inputSourceData.Availability)) { + return false; + } + return true; }; auto InputSourceDataForTopLevelPath = [&]() { std::vector ret; for (const InputSourcePathAvailData& inputSourceData : ipMetadata.InputSourcePaths) { - if (!prefixedByTopLevelPath(inputSourceData.Path)) { + if (!starts_with(inputSourceData.Path, topLevelPathString)) { continue; } ret.push_back(inputSourceData); @@ -2056,10 +2065,7 @@ namespace Conformance if (type != inputSourceData.Type) { continue; } - if (inputSourceData.systemOnly) { - continue; - } - if (!SatisfiedByDefault(inputSourceData.Availability)) { + if (!shouldExercisePath(inputSourceData)) { continue; } @@ -2182,15 +2188,10 @@ namespace Conformance if (inputSourceData.Type != type) { continue; } - if (inputSourceData.systemOnly) { - continue; - } - if (!SatisfiedByDefault(inputSourceData.Availability)) { + if (!shouldExercisePath(inputSourceData)) { continue; } - auto prefixedByParentPath = - (std::string(inputSourceData.Path).length() > parentPath.size()) && - (std::mismatch(parentPath.begin(), parentPath.end(), inputSourceData.Path).first == parentPath.end()); + auto prefixedByParentPath = starts_with(inputSourceData.Path, parentPath); if (prefixedByParentPath) { return true; } @@ -2203,10 +2204,7 @@ namespace Conformance if (type != inputSourceData.Type) { continue; } - if (inputSourceData.systemOnly) { - continue; - } - if (!SatisfiedByDefault(inputSourceData.Availability)) { + if (!shouldExercisePath(inputSourceData)) { continue; } @@ -2266,10 +2264,7 @@ namespace Conformance if (type != inputSourceData.Type) { continue; } - if (inputSourceData.systemOnly) { - continue; - } - if (!SatisfiedByDefault(inputSourceData.Availability)) { + if (!shouldExercisePath(inputSourceData)) { continue; } diff --git a/src/conformance/framework/conformance_utils.cpp b/src/conformance/framework/conformance_utils.cpp index faf0afda..b0c65f19 100644 --- a/src/conformance/framework/conformance_utils.cpp +++ b/src/conformance/framework/conformance_utils.cpp @@ -1148,6 +1148,49 @@ namespace Conformance return result; } + // Encapsulates xrEnumerateSwapchainFormats/xrCreateSwapchain + XrResult CreateMotionVectorSwapchain(XrSession session, IGraphicsPlugin* graphicsPlugin, XrSwapchain* swapchain, + XrExtent2Di* widthHeight, uint32_t arraySize) + { + std::vector formatArray; + uint32_t countOutput; + XrResult result = xrEnumerateSwapchainFormats(session, 0, &countOutput, nullptr); + + if (result == XR_SUCCESS) { // This should succeed + if (widthHeight->width < 1) + widthHeight->width = 256; + if (widthHeight->height < 1) + widthHeight->height = 256; + + formatArray.resize(countOutput); + result = xrEnumerateSwapchainFormats(session, (uint32_t)formatArray.size(), &countOutput, formatArray.data()); + + if (result == XR_SUCCESS) { + XrSwapchainCreateInfo createInfo{XR_TYPE_SWAPCHAIN_CREATE_INFO}; + + XrSwapchainUsageFlags usageFlags = XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT; + if (graphicsPlugin->DescribeGraphics() != "OpenGL") { + // mutability exists in GL but isn't used in the conformance tests, so don't require it + usageFlags |= XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT; + } + + createInfo.faceCount = 1; + createInfo.createFlags = 0; // XR_SWAPCHAIN_CREATE_PROTECTED_CONTENT_BIT or XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT + createInfo.usageFlags = usageFlags; + createInfo.format = graphicsPlugin->SelectMotionVectorSwapchainFormat(formatArray.data(), formatArray.size()); + createInfo.sampleCount = 1; + createInfo.width = (uint32_t)widthHeight->width; + createInfo.height = (uint32_t)widthHeight->height; + createInfo.arraySize = arraySize; + createInfo.mipCount = 1; + + result = xrCreateSwapchain(session, &createInfo, swapchain); + } + } + + return result; + } + XrResult CycleToNextSwapchainImage(XrSwapchain* swapchainArray, size_t count, XrDuration timeoutNs) { XrResult result = XR_SUCCESS; diff --git a/src/conformance/framework/conformance_utils.h b/src/conformance/framework/conformance_utils.h index b2cf7c74..d883a74d 100644 --- a/src/conformance/framework/conformance_utils.h +++ b/src/conformance/framework/conformance_utils.h @@ -172,6 +172,10 @@ namespace Conformance XrResult CreateDepthSwapchain(XrSession session, IGraphicsPlugin* graphicsPlugin, XrSwapchain* swapchain, XrExtent2Di* widthHeight, uint32_t arraySize = 1); + /// Creates a motion vector swapchain for the given session and graphics plugin. + XrResult CreateMotionVectorSwapchain(XrSession session, IGraphicsPlugin* graphicsPlugin, XrSwapchain* swapchain, + XrExtent2Di* widthHeight, uint32_t arraySize = 1); + /// Executes xrAcquireSwapchainImage, xrWaitSwapchainImage, xrReleaseSwapchainImage, with no drawing. /// /// The contents of the swapchain images have no predictable content as a result of this. diff --git a/src/conformance/framework/graphics_plugin.h b/src/conformance/framework/graphics_plugin.h index 73b13fb6..9292a462 100644 --- a/src/conformance/framework/graphics_plugin.h +++ b/src/conformance/framework/graphics_plugin.h @@ -313,6 +313,9 @@ namespace Conformance /// Select the preferred swapchain format from the list of available formats. virtual int64_t SelectDepthSwapchainFormat(const int64_t* /*imageFormatArray*/, size_t /*count*/) const = 0; + /// Implementation must select a signed format with four components unless there are none with alpha. + virtual int64_t SelectMotionVectorSwapchainFormat(const int64_t* /*imageFormatArray*/, size_t /*count*/) const = 0; + /// Select the preferred swapchain format. virtual int64_t GetSRGBA8Format() const = 0; diff --git a/src/conformance/framework/graphics_plugin_d3d11.cpp b/src/conformance/framework/graphics_plugin_d3d11.cpp index e5ee4f5c..e20c4f61 100644 --- a/src/conformance/framework/graphics_plugin_d3d11.cpp +++ b/src/conformance/framework/graphics_plugin_d3d11.cpp @@ -193,6 +193,8 @@ namespace Conformance int64_t SelectDepthSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectMotionVectorSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + // Format required by RGBAImage type. int64_t GetSRGBA8Format() const override; @@ -595,6 +597,23 @@ namespace Conformance return *it; } + // Select the preferred swapchain format from the list of available formats. + int64_t D3D11GraphicsPlugin::SelectMotionVectorSwapchainFormat(const int64_t* formatArray, size_t count) const + { + // List of swapchain formats suitable for motion vectors. + const std::array f{DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R32G32B32_FLOAT}; + + const int64_t* formatArrayEnd = formatArray + count; + auto it = std::find_first_of(formatArray, formatArrayEnd, f.begin(), f.end()); + + if (it == formatArrayEnd) { + assert(false); // Assert instead of throw as we need to switch to the big table which can't fail. + return formatArray[0]; + } + + return *it; + } + int64_t D3D11GraphicsPlugin::GetSRGBA8Format() const { return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; diff --git a/src/conformance/framework/graphics_plugin_d3d12.cpp b/src/conformance/framework/graphics_plugin_d3d12.cpp index 2f648132..667142e7 100644 --- a/src/conformance/framework/graphics_plugin_d3d12.cpp +++ b/src/conformance/framework/graphics_plugin_d3d12.cpp @@ -343,6 +343,8 @@ namespace Conformance int64_t SelectDepthSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectMotionVectorSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + // Format required by RGBAImage type. int64_t GetSRGBA8Format() const override; @@ -821,6 +823,23 @@ namespace Conformance return *it; } + // Select the preferred swapchain format from the list of available formats. + int64_t D3D12GraphicsPlugin::SelectMotionVectorSwapchainFormat(const int64_t* formatArray, size_t count) const + { + // List of swapchain formats suitable for motion vectors. + const std::array f{DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R32G32B32_FLOAT}; + + const int64_t* formatArrayEnd = formatArray + count; + auto it = std::find_first_of(formatArray, formatArrayEnd, f.begin(), f.end()); + + if (it == formatArrayEnd) { + assert(false); // Assert instead of throw as we need to switch to the big table which can't fail. + return formatArray[0]; + } + + return *it; + } + int64_t D3D12GraphicsPlugin::GetSRGBA8Format() const { return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; diff --git a/src/conformance/framework/graphics_plugin_opengl.cpp b/src/conformance/framework/graphics_plugin_opengl.cpp index ba6e8f69..e0edc7b3 100644 --- a/src/conformance/framework/graphics_plugin_opengl.cpp +++ b/src/conformance/framework/graphics_plugin_opengl.cpp @@ -404,6 +404,8 @@ namespace Conformance int64_t SelectDepthSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectMotionVectorSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + // Format required by RGBAImage type. int64_t GetSRGBA8Format() const override; @@ -933,6 +935,25 @@ namespace Conformance return *it; } + int64_t OpenGLGraphicsPlugin::SelectMotionVectorSwapchainFormat(const int64_t* imageFormatArray, size_t count) const + { + // List of swapchain formats suitable for motion vectors. + const std::array f{ + GL_RGBA16F, + GL_RGB16F, + }; + + const int64_t* formatArrayEnd = imageFormatArray + count; + auto it = std::find_first_of(imageFormatArray, formatArrayEnd, f.begin(), f.end()); + + if (it == formatArrayEnd) { + assert(false); // Assert instead of throw as we need to switch to the big table which can't fail. + return imageFormatArray[0]; + } + + return *it; + } + int64_t OpenGLGraphicsPlugin::GetSRGBA8Format() const { return GL_SRGB8_ALPHA8; diff --git a/src/conformance/framework/graphics_plugin_opengles.cpp b/src/conformance/framework/graphics_plugin_opengles.cpp index feca8db3..35ee5ac7 100644 --- a/src/conformance/framework/graphics_plugin_opengles.cpp +++ b/src/conformance/framework/graphics_plugin_opengles.cpp @@ -287,6 +287,8 @@ namespace Conformance int64_t SelectDepthSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectMotionVectorSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t GetSRGBA8Format() const override; ISwapchainImageData* AllocateSwapchainImageData(size_t size, const XrSwapchainCreateInfo& swapchainCreateInfo) override; @@ -1084,6 +1086,24 @@ namespace Conformance return *it; } + int64_t OpenGLESGraphicsPlugin::SelectMotionVectorSwapchainFormat(const int64_t* imageFormatArray, size_t count) const + { + // List of swapchain formats suitable for motion vectors. + const std::array f{ + GL_RGBA16F, + }; + + const int64_t* formatArrayEnd = imageFormatArray + count; + auto it = std::find_first_of(imageFormatArray, formatArrayEnd, f.begin(), f.end()); + + if (it == formatArrayEnd) { + assert(false); // Assert instead of throw as we need to switch to the big table which can't fail. + return imageFormatArray[0]; + } + + return *it; + } + int64_t OpenGLESGraphicsPlugin::GetSRGBA8Format() const { return GL_SRGB8_ALPHA8; diff --git a/src/conformance/framework/graphics_plugin_vulkan.cpp b/src/conformance/framework/graphics_plugin_vulkan.cpp index d01ccd45..ff3c1158 100644 --- a/src/conformance/framework/graphics_plugin_vulkan.cpp +++ b/src/conformance/framework/graphics_plugin_vulkan.cpp @@ -635,6 +635,8 @@ namespace Conformance int64_t SelectDepthSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectMotionVectorSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + // Format required by RGBAImage type. int64_t GetSRGBA8Format() const override; @@ -1688,6 +1690,23 @@ namespace Conformance return *it; } + // Select the preferred swapchain format from the list of available formats. + int64_t VulkanGraphicsPlugin::SelectMotionVectorSwapchainFormat(const int64_t* formatArray, size_t count) const + { + // List of supported swapchain formats suitable for motion vectors. + const std::array f{VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_R16G16B16_SFLOAT}; + + span formatArraySpan{formatArray, count}; + auto it = std::find_first_of(formatArraySpan.begin(), formatArraySpan.end(), f.begin(), f.end()); + + if (it == formatArraySpan.end()) { + assert(false); // Assert instead of throw as we need to switch to the big table which can't fail. + return formatArray[0]; + } + + return *it; + } + int64_t VulkanGraphicsPlugin::GetSRGBA8Format() const { return VK_FORMAT_R8G8B8A8_SRGB; diff --git a/src/conformance/framework/input_testinputdevice.cpp b/src/conformance/framework/input_testinputdevice.cpp index d3929047..4f7c31b5 100644 --- a/src/conformance/framework/input_testinputdevice.cpp +++ b/src/conformance/framework/input_testinputdevice.cpp @@ -22,6 +22,7 @@ #include "two_call.h" #include "utilities/throw_helpers.h" #include "utilities/types_and_constants.h" +#include "utilities/string_utils.h" #include @@ -104,17 +105,12 @@ namespace Conformance }; std::string topLevelPathString = std::string(CHECK_TWO_CALL(char, {}, xrPathToString, m_instance, m_topLevelPath).data()); - auto PrefixedByTopLevelPath = [&topLevelPathString](std::string binding) { - return (binding.length() > topLevelPathString.size()) && - (std::mismatch(topLevelPathString.begin(), topLevelPathString.end(), binding.begin()).first == - topLevelPathString.end()); - }; FeatureSet enabled; GetGlobalData().PopulateVersionAndEnabledExtensions(enabled); for (const InputSourcePathAvailData& inputSourceData : interactionProfilePaths) { - if (!PrefixedByTopLevelPath(inputSourceData.Path)) { + if (!starts_with(inputSourceData.Path, topLevelPathString)) { continue; } if (!kInteractionAvailabilities[(size_t)inputSourceData.Availability].IsSatisfiedBy(enabled)) { diff --git a/src/conformance/utilities/CMakeLists.txt b/src/conformance/utilities/CMakeLists.txt index 0cf50621..5b8efd38 100644 --- a/src/conformance/utilities/CMakeLists.txt +++ b/src/conformance/utilities/CMakeLists.txt @@ -54,6 +54,7 @@ add_library( event_reader.cpp feature_availability.cpp opengl_utils.cpp + string_utils.cpp stringification.cpp swapchain_format_data.cpp throw_helpers.cpp diff --git a/src/conformance/utilities/string_utils.cpp b/src/conformance/utilities/string_utils.cpp new file mode 100644 index 00000000..4ac05e46 --- /dev/null +++ b/src/conformance/utilities/string_utils.cpp @@ -0,0 +1,66 @@ +// Copyright (c) 2019-2024, The Khronos Group Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// 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 "string_utils.h" +#include + +namespace Conformance +{ + // Internal implementations that actually do the work + static bool starts_with(const char* str, size_t strLen, const char* prefix, size_t prefixLen) + { + if (prefixLen > strLen) { + return false; + } + return 0 == strncmp(str, prefix, prefixLen); + } + static bool ends_with(const char* str, size_t strLen, const char* suffix, size_t suffixLen) + { + if (suffixLen > strLen) { + return false; + } + return 0 == strncmp(str + strLen - suffixLen, suffix, suffixLen); + } + + // Exported wrapper functions. + + bool starts_with(const char* str, const char* prefix) + { + return starts_with(str, strlen(str), prefix, strlen(prefix)); + } + bool starts_with(const std::string& str, const char* prefix) + { + return starts_with(str.data(), str.size(), prefix, std::strlen(prefix)); + } + bool starts_with(const std::string& str, const std::string& prefix) + { + return starts_with(str.data(), str.size(), prefix.data(), prefix.size()); + } + + bool ends_with(const char* str, const char* suffix) + { + return ends_with(str, strlen(str), suffix, strlen(suffix)); + } + bool ends_with(const std::string& str, const char* suffix) + { + return ends_with(str.data(), str.size(), suffix, std::strlen(suffix)); + } + bool ends_with(const std::string& str, const std::string& suffix) + { + return ends_with(str.data(), str.size(), suffix.data(), suffix.size()); + } + +} // namespace Conformance diff --git a/src/conformance/utilities/string_utils.h b/src/conformance/utilities/string_utils.h new file mode 100644 index 00000000..6992f133 --- /dev/null +++ b/src/conformance/utilities/string_utils.h @@ -0,0 +1,48 @@ +// Copyright (c) 2019-2024, The Khronos Group Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*! + * @file + * @brief Helper functions for strings and string literals. + * + * Many of these can be removed/replaced when we eventually migrate to C++20. + */ + +#include + +/// @addtogroup cts_framework +/// @{ +#pragma once + +namespace Conformance +{ + /// Does the given string start with this prefix? + bool starts_with(const char* str, const char* prefix); + /// @overload + bool starts_with(const std::string& str, const char* prefix); + /// @overload + bool starts_with(const std::string& str, const std::string& prefix); + + /// Does the given string end with this suffix? + bool ends_with(const char* str, const char* suffix); + /// @overload + bool ends_with(const std::string& str, const char* suffix); + /// @overload + bool ends_with(const std::string& str, const std::string& suffix); + +} // namespace Conformance + +/// @}