From 26cd3eb241017a6bf1c3ac981a10fb77d4825b30 Mon Sep 17 00:00:00 2001 From: Rylie Pavlik Date: Fri, 8 Nov 2024 17:18:54 -0600 Subject: [PATCH 1/5] Fix CTS running on Android Needed to add the ANativeActivity_onCreate function to the map file for the test library. Bug fix approved by chair for publication from internal repo prior to next regular repo update. Tested-by: Reality Merger Part-of: --- changes/conformance/mr.3596.gl.md | 1 + src/conformance/conformance_test/CMakeLists.txt | 11 +++++++++++ .../conformance_test_android.map | 16 ++++++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 changes/conformance/mr.3596.gl.md create mode 100644 src/conformance/conformance_test/conformance_test_android.map diff --git a/changes/conformance/mr.3596.gl.md b/changes/conformance/mr.3596.gl.md new file mode 100644 index 00000000..8a23ccad --- /dev/null +++ b/changes/conformance/mr.3596.gl.md @@ -0,0 +1 @@ +Fix: Broken Android builds - not runnable due to undefined symbol. diff --git a/src/conformance/conformance_test/CMakeLists.txt b/src/conformance/conformance_test/CMakeLists.txt index 593672dc..adeb4a89 100644 --- a/src/conformance/conformance_test/CMakeLists.txt +++ b/src/conformance/conformance_test/CMakeLists.txt @@ -177,6 +177,17 @@ elseif(APPLE) conformance_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/conformance_test.expsym" ) +elseif(ANDROID) + set_target_properties( + conformance_test + PROPERTIES + LINK_FLAGS + "-Wl,--version-script=\"${CMAKE_CURRENT_SOURCE_DIR}/conformance_test_android.map\"" + ) + target_sources( + conformance_test + PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/conformance_test_android.map" + ) else() set_target_properties( conformance_test diff --git a/src/conformance/conformance_test/conformance_test_android.map b/src/conformance/conformance_test/conformance_test_android.map new file mode 100644 index 00000000..a36c081e --- /dev/null +++ b/src/conformance/conformance_test/conformance_test_android.map @@ -0,0 +1,16 @@ +/* +Copyright (c) 2019-2024, The Khronos Group Inc. + +SPDX-License-Identifier: Apache-2.0 +*/ + +{ + global: + testLayer_xrNegotiateLoaderApiLayerInterface; + xrcCleanup; + xrcEnumerateTestCases; + xrcRunConformanceTests; + ANativeActivity_onCreate; + local: + *; +}; From 793c416c7acdd9888236965c49fbc05a9d03b7cf Mon Sep 17 00:00:00 2001 From: Fred Emmott <360927+fredemmott@users.noreply.github.com> Date: Tue, 26 Nov 2024 08:29:38 -0600 Subject: [PATCH 2/5] Install `XrApiLayer_conformance_test_layer.json` This is missing from at least the Openxr-cts-x64 bundle, and appears to not be installed by CMake Taken the same approach as https://github.com/KhronosGroup/OpenXR-CTS/blob/devel/src/conformance/conformance_layer/CMakeLists.txt Without this, `validApiLayer` fails on all runtimes when using a prebuild CTS bundle. --- src/conformance/conformance_test/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/conformance/conformance_test/CMakeLists.txt b/src/conformance/conformance_test/CMakeLists.txt index adeb4a89..cbc07b7f 100644 --- a/src/conformance/conformance_test/CMakeLists.txt +++ b/src/conformance/conformance_test/CMakeLists.txt @@ -238,6 +238,11 @@ set_target_properties( conformance_test PROPERTIES FOLDER ${CONFORMANCE_TESTS_FOLDER} ) +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/XrApiLayer_conformance_test_layer.json + DESTINATION conformance +) + install( TARGETS conformance_test LIBRARY DESTINATION conformance From 76d9e3bc1837b3305bfbfb47aa825c224080a345 Mon Sep 17 00:00:00 2001 From: Fred Emmott Date: Tue, 26 Nov 2024 10:04:45 -0600 Subject: [PATCH 3/5] add changelog fragment --- changes/conformance/pr.100.gh.OpenXR-CTS.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changes/conformance/pr.100.gh.OpenXR-CTS.md diff --git a/changes/conformance/pr.100.gh.OpenXR-CTS.md b/changes/conformance/pr.100.gh.OpenXR-CTS.md new file mode 100644 index 00000000..4ae0d93b --- /dev/null +++ b/changes/conformance/pr.100.gh.OpenXR-CTS.md @@ -0,0 +1 @@ +Fix: Install manifest for conformance test layer From e22d4f1faa777ac1601d69cd130850d9faab4f03 Mon Sep 17 00:00:00 2001 From: Rylie Pavlik Date: Wed, 27 Nov 2024 12:15:27 -0600 Subject: [PATCH 4/5] Changes from OpenXR 1.1.43. GitOrigin-RevId: 46d1c5e46ca0e9f37d3233f36dbd7a1f8fe8460c --- .reuse/dep5 | 2 +- changes/conformance/mr.3379.gl.md | 7 + changes/conformance/mr.3401.gl.md | 1 + changes/conformance/mr.3555.gl.2.md | 1 + changes/conformance/mr.3555.gl.md | 5 + changes/conformance/mr.3561.gl.md | 1 + changes/conformance/mr.3575.gl.md | 5 + changes/conformance/mr.3582.gl.md | 1 + changes/conformance/mr.3589.gl.md | 4 + changes/conformance/mr.3592.gl.md | 1 + specification/Makefile | 2 +- specification/registry/xr.xml | 463 ++++++++++++++++-- .../scripts/spec_tools/macro_checker_file.py | 5 +- src/common/gfxwrapper_opengl.c | 4 +- src/conformance/conformance_layer/Action.cpp | 2 +- .../conformance_layer/ConformanceHooks.h | 9 +- src/conformance/conformance_layer/Session.cpp | 5 +- .../gltf_examples/AnisotropyBarnLamp.png | 3 + .../AnisotropyBarnLamp.png.license | 4 + .../conformance_test/test_ActionPoses.cpp | 79 ++- .../test_GradientFormatsLinearVsNonLinear.cpp | 2 +- .../conformance_test/test_HapticInterrupt.cpp | 60 +-- .../test_InteractiveThrow.cpp | 57 ++- .../test_LayerComposition.cpp | 39 +- .../conformance_test/test_SpaceOffsets.cpp | 44 +- .../conformance_test/test_Swapchains.cpp | 101 +++- .../test_XR_EXT_eye_gaze_interaction.cpp | 30 +- .../test_XR_EXT_hand_tracking.cpp | 2 +- .../test_XR_EXT_local_floor.cpp | 6 +- .../test_XR_EXT_palm_pose.cpp | 38 +- .../test_XR_EXT_plane_detection.cpp | 25 +- .../test_XR_MSFT_controller_model.cpp | 88 ++-- .../test_XR_VARJO_quad_views.cpp | 4 +- .../test_XrCompositionLayerProjection.cpp | 6 +- .../conformance_test/test_actions.cpp | 222 ++++----- .../conformance_test/test_glTFRendering.cpp | 10 +- src/conformance/framework/CMakeLists.txt | 1 + .../framework/composition_utils.cpp | 2 +- src/conformance/framework/composition_utils.h | 4 +- .../framework/conformance_framework.cpp | 7 +- src/conformance/framework/gltf_helpers.cpp | 2 +- src/conformance/framework/graphics_plugin.h | 5 + .../framework/graphics_plugin_d3d11.cpp | 59 ++- .../framework/graphics_plugin_d3d12.cpp | 75 ++- .../framework/graphics_plugin_metal.cpp | 12 + .../framework/graphics_plugin_opengl.cpp | 12 + .../framework/graphics_plugin_opengles.cpp | 11 + .../framework/graphics_plugin_vulkan.cpp | 320 +++++++++++- .../framework/input_testinputdevice.cpp | 20 +- .../framework/input_testinputdevice.h | 2 +- src/conformance/framework/interaction_info.h | 10 +- .../framework/pbr/OpenGL/GLTexture.cpp | 62 +-- .../framework/pbr/Vulkan/VkPipelineStates.h | 6 +- src/conformance/framework/report.h | 5 +- .../framework/vulkan_shaders/comp.glsl | 24 + .../framework/vulkan_shaders/comp.spv | 105 ++++ .../framework/vulkan_shaders/comp.spv.license | 3 + src/conformance/usage/asciidoctor-targets.mk | 2 +- src/conformance/utilities/utils.h | 12 +- src/conformance/utilities/vulkan_utils.h | 171 +++++-- src/external/jnipp/CHANGELOG.md | 8 + src/external/jnipp/CMakeLists.txt | 1 + src/external/jnipp/changes/changes/pr.40.md | 1 + src/external/jnipp/changes/fixes/pr.49.md | 1 + src/external/jnipp/jnipp.cpp | 34 +- src/external/jnipp/proclamation.json | 20 + src/external/jnipp/tests/main.cpp | 8 + src/scripts/generate_api_layer_manifest.py | 67 ++- .../template_interaction_info_generated.cpp | 4 +- 69 files changed, 1864 insertions(+), 550 deletions(-) create mode 100644 changes/conformance/mr.3379.gl.md create mode 100644 changes/conformance/mr.3401.gl.md create mode 100644 changes/conformance/mr.3555.gl.2.md create mode 100644 changes/conformance/mr.3555.gl.md create mode 100644 changes/conformance/mr.3561.gl.md create mode 100644 changes/conformance/mr.3575.gl.md create mode 100644 changes/conformance/mr.3582.gl.md create mode 100644 changes/conformance/mr.3589.gl.md create mode 100644 changes/conformance/mr.3592.gl.md create mode 100644 src/conformance/conformance_test/gltf_examples/AnisotropyBarnLamp.png create mode 100644 src/conformance/conformance_test/gltf_examples/AnisotropyBarnLamp.png.license create mode 100644 src/conformance/framework/vulkan_shaders/comp.glsl create mode 100644 src/conformance/framework/vulkan_shaders/comp.spv create mode 100644 src/conformance/framework/vulkan_shaders/comp.spv.license create mode 100644 src/external/jnipp/CHANGELOG.md create mode 100644 src/external/jnipp/changes/changes/pr.40.md create mode 100644 src/external/jnipp/changes/fixes/pr.49.md create mode 100644 src/external/jnipp/proclamation.json diff --git a/.reuse/dep5 b/.reuse/dep5 index 51db8c8d..5cd4f92c 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -77,7 +77,7 @@ Files: src/external/jnipp/* Copyright: 2016-2020, Mitchell Dowd 2020, Collabora, Ltd. License: MIT -Comment: Unmodified, vendored copy of commit e6c415837c5a487809fdbb2f71f1080d454eb99a +Comment: Unmodified, vendored copy of commit v1.0.0-13-gcdd6293 Files: src/external/metal-cpp/* Copyright: Copyright 2020-2022 Apple Inc. diff --git a/changes/conformance/mr.3379.gl.md b/changes/conformance/mr.3379.gl.md new file mode 100644 index 00000000..8e8b40bc --- /dev/null +++ b/changes/conformance/mr.3379.gl.md @@ -0,0 +1,7 @@ +--- +- issue.2162.gl +- issue.2400.gl +- mr.2597.gl +- mr.3600.gl +--- +- New test: Automated test that attempts to write from a compute shader to swapchain images in formats that support unordered access, via Vulkan. D3D11/12 check flags to see that they *could* do so but do not yet actually attempt it. diff --git a/changes/conformance/mr.3401.gl.md b/changes/conformance/mr.3401.gl.md new file mode 100644 index 00000000..96b49cc3 --- /dev/null +++ b/changes/conformance/mr.3401.gl.md @@ -0,0 +1 @@ +Improvement: Add ability to quit/fail test for `XR_EXT_eye_gaze_interaction` by closing your eyes or otherwise losing eye tracking for 10 seconds. diff --git a/changes/conformance/mr.3555.gl.2.md b/changes/conformance/mr.3555.gl.2.md new file mode 100644 index 00000000..78d2a6fd --- /dev/null +++ b/changes/conformance/mr.3555.gl.2.md @@ -0,0 +1 @@ +- Improvement: Add example image for _Anisotropy Barn Lamp_ self-test diff --git a/changes/conformance/mr.3555.gl.md b/changes/conformance/mr.3555.gl.md new file mode 100644 index 00000000..fb0c3b8d --- /dev/null +++ b/changes/conformance/mr.3555.gl.md @@ -0,0 +1,5 @@ +--- +- issue.2390.gl +--- +- Fix: Correctly load the `glCompressedTexImage2D` function +- Fix: Upload compressed and mip-mapped textures correctly on OpenGL and OpenGL ES diff --git a/changes/conformance/mr.3561.gl.md b/changes/conformance/mr.3561.gl.md new file mode 100644 index 00000000..ae2ba0c9 --- /dev/null +++ b/changes/conformance/mr.3561.gl.md @@ -0,0 +1 @@ +- Improvement: Rename types, fields, and variables to use the term "binding path" when appropriate. In the past these have sometimes been confusingly called "input sources" despite being unrelated to the paths returned from `xrEnumerateBoundSourcesForAction` and passed to `xrGetInputSourceLocalizedName`. diff --git a/changes/conformance/mr.3575.gl.md b/changes/conformance/mr.3575.gl.md new file mode 100644 index 00000000..7c23af74 --- /dev/null +++ b/changes/conformance/mr.3575.gl.md @@ -0,0 +1,5 @@ +--- +- mr.3575.gl +- mr.3609.gl +--- +Improvement: Code cleanup, documentation, and consistency improvements. diff --git a/changes/conformance/mr.3582.gl.md b/changes/conformance/mr.3582.gl.md new file mode 100644 index 00000000..be2aaf71 --- /dev/null +++ b/changes/conformance/mr.3582.gl.md @@ -0,0 +1 @@ +Fix: Fix printing of some printf-based messages in the CTS. diff --git a/changes/conformance/mr.3589.gl.md b/changes/conformance/mr.3589.gl.md new file mode 100644 index 00000000..6bbe30be --- /dev/null +++ b/changes/conformance/mr.3589.gl.md @@ -0,0 +1,4 @@ +--- +- mr.3589.gl +--- +Improvement: Update jnipp, used for Android loader builds. New version includes a build fix for some environments, as well as a crash fix. diff --git a/changes/conformance/mr.3592.gl.md b/changes/conformance/mr.3592.gl.md new file mode 100644 index 00000000..dcce072c --- /dev/null +++ b/changes/conformance/mr.3592.gl.md @@ -0,0 +1 @@ +Improvement: Add Vulkan debug messages during Vulkan instance creation. diff --git a/specification/Makefile b/specification/Makefile index 1efa7270..a092737e 100644 --- a/specification/Makefile +++ b/specification/Makefile @@ -39,7 +39,7 @@ endif VERSIONS := XR_VERSION_1_0 XR_VERSION_1_1 XR_LOADER_VERSION_1_0 VERSIONOPTIONS := $(foreach version,$(VERSIONS),-feature $(version)) -SPECREVISION = 1.1.42 +SPECREVISION = 1.1.43 REVISION_COMPONENTS = $(subst ., ,$(SPECREVISION)) MAJORMINORVER = $(word 1,$(REVISION_COMPONENTS)).$(word 2,$(REVISION_COMPONENTS)) diff --git a/specification/registry/xr.xml b/specification/registry/xr.xml index 17ea6811..98fca45a 100644 --- a/specification/registry/xr.xml +++ b/specification/registry/xr.xml @@ -135,7 +135,7 @@ maintained in the default branch of the Khronos OpenXR GitHub project. updates them automatically by processing a line at a time. --> // OpenXR current version number. -#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 1, 42) +#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 1, 43) typedef XrFlags64 XrWorldMeshDetectorFlagsML; + + typedef XrFlags64 XrFacialExpressionBlendShapePropertiesFlagsML; + XR_DEFINE_HANDLE(XrInstance) @@ -498,8 +501,8 @@ maintained in the default branch of the Khronos OpenXR GitHub project. XR_DEFINE_HANDLE(XrMarkerDetectorML) - - XR_DEFINE_OPAQUE_64(XrFutureEXT) + + XR_DEFINE_HANDLE(XrFacialExpressionClientML) XR_DEFINE_HANDLE(XrEnvironmentDepthProviderMETA) @@ -511,6 +514,11 @@ maintained in the default branch of the Khronos OpenXR GitHub project. XR_DEFINE_HANDLE(XrWorldMeshDetectorML) + + + XR_DEFINE_OPAQUE_64(XrFutureEXT) + + @@ -665,13 +673,14 @@ maintained in the default branch of the Khronos OpenXR GitHub project. + - + - + @@ -712,6 +721,10 @@ maintained in the default branch of the Khronos OpenXR GitHub project. + + + + @@ -2808,6 +2821,118 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( XrKeyboardTrackingQueryFlagsFB flags + + + XrStructureType type + void* next + XrBool32 supportsColocationDiscovery + + + XrStructureType type + const void* next + uint32_t bufferSize + uint8_t* buffer + + + XrStructureType type + const void* next + + + XrStructureType type + const void* next + + + XrStructureType type + const void* next + + + XrStructureType type + const void* next + XrAsyncRequestIdFB advertisementRequestId + XrResult result + XrUuid advertisementUuid + + + XrStructureType type + const void* next + XrAsyncRequestIdFB advertisementRequestId + XrResult result + + + XrStructureType type + const void* next + XrAsyncRequestIdFB requestId + XrResult result + + + XrStructureType type + const void* next + XrAsyncRequestIdFB discoveryRequestId + XrResult result + + + XrStructureType type + const void* next + XrAsyncRequestIdFB discoveryRequestId + XrUuid advertisementUuid + uint32_t bufferSize + uint8_t buffer[XR_MAX_COLOCATION_DISCOVERY_BUFFER_SIZE_META] + + + XrStructureType type + const void* next + XrAsyncRequestIdFB discoveryRequestId + XrResult result + + + XrStructureType type + const void* next + XrAsyncRequestIdFB requestId + XrResult result + + + + + XrStructureType type + void* next + XrBool32 supportsSpatialEntitySharing + + + XrStructureType type + const void* next + + + XrStructureType type + const void* next + uint32_t spaceCount + XrSpace* spaces + const XrShareSpacesRecipientBaseHeaderMETA* recipientInfo + + + XrStructureType type + const void* next + XrAsyncRequestIdFB requestId + XrResult result + + + + + XrStructureType type + const void* next + uint32_t groupCount + XrUuid* groups + + + XrStructureType type + const void* next + XrUuid groupUuid + + + XrStructureType type + void* next + XrBool32 supportsSpatialEntityGroupSharing + + XrStructureType type @@ -3674,6 +3799,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( XrMarkerML marker XrPosef poseInMarkerSpace + float r float g @@ -3718,6 +3844,31 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( + + + XrStructureType type + void* next + XrBool32 supportsFacialExpression + + + XrStructureType type + const void* next + uint32_t requestedCount + const XrFacialBlendShapeML* requestedFacialBlendShapes + + + XrStructureType type + void* next + XrFacialBlendShapeML requestedFacialBlendShape + float weight + XrFacialExpressionBlendShapePropertiesFlagsML flags + XrTime time + + + XrStructureType type + const void* next + + XrStructureType type @@ -4114,6 +4265,13 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( XrWorldMeshBlockML* blocks + + + XrStructureType type + const void* next + XrPassthroughLayerFB layer + + @@ -5424,6 +5582,61 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -6729,6 +6942,40 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( const XrPassthroughKeyboardHandsIntensityFB* intensity + + + XrResult xrStartColocationDiscoveryMETA + XrSession session + const XrColocationDiscoveryStartInfoMETA* info + XrAsyncRequestIdFB* discoveryRequestId + + + XrResult xrStopColocationDiscoveryMETA + XrSession session + const XrColocationDiscoveryStopInfoMETA* info + XrAsyncRequestIdFB* requestId + + + XrResult xrStartColocationAdvertisementMETA + XrSession session + const XrColocationAdvertisementStartInfoMETA* info + XrAsyncRequestIdFB* advertisementRequestId + + + XrResult xrStopColocationAdvertisementMETA + XrSession session + const XrColocationAdvertisementStopInfoMETA* info + XrAsyncRequestIdFB* requestId + + + + + XrResult xrShareSpacesMETA + XrSession session + const XrShareSpacesInfoMETA* info + XrAsyncRequestIdFB* requestId + + XrResult xrCreateSpatialAnchorStoreConnectionMSFT @@ -7317,6 +7564,24 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( const XrEnvironmentDepthHandRemovalSetInfoMETA* setInfo + + + XrResult xrCreateFacialExpressionClientML + XrSession session + const XrFacialExpressionClientCreateInfoML* createInfo + XrFacialExpressionClientML* facialExpressionClient + + + XrResult xrDestroyFacialExpressionClientML + XrFacialExpressionClientML facialExpressionClient + + + XrResult xrGetFacialExpressionBlendShapePropertiesML + XrFacialExpressionClientML facialExpressionClient + const XrFacialExpressionBlendShapeGetInfoML* blendShapeGetInfo + uint32_t blendShapeCount + XrFacialExpressionBlendShapePropertiesML* blendShapes + @@ -7878,6 +8143,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( + @@ -7947,6 +8213,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( + @@ -7983,6 +8250,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( + @@ -8016,6 +8284,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( + @@ -8046,6 +8315,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( + @@ -8075,6 +8345,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( + @@ -9007,9 +9278,9 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( - + - + @@ -11275,7 +11546,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( - + @@ -12410,7 +12681,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( - + @@ -12443,10 +12714,14 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( - + - - + + + + + + @@ -12523,13 +12798,28 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( - + - - + + + + + + + + + + + + + + + + + @@ -14229,10 +14519,30 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( - + - - + + + + + + + + + + + + + + + + + + + + + + @@ -14875,17 +15185,71 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + + + + + + + + + + + + + + + @@ -16163,17 +16527,17 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( - + - - + + - + - - + + @@ -16184,10 +16548,10 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( - + - - + + @@ -16198,17 +16562,17 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( - + - - + + - + - - + + @@ -16324,6 +16688,27 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( + + + + + + + + + + + + + + + + + + + + + diff --git a/specification/scripts/spec_tools/macro_checker_file.py b/specification/scripts/spec_tools/macro_checker_file.py index 3fa4409a..95a1f640 100644 --- a/specification/scripts/spec_tools/macro_checker_file.py +++ b/specification/scripts/spec_tools/macro_checker_file.py @@ -70,7 +70,7 @@ # or containing our interested area when matched against the text preceding). # Used to skip checking in some places. OPEN_LINK = re.compile( - r'.*(?]*$' + r'.*(?]*|xref:[^\[]*)$' ) # Matches if a string begins and is followed by a link "close" without a matching open. @@ -85,8 +85,9 @@ # - `ifdef:` # - `endif:` # - `todo` (followed by something matching \b, like : or (. capitalization ignored) +# - `[#` (anchor for an image) SKIP_LINE = re.compile( - r'^(ifdef:)|(endif:)|([tT][oO][dD][oO]\b).*' + r'^(ifdef:)|(endif:)|([tT][oO][dD][oO]\b)|(\[#).*' ) # Matches the whole inside of a refpage tag. diff --git a/src/common/gfxwrapper_opengl.c b/src/common/gfxwrapper_opengl.c index 595f1d6e..27a5c5e5 100644 --- a/src/common/gfxwrapper_opengl.c +++ b/src/common/gfxwrapper_opengl.c @@ -469,8 +469,8 @@ void GlInitExtensions() { #if defined(OS_WINDOWS) glActiveTexture = (PFNGLACTIVETEXTUREPROC)GetExtension("glActiveTexture"); glTexImage3D = (PFNGLTEXIMAGE3DPROC)GetExtension("glTexImage3D"); - glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)GetExtension("glCompressedTexImage2D "); - glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)GetExtension("glCompressedTexImage3D "); + glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)GetExtension("glCompressedTexImage2D"); + glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)GetExtension("glCompressedTexImage3D"); glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)GetExtension("glTexSubImage3D"); glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)GetExtension("glCompressedTexSubImage2D"); glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)GetExtension("glCompressedTexSubImage3D"); diff --git a/src/conformance/conformance_layer/Action.cpp b/src/conformance/conformance_layer/Action.cpp index 7a28984d..e63eedf7 100644 --- a/src/conformance/conformance_layer/Action.cpp +++ b/src/conformance/conformance_layer/Action.cpp @@ -133,7 +133,7 @@ XrResult ConformanceHooks::xrGetActionStatePose(XrSession session, const XrActio const XrResult result = ConformanceHooksBase::xrGetActionStatePose(session, getInfo, data); if (XR_SUCCEEDED(result)) { CustomActionState* const actionData = GetCustomActionState(getInfo->action); - NONCONFORMANT_IF(actionData->type != XR_ACTION_TYPE_POSE_INPUT, "Unexpected success with action handle type %s", + NONCONFORMANT_IF(actionData->type != XR_ACTION_TYPE_POSE_INPUT, "Unexpected success with action handle type %d", (int)actionData->type); VALIDATE_XRBOOL32(data->isActive); } diff --git a/src/conformance/conformance_layer/ConformanceHooks.h b/src/conformance/conformance_layer/ConformanceHooks.h index 7dc2970e..68ab458c 100644 --- a/src/conformance/conformance_layer/ConformanceHooks.h +++ b/src/conformance/conformance_layer/ConformanceHooks.h @@ -19,6 +19,12 @@ #include "gen_dispatch.h" #include +#ifdef __GNUC__ +#define LAYER_PRINT_ATTRIBUTE(a, b) __attribute__((format(printf, a, b))) +#else +#define LAYER_PRINT_ATTRIBUTE(a, b) +#endif + // Implementation of methods are distributed across multiple files, based on the primary handle type. // IConformanceHooks provides empty default implementations of all OpenXR functions. Only provide an override // if custom validation logic needs to be written. @@ -29,7 +35,8 @@ struct ConformanceHooks : ConformanceHooksBase { using ConformanceHooksBase::ConformanceHooksBase; - void ConformanceFailure(XrDebugUtilsMessageSeverityFlagsEXT severity, const char* functionName, const char* fmtMessage, ...) override; + void LAYER_PRINT_ATTRIBUTE(4, 5) + ConformanceFailure(XrDebugUtilsMessageSeverityFlagsEXT severity, const char* functionName, const char* fmtMessage, ...) override; // // Defined in Instance.cpp diff --git a/src/conformance/conformance_layer/Session.cpp b/src/conformance/conformance_layer/Session.cpp index a8e2a94e..ae773f97 100644 --- a/src/conformance/conformance_layer/Session.cpp +++ b/src/conformance/conformance_layer/Session.cpp @@ -15,6 +15,7 @@ // limitations under the License. #include +#include #include "ConformanceHooks.h" #include "CustomHandleState.h" #include "RuntimeFailure.h" @@ -302,7 +303,7 @@ XrResult ConformanceHooks::xrEndSession(XrSession session) if (XR_SUCCEEDED(result)) { NONCONFORMANT_IF(!customSessionState->sessionBegun, "Expected XR_ERROR_SESSION_NOT_RUNNING but got %s", to_string(result)); POSSIBLE_NONCONFORMANT_IF(customSessionState->sessionState != XR_SESSION_STATE_STOPPING, - "Expected XR_ERROR_SESSION_NOT_STOPPING when last known session state was %s", to_string(result), + "Expected XR_ERROR_SESSION_NOT_STOPPING when last known session state was %s", to_string(customSessionState->sessionState)); customSessionState->sessionBegun = false; @@ -351,7 +352,7 @@ XrResult ConformanceHooks::xrWaitFrame(XrSession session, const XrFrameWaitInfo* // to xrWaitFrame must block the caller until the start of the next rendering interval after the frame's target display time // as determined by the runtime. NONCONFORMANT_IF(frameState->predictedDisplayTime <= customSessionState->lastPredictedDisplayTime, - "New predicted display time %lld is less or equal to the previous predicted display time %lld", + "New predicted display time %" PRId64 " is less or equal to the previous predicted display time %" PRId64, frameState->predictedDisplayTime, customSessionState->lastPredictedDisplayTime); customSessionState->lastPredictedDisplayTime = frameState->predictedDisplayTime; diff --git a/src/conformance/conformance_test/gltf_examples/AnisotropyBarnLamp.png b/src/conformance/conformance_test/gltf_examples/AnisotropyBarnLamp.png new file mode 100644 index 00000000..58968208 --- /dev/null +++ b/src/conformance/conformance_test/gltf_examples/AnisotropyBarnLamp.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d76d53a8903c16717f539cb05d324357811b8b4fd9ad530224e4979b8ebfbdec +size 496965 diff --git a/src/conformance/conformance_test/gltf_examples/AnisotropyBarnLamp.png.license b/src/conformance/conformance_test/gltf_examples/AnisotropyBarnLamp.png.license new file mode 100644 index 00000000..63949097 --- /dev/null +++ b/src/conformance/conformance_test/gltf_examples/AnisotropyBarnLamp.png.license @@ -0,0 +1,4 @@ +SPDX-FileCopyrightText: Copyright 2023 Wayfair, LLC. +SPDX-FileCopyrightText: 2023-2024, The Khronos Group Inc. + +SPDX-License-Identifier: CC-BY-4.0 diff --git a/src/conformance/conformance_test/test_ActionPoses.cpp b/src/conformance/conformance_test/test_ActionPoses.cpp index 9ad181cf..2796b781 100644 --- a/src/conformance/conformance_test/test_ActionPoses.cpp +++ b/src/conformance/conformance_test/test_ActionPoses.cpp @@ -22,6 +22,7 @@ #include "utilities/stringification.h" #include "utilities/throw_helpers.h" #include "utilities/types_and_constants.h" +#include "utilities/xr_math_operators.h" #include #include @@ -37,9 +38,6 @@ using namespace Conformance; -// Useful to track down errors when debugging stateful graphics APIs like OpenGL: -#define CHKGR() GetGlobalData().graphicsPlugin->CheckState(XRC_FILE_AND_LINE) - namespace Conformance { using namespace openxr::math_operators; @@ -59,8 +57,9 @@ namespace Conformance "Press menu to complete the validation."; CompositionHelper compositionHelper("Grip and Aim Pose"); - - const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL, Pose::Identity); + XrInstance instance = compositionHelper.GetInstance(); + XrSession session = compositionHelper.GetSession(); + const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL); // Set up composition projection layer and swapchains (one swapchain per view). std::vector swapchains; @@ -89,19 +88,22 @@ namespace Conformance std::vector pointerCubes; }; - Hand hands[2]; - hands[0].subactionPath = StringToPath(compositionHelper.GetInstance(), "/user/hand/left"); - hands[1].subactionPath = StringToPath(compositionHelper.GetInstance(), "/user/hand/right"); + Hand hands[2] = {}; + hands[0].subactionPath = StringToPath(instance, "/user/hand/left"); + hands[1].subactionPath = StringToPath(instance, "/user/hand/right"); // Set up the actions. - const std::array subactionPaths{hands[0].subactionPath, hands[1].subactionPath}; + const std::array subactionPaths{ + hands[0].subactionPath, + hands[1].subactionPath, + }; XrActionSet actionSet; XrAction completeAction, switchHandsAction, gripPoseAction, aimPoseAction; { XrActionSetCreateInfo actionSetInfo{XR_TYPE_ACTION_SET_CREATE_INFO}; strcpy(actionSetInfo.actionSetName, "interaction_test"); strcpy(actionSetInfo.localizedActionSetName, "Interaction Test"); - XRC_CHECK_THROW_XRCMD(xrCreateActionSet(compositionHelper.GetInstance(), &actionSetInfo, &actionSet)); + XRC_CHECK_THROW_XRCMD(xrCreateActionSet(instance, &actionSetInfo, &actionSet)); XrActionCreateInfo actionInfo{XR_TYPE_ACTION_CREATE_INFO}; actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; @@ -132,45 +134,45 @@ namespace Conformance } const std::vector bindings = { - {completeAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/menu/click")}, - {completeAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/menu/click")}, - {switchHandsAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/select/click")}, - {switchHandsAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/select/click")}, - {gripPoseAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/grip/pose")}, - {gripPoseAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/grip/pose")}, - {aimPoseAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/aim/pose")}, - {aimPoseAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/aim/pose")}, + {completeAction, StringToPath(instance, "/user/hand/left/input/menu/click")}, + {completeAction, StringToPath(instance, "/user/hand/right/input/menu/click")}, + {switchHandsAction, StringToPath(instance, "/user/hand/left/input/select/click")}, + {switchHandsAction, StringToPath(instance, "/user/hand/right/input/select/click")}, + {gripPoseAction, StringToPath(instance, "/user/hand/left/input/grip/pose")}, + {gripPoseAction, StringToPath(instance, "/user/hand/right/input/grip/pose")}, + {aimPoseAction, StringToPath(instance, "/user/hand/left/input/aim/pose")}, + {aimPoseAction, StringToPath(instance, "/user/hand/right/input/aim/pose")}, }; XrInteractionProfileSuggestedBinding suggestedBindings{XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING}; - suggestedBindings.interactionProfile = StringToPath(compositionHelper.GetInstance(), "/interaction_profiles/khr/simple_controller"); + suggestedBindings.interactionProfile = StringToPath(instance, "/interaction_profiles/khr/simple_controller"); suggestedBindings.suggestedBindings = bindings.data(); suggestedBindings.countSuggestedBindings = (uint32_t)bindings.size(); - XRC_CHECK_THROW_XRCMD(xrSuggestInteractionProfileBindings(compositionHelper.GetInstance(), &suggestedBindings)); + XRC_CHECK_THROW_XRCMD(xrSuggestInteractionProfileBindings(instance, &suggestedBindings)); XrSessionActionSetsAttachInfo attachInfo{XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO}; attachInfo.actionSets = &actionSet; attachInfo.countActionSets = 1; - XRC_CHECK_THROW_XRCMD(xrAttachSessionActionSets(compositionHelper.GetSession(), &attachInfo)); + XRC_CHECK_THROW_XRCMD(xrAttachSessionActionSets(session, &attachInfo)); compositionHelper.BeginSession(); // Create the instructional quad layer placed to the left bottom. XrCompositionLayerQuad* const instructionsQuad = compositionHelper.CreateQuadLayer(compositionHelper.CreateStaticSwapchainImage(CreateTextImage(1024, 512, instructions, 48)), - localSpace, 1.0f, {{0, 0, 0, 1}, {-1.5f, -0.33f, -0.3f}}); + localSpace, 1.0f, {Quat::Identity, {-1.5f, -0.33f, -0.3f}}); instructionsQuad->pose.orientation = Quat::FromAxisAngle(Up, DegToRad(70)); // Create the diagram quad layer placed to the left top. XrCompositionLayerQuad* const diagramQuad = compositionHelper.CreateQuadLayer(compositionHelper.CreateStaticSwapchainImage(RGBAImage::Load(diagramImage)), localSpace, 1.0f, - {{0, 0, 0, 1}, {-1.5f, 0.33f, -0.3f}}); + {Quat::Identity, {-1.5f, 0.33f, -0.3f}}); diagramQuad->pose.orientation = Quat::FromAxisAngle(Up, DegToRad(70)); // Create a sample image quad layer placed to the right. XrCompositionLayerQuad* const exampleQuad = compositionHelper.CreateQuadLayer(compositionHelper.CreateStaticSwapchainImage(RGBAImage::Load(exampleImage)), localSpace, - 1.25f, {{0, 0, 0, 1}, {1.5f, 0, -0.3f}}); + 1.25f, {Quat::Identity, {1.5f, 0, -0.3f}}); exampleQuad->pose.orientation = Quat::FromAxisAngle(Up, DegToRad(-70)); const float PointerLength = 4.00f; @@ -195,8 +197,8 @@ namespace Conformance XrActionSpaceCreateInfo spaceCreateInfo{XR_TYPE_ACTION_SPACE_CREATE_INFO}; spaceCreateInfo.subactionPath = hand.subactionPath; spaceCreateInfo.action = poseAction; - spaceCreateInfo.poseInActionSpace = {{0, 0, 0, 1}, poseInSpacePos}; - XRC_CHECK_THROW_XRCMD(xrCreateActionSpace(compositionHelper.GetSession(), &spaceCreateInfo, &spaceCube.space)); + spaceCreateInfo.poseInActionSpace = {Quat::Identity, poseInSpacePos}; + XRC_CHECK_THROW_XRCMD(xrCreateActionSpace(session, &spaceCreateInfo, &spaceCube.space)); spaceCubes.push_back(std::move(spaceCube)); }; @@ -227,15 +229,14 @@ namespace Conformance XrActionsSyncInfo syncInfo{XR_TYPE_ACTIONS_SYNC_INFO}; syncInfo.activeActionSets = activeActionSets.data(); syncInfo.countActiveActionSets = (uint32_t)activeActionSets.size(); - XRC_CHECK_THROW_XRCMD(xrSyncActions(compositionHelper.GetSession(), &syncInfo)); + XRC_CHECK_THROW_XRCMD(xrSyncActions(session, &syncInfo)); // Check if user has requested to complete the test. { XrActionStateGetInfo completeActionGetInfo{XR_TYPE_ACTION_STATE_GET_INFO}; completeActionGetInfo.action = completeAction; XrActionStateBoolean completeActionState{XR_TYPE_ACTION_STATE_BOOLEAN}; - XRC_CHECK_THROW_XRCMD( - xrGetActionStateBoolean(compositionHelper.GetSession(), &completeActionGetInfo, &completeActionState)); + XRC_CHECK_THROW_XRCMD(xrGetActionStateBoolean(session, &completeActionGetInfo, &completeActionState)); if (completeActionState.currentState == XR_TRUE && completeActionState.changedSinceLastSync) { return false; } @@ -259,7 +260,7 @@ namespace Conformance swapActionGetInfo.action = switchHandsAction; swapActionGetInfo.subactionPath = hand.subactionPath; XrActionStateBoolean swapActionState{XR_TYPE_ACTION_STATE_BOOLEAN}; - XRC_CHECK_THROW_XRCMD(xrGetActionStateBoolean(compositionHelper.GetSession(), &swapActionGetInfo, &swapActionState)); + XRC_CHECK_THROW_XRCMD(xrGetActionStateBoolean(session, &swapActionGetInfo, &swapActionState)); if (swapActionState.currentState == XR_TRUE && swapActionState.changedSinceLastSync) { pointerHand = hand.subactionPath; } @@ -282,15 +283,13 @@ namespace Conformance // Render into each of the separate swapchains using the projection layer view fov and pose. for (size_t view = 0; view < views.size(); view++) { - compositionHelper.AcquireWaitReleaseImage(swapchains[view], // - [&](const XrSwapchainImageBaseHeader* swapchainImage) { - GetGlobalData().graphicsPlugin->ClearImageSlice(swapchainImage); - const_cast(projLayer->views[view].fov) = views[view].fov; - const_cast(projLayer->views[view].pose) = views[view].pose; - GetGlobalData().graphicsPlugin->RenderView( - projLayer->views[view], swapchainImage, - RenderParams().Draw(renderedCubes)); - }); + compositionHelper.AcquireWaitReleaseImage(swapchains[view], [&](const XrSwapchainImageBaseHeader* swapchainImage) { + GetGlobalData().graphicsPlugin->ClearImageSlice(swapchainImage); + const_cast(projLayer->views[view].fov) = views[view].fov; + const_cast(projLayer->views[view].pose) = views[view].pose; + GetGlobalData().graphicsPlugin->RenderView(projLayer->views[view], swapchainImage, + RenderParams().Draw(renderedCubes)); + }); } layers.push_back({reinterpret_cast(projLayer)}); @@ -306,6 +305,6 @@ namespace Conformance return true; }; - RenderLoop(compositionHelper.GetSession(), update).Loop(); + RenderLoop(session, update).Loop(); } } // namespace Conformance diff --git a/src/conformance/conformance_test/test_GradientFormatsLinearVsNonLinear.cpp b/src/conformance/conformance_test/test_GradientFormatsLinearVsNonLinear.cpp index b4dac66e..c8d3e517 100644 --- a/src/conformance/conformance_test/test_GradientFormatsLinearVsNonLinear.cpp +++ b/src/conformance/conformance_test/test_GradientFormatsLinearVsNonLinear.cpp @@ -133,7 +133,7 @@ namespace Conformance XrSession session = compositionHelper.GetSession(); - const XrSpace viewSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_VIEW, Pose::Identity); + const XrSpace viewSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_VIEW); // Enumerate formats std::vector imageFormatArray; diff --git a/src/conformance/conformance_test/test_HapticInterrupt.cpp b/src/conformance/conformance_test/test_HapticInterrupt.cpp index 387b75f1..69585dc7 100644 --- a/src/conformance/conformance_test/test_HapticInterrupt.cpp +++ b/src/conformance/conformance_test/test_HapticInterrupt.cpp @@ -21,6 +21,7 @@ #include "graphics_plugin.h" #include "utilities/throw_helpers.h" #include "utilities/types_and_constants.h" +#include "utilities/xr_math_operators.h" #include #include @@ -51,8 +52,9 @@ namespace Conformance "Press the menu button on either controller to pass the test. "; CompositionHelper compositionHelper("Haptic Interrupt"); - - const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL, Pose::Identity); + XrInstance instance = compositionHelper.GetInstance(); + XrSession session = compositionHelper.GetSession(); + const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL); // Set up composition projection layer and swapchains (one swapchain per view). std::vector swapchains; @@ -67,8 +69,10 @@ namespace Conformance } } - const std::vector subactionPaths{StringToPath(compositionHelper.GetInstance(), "/user/hand/left"), - StringToPath(compositionHelper.GetInstance(), "/user/hand/right")}; + const std::array subactionPaths{ + StringToPath(instance, "/user/hand/left"), + StringToPath(instance, "/user/hand/right"), + }; XrActionSet actionSet; XrAction hapticAction, completeAction, gripPoseAction, applyHapticAction; @@ -76,7 +80,7 @@ namespace Conformance XrActionSetCreateInfo actionSetInfo{XR_TYPE_ACTION_SET_CREATE_INFO}; strcpy(actionSetInfo.actionSetName, "interaction_test"); strcpy(actionSetInfo.localizedActionSetName, "Interaction Test"); - XRC_CHECK_THROW_XRCMD(xrCreateActionSet(compositionHelper.GetInstance(), &actionSetInfo, &actionSet)); + XRC_CHECK_THROW_XRCMD(xrCreateActionSet(instance, &actionSetInfo, &actionSet)); XrActionCreateInfo actionInfo{XR_TYPE_ACTION_CREATE_INFO}; actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; @@ -111,33 +115,33 @@ namespace Conformance } const std::vector bindings = { - {completeAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/menu/click")}, - {completeAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/menu/click")}, - {applyHapticAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/select/click")}, - {applyHapticAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/select/click")}, - {gripPoseAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/grip/pose")}, - {gripPoseAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/grip/pose")}, - {hapticAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/output/haptic")}, - {hapticAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/output/haptic")}, + {completeAction, StringToPath(instance, "/user/hand/left/input/menu/click")}, + {completeAction, StringToPath(instance, "/user/hand/right/input/menu/click")}, + {applyHapticAction, StringToPath(instance, "/user/hand/left/input/select/click")}, + {applyHapticAction, StringToPath(instance, "/user/hand/right/input/select/click")}, + {gripPoseAction, StringToPath(instance, "/user/hand/left/input/grip/pose")}, + {gripPoseAction, StringToPath(instance, "/user/hand/right/input/grip/pose")}, + {hapticAction, StringToPath(instance, "/user/hand/left/output/haptic")}, + {hapticAction, StringToPath(instance, "/user/hand/right/output/haptic")}, }; XrInteractionProfileSuggestedBinding suggestedBindings{XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING}; - suggestedBindings.interactionProfile = StringToPath(compositionHelper.GetInstance(), "/interaction_profiles/khr/simple_controller"); + suggestedBindings.interactionProfile = StringToPath(instance, "/interaction_profiles/khr/simple_controller"); suggestedBindings.suggestedBindings = bindings.data(); suggestedBindings.countSuggestedBindings = (uint32_t)bindings.size(); - XRC_CHECK_THROW_XRCMD(xrSuggestInteractionProfileBindings(compositionHelper.GetInstance(), &suggestedBindings)); + XRC_CHECK_THROW_XRCMD(xrSuggestInteractionProfileBindings(instance, &suggestedBindings)); XrSessionActionSetsAttachInfo attachInfo{XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO}; attachInfo.actionSets = &actionSet; attachInfo.countActionSets = 1; - XRC_CHECK_THROW_XRCMD(xrAttachSessionActionSets(compositionHelper.GetSession(), &attachInfo)); + XRC_CHECK_THROW_XRCMD(xrAttachSessionActionSets(session, &attachInfo)); compositionHelper.BeginSession(); // Create the instructional quad layer placed to the left. XrCompositionLayerQuad* const instructionsQuad = compositionHelper.CreateQuadLayer(compositionHelper.CreateStaticSwapchainImage(CreateTextImage(1024, 512, instructions, 48)), - localSpace, 1, {{0, 0, 0, 1}, {-1.5f, 0, -0.3f}}); + localSpace, 1.0f, {Quat::Identity, {-1.5f, 0, -0.3f}}); instructionsQuad->pose.orientation = Quat::FromAxisAngle(Up, DegToRad(70)); struct Hand @@ -148,15 +152,15 @@ namespace Conformance }; Hand hands[2]; - hands[0].subactionPath = StringToPath(compositionHelper.GetInstance(), "/user/hand/left"); - hands[1].subactionPath = StringToPath(compositionHelper.GetInstance(), "/user/hand/right"); + hands[0].subactionPath = StringToPath(instance, "/user/hand/left"); + hands[1].subactionPath = StringToPath(instance, "/user/hand/right"); for (Hand& hand : hands) { XrActionSpaceCreateInfo spaceCreateInfo{XR_TYPE_ACTION_SPACE_CREATE_INFO}; spaceCreateInfo.action = gripPoseAction; spaceCreateInfo.subactionPath = hand.subactionPath; - spaceCreateInfo.poseInActionSpace.orientation.w = 1.0f; - XRC_CHECK_THROW_XRCMD(xrCreateActionSpace(compositionHelper.GetSession(), &spaceCreateInfo, &hand.space)); + spaceCreateInfo.poseInActionSpace = Pose::Identity; + XRC_CHECK_THROW_XRCMD(xrCreateActionSpace(session, &spaceCreateInfo, &hand.space)); } constexpr XrVector3f cubeScale{0.1f, 0.1f, 0.1f}; @@ -167,15 +171,14 @@ namespace Conformance XrActionsSyncInfo syncInfo{XR_TYPE_ACTIONS_SYNC_INFO}; syncInfo.activeActionSets = activeActionSets.data(); syncInfo.countActiveActionSets = (uint32_t)activeActionSets.size(); - XRC_CHECK_THROW_XRCMD(xrSyncActions(compositionHelper.GetSession(), &syncInfo)); + XRC_CHECK_THROW_XRCMD(xrSyncActions(session, &syncInfo)); // Check if user has requested to complete the test. { XrActionStateGetInfo completeActionGetInfo{XR_TYPE_ACTION_STATE_GET_INFO}; completeActionGetInfo.action = completeAction; XrActionStateBoolean completeActionState{XR_TYPE_ACTION_STATE_BOOLEAN}; - XRC_CHECK_THROW_XRCMD( - xrGetActionStateBoolean(compositionHelper.GetSession(), &completeActionGetInfo, &completeActionState)); + XRC_CHECK_THROW_XRCMD(xrGetActionStateBoolean(session, &completeActionGetInfo, &completeActionState)); if (completeActionState.currentState == XR_TRUE && completeActionState.changedSinceLastSync) { return false; } @@ -196,7 +199,7 @@ namespace Conformance actionStateGetInfo.action = applyHapticAction; actionStateGetInfo.subactionPath = hand.subactionPath; XrActionStateBoolean applyHapticValue{XR_TYPE_ACTION_STATE_BOOLEAN}; - XRC_CHECK_THROW_XRCMD(xrGetActionStateBoolean(compositionHelper.GetSession(), &actionStateGetInfo, &applyHapticValue)); + XRC_CHECK_THROW_XRCMD(xrGetActionStateBoolean(session, &actionStateGetInfo, &applyHapticValue)); if (applyHapticValue.currentState == XR_TRUE && applyHapticValue.changedSinceLastSync) { XrHapticActionInfo hapticInfo{XR_TYPE_HAPTIC_ACTION_INFO}; @@ -206,8 +209,7 @@ namespace Conformance vibration.amplitude = hand.highAmplitude ? 0.75f : 0.25f; vibration.duration = 2000000000; vibration.frequency = XR_FREQUENCY_UNSPECIFIED; - XRC_CHECK_THROW_XRCMD( - xrApplyHapticFeedback(compositionHelper.GetSession(), &hapticInfo, (XrHapticBaseHeader*)&vibration)); + XRC_CHECK_THROW_XRCMD(xrApplyHapticFeedback(session, &hapticInfo, (XrHapticBaseHeader*)&vibration)); hand.highAmplitude = !hand.highAmplitude; } @@ -224,7 +226,7 @@ namespace Conformance // Render into each of the separate swapchains using the projection layer view fov and pose. for (size_t view = 0; view < views.size(); view++) { compositionHelper.AcquireWaitReleaseImage(swapchains[view], [&](const XrSwapchainImageBaseHeader* swapchainImage) { - GetGlobalData().graphicsPlugin->ClearImageSlice(swapchainImage, 0); + GetGlobalData().graphicsPlugin->ClearImageSlice(swapchainImage); const_cast(projLayer->views[view].fov) = views[view].fov; const_cast(projLayer->views[view].pose) = views[view].pose; GetGlobalData().graphicsPlugin->RenderView(projLayer->views[view], swapchainImage, @@ -243,6 +245,6 @@ namespace Conformance return true; }; - RenderLoop(compositionHelper.GetSession(), update).Loop(); + RenderLoop(session, update).Loop(); } } // namespace Conformance diff --git a/src/conformance/conformance_test/test_InteractiveThrow.cpp b/src/conformance/conformance_test/test_InteractiveThrow.cpp index 767f117d..44bcc368 100644 --- a/src/conformance/conformance_test/test_InteractiveThrow.cpp +++ b/src/conformance/conformance_test/test_InteractiveThrow.cpp @@ -20,6 +20,7 @@ #include "utilities/ballistics.h" #include "utilities/throw_helpers.h" #include "utilities/utils.h" +#include "utilities/xr_math_operators.h" #include #include @@ -28,9 +29,6 @@ using namespace Conformance; -// Useful to track down errors when debugging stateful graphics APIs like OpenGL: -#define CHKGR() GetGlobalData().graphicsPlugin->CheckState(XRC_FILE_AND_LINE) - namespace Conformance { using namespace openxr::math_operators; @@ -52,7 +50,9 @@ namespace Conformance CompositionHelper compositionHelper("Interactive Throw"); - const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL, Pose::Identity); + XrInstance instance = compositionHelper.GetInstance(); + XrSession session = compositionHelper.GetSession(); + const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL); // Set up composition projection layer and swapchains (one swapchain per view). std::vector swapchains; @@ -67,8 +67,10 @@ namespace Conformance } } - const std::vector subactionPaths{StringToPath(compositionHelper.GetInstance(), "/user/hand/left"), - StringToPath(compositionHelper.GetInstance(), "/user/hand/right")}; + const std::array subactionPaths{ + StringToPath(instance, "/user/hand/left"), + StringToPath(instance, "/user/hand/right"), + }; XrActionSet actionSet; XrAction throwAction, failAction, gripPoseAction; @@ -76,7 +78,7 @@ namespace Conformance XrActionSetCreateInfo actionSetInfo{XR_TYPE_ACTION_SET_CREATE_INFO}; strcpy(actionSetInfo.actionSetName, "interaction_test"); strcpy(actionSetInfo.localizedActionSetName, "Interaction Test"); - XRC_CHECK_THROW_XRCMD(xrCreateActionSet(compositionHelper.GetInstance(), &actionSetInfo, &actionSet)); + XRC_CHECK_THROW_XRCMD(xrCreateActionSet(instance, &actionSetInfo, &actionSet)); XrActionCreateInfo actionInfo{XR_TYPE_ACTION_CREATE_INFO}; actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; @@ -102,31 +104,31 @@ namespace Conformance } const std::vector bindings = { - {throwAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/select/click")}, - {throwAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/select/click")}, - {failAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/menu/click")}, - {failAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/menu/click")}, - {gripPoseAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/grip/pose")}, - {gripPoseAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/grip/pose")}, + {throwAction, StringToPath(instance, "/user/hand/left/input/select/click")}, + {throwAction, StringToPath(instance, "/user/hand/right/input/select/click")}, + {failAction, StringToPath(instance, "/user/hand/left/input/menu/click")}, + {failAction, StringToPath(instance, "/user/hand/right/input/menu/click")}, + {gripPoseAction, StringToPath(instance, "/user/hand/left/input/grip/pose")}, + {gripPoseAction, StringToPath(instance, "/user/hand/right/input/grip/pose")}, }; XrInteractionProfileSuggestedBinding suggestedBindings{XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING}; - suggestedBindings.interactionProfile = StringToPath(compositionHelper.GetInstance(), "/interaction_profiles/khr/simple_controller"); + suggestedBindings.interactionProfile = StringToPath(instance, "/interaction_profiles/khr/simple_controller"); suggestedBindings.suggestedBindings = bindings.data(); suggestedBindings.countSuggestedBindings = (uint32_t)bindings.size(); - XRC_CHECK_THROW_XRCMD(xrSuggestInteractionProfileBindings(compositionHelper.GetInstance(), &suggestedBindings)); + XRC_CHECK_THROW_XRCMD(xrSuggestInteractionProfileBindings(instance, &suggestedBindings)); XrSessionActionSetsAttachInfo attachInfo{XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO}; attachInfo.actionSets = &actionSet; attachInfo.countActionSets = 1; - XRC_CHECK_THROW_XRCMD(xrAttachSessionActionSets(compositionHelper.GetSession(), &attachInfo)); + XRC_CHECK_THROW_XRCMD(xrAttachSessionActionSets(session, &attachInfo)); compositionHelper.BeginSession(); // Create the instructional quad layer placed to the left. XrCompositionLayerQuad* const instructionsQuad = compositionHelper.CreateQuadLayer(compositionHelper.CreateStaticSwapchainImage(CreateTextImage(1024, 768, instructions, 48)), - localSpace, 1, {{0, 0, 0, 1}, {-1.5f, 0, -0.3f}}); + localSpace, 1, {Quat::Identity, {-1.5f, 0, -0.3f}}); instructionsQuad->pose.orientation = Quat::FromAxisAngle(Up, DegToRad(70)); // Spaces attached to the hand (subaction). @@ -146,8 +148,8 @@ namespace Conformance XrActionSpaceCreateInfo spaceCreateInfo{XR_TYPE_ACTION_SPACE_CREATE_INFO}; spaceCreateInfo.action = gripPoseAction; spaceCreateInfo.subactionPath = subactionPath; - spaceCreateInfo.poseInActionSpace = {{0, 0, 0, 1}, {0, 0, -meterDistance}}; - XRC_CHECK_THROW_XRCMD(xrCreateActionSpace(compositionHelper.GetSession(), &spaceCreateInfo, &handSpace)); + spaceCreateInfo.poseInActionSpace = {Quat::Identity, {0, 0, -meterDistance}}; + XRC_CHECK_THROW_XRCMD(xrCreateActionSpace(session, &spaceCreateInfo, &handSpace)); handThrowSpaces.spaces.push_back(handSpace); } throwSpaces.push_back(std::move(handThrowSpaces)); @@ -164,6 +166,8 @@ namespace Conformance constexpr XrVector3f targetCubeScale{0.2f, 0.2f, 0.2f}; constexpr float targetCubeHitThreshold = 0.25f; + constexpr XrVector3f accelDueToGravity{0.f, -9.8f, 0.f}; + MeshHandle gnomonMesh = GetGlobalData().graphicsPlugin->MakeGnomonMesh(); auto update = [&](const XrFrameState& frameState) { @@ -174,15 +178,14 @@ namespace Conformance XrActionsSyncInfo syncInfo{XR_TYPE_ACTIONS_SYNC_INFO}; syncInfo.activeActionSets = activeActionSets.data(); syncInfo.countActiveActionSets = (uint32_t)activeActionSets.size(); - XRC_CHECK_THROW_XRCMD(xrSyncActions(compositionHelper.GetSession(), &syncInfo)); + XRC_CHECK_THROW_XRCMD(xrSyncActions(session, &syncInfo)); // Check if user has requested to fail the test. { XrActionStateGetInfo completeActionGetInfo{XR_TYPE_ACTION_STATE_GET_INFO}; completeActionGetInfo.action = failAction; XrActionStateBoolean completeActionState{XR_TYPE_ACTION_STATE_BOOLEAN}; - XRC_CHECK_THROW_XRCMD( - xrGetActionStateBoolean(compositionHelper.GetSession(), &completeActionGetInfo, &completeActionState)); + XRC_CHECK_THROW_XRCMD(xrGetActionStateBoolean(session, &completeActionGetInfo, &completeActionState)); if (completeActionState.currentState == XR_TRUE && completeActionState.changedSinceLastSync) { return false; } @@ -199,7 +202,7 @@ namespace Conformance } for (BodyInMotion& thrownCube : thrownCubes) { - thrownCube.doSimulationStep({0.f, -9.8f, 0.f}, frameState.predictedDisplayTime); + thrownCube.doSimulationStep(accelDueToGravity, frameState.predictedDisplayTime); cubes.push_back({thrownCube.pose, activateCubeScale}); // Remove any target cubes which are hit by the thrown cube. @@ -221,7 +224,7 @@ namespace Conformance // Add the targets. for (const XrVector3f& targetCubePosition : targetCubes) { - cubes.push_back({{{0, 0, 0, 1}, targetCubePosition}, targetCubeScale}); + cubes.push_back({{Quat::Identity, targetCubePosition}, targetCubeScale}); } // Locate throw spaces and add as cubes. Spawn thrown cubes when select released. @@ -231,7 +234,7 @@ namespace Conformance getInfo.action = throwAction; getInfo.subactionPath = subactionSpaces.subactionPath; XrActionStateBoolean boolState{XR_TYPE_ACTION_STATE_BOOLEAN}; - XRC_CHECK_THROW_XRCMD(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &boolState)); + XRC_CHECK_THROW_XRCMD(xrGetActionStateBoolean(session, &getInfo, &boolState)); for (XrSpace throwSpace : subactionSpaces.spaces) { XrSpaceVelocity spaceVelocity{XR_TYPE_SPACE_VELOCITY}; @@ -247,7 +250,7 @@ namespace Conformance for (int step = 1; step < 20; ++step) { auto predictedDisplayTimeAtStep = frameState.predictedDisplayTime + step * frameState.predictedDisplayPeriod; - gnomon.doSimulationStep({0.f, -9.8f, 0.f}, predictedDisplayTimeAtStep); + gnomon.doSimulationStep(accelDueToGravity, predictedDisplayTimeAtStep); meshes.push_back(MeshDrawable{gnomonMesh, gnomon.pose, gnomonScale}); } } @@ -302,7 +305,7 @@ namespace Conformance return true; }; - RenderLoop(compositionHelper.GetSession(), update).Loop(); + RenderLoop(session, update).Loop(); // The render loop will end if the user hits and removes all three target cubes or if the user presses menu. if (!targetCubes.empty()) { diff --git a/src/conformance/conformance_test/test_LayerComposition.cpp b/src/conformance/conformance_test/test_LayerComposition.cpp index 3f1eb250..4f2146e5 100644 --- a/src/conformance/conformance_test/test_LayerComposition.cpp +++ b/src/conformance/conformance_test/test_LayerComposition.cpp @@ -315,7 +315,7 @@ namespace Conformance interactionManager.AttachActionSets(); compositionHelper.BeginSession(); - const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL, Pose::Identity); + const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL); const std::vector viewProperties = compositionHelper.EnumerateConfigurationViews(); @@ -387,7 +387,7 @@ namespace Conformance interactionManager.AttachActionSets(); compositionHelper.BeginSession(); - const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL, Pose::Identity); + const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL); const std::vector viewProperties = compositionHelper.EnumerateConfigurationViews(); @@ -486,7 +486,10 @@ namespace Conformance "that \'R\' is always rendered atop \'L\', " "and both are atop the cubes when visible."); - const std::vector subactionPaths{StringToPath(instance, "/user/hand/left"), StringToPath(instance, "/user/hand/right")}; + const std::array subactionPaths{ + StringToPath(instance, "/user/hand/left"), + StringToPath(instance, "/user/hand/right"), + }; XrActionSet actionSet; XrAction gripPoseAction; @@ -590,7 +593,7 @@ namespace Conformance interactionManager.AttachActionSets(); compositionHelper.BeginSession(); - const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL, Pose::Identity); + const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL); if (!compositionHelper.GetViewConfigurationProperties().fovMutable) { SKIP("View configuration does not support mutable FoV"); @@ -762,7 +765,7 @@ namespace Conformance interactionManager.AttachActionSets(); compositionHelper.BeginSession(); - const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL, Pose::Identity); + const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL); const std::vector viewProperties = compositionHelper.EnumerateConfigurationViews(); @@ -776,39 +779,39 @@ namespace Conformance } const int LayerCount = 2; - XrCompositionLayerProjection* projLayer[LayerCount]; + XrCompositionLayerProjection* projLayers[LayerCount]; XrCompositionLayerDepthTestFB depthTestInfo[LayerCount]; std::vector> swapchain[LayerCount]; std::vector depthInfo[LayerCount]; // Set up the projection layers for (int layer = 0; layer < LayerCount; layer++) { - projLayer[layer] = compositionHelper.CreateProjectionLayer(localSpace); + projLayers[layer] = compositionHelper.CreateProjectionLayer(localSpace); // Add depth test info to the chain for each projection layer depthTestInfo[layer].type = XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_FB; - depthTestInfo[layer].next = projLayer[layer]->next; + depthTestInfo[layer].next = projLayers[layer]->next; depthTestInfo[layer].depthMask = true; depthTestInfo[layer].compareOp = XR_COMPARE_OP_LESS_FB; - const_cast(projLayer[layer]->next) = &depthTestInfo[layer]; + const_cast(projLayers[layer]->next) = &depthTestInfo[layer]; - depthInfo[layer].resize(projLayer[layer]->viewCount); - for (uint32_t j = 0; j < projLayer[layer]->viewCount; j++) { + depthInfo[layer].resize(projLayers[layer]->viewCount); + for (uint32_t j = 0; j < projLayers[layer]->viewCount; j++) { // create color and depth swapchains swapchain[layer].push_back( compositionHelper.CreateSwapchainWithDepth(colorSwapchainCreateInfo[j], depthSwapchainCreateInfo[j])); - const_cast(projLayer[layer]->views[j].subImage) = + const_cast(projLayers[layer]->views[j].subImage) = compositionHelper.MakeDefaultSubImage(swapchain[layer][j].first); // Add depth info to the chain for each projection layer view depthInfo[layer][j].type = XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR; - depthInfo[layer][j].next = projLayer[layer]->views[j].next; + depthInfo[layer][j].next = projLayers[layer]->views[j].next; depthInfo[layer][j].minDepth = 0.0f; depthInfo[layer][j].maxDepth = 1.0f; depthInfo[layer][j].nearZ = 0.05f; depthInfo[layer][j].farZ = 100.0f; depthInfo[layer][j].subImage = compositionHelper.MakeDefaultSubImage(swapchain[layer][j].second); - const_cast(projLayer[layer]->views[j].next) = &depthInfo[layer][j]; + const_cast(projLayers[layer]->views[j].next) = &depthInfo[layer][j]; } } @@ -834,13 +837,13 @@ namespace Conformance swapchain[layer][j].first, [&](const XrSwapchainImageBaseHeader* swapchainImage) { GetGlobalData().graphicsPlugin->ClearImageSlice(swapchainImage); - const_cast(projLayer[layer]->views[j].fov) = views[j].fov; - const_cast(projLayer[layer]->views[j].pose) = views[j].pose; - GetGlobalData().graphicsPlugin->RenderView(projLayer[layer]->views[j], swapchainImage, + const_cast(projLayers[layer]->views[j].fov) = views[j].fov; + const_cast(projLayers[layer]->views[j].pose) = views[j].pose; + GetGlobalData().graphicsPlugin->RenderView(projLayers[layer]->views[j], swapchainImage, RenderParams().Draw(cubes[layer])); }); } - layers.push_back(reinterpret_cast(projLayer[layer])); + layers.push_back(reinterpret_cast(projLayers[layer])); } } return interactiveLayerManager.EndFrame(frameState, layers); diff --git a/src/conformance/conformance_test/test_SpaceOffsets.cpp b/src/conformance/conformance_test/test_SpaceOffsets.cpp index f3769e9b..41334185 100644 --- a/src/conformance/conformance_test/test_SpaceOffsets.cpp +++ b/src/conformance/conformance_test/test_SpaceOffsets.cpp @@ -113,7 +113,10 @@ namespace Conformance CompositionHelper compositionHelper("Space Offsets"); - const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL, Pose::Identity); + XrInstance instance = compositionHelper.GetInstance(); + XrSession session = compositionHelper.GetSession(); + + const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL); // Set up composition projection layer and swapchains (one swapchain per view). std::vector swapchains; @@ -128,15 +131,17 @@ namespace Conformance } } - const std::vector subactionPaths{StringToPath(compositionHelper.GetInstance(), "/user/hand/left"), - StringToPath(compositionHelper.GetInstance(), "/user/hand/right")}; + const std::array subactionPaths{ + StringToPath(instance, "/user/hand/left"), + StringToPath(instance, "/user/hand/right"), + }; XrActionSet actionSet; XrAction freezeAction, failAction, gripPoseAction; { XrActionSetCreateInfo actionSetInfo{XR_TYPE_ACTION_SET_CREATE_INFO}; strcpy(actionSetInfo.actionSetName, "interaction_test"); strcpy(actionSetInfo.localizedActionSetName, "Interaction Test"); - XRC_CHECK_THROW_XRCMD(xrCreateActionSet(compositionHelper.GetInstance(), &actionSetInfo, &actionSet)); + XRC_CHECK_THROW_XRCMD(xrCreateActionSet(instance, &actionSetInfo, &actionSet)); XrActionCreateInfo actionInfo{XR_TYPE_ACTION_CREATE_INFO}; actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; @@ -162,24 +167,24 @@ namespace Conformance } const std::vector bindings = { - {freezeAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/select/click")}, - {freezeAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/select/click")}, - {failAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/menu/click")}, - {failAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/menu/click")}, - {gripPoseAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/grip/pose")}, - {gripPoseAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/grip/pose")}, + {freezeAction, StringToPath(instance, "/user/hand/left/input/select/click")}, + {freezeAction, StringToPath(instance, "/user/hand/right/input/select/click")}, + {failAction, StringToPath(instance, "/user/hand/left/input/menu/click")}, + {failAction, StringToPath(instance, "/user/hand/right/input/menu/click")}, + {gripPoseAction, StringToPath(instance, "/user/hand/left/input/grip/pose")}, + {gripPoseAction, StringToPath(instance, "/user/hand/right/input/grip/pose")}, }; XrInteractionProfileSuggestedBinding suggestedBindings{XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING}; - suggestedBindings.interactionProfile = StringToPath(compositionHelper.GetInstance(), "/interaction_profiles/khr/simple_controller"); + suggestedBindings.interactionProfile = StringToPath(instance, "/interaction_profiles/khr/simple_controller"); suggestedBindings.suggestedBindings = bindings.data(); suggestedBindings.countSuggestedBindings = (uint32_t)bindings.size(); - XRC_CHECK_THROW_XRCMD(xrSuggestInteractionProfileBindings(compositionHelper.GetInstance(), &suggestedBindings)); + XRC_CHECK_THROW_XRCMD(xrSuggestInteractionProfileBindings(instance, &suggestedBindings)); XrSessionActionSetsAttachInfo attachInfo{XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO}; attachInfo.actionSets = &actionSet; attachInfo.countActionSets = 1; - XRC_CHECK_THROW_XRCMD(xrAttachSessionActionSets(compositionHelper.GetSession(), &attachInfo)); + XRC_CHECK_THROW_XRCMD(xrAttachSessionActionSets(session, &attachInfo)); compositionHelper.BeginSession(); @@ -254,12 +259,12 @@ namespace Conformance spaceCreateInfo.subactionPath = subactionPath; spaceCreateInfo.poseInActionSpace = Pose::Identity; - XRC_CHECK_THROW_XRCMD(xrCreateActionSpace(compositionHelper.GetSession(), &spaceCreateInfo, &handSpaces.spaceWithoutOffset)); + XRC_CHECK_THROW_XRCMD(xrCreateActionSpace(session, &spaceCreateInfo, &handSpaces.spaceWithoutOffset)); for (XrPosef pose : handRelativePoses) { spaceCreateInfo.poseInActionSpace = pose; XrSpace handSpace; - XRC_CHECK_THROW_XRCMD(xrCreateActionSpace(compositionHelper.GetSession(), &spaceCreateInfo, &handSpace)); + XRC_CHECK_THROW_XRCMD(xrCreateActionSpace(session, &spaceCreateInfo, &handSpace)); handSpaces.spaces.emplace_back(pose, handSpace); } spaces.emplace_back(std::move(handSpaces)); @@ -287,15 +292,14 @@ namespace Conformance XrActionsSyncInfo syncInfo{XR_TYPE_ACTIONS_SYNC_INFO}; syncInfo.activeActionSets = activeActionSets.data(); syncInfo.countActiveActionSets = (uint32_t)activeActionSets.size(); - XRC_CHECK_THROW_XRCMD(xrSyncActions(compositionHelper.GetSession(), &syncInfo)); + XRC_CHECK_THROW_XRCMD(xrSyncActions(session, &syncInfo)); // Check if user has requested to fail the test. { XrActionStateGetInfo completeActionGetInfo{XR_TYPE_ACTION_STATE_GET_INFO}; completeActionGetInfo.action = failAction; XrActionStateBoolean completeActionState{XR_TYPE_ACTION_STATE_BOOLEAN}; - XRC_CHECK_THROW_XRCMD( - xrGetActionStateBoolean(compositionHelper.GetSession(), &completeActionGetInfo, &completeActionState)); + XRC_CHECK_THROW_XRCMD(xrGetActionStateBoolean(session, &completeActionGetInfo, &completeActionState)); if (completeActionState.currentState == XR_TRUE && completeActionState.changedSinceLastSync) { testFailed = true; return false; @@ -305,7 +309,7 @@ namespace Conformance XrActionStateGetInfo freezeActionGetInfo{XR_TYPE_ACTION_STATE_GET_INFO}; freezeActionGetInfo.action = freezeAction; XrActionStateBoolean freezeActionState{XR_TYPE_ACTION_STATE_BOOLEAN}; - XRC_CHECK_THROW_XRCMD(xrGetActionStateBoolean(compositionHelper.GetSession(), &freezeActionGetInfo, &freezeActionState)); + XRC_CHECK_THROW_XRCMD(xrGetActionStateBoolean(session, &freezeActionGetInfo, &freezeActionState)); if (testFailed) { postFailureUnfreeze = freezeActionState.currentState; @@ -586,7 +590,7 @@ namespace Conformance return true; }; - RenderLoop(compositionHelper.GetSession(), update).Loop(); + RenderLoop(session, update).Loop(); // The render loop will end if the user waves the controller or if the user presses menu. if (testFailed) { diff --git a/src/conformance/conformance_test/test_Swapchains.cpp b/src/conformance/conformance_test/test_Swapchains.cpp index d1701e59..1238e846 100644 --- a/src/conformance/conformance_test/test_Swapchains.cpp +++ b/src/conformance/conformance_test/test_Swapchains.cpp @@ -25,6 +25,7 @@ #include "utilities/throw_helpers.h" #include "utilities/types_and_constants.h" #include "utilities/utils.h" +#include "utilities/xr_math_operators.h" #include #include @@ -39,12 +40,21 @@ XRC_DISABLE_MSVC_WARNING(4505) // unreferenced local function has been removed namespace Conformance { + namespace + { + enum class RenderTestRoutine + { + ClearAndRender, + ClearWithCompute, + }; + } + static void DoRenderTest(ISwapchainImageData* swapchainImages, uint32_t colorImageCount, const XrSwapchainCreateInfo& colorCreateInfo, - XrSwapchain colorSwapchain) + XrSwapchain colorSwapchain, RenderTestRoutine renderRoutine) { XrCompositionLayerProjectionView projectionView{XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW}; - projectionView.pose = XrPosef{{0, 0, 0, 1}, {0, 0, 0}}; + projectionView.pose = Pose::Identity; projectionView.fov = {1, 1, 1, 1}; projectionView.subImage.swapchain = colorSwapchain; projectionView.subImage.imageRect = {{0, 0}, {(int32_t)colorCreateInfo.width, (int32_t)colorCreateInfo.height}}; @@ -76,8 +86,18 @@ namespace Conformance { INFO("Rendering to the swapchain(s)"); const XrSwapchainImageBaseHeader* image = swapchainImages->GetGenericColorImage(colorImageIndex); - GetGlobalData().graphicsPlugin->ClearImageSlice(image, 0); - GetGlobalData().graphicsPlugin->RenderView(projectionView, image, {}); + + switch (renderRoutine) { + case RenderTestRoutine::ClearAndRender: + GetGlobalData().graphicsPlugin->ClearImageSlice(image, 0); + GetGlobalData().graphicsPlugin->RenderView(projectionView, image, {}); + break; + + case RenderTestRoutine::ClearWithCompute: + // this is only implemented in the Vulkan plugin + GetGlobalData().graphicsPlugin->RenderClearImageSliceCompute(projectionView, image, {1.0, 0.0, 0.0, 1.0}); + break; + } } { INFO("Release the depth image if applicable"); @@ -489,7 +509,10 @@ namespace Conformance } } - TEST_CASE("SwapchainsRender", "") + void SwapchainsCommonTest( + const std::function& skipFormatCondition, + const std::function& skipCreateInfoCondition, + RenderTestRoutine renderRoutine) { const GlobalData& globalData = GetGlobalData(); if (!globalData.IsUsingGraphicsPlugin()) { @@ -524,13 +547,7 @@ namespace Conformance SwapchainCreateTestParameters tp; REQUIRE(globalData.graphicsPlugin->GetSwapchainCreateTestParameters(imageFormat, &tp)); - if (!tp.supportsRendering) { - // skip this format - continue; - } - - if (!tp.colorFormat && !tp.useAsDepth) { - // Image does not have a usable color or depth aspect + if (skipFormatCondition(tp)) { continue; } @@ -549,6 +566,10 @@ namespace Conformance continue; } + if (skipCreateInfoCondition(tp, createInfo)) { + continue; + } + CAPTURE(XrSwapchainCreateFlagsCPP(createInfo.createFlags)); CAPTURE(XrSwapchainUsageFlagsCPP(createInfo.usageFlags)); CAPTURE(createInfo.format); @@ -613,7 +634,7 @@ namespace Conformance XRC_CHECK_THROW_XRCMD(xrEnumerateSwapchainImages(colorSwapchain.get(), colorImageCount, &colorImageCount, swapchainImages->GetColorImageArray())); - DoRenderTest(swapchainImages, colorImageCount, colorCreateInfo, colorSwapchain.get()); + DoRenderTest(swapchainImages, colorImageCount, colorCreateInfo, colorSwapchain.get(), renderRoutine); GetGlobalData().graphicsPlugin->Flush(); } @@ -624,6 +645,60 @@ namespace Conformance } } + TEST_CASE("SwapchainsRender", "") + { + auto skipTpCondition = [](SwapchainCreateTestParameters& tp) -> bool { + if (!tp.supportsRendering) { + // skip this format + return true; + } + + if (!tp.colorFormat && !tp.useAsDepth) { + // Image does not have a usable color or depth aspect + return true; + } + + return false; + }; + + auto skipCreateInfoCondition = [](SwapchainCreateTestParameters& tp, XrSwapchainCreateInfo& createInfo) -> bool { + (void)tp; + (void)createInfo; + return false; + }; + SwapchainsCommonTest(skipTpCondition, skipCreateInfoCondition, RenderTestRoutine::ClearAndRender); + } + + // Ensure that XR_SWAPCHAIN_USAGE_UNORDERED_ACCESS_BIT is respected by rendering to the swapchain image with a compute shader in RenderClearImageSliceCompute + TEST_CASE("SwapchainsUnorderedAccess", "") + { + auto skipTpCondition = [](SwapchainCreateTestParameters& tp) -> bool { + (void)tp; + // Never skip an entire format + return false; + }; + + auto skipCreateInfoCondition = [](SwapchainCreateTestParameters& tp, XrSwapchainCreateInfo& createInfo) -> bool { + (void)tp; + //! @todo Only testing unordered access in combination with color attachment for now. + constexpr XrSwapchainUsageFlags uaColorFlags = + XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_UNORDERED_ACCESS_BIT; + + // Check whether createInfo.usageFlags contains *all* flags contained in uaColorFlags + if ((createInfo.usageFlags & uaColorFlags) != uaColorFlags) { + return true; + } + + if (createInfo.arraySize > 1) { + // Skip XrSwapchainCreateInfo array texture + return true; + } + return false; + }; + + SwapchainsCommonTest(skipTpCondition, skipCreateInfoCondition, RenderTestRoutine::ClearWithCompute); + } + TEST_CASE("SwapchainsAcquire", "") { GlobalData& globalData = GetGlobalData(); diff --git a/src/conformance/conformance_test/test_XR_EXT_eye_gaze_interaction.cpp b/src/conformance/conformance_test/test_XR_EXT_eye_gaze_interaction.cpp index 86e54fb9..83ca15d8 100644 --- a/src/conformance/conformance_test/test_XR_EXT_eye_gaze_interaction.cpp +++ b/src/conformance/conformance_test/test_XR_EXT_eye_gaze_interaction.cpp @@ -23,8 +23,10 @@ #include "utilities/system_properties_helper.h" #include "common/xr_linear.h" #include +#include using namespace Conformance; +namespace chrono = std::chrono; namespace Conformance { @@ -198,9 +200,9 @@ namespace Conformance } } - SECTION("Combine eye gaze with another input source - simple controller") + SECTION("Combine eye gaze with another input - simple controller") { - // Verify that eye gaze interaction input can be combined with other input sources. + // Verify that eye gaze interaction input can be combined with other inputs. // Use Simple Controller profile as opposed to vendor-specific inputs for broader coverage. AutoBasicInstance instance({XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME}); @@ -416,8 +418,8 @@ namespace Conformance attachInfo.countActionSets = 1; REQUIRE_RESULT(XR_SUCCESS, xrAttachSessionActionSets(compositionHelper.GetSession(), &attachInfo)); - const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL, Pose::Identity); - const XrSpace viewSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_VIEW, Pose::Identity); + const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL); + const XrSpace viewSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_VIEW); XrActionSpaceCreateInfo createActionSpaceInfo{XR_TYPE_ACTION_SPACE_CREATE_INFO}; createActionSpaceInfo.action = gazeAction; @@ -430,7 +432,8 @@ namespace Conformance const char* instructions = "A ray should point in the direction of eye gaze. " "Two small cubes are rendered in the environment. " - "Bring your head to one of these cubes to complete the validation. "; + "Bring your head to one of these cubes to complete the validation " + "or close your eyes for ten seconds to fail the test."; // Set up composition projection layer and swapchains (one swapchain per view). std::vector swapchains; @@ -455,6 +458,8 @@ namespace Conformance instructionsQuad->pose.orientation = Quat::FromAxisAngle(kVectorUp, DegToRad(70)); bool eyeGazeSampleTimeFound = false; + auto lastTrackedGaze = chrono::steady_clock::now(); + const int blinkTimout = 10; auto update = [&](const XrFrameState& frameState) { std::vector renderedCubes; @@ -471,8 +476,15 @@ namespace Conformance renderedCubes.push_back(Cube::Make(staticCubeLocs[i], staticCubeScale)); } - // Check if user has requested to complete the test. + // Check if user has requested to complete or fail the test. { + // Check if the user closed eyes (or otherwise lost gaze tracking) for ten seconds + const auto lostGazeDuration = chrono::duration_cast(chrono::steady_clock::now() - lastTrackedGaze); + if (lostGazeDuration.count() > blinkTimout) { + FAIL("Test failed by user request"); + } + + // Check if user has brought the head to the cubes if (viewLoc.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) { const XrVector3f& headPosition = viewLoc.pose.position; for (size_t i = 0; i < staticCubeLocs.size(); ++i) { @@ -512,6 +524,12 @@ namespace Conformance if (gazeLocation.locationFlags & spaceTrackedBits) { REQUIRE(spaceTrackedBits == (gazeLocation.locationFlags & spaceTrackedBits)); } + + // Check if eyes were tracked and reset timeout + if ((gazeLocation.locationFlags & XR_SPACE_LOCATION_POSITION_TRACKED_BIT) == XR_SPACE_LOCATION_POSITION_TRACKED_BIT) { + lastTrackedGaze = chrono::steady_clock::now(); + } + // If at least orientation is valid, show a ray representing the gaze if (gazeLocation.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) { // The sample time must be set diff --git a/src/conformance/conformance_test/test_XR_EXT_hand_tracking.cpp b/src/conformance/conformance_test/test_XR_EXT_hand_tracking.cpp index 24877c0a..0f3f9e30 100644 --- a/src/conformance/conformance_test/test_XR_EXT_hand_tracking.cpp +++ b/src/conformance/conformance_test/test_XR_EXT_hand_tracking.cpp @@ -323,7 +323,7 @@ namespace Conformance auto xrDestroyHandTrackerEXT = GetInstanceExtensionFunction(instance, "xrDestroyHandTrackerEXT"); auto xrLocateHandJointsEXT = GetInstanceExtensionFunction(instance, "xrLocateHandJointsEXT"); - const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL, Pose::Identity); + const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL); // Set up composition projection layer and swapchains (one swapchain per view). std::vector swapchains; 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 7f8e33fe..3b4bae9b 100644 --- a/src/conformance/conformance_test/test_XR_EXT_local_floor.cpp +++ b/src/conformance/conformance_test/test_XR_EXT_local_floor.cpp @@ -342,9 +342,9 @@ namespace Conformance SKIP("XR_REFERENCE_SPACE_TYPE_STAGE not supported"); } - XrSpace refSpace = compositionHelper.CreateReferenceSpace(refSpaceType, Pose::Identity); - XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL, Pose::Identity); - XrSpace localFloorSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT, Pose::Identity); + XrSpace refSpace = compositionHelper.CreateReferenceSpace(refSpaceType); + XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL); + XrSpace localFloorSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT); // Set up composition projection layer and swapchains (one swapchain per view). std::vector swapchains; 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 99087f20..ddd47898 100644 --- a/src/conformance/conformance_test/test_XR_EXT_palm_pose.cpp +++ b/src/conformance/conformance_test/test_XR_EXT_palm_pose.cpp @@ -26,6 +26,7 @@ #include "utilities/types_and_constants.h" #include "utilities/utils.h" #include "availability_helper.h" +#include "utilities/xr_math_operators.h" #include #include @@ -77,7 +78,7 @@ namespace Conformance XrInstance instance = compositionHelper.GetInstance(); XrSession session = compositionHelper.GetSession(); - const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL, Pose::Identity); + const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL); // Set up composition projection layer and swapchains (one swapchain per view). std::vector swapchains; @@ -111,7 +112,10 @@ namespace Conformance hands[1].subactionPath = StringToPath(instance, "/user/hand/right"); // Set up the actions. - const std::array subactionPaths{hands[0].subactionPath, hands[1].subactionPath}; + const std::array subactionPaths{ + hands[0].subactionPath, + hands[1].subactionPath, + }; XrActionSet actionSet; XrAction completeAction, switchHandsAction, gripSurfacePoseAction; { @@ -176,13 +180,13 @@ namespace Conformance // Create the instructional quad layer placed to the left. XrCompositionLayerQuad* const instructionsQuad = compositionHelper.CreateQuadLayer( compositionHelper.CreateStaticSwapchainImage(CreateTextImage(1024, 512, instructions.str().c_str(), 48)), localSpace, 1.0f, - {{0, 0, 0, 1}, {-1.5f, 0, -0.3f}}); + {Quat::Identity, {-1.5f, 0, -0.3f}}); instructionsQuad->pose.orientation = Quat::FromAxisAngle(Up, DegToRad(70)); // Create a sample image quad layer placed to the right. XrCompositionLayerQuad* const exampleQuad = compositionHelper.CreateQuadLayer(compositionHelper.CreateStaticSwapchainImage(RGBAImage::Load(exampleImage)), localSpace, - 1.25f, {{0, 0, 0, 1}, {1.5f, 0, -0.3f}}); + 1.25f, {Quat::Identity, {1.5f, 0, -0.3f}}); exampleQuad->pose.orientation = Quat::FromAxisAngle(Up, -DegToRad(70)); // const float PointerLength = 4.00f; @@ -423,15 +427,13 @@ namespace Conformance // Render into each of the separate swapchains using the projection layer view fov and pose. for (size_t view = 0; view < views.size(); view++) { - compositionHelper.AcquireWaitReleaseImage(swapchains[view], // - [&](const XrSwapchainImageBaseHeader* swapchainImage) { - GetGlobalData().graphicsPlugin->ClearImageSlice(swapchainImage); - const_cast(projLayer->views[view].fov) = views[view].fov; - const_cast(projLayer->views[view].pose) = views[view].pose; - GetGlobalData().graphicsPlugin->RenderView( - projLayer->views[view], swapchainImage, - RenderParams().Draw(renderedCubes)); - }); + compositionHelper.AcquireWaitReleaseImage(swapchains[view], [&](const XrSwapchainImageBaseHeader* swapchainImage) { + GetGlobalData().graphicsPlugin->ClearImageSlice(swapchainImage); + const_cast(projLayer->views[view].fov) = views[view].fov; + const_cast(projLayer->views[view].pose) = views[view].pose; + GetGlobalData().graphicsPlugin->RenderView(projLayer->views[view], swapchainImage, + RenderParams().Draw(renderedCubes)); + }); } layers.push_back({reinterpret_cast(projLayer)}); @@ -480,8 +482,10 @@ namespace Conformance auto makeActionSuggestedBindings = [&](XrInstance instance, bool testExtension) -> const std::vector { // Set up the actions. - const std::array subactionPaths{StringToPath(instance, "/user/hand/left"), - StringToPath(instance, "/user/hand/right")}; + const std::array subactionPaths{ + StringToPath(instance, "/user/hand/left"), + StringToPath(instance, "/user/hand/right"), + }; { XrActionSetCreateInfo actionSetInfo{XR_TYPE_ACTION_SET_CREATE_INFO}; @@ -589,10 +593,10 @@ namespace Conformance std::shared_ptr leftHandInputDevice = CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, compositionHelper.GetSession(), - simpleInteractionProfile, handPaths[0], GetSimpleInteractionProfile().InputSourcePaths); + simpleInteractionProfile, handPaths[0], GetSimpleInteractionProfile().BindingPaths); std::shared_ptr rightHandInputDevice = CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, compositionHelper.GetSession(), - simpleInteractionProfile, handPaths[1], GetSimpleInteractionProfile().InputSourcePaths); + simpleInteractionProfile, handPaths[1], GetSimpleInteractionProfile().BindingPaths); // gripPoseAction and gripSurfacePoseAction are populated here const std::vector bindings = makeActionSuggestedBindings(instance, testExtension); diff --git a/src/conformance/conformance_test/test_XR_EXT_plane_detection.cpp b/src/conformance/conformance_test/test_XR_EXT_plane_detection.cpp index 80bd2ff9..c7063b14 100644 --- a/src/conformance/conformance_test/test_XR_EXT_plane_detection.cpp +++ b/src/conformance/conformance_test/test_XR_EXT_plane_detection.cpp @@ -189,8 +189,8 @@ namespace Conformance GetInstanceExtensionFunction(instance, "xrGetPlaneDetectionStateEXT"); auto xrGetPlaneDetectionsEXT = GetInstanceExtensionFunction(instance, "xrGetPlaneDetectionsEXT"); - const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL, Pose::Identity); - const XrSpace viewSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_VIEW, Pose::Identity); + const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL); + const XrSpace viewSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_VIEW); // Set up composition projection layer and swapchains (one swapchain per view). std::vector swapchains; @@ -205,16 +205,13 @@ namespace Conformance } } - const std::vector subactionPaths{StringToPath(compositionHelper.GetInstance(), "/user/hand/left"), - StringToPath(compositionHelper.GetInstance(), "/user/hand/right")}; - XrActionSet actionSet; XrAction completeAction; { XrActionSetCreateInfo actionSetInfo{XR_TYPE_ACTION_SET_CREATE_INFO}; strcpy(actionSetInfo.actionSetName, "plane_detection_test"); strcpy(actionSetInfo.localizedActionSetName, "Plane Detection Test"); - XRC_CHECK_THROW_XRCMD(xrCreateActionSet(compositionHelper.GetInstance(), &actionSetInfo, &actionSet)) + XRC_CHECK_THROW_XRCMD(xrCreateActionSet(instance, &actionSetInfo, &actionSet)) XrActionCreateInfo actionInfo{XR_TYPE_ACTION_CREATE_INFO}; actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; @@ -224,15 +221,15 @@ namespace Conformance } const std::vector bindings = { - {completeAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/select/click")}, - {completeAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/select/click")}, + {completeAction, StringToPath(instance, "/user/hand/left/input/select/click")}, + {completeAction, StringToPath(instance, "/user/hand/right/input/select/click")}, }; XrInteractionProfileSuggestedBinding suggestedBindings{XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING}; - suggestedBindings.interactionProfile = StringToPath(compositionHelper.GetInstance(), "/interaction_profiles/khr/simple_controller"); + suggestedBindings.interactionProfile = StringToPath(instance, "/interaction_profiles/khr/simple_controller"); suggestedBindings.suggestedBindings = bindings.data(); suggestedBindings.countSuggestedBindings = (uint32_t)bindings.size(); - XRC_CHECK_THROW_XRCMD(xrSuggestInteractionProfileBindings(compositionHelper.GetInstance(), &suggestedBindings)) + XRC_CHECK_THROW_XRCMD(xrSuggestInteractionProfileBindings(instance, &suggestedBindings)) XrSessionActionSetsAttachInfo attachInfo{XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO}; attachInfo.actionSets = &actionSet; @@ -497,8 +494,8 @@ namespace Conformance auto xrCreatePlaneDetectorEXT = GetInstanceExtensionFunction(instance, "xrCreatePlaneDetectorEXT"); auto xrDestroyPlaneDetectorEXT = GetInstanceExtensionFunction(instance, "xrDestroyPlaneDetectorEXT"); auto xrBeginPlaneDetectionEXT = GetInstanceExtensionFunction(instance, "xrBeginPlaneDetectionEXT"); - const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL, Pose::Identity); - const XrSpace viewSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_VIEW, Pose::Identity); + const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL); + const XrSpace viewSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_VIEW); // Set up composition projection layer and swapchains (one swapchain per view). std::vector swapchains; @@ -638,8 +635,8 @@ namespace Conformance auto xrGetPlanePolygonBufferEXT = GetInstanceExtensionFunction(instance, "xrGetPlanePolygonBufferEXT"); - const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL, Pose::Identity); - const XrSpace viewSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_VIEW, Pose::Identity); + const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL); + const XrSpace viewSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_VIEW); // Set up composition projection layer and swapchains (one swapchain per view). std::vector swapchains; diff --git a/src/conformance/conformance_test/test_XR_MSFT_controller_model.cpp b/src/conformance/conformance_test/test_XR_MSFT_controller_model.cpp index 4bf00f1e..7df145d6 100644 --- a/src/conformance/conformance_test/test_XR_MSFT_controller_model.cpp +++ b/src/conformance/conformance_test/test_XR_MSFT_controller_model.cpp @@ -20,6 +20,7 @@ #include "utilities/throw_helpers.h" #include "utilities/types_and_constants.h" #include "utilities/utils.h" +#include "utilities/xr_math_operators.h" #include #include @@ -31,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -138,22 +138,26 @@ namespace Conformance CompositionHelper compositionHelper("XR_MSFT_controller_model", {"XR_MSFT_controller_model"}); XrInstance instance = compositionHelper.GetInstance(); + XrSession session = compositionHelper.GetSession(); ExtensionDataForXR_MSFT_controller_model ext(instance); ActionLayerManager actionLayerManager(compositionHelper); XrPath simpleKHR = StringToPath(instance, "/interaction_profiles/microsoft/motion_controller"); XrPath leftHandPath{StringToPath(instance, "/user/hand/left")}; - std::shared_ptr leftHandInputDevice = CreateTestDevice( - &actionLayerManager, &compositionHelper.GetInteractionManager(), instance, compositionHelper.GetSession(), simpleKHR, - leftHandPath, GetInteractionProfile(InteractionProfileIndex::Profile_microsoft_motion_controller).InputSourcePaths); + std::shared_ptr leftHandInputDevice = + CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, simpleKHR, leftHandPath, + GetInteractionProfile(InteractionProfileIndex::Profile_microsoft_motion_controller).BindingPaths); XrPath rightHandPath{StringToPath(instance, "/user/hand/right")}; - std::shared_ptr rightHandInputDevice = CreateTestDevice( - &actionLayerManager, &compositionHelper.GetInteractionManager(), instance, compositionHelper.GetSession(), simpleKHR, - rightHandPath, GetInteractionProfile(InteractionProfileIndex::Profile_microsoft_motion_controller).InputSourcePaths); + std::shared_ptr rightHandInputDevice = + CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, simpleKHR, rightHandPath, + GetInteractionProfile(InteractionProfileIndex::Profile_microsoft_motion_controller).BindingPaths); - const std::vector subactionPaths{leftHandPath, rightHandPath}; + const std::array subactionPaths{ + leftHandPath, + rightHandPath, + }; XrActionSet actionSet; XrAction gripPoseAction; @@ -169,8 +173,6 @@ namespace Conformance actionInfo.actionType = XR_ACTION_TYPE_POSE_INPUT; strcpy(actionInfo.actionName, "grip_pose"); strcpy(actionInfo.localizedActionName, "Grip pose"); - actionInfo.subactionPaths = subactionPaths.data(); - actionInfo.countSubactionPaths = (uint32_t)subactionPaths.size(); REQUIRE_RESULT_UNQUALIFIED_SUCCESS(xrCreateAction(actionSet, &actionInfo, &gripPoseAction)); } @@ -200,14 +202,12 @@ namespace Conformance actionSpaceCreateInfo.subactionPath = leftHandInputDevice->TopLevelPath(); actionSpaceCreateInfo.action = gripPoseAction; XrSpace gripSpace; - XRC_CHECK_THROW_XRCMD(xrCreateActionSpace(compositionHelper.GetSession(), &actionSpaceCreateInfo, &gripSpace)); + XRC_CHECK_THROW_XRCMD(xrCreateActionSpace(session, &actionSpaceCreateInfo, &gripSpace)); gripSpaces.push_back(gripSpace); } actionLayerManager.SyncActionsUntilFocusWithMessage(syncInfo); - XrSession session = compositionHelper.GetSession(); - std::vector modelKeys; std::map pathsAndKeys; // std::vector> pathsAndKeys; @@ -216,7 +216,7 @@ namespace Conformance [&]() { actionLayerManager.IterateFrame(); - xrSyncActions(compositionHelper.GetSession(), &syncInfo); + xrSyncActions(session, &syncInfo); for (XrPath subactionPath : subactionPaths) { if (pathsAndKeys.count(subactionPath)) { @@ -288,11 +288,11 @@ namespace Conformance std::string warn; bool loadedModel = loader.LoadBinaryFromMemory(&model, &err, &warn, modelBuffer.data(), (unsigned int)modelBuffer.size()); if (!warn.empty()) { - ReportF("glTF WARN: %s", &warn); + ReportF("glTF WARN: %s", warn.c_str()); } if (!err.empty()) { - ReportF("glTF ERR: %s", &err); + ReportF("glTF ERR: %s", err.c_str()); } if (!loadedModel) { @@ -330,9 +330,10 @@ namespace Conformance CompositionHelper compositionHelper("XR_MSFT_controller_model_inte...", {"XR_MSFT_controller_model"}); XrInstance instance = compositionHelper.GetInstance(); + XrSession session = compositionHelper.GetSession(); ExtensionDataForXR_MSFT_controller_model ext(instance); - const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL, Pose::Identity); + const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL); // Set up composition projection layer and swapchains (one swapchain per view). std::vector swapchains; @@ -358,18 +359,21 @@ namespace Conformance }; Hand hands[2] = {}; - hands[0].subactionPath = StringToPath(compositionHelper.GetInstance(), "/user/hand/left"); - hands[1].subactionPath = StringToPath(compositionHelper.GetInstance(), "/user/hand/right"); + hands[0].subactionPath = StringToPath(instance, "/user/hand/left"); + hands[1].subactionPath = StringToPath(instance, "/user/hand/right"); // Set up the actions. - const std::array subactionPaths{hands[0].subactionPath, hands[1].subactionPath}; + const std::array subactionPaths{ + hands[0].subactionPath, + hands[1].subactionPath, + }; XrActionSet actionSet; XrAction completeAction, gripPoseAction; { XrActionSetCreateInfo actionSetInfo{XR_TYPE_ACTION_SET_CREATE_INFO}; strcpy(actionSetInfo.actionSetName, "interaction_test"); strcpy(actionSetInfo.localizedActionSetName, "Interaction Test"); - XRC_CHECK_THROW_XRCMD(xrCreateActionSet(compositionHelper.GetInstance(), &actionSetInfo, &actionSet)); + XRC_CHECK_THROW_XRCMD(xrCreateActionSet(instance, &actionSetInfo, &actionSet)); XrActionCreateInfo actionInfo{XR_TYPE_ACTION_CREATE_INFO}; actionInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; @@ -390,31 +394,30 @@ namespace Conformance } const std::vector bindings = { - {completeAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/menu/click")}, - {completeAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/menu/click")}, - {gripPoseAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/grip/pose")}, - {gripPoseAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/grip/pose")}, + {completeAction, StringToPath(instance, "/user/hand/left/input/menu/click")}, + {completeAction, StringToPath(instance, "/user/hand/right/input/menu/click")}, + {gripPoseAction, StringToPath(instance, "/user/hand/left/input/grip/pose")}, + {gripPoseAction, StringToPath(instance, "/user/hand/right/input/grip/pose")}, }; XrInteractionProfileSuggestedBinding suggestedBindings{XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING}; - suggestedBindings.interactionProfile = StringToPath(compositionHelper.GetInstance(), "/interaction_profiles/khr/simple_controller"); + suggestedBindings.interactionProfile = StringToPath(instance, "/interaction_profiles/khr/simple_controller"); suggestedBindings.suggestedBindings = bindings.data(); suggestedBindings.countSuggestedBindings = (uint32_t)bindings.size(); - XRC_CHECK_THROW_XRCMD(xrSuggestInteractionProfileBindings(compositionHelper.GetInstance(), &suggestedBindings)); + XRC_CHECK_THROW_XRCMD(xrSuggestInteractionProfileBindings(instance, &suggestedBindings)); XrSessionActionSetsAttachInfo attachInfo{XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO}; attachInfo.actionSets = &actionSet; attachInfo.countActionSets = 1; - XRC_CHECK_THROW_XRCMD(xrAttachSessionActionSets(compositionHelper.GetSession(), &attachInfo)); + XRC_CHECK_THROW_XRCMD(xrAttachSessionActionSets(session, &attachInfo)); compositionHelper.BeginSession(); - XrSession session = compositionHelper.GetSession(); auto& graphicsPlugin = GetGlobalData().graphicsPlugin; // Create the instructional quad layer placed to the left. XrCompositionLayerQuad* const instructionsQuad = compositionHelper.CreateQuadLayer(compositionHelper.CreateStaticSwapchainImage(CreateTextImage(1024, 768, instructions, 48)), - localSpace, 1, {{0, 0, 0, 1}, {-1.5f, 0, -0.3f}}); + localSpace, 1, {Quat::Identity, {-1.5f, 0, -0.3f}}); instructionsQuad->pose.orientation = Quat::FromAxisAngle(Up, DegToRad(70)); // Initialize an XrSpace for each hand @@ -423,7 +426,7 @@ namespace Conformance spaceCreateInfo.subactionPath = hand.subactionPath; spaceCreateInfo.action = gripPoseAction; spaceCreateInfo.poseInActionSpace = Pose::Identity; - XRC_CHECK_THROW_XRCMD(xrCreateActionSpace(compositionHelper.GetSession(), &spaceCreateInfo, &hand.space)); + XRC_CHECK_THROW_XRCMD(xrCreateActionSpace(session, &spaceCreateInfo, &hand.space)); } auto update = [&](const XrFrameState& frameState) { @@ -434,15 +437,14 @@ namespace Conformance XrActionsSyncInfo syncInfo{XR_TYPE_ACTIONS_SYNC_INFO}; syncInfo.activeActionSets = activeActionSets.data(); syncInfo.countActiveActionSets = (uint32_t)activeActionSets.size(); - XRC_CHECK_THROW_XRCMD(xrSyncActions(compositionHelper.GetSession(), &syncInfo)); + XRC_CHECK_THROW_XRCMD(xrSyncActions(session, &syncInfo)); // Check if user has requested to complete the test. { XrActionStateGetInfo completeActionGetInfo{XR_TYPE_ACTION_STATE_GET_INFO}; completeActionGetInfo.action = completeAction; XrActionStateBoolean completeActionState{XR_TYPE_ACTION_STATE_BOOLEAN}; - XRC_CHECK_THROW_XRCMD( - xrGetActionStateBoolean(compositionHelper.GetSession(), &completeActionGetInfo, &completeActionState)); + XRC_CHECK_THROW_XRCMD(xrGetActionStateBoolean(session, &completeActionGetInfo, &completeActionState)); if (completeActionState.currentState == XR_TRUE && completeActionState.changedSinceLastSync) { return false; } @@ -516,15 +518,13 @@ namespace Conformance // Render into each of the separate swapchains using the projection layer view fov and pose. for (size_t view = 0; view < views.size(); view++) { - compositionHelper.AcquireWaitReleaseImage(swapchains[view], // - [&](const XrSwapchainImageBaseHeader* swapchainImage) { - GetGlobalData().graphicsPlugin->ClearImageSlice(swapchainImage, 0); - const_cast(projLayer->views[view].fov) = views[view].fov; - const_cast(projLayer->views[view].pose) = views[view].pose; - GetGlobalData().graphicsPlugin->RenderView( - projLayer->views[view], swapchainImage, - RenderParams().Draw(renderedCubes).Draw(renderedGLTFs)); - }); + compositionHelper.AcquireWaitReleaseImage(swapchains[view], [&](const XrSwapchainImageBaseHeader* swapchainImage) { + GetGlobalData().graphicsPlugin->ClearImageSlice(swapchainImage); + const_cast(projLayer->views[view].fov) = views[view].fov; + const_cast(projLayer->views[view].pose) = views[view].pose; + GetGlobalData().graphicsPlugin->RenderView(projLayer->views[view], swapchainImage, + RenderParams().Draw(renderedCubes).Draw(renderedGLTFs)); + }); } layers.push_back({reinterpret_cast(projLayer)}); @@ -538,7 +538,7 @@ namespace Conformance return true; }; - RenderLoop(compositionHelper.GetSession(), update).Loop(); + RenderLoop(session, update).Loop(); } } // namespace Conformance diff --git a/src/conformance/conformance_test/test_XR_VARJO_quad_views.cpp b/src/conformance/conformance_test/test_XR_VARJO_quad_views.cpp index 5feb36db..7ac1c65b 100644 --- a/src/conformance/conformance_test/test_XR_VARJO_quad_views.cpp +++ b/src/conformance/conformance_test/test_XR_VARJO_quad_views.cpp @@ -143,7 +143,7 @@ namespace Conformance true); XrSession session = compositionHelper.GetSession(); - XrSpace viewSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_VIEW, Pose::Identity); + XrSpace viewSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_VIEW); InteractionManager& interactionManager = compositionHelper.GetInteractionManager(); interactionManager.AttachActionSets(); @@ -212,7 +212,7 @@ namespace Conformance InteractiveLayerManager interactiveLayerManager(compositionHelper, "projection_separate.png", "Stereo inset views."); XrSession session = compositionHelper.GetSession(); - XrSpace viewSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_VIEW, Pose::Identity); + XrSpace viewSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_VIEW); InteractionManager& interactionManager = compositionHelper.GetInteractionManager(); interactionManager.AttachActionSets(); diff --git a/src/conformance/conformance_test/test_XrCompositionLayerProjection.cpp b/src/conformance/conformance_test/test_XrCompositionLayerProjection.cpp index c1755d96..a0f12c94 100644 --- a/src/conformance/conformance_test/test_XrCompositionLayerProjection.cpp +++ b/src/conformance/conformance_test/test_XrCompositionLayerProjection.cpp @@ -191,14 +191,16 @@ namespace Conformance } { + // Make sure you can submit at least 16 projection layers successfully INFO("XR_MIN_COMPOSITION_LAYERS_SUPPORTED layers"); XrFrameState frameState = waitAndBeginFrame(); std::vector views = locateViews(frameState); - std::vector minQuadLayers(XR_MIN_COMPOSITION_LAYERS_SUPPORTED, + std::vector minProjLayers(XR_MIN_COMPOSITION_LAYERS_SUPPORTED, {views, session.spaceVector.front(), createColorSwapchainSubImage}); std::vector minLayers; // Convert into an array of pointers (needed by xrEndFrame). - std::transform(minQuadLayers.begin(), minQuadLayers.end(), std::back_inserter(minLayers), + std::transform(minProjLayers.begin(), minProjLayers.end(), std::back_inserter(minLayers), [](ProjectionLayerWithViews& q) { return (void*)&q.Layer; }); + // If you hit a "limit exceeded" here, rerun: it should be possible for your runtime to succeed here. CHECK(XR_SUCCESS == endFrame(frameState, minLayers)); } } diff --git a/src/conformance/conformance_test/test_actions.cpp b/src/conformance/conformance_test/test_actions.cpp index b4bc19a1..cd89dd7b 100644 --- a/src/conformance/conformance_test/test_actions.cpp +++ b/src/conformance/conformance_test/test_actions.cpp @@ -39,6 +39,7 @@ #include #include +#include #include #include #include @@ -264,9 +265,12 @@ namespace Conformance SECTION("Duplicate subaction paths") { - XrPath subactionPaths[2] = {StringToPath(instance, "/user/head"), StringToPath(instance, "/user/head")}; + const std::array subactionPaths = { + StringToPath(instance, "/user/head"), + StringToPath(instance, "/user/head"), + }; actionCreateInfo.countSubactionPaths = 2; - actionCreateInfo.subactionPaths = subactionPaths; + actionCreateInfo.subactionPaths = subactionPaths.data(); REQUIRE_RESULT(xrCreateAction(actionSet, &actionCreateInfo, &action), XR_ERROR_PATH_UNSUPPORTED); } @@ -559,16 +563,16 @@ namespace Conformance CAPTURE(ipMetadata.InteractionProfilePathString); bindings.interactionProfile = StringToPath(instance, ipMetadata.InteractionProfilePathString); bindings.countSuggestedBindings = 1; - for (const auto& inputSourcePathData : ipMetadata.InputSourcePaths) { - CAPTURE(inputSourcePathData.Path); - CAPTURE(inputSourcePathData.Type); + for (const auto& bindingPathData : ipMetadata.BindingPaths) { + CAPTURE(bindingPathData.Path); + CAPTURE(bindingPathData.Type); - if (!SatisfiedByDefault(inputSourcePathData.Availability)) { + if (!SatisfiedByDefault(bindingPathData.Availability)) { continue; } XrAction selectedAction; - switch (inputSourcePathData.Type) { + switch (bindingPathData.Type) { case XR_ACTION_TYPE_BOOLEAN_INPUT: selectedAction = boolAction; break; @@ -585,7 +589,7 @@ namespace Conformance selectedAction = hapticAction; } - XrActionSuggestedBinding suggestedBindings{selectedAction, StringToPath(instance, inputSourcePathData.Path)}; + XrActionSuggestedBinding suggestedBindings{selectedAction, StringToPath(instance, bindingPathData.Path)}; bindings.suggestedBindings = &suggestedBindings; REQUIRE_RESULT(xrSuggestInteractionProfileBindings(instance, &bindings), XR_SUCCESS); } @@ -683,7 +687,7 @@ namespace Conformance strcpy(actionCreateInfo.actionName, "test_haptic_action_name"); REQUIRE_RESULT(xrCreateAction(actionSet, &actionCreateInfo, &hapticAction), XR_SUCCESS); - auto setupBinding = [&](const InputSourcePathAvailData& pathData) { + auto setupBinding = [&](const BindingPathData& pathData) { CAPTURE(pathData.Path); CAPTURE(pathData.Type); @@ -725,8 +729,8 @@ namespace Conformance if (SatisfiedByDefault(ipMetadata.Availability)) { DYNAMIC_SECTION(ipMetadata.InteractionProfileShortname << " Expect Available") { - for (const auto& inputSourcePathData : ipMetadata.InputSourcePaths) { - setupBinding(inputSourcePathData); + for (const auto& bindingPathData : ipMetadata.BindingPaths) { + setupBinding(bindingPathData); } } } @@ -734,8 +738,8 @@ namespace Conformance // Not available by default DYNAMIC_SECTION(ipMetadata.InteractionProfileShortname << " Expect Unavailable") { - for (const auto& inputSourcePathData : ipMetadata.InputSourcePaths) { - setupBinding(inputSourcePathData); + for (const auto& bindingPathData : ipMetadata.BindingPaths) { + setupBinding(bindingPathData); } } } @@ -780,7 +784,7 @@ namespace Conformance std::shared_ptr inputDevice = CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, StringToPath(instance, GetSimpleInteractionProfile().InteractionProfilePathString), path, - GetSimpleInteractionProfile().InputSourcePaths); + GetSimpleInteractionProfile().BindingPaths); compositionHelper.GetInteractionManager().AddActionSet(actionSet); @@ -1122,17 +1126,17 @@ namespace Conformance XrPath interactionProfilePath = StringToPath(instance, interactionProfileName); bool bindingSuggested = false; - for (auto& bindings : interactionProfile.InputSourcePaths) { + for (auto& bindingPathData : interactionProfile.BindingPaths) { // We use the same pattern as the rest of the action conformance suite // and only bind the boolean actions. Note that we bind "boolAction" // to *every* boolean input, not just the first one. - if (bindings.Type != XR_ACTION_TYPE_BOOLEAN_INPUT) { + if (bindingPathData.Type != XR_ACTION_TYPE_BOOLEAN_INPUT) { continue; } - if (!SatisfiedByDefault(bindings.Availability)) { + if (!SatisfiedByDefault(bindingPathData.Availability)) { continue; } - XrActionSuggestedBinding binding = {boolAction, StringToPath(instance, bindings.Path)}; + XrActionSuggestedBinding binding = {boolAction, StringToPath(instance, bindingPathData.Path)}; interactionManager.AddActionBindings(interactionProfilePath, {binding}); bindingSuggested = true; } @@ -1160,7 +1164,7 @@ namespace Conformance std::shared_ptr inputDevice = CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, StringToPath(instance, GetSimpleInteractionProfile().InteractionProfilePathString), userHandLeftXrPath, - GetSimpleInteractionProfile().InputSourcePaths); + GetSimpleInteractionProfile().BindingPaths); // This function calls xrSuggestInteractionProfileBindings() before attaching the actionsets interactionManager.AttachActionSets(&interactionProfileOrder); @@ -1237,13 +1241,13 @@ namespace Conformance std::shared_ptr leftHandInputDevice = CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, StringToPath(instance, GetSimpleInteractionProfile().InteractionProfilePathString), leftHandPath, - GetSimpleInteractionProfile().InputSourcePaths); + GetSimpleInteractionProfile().BindingPaths); XrPath rightHandPath{StringToPath(instance, "/user/hand/right")}; std::shared_ptr rightHandInputDevice = CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, StringToPath(instance, GetSimpleInteractionProfile().InteractionProfilePathString), rightHandPath, - GetSimpleInteractionProfile().InputSourcePaths); + GetSimpleInteractionProfile().BindingPaths); XrActionsSyncInfo syncInfo{XR_TYPE_ACTIONS_SYNC_INFO}; XrActiveActionSet activeActionSet{actionSet}; @@ -1361,13 +1365,13 @@ namespace Conformance XrPath leftHandPath{StringToPath(instance, "/user/hand/left")}; std::shared_ptr leftHandInputDevice = CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, - simpleControllerInteractionProfile, leftHandPath, GetSimpleInteractionProfile().InputSourcePaths); + simpleControllerInteractionProfile, leftHandPath, GetSimpleInteractionProfile().BindingPaths); std::string rightHandPathString = "/user/hand/right"; XrPath rightHandPath{StringToPath(instance, "/user/hand/right")}; std::shared_ptr rightHandInputDevice = CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, - simpleControllerInteractionProfile, rightHandPath, GetSimpleInteractionProfile().InputSourcePaths); + simpleControllerInteractionProfile, rightHandPath, GetSimpleInteractionProfile().BindingPaths); bool leftUnderTest = GetGlobalData().leftHandUnderTest; std::string defaultDevicePathStr = leftUnderTest ? leftHandPathString : rightHandPathString; @@ -2065,7 +2069,7 @@ namespace Conformance { struct ActionInfo { - InputSourcePathAvailData Data; + BindingPathData Data; XrAction Action{XR_NULL_HANDLE}; XrAction XAction{XR_NULL_HANDLE}; // Set if type is vector2f XrAction YAction{XR_NULL_HANDLE}; // Set if type is vector2f @@ -2077,7 +2081,7 @@ namespace Conformance constexpr float cEpsilon = 0.1f; constexpr float cLargeEpsilon = 0.15f; - auto TestInteractionProfile = [&](const InteractionProfileAvailMetadata& ipMetadata, const std::string& topLevelPathString) { + auto TestInteractionProfile = [&](const InteractionProfileAvailMetadata& ipMetadata, const std::string& topLevelUserPathString) { CompositionHelper compositionHelper("Input device state query"); XrInstance instance = compositionHelper.GetInstance(); XrSession session = compositionHelper.GetSession(); @@ -2086,16 +2090,16 @@ namespace Conformance actionLayerManager.WaitForSessionFocusWithMessage(); - XrPath interactionProfile = StringToPath(instance, ipMetadata.InteractionProfilePathString); - XrPath inputDevicePath{StringToPath(instance, topLevelPathString.data())}; + XrPath interactionProfilePath = StringToPath(instance, ipMetadata.InteractionProfilePathString); + XrPath topLevelUserPath{StringToPath(instance, topLevelUserPathString.data())}; std::shared_ptr inputDevice = - CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, interactionProfile, - inputDevicePath, ipMetadata.InputSourcePaths); + CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, interactionProfilePath, + topLevelUserPath, ipMetadata.BindingPaths); XrActionSet actionSet{XR_NULL_HANDLE}; - std::string actionSetName = "state_query_test_action_set_" + std::to_string(inputDevicePath); - std::string localizedActionSetName = "State Query Test Action Set " + std::to_string(inputDevicePath); + std::string actionSetName = "state_query_test_action_set_" + std::to_string(topLevelUserPath); + std::string localizedActionSetName = "State Query Test Action Set " + std::to_string(topLevelUserPath); XrActionSetCreateInfo actionSetCreateInfo{XR_TYPE_ACTION_SET_CREATE_INFO}; strcpy(actionSetCreateInfo.localizedActionSetName, localizedActionSetName.c_str()); @@ -2109,54 +2113,54 @@ namespace Conformance "state query test action " + std::to_string(uniqueActionNameCounter)}; }; - auto shouldExercisePath = [&ipMetadata](const InputSourcePathAvailData& inputSourceData) -> bool { - if (inputSourceData.systemOnly) { + auto shouldExercisePath = [&ipMetadata](const BindingPathData& bindingPathData) -> bool { + if (bindingPathData.systemOnly) { return false; } if (strcmp(ipMetadata.InteractionProfileShortname, "oculus/touch_controller") == 0 && - ends_with(inputSourceData.Path, "/input/thumbrest/touch")) { + ends_with(bindingPathData.Path, "/input/thumbrest/touch")) { // Rift S and Quest 1 controllers lack thumbrests. return false; } if (strcmp(ipMetadata.InteractionProfileShortname, "ext/hand_interaction_ext") == 0 && - ends_with(inputSourceData.Path, "/input/aim_activate_ext/value")) { + ends_with(bindingPathData.Path, "/input/aim_activate_ext/value")) { // aim_activate_ext/value does not require that the values coming back // actually be floats, they can also be boolean so this is hard for // us to exercise. return false; } - if (!SatisfiedByDefault(inputSourceData.Availability)) { + if (!SatisfiedByDefault(bindingPathData.Availability)) { return false; } return true; }; - auto InputSourceDataForTopLevelPath = [&]() { - std::vector ret; - for (const InputSourcePathAvailData& inputSourceData : ipMetadata.InputSourcePaths) { - if (!starts_with(inputSourceData.Path, topLevelPathString)) { + auto BindingPathDataForTopLevelUserPath = [&]() { + std::vector ret; + for (const BindingPathData& bindingPathData : ipMetadata.BindingPaths) { + if (!starts_with(bindingPathData.Path, topLevelUserPathString)) { continue; } - ret.push_back(inputSourceData); + ret.push_back(bindingPathData); } return ret; }; - auto ActionsForTopLevelPath = [&](XrActionType type) -> std::vector { - auto inputSourceDataList = InputSourceDataForTopLevelPath(); + auto ActionsForTopLevelUserPath = [&](XrActionType type) -> std::vector { + auto bindingPathDataList = BindingPathDataForTopLevelUserPath(); std::vector actions; - for (const InputSourcePathAvailData& inputSourceData : inputSourceDataList) { - if (type != inputSourceData.Type) { + for (const BindingPathData& bindingPathData : bindingPathDataList) { + if (type != bindingPathData.Type) { continue; } - if (!shouldExercisePath(inputSourceData)) { + if (!shouldExercisePath(bindingPathData)) { continue; } // Skip /x or /y components since we handle those with the parent Vector2f. - const std::string pathString = inputSourceData.Path; + const std::string pathString = bindingPathData.Path; std::cmatch bindingPathRegexMatch; REQUIRE_MSG(std::regex_match(pathString.data(), bindingPathRegexMatch, cInteractionSourcePathRegex), - "input source path does not match require format"); + "binding path does not match required format"); if (bindingPathRegexMatch[7].matched) { if (bindingPathRegexMatch[7] == "x" || bindingPathRegexMatch[7] == "y") { #if !defined(NDEBUG) @@ -2171,18 +2175,18 @@ namespace Conformance XrAction yAction{XR_NULL_HANDLE}; XrActionCreateInfo actionCreateInfo{XR_TYPE_ACTION_CREATE_INFO}; - actionCreateInfo.actionType = inputSourceData.Type; + actionCreateInfo.actionType = bindingPathData.Type; auto actionNames = GetActionNames(); strcpy(actionCreateInfo.localizedActionName, std::get<1>(actionNames).c_str()); strcpy(actionCreateInfo.actionName, std::get<0>(actionNames).c_str()); REQUIRE_RESULT(xrCreateAction(actionSet, &actionCreateInfo, &action), XR_SUCCESS); - XrPath bindingPath = StringToPath(instance, inputSourceData.Path); - compositionHelper.GetInteractionManager().AddActionBindings(interactionProfile, {{action, bindingPath}}); + XrPath bindingPath = StringToPath(instance, bindingPathData.Path); + compositionHelper.GetInteractionManager().AddActionBindings(interactionProfilePath, {{action, bindingPath}}); ActionInfo info{}; - switch (inputSourceData.Type) { + switch (bindingPathData.Type) { case XR_ACTION_TYPE_BOOLEAN_INPUT: // Need to see 0 1 info.UnseenValues = {false, true}; @@ -2221,18 +2225,18 @@ namespace Conformance strcpy(actionCreateInfo.actionName, std::get<0>(actionNames).c_str()); REQUIRE_RESULT(xrCreateAction(actionSet, &actionCreateInfo, &xAction), XR_SUCCESS); - std::string xSubBindingPath = std::string(inputSourceData.Path) + "/x"; + std::string xSubBindingPath = std::string(bindingPathData.Path) + "/x"; bindingPath = StringToPath(instance, xSubBindingPath); - compositionHelper.GetInteractionManager().AddActionBindings(interactionProfile, {{xAction, bindingPath}}); + compositionHelper.GetInteractionManager().AddActionBindings(interactionProfilePath, {{xAction, bindingPath}}); actionNames = GetActionNames(); strcpy(actionCreateInfo.localizedActionName, std::get<1>(actionNames).c_str()); strcpy(actionCreateInfo.actionName, std::get<0>(actionNames).c_str()); REQUIRE_RESULT(xrCreateAction(actionSet, &actionCreateInfo, &yAction), XR_SUCCESS); - std::string ySubBindingPath = std::string(inputSourceData.Path) + "/y"; + std::string ySubBindingPath = std::string(bindingPathData.Path) + "/y"; bindingPath = StringToPath(instance, ySubBindingPath); - compositionHelper.GetInteractionManager().AddActionBindings(interactionProfile, {{yAction, bindingPath}}); + compositionHelper.GetInteractionManager().AddActionBindings(interactionProfilePath, {{yAction, bindingPath}}); break; } case XR_ACTION_TYPE_POSE_INPUT: @@ -2240,20 +2244,20 @@ namespace Conformance break; case XR_ACTION_TYPE_MAX_ENUM: default: - WARN("Unexpected action type " << inputSourceData.Type); + WARN("Unexpected action type " << bindingPathData.Type); break; } #if !defined(NDEBUG) // Debug UnseenValues - std::string unseen = inputSourceData.Path; + std::string unseen = bindingPathData.Path; for (auto key : info.UnseenValues) { unseen += " " + std::to_string(key); } ReportF("Keys for %s", unseen.c_str()); #endif - info.Data = inputSourceData; + info.Data = bindingPathData; info.Action = action; info.XAction = xAction; info.YAction = yAction; @@ -2264,17 +2268,17 @@ namespace Conformance return actions; }; auto ActionsForTopLevelPathCoerced = [&](XrActionType type, XrActionType coercionType) -> std::vector { - auto inputSourceDataList = InputSourceDataForTopLevelPath(); + auto bindingPathDataList = BindingPathDataForTopLevelUserPath(); auto HasSubpathOfType = [&](std::string parentPath, XrActionType type) { - for (const InputSourcePathAvailData& inputSourceData : inputSourceDataList) { - if (inputSourceData.Type != type) { + for (const BindingPathData& bindingPathData : bindingPathDataList) { + if (bindingPathData.Type != type) { continue; } - if (!shouldExercisePath(inputSourceData)) { + if (!shouldExercisePath(bindingPathData)) { continue; } - auto prefixedByParentPath = starts_with(inputSourceData.Path, parentPath); + auto prefixedByParentPath = starts_with(bindingPathData.Path, parentPath); if (prefixedByParentPath) { return true; } @@ -2283,31 +2287,31 @@ namespace Conformance }; std::vector actions; - for (const InputSourcePathAvailData& inputSourceData : inputSourceDataList) { - if (type != inputSourceData.Type) { + for (const BindingPathData& bindingPathData : bindingPathDataList) { + if (type != bindingPathData.Type) { continue; } - if (!shouldExercisePath(inputSourceData)) { + if (!shouldExercisePath(bindingPathData)) { continue; } // If we are using the parent path, the runtime should map it if there is a subpath // e.g. .../thumbstick may get bound to .../thumbstick/click which is valid - const std::string pathString = inputSourceData.Path; + const std::string pathString = bindingPathData.Path; std::cmatch bindingPathRegexMatch; REQUIRE_MSG(std::regex_match(pathString.data(), bindingPathRegexMatch, cInteractionSourcePathRegex), - "input source path does not match require format"); + "binding path does not match required format"); if (bindingPathRegexMatch[5].matched) { if (coercionType == XR_ACTION_TYPE_BOOLEAN_INPUT && - HasSubpathOfType(inputSourceData.Path, XR_ACTION_TYPE_BOOLEAN_INPUT)) { + HasSubpathOfType(bindingPathData.Path, XR_ACTION_TYPE_BOOLEAN_INPUT)) { continue; } if (coercionType == XR_ACTION_TYPE_FLOAT_INPUT && - HasSubpathOfType(inputSourceData.Path, XR_ACTION_TYPE_FLOAT_INPUT)) { + HasSubpathOfType(bindingPathData.Path, XR_ACTION_TYPE_FLOAT_INPUT)) { continue; } if (coercionType == XR_ACTION_TYPE_POSE_INPUT && - HasSubpathOfType(inputSourceData.Path, XR_ACTION_TYPE_POSE_INPUT)) { + HasSubpathOfType(bindingPathData.Path, XR_ACTION_TYPE_POSE_INPUT)) { continue; } } @@ -2320,11 +2324,11 @@ namespace Conformance strcpy(actionCreateInfo.actionName, std::get<0>(actionNames).c_str()); REQUIRE_RESULT(xrCreateAction(actionSet, &actionCreateInfo, &action), XR_SUCCESS); - XrPath bindingPath = StringToPath(instance, inputSourceData.Path); - compositionHelper.GetInteractionManager().AddActionBindings(interactionProfile, {{action, bindingPath}}); + XrPath bindingPath = StringToPath(instance, bindingPathData.Path); + compositionHelper.GetInteractionManager().AddActionBindings(interactionProfilePath, {{action, bindingPath}}); ActionInfo info{}; - info.Data = inputSourceData; + info.Data = bindingPathData; info.Data.Type = coercionType; info.Action = action; actions.push_back(info); @@ -2333,7 +2337,7 @@ namespace Conformance return actions; }; auto ActionOfTypeForTopLevelPath = [&](XrActionType type) -> ActionInfo { - auto inputSourceDataList = InputSourceDataForTopLevelPath(); + auto bindingPathDataList = BindingPathDataForTopLevelUserPath(); XrAction action{XR_NULL_HANDLE}; XrActionCreateInfo actionCreateInfo{XR_TYPE_ACTION_CREATE_INFO}; @@ -2343,16 +2347,16 @@ namespace Conformance strcpy(actionCreateInfo.actionName, std::get<0>(actionNames).c_str()); REQUIRE_RESULT(xrCreateAction(actionSet, &actionCreateInfo, &action), XR_SUCCESS); - for (const InputSourcePathAvailData& inputSourceData : inputSourceDataList) { - if (type != inputSourceData.Type) { + for (const BindingPathData& bindingPathData : bindingPathDataList) { + if (type != bindingPathData.Type) { continue; } - if (!shouldExercisePath(inputSourceData)) { + if (!shouldExercisePath(bindingPathData)) { continue; } - XrPath bindingPath = StringToPath(instance, inputSourceData.Path); - compositionHelper.GetInteractionManager().AddActionBindings(interactionProfile, {{action, bindingPath}}); + XrPath bindingPath = StringToPath(instance, bindingPathData.Path); + compositionHelper.GetInteractionManager().AddActionBindings(interactionProfilePath, {{action, bindingPath}}); } ActionInfo info{}; @@ -2368,11 +2372,11 @@ namespace Conformance }; // Actions for each of source of a type - auto booleanActions = ActionsForTopLevelPath(XR_ACTION_TYPE_BOOLEAN_INPUT); - auto floatActions = ActionsForTopLevelPath(XR_ACTION_TYPE_FLOAT_INPUT); - auto vectorActions = ActionsForTopLevelPath(XR_ACTION_TYPE_VECTOR2F_INPUT); - auto poseActions = ActionsForTopLevelPath(XR_ACTION_TYPE_POSE_INPUT); - auto hapticActions = ActionsForTopLevelPath(XR_ACTION_TYPE_VIBRATION_OUTPUT); + auto booleanActions = ActionsForTopLevelUserPath(XR_ACTION_TYPE_BOOLEAN_INPUT); + auto floatActions = ActionsForTopLevelUserPath(XR_ACTION_TYPE_FLOAT_INPUT); + auto vectorActions = ActionsForTopLevelUserPath(XR_ACTION_TYPE_VECTOR2F_INPUT); + auto poseActions = ActionsForTopLevelUserPath(XR_ACTION_TYPE_POSE_INPUT); + auto hapticActions = ActionsForTopLevelUserPath(XR_ACTION_TYPE_VIBRATION_OUTPUT); // Single actions bound to all of a type auto allBooleanAction = ActionOfTypeForTopLevelPath(XR_ACTION_TYPE_BOOLEAN_INPUT); @@ -2406,8 +2410,8 @@ namespace Conformance actionLayerManager.SyncActionsUntilFocusWithMessage(syncInfo); XrInteractionProfileState interactionProfileState{XR_TYPE_INTERACTION_PROFILE_STATE}; - REQUIRE_RESULT(xrGetCurrentInteractionProfile(session, inputDevicePath, &interactionProfileState), XR_SUCCESS); - REQUIRE(interactionProfile == interactionProfileState.interactionProfile); + REQUIRE_RESULT(xrGetCurrentInteractionProfile(session, topLevelUserPath, &interactionProfileState), XR_SUCCESS); + REQUIRE(interactionProfilePath == interactionProfileState.interactionProfile); XrActionStateBoolean booleanState{XR_TYPE_ACTION_STATE_BOOLEAN}; PoisonStructContents(booleanState); @@ -2421,7 +2425,7 @@ namespace Conformance { XrActionStateGetInfo getInfo{XR_TYPE_ACTION_STATE_GET_INFO}; - actionLayerManager.DisplayMessage("Use all controller inputs on\n" + topLevelPathString); + actionLayerManager.DisplayMessage("Use all controller inputs on\n" + topLevelUserPathString); if (!GetGlobalData().IsUsingConformanceAutomation()) { actionLayerManager.Sleep_For(1s); @@ -2718,7 +2722,7 @@ namespace Conformance waitForCombinedPrefix = ","; } std::string prompt = "Used " + std::to_string(seenActions.size()) + "/" + std::to_string(actionCount) + - " inputs on:\n" + topLevelPathString + waitForCombined + nextActionPrompt; + " inputs on:\n" + topLevelUserPathString + waitForCombined + nextActionPrompt; actionLayerManager.DisplayMessage(prompt); return false; @@ -2796,7 +2800,7 @@ namespace Conformance selectedBooleanActions = booleanActions; } - XrPath inputSourcePath = StringToPath(instance, selectedBooleanActions[0].Data.Path); + XrPath bindingPath = StringToPath(instance, selectedBooleanActions[0].Data.Path); XrAction currentBooleanAction{XR_NULL_HANDLE}; auto GetBooleanButtonState = [&]() -> bool { @@ -2838,9 +2842,9 @@ namespace Conformance { // For automation only - inputDevice->SetButtonStateBool(inputSourcePath, false, true); + inputDevice->SetButtonStateBool(bindingPath, false, true); actionLayerManager.SyncActionsUntilFocusWithMessage(syncInfo); - inputDevice->SetButtonStateBool(inputSourcePath, true, true); + inputDevice->SetButtonStateBool(bindingPath, true, true); } currentBooleanAction = XR_NULL_HANDLE; WaitUntilPredicateWithTimeout( @@ -2854,7 +2858,7 @@ namespace Conformance { // For automation only - inputDevice->SetButtonStateBool(inputSourcePath, false, true); + inputDevice->SetButtonStateBool(bindingPath, false, true); } REQUIRE_RESULT(xrStopHapticFeedback(session, &hapticActionInfo), XR_SUCCESS); @@ -2877,9 +2881,9 @@ namespace Conformance XR_SUCCESS); { - inputDevice->SetButtonStateBool(inputSourcePath, false, true); + inputDevice->SetButtonStateBool(bindingPath, false, true); actionLayerManager.SyncActionsUntilFocusWithMessage(syncInfo); - inputDevice->SetButtonStateBool(inputSourcePath, true, true); + inputDevice->SetButtonStateBool(bindingPath, true, true); } currentBooleanAction = XR_NULL_HANDLE; WaitUntilPredicateWithTimeout( @@ -2893,7 +2897,7 @@ namespace Conformance { // For automation only - inputDevice->SetButtonStateBool(inputSourcePath, false, true); + inputDevice->SetButtonStateBool(bindingPath, false, true); } } @@ -2909,25 +2913,25 @@ namespace Conformance INFO("Boolean->Float"); for (const auto& booleanToFloatActionData : floatActionsCoercedToBoolean) { CAPTURE(booleanToFloatActionData.Data.Path); - XrPath inputSourcePath = StringToPath(instance, booleanToFloatActionData.Data.Path); + XrPath bindingPath = StringToPath(instance, booleanToFloatActionData.Data.Path); XrActionStateGetInfo getInfo{XR_TYPE_ACTION_STATE_GET_INFO}; getInfo.action = booleanToFloatActionData.Action; - inputDevice->SetButtonStateFloat(inputSourcePath, 0.0f, cEpsilon, false, actionSet); + inputDevice->SetButtonStateFloat(bindingPath, 0.0f, cEpsilon, false, actionSet); REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &booleanState), XR_SUCCESS); REQUIRE(booleanState.isActive); REQUIRE_FALSE(booleanState.currentState); - inputDevice->SetButtonStateFloat(inputSourcePath, 1.0f, cEpsilon, false, actionSet); + inputDevice->SetButtonStateFloat(bindingPath, 1.0f, cEpsilon, false, actionSet); REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &booleanState), XR_SUCCESS); REQUIRE(booleanState.isActive); REQUIRE(booleanState.currentState); REQUIRE(booleanState.lastChangeTime > 0); - inputDevice->SetButtonStateFloat(inputSourcePath, 0.0f, cEpsilon, false, actionSet); + inputDevice->SetButtonStateFloat(bindingPath, 0.0f, cEpsilon, false, actionSet); REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &booleanState), XR_SUCCESS); REQUIRE(booleanState.isActive); @@ -2938,25 +2942,25 @@ namespace Conformance INFO("Float->Boolean"); for (const auto& floatToBooleanActionData : booleanActionsCoercedToFloat) { CAPTURE(floatToBooleanActionData.Data.Path); - XrPath inputSourcePath = StringToPath(instance, floatToBooleanActionData.Data.Path); + XrPath bindingPath = StringToPath(instance, floatToBooleanActionData.Data.Path); XrActionStateGetInfo getInfo{XR_TYPE_ACTION_STATE_GET_INFO}; getInfo.action = floatToBooleanActionData.Action; - inputDevice->SetButtonStateBool(inputSourcePath, false, false, actionSet); + inputDevice->SetButtonStateBool(bindingPath, false, false, actionSet); REQUIRE_RESULT(xrGetActionStateFloat(session, &getInfo, &floatState), XR_SUCCESS); REQUIRE(floatState.isActive); REQUIRE(floatState.currentState == Catch::Approx(0.0f).margin(cLargeEpsilon)); - inputDevice->SetButtonStateBool(inputSourcePath, true, false, actionSet); + inputDevice->SetButtonStateBool(bindingPath, true, false, actionSet); REQUIRE_RESULT(xrGetActionStateFloat(session, &getInfo, &floatState), XR_SUCCESS); REQUIRE(floatState.isActive); REQUIRE(floatState.currentState == Catch::Approx(1.0f).margin(cLargeEpsilon)); REQUIRE(floatState.lastChangeTime > 0); - inputDevice->SetButtonStateBool(inputSourcePath, false, false, actionSet); + inputDevice->SetButtonStateBool(bindingPath, false, false, actionSet); REQUIRE_RESULT(xrGetActionStateFloat(session, &getInfo, &floatState), XR_SUCCESS); REQUIRE(floatState.isActive); @@ -3345,7 +3349,7 @@ namespace Conformance std::shared_ptr handInputDevice = CreateTestDevice( &actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, simpleControllerInteractionProfile, - StringToPath(instance, useLeftHand ? "/user/hand/left" : "/user/hand/right"), GetSimpleInteractionProfile().InputSourcePaths); + StringToPath(instance, useLeftHand ? "/user/hand/left" : "/user/hand/right"), GetSimpleInteractionProfile().BindingPaths); compositionHelper.GetInteractionManager().AddActionSet(actionSet); compositionHelper.GetInteractionManager().AddActionBindings( @@ -3426,11 +3430,11 @@ namespace Conformance std::shared_ptr leftHandInputDevice = CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, - simpleControllerInteractionProfile, leftHandPath, GetSimpleInteractionProfile().InputSourcePaths); + simpleControllerInteractionProfile, leftHandPath, GetSimpleInteractionProfile().BindingPaths); std::shared_ptr rightHandInputDevice = CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, - simpleControllerInteractionProfile, rightHandPath, GetSimpleInteractionProfile().InputSourcePaths); + simpleControllerInteractionProfile, rightHandPath, GetSimpleInteractionProfile().BindingPaths); compositionHelper.GetInteractionManager().AddActionSet(actionSet); compositionHelper.GetInteractionManager().AddActionBindings( @@ -3894,7 +3898,7 @@ namespace Conformance std::shared_ptr inputDevice = CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, StringToPath(instance, GetSimpleInteractionProfile().InteractionProfilePathString), path, - GetSimpleInteractionProfile().InputSourcePaths); + GetSimpleInteractionProfile().BindingPaths); compositionHelper.GetInteractionManager().AddActionSet(actionSet); compositionHelper.GetInteractionManager().AddActionBindings( diff --git a/src/conformance/conformance_test/test_glTFRendering.cpp b/src/conformance/conformance_test/test_glTFRendering.cpp index 8286198c..e7e3a45c 100644 --- a/src/conformance/conformance_test/test_glTFRendering.cpp +++ b/src/conformance/conformance_test/test_glTFRendering.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -45,7 +46,7 @@ namespace Conformance // Each test case will configure the layer manager with its own instructions and image InteractiveLayerManager interactiveLayerManager(compositionHelper, nullptr, "glTF rendering"); - const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL, Pose::Identity); + const XrSpace localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL); // Set up composition projection layer and swapchains (one swapchain per view). std::vector swapchains; @@ -60,7 +61,10 @@ namespace Conformance } } - const std::vector subactionPaths{StringToPath(instance, "/user/hand/left"), StringToPath(instance, "/user/hand/right")}; + const std::array subactionPaths{ + StringToPath(instance, "/user/hand/left"), + StringToPath(instance, "/user/hand/right"), + }; XrActionSet actionSet; XrAction gripPoseAction; @@ -176,7 +180,7 @@ namespace Conformance "Barn Lamp KTX2 Texture Test", "This model uses many unimplemented extensions." " To pass, simply ensure that text is visible on the side of the lamp.", - nullptr, + "AnisotropyBarnLamp.png", {Quat::FromAxisAngle({1, 0, 0}, DegToRad(-90)), {0, 0, 0}}, 1.0f}, }; diff --git a/src/conformance/framework/CMakeLists.txt b/src/conformance/framework/CMakeLists.txt index 9f89b954..5e93fe0c 100644 --- a/src/conformance/framework/CMakeLists.txt +++ b/src/conformance/framework/CMakeLists.txt @@ -43,6 +43,7 @@ add_subdirectory(gltf) set(VULKAN_SHADERS "${CMAKE_CURRENT_SOURCE_DIR}/vulkan_shaders/frag.glsl" "${CMAKE_CURRENT_SOURCE_DIR}/vulkan_shaders/vert.glsl" + "${CMAKE_CURRENT_SOURCE_DIR}/vulkan_shaders/comp.glsl" ) run_xr_xml_generate( diff --git a/src/conformance/framework/composition_utils.cpp b/src/conformance/framework/composition_utils.cpp index 9ce923c1..967a6f2b 100644 --- a/src/conformance/framework/composition_utils.cpp +++ b/src/conformance/framework/composition_utils.cpp @@ -612,7 +612,7 @@ namespace Conformance } BaseProjectionLayerHelper::BaseProjectionLayerHelper(CompositionHelper& compositionHelper, XrReferenceSpaceType spaceType) - : m_compositionHelper(compositionHelper), m_localSpace(compositionHelper.CreateReferenceSpace(spaceType, Pose::Identity)) + : m_compositionHelper(compositionHelper), m_localSpace(compositionHelper.CreateReferenceSpace(spaceType)) { const std::vector viewProperties = compositionHelper.EnumerateConfigurationViews(); diff --git a/src/conformance/framework/composition_utils.h b/src/conformance/framework/composition_utils.h index f29f77cf..94e917c6 100644 --- a/src/conformance/framework/composition_utils.h +++ b/src/conformance/framework/composition_utils.h @@ -435,8 +435,8 @@ namespace Conformance }}); } - m_viewSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_VIEW, XrPosef{{0, 0, 0, 1}, {0, 0, 0}}); - m_localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL, XrPosef{{0, 0, 0, 1}, {0, 0, 0}}); + m_viewSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_VIEW); + m_localSpace = compositionHelper.CreateReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL); // description quad to the left, example image quad to the right, counter-rotated 15 degrees towards the viewer m_descriptionQuadSpace = compositionHelper.CreateReferenceSpace( diff --git a/src/conformance/framework/conformance_framework.cpp b/src/conformance/framework/conformance_framework.cpp index fce1ff4c..53d826a4 100644 --- a/src/conformance/framework/conformance_framework.cpp +++ b/src/conformance/framework/conformance_framework.cpp @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -108,7 +109,7 @@ namespace Conformance GlobalData& globalData = GetGlobalData(); std::string reportString; - AppendSprintf(reportString, "Random seed used: %llu\n", globalData.randEngine.GetSeed()); + AppendSprintf(reportString, "Random seed used: %" PRIu64 "\n", globalData.randEngine.GetSeed()); AppendSprintf(reportString, "API version: %u.%u.%u\n", XR_VERSION_MAJOR(apiVersion), XR_VERSION_MINOR(apiVersion), XR_VERSION_PATCH(apiVersion)); AppendSprintf(reportString, "Graphics system: %s\n", globalData.options.graphicsPlugin.c_str()); @@ -133,8 +134,8 @@ namespace Conformance AppendSprintf(reportString, "Handle invalidation tested: %s\n", globalData.options.invalidHandleValidation ? "yes" : "no"); AppendSprintf(reportString, "Type invalidation tested: %s\n", globalData.options.invalidTypeValidation ? "yes" : "no"); AppendSprintf(reportString, "Non-disconnectable devices: %s\n", globalData.options.nonDisconnectableDevices ? "yes" : "no"); - AppendSprintf(reportString, "Test Success Count: %zu\n", TestSuccessCount()); - AppendSprintf(reportString, "Test Failure Count: %zu\n", TestFailureCount()); + AppendSprintf(reportString, "Test Success Count: %zu\n", static_cast(TestSuccessCount())); + AppendSprintf(reportString, "Test Failure Count: %zu\n", static_cast(TestFailureCount())); if (TestFailureCount() > 0) { AppendSprintf(reportString, "Tests with failures:\n"); for (auto const& pair : results) { diff --git a/src/conformance/framework/gltf_helpers.cpp b/src/conformance/framework/gltf_helpers.cpp index ad6ec5c7..1171f15a 100644 --- a/src/conformance/framework/gltf_helpers.cpp +++ b/src/conformance/framework/gltf_helpers.cpp @@ -27,7 +27,7 @@ namespace Conformance loader.SetImageLoader(GltfHelper::PassThroughKTX2, nullptr); bool loadedModel = loader.LoadBinaryFromMemory(model.get(), &err, &warn, data.data(), (unsigned int)data.size()); if (!warn.empty()) { - ReportF("glTF WARN: %s", &warn); + ReportF("glTF WARN: %s", warn.c_str()); } if (!err.empty()) { diff --git a/src/conformance/framework/graphics_plugin.h b/src/conformance/framework/graphics_plugin.h index e284b8eb..595fe407 100644 --- a/src/conformance/framework/graphics_plugin.h +++ b/src/conformance/framework/graphics_plugin.h @@ -401,6 +401,11 @@ namespace Conformance /// Render a list of drawables to a swapchain image. ClearImageSlice must be called first to clear internal state. virtual void RenderView(const XrCompositionLayerProjectionView& layerView, const XrSwapchainImageBaseHeader* colorSwapchainImage, const RenderParams& params) = 0; + + /// Clears a slice to an arbitrary color with a compute shader. Can only be used with XR_SWAPCHAIN_USAGE_UNORDERED_ACCESS_BIT. + /// @todo The actual rendering is only implemented for Vulkan. On OpenGL (ES) this is a noop, on D3D11/D3D12 it checks whether the appropriate flags are set. + virtual void RenderClearImageSliceCompute(const XrCompositionLayerProjectionView& layerView, + const XrSwapchainImageBaseHeader* colorSwapchainImage, XrColor4f color) = 0; }; /// Create a graphics plugin for the graphics API specified in the options. diff --git a/src/conformance/framework/graphics_plugin_d3d11.cpp b/src/conformance/framework/graphics_plugin_d3d11.cpp index 89fadcaa..3cd3a99d 100644 --- a/src/conformance/framework/graphics_plugin_d3d11.cpp +++ b/src/conformance/framework/graphics_plugin_d3d11.cpp @@ -216,6 +216,9 @@ namespace Conformance void RenderView(const XrCompositionLayerProjectionView& layerView, const XrSwapchainImageBaseHeader* colorSwapchainImage, const RenderParams& params) override; + void RenderClearImageSliceCompute(const XrCompositionLayerProjectionView& layerView, + const XrSwapchainImageBaseHeader* colorSwapchainImage, XrColor4f color) override; + private: ComPtr CreateRenderTargetView(D3D11SwapchainImageData& swapchainData, uint32_t imageIndex, uint32_t imageArrayIndex) const; @@ -500,7 +503,37 @@ namespace Conformance bool D3D11GraphicsPlugin::GetSwapchainCreateTestParameters(int64_t imageFormat, SwapchainCreateTestParameters* swapchainTestParameters) { - return GetDxgiSwapchainCreateTestParameters(imageFormat, swapchainTestParameters); + bool success = GetDxgiSwapchainCreateTestParameters(imageFormat, swapchainTestParameters); + + if (!success) { + return success; + } + + /// @todo Conformance::GetDxgiSwapchainTestMap() has no access to our d3d11 objects, therefore remove the wrongly added unordered access here. + bool supportsUnorderedAccess = false; + D3D11_FEATURE_DATA_FORMAT_SUPPORT formatSupport = {(DXGI_FORMAT)imageFormat}; + if (SUCCEEDED(d3d11Device->CheckFeatureSupport(D3D11_FEATURE_FORMAT_SUPPORT, &formatSupport, sizeof(formatSupport)))) { + if ((formatSupport.OutFormatSupport & D3D11_FORMAT_SUPPORT_TYPED_UNORDERED_ACCESS_VIEW) != 0) { + supportsUnorderedAccess = true; + } + } + else { + WARN("Failed to check format support."); + } + + swapchainTestParameters->usageFlagsVector.erase( + std::remove_if(swapchainTestParameters->usageFlagsVector.begin(), swapchainTestParameters->usageFlagsVector.end(), + [&](auto uf) { + if ((uf & XR_SWAPCHAIN_USAGE_UNORDERED_ACCESS_BIT) != 0) { + if (!supportsUnorderedAccess) { + return true; + } + } + return false; + }), + swapchainTestParameters->usageFlagsVector.end()); + + return true; } bool D3D11GraphicsPlugin::ValidateSwapchainImages(int64_t /*imageFormat*/, const SwapchainCreateTestParameters* tp, @@ -824,6 +857,30 @@ namespace Conformance } } + void D3D11GraphicsPlugin::RenderClearImageSliceCompute(const XrCompositionLayerProjectionView& layerView, + const XrSwapchainImageBaseHeader* colorSwapchainImage, XrColor4f color) + { + (void)layerView; + (void)color; + + D3D11SwapchainImageData* swapchainData; + uint32_t imageIndex; + + std::tie(swapchainData, imageIndex) = m_swapchainImageDataMap.GetDataAndIndexFromBasePointer(colorSwapchainImage); + + ID3D11Texture2D* const colorTexture = swapchainData->GetTypedImage(imageIndex).texture; + + D3D11_TEXTURE2D_DESC desc{}; + colorTexture->GetDesc(&desc); + + REQUIRE((desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) != 0); + + bool defaultOrDynamicUsage = (desc.Usage == D3D11_USAGE_DEFAULT || desc.Usage == D3D11_USAGE_DYNAMIC); + REQUIRE(defaultOrDynamicUsage); + + /// @todo: implement actual rendering + } + std::shared_ptr CreateGraphicsPlugin_D3D11(std::shared_ptr platformPlugin) { return std::make_shared(platformPlugin); diff --git a/src/conformance/framework/graphics_plugin_d3d12.cpp b/src/conformance/framework/graphics_plugin_d3d12.cpp index 1a9a8ee3..d2b55ec6 100644 --- a/src/conformance/framework/graphics_plugin_d3d12.cpp +++ b/src/conformance/framework/graphics_plugin_d3d12.cpp @@ -367,6 +367,9 @@ namespace Conformance void RenderView(const XrCompositionLayerProjectionView& layerView, const XrSwapchainImageBaseHeader* colorSwapchainImage, const RenderParams& params) override; + void RenderClearImageSliceCompute(const XrCompositionLayerProjectionView& layerView, + const XrSwapchainImageBaseHeader* colorSwapchainImage, XrColor4f color) override; + void Flush() override; protected: @@ -675,7 +678,38 @@ namespace Conformance bool D3D12GraphicsPlugin::GetSwapchainCreateTestParameters(int64_t imageFormat, SwapchainCreateTestParameters* swapchainTestParameters) { - return GetDxgiSwapchainCreateTestParameters(imageFormat, swapchainTestParameters); + bool success = GetDxgiSwapchainCreateTestParameters(imageFormat, swapchainTestParameters); + if (!success) { + return success; + } + + /// @todo Conformance::GetDxgiSwapchainTestMap() has no access to our d3d12 objects, therefore remove the wrongly added unordered access here. + bool supportsUnorderedAccessStore = false; + D3D12_FEATURE_DATA_FORMAT_SUPPORT formatSupport = {(DXGI_FORMAT)imageFormat, D3D12_FORMAT_SUPPORT1_NONE, + D3D12_FORMAT_SUPPORT2_NONE}; + if (SUCCEEDED(d3d12Device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &formatSupport, sizeof(formatSupport)))) { + // check specifically for write support + if ((formatSupport.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE) != 0) { + supportsUnorderedAccessStore = true; + } + } + else { + WARN("Failed to check format support."); + } + + swapchainTestParameters->usageFlagsVector.erase( + std::remove_if(swapchainTestParameters->usageFlagsVector.begin(), swapchainTestParameters->usageFlagsVector.end(), + [&](auto uf) { + if ((uf & XR_SWAPCHAIN_USAGE_UNORDERED_ACCESS_BIT) != 0) { + if (!supportsUnorderedAccessStore) { + return true; + } + } + return false; + }), + swapchainTestParameters->usageFlagsVector.end()); + + return true; } bool D3D12GraphicsPlugin::ValidateSwapchainImages(int64_t /*imageFormat*/, const SwapchainCreateTestParameters* tp, @@ -1191,6 +1225,45 @@ namespace Conformance WaitForGpu(); } + void D3D12GraphicsPlugin::RenderClearImageSliceCompute(const XrCompositionLayerProjectionView& layerView, + const XrSwapchainImageBaseHeader* colorSwapchainImage, XrColor4f color) + { + (void)layerView; + (void)color; + + D3D12SwapchainImageData* swapchainData; + uint32_t imageIndex; + + std::tie(swapchainData, imageIndex) = m_swapchainImageDataMap.GetDataAndIndexFromBasePointer(colorSwapchainImage); + + ID3D12Resource* const colorTexture = swapchainData->GetTypedImage(imageIndex).texture; + { + auto& createInfo = swapchainData->GetCreateInfo(); + + D3D12_RESOURCE_FLAGS expectedFlags = D3D12_RESOURCE_FLAG_NONE; + D3D12_RESOURCE_STATES expectedState = D3D12_RESOURCE_STATE_COMMON; + + // D3D12_RESOURCE_FLAGS are additive + // D3D12_RESOURCE_STATES are mutually exclusive, therefore go in reverse order of precedence + if ((createInfo.usageFlags & XR_SWAPCHAIN_USAGE_UNORDERED_ACCESS_BIT) != 0) { + expectedFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + expectedState = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + } + if ((createInfo.usageFlags & XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT) != 0) { + expectedFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + expectedState = D3D12_RESOURCE_STATE_RENDER_TARGET; + } + + CAPTURE(expectedFlags); + CAPTURE(expectedState); + D3D12_RESOURCE_DESC desc = colorTexture->GetDesc(); + REQUIRE((desc.Flags & expectedFlags) == expectedFlags); + + /// @todo to verify expectedState either we need to find a way to query the D3D12_RESOURCE_STATES of an ID3D12Resource or attempt to render and see if that works. + } + /// @todo: implement actual rendering + } + void D3D12GraphicsPlugin::Flush() { if (m_queueWrapper) { diff --git a/src/conformance/framework/graphics_plugin_metal.cpp b/src/conformance/framework/graphics_plugin_metal.cpp index ae18e64d..e7015ee0 100644 --- a/src/conformance/framework/graphics_plugin_metal.cpp +++ b/src/conformance/framework/graphics_plugin_metal.cpp @@ -267,6 +267,9 @@ namespace Conformance void RenderView(const XrCompositionLayerProjectionView& layerView, const XrSwapchainImageBaseHeader* colorSwapchainImage, const RenderParams& params) override; + void RenderClearImageSliceCompute(const XrCompositionLayerProjectionView& layerView, + const XrSwapchainImageBaseHeader* colorSwapchainImage, XrColor4f color) override; + private: bool m_initialized{false}; XrGraphicsBindingMetalKHR m_graphicsBinding{XR_TYPE_GRAPHICS_BINDING_METAL_KHR}; @@ -936,6 +939,15 @@ namespace Conformance pCmd->commit(); } + void MetalGraphicsPlugin::RenderClearImageSliceCompute(const XrCompositionLayerProjectionView& layerView, + const XrSwapchainImageBaseHeader* colorSwapchainImage, XrColor4f color) + { + (void)layerView; + (void)colorSwapchainImage; + (void)color; + /// @todo: implement for Metal + } + // Private methods bool MetalGraphicsPlugin::InitializeResources() diff --git a/src/conformance/framework/graphics_plugin_opengl.cpp b/src/conformance/framework/graphics_plugin_opengl.cpp index 95f4d5d2..b7e9ddd1 100644 --- a/src/conformance/framework/graphics_plugin_opengl.cpp +++ b/src/conformance/framework/graphics_plugin_opengl.cpp @@ -437,6 +437,9 @@ namespace Conformance void RenderView(const XrCompositionLayerProjectionView& layerView, const XrSwapchainImageBaseHeader* colorSwapchainImage, const RenderParams& params) override; + void RenderClearImageSliceCompute(const XrCompositionLayerProjectionView& layerView, + const XrSwapchainImageBaseHeader* colorSwapchainImage, XrColor4f color) override; + private: bool initialized = false; bool deviceInitialized = false; @@ -1198,6 +1201,15 @@ namespace Conformance glBindFramebuffer(GL_FRAMEBUFFER, 0); } + void OpenGLGraphicsPlugin::RenderClearImageSliceCompute(const XrCompositionLayerProjectionView& layerView, + const XrSwapchainImageBaseHeader* colorSwapchainImage, XrColor4f color) + { + (void)layerView; + (void)colorSwapchainImage; + (void)color; + /// @todo: implement for OpenGL + } + std::shared_ptr CreateGraphicsPlugin_OpenGL(std::shared_ptr platformPlugin) { return std::make_shared(std::move(platformPlugin)); diff --git a/src/conformance/framework/graphics_plugin_opengles.cpp b/src/conformance/framework/graphics_plugin_opengles.cpp index e6255159..d2c933e0 100644 --- a/src/conformance/framework/graphics_plugin_opengles.cpp +++ b/src/conformance/framework/graphics_plugin_opengles.cpp @@ -308,6 +308,8 @@ namespace Conformance void RenderView(const XrCompositionLayerProjectionView& layerView, const XrSwapchainImageBaseHeader* colorSwapchainImage, const RenderParams& params) override; + void RenderClearImageSliceCompute(const XrCompositionLayerProjectionView& layerView, + const XrSwapchainImageBaseHeader* colorSwapchainImage, XrColor4f color) override; private: bool initialized{false}; @@ -1377,6 +1379,15 @@ namespace Conformance GL(glBindFramebuffer(GL_FRAMEBUFFER, 0)); } + void OpenGLESGraphicsPlugin::RenderClearImageSliceCompute(const XrCompositionLayerProjectionView& layerView, + const XrSwapchainImageBaseHeader* colorSwapchainImage, XrColor4f color) + { + (void)layerView; + (void)colorSwapchainImage; + (void)color; + /// @todo: implement for OpenGLES + } + } // namespace Conformance #endif // XR_USE_GRAPHICS_API_OPENGL_ES diff --git a/src/conformance/framework/graphics_plugin_vulkan.cpp b/src/conformance/framework/graphics_plugin_vulkan.cpp index 657abf20..19cc1337 100644 --- a/src/conformance/framework/graphics_plugin_vulkan.cpp +++ b/src/conformance/framework/graphics_plugin_vulkan.cpp @@ -14,6 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "utilities/array_size.h" #ifdef XR_USE_GRAPHICS_API_VULKAN #include "RGBAImage.h" #include "conformance_utils.h" @@ -53,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -129,20 +131,25 @@ namespace Conformance std::vector m_renderTarget; // per swapchain index RenderPass m_rp{}; Pipeline m_pipe{}; + Pipeline m_pipeCompute{}; void init(const VulkanDebugObjectNamer& namer, VkDevice device, uint32_t capacity, const VkExtent2D size, VkFormat colorFormat, - VkFormat depthFormat, VkSampleCountFlagBits sampleCount, const PipelineLayout& layout, const ShaderProgram& sp, + VkFormat depthFormat, VkSampleCountFlagBits sampleCount, const PipelineLayout& layout, + const PipelineLayout& computeLayout, const ShaderProgram& sp, const ShaderProgram& spCompute, const VkVertexInputBindingDescription& bindDesc, span attrDesc) { m_renderTarget.resize(capacity); m_rp.Create(namer, device, colorFormat, depthFormat, sampleCount); VkDynamicState dynamicStates[] = {VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_VIEWPORT}; m_pipe.Create(device, size, layout, m_rp, sp, bindDesc, attrDesc, dynamicStates); + + m_pipeCompute.Create(device, size, computeLayout, m_rp, spCompute, bindDesc, attrDesc, dynamicStates); } void Reset() { m_pipe.Reset(); + m_pipeCompute.Reset(); m_rp.Reset(); m_renderTarget.clear(); } @@ -151,19 +158,21 @@ namespace Conformance /// Vulkan data used per swapchain. One per XrSwapchain handle. class VulkanSwapchainImageData : public SwapchainImageDataBase { - void init(uint32_t capacity, VkFormat colorFormat, const PipelineLayout& layout, const ShaderProgram& sp, - const VkVertexInputBindingDescription& bindDesc, span attrDesc) + void init(uint32_t capacity, VkFormat colorFormat, const PipelineLayout& layout, const PipelineLayout& computeLayout, + const ShaderProgram& sp, const ShaderProgram& spCompute, const VkVertexInputBindingDescription& bindDesc, + span attrDesc) { m_depthBuffer.resize(capacity); for (auto& slice : m_slices) { - slice.init(m_namer, m_vkDevice, capacity, m_size, colorFormat, m_depthFormat, m_sampleCount, layout, sp, bindDesc, - attrDesc); + slice.init(m_namer, m_vkDevice, capacity, m_size, colorFormat, m_depthFormat, m_sampleCount, layout, computeLayout, sp, + spCompute, bindDesc, attrDesc); } } public: VulkanSwapchainImageData(const VulkanDebugObjectNamer& namer, uint32_t capacity, const XrSwapchainCreateInfo& swapchainCreateInfo, - VkDevice device, MemoryAllocator* memAllocator, const PipelineLayout& layout, const ShaderProgram& sp, + VkDevice device, MemoryAllocator* memAllocator, const PipelineLayout& layout, + const PipelineLayout& computeLayout, const ShaderProgram& sp, const ShaderProgram& spCompute, const VkVertexInputBindingDescription& bindDesc, span attrDesc) : SwapchainImageDataBase(XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR, capacity, swapchainCreateInfo) , m_namer(namer) @@ -173,13 +182,14 @@ namespace Conformance , m_sampleCount{(VkSampleCountFlagBits)swapchainCreateInfo.sampleCount} , m_slices(swapchainCreateInfo.arraySize) { - init(capacity, (VkFormat)swapchainCreateInfo.format, layout, sp, bindDesc, attrDesc); + init(capacity, (VkFormat)swapchainCreateInfo.format, layout, computeLayout, sp, spCompute, bindDesc, attrDesc); } VulkanSwapchainImageData(const VulkanDebugObjectNamer& namer, uint32_t capacity, const XrSwapchainCreateInfo& swapchainCreateInfo, XrSwapchain depthSwapchain, const XrSwapchainCreateInfo& depthSwapchainCreateInfo, VkDevice device, - MemoryAllocator* memAllocator, const PipelineLayout& layout, const ShaderProgram& sp, - const VkVertexInputBindingDescription& bindDesc, span attrDesc) + MemoryAllocator* memAllocator, const PipelineLayout& layout, const PipelineLayout& computeLayout, + const ShaderProgram& sp, const ShaderProgram& spCompute, const VkVertexInputBindingDescription& bindDesc, + span attrDesc) : SwapchainImageDataBase(XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR, capacity, swapchainCreateInfo, depthSwapchain, depthSwapchainCreateInfo) , m_namer(namer) @@ -190,7 +200,7 @@ namespace Conformance , m_depthFormat((VkFormat)depthSwapchainCreateInfo.format) , m_slices(swapchainCreateInfo.arraySize) { - init(capacity, (VkFormat)swapchainCreateInfo.format, layout, sp, bindDesc, attrDesc); + init(capacity, (VkFormat)swapchainCreateInfo.format, layout, computeLayout, sp, spCompute, bindDesc, attrDesc); } ~VulkanSwapchainImageData() override @@ -213,9 +223,18 @@ namespace Conformance renderPassBeginInfo->renderArea = renderArea; } - void BindPipeline(VkCommandBuffer buf, uint32_t arraySlice) + void BindPipeline(VkCommandBuffer buf, uint32_t arraySlice, enum ShaderProgramType programType = SHADER_PROGRAM_TYPE_GRAPHICS) { - vkCmdBindPipeline(buf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_slices[arraySlice].m_pipe.pipe); + switch (programType) { + case SHADER_PROGRAM_TYPE_GRAPHICS: + vkCmdBindPipeline(buf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_slices[arraySlice].m_pipe.pipe); + break; + case SHADER_PROGRAM_TYPE_COMPUTE: + vkCmdBindPipeline(buf, VK_PIPELINE_BIND_POINT_COMPUTE, m_slices[arraySlice].m_pipeCompute.pipe); + break; + default: + XRC_THROW("unknown programType"); + } } void TransitionLayout(uint32_t imageIndex, CmdBuffer* cmdBuffer, VkImageLayout newLayout) @@ -237,6 +256,11 @@ namespace Conformance return m_depthFormat; } + const std::vector& GetSlices() const + { + return m_slices; + } + protected: const XrSwapchainImageVulkanKHR& GetFallbackDepthSwapchainImage(uint32_t i) override { @@ -669,6 +693,9 @@ namespace Conformance void RenderView(const XrCompositionLayerProjectionView& layerView, const XrSwapchainImageBaseHeader* colorSwapchainImage, const RenderParams& params) override; + void RenderClearImageSliceCompute(const XrCompositionLayerProjectionView& layerView, + const XrSwapchainImageBaseHeader* colorSwapchainImage, XrColor4f color) override; + /// Get data on a known swapchain format const SwapchainFormatData& FindFormatData(int64_t format) const; @@ -714,9 +741,15 @@ namespace Conformance VkSemaphore m_vkDrawDone{VK_NULL_HANDLE}; MemoryAllocator m_memAllocator{}; - ShaderProgram m_shaderProgram{}; + ShaderProgram m_shaderProgram{SHADER_PROGRAM_TYPE_GRAPHICS}; + ShaderProgram m_computeShaderProgram{SHADER_PROGRAM_TYPE_COMPUTE}; CmdBuffer m_cmdBuffer{}; PipelineLayout m_pipelineLayout{}; + + PipelineLayout m_computePipelineLayout{}; + Conformance::ScopedVkDescriptorPool m_computeDescriptorPool; + VkDescriptorSet m_ComputeDescriptorSet; + MeshHandle m_cubeMesh{}; VectorWithGenerationCountedHandles m_meshes; // This is fine to be a shared_ptr because Model doesn't directly hold any graphics state. @@ -824,7 +857,7 @@ namespace Conformance } } - ReportF("%s (%s 0x%llx) %s", flagNames.c_str(), objName.c_str(), object, pCallbackData->pMessage); + ReportF("%s (%s 0x%" PRIu64 ") %s", flagNames.c_str(), objName.c_str(), object, pCallbackData->pMessage); return VK_FALSE; } @@ -986,6 +1019,25 @@ namespace Conformance return pfnCreateVulkanDeviceKHR(instance, createInfo, vulkanDevice, vulkanResult); } + static VkDescriptorPool CreateDescriptorPool(VkDevice device, uint32_t maxSets, uint32_t descriptorCount) + { + VkDescriptorPoolSize poolSizes[2]{}; + poolSizes[0].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + poolSizes[0].descriptorCount = descriptorCount; + + poolSizes[1].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + poolSizes[1].descriptorCount = descriptorCount; + + VkDescriptorPoolCreateInfo descriptorPoolInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO}; + descriptorPoolInfo.maxSets = maxSets; + descriptorPoolInfo.poolSizeCount = (uint32_t)ArraySize(poolSizes); + descriptorPoolInfo.pPoolSizes = poolSizes; + + VkDescriptorPool descriptorPool; + XRC_CHECK_THROW_VKCMD(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); + return descriptorPool; + }; + XrResult VulkanGraphicsPluginLegacy::CreateVulkanDeviceKHR(XrInstance instance, const XrVulkanDeviceCreateInfoKHR* createInfo, VkDevice* vulkanDevice, VkResult* vulkanResult) { @@ -1118,6 +1170,15 @@ namespace Conformance } } + VkDebugUtilsMessengerCreateInfoEXT debugInfo{VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT}; + debugInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; + debugInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; +#if !defined(NDEBUG) + debugInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT; +#endif + debugInfo.pfnUserCallback = debugMessageThunk; + debugInfo.pUserData = this; + VkResult err; { // Note: This cannot outlive the extensionNames above, since it's just a collection of views into that string! @@ -1181,6 +1242,7 @@ namespace Conformance appInfo.apiVersion = VK_API_VERSION_1_0; VkInstanceCreateInfo instInfo{VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO}; + instInfo.pNext = &debugInfo; instInfo.pApplicationInfo = &appInfo; instInfo.enabledLayerCount = (uint32_t)layers.size(); instInfo.ppEnabledLayerNames = layers.empty() ? nullptr : layers.data(); @@ -1207,14 +1269,6 @@ namespace Conformance (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(m_vkInstance, "vkDestroyDebugUtilsMessengerEXT"); if (vkCreateDebugUtilsMessengerEXT != nullptr && vkDestroyDebugUtilsMessengerEXT != nullptr) { - VkDebugUtilsMessengerCreateInfoEXT debugInfo{VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT}; - debugInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; - debugInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; -#if !defined(NDEBUG) - debugInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT; -#endif - debugInfo.pfnUserCallback = debugMessageThunk; - debugInfo.pUserData = this; XRC_CHECK_THROW_VKCMD(vkCreateDebugUtilsMessengerEXT(m_vkInstance, &debugInfo, nullptr, &m_vkDebugUtilsMessenger)); } @@ -1316,16 +1370,24 @@ namespace Conformance std::vector fragmentSPIRV = SPV_PREFIX #include "frag.spv" // IWYU pragma: keep SPV_SUFFIX; + std::vector computeSPIRV = SPV_PREFIX +#include "comp.spv" // IWYU pragma: keep + SPV_SUFFIX; #endif if (vertexSPIRV.empty()) XRC_THROW("Failed to compile vertex shader"); if (fragmentSPIRV.empty()) XRC_THROW("Failed to compile fragment shader"); + if (computeSPIRV.empty()) + XRC_THROW("Failed to compile compute shader"); m_shaderProgram.Init(m_vkDevice); m_shaderProgram.LoadVertexShader(vertexSPIRV); m_shaderProgram.LoadFragmentShader(fragmentSPIRV); + m_computeShaderProgram.Init(m_vkDevice); + m_computeShaderProgram.LoadComputeShader(computeSPIRV); + // Semaphore to block on draw complete VkSemaphoreCreateInfo semInfo{VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO}; XRC_CHECK_THROW_VKCMD(vkCreateSemaphore(m_vkDevice, &semInfo, nullptr, &m_vkDrawDone)); @@ -1338,6 +1400,21 @@ namespace Conformance XRC_CHECK_THROW_VKCMD( m_namer.SetName(VK_OBJECT_TYPE_PIPELINE_LAYOUT, (uint64_t)m_pipelineLayout.layout, "CTS graphics pipeline layout")); + m_computePipelineLayout.Create(m_vkDevice, SHADER_PROGRAM_TYPE_COMPUTE); + XRC_CHECK_THROW_VKCMD( + m_namer.SetName(VK_OBJECT_TYPE_PIPELINE_LAYOUT, (uint64_t)m_computePipelineLayout.layout, "CTS compute pipeline layout")); + XRC_CHECK_THROW_VKCMD(m_namer.SetName(VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)m_computePipelineLayout.descriptorSetLayout, + "CTS compute descriptor set layout")); + + // resources for compute pipeline + m_computeDescriptorPool.adopt(CreateDescriptorPool(m_vkDevice, 1, 1), m_vkDevice); + + VkDescriptorSetAllocateInfo allocInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + allocInfo.descriptorPool = m_computeDescriptorPool.get(); + allocInfo.descriptorSetCount = 1; + allocInfo.pSetLayouts = &m_computePipelineLayout.descriptorSetLayout; + XRC_CHECK_THROW_VKCMD(vkAllocateDescriptorSets(m_vkDevice, &allocInfo, &m_ComputeDescriptorSet)); + static_assert(sizeof(Geometry::Vertex) == 24, "Unexpected Vertex size"); m_cubeMesh = MakeCubeMesh(); @@ -1399,9 +1476,13 @@ namespace Conformance m_cmdBuffer.Reset(); m_pipelineLayout.Reset(); + m_computePipelineLayout.Reset(); m_shaderProgram.Reset(); + m_computeShaderProgram.Reset(); m_memAllocator.Reset(); + m_computeDescriptorPool.reset(); + #if defined(USE_MIRROR_WINDOW) m_swapchain.Reset(); m_swapchainImageData.clear(); @@ -1604,6 +1685,27 @@ namespace Conformance bool VulkanGraphicsPlugin::GetSwapchainCreateTestParameters(int64_t imageFormat, SwapchainCreateTestParameters* swapchainTestParameters) { *swapchainTestParameters = ::Conformance::GetSwapchainCreateTestParameters(GetSwapchainFormatData(), imageFormat); + + // Conformance::GetSwapchainCreateTestParameters has no access to our Vulkan objects, therefore the queries have to be made here. + + VkFormatProperties formatProperties{}; + vkGetPhysicalDeviceFormatProperties(m_vkPhysicalDevice, (VkFormat)imageFormat, &formatProperties); + + // we only care about optimal tiling + bool supportsStorageImage = (formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) != 0; + + swapchainTestParameters->usageFlagsVector.erase( + std::remove_if(swapchainTestParameters->usageFlagsVector.begin(), swapchainTestParameters->usageFlagsVector.end(), + [&](auto uf) { + if ((uf & XR_SWAPCHAIN_USAGE_UNORDERED_ACCESS_BIT) != 0) { + if (!supportsStorageImage) { + return true; + } + } + return false; + }), + swapchainTestParameters->usageFlagsVector.end()); + return true; } @@ -1719,9 +1821,9 @@ namespace Conformance ISwapchainImageData* VulkanGraphicsPlugin::AllocateSwapchainImageData(size_t size, const XrSwapchainCreateInfo& swapchainCreateInfo) { - auto typedResult = std::make_unique(m_namer, uint32_t(size), swapchainCreateInfo, m_vkDevice, - &m_memAllocator, m_pipelineLayout, m_shaderProgram, - VulkanMesh::c_bindingDesc, VulkanMesh::c_attrDesc); + auto typedResult = std::make_unique( + m_namer, uint32_t(size), swapchainCreateInfo, m_vkDevice, &m_memAllocator, m_pipelineLayout, m_computePipelineLayout, + m_shaderProgram, m_computeShaderProgram, VulkanMesh::c_bindingDesc, VulkanMesh::c_attrDesc); // Cast our derived type to the caller-expected type. auto ret = static_cast(typedResult.get()); @@ -1738,7 +1840,8 @@ namespace Conformance auto typedResult = std::make_unique( m_namer, uint32_t(size), colorSwapchainCreateInfo, depthSwapchain, depthSwapchainCreateInfo, m_vkDevice, &m_memAllocator, - m_pipelineLayout, m_shaderProgram, VulkanMesh::c_bindingDesc, VulkanMesh::c_attrDesc); + m_pipelineLayout, m_computePipelineLayout, m_shaderProgram, m_computeShaderProgram, VulkanMesh::c_bindingDesc, + VulkanMesh::c_attrDesc); // Cast our derived type to the caller-expected type. auto ret = static_cast(typedResult.get()); @@ -2134,6 +2237,171 @@ namespace Conformance #endif } + void VulkanGraphicsPlugin::RenderClearImageSliceCompute(const XrCompositionLayerProjectionView& layerView, + const XrSwapchainImageBaseHeader* colorSwapchainImage, XrColor4f color) + { + (void)colorSwapchainImage; + (void)color; + + VulkanSwapchainImageData* swapchainData; + uint32_t imageIndex; + + std::tie(swapchainData, imageIndex) = m_swapchainImageDataMap.GetDataAndIndexFromBasePointer(colorSwapchainImage); + + m_cmdBuffer.Clear(); + m_cmdBuffer.Begin(); + + CHECKPOINT(); + + const XrRect2Di& r = layerView.subImage.imageRect; + VkRect2D renderArea = {{r.offset.x, r.offset.y}, {uint32_t(r.extent.width), uint32_t(r.extent.height)}}; + SetViewportAndScissor(renderArea); + + // may be depth, stencil, or both + int64_t secondImageFormat = swapchainData->GetDepthFormat(); + const SwapchainFormatData& secondFormatData = FindFormatData(secondImageFormat); + VkImageAspectFlags secondAttachmentAspect = ComputeAspectFlags(secondFormatData); + + // Bind eye render target + VkRenderPassBeginInfo renderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + + // aka slice + auto imageArrayIndex = layerView.subImage.imageArrayIndex; + + swapchainData->BindRenderTarget(imageIndex, imageArrayIndex, renderArea, secondAttachmentAspect, &renderPassBeginInfo); + + if (!swapchainData->DepthSwapchainEnabled()) { + // Ensure self-made fallback depth is in the right layout + VkImageLayout layout = ComputeLayout(secondFormatData); + swapchainData->TransitionLayout(imageIndex, &m_cmdBuffer, layout); + } + + CHECKPOINT(); + + auto defaultSampler = std::make_shared(Pbr::VulkanTexture::CreateSampler(m_vkDevice), m_vkDevice); + + struct + { + float color[4]; + } ubo = {color.r, color.r, color.g, color.a}; + uint8_t* uboData = (uint8_t*)&ubo; + + VkBufferCreateInfo bufferCreateInfo{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + bufferCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + bufferCreateInfo.size = static_cast(sizeof(ubo)); + + Conformance::BufferAndMemory uboBuffer; + uboBuffer.Create(m_vkDevice, m_memAllocator, bufferCreateInfo); + XRC_CHECK_THROW_VKCMD(m_namer.SetName(VK_OBJECT_TYPE_BUFFER, (uint64_t)uboBuffer.buf, "CTS UBO buffer")); + uboBuffer.Update(m_vkDevice, {uboData, static_cast(bufferCreateInfo.size)}, 0); + + { + VkImageMemoryBarrier imgBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; + // Switch the destination image from COLOR_ATTACHMENT_OPTIMAL -> GENERAL + // + // XR_KHR_vulkan_enable / XR_KHR_vulkan_enable2 + // When an application acquires a swapchain image by calling xrAcquireSwapchainImage + // in a session created using XrGraphicsBindingVulkanKHR, the OpenXR runtime must + // guarantee that: + // - The image has a memory layout compatible with VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL + // for color images, or VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL for depth images. + // - The VkQueue specified in XrGraphicsBindingVulkanKHR has ownership of the image. + imgBarrier.srcAccessMask = 0; + imgBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imgBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + imgBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; + imgBarrier.srcQueueFamilyIndex = m_queueFamilyIndex; + imgBarrier.dstQueueFamilyIndex = m_queueFamilyIndex; + imgBarrier.image = swapchainData->GetTypedImage(imageIndex).image; + imgBarrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; + vkCmdPipelineBarrier(m_cmdBuffer.buf, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, + 1, &imgBarrier); + } + + { + // TODO texture array with multiple slices + assert(swapchainData->GetSlices().size() == 1); + VkImageView targetImageView = swapchainData->GetSlices()[0].m_renderTarget[imageIndex].colorView; + VkImageLayout targetImageLayout = VK_IMAGE_LAYOUT_GENERAL; + uint32_t targetImageBinding = 0; + uint32_t uboBinding = 1; + + VkDescriptorImageInfo targetImageInfo; + targetImageInfo.imageLayout = targetImageLayout; + targetImageInfo.imageView = targetImageView; + targetImageInfo.sampler = defaultSampler->get(); + + VkDescriptorBufferInfo uboInfo; + uboInfo.buffer = uboBuffer.buf; + uboInfo.offset = 0; + uboInfo.range = VK_WHOLE_SIZE; + + VkWriteDescriptorSet writeDescriptorSets[2]{}; + writeDescriptorSets[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[0].dstSet = m_ComputeDescriptorSet; + writeDescriptorSets[0].dstBinding = targetImageBinding; + writeDescriptorSets[0].descriptorCount = 1; + writeDescriptorSets[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + writeDescriptorSets[0].pImageInfo = &targetImageInfo; + + writeDescriptorSets[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSets[1].dstSet = m_ComputeDescriptorSet; + writeDescriptorSets[1].dstBinding = uboBinding; + writeDescriptorSets[1].descriptorCount = 1; + writeDescriptorSets[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + writeDescriptorSets[1].pBufferInfo = &uboInfo; + + vkUpdateDescriptorSets(m_vkDevice, (uint32_t)ArraySize(writeDescriptorSets), writeDescriptorSets, 0, NULL); + } + + swapchainData->BindPipeline(m_cmdBuffer.buf, imageArrayIndex, SHADER_PROGRAM_TYPE_COMPUTE); + + vkCmdBindDescriptorSets(m_cmdBuffer.buf, VK_PIPELINE_BIND_POINT_COMPUTE, m_computePipelineLayout.layout, 0, 1, + &m_ComputeDescriptorSet, 0, NULL); + + CHECKPOINT(); + + uint32_t widthDiv = (r.extent.width + 15) / 16; + uint32_t heightDiv = (r.extent.height + 15) / 16; + + vkCmdDispatch(m_cmdBuffer.buf, widthDiv, heightDiv, 1); + + CHECKPOINT(); + + { + VkImageMemoryBarrier imgBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; + // Switch the destination image from GENERAL -> COLOR_ATTACHMENT_OPTIMAL + // + // XR_KHR_vulkan_enable / XR_KHR_vulkan_enable2 + // When an application releases a swapchain image by calling xrReleaseSwapchainImage, in a + // session created using XrGraphicsBindingVulkanKHR, the OpenXR runtime must interpret the + // image as: + // + // - Having a memory layout compatible with VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL for + // color images, or VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL for depth images. + // - Being owned by the VkQueue specified in XrGraphicsBindingVulkanKHR. + imgBarrier.srcAccessMask = 0; + imgBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imgBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + imgBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + imgBarrier.srcQueueFamilyIndex = m_queueFamilyIndex; + imgBarrier.dstQueueFamilyIndex = m_queueFamilyIndex; + imgBarrier.image = swapchainData->GetTypedImage(imageIndex).image; + imgBarrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; + vkCmdPipelineBarrier(m_cmdBuffer.buf, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, + 1, &imgBarrier); + } + + CHECKPOINT(); + + m_cmdBuffer.End(); + m_cmdBuffer.Exec(m_vkQueue); + // XXX Should double-buffer the command buffers, for now just flush + m_cmdBuffer.Wait(); + + uboBuffer.Reset(m_vkDevice); + } + #if defined(USE_CHECKPOINTS) static void ShowCheckpoints() { diff --git a/src/conformance/framework/input_testinputdevice.cpp b/src/conformance/framework/input_testinputdevice.cpp index 0ea05a63..b5c3d65d 100644 --- a/src/conformance/framework/input_testinputdevice.cpp +++ b/src/conformance/framework/input_testinputdevice.cpp @@ -82,7 +82,7 @@ namespace Conformance HumanDrivenInputdevice(ITestMessageDisplay* const messageDisplay, InteractionManager* const interactionManager, XrInstance instance, XrSession session, XrPath interactionProfile, XrPath topLevelPath, - const InputSourcePathAvailCollection& interactionProfilePaths) + const BindingPathDataCollection& interactionProfilePaths) : m_messageDisplay(messageDisplay) , m_instance(instance) , m_session(session) @@ -110,11 +110,11 @@ namespace Conformance FeatureSet enabled; GetGlobalData().PopulateVersionAndEnabledExtensions(enabled); - for (const InputSourcePathAvailData& inputSourceData : interactionProfilePaths) { - if (!starts_with(inputSourceData.Path, topLevelPathString)) { + for (const BindingPathData& bindingPathData : interactionProfilePaths) { + if (!starts_with(bindingPathData.Path, topLevelPathString)) { continue; } - if (!kInteractionAvailabilities[(size_t)inputSourceData.Availability].IsSatisfiedBy(enabled)) { + if (!kInteractionAvailabilities[(size_t)bindingPathData.Availability].IsSatisfiedBy(enabled)) { continue; } @@ -122,19 +122,19 @@ namespace Conformance XrAction action{XR_NULL_HANDLE}; XrActionCreateInfo actionCreateInfo{XR_TYPE_ACTION_CREATE_INFO}; - actionCreateInfo.actionType = inputSourceData.Type; + actionCreateInfo.actionType = bindingPathData.Type; strcpy(actionCreateInfo.localizedActionName, std::get<1>(actionNames).c_str()); strcpy(actionCreateInfo.actionName, std::get<0>(actionNames).c_str()); REQUIRE_RESULT(xrCreateAction(m_actionSet, &actionCreateInfo, &action), XR_SUCCESS); - if (m_firstBooleanAction == XR_NULL_PATH && inputSourceData.Type == XR_ACTION_TYPE_BOOLEAN_INPUT) { + if (m_firstBooleanAction == XR_NULL_PATH && bindingPathData.Type == XR_ACTION_TYPE_BOOLEAN_INPUT) { m_firstBooleanAction = action; } - if (m_firstTrackerAction == XR_NULL_PATH && inputSourceData.Type == XR_ACTION_TYPE_POSE_INPUT) { + if (m_firstTrackerAction == XR_NULL_PATH && bindingPathData.Type == XR_ACTION_TYPE_POSE_INPUT) { m_firstTrackerAction = action; } - const XrPath bindingPath = StringToPath(instance, inputSourceData.Path); + const XrPath bindingPath = StringToPath(instance, bindingPathData.Path); m_actionMap.insert({bindingPath, action}); interactionManager->AddActionBindings(m_interactionProfile, {{action, bindingPath}}); } @@ -560,10 +560,10 @@ namespace Conformance std::unique_ptr CreateTestDevice(ITestMessageDisplay* const messageDisplay, InteractionManager* const interactionManager, XrInstance instance, XrSession session, XrPath interactionProfile, XrPath topLevelPath, - const InputSourcePathAvailCollection& interactionProfilePaths) + const BindingPathDataCollection& bindingPaths) { return std::make_unique(messageDisplay, interactionManager, instance, session, interactionProfile, - topLevelPath, interactionProfilePaths); + topLevelPath, bindingPaths); } std::unique_ptr CreateTestDevice(ITestMessageDisplay* const messageDisplay, XrInstance instance, XrSession session, diff --git a/src/conformance/framework/input_testinputdevice.h b/src/conformance/framework/input_testinputdevice.h index 2351f465..da06e6af 100644 --- a/src/conformance/framework/input_testinputdevice.h +++ b/src/conformance/framework/input_testinputdevice.h @@ -115,7 +115,7 @@ namespace Conformance std::unique_ptr CreateTestDevice(ITestMessageDisplay* const messageDisplay, InteractionManager* const interactionManager, XrInstance instance, XrSession session, XrPath interactionProfile, XrPath topLevelPath, - const InputSourcePathAvailCollection& interactionProfilePaths); + const BindingPathDataCollection& interactionProfilePaths); std::unique_ptr CreateTestDevice(ITestMessageDisplay* const messageDisplay, XrInstance instance, XrSession session, XrPath interactionProfile, XrPath topLevelPath, XrActionSet actionSet, diff --git a/src/conformance/framework/interaction_info.h b/src/conformance/framework/interaction_info.h index 5d0e81ba..1c3a4eb4 100644 --- a/src/conformance/framework/interaction_info.h +++ b/src/conformance/framework/interaction_info.h @@ -8,14 +8,14 @@ namespace Conformance { - struct InputSourcePathAvailData + struct BindingPathData { const char* Path; XrActionType Type; InteractionProfileAvailability Availability; bool systemOnly = false; }; - using InputSourcePathAvailCollection = std::initializer_list; + using BindingPathDataCollection = std::initializer_list; struct InteractionProfileAvailMetadata { @@ -29,15 +29,19 @@ namespace Conformance /// Index into @ref kInteractionAvailabilities InteractionProfileAvailability Availability; - InputSourcePathAvailCollection InputSourcePaths; + BindingPathDataCollection BindingPaths; }; /// Get the generated list of all interaction profiles with availability and other metadata const std::vector& GetAllInteractionProfiles(); + + /// Get the generated metadata for a given interaction profile index enumerant. inline const InteractionProfileAvailMetadata& GetInteractionProfile(InteractionProfileIndex profile) { return GetAllInteractionProfiles()[(size_t)profile]; } + + /// Get the generated metadata for `/interaction_profile/khr/simple_controller` inline const InteractionProfileAvailMetadata& GetSimpleInteractionProfile() { return GetInteractionProfile(InteractionProfileIndex::Profile_khr_simple_controller); diff --git a/src/conformance/framework/pbr/OpenGL/GLTexture.cpp b/src/conformance/framework/pbr/OpenGL/GLTexture.cpp index 35a94cc9..175987d4 100644 --- a/src/conformance/framework/pbr/OpenGL/GLTexture.cpp +++ b/src/conformance/framework/pbr/OpenGL/GLTexture.cpp @@ -43,9 +43,6 @@ namespace Pbr /// Creates a texture and fills all array members with the data in rgba ScopedGLTexture CreateTextureOrCubemapRepeat(const Image::Image& image, bool isCubemap) { - assert(image.format.codec == Image::Codec::Raw8bpc); // only 8bpc is implemented - assert(image.format.channels == Image::Channels::RGBA); // non-RGBA isn't implemented - GLFormatData glFormat = ToGLFormatData(image.format); GLenum internalFormat = glFormat.InternalFormat; @@ -57,61 +54,48 @@ namespace Pbr bool isCompressed = Image::IsCompressed(image.format.codec); - uint16_t baseMipWidth = image.levels[0].metadata.physicalDimensions.width; - uint16_t baseMipHeight = image.levels[0].metadata.physicalDimensions.height; - ScopedGLTexture texture{}; const GLenum target = isCubemap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; + XRC_CHECK_THROW_GLCMD(glGenTextures(1, texture.resetAndPut())); XRC_CHECK_THROW_GLCMD(glBindTexture(target, texture.get())); + + // note that these are overridden by the sampler XRC_CHECK_THROW_GLCMD(glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); XRC_CHECK_THROW_GLCMD(glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); XRC_CHECK_THROW_GLCMD(glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); XRC_CHECK_THROW_GLCMD(glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + XRC_CHECK_THROW_GLCMD(glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0)); - XRC_CHECK_THROW_GLCMD(glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, 0)); // if we add mipmaps we need to change this - if (isCompressed) { - assert(!isCubemap); // compressed cubemaps aren't implemented - XRC_CHECK_THROW_GLCMD( - glCompressedTexImage2D(target, 0, glFormat.InternalFormat, baseMipWidth, baseMipHeight, 0, 0, nullptr)); - } - else { - assert(uncompressedFormat != GLFormatData::Unpopulated); - assert(uncompressedType != GLFormatData::Unpopulated); - if (isCubemap) { - for (unsigned int i = 0; i < 6; i++) - XRC_CHECK_THROW_GLCMD(glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat.InternalFormat, baseMipWidth, - baseMipHeight, 0, uncompressedFormat, uncompressedType, nullptr)); - } - else { - XRC_CHECK_THROW_GLCMD(glTexImage2D(target, 0, glFormat.InternalFormat, baseMipWidth, baseMipHeight, 0, - uncompressedFormat, uncompressedType, nullptr)); - } - } + XRC_CHECK_THROW_GLCMD(glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, image.levels.size() - 1)); XRC_CHECK_THROW_GLCMD(glBindTexture(target, texture.get())); for (int mipLevel = 0; mipLevel < (int)image.levels.size(); mipLevel++) { auto levelData = image.levels[mipLevel]; auto width = levelData.metadata.physicalDimensions.width; auto height = levelData.metadata.physicalDimensions.height; - if (isCompressed) { - XRC_CHECK_THROW_GLCMD(glCompressedTexSubImage2D(target, mipLevel, 0, 0, width, height, glFormat.InternalFormat, - levelData.data.size(), levelData.data.data())); - } - else { - assert(uncompressedFormat != GLFormatData::Unpopulated); - assert(uncompressedType != GLFormatData::Unpopulated); - if (isCubemap) { - for (unsigned int i = 0; i < 6; i++) { - XRC_CHECK_THROW_GLCMD(glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, width, height, - uncompressedFormat, uncompressedType, levelData.data.data())); - } + + auto uploadForSubtarget = [&](GLenum subtarget) { + if (isCompressed) { + XRC_CHECK_THROW_GLCMD(glCompressedTexImage2D(subtarget, mipLevel, glFormat.InternalFormat, width, height, 0, + levelData.data.size(), levelData.data.data())); } else { - XRC_CHECK_THROW_GLCMD( - glTexSubImage2D(target, 0, 0, 0, width, height, uncompressedFormat, uncompressedType, levelData.data.data())); + assert(uncompressedFormat != GLFormatData::Unpopulated); + assert(uncompressedType != GLFormatData::Unpopulated); + XRC_CHECK_THROW_GLCMD(glTexImage2D(subtarget, mipLevel, glFormat.InternalFormat, width, height, 0, + uncompressedFormat, uncompressedType, levelData.data.data())); } + }; + + if (isCubemap) { + for (unsigned int i = 0; i < 6; i++) { + uploadForSubtarget(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i); + } + } + else { + uploadForSubtarget(target); } } XRC_CHECK_THROW_GLCMD(glBindTexture(target, 0)); diff --git a/src/conformance/framework/pbr/Vulkan/VkPipelineStates.h b/src/conformance/framework/pbr/Vulkan/VkPipelineStates.h index 1443d11d..a0ebdae1 100644 --- a/src/conformance/framework/pbr/Vulkan/VkPipelineStates.h +++ b/src/conformance/framework/pbr/Vulkan/VkPipelineStates.h @@ -35,7 +35,11 @@ namespace Pbr span vertexAttrDesc, span vertexInputBindDesc, span pbrVS, span pbrPS) - : m_device(device), m_layout(layout), m_vertexAttrDesc(vertexAttrDesc), m_vertexInputBindDesc(vertexInputBindDesc) + : m_device(device) + , m_layout(layout) + , m_vertexAttrDesc(vertexAttrDesc) + , m_vertexInputBindDesc(vertexInputBindDesc) + , m_pbrShader(Conformance::SHADER_PROGRAM_TYPE_GRAPHICS) { m_pbrShader.Init(m_device); m_pbrShader.LoadVertexShader(pbrVS); diff --git a/src/conformance/framework/report.h b/src/conformance/framework/report.h index df01bf53..73fb011a 100644 --- a/src/conformance/framework/report.h +++ b/src/conformance/framework/report.h @@ -20,6 +20,7 @@ #include #include #include +#include "utilities/utils.h" namespace Conformance { @@ -38,10 +39,10 @@ namespace Conformance /// @todo Any code that uses this, must be modified to output to the CTS catch2 reporter. /// /// Do not write new code that uses this function! - void ReportF(const char* format, ...); + void PRINT_ATTRIBUTE(1, 2) ReportF(const char* format, ...); /// Formatted report function, like ReportF, but for console output only (when XML report output has another way of including this data) - void ReportConsoleOnlyF(const char* format, ...); + void PRINT_ATTRIBUTE(1, 2) ReportConsoleOnlyF(const char* format, ...); /// @} diff --git a/src/conformance/framework/vulkan_shaders/comp.glsl b/src/conformance/framework/vulkan_shaders/comp.glsl new file mode 100644 index 00000000..83114f99 --- /dev/null +++ b/src/conformance/framework/vulkan_shaders/comp.glsl @@ -0,0 +1,24 @@ +// Copyright (c) 2017-2024, The Khronos Group Inc. +// +// SPDX-License-Identifier: Apache-2.0 + +#version 450 + +layout (local_size_x = 16, local_size_y = 16) in; +// layout (binding = 0) uniform sampler2D source; +layout (rgba8, binding = 0) uniform image2D target; +layout(set = 0, binding = 1, std140) uniform restrict Config +{ + vec4 color; +} ubo; + +void main() { + uint ix = gl_GlobalInvocationID.x; + uint iy = gl_GlobalInvocationID.y; + ivec2 extent = imageSize(target); + if (ix >= extent.x || iy >= extent.y) { + return; + } + vec4 rgba = vec4(1.0, 0.0, 0.0, 1.0); + imageStore(target, ivec2(ix, iy), rgba); +} diff --git a/src/conformance/framework/vulkan_shaders/comp.spv b/src/conformance/framework/vulkan_shaders/comp.spv new file mode 100644 index 00000000..513ee6c9 --- /dev/null +++ b/src/conformance/framework/vulkan_shaders/comp.spv @@ -0,0 +1,105 @@ +{0x07230203,0x00010000,0x000d000b,0x00000043, +0x00000000,0x00020011,0x00000001,0x00020011, +0x00000032,0x0006000b,0x00000001,0x4c534c47, +0x6474732e,0x3035342e,0x00000000,0x0003000e, +0x00000000,0x00000001,0x0006000f,0x00000005, +0x00000004,0x6e69616d,0x00000000,0x0000000b, +0x00060010,0x00000004,0x00000011,0x00000010, +0x00000010,0x00000001,0x00030003,0x00000002, +0x000001c2,0x000a0004,0x475f4c47,0x4c474f4f, +0x70635f45,0x74735f70,0x5f656c79,0x656e696c, +0x7269645f,0x69746365,0x00006576,0x00080004, +0x475f4c47,0x4c474f4f,0x6e695f45,0x64756c63, +0x69645f65,0x74636572,0x00657669,0x00040005, +0x00000004,0x6e69616d,0x00000000,0x00030005, +0x00000008,0x00007869,0x00080005,0x0000000b, +0x475f6c67,0x61626f6c,0x766e496c,0x7461636f, +0x496e6f69,0x00000044,0x00030005,0x00000010, +0x00007969,0x00040005,0x00000017,0x65747865, +0x0000746e,0x00040005,0x0000001b,0x67726174, +0x00007465,0x00040005,0x00000033,0x61626772, +0x00000000,0x00040005,0x00000040,0x666e6f43, +0x00006769,0x00050006,0x00000040,0x00000000, +0x6f6c6f63,0x00000072,0x00030005,0x00000042, +0x006f6275,0x00040047,0x0000000b,0x0000000b, +0x0000001c,0x00040047,0x0000001b,0x00000022, +0x00000000,0x00040047,0x0000001b,0x00000021, +0x00000000,0x00040047,0x0000003f,0x0000000b, +0x00000019,0x00050048,0x00000040,0x00000000, +0x00000023,0x00000000,0x00030047,0x00000040, +0x00000002,0x00040047,0x00000042,0x00000022, +0x00000000,0x00040047,0x00000042,0x00000021, +0x00000001,0x00020013,0x00000002,0x00030021, +0x00000003,0x00000002,0x00040015,0x00000006, +0x00000020,0x00000000,0x00040020,0x00000007, +0x00000007,0x00000006,0x00040017,0x00000009, +0x00000006,0x00000003,0x00040020,0x0000000a, +0x00000001,0x00000009,0x0004003b,0x0000000a, +0x0000000b,0x00000001,0x0004002b,0x00000006, +0x0000000c,0x00000000,0x00040020,0x0000000d, +0x00000001,0x00000006,0x0004002b,0x00000006, +0x00000011,0x00000001,0x00040015,0x00000014, +0x00000020,0x00000001,0x00040017,0x00000015, +0x00000014,0x00000002,0x00040020,0x00000016, +0x00000007,0x00000015,0x00030016,0x00000018, +0x00000020,0x00090019,0x00000019,0x00000018, +0x00000001,0x00000000,0x00000000,0x00000000, +0x00000002,0x00000004,0x00040020,0x0000001a, +0x00000000,0x00000019,0x0004003b,0x0000001a, +0x0000001b,0x00000000,0x00020014,0x0000001e, +0x00040020,0x00000020,0x00000007,0x00000014, +0x00040017,0x00000031,0x00000018,0x00000004, +0x00040020,0x00000032,0x00000007,0x00000031, +0x0004002b,0x00000018,0x00000034,0x3f800000, +0x0004002b,0x00000018,0x00000035,0x00000000, +0x0007002c,0x00000031,0x00000036,0x00000034, +0x00000035,0x00000035,0x00000034,0x0004002b, +0x00000006,0x0000003e,0x00000010,0x0006002c, +0x00000009,0x0000003f,0x0000003e,0x0000003e, +0x00000011,0x0003001e,0x00000040,0x00000031, +0x00040020,0x00000041,0x00000002,0x00000040, +0x0004003b,0x00000041,0x00000042,0x00000002, +0x00050036,0x00000002,0x00000004,0x00000000, +0x00000003,0x000200f8,0x00000005,0x0004003b, +0x00000007,0x00000008,0x00000007,0x0004003b, +0x00000007,0x00000010,0x00000007,0x0004003b, +0x00000016,0x00000017,0x00000007,0x0004003b, +0x00000032,0x00000033,0x00000007,0x00050041, +0x0000000d,0x0000000e,0x0000000b,0x0000000c, +0x0004003d,0x00000006,0x0000000f,0x0000000e, +0x0003003e,0x00000008,0x0000000f,0x00050041, +0x0000000d,0x00000012,0x0000000b,0x00000011, +0x0004003d,0x00000006,0x00000013,0x00000012, +0x0003003e,0x00000010,0x00000013,0x0004003d, +0x00000019,0x0000001c,0x0000001b,0x00040068, +0x00000015,0x0000001d,0x0000001c,0x0003003e, +0x00000017,0x0000001d,0x0004003d,0x00000006, +0x0000001f,0x00000008,0x00050041,0x00000020, +0x00000021,0x00000017,0x0000000c,0x0004003d, +0x00000014,0x00000022,0x00000021,0x0004007c, +0x00000006,0x00000023,0x00000022,0x000500ae, +0x0000001e,0x00000024,0x0000001f,0x00000023, +0x000400a8,0x0000001e,0x00000025,0x00000024, +0x000300f7,0x00000027,0x00000000,0x000400fa, +0x00000025,0x00000026,0x00000027,0x000200f8, +0x00000026,0x0004003d,0x00000006,0x00000028, +0x00000010,0x00050041,0x00000020,0x00000029, +0x00000017,0x00000011,0x0004003d,0x00000014, +0x0000002a,0x00000029,0x0004007c,0x00000006, +0x0000002b,0x0000002a,0x000500ae,0x0000001e, +0x0000002c,0x00000028,0x0000002b,0x000200f9, +0x00000027,0x000200f8,0x00000027,0x000700f5, +0x0000001e,0x0000002d,0x00000024,0x00000005, +0x0000002c,0x00000026,0x000300f7,0x0000002f, +0x00000000,0x000400fa,0x0000002d,0x0000002e, +0x0000002f,0x000200f8,0x0000002e,0x000100fd, +0x000200f8,0x0000002f,0x0003003e,0x00000033, +0x00000036,0x0004003d,0x00000019,0x00000037, +0x0000001b,0x0004003d,0x00000006,0x00000038, +0x00000008,0x0004007c,0x00000014,0x00000039, +0x00000038,0x0004003d,0x00000006,0x0000003a, +0x00000010,0x0004007c,0x00000014,0x0000003b, +0x0000003a,0x00050050,0x00000015,0x0000003c, +0x00000039,0x0000003b,0x0004003d,0x00000031, +0x0000003d,0x00000033,0x00040063,0x00000037, +0x0000003c,0x0000003d,0x000100fd,0x00010038} diff --git a/src/conformance/framework/vulkan_shaders/comp.spv.license b/src/conformance/framework/vulkan_shaders/comp.spv.license new file mode 100644 index 00000000..3caf3ed8 --- /dev/null +++ b/src/conformance/framework/vulkan_shaders/comp.spv.license @@ -0,0 +1,3 @@ +Copyright (c) 2017-2024, The Khronos Group Inc. + +SPDX-License-Identifier: Apache-2.0 diff --git a/src/conformance/usage/asciidoctor-targets.mk b/src/conformance/usage/asciidoctor-targets.mk index c14319d8..3d7d9688 100644 --- a/src/conformance/usage/asciidoctor-targets.mk +++ b/src/conformance/usage/asciidoctor-targets.mk @@ -14,7 +14,7 @@ ADOCOPTS = --doctype book \ $(ADOC_FAILURE_LEVEL) \ $(ATTRIBOPTS) -SPECREVISION = 1.1.42 +SPECREVISION = 1.1.43 ifneq (,$(strip $(RELEASE))) # No dates or internal commit hashes in release builds for reproducibility diff --git a/src/conformance/utilities/utils.h b/src/conformance/utilities/utils.h index 57c307bb..493fdbb4 100644 --- a/src/conformance/utilities/utils.h +++ b/src/conformance/utilities/utils.h @@ -207,6 +207,12 @@ #define striequal(a, b) (strcasecmp(a, b) == 0) #endif +#ifdef __GNUC__ +#define PRINT_ATTRIBUTE(a, b) __attribute__((format(printf, a, b))) +#else +#define PRINT_ATTRIBUTE(a, b) +#endif + namespace Conformance { // Copied directly from the helloXr project. Let's get to a point in the future where all these @@ -227,19 +233,19 @@ namespace Conformance /// The behavior is undefined if the specified format or arguments are invalid. /// Example usage: /// std::string s = StringSprintf("Hello %s", "world"); - std::string StringSprintf(const char* format, ...); + std::string PRINT_ATTRIBUTE(1, 2) StringSprintf(const char* format, ...); /// Returns a std::string that was initialized via printf-style formatting. /// The behavior is undefined if the specified format or arguments are invalid. /// Example usage: /// std::string s = StringVsprintf("Hello %s", args); - std::string StringVsprintf(const char* format, va_list args); + std::string PRINT_ATTRIBUTE(1, 0) StringVsprintf(const char* format, va_list args); /// Returns a std::string that was appended to via printf-style formatting. /// The behavior is undefined if the specified format or arguments are invalid. /// Example usage: /// AppendSprintf(s, "appended %s", "hello world"); - std::string& AppendSprintf(std::string& s, const char* format, ...); + std::string& PRINT_ATTRIBUTE(2, 3) AppendSprintf(std::string& s, const char* format, ...); /// Changes the case of str, typically for the purpose of exercising case-sensitivity requirements. /// Returns a reference to the input str. diff --git a/src/conformance/utilities/vulkan_utils.h b/src/conformance/utilities/vulkan_utils.h index a234bd84..ad7fdf77 100644 --- a/src/conformance/utilities/vulkan_utils.h +++ b/src/conformance/utilities/vulkan_utils.h @@ -4,6 +4,7 @@ #pragma once +#include "utilities/array_size.h" #ifdef XR_USE_GRAPHICS_API_VULKAN #include "throw_helpers.h" @@ -361,13 +362,34 @@ namespace Conformance } }; + enum ShaderProgramType + { + SHADER_PROGRAM_TYPE_GRAPHICS, + SHADER_PROGRAM_TYPE_COMPUTE, + }; + /// ShaderProgram to hold a pair of vertex & fragment shaders struct ShaderProgram { - std::array shaderInfo{ - {{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}, {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}}}; + std::vector shaderInfo; + ShaderProgramType m_programType; - ShaderProgram() = default; + ShaderProgram(ShaderProgramType programType) : m_programType(programType) + { + switch (programType) { + case SHADER_PROGRAM_TYPE_GRAPHICS: { + shaderInfo.push_back({VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}); + shaderInfo.push_back({VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}); + break; + } + case SHADER_PROGRAM_TYPE_COMPUTE: { + shaderInfo.push_back({VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}); + break; + } + default: + XRC_THROW("Unknown shader program type"); + } + } void Reset() { @@ -403,6 +425,11 @@ namespace Conformance Load(1, code); } + void LoadComputeShader(const span code) + { + Load(0, code); + } + void Init(VkDevice device) { m_vkDevice = device; @@ -419,17 +446,34 @@ namespace Conformance si.pName = "main"; std::string name; - switch (index) { - case 0: - si.stage = VK_SHADER_STAGE_VERTEX_BIT; - name = "vertex"; - break; - case 1: - si.stage = VK_SHADER_STAGE_FRAGMENT_BIT; - name = "fragment"; - break; - default: - XRC_THROW("Unknown code index " + std::to_string(index)); + switch (m_programType) { + case SHADER_PROGRAM_TYPE_GRAPHICS: { + + switch (index) { + case 0: + si.stage = VK_SHADER_STAGE_VERTEX_BIT; + name = "vertex"; + break; + case 1: + si.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + name = "fragment"; + break; + default: + XRC_THROW("Unknown code index " + std::to_string(index)); + } + } break; + + case SHADER_PROGRAM_TYPE_COMPUTE: { + + switch (index) { + case 0: + si.stage = VK_SHADER_STAGE_COMPUTE_BIT; + name = "compute"; + break; + default: + XRC_THROW("Unknown code index " + std::to_string(index)); + } + } break; } modInfo.codeSize = code.size() * sizeof(code[0]); @@ -1012,6 +1056,9 @@ namespace Conformance { VkPipelineLayout layout{VK_NULL_HANDLE}; + // only set for compute pipelines + VkDescriptorSetLayout descriptorSetLayout{VK_NULL_HANDLE}; + PipelineLayout() = default; void Reset() @@ -1020,6 +1067,9 @@ namespace Conformance if (layout != VK_NULL_HANDLE) { vkDestroyPipelineLayout(m_vkDevice, layout, nullptr); } + if (descriptorSetLayout != VK_NULL_HANDLE) { + vkDestroyDescriptorSetLayout(m_vkDevice, descriptorSetLayout, nullptr); + } } layout = VK_NULL_HANDLE; m_vkDevice = nullptr; @@ -1030,20 +1080,49 @@ namespace Conformance Reset(); } - void Create(VkDevice device) + void Create(VkDevice device, ShaderProgramType programType = SHADER_PROGRAM_TYPE_GRAPHICS) { m_vkDevice = device; - - // MVP matrix is a push_constant - VkPushConstantRange pcr = {}; - pcr.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - pcr.offset = 0; - pcr.size = sizeof(VulkanUniformBuffer); - - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - pipelineLayoutCreateInfo.pushConstantRangeCount = 1; - pipelineLayoutCreateInfo.pPushConstantRanges = &pcr; - XRC_CHECK_THROW_VKCMD(vkCreatePipelineLayout(m_vkDevice, &pipelineLayoutCreateInfo, nullptr, &layout)); + switch (programType) { + case SHADER_PROGRAM_TYPE_GRAPHICS: { + // MVP matrix is a push_constant + VkPushConstantRange pcr = {}; + pcr.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + pcr.offset = 0; + pcr.size = sizeof(VulkanUniformBuffer); + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + pipelineLayoutCreateInfo.pushConstantRangeCount = 1; + pipelineLayoutCreateInfo.pPushConstantRanges = &pcr; + XRC_CHECK_THROW_VKCMD(vkCreatePipelineLayout(m_vkDevice, &pipelineLayoutCreateInfo, nullptr, &layout)); + } break; + case SHADER_PROGRAM_TYPE_COMPUTE: { + VkDescriptorSetLayoutBinding descriptorSetBindings[2]{}; + descriptorSetBindings[0].binding = 0; + descriptorSetBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + descriptorSetBindings[0].descriptorCount = 1; + descriptorSetBindings[0].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + + descriptorSetBindings[1].binding = 1; + descriptorSetBindings[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptorSetBindings[1].descriptorCount = 1; + descriptorSetBindings[1].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO}; + descriptorSetLayoutInfo.bindingCount = (uint32_t)ArraySize(descriptorSetBindings); + descriptorSetLayoutInfo.pBindings = descriptorSetBindings; + + vkCreateDescriptorSetLayout(device, // + &descriptorSetLayoutInfo, NULL, &descriptorSetLayout); + + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + pipelineLayoutCreateInfo.setLayoutCount = 1; + pipelineLayoutCreateInfo.pSetLayouts = &descriptorSetLayout; + XRC_CHECK_THROW_VKCMD(vkCreatePipelineLayout(m_vkDevice, &pipelineLayoutCreateInfo, nullptr, &layout)); + } break; + default: + XRC_THROW("Unknown programType"); + } } PipelineLayout(const PipelineLayout&) = delete; @@ -1066,9 +1145,9 @@ namespace Conformance Reset(); } - void Create(VkDevice device, VkExtent2D /*size*/, const PipelineLayout& layout, const RenderPass& rp, const ShaderProgram& sp, - const VkVertexInputBindingDescription& bindDesc, span attrDesc, - span dynamicStates) + void CreateGraphics(VkDevice device, VkExtent2D /*size*/, const PipelineLayout& layout, const RenderPass& rp, + const ShaderProgram& sp, const VkVertexInputBindingDescription& bindDesc, + span attrDesc, span dynamicStates) { m_vkDevice = device; @@ -1162,6 +1241,33 @@ namespace Conformance Create(device, pipeInfo); } + void CreateCompute(VkDevice device, VkExtent2D /*size*/, const PipelineLayout& layout, const RenderPass& /* rp */, + const ShaderProgram& sp, const VkVertexInputBindingDescription& /* bindDesc */, + span /* attrDesc */, span /* dynamicStates */) + { + VkComputePipelineCreateInfo pipeInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; + pipeInfo.flags = 0; + pipeInfo.stage = sp.shaderInfo[0], pipeInfo.layout = layout.layout, + + Create(device, pipeInfo); + } + + void Create(VkDevice device, VkExtent2D size, const PipelineLayout& layout, const RenderPass& rp, const ShaderProgram& sp, + const VkVertexInputBindingDescription& bindDesc, span attrDesc, + span dynamicStates) + { + switch (sp.m_programType) { + case SHADER_PROGRAM_TYPE_GRAPHICS: + CreateGraphics(device, size, layout, rp, sp, bindDesc, attrDesc, dynamicStates); + break; + case SHADER_PROGRAM_TYPE_COMPUTE: + CreateCompute(device, size, layout, rp, sp, bindDesc, attrDesc, dynamicStates); + break; + default: + XRC_THROW("Unknown programType") + } + } + void Create(VkDevice device, const VkGraphicsPipelineCreateInfo& info) { m_vkDevice = device; @@ -1169,6 +1275,13 @@ namespace Conformance XRC_CHECK_THROW_VKCMD(vkCreateGraphicsPipelines(m_vkDevice, VK_NULL_HANDLE, 1, &info, nullptr, &pipe)); } + void Create(VkDevice device, const VkComputePipelineCreateInfo& info) + { + m_vkDevice = device; + + XRC_CHECK_THROW_VKCMD(vkCreateComputePipelines(m_vkDevice, VK_NULL_HANDLE, 1, &info, nullptr, &pipe)); + } + void Reset() { if (m_vkDevice != nullptr) { diff --git a/src/external/jnipp/CHANGELOG.md b/src/external/jnipp/CHANGELOG.md new file mode 100644 index 00000000..18851fcb --- /dev/null +++ b/src/external/jnipp/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog for jnipp + +## jnipp 1.0.0 (25-October-2023) + +This release is somewhat of a formality, as jnipp has been used in production +environments for some time. It was prompted by the need for an API breaking +change to ensure continued compatibility with libc++ as they move to more +strictly follow the C++ standard. diff --git a/src/external/jnipp/CMakeLists.txt b/src/external/jnipp/CMakeLists.txt index df206fec..9b0c1879 100644 --- a/src/external/jnipp/CMakeLists.txt +++ b/src/external/jnipp/CMakeLists.txt @@ -13,6 +13,7 @@ target_include_directories( jnipp PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} PRIVATE ${JNI_INCLUDE_DIRS}) +target_compile_features(jnipp PUBLIC cxx_std_11) target_link_libraries(jnipp PUBLIC ${CMAKE_DL_LIBS}) add_subdirectory(tests) diff --git a/src/external/jnipp/changes/changes/pr.40.md b/src/external/jnipp/changes/changes/pr.40.md new file mode 100644 index 00000000..e5abd824 --- /dev/null +++ b/src/external/jnipp/changes/changes/pr.40.md @@ -0,0 +1 @@ +Stop using `std::basic_string` internally, because it is `std::basic_string` on some platforms, and this specialization is not technically provided by the standard library. libc++ is removing support for it, so this internal change is required to continue to compile against libc++. In place of it, use `std::vector`. diff --git a/src/external/jnipp/changes/fixes/pr.49.md b/src/external/jnipp/changes/fixes/pr.49.md new file mode 100644 index 00000000..c77aba77 --- /dev/null +++ b/src/external/jnipp/changes/fixes/pr.49.md @@ -0,0 +1 @@ +Do not allow exceptions to escape destructors. diff --git a/src/external/jnipp/jnipp.cpp b/src/external/jnipp/jnipp.cpp index 20a91d9a..a6c656a6 100644 --- a/src/external/jnipp/jnipp.cpp +++ b/src/external/jnipp/jnipp.cpp @@ -8,6 +8,7 @@ # include # include # include +# include #endif // External Dependencies @@ -44,6 +45,7 @@ namespace jni ScopedEnv() noexcept : _vm(nullptr), _env(nullptr), _attached(false) {} ~ScopedEnv(); + // Caution - throws if VM is nullptr! void init(JavaVM* vm); JNIEnv* get() const noexcept { return _env; } @@ -157,10 +159,16 @@ namespace jni #endif // _WIN32 - JNIEnv* env() + static ScopedEnv &scopedEnvInstance() noexcept { static thread_local ScopedEnv env; + return env; + } + // may return nullptr, beware! + JNIEnv *env_noexcept() noexcept + { + ScopedEnv& env = scopedEnvInstance(); if (env.get() != nullptr && !isAttached(javaVm)) { // we got detached, so clear it. @@ -168,7 +176,7 @@ namespace jni env = ScopedEnv{}; } - if (env.get() == nullptr) + if (env.get() == nullptr && javaVm != nullptr) { env.init(javaVm); } @@ -176,6 +184,17 @@ namespace jni return env.get(); } + JNIEnv* env() + { + JNIEnv *ret = env_noexcept(); + if (ret == nullptr) + { + throw InitializationException("JNI not initialized"); + } + + return ret; + } + static jclass findClass(const char* name) { jclass ref = env()->FindClass(name); @@ -307,9 +326,14 @@ namespace jni Object::~Object() noexcept { - JNIEnv* env = jni::env(); + JNIEnv* env = jni::env_noexcept(); + if (env == nullptr) + { + // Better be empty. Cannot do anything useful. + return; + } - if (_isGlobal) + if (_isGlobal && _handle != nullptr) env->DeleteGlobalRef(_handle); if (_class != nullptr) @@ -642,7 +666,7 @@ namespace jni return Class(getClass(), Temporary).getField(name, signature); } - jobject Object::makeLocalReference() const + jobject Object::makeLocalReference() const { if (isNull()) return nullptr; diff --git a/src/external/jnipp/proclamation.json b/src/external/jnipp/proclamation.json new file mode 100644 index 00000000..f2fed627 --- /dev/null +++ b/src/external/jnipp/proclamation.json @@ -0,0 +1,20 @@ +{ + "#": "This is a config file for Proclamation, the changelog combiner: https://gitlab.com/proclamation/proclamation", + "SPDX-License-Identifier: CC0-1.0": "", + "SPDX-FileCopyrightText: 2020 Collabora, Ltd. and the Proclamation contributors": "", + "$schema": "https://proclamation.gitlab.io/proclamation/proclamation.schema.json", + "project_name": "jnipp", + "base_url": "https://github.com/mitchdowd/jnipp", + "news_filename": "CHANGELOG.md", + "sections": { + "Changes": { + "directory": "changes/templates" + }, + "Fixes": { + "directory": "changes/misc" + }, + "Additions": { + "directory": "changes/script" + } + } +} diff --git a/src/external/jnipp/tests/main.cpp b/src/external/jnipp/tests/main.cpp index 47148475..d92e0bd0 100644 --- a/src/external/jnipp/tests/main.cpp +++ b/src/external/jnipp/tests/main.cpp @@ -203,6 +203,11 @@ TEST(Class_call_staticMethod_byName) jni::Object Tests */ +// Must run before loading JVM +TEST(Object_noDestructorException) +{ + jni::Object o; +} TEST(Object_defaultConstructor_isNull) { @@ -574,6 +579,9 @@ TEST(Arg_ObjectPtr) int main() { + // Tests that depend on having no JVM + RUN_TEST(Object_noDestructorException); + // jni::Vm Tests RUN_TEST(Vm_detectsJreInstall); RUN_TEST(Vm_notAllowedMultipleVms); diff --git a/src/scripts/generate_api_layer_manifest.py b/src/scripts/generate_api_layer_manifest.py index 7a6b9e85..517dba34 100755 --- a/src/scripts/generate_api_layer_manifest.py +++ b/src/scripts/generate_api_layer_manifest.py @@ -128,7 +128,8 @@ def main(argv): file_text += f' "library_path": "{library_location}",\n' file_text += f' "api_version": "{api_version}",\n' file_text += f' "implementation_version": "{implementation_version}",\n' - file_text += f' "description": "{description}"' + file_text += f' "description": "{description}",\n' + file_text += f' "disable_environment": "{layer_name}_disabled"' # If testing bad JSONs, then add in a fake extension if generate_badjson_jsons: @@ -162,7 +163,8 @@ def main(argv): file_text += f' "library_path": "{library_location}",\n' file_text += f' "api_version": "{api_version}",\n' file_text += f' "implementation_version": "{implementation_version}",\n' - file_text += f' "description": "{description}\"\n' + file_text += f' "description": "{description}\",\n' + file_text += f' "disable_environment": "{layer_name}_disabled"\n' file_text += ' }\n' file_text += '}\n' bad_name += '.json' @@ -180,7 +182,8 @@ def main(argv): file_text += f' "library_path": "{library_location}",\n' file_text += f' "api_version": "{api_version}",\n' file_text += f' "implementation_version": "{implementation_version}",\n' - file_text += f' "description": "{description}\"\n' + file_text += f' "description": "{description}\",\n' + file_text += f' "disable_environment": "{layer_name}_disabled"\n' file_text += ' }\n' file_text += '}\n' bad_name += '.json' @@ -198,7 +201,8 @@ def main(argv): file_text += f' "library_path": "{library_location}",\n' file_text += f' "api_version": "{api_version}",\n' file_text += f' "implementation_version": "{implementation_version}",\n' - file_text += f' "description": "{description}\"\n' + file_text += f' "description": "{description}\",\n' + file_text += f' "disable_environment": "{layer_name}_disabled"\n' file_text += ' }\n' file_text += '}\n' bad_name += '.json' @@ -216,7 +220,8 @@ def main(argv): file_text += f' "library_path": "{library_location}",\n' file_text += f' "api_version": "{api_version}",\n' file_text += f' "implementation_version": "{implementation_version}",\n' - file_text += f' "description": "{description}\"\n' + file_text += f' "description": "{description}\",\n' + file_text += f' "disable_environment": "{layer_name}_disabled"\n' file_text += ' }\n' file_text += '}\n' bad_name += '.json' @@ -234,7 +239,8 @@ def main(argv): file_text += f' "library_path": "{library_location}",\n' file_text += f' "api_version": "{api_version}",\n' file_text += f' "implementation_version": "{implementation_version}",\n' - file_text += f' "description": "{description}\"\n' + file_text += f' "description": "{description}\",\n' + file_text += f' "disable_environment": "{layer_name}_disabled"\n' file_text += ' }\n' file_text += '}\n' bad_name += '.json' @@ -252,7 +258,8 @@ def main(argv): file_text += f' "library_path": "{library_location}",\n' file_text += f' "api_version": "{api_version}",\n' file_text += f' "implementation_version": "{implementation_version}",\n' - file_text += f' "description": "{description}\"\n' + file_text += f' "description": "{description}\",\n' + file_text += f' "disable_environment": "{layer_name}_disabled"\n' file_text += ' }\n' file_text += '}\n' bad_name += '.json' @@ -272,7 +279,8 @@ def main(argv): file_text += f' "library_path": "{library_location}",\n' file_text += f' "api_version": "{api_version}",\n' file_text += f' "implementation_version": "{implementation_version}",\n' - file_text += f' "description": "{description}\"\n' + file_text += f' "description": "{description}\",\n' + file_text += f' "disable_environment": "{layer_name}_disabled"\n' file_text += '}\n' bad_name += '.json' bad_file = output_file.replace(".json", bad_name) @@ -290,7 +298,8 @@ def main(argv): file_text += f' "library_path": "{library_location}",\n' file_text += f' "api_version": "{api_version}",\n' file_text += f' "implementation_version": "{implementation_version}",\n' - file_text += f' "description": "{description}\"\n' + file_text += f' "description": "{description}\",\n' + file_text += f' "disable_environment": "{layer_name}_disabled"\n' file_text += '}\n' bad_name += '.json' bad_file = output_file.replace(".json", bad_name) @@ -310,7 +319,8 @@ def main(argv): file_text += f' "library_path": "{library_location}",\n' file_text += f' "api_version": "{api_version}",\n' file_text += f' "implementation_version": "{implementation_version}",\n' - file_text += f' "description": "{description}\"\n' + file_text += f' "description": "{description}\",\n' + file_text += f' "disable_environment": "{layer_name}_disabled"\n' file_text += ' }\n' file_text += '}\n' bad_name += '.json' @@ -327,7 +337,8 @@ def main(argv): file_text += f' "library_path": "{library_location}",\n' file_text += f' "api_version": "{api_version}",\n' file_text += f' "implementation_version": "{implementation_version}",\n' - file_text += f' "description": "{description}\"\n' + file_text += f' "description": "{description}\",\n' + file_text += f' "disable_environment": "{layer_name}_disabled"\n' file_text += ' }\n' file_text += '}\n' bad_name += '.json' @@ -347,7 +358,8 @@ def main(argv): file_text += f' "name": "XR_APILAYER_LUNARG_{layer_name}{bad_name}",\n' file_text += f' "api_version": "{api_version}",\n' file_text += f' "implementation_version": "{implementation_version}",\n' - file_text += f' "description": "{description}\"\n' + file_text += f' "description": "{description}\",\n' + file_text += f' "disable_environment": "{layer_name}_disabled"\n' file_text += ' }\n' file_text += '}\n' bad_name += '.json' @@ -365,7 +377,8 @@ def main(argv): file_text += ' "library_path": 1,\n' file_text += f' "api_version": "{api_version}",\n' file_text += f' "implementation_version": "{implementation_version}",\n' - file_text += f' "description": "{description}\"\n' + file_text += f' "description": "{description}\",\n' + file_text += f' "disable_environment": "{layer_name}_disabled"\n' file_text += ' }\n' file_text += '}\n' bad_name += '.json' @@ -383,7 +396,8 @@ def main(argv): file_text += f" \"library_path\": \"{library_location.replace('test_layers', 'not_real')}\",\n" file_text += f' "api_version": "{api_version}",\n' file_text += f' "implementation_version": "{implementation_version}",\n' - file_text += f' "description": "{description}\"\n' + file_text += f' "description": "{description}\",\n' + file_text += f' "disable_environment": "{layer_name}_disabled"\n' file_text += ' }\n' file_text += '}\n' bad_name += '.json' @@ -403,7 +417,8 @@ def main(argv): file_text += f' "name": "XR_APILAYER_LUNARG_{layer_name}{bad_name}",\n' file_text += f' "library_path": "{library_location}",\n' file_text += f' "implementation_version": "{implementation_version}",\n' - file_text += f' "description": "{description}\"\n' + file_text += f' "description": "{description}\",\n' + file_text += f' "disable_environment": "{layer_name}_disabled"\n' file_text += ' }\n' file_text += '}\n' bad_name += '.json' @@ -421,7 +436,8 @@ def main(argv): file_text += f' "library_path": "{library_location}",\n' file_text += ' "api_version": 1,\n' file_text += f' "implementation_version": "{implementation_version}",\n' - file_text += f' "description": "{description}\"\n' + file_text += f' "description": "{description}\",\n' + file_text += f' "disable_environment": "{layer_name}_disabled"\n' file_text += ' }\n' file_text += '}\n' bad_name += '.json' @@ -439,7 +455,8 @@ def main(argv): file_text += f' "library_path": "{library_location}",\n' file_text += ' "api_version": 1.0,\n' file_text += f' "implementation_version": "{implementation_version}",\n' - file_text += f' "description": "{description}\"\n' + file_text += f' "description": "{description}\",\n' + file_text += f' "disable_environment": "{layer_name}_disabled"\n' file_text += ' }\n' file_text += '}\n' bad_name += '.json' @@ -457,7 +474,8 @@ def main(argv): file_text += f' "library_path": "{library_location}",\n' file_text += ' "api_version": "string",\n' file_text += f' "implementation_version": "{implementation_version}",\n' - file_text += f' "description": "{description}\"\n' + file_text += f' "description": "{description}\",\n' + file_text += f' "disable_environment": "{layer_name}_disabled"\n' file_text += ' }\n' file_text += '}\n' bad_name += '.json' @@ -475,7 +493,8 @@ def main(argv): file_text += f' "library_path": "{library_location}",\n' file_text += ' "api_version": "15.0",\n' file_text += f' "implementation_version": "{implementation_version}",\n' - file_text += f' "description": "{description}\"\n' + file_text += f' "description": "{description}\",\n' + file_text += f' "disable_environment": "{layer_name}_disabled"\n' file_text += ' }\n' file_text += '}\n' bad_name += '.json' @@ -497,6 +516,7 @@ def main(argv): file_text += f' "api_version": "{api_version}",\n' file_text += f' "implementation_version": "{implementation_version}",\n' file_text += f' "description": "{description}",\n' + file_text += f' "disable_environment": "{layer_name}_disabled",\n' file_text += ' "functions": {\n' file_text += ' "xrNegotiateLoaderApiLayerInterface":\n' file_text += ' "TestLayerAlwaysFailNegotiateLoaderApiLayerInterface"\n' @@ -519,6 +539,7 @@ def main(argv): file_text += f' "api_version": "{api_version}",\n' file_text += f' "implementation_version": "{implementation_version}",\n' file_text += f' "description": "{description}",\n' + file_text += f' "disable_environment": "{layer_name}_disabled",\n' file_text += ' "functions": {\n' file_text += ' "xrNegotiateLoaderApiLayerInterface":\n' file_text += ' "TestLayerNullGipaNegotiateLoaderApiLayerInterface"\n' @@ -541,6 +562,7 @@ def main(argv): file_text += f' "api_version": "{api_version}",\n' file_text += f' "implementation_version": "{implementation_version}",\n' file_text += f' "description": "{description}",\n' + file_text += f' "disable_environment": "{layer_name}_disabled",\n' file_text += ' "functions": {\n' file_text += ' "xrNegotiateLoaderApiLayerInterface":\n' file_text += ' "TestLayerInvalidInterfaceNegotiateLoaderApiLayerInterface"\n' @@ -563,6 +585,7 @@ def main(argv): file_text += f' "api_version": "{api_version}",\n' file_text += f' "implementation_version": "{implementation_version}",\n' file_text += f' "description": "{description}",\n' + file_text += f' "disable_environment": "{layer_name}_disabled",\n' file_text += ' "functions": {\n' file_text += ' "xrNegotiateLoaderApiLayerInterface":\n' file_text += ' "TestLayerInvalidApiNegotiateLoaderApiLayerInterface"\n' @@ -588,7 +611,8 @@ def main(argv): file_text += f' "library_path": "{relative_lib}",\n' file_text += f' "api_version": "{api_version}",\n' file_text += f' "implementation_version": "{implementation_version}",\n' - file_text += f' "description": "{description}\"\n' + file_text += f' "description": "{description}\",\n' + file_text += f' "disable_environment": "{layer_name}_disabled"\n' file_text += ' }\n' file_text += '}\n' layer_suffix_name += '.json' @@ -606,7 +630,8 @@ def main(argv): file_text += f" \"library_path\": \"{relative_lib.replace('test_layers', 'not_real')}\",\n" file_text += f' "api_version": "{api_version}",\n' file_text += f' "implementation_version": "{implementation_version}",\n' - file_text += f' "description": "{description}\"\n' + file_text += f' "description": "{description}\",\n' + file_text += f' "disable_environment": "{layer_name}_disabled"\n' file_text += ' }\n' file_text += '}\n' layer_suffix_name += '.json' diff --git a/src/scripts/template_interaction_info_generated.cpp b/src/scripts/template_interaction_info_generated.cpp index e6edc388..1ef6a28a 100644 --- a/src/scripts/template_interaction_info_generated.cpp +++ b/src/scripts/template_interaction_info_generated.cpp @@ -10,7 +10,7 @@ namespace Conformance { //# macro make_path_entry(binding_path, avail, component) - InputSourcePathAvailData{ + BindingPathData{ /*{ binding_path | quote_string }*/, /*{ component.action_type }*/, InteractionProfileAvailability::Avail_/*{- avail.as_normalized_symbol() }*/ @@ -29,7 +29,7 @@ const std::vector& GetAllInteractionProfiles() // Interaction profile path: /*{ path }*/ // Availability: /*{ profile.availability }*/ - static const InputSourcePathAvailCollection /*{'c' + (path | replace("/", "_") | replace("-", "_")) }*/{ + static const BindingPathDataCollection /*{'c' + (path | replace("/", "_") | replace("-", "_")) }*/{ //# for binding_path, avail, component in profile.generate_binding_paths() /*{ make_path_entry(binding_path, avail, component) | collapse_whitespace }*/, //# endfor From 7162782f4fb5aaa9d9ad7c34bf23c87e4898711b Mon Sep 17 00:00:00 2001 From: Rylie Pavlik Date: Thu, 12 Dec 2024 17:10:53 -0600 Subject: [PATCH 5/5] OpenXR CTS 1.1.43.0 (2024-12-12) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Conformance Tests - Fix: Correctly load the glCompressedTexImage2D function (internal MR 3555, internal issue 2390) - Fix: Upload compressed and mip-mapped textures correctly on OpenGL and OpenGL ES (internal MR 3555, internal issue 2390) - Fix: Fix printing of some printf-based messages in the CTS. (internal MR 3582) - Fix: Broken Android builds - not runnable due to undefined symbol. (internal MR 3596) - Fix: Install manifest for conformance test layer (OpenXR-CTS PR 100) - Improvement: Simplify and refactor selection of swapchain formats. (internal MR 3368) - Improvement: Add ability to quit/fail test for XR_EXT_eye_gaze_interaction by closing your eyes or otherwise losing eye tracking for 10 seconds. (internal MR 3401, internal MR 3587) - Improvement: Add example image for Anisotropy Barn Lamp self-test (internal MR 3555) - Improvement: Rename types, fields, and variables to use the term “binding path” when appropriate. In the past these have sometimes been confusingly called “input sources” despite being unrelated to the paths returned from xrEnumerateBoundSourcesForAction and passed to xrGetInputSourceLocalizedName. (internal MR 3561) - Improvement: Code cleanup, documentation, and consistency improvements. (internal MR 3575, internal MR 3609) - Improvement: Update jnipp, used for Android loader builds. New version includes a build fix for some environments, as well as a crash fix. (internal MR 3589) - Improvement: Add Vulkan debug messages during Vulkan instance creation. (internal MR 3592) - Improvement: Test correct non-availability in the xrLocateSpacesKHR and xrLocateSpaces tests, as well as the non-interactive local floor tests. (internal MR 3619) - New test: Automated test that attempts to write from a compute shader to swapchain images in formats that support unordered access, via Vulkan. D3D11/12 check flags to see that they could do so but do not yet actually attempt it. (internal MR 3379, internal issue 2162, internal issue 2400, internal MR 2597, internal MR 3600) GitOrigin-RevId: 40d446b855b4315965f457e75a63bcd44febb423 --- .gitignore | 3 + CHANGELOG.CTS.md | 50 +++++++++++ changes/conformance/mr.3379.gl.md | 7 -- changes/conformance/mr.3401.gl.md | 1 - changes/conformance/mr.3555.gl.2.md | 1 - changes/conformance/mr.3555.gl.md | 5 -- changes/conformance/mr.3561.gl.md | 1 - changes/conformance/mr.3575.gl.md | 5 -- changes/conformance/mr.3582.gl.md | 1 - changes/conformance/mr.3589.gl.md | 4 - changes/conformance/mr.3592.gl.md | 1 - changes/conformance/mr.3596.gl.md | 1 - changes/conformance/pr.100.gh.OpenXR-CTS.md | 1 - .../test_XR_EXT_eye_gaze_interaction.cpp | 20 +++-- .../test_XR_EXT_local_floor.cpp | 4 +- .../test_XR_KHR_locate_spaces.cpp | 5 +- .../framework/composition_utils.cpp | 6 +- .../framework/conformance_utils.cpp | 6 +- src/conformance/framework/graphics_plugin.h | 11 ++- .../framework/graphics_plugin_d3d11.cpp | 70 ++++++--------- .../framework/graphics_plugin_d3d12.cpp | 70 ++++++--------- .../framework/graphics_plugin_impl_helpers.h | 31 ++++++- .../framework/graphics_plugin_metal.cpp | 69 ++++++-------- .../framework/graphics_plugin_opengl.cpp | 87 +++++++----------- .../framework/graphics_plugin_opengles.cpp | 90 +++++++------------ .../framework/graphics_plugin_vulkan.cpp | 74 +++++++-------- src/scripts/conformance_layer_generator.py | 4 + src/scripts/template_gen_dispatch.cpp | 5 +- 28 files changed, 306 insertions(+), 327 deletions(-) delete mode 100644 changes/conformance/mr.3379.gl.md delete mode 100644 changes/conformance/mr.3401.gl.md delete mode 100644 changes/conformance/mr.3555.gl.2.md delete mode 100644 changes/conformance/mr.3555.gl.md delete mode 100644 changes/conformance/mr.3561.gl.md delete mode 100644 changes/conformance/mr.3575.gl.md delete mode 100644 changes/conformance/mr.3582.gl.md delete mode 100644 changes/conformance/mr.3589.gl.md delete mode 100644 changes/conformance/mr.3592.gl.md delete mode 100644 changes/conformance/mr.3596.gl.md delete mode 100644 changes/conformance/pr.100.gh.OpenXR-CTS.md diff --git a/.gitignore b/.gitignore index 386c5312..62a3d5c3 100644 --- a/.gitignore +++ b/.gitignore @@ -84,6 +84,9 @@ local.properties *.pom clang-format-patches/ /*.jar +/*.diff +/*.log +/*.pdf # Key stores *.jks diff --git a/CHANGELOG.CTS.md b/CHANGELOG.CTS.md index 21a16161..862d33a6 100644 --- a/CHANGELOG.CTS.md +++ b/CHANGELOG.CTS.md @@ -17,6 +17,56 @@ 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.43.0 (2024-12-12) + +- Conformance Tests + - Fix: Correctly load the `glCompressedTexImage2D` function + ([internal MR 3555](https://gitlab.khronos.org/openxr/openxr/merge_requests/3555), + [internal issue 2390](https://gitlab.khronos.org/openxr/openxr/issues/2390)) + - Fix: Upload compressed and mip-mapped textures correctly on OpenGL and OpenGL + ES + ([internal MR 3555](https://gitlab.khronos.org/openxr/openxr/merge_requests/3555), + [internal issue 2390](https://gitlab.khronos.org/openxr/openxr/issues/2390)) + - Fix: Fix printing of some printf-based messages in the CTS. + ([internal MR 3582](https://gitlab.khronos.org/openxr/openxr/merge_requests/3582)) + - Fix: Broken Android builds - not runnable due to undefined symbol. + ([internal MR 3596](https://gitlab.khronos.org/openxr/openxr/merge_requests/3596)) + - Fix: Install manifest for conformance test layer + ([OpenXR-CTS PR 100](https://github.com/KhronosGroup/OpenXR-CTS/pull/100)) + - Improvement: Simplify and refactor selection of swapchain formats. + ([internal MR 3368](https://gitlab.khronos.org/openxr/openxr/merge_requests/3368)) + - Improvement: Add ability to quit/fail test for `XR_EXT_eye_gaze_interaction` by + closing your eyes or otherwise losing eye tracking for 10 seconds. + ([internal MR 3401](https://gitlab.khronos.org/openxr/openxr/merge_requests/3401), + [internal MR 3587](https://gitlab.khronos.org/openxr/openxr/merge_requests/3587)) + - Improvement: Add example image for _Anisotropy Barn Lamp_ self-test + ([internal MR 3555](https://gitlab.khronos.org/openxr/openxr/merge_requests/3555)) + - Improvement: Rename types, fields, and variables to use the term "binding path" + when appropriate. In the past these have sometimes been confusingly called + "input sources" despite being unrelated to the paths returned from + `xrEnumerateBoundSourcesForAction` and passed to + `xrGetInputSourceLocalizedName`. + ([internal MR 3561](https://gitlab.khronos.org/openxr/openxr/merge_requests/3561)) + - Improvement: Code cleanup, documentation, and consistency improvements. + ([internal MR 3575](https://gitlab.khronos.org/openxr/openxr/merge_requests/3575), + [internal MR 3609](https://gitlab.khronos.org/openxr/openxr/merge_requests/3609)) + - Improvement: Update jnipp, used for Android loader builds. New version includes + a build fix for some environments, as well as a crash fix. + ([internal MR 3589](https://gitlab.khronos.org/openxr/openxr/merge_requests/3589)) + - Improvement: Add Vulkan debug messages during Vulkan instance creation. + ([internal MR 3592](https://gitlab.khronos.org/openxr/openxr/merge_requests/3592)) + - Improvement: Test correct non-availability in the `xrLocateSpacesKHR` and + `xrLocateSpaces` tests, as well as the non-interactive local floor tests. + ([internal MR 3619](https://gitlab.khronos.org/openxr/openxr/merge_requests/3619)) + - New test: Automated test that attempts to write from a compute shader to + swapchain images in formats that support unordered access, via Vulkan. D3D11/12 + check flags to see that they *could* do so but do not yet actually attempt it. + ([internal MR 3379](https://gitlab.khronos.org/openxr/openxr/merge_requests/3379), + [internal issue 2162](https://gitlab.khronos.org/openxr/openxr/issues/2162), + [internal issue 2400](https://gitlab.khronos.org/openxr/openxr/issues/2400), + [internal MR 2597](https://gitlab.khronos.org/openxr/openxr/merge_requests/2597), + [internal MR 3600](https://gitlab.khronos.org/openxr/openxr/merge_requests/3600)) + ## OpenXR CTS 1.1.42.0 (2024-11-07) This release, like the previous one, has a separate "Usage Guide" document with diff --git a/changes/conformance/mr.3379.gl.md b/changes/conformance/mr.3379.gl.md deleted file mode 100644 index 8e8b40bc..00000000 --- a/changes/conformance/mr.3379.gl.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -- issue.2162.gl -- issue.2400.gl -- mr.2597.gl -- mr.3600.gl ---- -- New test: Automated test that attempts to write from a compute shader to swapchain images in formats that support unordered access, via Vulkan. D3D11/12 check flags to see that they *could* do so but do not yet actually attempt it. diff --git a/changes/conformance/mr.3401.gl.md b/changes/conformance/mr.3401.gl.md deleted file mode 100644 index 96b49cc3..00000000 --- a/changes/conformance/mr.3401.gl.md +++ /dev/null @@ -1 +0,0 @@ -Improvement: Add ability to quit/fail test for `XR_EXT_eye_gaze_interaction` by closing your eyes or otherwise losing eye tracking for 10 seconds. diff --git a/changes/conformance/mr.3555.gl.2.md b/changes/conformance/mr.3555.gl.2.md deleted file mode 100644 index 78d2a6fd..00000000 --- a/changes/conformance/mr.3555.gl.2.md +++ /dev/null @@ -1 +0,0 @@ -- Improvement: Add example image for _Anisotropy Barn Lamp_ self-test diff --git a/changes/conformance/mr.3555.gl.md b/changes/conformance/mr.3555.gl.md deleted file mode 100644 index fb0c3b8d..00000000 --- a/changes/conformance/mr.3555.gl.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -- issue.2390.gl ---- -- Fix: Correctly load the `glCompressedTexImage2D` function -- Fix: Upload compressed and mip-mapped textures correctly on OpenGL and OpenGL ES diff --git a/changes/conformance/mr.3561.gl.md b/changes/conformance/mr.3561.gl.md deleted file mode 100644 index ae2ba0c9..00000000 --- a/changes/conformance/mr.3561.gl.md +++ /dev/null @@ -1 +0,0 @@ -- Improvement: Rename types, fields, and variables to use the term "binding path" when appropriate. In the past these have sometimes been confusingly called "input sources" despite being unrelated to the paths returned from `xrEnumerateBoundSourcesForAction` and passed to `xrGetInputSourceLocalizedName`. diff --git a/changes/conformance/mr.3575.gl.md b/changes/conformance/mr.3575.gl.md deleted file mode 100644 index 7c23af74..00000000 --- a/changes/conformance/mr.3575.gl.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -- mr.3575.gl -- mr.3609.gl ---- -Improvement: Code cleanup, documentation, and consistency improvements. diff --git a/changes/conformance/mr.3582.gl.md b/changes/conformance/mr.3582.gl.md deleted file mode 100644 index be2aaf71..00000000 --- a/changes/conformance/mr.3582.gl.md +++ /dev/null @@ -1 +0,0 @@ -Fix: Fix printing of some printf-based messages in the CTS. diff --git a/changes/conformance/mr.3589.gl.md b/changes/conformance/mr.3589.gl.md deleted file mode 100644 index 6bbe30be..00000000 --- a/changes/conformance/mr.3589.gl.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -- mr.3589.gl ---- -Improvement: Update jnipp, used for Android loader builds. New version includes a build fix for some environments, as well as a crash fix. diff --git a/changes/conformance/mr.3592.gl.md b/changes/conformance/mr.3592.gl.md deleted file mode 100644 index dcce072c..00000000 --- a/changes/conformance/mr.3592.gl.md +++ /dev/null @@ -1 +0,0 @@ -Improvement: Add Vulkan debug messages during Vulkan instance creation. diff --git a/changes/conformance/mr.3596.gl.md b/changes/conformance/mr.3596.gl.md deleted file mode 100644 index 8a23ccad..00000000 --- a/changes/conformance/mr.3596.gl.md +++ /dev/null @@ -1 +0,0 @@ -Fix: Broken Android builds - not runnable due to undefined symbol. diff --git a/changes/conformance/pr.100.gh.OpenXR-CTS.md b/changes/conformance/pr.100.gh.OpenXR-CTS.md deleted file mode 100644 index 4ae0d93b..00000000 --- a/changes/conformance/pr.100.gh.OpenXR-CTS.md +++ /dev/null @@ -1 +0,0 @@ -Fix: Install manifest for conformance test layer diff --git a/src/conformance/conformance_test/test_XR_EXT_eye_gaze_interaction.cpp b/src/conformance/conformance_test/test_XR_EXT_eye_gaze_interaction.cpp index 83ca15d8..1e02f07f 100644 --- a/src/conformance/conformance_test/test_XR_EXT_eye_gaze_interaction.cpp +++ b/src/conformance/conformance_test/test_XR_EXT_eye_gaze_interaction.cpp @@ -26,12 +26,13 @@ #include using namespace Conformance; -namespace chrono = std::chrono; namespace Conformance { using namespace openxr::math_operators; + using namespace std::chrono_literals; + static constexpr const char* kEyeGazeInteractionUserPath = "/user/eyes_ext"; static constexpr const char* kEyeGazeInteractionPoseInputPath = "/user/eyes_ext/input/gaze_ext/pose"; static constexpr const char* kEyeGazeInteractionProfilePath = "/interaction_profiles/ext/eye_gaze_interaction"; @@ -43,6 +44,8 @@ namespace Conformance static constexpr XrVector3f kVectorUp{0, 1, 0}; static constexpr XrVector3f kVectorForward{0, 0, -1}; + static constexpr std::chrono::seconds kGazeLostTimeout = 10s; + static const auto SystemSupportsEyeGazeInteraction = MakeSystemPropertiesBoolChecker(XrSystemEyeGazeInteractionPropertiesEXT{XR_TYPE_SYSTEM_EYE_GAZE_INTERACTION_PROPERTIES_EXT}, &XrSystemEyeGazeInteractionPropertiesEXT::supportsEyeGazeInteraction); @@ -458,8 +461,7 @@ namespace Conformance instructionsQuad->pose.orientation = Quat::FromAxisAngle(kVectorUp, DegToRad(70)); bool eyeGazeSampleTimeFound = false; - auto lastTrackedGaze = chrono::steady_clock::now(); - const int blinkTimout = 10; + Stopwatch sinceTrackedGazeDuration; auto update = [&](const XrFrameState& frameState) { std::vector renderedCubes; @@ -479,9 +481,9 @@ namespace Conformance // Check if user has requested to complete or fail the test. { // Check if the user closed eyes (or otherwise lost gaze tracking) for ten seconds - const auto lostGazeDuration = chrono::duration_cast(chrono::steady_clock::now() - lastTrackedGaze); - if (lostGazeDuration.count() > blinkTimout) { - FAIL("Test failed by user request"); + if (sinceTrackedGazeDuration.IsStarted() && + std::chrono::duration_cast(sinceTrackedGazeDuration.Elapsed()) >= kGazeLostTimeout) { + FAIL("Test failed by user request - gaze lost for longer than timeout"); } // Check if user has brought the head to the cubes @@ -527,7 +529,11 @@ namespace Conformance // Check if eyes were tracked and reset timeout if ((gazeLocation.locationFlags & XR_SPACE_LOCATION_POSITION_TRACKED_BIT) == XR_SPACE_LOCATION_POSITION_TRACKED_BIT) { - lastTrackedGaze = chrono::steady_clock::now(); + sinceTrackedGazeDuration.Stop(); + } + // not tracked, make sure timer is running. + else if (!sinceTrackedGazeDuration.IsStarted()) { + sinceTrackedGazeDuration.Restart(); } // If at least orientation is valid, show a ray representing the gaze 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 3b4bae9b..ad477c1b 100644 --- a/src/conformance/conformance_test/test_XR_EXT_local_floor.cpp +++ b/src/conformance/conformance_test/test_XR_EXT_local_floor.cpp @@ -163,7 +163,6 @@ namespace Conformance static inline void SharedLocalFloorAutomated(const FeatureSet& featureSet) { GlobalData& globalData = GetGlobalData(); - const std::vector extensions = SkipOrGetExtensions("Local floor", globalData, featureSet); // See if it is explicitly enabled by default FeatureSet enabled; @@ -180,6 +179,9 @@ namespace Conformance } } + // Skip after the "Requirements not enabled" tests, so that unavailability of LOCAL_FLOOR on OpenXR 1.0 is tested before the skip. + const std::vector extensions = SkipOrGetExtensions("Local floor", globalData, featureSet); + SECTION("Validate creation") { AutoBasicInstance instance(extensions); diff --git a/src/conformance/conformance_test/test_XR_KHR_locate_spaces.cpp b/src/conformance/conformance_test/test_XR_KHR_locate_spaces.cpp index 9d1ffeeb..927577b4 100644 --- a/src/conformance/conformance_test/test_XR_KHR_locate_spaces.cpp +++ b/src/conformance/conformance_test/test_XR_KHR_locate_spaces.cpp @@ -45,8 +45,6 @@ namespace Conformance { GlobalData& globalData = GetGlobalData(); - const std::vector extensions = SkipOrGetExtensions("Locate spaces", globalData, featureSet); - SECTION("Requirements not enabled") { // See if it is explicitly enabled by default @@ -67,6 +65,9 @@ namespace Conformance } } + // Skip after the "Requirements not enabled" tests, so that unavailability of xrLocateSpaces{,KHR} on OpenXR 1.0 is tested before the skip. + const std::vector extensions = SkipOrGetExtensions("Locate spaces", globalData, featureSet); + AutoBasicInstance instance(extensions, AutoBasicInstance::createSystemId); PFN_xrLocateSpacesKHR xrLocateSpacesPFN = nullptr; diff --git a/src/conformance/framework/composition_utils.cpp b/src/conformance/framework/composition_utils.cpp index 967a6f2b..09e7a0e6 100644 --- a/src/conformance/framework/composition_utils.cpp +++ b/src/conformance/framework/composition_utils.cpp @@ -213,10 +213,8 @@ namespace Conformance } if (GetGlobalData().IsUsingGraphicsPlugin()) { - m_defaultColorFormat = - GetGlobalData().graphicsPlugin->SelectColorSwapchainFormat(swapchainFormats.data(), swapchainFormats.size()); - m_defaultDepthFormat = - GetGlobalData().graphicsPlugin->SelectDepthSwapchainFormat(swapchainFormats.data(), swapchainFormats.size()); + m_defaultColorFormat = GetGlobalData().graphicsPlugin->SelectColorSwapchainFormat(true, swapchainFormats); + m_defaultDepthFormat = GetGlobalData().graphicsPlugin->SelectDepthSwapchainFormat(true, swapchainFormats); } else { m_defaultColorFormat = static_cast(-1); diff --git a/src/conformance/framework/conformance_utils.cpp b/src/conformance/framework/conformance_utils.cpp index 412f57dd..e5a74d95 100644 --- a/src/conformance/framework/conformance_utils.cpp +++ b/src/conformance/framework/conformance_utils.cpp @@ -1112,7 +1112,7 @@ namespace Conformance createInfo.faceCount = cubemap ? 6 : 1; createInfo.createFlags = 0; // XR_SWAPCHAIN_CREATE_PROTECTED_CONTENT_BIT or XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT createInfo.usageFlags = usageFlags; - createInfo.format = graphicsPlugin->SelectColorSwapchainFormat(formatArray.data(), formatArray.size()); + createInfo.format = graphicsPlugin->SelectColorSwapchainFormat(true, formatArray); createInfo.sampleCount = 1; createInfo.width = (uint32_t)widthHeight->width; createInfo.height = (uint32_t)widthHeight->height; @@ -1159,7 +1159,7 @@ namespace Conformance 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->SelectDepthSwapchainFormat(formatArray.data(), formatArray.size()); + createInfo.format = graphicsPlugin->SelectDepthSwapchainFormat(true, formatArray); createInfo.sampleCount = 1; createInfo.width = (uint32_t)widthHeight->width; createInfo.height = (uint32_t)widthHeight->height; @@ -1202,7 +1202,7 @@ namespace Conformance 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.format = graphicsPlugin->SelectMotionVectorSwapchainFormat(true, formatArray); createInfo.sampleCount = 1; createInfo.width = (uint32_t)widthHeight->width; createInfo.height = (uint32_t)widthHeight->height; diff --git a/src/conformance/framework/graphics_plugin.h b/src/conformance/framework/graphics_plugin.h index 595fe407..65562b12 100644 --- a/src/conformance/framework/graphics_plugin.h +++ b/src/conformance/framework/graphics_plugin.h @@ -311,14 +311,17 @@ namespace Conformance virtual bool ValidateSwapchainImageState(XrSwapchain /*swapchain*/, uint32_t /*index*/, int64_t /*imageFormat*/) const noexcept(false) = 0; + /// Select the first supported color swapchain format from the list of available formats. /// Implementation must select a format with alpha unless there are none with alpha. - virtual int64_t SelectColorSwapchainFormat(const int64_t* /*imageFormatArray*/, size_t /*count*/) const = 0; + /// (As of writing, no backend supports a format without alpha, so this may be buggy.) + virtual int64_t SelectColorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const = 0; - /// Select the preferred swapchain format from the list of available formats. - virtual int64_t SelectDepthSwapchainFormat(const int64_t* /*imageFormatArray*/, size_t /*count*/) const = 0; + /// Select the first supported depth swapchain format from the list of available formats. + virtual int64_t SelectDepthSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const = 0; + /// Select the first swapchain format appropriate for motion vectors from the list of available formats. /// 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; + virtual int64_t SelectMotionVectorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) 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 3cd3a99d..6f792ad1 100644 --- a/src/conformance/framework/graphics_plugin_d3d11.cpp +++ b/src/conformance/framework/graphics_plugin_d3d11.cpp @@ -188,11 +188,11 @@ namespace Conformance uint32_t* imageCount) const override; bool ValidateSwapchainImageState(XrSwapchain swapchain, uint32_t index, int64_t imageFormat) const override; - int64_t SelectColorSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectColorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const override; - int64_t SelectDepthSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectDepthSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const override; - int64_t SelectMotionVectorSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectMotionVectorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const override; // Format required by RGBAImage type. int64_t GetSRGBA8Format() const override; @@ -593,56 +593,44 @@ namespace Conformance } // Select the preferred swapchain format from the list of available formats. - int64_t D3D11GraphicsPlugin::SelectColorSwapchainFormat(const int64_t* formatArray, size_t count) const + int64_t D3D11GraphicsPlugin::SelectColorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const { // List of supported color swapchain formats. - const std::array f{DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_B8G8R8A8_UNORM}; - - 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; + return SelectSwapchainFormat( // + throwIfNotFound, imageFormatArray, + { + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + }); } // Select the preferred swapchain format from the list of available formats. - int64_t D3D11GraphicsPlugin::SelectDepthSwapchainFormat(const int64_t* formatArray, size_t count) const + int64_t D3D11GraphicsPlugin::SelectDepthSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const { // List of supported depth swapchain formats. - const std::array f{DXGI_FORMAT_D32_FLOAT, DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_D16_UNORM, - DXGI_FORMAT_D32_FLOAT_S8X24_UINT}; - - 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; + return SelectSwapchainFormat( // + throwIfNotFound, imageFormatArray, + { + DXGI_FORMAT_D32_FLOAT, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_D16_UNORM, + DXGI_FORMAT_D32_FLOAT_S8X24_UINT, + }); } // Select the preferred swapchain format from the list of available formats. - int64_t D3D11GraphicsPlugin::SelectMotionVectorSwapchainFormat(const int64_t* formatArray, size_t count) const + int64_t D3D11GraphicsPlugin::SelectMotionVectorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) 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]; + // Implementation must select a signed format with four components unless there are none with alpha. + int64_t alphaFormat = SelectSwapchainFormat( // + false, imageFormatArray, {DXGI_FORMAT_R16G16B16A16_FLOAT}); + if (alphaFormat != -1) { + return alphaFormat; } - - return *it; + return SelectSwapchainFormat( // + throwIfNotFound, imageFormatArray, {DXGI_FORMAT_R32G32B32_FLOAT}); } int64_t D3D11GraphicsPlugin::GetSRGBA8Format() const diff --git a/src/conformance/framework/graphics_plugin_d3d12.cpp b/src/conformance/framework/graphics_plugin_d3d12.cpp index d2b55ec6..fc99d32f 100644 --- a/src/conformance/framework/graphics_plugin_d3d12.cpp +++ b/src/conformance/framework/graphics_plugin_d3d12.cpp @@ -339,11 +339,11 @@ namespace Conformance uint32_t* imageCount) const override; bool ValidateSwapchainImageState(XrSwapchain swapchain, uint32_t index, int64_t imageFormat) const override; - int64_t SelectColorSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectColorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const override; - int64_t SelectDepthSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectDepthSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const override; - int64_t SelectMotionVectorSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectMotionVectorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const override; // Format required by RGBAImage type. int64_t GetSRGBA8Format() const override; @@ -819,56 +819,44 @@ namespace Conformance } // Select the preferred swapchain format from the list of available formats. - int64_t D3D12GraphicsPlugin::SelectColorSwapchainFormat(const int64_t* formatArray, size_t count) const + int64_t D3D12GraphicsPlugin::SelectColorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const { // List of supported color swapchain formats. - const std::array f{DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_B8G8R8A8_UNORM}; - - 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; + return SelectSwapchainFormat( // + throwIfNotFound, imageFormatArray, + { + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, + }); } // Select the preferred swapchain format from the list of available formats. - int64_t D3D12GraphicsPlugin::SelectDepthSwapchainFormat(const int64_t* formatArray, size_t count) const + int64_t D3D12GraphicsPlugin::SelectDepthSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const { // List of supported depth swapchain formats. - const std::array f{DXGI_FORMAT_D32_FLOAT, DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_D16_UNORM, - DXGI_FORMAT_D32_FLOAT_S8X24_UINT}; - - 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; + return SelectSwapchainFormat( // + throwIfNotFound, imageFormatArray, + { + DXGI_FORMAT_D32_FLOAT, + DXGI_FORMAT_D24_UNORM_S8_UINT, + DXGI_FORMAT_D16_UNORM, + DXGI_FORMAT_D32_FLOAT_S8X24_UINT, + }); } // Select the preferred swapchain format from the list of available formats. - int64_t D3D12GraphicsPlugin::SelectMotionVectorSwapchainFormat(const int64_t* formatArray, size_t count) const + int64_t D3D12GraphicsPlugin::SelectMotionVectorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const { - // List of swapchain formats suitable for motion vectors. - const std::array f{DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R32G32B32_FLOAT}; - - 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]; + // Implementation must select a signed format with four components unless there are none with alpha. + int64_t alphaFormat = SelectSwapchainFormat( // + false, imageFormatArray, {DXGI_FORMAT_R16G16B16A16_FLOAT}); + if (alphaFormat != -1) { + return alphaFormat; } - - return *it; + return SelectSwapchainFormat( // + throwIfNotFound, imageFormatArray, {DXGI_FORMAT_R32G32B32_FLOAT}); } int64_t D3D12GraphicsPlugin::GetSRGBA8Format() const diff --git a/src/conformance/framework/graphics_plugin_impl_helpers.h b/src/conformance/framework/graphics_plugin_impl_helpers.h index f11bdb6c..64ec575b 100644 --- a/src/conformance/framework/graphics_plugin_impl_helpers.h +++ b/src/conformance/framework/graphics_plugin_impl_helpers.h @@ -16,12 +16,18 @@ #pragma once -#include +#include + +#include +#include #include #include +#include namespace Conformance { + using nonstd::span; + /// Wraps a vector to keep track of collections of things referenced by a type-safe handle. /// The handle consists of the index in the vector combined with a "generation number" which is /// incremented every time the container is cleared. @@ -92,4 +98,27 @@ namespace Conformance GenerationType m_generationNumber{1}; }; + /// Helper for selecting swapchain formats. + /// + /// @param throwIfNotFound If true, an exception will be thrown if no suitable format is found. + /// @param runtimeSupportedTypes The types exposed by the runtime, in runtime-provided preference order + /// @param usableFormats The formats that would be usable. + /// + /// Returns the first element of @p runtimeSupportedTypes found in @p usableFormats or + /// -1 if no intersection and @p throwIfNotFound is false. + template + int64_t SelectSwapchainFormat(bool throwIfNotFound, span runtimeSupportedTypes, + const std::initializer_list& usableFormats) + { + auto it = std::find_first_of( + runtimeSupportedTypes.begin(), runtimeSupportedTypes.end(), usableFormats.begin(), usableFormats.end(), + [](int64_t supportedFormat, FormatType usableFormat) { return static_cast(usableFormat) == supportedFormat; }); + if (it == runtimeSupportedTypes.end()) { + if (throwIfNotFound) { + throw std::runtime_error("No suitable format was returned by the runtime"); + } + return -1; + } + return *it; + }; } // namespace Conformance diff --git a/src/conformance/framework/graphics_plugin_metal.cpp b/src/conformance/framework/graphics_plugin_metal.cpp index e7015ee0..0c034249 100644 --- a/src/conformance/framework/graphics_plugin_metal.cpp +++ b/src/conformance/framework/graphics_plugin_metal.cpp @@ -239,11 +239,11 @@ namespace Conformance bool ValidateSwapchainImageState(XrSwapchain swapchain, uint32_t index, int64_t imageFormat) const override; - int64_t SelectColorSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectColorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const override; - int64_t SelectDepthSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectDepthSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const override; - int64_t SelectMotionVectorSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectMotionVectorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const override; // Format required by RGBAImage type. int64_t GetSRGBA8Format() const override; @@ -649,55 +649,42 @@ namespace Conformance return true; } - int64_t MetalGraphicsPlugin::SelectColorSwapchainFormat(const int64_t* formatArray, size_t count) const + int64_t MetalGraphicsPlugin::SelectColorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const { // List of supported color swapchain formats. - const std::array f{MTL::PixelFormatRGBA8Unorm_sRGB, MTL::PixelFormatBGRA8Unorm_sRGB, - MTL::PixelFormatRGBA8Unorm, MTL::PixelFormatBGRA8Unorm}; - - 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; + return SelectSwapchainFormat( // + throwIfNotFound, imageFormatArray, + { + MTL::PixelFormatRGBA8Unorm_sRGB, + MTL::PixelFormatBGRA8Unorm_sRGB, + MTL::PixelFormatRGBA8Unorm, + MTL::PixelFormatBGRA8Unorm, + }); } - int64_t MetalGraphicsPlugin::SelectDepthSwapchainFormat(const int64_t* formatArray, size_t count) const + int64_t MetalGraphicsPlugin::SelectDepthSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const { // List of supported depth swapchain formats. - const std::array f{MTL::PixelFormatDepth32Float, MTL::PixelFormatDepth24Unorm_Stencil8, - MTL::PixelFormatDepth16Unorm, MTL::PixelFormatDepth32Float_Stencil8}; - - 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; + return SelectSwapchainFormat( // + throwIfNotFound, imageFormatArray, + { + MTL::PixelFormatDepth32Float, + MTL::PixelFormatDepth24Unorm_Stencil8, + MTL::PixelFormatDepth16Unorm, + MTL::PixelFormatDepth32Float_Stencil8, + }); } // Select the preferred swapchain format from the list of available formats. - int64_t MetalGraphicsPlugin::SelectMotionVectorSwapchainFormat(const int64_t* formatArray, size_t count) const + int64_t MetalGraphicsPlugin::SelectMotionVectorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const { // List of swapchain formats suitable for motion vectors. - const std::array f{MTL::PixelFormatRGBA16Float, MTL::PixelFormatRGBA32Float}; - - 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; + return SelectSwapchainFormat( // + throwIfNotFound, imageFormatArray, + { + MTL::PixelFormatRGBA16Float, + MTL::PixelFormatRGBA32Float, + }); } int64_t MetalGraphicsPlugin::GetSRGBA8Format() const diff --git a/src/conformance/framework/graphics_plugin_opengl.cpp b/src/conformance/framework/graphics_plugin_opengl.cpp index b7e9ddd1..05cb02d0 100644 --- a/src/conformance/framework/graphics_plugin_opengl.cpp +++ b/src/conformance/framework/graphics_plugin_opengl.cpp @@ -409,11 +409,11 @@ namespace Conformance uint32_t* imageCount) const override; bool ValidateSwapchainImageState(XrSwapchain swapchain, uint32_t index, int64_t imageFormat) const override; - int64_t SelectColorSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectColorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const override; - int64_t SelectDepthSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectDepthSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const override; - int64_t SelectMotionVectorSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectMotionVectorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const override; // Format required by RGBAImage type. int64_t GetSRGBA8Format() const override; @@ -902,67 +902,48 @@ namespace Conformance return true; } - int64_t OpenGLGraphicsPlugin::SelectColorSwapchainFormat(const int64_t* formatArray, size_t count) const + int64_t OpenGLGraphicsPlugin::SelectColorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const { // List of supported color swapchain formats, note sRGB formats skipped due to CTS bug. // The order of this list does not effect the priority of selecting formats, the runtime list defines that. - const std::array f{ - GL_RGB10_A2, - GL_RGBA16, - GL_RGBA16F, - GL_RGBA32F, - // The two below should only be used as a fallback, as they are linear color formats without enough bits for color - // depth, thus leading to banding. - GL_RGBA8, - GL_RGBA8_SNORM, - }; - - 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; + return SelectSwapchainFormat( // + throwIfNotFound, imageFormatArray, + { + GL_RGB10_A2, + GL_RGBA16, + GL_RGBA16F, + GL_RGBA32F, + // The two below should only be used as a fallback, as they are linear color formats without enough bits for color + // depth, thus leading to banding. + GL_RGBA8, + GL_RGBA8_SNORM, + }); } - int64_t OpenGLGraphicsPlugin::SelectDepthSwapchainFormat(const int64_t* formatArray, size_t count) const + int64_t OpenGLGraphicsPlugin::SelectDepthSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const { // List of supported depth swapchain formats. - const std::array f{ - GL_DEPTH24_STENCIL8, GL_DEPTH32F_STENCIL8, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT16, - }; - - 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; + return SelectSwapchainFormat( // + throwIfNotFound, imageFormatArray, + { + GL_DEPTH24_STENCIL8, + GL_DEPTH32F_STENCIL8, + GL_DEPTH_COMPONENT24, + GL_DEPTH_COMPONENT32F, + GL_DEPTH_COMPONENT16, + }); } - int64_t OpenGLGraphicsPlugin::SelectMotionVectorSwapchainFormat(const int64_t* formatArray, size_t count) const + int64_t OpenGLGraphicsPlugin::SelectMotionVectorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const { - // List of swapchain formats suitable for motion vectors. - const std::array f{ - GL_RGBA16F, - GL_RGB16F, - }; - - 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]; + // Implementation must select a signed format with four components unless there are none with alpha. + int64_t alphaFormat = SelectSwapchainFormat( // + false, imageFormatArray, {GL_RGBA16F}); + if (alphaFormat != -1) { + return alphaFormat; } - - return *it; + return SelectSwapchainFormat( // + throwIfNotFound, imageFormatArray, {GL_RGB16F}); } int64_t OpenGLGraphicsPlugin::GetSRGBA8Format() const diff --git a/src/conformance/framework/graphics_plugin_opengles.cpp b/src/conformance/framework/graphics_plugin_opengles.cpp index d2c933e0..8c12950a 100644 --- a/src/conformance/framework/graphics_plugin_opengles.cpp +++ b/src/conformance/framework/graphics_plugin_opengles.cpp @@ -282,11 +282,11 @@ namespace Conformance uint32_t* imageCount) const override; bool ValidateSwapchainImageState(XrSwapchain swapchain, uint32_t index, int64_t imageFormat) const override; - int64_t SelectColorSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectColorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const override; - int64_t SelectDepthSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectDepthSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const override; - int64_t SelectMotionVectorSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectMotionVectorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const override; int64_t GetSRGBA8Format() const override; @@ -1105,70 +1105,46 @@ namespace Conformance } // Select the preferred swapchain format from the list of available formats. - int64_t OpenGLESGraphicsPlugin::SelectColorSwapchainFormat(const int64_t* imageFormatArray, size_t count) const + int64_t OpenGLESGraphicsPlugin::SelectColorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const { // List of supported color swapchain formats. // The order of this list does not effect the priority of selecting formats, the runtime list defines that. - const std::array f{ - GL_RGB10_A2, - GL_RGBA16, - GL_RGBA16F, - GL_RGBA32F, - - // The two below should only be used as a fallback, as they are linear color formats without enough bits for color - // depth, thus leading to banding. - GL_RGBA8, - GL_SRGB8_ALPHA8, - }; - - 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; + return SelectSwapchainFormat( // + throwIfNotFound, imageFormatArray, + { + GL_RGB10_A2, + GL_RGBA16, + GL_RGBA16F, + GL_RGBA32F, + + // The two below should only be used as a fallback, as they are linear color formats without enough bits for color + // depth, thus leading to banding. + GL_RGBA8, + GL_SRGB8_ALPHA8, + }); } - int64_t OpenGLESGraphicsPlugin::SelectDepthSwapchainFormat(const int64_t* imageFormatArray, size_t count) const + int64_t OpenGLESGraphicsPlugin::SelectDepthSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const { // List of supported depth swapchain formats. - const std::array f{ - GL_DEPTH24_STENCIL8, - GL_DEPTH_COMPONENT24, - GL_DEPTH_COMPONENT16, - GL_DEPTH_COMPONENT32F, - }; - - 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; + return SelectSwapchainFormat( // + throwIfNotFound, imageFormatArray, + { + GL_DEPTH24_STENCIL8, + GL_DEPTH_COMPONENT24, + GL_DEPTH_COMPONENT16, + GL_DEPTH_COMPONENT32F, + }); } - int64_t OpenGLESGraphicsPlugin::SelectMotionVectorSwapchainFormat(const int64_t* imageFormatArray, size_t count) const + int64_t OpenGLESGraphicsPlugin::SelectMotionVectorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) 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; + // Implementation must select a signed format with four components unless there are none with alpha. + return SelectSwapchainFormat( // + throwIfNotFound, imageFormatArray, + { + GL_RGBA16F, + }); } int64_t OpenGLESGraphicsPlugin::GetSRGBA8Format() const diff --git a/src/conformance/framework/graphics_plugin_vulkan.cpp b/src/conformance/framework/graphics_plugin_vulkan.cpp index 19cc1337..5e52a01b 100644 --- a/src/conformance/framework/graphics_plugin_vulkan.cpp +++ b/src/conformance/framework/graphics_plugin_vulkan.cpp @@ -559,8 +559,8 @@ namespace Conformance XRC_CHECK_THROW_VKCMD(namer.SetName(VK_OBJECT_TYPE_BUFFER, (uint64_t)m_DrawBuffer.idx.buf, "CTS mesh draw index buffer")); XRC_CHECK_THROW_VKCMD(namer.SetName(VK_OBJECT_TYPE_BUFFER, (uint64_t)m_DrawBuffer.vtx.buf, "CTS mesh draw vertex buffer")); - m_DrawBuffer.UpdateIndices(nonstd::span(idx_data, idx_count), 0); - m_DrawBuffer.UpdateVertices(nonstd::span(vtx_data, vtx_count), 0); + m_DrawBuffer.UpdateIndices(span(idx_data, idx_count), 0); + m_DrawBuffer.UpdateVertices(span(vtx_data, vtx_count), 0); } VulkanMesh(VulkanMesh&& other) noexcept @@ -658,11 +658,11 @@ namespace Conformance uint32_t* imageCount) const override; bool ValidateSwapchainImageState(XrSwapchain swapchain, uint32_t index, int64_t imageFormat) const override; - int64_t SelectColorSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectColorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const override; - int64_t SelectDepthSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectDepthSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const override; - int64_t SelectMotionVectorSwapchainFormat(const int64_t* imageFormatArray, size_t count) const override; + int64_t SelectMotionVectorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const override; // Format required by RGBAImage type. int64_t GetSRGBA8Format() const override; @@ -1762,56 +1762,44 @@ namespace Conformance } // Select the preferred swapchain format from the list of available formats. - int64_t VulkanGraphicsPlugin::SelectColorSwapchainFormat(const int64_t* formatArray, size_t count) const + int64_t VulkanGraphicsPlugin::SelectColorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const { // List of supported color swapchain formats. - const std::array f{VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_R8G8B8A8_UNORM, - VK_FORMAT_B8G8R8A8_UNORM}; - - 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; + return SelectSwapchainFormat( // + throwIfNotFound, imageFormatArray, + { + VK_FORMAT_R8G8B8A8_SRGB, + VK_FORMAT_B8G8R8A8_SRGB, + VK_FORMAT_R8G8B8A8_UNORM, + VK_FORMAT_B8G8R8A8_UNORM, + }); } // Select the preferred swapchain format from the list of available formats. - int64_t VulkanGraphicsPlugin::SelectDepthSwapchainFormat(const int64_t* formatArray, size_t count) const + int64_t VulkanGraphicsPlugin::SelectDepthSwapchainFormat(bool throwIfNotFound, span imageFormatArray) const { // List of supported depth swapchain formats. - const std::array f{VK_FORMAT_D32_SFLOAT, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D16_UNORM, - VK_FORMAT_D32_SFLOAT_S8_UINT}; - - 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; + return SelectSwapchainFormat( // + throwIfNotFound, imageFormatArray, + { + VK_FORMAT_D32_SFLOAT, + VK_FORMAT_D24_UNORM_S8_UINT, + VK_FORMAT_D16_UNORM, + VK_FORMAT_D32_SFLOAT_S8_UINT, + }); } // Select the preferred swapchain format from the list of available formats. - int64_t VulkanGraphicsPlugin::SelectMotionVectorSwapchainFormat(const int64_t* formatArray, size_t count) const + int64_t VulkanGraphicsPlugin::SelectMotionVectorSwapchainFormat(bool throwIfNotFound, span imageFormatArray) 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]; + // Implementation must select a signed format with four components unless there are none with alpha. + int64_t alphaFormat = SelectSwapchainFormat( // + false, imageFormatArray, {VK_FORMAT_R16G16B16A16_SFLOAT}); + if (alphaFormat != -1) { + return alphaFormat; } - - return *it; + return SelectSwapchainFormat( // + throwIfNotFound, imageFormatArray, {VK_FORMAT_R16G16B16_SFLOAT}); } int64_t VulkanGraphicsPlugin::GetSRGBA8Format() const diff --git a/src/scripts/conformance_layer_generator.py b/src/scripts/conformance_layer_generator.py index 71657cbf..73ad94dc 100644 --- a/src/scripts/conformance_layer_generator.py +++ b/src/scripts/conformance_layer_generator.py @@ -30,10 +30,14 @@ def make_ext_variable_name(extName): return extName.lower()[3:] +def make_version_variable_name(extName): + return f"version_{extName.lower()[-3:]}_compatible" + def make_environment(): env = make_jinja_environment(file_with_templates_as_sibs=__file__) env.filters['make_ext_variable_name'] = make_ext_variable_name + env.filters['make_version_variable_name'] = make_version_variable_name return env diff --git a/src/scripts/template_gen_dispatch.cpp b/src/scripts/template_gen_dispatch.cpp index 57163776..c7d0191a 100644 --- a/src/scripts/template_gen_dispatch.cpp +++ b/src/scripts/template_gen_dispatch.cpp @@ -174,15 +174,18 @@ static PFN_xrVoidFunction ConformanceLayer_InnerGetInstanceProcAddr( } //# for cur_cmd in sorted_cmds //# set is_core = "XR_VERSION_" in cur_cmd.ext_name +//# set is_core_1_0 = "XR_VERSION_1_0" in cur_cmd.ext_name //# if cur_cmd.name not in skip_hooks and cur_cmd.name != "xrGetInstanceProcAddr" /*{ protect_begin(cur_cmd) }*/ if (strcmp(name, /*{cur_cmd.name | quote_string}*/) == 0) { //# if not is_core if (handleState->conformanceHooks->enabledExtensions./*{cur_cmd.ext_name | make_ext_variable_name}*/) { +//# elif not is_core_1_0 + if (handleState->conformanceHooks->enabledVersions./*{cur_cmd.ext_name | make_version_variable_name}*/) { //# endif return reinterpret_cast(ConformanceLayer_/*{cur_cmd.name}*/); -//# if not is_core +//# if not is_core_1_0 } return nullptr; //# endif