From c42343fd8b7911c369969f9fcce9cbb3c6af533e Mon Sep 17 00:00:00 2001 From: Rylie Pavlik Date: Thu, 6 Jun 2024 17:20:53 -0500 Subject: [PATCH] OpenXR CTS 1.1.37.0 (2024-06-06) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Conformance Tests - Fix: Action test when constrained to right-hand only. (internal MR 3244) - Fix: Skip StereoWithFoveatedInset-interactive if runtime does not support it. (internal MR 3350) - Fix: Dangling pointer in action test. (internal MR 3357) - Fix: Resolve Vulkan validation warning in some tests. (internal MR 3367) - Improvement: Use absolute epsilons for pose comparison in action test. (internal MR 3244) - Improvement: Improve user message in action test. (internal MR 3244) - Improvement: Only suggest binding the proceed action to “…/click” binding paths, rather than all binding paths of boolean type, to avoid accidental activation. (internal MR 3312) - Improvement: Support hiding parts of models in the glTF/PBR subsystem. (internal MR 3314) - Improvement: Code cleanup. (internal MR 3323) - Improvement: Use new XR_API_VERSION_1_0 and XR_API_VERSION_1_1 defines. (internal MR 3329) - Improvement: Relax too strict palm/grip_surface pose assumptions. (internal MR 3345) - Improvement: Add missing extension name tags to test cases. (internal MR 3355) - Improvement: Code cleanup and documentation in helper utilities. (internal MR 3356) - Improvement: Code cleanups and clang-tidy fixes. (internal MR 3357, internal MR 3357) - Improvement: Improve readability of test sources. (internal MR 3358) - Improvement: Fix duplicated inaccurate code comment. (internal MR 3372) - New test: Add interactive tests for XR_KHR_composition_layer_equirect and XR_KHR_composition_layer_equirect2. (internal MR 2882) - New test: Add test which creates a session but does not call xrDestroySession. (internal MR 3247) GitOrigin-RevId: c3e7f173147ad8730e9041e04b7e7b2d61c5de4c --- CHANGELOG.CTS.md | 45 +++++++++ changes/conformance/mr.2882.gl.md | 1 - changes/conformance/mr.3247.gl.md | 1 - changes/conformance/mr.3329.gl.md | 1 - changes/conformance/mr.3345.gl.md | 1 - changes/conformance/mr.3350.gl.md | 1 - changes/conformance/mr.3355.gl.md | 1 - changes/conformance/mr.3356.gl.md | 1 - changes/conformance/mr.3357.gl.1.md | 4 - changes/conformance/mr.3357.gl.md | 1 - changes/conformance/mr.3358.gl.md | 1 - .../conformance_test/test_ActionPoses.cpp | 2 +- .../conformance_test/test_HapticInterrupt.cpp | 2 +- .../test_InteractiveThrow.cpp | 2 +- .../conformance_test/test_SessionState.cpp | 22 +++-- .../conformance_test/test_SpaceOffsets.cpp | 2 +- .../conformance_test/test_Swapchains.cpp | 13 ++- .../test_XR_EXT_eye_gaze_interaction.cpp | 2 +- .../test_XR_EXT_palm_pose.cpp | 2 +- .../test_XR_MSFT_controller_model.cpp | 2 +- .../conformance_test/test_actions.cpp | 81 +++++++++++----- .../conformance_test/test_glTFRendering.cpp | 2 +- .../conformance_test/test_multithreading.cpp | 4 +- .../test_xrCreateSwapchain.cpp | 2 +- .../conformance_test/test_xrLocateViews.cpp | 13 ++- src/conformance/framework/action_utils.cpp | 93 +++++++++++++++++++ src/conformance/framework/action_utils.h | 3 + .../framework/conformance_utils.cpp | 18 ++-- src/conformance/framework/conformance_utils.h | 3 +- .../framework/input_testinputdevice.cpp | 4 +- .../framework/input_testinputdevice.h | 4 +- .../framework/pbr/D3D11/D3D11Model.cpp | 9 +- .../framework/pbr/D3D11/D3D11Primitive.cpp | 9 +- .../framework/pbr/D3D11/D3D11Primitive.h | 9 +- .../framework/pbr/D3D12/D3D12Model.cpp | 9 +- .../framework/pbr/D3D12/D3D12Primitive.cpp | 9 +- .../framework/pbr/D3D12/D3D12Primitive.h | 10 +- src/conformance/framework/pbr/GltfLoader.cpp | 2 + .../framework/pbr/OpenGL/GLModel.cpp | 9 +- .../framework/pbr/OpenGL/GLPrimitive.cpp | 5 +- .../framework/pbr/OpenGL/GLPrimitive.h | 9 +- src/conformance/framework/pbr/PbrCommon.cpp | 10 ++ src/conformance/framework/pbr/PbrCommon.h | 4 + src/conformance/framework/pbr/PbrModel.h | 69 +++++++++++--- .../framework/pbr/Vulkan/VkModel.cpp | 9 +- .../framework/pbr/Vulkan/VkPrimitive.cpp | 7 +- .../framework/pbr/Vulkan/VkPrimitive.h | 10 +- .../framework/pbr/Vulkan/VkResources.cpp | 9 +- 48 files changed, 413 insertions(+), 119 deletions(-) delete mode 100644 changes/conformance/mr.2882.gl.md delete mode 100644 changes/conformance/mr.3247.gl.md delete mode 100644 changes/conformance/mr.3329.gl.md delete mode 100644 changes/conformance/mr.3345.gl.md delete mode 100644 changes/conformance/mr.3350.gl.md delete mode 100644 changes/conformance/mr.3355.gl.md delete mode 100644 changes/conformance/mr.3356.gl.md delete mode 100644 changes/conformance/mr.3357.gl.1.md delete mode 100644 changes/conformance/mr.3357.gl.md delete mode 100644 changes/conformance/mr.3358.gl.md diff --git a/CHANGELOG.CTS.md b/CHANGELOG.CTS.md index 6a354453..292b985a 100644 --- a/CHANGELOG.CTS.md +++ b/CHANGELOG.CTS.md @@ -17,6 +17,51 @@ 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.37.0 (2024-06-06) + +- Conformance Tests + - Fix: Action test when constrained to right-hand only. + ([internal MR 3244](https://gitlab.khronos.org/openxr/openxr/merge_requests/3244)) + - Fix: Skip StereoWithFoveatedInset-interactive if runtime does not support it. + ([internal MR 3350](https://gitlab.khronos.org/openxr/openxr/merge_requests/3350)) + - Fix: Dangling pointer in action test. + ([internal MR 3357](https://gitlab.khronos.org/openxr/openxr/merge_requests/3357)) + - Fix: Resolve Vulkan validation warning in some tests. + ([internal MR 3367](https://gitlab.khronos.org/openxr/openxr/merge_requests/3367)) + - Improvement: Use absolute epsilons for pose comparison in action test. + ([internal MR 3244](https://gitlab.khronos.org/openxr/openxr/merge_requests/3244)) + - Improvement: Improve user message in action test. + ([internal MR 3244](https://gitlab.khronos.org/openxr/openxr/merge_requests/3244)) + - Improvement: Only suggest binding the proceed action to ".../click" binding + paths, rather than all binding paths of boolean type, to avoid accidental + activation. + ([internal MR 3312](https://gitlab.khronos.org/openxr/openxr/merge_requests/3312)) + - Improvement: Support hiding parts of models in the glTF/PBR subsystem. + ([internal MR 3314](https://gitlab.khronos.org/openxr/openxr/merge_requests/3314)) + - Improvement: Code cleanup. + ([internal MR 3323](https://gitlab.khronos.org/openxr/openxr/merge_requests/3323)) + - Improvement: Use new `XR_API_VERSION_1_0` and `XR_API_VERSION_1_1` defines. + ([internal MR 3329](https://gitlab.khronos.org/openxr/openxr/merge_requests/3329)) + - Improvement: Relax too strict palm/grip_surface pose assumptions. + ([internal MR 3345](https://gitlab.khronos.org/openxr/openxr/merge_requests/3345)) + - Improvement: Add missing extension name tags to test cases. + ([internal MR 3355](https://gitlab.khronos.org/openxr/openxr/merge_requests/3355)) + - Improvement: Code cleanup and documentation in helper utilities. + ([internal MR 3356](https://gitlab.khronos.org/openxr/openxr/merge_requests/3356)) + - Improvement: Code cleanups and clang-tidy fixes. + ([internal MR 3357](https://gitlab.khronos.org/openxr/openxr/merge_requests/3357), + [internal MR 3357](https://gitlab.khronos.org/openxr/openxr/merge_requests/3357)) + - Improvement: Improve readability of test sources. + ([internal MR 3358](https://gitlab.khronos.org/openxr/openxr/merge_requests/3358)) + - Improvement: Fix duplicated inaccurate code comment. + ([internal MR 3372](https://gitlab.khronos.org/openxr/openxr/merge_requests/3372)) + - New test: Add interactive tests for `XR_KHR_composition_layer_equirect` and + `XR_KHR_composition_layer_equirect2`. + ([internal MR 2882](https://gitlab.khronos.org/openxr/openxr/merge_requests/2882)) + - New test: Add test which creates a session but does not call + `xrDestroySession`. + ([internal MR 3247](https://gitlab.khronos.org/openxr/openxr/merge_requests/3247)) + ## OpenXR CTS 1.1.36.0 (2024-04-25) This new release supports testing both OpenXR 1.0 and OpenXR 1.1 runtimes, and diff --git a/changes/conformance/mr.2882.gl.md b/changes/conformance/mr.2882.gl.md deleted file mode 100644 index cf9b73bc..00000000 --- a/changes/conformance/mr.2882.gl.md +++ /dev/null @@ -1 +0,0 @@ -New test: Add interactive tests for `XR_KHR_composition_layer_equirect` and `XR_KHR_composition_layer_equirect2`. diff --git a/changes/conformance/mr.3247.gl.md b/changes/conformance/mr.3247.gl.md deleted file mode 100644 index 561e6194..00000000 --- a/changes/conformance/mr.3247.gl.md +++ /dev/null @@ -1 +0,0 @@ -New test: Add test which creates a session but does not call `xrDestroySession`. diff --git a/changes/conformance/mr.3329.gl.md b/changes/conformance/mr.3329.gl.md deleted file mode 100644 index de2028b6..00000000 --- a/changes/conformance/mr.3329.gl.md +++ /dev/null @@ -1 +0,0 @@ -Improvement: Use new `XR_API_VERSION_1_0` and `XR_API_VERSION_1_1` defines. diff --git a/changes/conformance/mr.3345.gl.md b/changes/conformance/mr.3345.gl.md deleted file mode 100644 index 46c4f98b..00000000 --- a/changes/conformance/mr.3345.gl.md +++ /dev/null @@ -1 +0,0 @@ -Improvement: Relax too strict palm/grip_surface pose assumptions. diff --git a/changes/conformance/mr.3350.gl.md b/changes/conformance/mr.3350.gl.md deleted file mode 100644 index e6faac7d..00000000 --- a/changes/conformance/mr.3350.gl.md +++ /dev/null @@ -1 +0,0 @@ -Fix: Skip StereoWithFoveatedInset-interactive if runtime does not support it. diff --git a/changes/conformance/mr.3355.gl.md b/changes/conformance/mr.3355.gl.md deleted file mode 100644 index 623f4374..00000000 --- a/changes/conformance/mr.3355.gl.md +++ /dev/null @@ -1 +0,0 @@ -Improvement: Add missing extension name tags to test cases. diff --git a/changes/conformance/mr.3356.gl.md b/changes/conformance/mr.3356.gl.md deleted file mode 100644 index 04ccf5d1..00000000 --- a/changes/conformance/mr.3356.gl.md +++ /dev/null @@ -1 +0,0 @@ -Improvement: Code cleanup and documentation in helper utilities. diff --git a/changes/conformance/mr.3357.gl.1.md b/changes/conformance/mr.3357.gl.1.md deleted file mode 100644 index 932734ab..00000000 --- a/changes/conformance/mr.3357.gl.1.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -- mr.3357.gl ---- -Improvement: Code cleanups and clang-tidy fixes. diff --git a/changes/conformance/mr.3357.gl.md b/changes/conformance/mr.3357.gl.md deleted file mode 100644 index ab483f38..00000000 --- a/changes/conformance/mr.3357.gl.md +++ /dev/null @@ -1 +0,0 @@ -Fix: Dangling pointer in action test. diff --git a/changes/conformance/mr.3358.gl.md b/changes/conformance/mr.3358.gl.md deleted file mode 100644 index 8c4dddf7..00000000 --- a/changes/conformance/mr.3358.gl.md +++ /dev/null @@ -1 +0,0 @@ -Improvement: Improve readability of test sources. diff --git a/src/conformance/conformance_test/test_ActionPoses.cpp b/src/conformance/conformance_test/test_ActionPoses.cpp index af356631..209c7620 100644 --- a/src/conformance/conformance_test/test_ActionPoses.cpp +++ b/src/conformance/conformance_test/test_ActionPoses.cpp @@ -278,7 +278,7 @@ namespace Conformance viewState.viewStateFlags & XR_VIEW_STATE_ORIENTATION_VALID_BIT) { const auto& views = std::get>(viewData); - // Render into each view port of the wide swapchain using the projection layer view fov and pose. + // 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) { diff --git a/src/conformance/conformance_test/test_HapticInterrupt.cpp b/src/conformance/conformance_test/test_HapticInterrupt.cpp index 1adce26c..1afce9c2 100644 --- a/src/conformance/conformance_test/test_HapticInterrupt.cpp +++ b/src/conformance/conformance_test/test_HapticInterrupt.cpp @@ -219,7 +219,7 @@ namespace Conformance viewState.viewStateFlags & XR_VIEW_STATE_ORIENTATION_VALID_BIT) { const auto& views = std::get>(viewData); - // Render into each view port of the wide swapchain using the projection layer view fov and pose. + // 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); diff --git a/src/conformance/conformance_test/test_InteractiveThrow.cpp b/src/conformance/conformance_test/test_InteractiveThrow.cpp index d05929ec..e52374c2 100644 --- a/src/conformance/conformance_test/test_InteractiveThrow.cpp +++ b/src/conformance/conformance_test/test_InteractiveThrow.cpp @@ -279,7 +279,7 @@ namespace Conformance viewState.viewStateFlags & XR_VIEW_STATE_ORIENTATION_VALID_BIT) { const auto& views = std::get>(viewData); - // Render into each view port of the wide swapchain using the projection layer view fov and pose. + // 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); diff --git a/src/conformance/conformance_test/test_SessionState.cpp b/src/conformance/conformance_test/test_SessionState.cpp index 645a23ce..930d2d2e 100644 --- a/src/conformance/conformance_test/test_SessionState.cpp +++ b/src/conformance/conformance_test/test_SessionState.cpp @@ -14,6 +14,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "catch2/matchers/catch_matchers.hpp" +#include "catch2/matchers/catch_matchers_vector.hpp" #include "utilities/utils.h" #include "conformance_utils.h" #include "conformance_framework.h" @@ -45,6 +47,9 @@ namespace Conformance REQUIRE_MSG(session != XR_NULL_HANDLE_CPP, "If this (XrSession creation) fails, ensure the runtime is configured and the AR/VR device is present."); + XrInstance instance = session.GetInstance(); + XrSystemId systemId = session.GetSystemId(); + auto tryReadEvent = [&](XrEventDataBuffer* evt) { *evt = {XR_TYPE_EVENT_DATA_BUFFER}; XrResult res; @@ -88,10 +93,9 @@ namespace Conformance { // Get the list of supported view configurations uint32_t viewCount = 0; - REQUIRE(XR_SUCCESS == xrEnumerateViewConfigurations(session.instance, session.systemId, 0, &viewCount, nullptr)); + REQUIRE(XR_SUCCESS == xrEnumerateViewConfigurations(instance, systemId, 0, &viewCount, nullptr)); std::vector runtimeViewTypes(viewCount); - REQUIRE(XR_SUCCESS == - xrEnumerateViewConfigurations(session.instance, session.systemId, viewCount, &viewCount, runtimeViewTypes.data())); + REQUIRE(XR_SUCCESS == xrEnumerateViewConfigurations(instance, systemId, viewCount, &viewCount, runtimeViewTypes.data())); for (XrViewConfigurationType viewType : KnownViewTypes) { CAPTURE(viewType); @@ -99,15 +103,13 @@ namespace Conformance // Is this enum valid, check against enabled extensions. bool valid = IsViewConfigurationTypeEnumValid(viewType); - const bool isSupportedType = - std::find(runtimeViewTypes.begin(), runtimeViewTypes.end(), viewType) != runtimeViewTypes.end(); - - if (!valid) { - CHECK_MSG(valid == isSupportedType, "Can not support invalid view configuration type"); + if (!IsViewConfigurationTypeEnumValid(viewType)) { + INFO("Must not enumerate invalid view configuration type"); + CHECK_THAT(runtimeViewTypes, !Catch::Matchers::VectorContains(viewType)); } - // Skip this view config. - if (isSupportedType) { + // Skip this view config if it is supported, since we cannot test correct handling of unsupported values with it. + if (Catch::Matchers::VectorContains(viewType).match(runtimeViewTypes)) { continue; } diff --git a/src/conformance/conformance_test/test_SpaceOffsets.cpp b/src/conformance/conformance_test/test_SpaceOffsets.cpp index 6b5a920d..1d799baa 100644 --- a/src/conformance/conformance_test/test_SpaceOffsets.cpp +++ b/src/conformance/conformance_test/test_SpaceOffsets.cpp @@ -569,7 +569,7 @@ namespace Conformance viewState.viewStateFlags & XR_VIEW_STATE_ORIENTATION_VALID_BIT) { const auto& views = std::get>(viewData); - // Render into each view port of the wide swapchain using the projection layer view fov and pose. + // 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); diff --git a/src/conformance/conformance_test/test_Swapchains.cpp b/src/conformance/conformance_test/test_Swapchains.cpp index c7b7ed1b..92ec7976 100644 --- a/src/conformance/conformance_test/test_Swapchains.cpp +++ b/src/conformance/conformance_test/test_Swapchains.cpp @@ -433,6 +433,9 @@ namespace Conformance REQUIRE_THAT(imageFormatArray, VectorHasOnlyUniqueElements()); REQUIRE_THAT(imageFormatArray, !Catch::Matchers::VectorContains(kImageFormatInvalid)); + XrInstance instance = session.GetInstance(); + XrSystemId systemId = session.GetSystemId(); + SECTION("Swapchain creation test parameters") { // At this point, session.viewConfigurationViewVector has the system's set of view configurations, @@ -446,8 +449,7 @@ namespace Conformance for (int64_t imageFormat : imageFormatArray) { SwapchainCreateTestParameters tp; - REQUIRE(globalData.graphicsPlugin->GetSwapchainCreateTestParameters(session.instance, session, session.systemId, - imageFormat, &tp)); + REQUIRE(globalData.graphicsPlugin->GetSwapchainCreateTestParameters(instance, session, systemId, imageFormat, &tp)); // TODO remove this when we can mark it as a stencil-only format. if (tp.imageFormatName == "VK_FORMAT_S8_UINT") { @@ -485,6 +487,8 @@ namespace Conformance // Set up the session we will use for the testing AutoBasicSession session(AutoBasicSession::OptionFlags::beginSession); + XrInstance instance = session.GetInstance(); + XrSystemId systemId = session.GetSystemId(); // Enumerate formats std::vector imageFormatArray; @@ -498,7 +502,7 @@ namespace Conformance } } const XrSwapchainCreateInfo defaultColorCreateInfo = - FindDefaultColorSwapchainCreateInfo(imageFormatArray, session.instance, session.systemId, session); + FindDefaultColorSwapchainCreateInfo(imageFormatArray, instance, systemId, session); // In the past, bugs in the CTS have made this fail when called back to back (or called right before graphics shutdown) // Because it can be hard to debug failures in these tests, try to provoke this particular issue early, @@ -509,8 +513,7 @@ namespace Conformance for (int64_t imageFormat : imageFormatArray) { SwapchainCreateTestParameters tp; - REQUIRE( - globalData.graphicsPlugin->GetSwapchainCreateTestParameters(session.instance, session, session.systemId, imageFormat, &tp)); + REQUIRE(globalData.graphicsPlugin->GetSwapchainCreateTestParameters(instance, session, systemId, imageFormat, &tp)); if (!tp.supportsRendering) { // skip this format 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 ae8d6d66..fff9e6b1 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 @@ -557,7 +557,7 @@ namespace Conformance viewState.viewStateFlags & XR_VIEW_STATE_ORIENTATION_VALID_BIT) { const auto& views = std::get>(viewData); - // Render into each view port of the wide swapchain using the projection layer view fov and pose. + // 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); 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 ec790ee0..f145ff0f 100644 --- a/src/conformance/conformance_test/test_XR_EXT_palm_pose.cpp +++ b/src/conformance/conformance_test/test_XR_EXT_palm_pose.cpp @@ -417,7 +417,7 @@ namespace Conformance viewState.viewStateFlags & XR_VIEW_STATE_ORIENTATION_VALID_BIT) { const auto& views = std::get>(viewData); - // Render into each view port of the wide swapchain using the projection layer view fov and pose. + // 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) { 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 7f88d5e1..5cb63972 100644 --- a/src/conformance/conformance_test/test_XR_MSFT_controller_model.cpp +++ b/src/conformance/conformance_test/test_XR_MSFT_controller_model.cpp @@ -507,7 +507,7 @@ namespace Conformance viewState.viewStateFlags & XR_VIEW_STATE_ORIENTATION_VALID_BIT) { const auto& views = std::get>(viewData); - // Render into each view port of the wide swapchain using the projection layer view fov and pose. + // 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) { diff --git a/src/conformance/conformance_test/test_actions.cpp b/src/conformance/conformance_test/test_actions.cpp index b4540777..94e01e8b 100644 --- a/src/conformance/conformance_test/test_actions.cpp +++ b/src/conformance/conformance_test/test_actions.cpp @@ -1430,8 +1430,7 @@ namespace Conformance OPTIONAL_DISCONNECTABLE_DEVICE_INFO { - actionLayerManager.DisplayMessage("Turn off " + defaultDevicePathStr + " and wait for 20s"); - defaultInputDevice->SetDeviceActive(false, true); + defaultInputDevice->SetDeviceActive(false, true, XR_NULL_HANDLE, XR_NULL_HANDLE, " and wait for 20s"); WaitUntilPredicateWithTimeout( [&]() { @@ -1443,10 +1442,10 @@ namespace Conformance }, 20s, kActionWaitDelay); - actionLayerManager.DisplayMessage("Wait for 5s"); - actionLayerManager.SyncActionsUntilFocusWithMessage(syncInfo); + actionLayerManager.DisplayMessage("Wait for 5s"); + WaitUntilPredicateWithTimeout( [&]() { actionLayerManager.GetRenderLoop().IterateFrame(); @@ -2667,8 +2666,6 @@ namespace Conformance for (const auto& hapticActionData : hapticActions) { CAPTURE(hapticActionData.Data.Path); - XrPath inputSourcePath = StringToPath(instance, booleanActions[0].Data.Path); - XrHapticActionInfo hapticActionInfo{XR_TYPE_HAPTIC_ACTION_INFO}; hapticActionInfo.action = hapticActionData.Action; @@ -2679,10 +2676,27 @@ namespace Conformance XrActionStateGetInfo getInfo{XR_TYPE_ACTION_STATE_GET_INFO}; + std::vector selectedBooleanActions; + std::copy_if(std::begin(booleanActions), std::end(booleanActions), std::back_inserter(selectedBooleanActions), + [&](const ActionInfo& action) { + const std::string path = std::string(action.Data.Path); + const std::string suffix = "/click"; + return path.size() >= suffix.size() && + path.compare(path.size() - suffix.size(), suffix.size(), suffix) == 0; + }); + + bool foundClickActions = selectedBooleanActions.size() > 0; + if (!foundClickActions) { + // At time of writing, only hand and eye interaction profiles have no path ending in /click. + selectedBooleanActions = booleanActions; + } + + XrPath inputSourcePath = StringToPath(instance, selectedBooleanActions[0].Data.Path); + XrAction currentBooleanAction{XR_NULL_HANDLE}; auto GetBooleanButtonState = [&]() -> bool { actionLayerManager.SyncActionsUntilFocusWithMessage(syncInfo); - for (const auto& booleanActionData : booleanActions) { + for (const auto& booleanActionData : selectedBooleanActions) { getInfo.action = booleanActionData.Action; REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &booleanState), XR_SUCCESS); if (booleanState.changedSinceLastSync && booleanState.currentState) { @@ -2693,7 +2707,19 @@ namespace Conformance return false; }; - actionLayerManager.DisplayMessage("Press any button when you feel the 3 second haptic vibration"); + std::string buttonPromptPrefix = + foundClickActions ? "Activate any boolean .../click action " : "Activate any boolean action "; + std::string buttonPromptSuffix = ""; + if (foundClickActions) { + std::vector actions; + std::transform(selectedBooleanActions.begin(), selectedBooleanActions.end(), std::back_inserter(actions), + [](ActionInfo& action) { return action.Action; }); + std::string localizedActions = actionLayerManager.ListActionsLocalized(syncInfo, actions, ", ", "; on ", ": "); + buttonPromptSuffix = ", e.g.:\non " + localizedActions; + } + + std::string prompt = buttonPromptPrefix + "when you feel the 3 second haptic vibration" + buttonPromptSuffix; + actionLayerManager.DisplayMessage(prompt); actionLayerManager.IterateFrame(); actionLayerManager.Sleep_For(3s); @@ -2711,6 +2737,7 @@ namespace Conformance currentBooleanAction = XR_NULL_HANDLE; WaitUntilPredicateWithTimeout( [&]() { + actionLayerManager.DisplayMessage(prompt); actionLayerManager.GetRenderLoop().IterateFrame(); return GetBooleanButtonState(); }, @@ -2724,7 +2751,11 @@ namespace Conformance REQUIRE_RESULT(xrStopHapticFeedback(session, &hapticActionInfo), XR_SUCCESS); - actionLayerManager.DisplayMessage("Press any button when you feel the short haptic pulse"); + actionLayerManager.IterateFrame(); + actionLayerManager.Sleep_For(0.25s); + + prompt = buttonPromptPrefix + "when you feel the short haptic pulse" + buttonPromptSuffix; + actionLayerManager.DisplayMessage(prompt); actionLayerManager.IterateFrame(); actionLayerManager.Sleep_For(3s); @@ -2741,6 +2772,7 @@ namespace Conformance currentBooleanAction = XR_NULL_HANDLE; WaitUntilPredicateWithTimeout( [&]() { + actionLayerManager.DisplayMessage(prompt); actionLayerManager.GetRenderLoop().IterateFrame(); return GetBooleanButtonState(); }, @@ -3115,6 +3147,8 @@ namespace Conformance } TEST_CASE("action_space_creation_pre_suggest", "[actions][interactive]") { + bool useLeftHand = GetGlobalData().leftHandUnderTest; + // Creates two ActionSpaces // - one is created before xrSuggestInteractionProfileBindings and // - the other is created after. @@ -3149,13 +3183,14 @@ namespace Conformance XrSpace earlyActionSpace{XR_NULL_HANDLE}; REQUIRE_RESULT(xrCreateActionSpace(session, &earlySpaceCreateInfo, &earlyActionSpace), XR_SUCCESS); - std::shared_ptr leftHandInputDevice = CreateTestDevice( + std::shared_ptr handInputDevice = CreateTestDevice( &actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, simpleControllerInteractionProfile, - StringToPath(instance, "/user/hand/left"), GetSimpleInteractionProfile().InputSourcePaths); + StringToPath(instance, useLeftHand ? "/user/hand/left" : "/user/hand/right"), GetSimpleInteractionProfile().InputSourcePaths); compositionHelper.GetInteractionManager().AddActionSet(actionSet); compositionHelper.GetInteractionManager().AddActionBindings( - simpleControllerInteractionProfile, {{poseAction, StringToPath(instance, "/user/hand/left/input/grip/pose")}}); + simpleControllerInteractionProfile, + {{poseAction, StringToPath(instance, useLeftHand ? "/user/hand/left/input/grip/pose" : "/user/hand/right/input/grip/pose")}}); compositionHelper.GetInteractionManager().AttachActionSets(); // Create an ActionSpace after xrSuggestInteractionProfileBindings @@ -3173,7 +3208,7 @@ namespace Conformance createSpaceInfo.poseInReferenceSpace = XrPosefCPP(); REQUIRE_RESULT(xrCreateReferenceSpace(session, &createSpaceInfo, &localSpace), XR_SUCCESS); - leftHandInputDevice->SetDeviceActive(true); + handInputDevice->SetDeviceActive(true); XrActionsSyncInfo syncInfo{XR_TYPE_ACTIONS_SYNC_INFO}; syncInfo.countActiveActionSets = 1; @@ -3183,7 +3218,7 @@ namespace Conformance XrSpaceLocation earlyLocation{XR_TYPE_SPACE_LOCATION, nullptr}; XrSpaceLocation lateLocation{XR_TYPE_SPACE_LOCATION, nullptr}; - REQUIRE(actionLayerManager.WaitForLocatability("left", lateActionSpace, localSpace, &lateLocation, true)); + REQUIRE(actionLayerManager.WaitForLocatability(useLeftHand ? "left" : "right", lateActionSpace, localSpace, &lateLocation, true)); XrTime locateTime = actionLayerManager.GetRenderLoop().GetLastPredictedDisplayTime(); // Ensure using the same time for the pose checks. @@ -3292,14 +3327,13 @@ namespace Conformance syncInfo.activeActionSets = bothSets; auto PosesAreEqual = [](XrPosef a, XrPosef b) -> bool { - constexpr float e = 0.001f; // 1mm - return (a.position.x == Catch::Approx(b.position.x).epsilon(e)) && - (a.position.y == Catch::Approx(b.position.y).epsilon(e)) && - (a.position.z == Catch::Approx(b.position.z).epsilon(e)) && - (a.orientation.x == Catch::Approx(b.orientation.x).epsilon(e)) && - (a.orientation.y == Catch::Approx(b.orientation.y).epsilon(e)) && - (a.orientation.z == Catch::Approx(b.orientation.z).epsilon(e)) && - (a.orientation.w == Catch::Approx(b.orientation.w).epsilon(e)); + constexpr float e = 0.002f; // 1mm (margin below means absolute delta) + return (a.position.x == Catch::Approx(b.position.x).margin(e)) && (a.position.y == Catch::Approx(b.position.y).margin(e)) && + (a.position.z == Catch::Approx(b.position.z).margin(e)) && + (a.orientation.x == Catch::Approx(b.orientation.x).margin(e)) && + (a.orientation.y == Catch::Approx(b.orientation.y).margin(e)) && + (a.orientation.z == Catch::Approx(b.orientation.z).margin(e)) && + (a.orientation.w == Catch::Approx(b.orientation.w).margin(e)); }; if (globalData.leftHandUnderTest && globalData.rightHandUnderTest) { @@ -3484,7 +3518,8 @@ namespace Conformance INFO("Off controller should not have active pose state"); REQUIRE(getActionStatePoseActive() == false); } - availableInputDevice->SetDeviceActiveWithoutWaiting(true, " - Will wait 20s whether or not the controller is found"); + availableInputDevice->SetDeviceActiveWithoutWaiting( + true, "\nSlowly move the controller for 20 seconds to prevent it from going idle and becoming inactive."); { INFO("Pose state should not become active again without a call to xrSyncActions"); REQUIRE(getActionStatePoseActive() == false); diff --git a/src/conformance/conformance_test/test_glTFRendering.cpp b/src/conformance/conformance_test/test_glTFRendering.cpp index 21010dcb..9c1c0a0c 100644 --- a/src/conformance/conformance_test/test_glTFRendering.cpp +++ b/src/conformance/conformance_test/test_glTFRendering.cpp @@ -227,7 +227,7 @@ namespace Conformance viewState.viewStateFlags & XR_VIEW_STATE_ORIENTATION_VALID_BIT) { const auto& views = std::get>(viewData); - // Render into each view port of the wide swapchain using the projection layer view fov and pose. + // 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); diff --git a/src/conformance/conformance_test/test_multithreading.cpp b/src/conformance/conformance_test/test_multithreading.cpp index 05a4d04b..c5ec5741 100644 --- a/src/conformance/conformance_test/test_multithreading.cpp +++ b/src/conformance/conformance_test/test_multithreading.cpp @@ -377,7 +377,7 @@ namespace Conformance XrSessionActionSetsAttachInfo attachInfo{XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO}; attachInfo.countActionSets = 1; attachInfo.actionSets = &env.GetAutoBasicSession().actionSet; - XRC_CHECK_THROW_XRCMD(xrAttachSessionActionSets(env.GetAutoBasicSession().session, &attachInfo)); + XRC_CHECK_THROW_XRCMD(xrAttachSessionActionSets(env.GetAutoBasicSession(), &attachInfo)); } // Get frames iterating to the point of app focused state. This will draw frames along the way. @@ -871,7 +871,7 @@ namespace Conformance RandEngine& randEngine = GetGlobalData().GetRandEngine(); // References to AutoBasicSession members. - XrSession& session = env.GetAutoBasicSession().session; + XrSession session = env.GetAutoBasicSession().GetSession(); XrActionSet& actionSet = env.GetAutoBasicSession().actionSet; std::vector& actionVector = env.GetAutoBasicSession().actionVector; // This actions are part of the actionSet. std::array& handSubactionArray = env.GetAutoBasicSession().handSubactionArray; diff --git a/src/conformance/conformance_test/test_xrCreateSwapchain.cpp b/src/conformance/conformance_test/test_xrCreateSwapchain.cpp index 59297cc8..856095d2 100644 --- a/src/conformance/conformance_test/test_xrCreateSwapchain.cpp +++ b/src/conformance/conformance_test/test_xrCreateSwapchain.cpp @@ -43,7 +43,7 @@ namespace Conformance CAPTURE(formatName); SwapchainCreateTestParameters tp{}; - CHECK(graphicsPlugin->GetSwapchainCreateTestParameters(session.instance, session, session.systemId, format, &tp)); + CHECK(graphicsPlugin->GetSwapchainCreateTestParameters(session.GetInstance(), session, session.GetSystemId(), format, &tp)); XrSwapchainCreateInfo createInfo{ XR_TYPE_SWAPCHAIN_CREATE_INFO, diff --git a/src/conformance/conformance_test/test_xrLocateViews.cpp b/src/conformance/conformance_test/test_xrLocateViews.cpp index ba0ec5cd..7a25aac6 100644 --- a/src/conformance/conformance_test/test_xrLocateViews.cpp +++ b/src/conformance/conformance_test/test_xrLocateViews.cpp @@ -14,6 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "catch2/matchers/catch_matchers_vector.hpp" #include "conformance_utils.h" #include "conformance_framework.h" #include "matchers.h" @@ -106,12 +107,15 @@ namespace Conformance { // Ensure unsupported view configuration types fail and supported types pass + XrInstance instance = session.GetInstance(); + XrSystemId systemId = session.GetSystemId(); + // Get the list of supported view configurations uint32_t viewConfigCount = 0; - REQUIRE(XR_SUCCESS == xrEnumerateViewConfigurations(session.instance, session.systemId, 0, &viewConfigCount, nullptr)); + REQUIRE(XR_SUCCESS == xrEnumerateViewConfigurations(instance, systemId, 0, &viewConfigCount, nullptr)); std::vector runtimeViewTypes(viewConfigCount); - REQUIRE(XR_SUCCESS == xrEnumerateViewConfigurations(session.instance, session.systemId, viewConfigCount, &viewConfigCount, - runtimeViewTypes.data())); + REQUIRE(XR_SUCCESS == + xrEnumerateViewConfigurations(instance, systemId, viewConfigCount, &viewConfigCount, runtimeViewTypes.data())); CAPTURE(locateInfo.displayTime); @@ -123,8 +127,7 @@ namespace Conformance // Is this enum valid, check against enabled extensions. bool valid = IsViewConfigurationTypeEnumValid(viewType); - const bool isSupportedType = - std::find(runtimeViewTypes.begin(), runtimeViewTypes.end(), viewType) != runtimeViewTypes.end(); + const bool isSupportedType = Catch::Matchers::VectorContains(viewType).match(runtimeViewTypes); CAPTURE(valid); CAPTURE(isSupportedType); diff --git a/src/conformance/framework/action_utils.cpp b/src/conformance/framework/action_utils.cpp index 555b27ca..a4871409 100644 --- a/src/conformance/framework/action_utils.cpp +++ b/src/conformance/framework/action_utils.cpp @@ -17,9 +17,40 @@ #include "action_utils.h" #include "composition_utils.h" #include "report.h" +#include "utilities/throw_helpers.h" + +#include using namespace std::chrono_literals; +namespace +{ + static std::vector EnumerateBoundSourcesForAction(XrSession session, const XrBoundSourcesForActionEnumerateInfo& info) + { + std::vector boundSources; + uint32_t countOutput; + XRC_CHECK_THROW_XRCMD(xrEnumerateBoundSourcesForAction(session, &info, 0, &countOutput, nullptr)); + if (countOutput != 0) { + boundSources.resize(countOutput, XR_NULL_PATH); + XRC_CHECK_THROW_XRCMD( + xrEnumerateBoundSourcesForAction(session, &info, (uint32_t)boundSources.size(), &countOutput, boundSources.data())); + } + return boundSources; + } + static std::string GetInputSourceLocalizedName(XrSession session, const XrInputSourceLocalizedNameGetInfo& getInfo) + { + uint32_t countOutput; + XRC_CHECK_THROW_XRCMD(xrGetInputSourceLocalizedName(session, &getInfo, 0, &countOutput, nullptr)); + if (countOutput != 0) { + std::vector localizedStringBuf(countOutput, '\0'); + XRC_CHECK_THROW_XRCMD(xrGetInputSourceLocalizedName(session, &getInfo, (uint32_t)localizedStringBuf.size(), &countOutput, + localizedStringBuf.data())); + return std::string(localizedStringBuf.data()); + } + return ""; + } +} // namespace + namespace Conformance { @@ -152,6 +183,68 @@ namespace Conformance m_lastMessage = message; } + std::string ActionLayerManager::ListActionsLocalized(XrActionsSyncInfo syncInfo, nonstd::span actions, + const char* actionDelimiter, const char* pathDelimiter, const char* pathSuffix) + { + std::vector localizedUserPathsAndProfiles; + std::map> pathsByLocalizedUserPathAndProfile; + + for (auto& action : actions) { + XrBoundSourcesForActionEnumerateInfo info{XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO}; + info.action = action; + + SyncActionsUntilFocusWithMessage(syncInfo); + + std::vector boundSources = EnumerateBoundSourcesForAction(m_compositionHelper.GetSession(), info); + + for (XrPath path : boundSources) { + XrInputSourceLocalizedNameGetInfo getInfo{XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO}; + getInfo.sourcePath = path; + getInfo.whichComponents = + XR_INPUT_SOURCE_LOCALIZED_NAME_USER_PATH_BIT | XR_INPUT_SOURCE_LOCALIZED_NAME_INTERACTION_PROFILE_BIT; + + std::string localizedUserPathAndProfile = GetInputSourceLocalizedName(m_compositionHelper.GetSession(), getInfo); + + auto& paths = pathsByLocalizedUserPathAndProfile[localizedUserPathAndProfile]; + if (paths.size() == 0) { + localizedUserPathsAndProfiles.push_back(localizedUserPathAndProfile); + } + paths.push_back(path); + } + } + + std::ostringstream oss; + + bool firstPathAndProfile = true; + for (auto& localizedUserPathAndProfile : localizedUserPathsAndProfiles) { + if (!firstPathAndProfile) { + oss << pathDelimiter; + } + firstPathAndProfile = false; + + oss << localizedUserPathAndProfile << pathSuffix; + + auto paths = pathsByLocalizedUserPathAndProfile[localizedUserPathAndProfile]; + + bool firstComponent = true; + for (XrPath path : paths) { + if (!firstComponent) { + oss << actionDelimiter; + } + firstComponent = false; + + XrInputSourceLocalizedNameGetInfo getInfo{XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO}; + getInfo.sourcePath = path; + getInfo.whichComponents = XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT; + + std::string localizedComponent = GetInputSourceLocalizedName(m_compositionHelper.GetSession(), getInfo); + + oss << localizedComponent; + } + } + return oss.str(); + } // namespace Conformance + ActionLayerManager::MessageQuad::MessageQuad(CompositionHelper& compositionHelper, std::unique_ptr image, XrSpace compositionSpace) : m_compositionHelper(compositionHelper) diff --git a/src/conformance/framework/action_utils.h b/src/conformance/framework/action_utils.h index efbf2c31..daba1059 100644 --- a/src/conformance/framework/action_utils.h +++ b/src/conformance/framework/action_utils.h @@ -21,6 +21,7 @@ #include "input_testinputdevice.h" #include "utilities/event_reader.h" +#include #include #include @@ -125,6 +126,8 @@ namespace Conformance /// directly or indirectly, through this helper object. /// (Does not directly submit frames!) void DisplayMessage(const std::string& message) override; + std::string ListActionsLocalized(XrActionsSyncInfo syncInfo, nonstd::span actions, const char* actionDelimiter, + const char* pathDelimiter, const char* pathSuffix); private: std::mutex m_mutex; diff --git a/src/conformance/framework/conformance_utils.cpp b/src/conformance/framework/conformance_utils.cpp index 43112439..43aeaeff 100644 --- a/src/conformance/framework/conformance_utils.cpp +++ b/src/conformance/framework/conformance_utils.cpp @@ -668,8 +668,8 @@ namespace Conformance : autoBasicSession(autoBasicSession_), sessionState(autoBasicSession->GetSessionState()), frameState(), viewVector() { XRC_CHECK_THROW(autoBasicSession); - XRC_CHECK_THROW(autoBasicSession->instance); - XRC_CHECK_THROW(autoBasicSession->session); + XRC_CHECK_THROW(autoBasicSession->GetInstance()); + XRC_CHECK_THROW(autoBasicSession->GetSession()); XRC_CHECK_THROW(!autoBasicSession->viewConfigurationTypeVector.empty()); XRC_CHECK_THROW(!autoBasicSession->environmentBlendModeVector.empty()); } @@ -682,7 +682,7 @@ namespace Conformance FrameIterator::TickResult FrameIterator::PollEvent() { XrEventDataBuffer eventData{XR_TYPE_EVENT_DATA_BUFFER}; - XrResult result = xrPollEvent(autoBasicSession->instance, &eventData); + XrResult result = xrPollEvent(autoBasicSession->GetInstance(), &eventData); switch (result) { case XR_SUCCESS: { @@ -748,11 +748,11 @@ namespace Conformance } XrResult result; - + XrSession session = autoBasicSession->GetSession(); // xrWaitFrame may block. XrFrameWaitInfo frameWaitInfo{XR_TYPE_FRAME_WAIT_INFO}; frameState = XrFrameState{XR_TYPE_FRAME_STATE}; - result = xrWaitFrame(autoBasicSession->session, &frameWaitInfo, &frameState); + result = xrWaitFrame(session, &frameWaitInfo, &frameState); if (XR_FAILED(result)) return RunResult::Error; @@ -763,13 +763,13 @@ namespace Conformance XrViewState viewState{XR_TYPE_VIEW_STATE}; uint32_t viewCount = (uint32_t)autoBasicSession->viewConfigurationViewVector.size(); viewVector.resize(viewCount, {XR_TYPE_VIEW}); - result = xrLocateViews(autoBasicSession->session, &viewLocateInfo, &viewState, viewCount, &viewCount, viewVector.data()); + result = xrLocateViews(session, &viewLocateInfo, &viewState, viewCount, &viewCount, viewVector.data()); if (XR_FAILED(result)) return RunResult::Error; viewVector.resize(viewCount); XrFrameBeginInfo frameBeginInfo{XR_TYPE_FRAME_BEGIN_INFO}; - result = xrBeginFrame(autoBasicSession->session, &frameBeginInfo); + result = xrBeginFrame(session, &frameBeginInfo); if (XR_FAILED(result)) return RunResult::Error; @@ -848,7 +848,7 @@ namespace Conformance frameEndInfo.layerCount = 1; frameEndInfo.layers = headerPtrArray; - XrResult result = xrEndFrame(autoBasicSession->session, &frameEndInfo); + XrResult result = xrEndFrame(autoBasicSession->GetSession(), &frameEndInfo); if (XR_FAILED(result)) return RunResult::Error; @@ -902,7 +902,7 @@ namespace Conformance XrSessionBeginInfo sessionBeginInfo{ XR_TYPE_SESSION_BEGIN_INFO, globalData.GetPlatformPlugin()->PopulateNextFieldForStruct(XR_TYPE_SESSION_BEGIN_INFO), globalData.options.viewConfigurationValue}; - REQUIRE(xrBeginSession(autoBasicSession->session, &sessionBeginInfo) == XR_SUCCESS); + REQUIRE(xrBeginSession(autoBasicSession->GetSession(), &sessionBeginInfo) == XR_SUCCESS); } // Fall-through because frames must be submitted to get promoted from READY to SYNCHRONIZED. diff --git a/src/conformance/framework/conformance_utils.h b/src/conformance/framework/conformance_utils.h index 1624cf63..43340daf 100644 --- a/src/conformance/framework/conformance_utils.h +++ b/src/conformance/framework/conformance_utils.h @@ -639,7 +639,7 @@ namespace Conformance return session != XR_NULL_HANDLE; } - public: + private: int optionFlags{0}; //< Enum OptionFlags XrInstance instance{XR_NULL_HANDLE}; @@ -653,6 +653,7 @@ namespace Conformance std::unique_ptr m_eventQueue; std::unique_ptr m_privateEventReader; + public: std::array handSubactionArray; // "/user/hand/left", "/user/hand/right" // Optional created types. diff --git a/src/conformance/framework/input_testinputdevice.cpp b/src/conformance/framework/input_testinputdevice.cpp index 4f7c31b5..cf220d95 100644 --- a/src/conformance/framework/input_testinputdevice.cpp +++ b/src/conformance/framework/input_testinputdevice.cpp @@ -304,10 +304,10 @@ namespace Conformance } void SetDeviceActive(bool state, bool skipInteraction = false, XrAction detectionBoolAction = XR_NULL_HANDLE, - XrActionSet detectionActionSet = XR_NULL_HANDLE) override + XrActionSet detectionActionSet = XR_NULL_HANDLE, const char* extraMessage = nullptr) override { - SetDeviceActiveWithoutWaiting(state); + SetDeviceActiveWithoutWaiting(state, extraMessage); if (skipInteraction) { // Skip human interaction, this is just a hint to the runtime via the extension return; diff --git a/src/conformance/framework/input_testinputdevice.h b/src/conformance/framework/input_testinputdevice.h index bf028b8f..47c59677 100644 --- a/src/conformance/framework/input_testinputdevice.h +++ b/src/conformance/framework/input_testinputdevice.h @@ -44,8 +44,10 @@ namespace Conformance /// @param skipInteraction Skip human interaction (i.e. this is a hint for the conformance extension) /// @param detectionBoolAction Boolean action used to determine if device became active /// @param detectionActionSet Action Set associated with detectionBoolAction + /// @param extraMessage text to append to the end of the message (after "Turn on/off " and the top level user path), + /// if any. virtual void SetDeviceActive(bool state, bool skipInteraction = false, XrAction detectionBoolAction = XR_NULL_HANDLE, - XrActionSet detectionActionSet = XR_NULL_HANDLE) = 0; + XrActionSet detectionActionSet = XR_NULL_HANDLE, const char* extraMessage = nullptr) = 0; /// Call xrLocateSpace until XR_SPACE_LOCATION_ORIENTATION_VALID matches the desired state struct WaitUntilLosesOrGainsOrientationValidity diff --git a/src/conformance/framework/pbr/D3D11/D3D11Model.cpp b/src/conformance/framework/pbr/D3D11/D3D11Model.cpp index 1e7b5896..91f7f736 100644 --- a/src/conformance/framework/pbr/D3D11/D3D11Model.cpp +++ b/src/conformance/framework/pbr/D3D11/D3D11Model.cpp @@ -40,6 +40,9 @@ namespace Pbr if (primitive.GetMaterial()->Hidden) continue; + if (!IsAnyNodeVisible(primitive.GetNodes())) + continue; + primitive.GetMaterial()->Bind(context, pbrResources); primitive.Render(context); } @@ -82,12 +85,12 @@ namespace Pbr void D3D11ModelInstance::UpdateTransforms(Pbr::D3D11Resources const& /*pbrResources*/, _In_ ID3D11DeviceContext* context) { // If none of the node transforms have changed, no need to recompute/update the model transform structured buffer. - if (WereNodeLocalTransformsUpdated()) { - ResolveTransforms(true); + if (ResolvedTransformsNeedUpdate()) { + ResolveTransformsAndVisibilities(true); // Update node transform structured buffer. context->UpdateSubresource(m_modelTransformsStructuredBuffer.Get(), 0, nullptr, GetResolvedTransforms().data(), 0, 0); - ClearTransformsUpdatedFlag(); + MarkResolvedTransformsUpdated(); } } } // namespace Pbr diff --git a/src/conformance/framework/pbr/D3D11/D3D11Primitive.cpp b/src/conformance/framework/pbr/D3D11/D3D11Primitive.cpp index b769e667..c0b313df 100644 --- a/src/conformance/framework/pbr/D3D11/D3D11Primitive.cpp +++ b/src/conformance/framework/pbr/D3D11/D3D11Primitive.cpp @@ -77,11 +77,13 @@ namespace namespace Pbr { D3D11Primitive::D3D11Primitive(UINT indexCount, Microsoft::WRL::ComPtr indexBuffer, - Microsoft::WRL::ComPtr vertexBuffer, std::shared_ptr material) + Microsoft::WRL::ComPtr vertexBuffer, std::shared_ptr material, + std::vector nodeIndices) : m_indexCount(indexCount) , m_indexBuffer(std::move(indexBuffer)) , m_vertexBuffer(std::move(vertexBuffer)) , m_material(std::move(material)) + , m_nodeIndices(std::move(nodeIndices)) { } @@ -89,13 +91,14 @@ namespace Pbr const std::shared_ptr& material, bool updatableBuffers) : D3D11Primitive((UINT)primitiveBuilder.Indices.size(), CreateIndexBuffer(pbrResources.GetDevice().Get(), primitiveBuilder, updatableBuffers), - CreateVertexBuffer(pbrResources.GetDevice().Get(), primitiveBuilder, updatableBuffers), std::move(material)) + CreateVertexBuffer(pbrResources.GetDevice().Get(), primitiveBuilder, updatableBuffers), std::move(material), + primitiveBuilder.NodeIndicesVector()) { } D3D11Primitive D3D11Primitive::Clone(Pbr::D3D11Resources const& pbrResources) const { - return D3D11Primitive(m_indexCount, m_indexBuffer, m_vertexBuffer, m_material->Clone(pbrResources)); + return D3D11Primitive(m_indexCount, m_indexBuffer, m_vertexBuffer, m_material->Clone(pbrResources), m_nodeIndices); } void D3D11Primitive::UpdateBuffers(_In_ ID3D11Device* device, _In_ ID3D11DeviceContext* context, diff --git a/src/conformance/framework/pbr/D3D11/D3D11Primitive.h b/src/conformance/framework/pbr/D3D11/D3D11Primitive.h index 92f709bb..8dc73b1d 100644 --- a/src/conformance/framework/pbr/D3D11/D3D11Primitive.h +++ b/src/conformance/framework/pbr/D3D11/D3D11Primitive.h @@ -26,7 +26,7 @@ namespace Pbr D3D11Primitive() = delete; D3D11Primitive(UINT indexCount, Microsoft::WRL::ComPtr indexBuffer, Microsoft::WRL::ComPtr vertexBuffer, - std::shared_ptr material); + std::shared_ptr material, std::vector nodeIndices); D3D11Primitive(Pbr::D3D11Resources const& pbrResources, const Pbr::PrimitiveBuilder& primitiveBuilder, const std::shared_ptr& material, bool updatableBuffers = false); @@ -44,6 +44,12 @@ namespace Pbr m_material = std::move(material); } + /// Get the nodes that the primitive represents + const std::vector& GetNodes() const + { + return m_nodeIndices; + } + protected: friend class D3D11ModelInstance; void Render(_In_ ID3D11DeviceContext* context) const; @@ -54,5 +60,6 @@ namespace Pbr Microsoft::WRL::ComPtr m_indexBuffer; Microsoft::WRL::ComPtr m_vertexBuffer; std::shared_ptr m_material; + std::vector m_nodeIndices; }; } // namespace Pbr diff --git a/src/conformance/framework/pbr/D3D12/D3D12Model.cpp b/src/conformance/framework/pbr/D3D12/D3D12Model.cpp index e0f96c1a..f3a8a775 100644 --- a/src/conformance/framework/pbr/D3D12/D3D12Model.cpp +++ b/src/conformance/framework/pbr/D3D12/D3D12Model.cpp @@ -45,6 +45,9 @@ namespace Pbr if (primitive.GetMaterial()->Hidden) continue; + if (!IsAnyNodeVisible(primitive.GetNodes())) + continue; + primitive.Render(directCommandList, pbrResources, colorRenderTargetFormat, depthRenderTargetFormat); } } @@ -94,15 +97,15 @@ namespace Pbr void D3D12ModelInstance::UpdateTransforms(Pbr::D3D12Resources& pbrResources) { // If none of the node transforms have changed, no need to recompute/update the model transform structured buffer. - if (WereNodeLocalTransformsUpdated()) { - ResolveTransforms(true); + if (ResolvedTransformsNeedUpdate()) { + ResolveTransformsAndVisibilities(true); // Update node transform structured buffer. auto& resolvedTransforms = GetResolvedTransforms(); pbrResources.WithCopyCommandList([&](ID3D12GraphicsCommandList* cmdList) { m_modelTransformsStructuredBuffer.AsyncUpload(cmdList, resolvedTransforms.data(), resolvedTransforms.size()); }); - ClearTransformsUpdatedFlag(); + MarkResolvedTransformsUpdated(); } } } // namespace Pbr diff --git a/src/conformance/framework/pbr/D3D12/D3D12Primitive.cpp b/src/conformance/framework/pbr/D3D12/D3D12Primitive.cpp index 186a6272..dc7f1ab3 100644 --- a/src/conformance/framework/pbr/D3D12/D3D12Primitive.cpp +++ b/src/conformance/framework/pbr/D3D12/D3D12Primitive.cpp @@ -24,18 +24,21 @@ using namespace DirectX; namespace Pbr { D3D12Primitive::D3D12Primitive(UINT indexCount, Conformance::D3D12BufferWithUpload indexBuffer, UINT vertexCount, - Conformance::D3D12BufferWithUpload vertexBuffer, std::shared_ptr material) + Conformance::D3D12BufferWithUpload vertexBuffer, std::shared_ptr material, + std::vector nodeIndices) : m_indexCount(indexCount) , m_indexBuffer(std::move(indexBuffer)) , m_vertexCount(vertexCount) , m_vertexBuffer(std::move(vertexBuffer)) , m_material(std::move(material)) + , m_nodeIndices(std::move(nodeIndices)) { } D3D12Primitive::D3D12Primitive(Pbr::D3D12Resources& pbrResources, const Pbr::PrimitiveBuilder& primitiveBuilder, const std::shared_ptr& material) - : D3D12Primitive((UINT)primitiveBuilder.Indices.size(), {}, (UINT)primitiveBuilder.Vertices.size(), {}, std::move(material)) + : D3D12Primitive((UINT)primitiveBuilder.Indices.size(), {}, (UINT)primitiveBuilder.Vertices.size(), {}, std::move(material), + primitiveBuilder.NodeIndicesVector()) { m_indexBuffer.Allocate(pbrResources.GetDevice().Get(), primitiveBuilder.Indices.size()); m_vertexBuffer.Allocate(pbrResources.GetDevice().Get(), primitiveBuilder.Vertices.size()); @@ -58,7 +61,7 @@ namespace Pbr D3D12Primitive D3D12Primitive::Clone(Pbr::D3D12Resources const& pbrResources) const { - return D3D12Primitive(m_indexCount, m_indexBuffer, m_vertexCount, m_vertexBuffer, m_material->Clone(pbrResources)); + return D3D12Primitive(m_indexCount, m_indexBuffer, m_vertexCount, m_vertexBuffer, m_material->Clone(pbrResources), m_nodeIndices); } void D3D12Primitive::UpdateBuffers(Pbr::D3D12Resources& pbrResources, const Pbr::PrimitiveBuilder& primitiveBuilder) diff --git a/src/conformance/framework/pbr/D3D12/D3D12Primitive.h b/src/conformance/framework/pbr/D3D12/D3D12Primitive.h index 26b6f383..a3c3be5e 100644 --- a/src/conformance/framework/pbr/D3D12/D3D12Primitive.h +++ b/src/conformance/framework/pbr/D3D12/D3D12Primitive.h @@ -25,7 +25,8 @@ namespace Pbr D3D12Primitive() = delete; D3D12Primitive(UINT indexCount, Conformance::D3D12BufferWithUpload indexBuffer, UINT vertexCount, - Conformance::D3D12BufferWithUpload vertexBuffer, std::shared_ptr material); + Conformance::D3D12BufferWithUpload vertexBuffer, std::shared_ptr material, + std::vector nodeIndices); D3D12Primitive(Pbr::D3D12Resources& pbrResources, const Pbr::PrimitiveBuilder& primitiveBuilder, const std::shared_ptr& material); @@ -43,6 +44,12 @@ namespace Pbr m_material = std::move(material); } + /// Get the nodes that the primitive represents + const std::vector& GetNodes() const + { + return m_nodeIndices; + } + protected: friend class D3D12ModelInstance; void Render(_In_ ID3D12GraphicsCommandList* directCommandList, D3D12Resources& pbrResources, DXGI_FORMAT colorRenderTargetFormat, @@ -59,5 +66,6 @@ namespace Pbr std::shared_ptr m_material; Microsoft::WRL::ComPtr m_srvHeap; Microsoft::WRL::ComPtr m_samplerHeap; + std::vector m_nodeIndices; }; } // namespace Pbr diff --git a/src/conformance/framework/pbr/GltfLoader.cpp b/src/conformance/framework/pbr/GltfLoader.cpp index 70049669..bf75fed9 100644 --- a/src/conformance/framework/pbr/GltfLoader.cpp +++ b/src/conformance/framework/pbr/GltfLoader.cpp @@ -87,6 +87,8 @@ namespace primitiveBuilder.Indices[startIndex + i + 1] = startVertex + primitive.Indices[i + 2]; primitiveBuilder.Indices[startIndex + i + 2] = startVertex + primitive.Indices[i + 1]; } + + primitiveBuilder.NodeIndices.insert(transformIndex); } } diff --git a/src/conformance/framework/pbr/OpenGL/GLModel.cpp b/src/conformance/framework/pbr/OpenGL/GLModel.cpp index 9e80598f..51a03066 100644 --- a/src/conformance/framework/pbr/OpenGL/GLModel.cpp +++ b/src/conformance/framework/pbr/OpenGL/GLModel.cpp @@ -48,6 +48,9 @@ namespace Pbr if (primitive.GetMaterial()->Hidden) continue; + if (!IsAnyNodeVisible(primitive.GetNodes())) + continue; + primitive.GetMaterial()->Bind(pbrResources); primitive.Render(pbrResources.GetFillMode()); } @@ -78,15 +81,15 @@ namespace Pbr void GLModelInstance::UpdateTransforms(Pbr::GLResources const& /* pbrResources */) { // If none of the node transforms have changed, no need to recompute/update the model transform structured buffer. - if (WereNodeLocalTransformsUpdated()) { - ResolveTransforms(false); + if (ResolvedTransformsNeedUpdate()) { + ResolveTransformsAndVisibilities(false); // Update node transform structured buffer. auto& resolvedTransforms = GetResolvedTransforms(); XRC_CHECK_THROW_GLCMD(glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_modelTransformsStructuredBuffer.get())); XRC_CHECK_THROW_GLCMD( glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(XrMatrix4x4f) * resolvedTransforms.size(), resolvedTransforms.data())); - ClearTransformsUpdatedFlag(); + MarkResolvedTransformsUpdated(); } } } // namespace Pbr diff --git a/src/conformance/framework/pbr/OpenGL/GLPrimitive.cpp b/src/conformance/framework/pbr/OpenGL/GLPrimitive.cpp index 813e9782..5c93a937 100644 --- a/src/conformance/framework/pbr/OpenGL/GLPrimitive.cpp +++ b/src/conformance/framework/pbr/OpenGL/GLPrimitive.cpp @@ -105,18 +105,19 @@ namespace namespace Pbr { GLPrimitive::GLPrimitive(GLsizei indexCount, ScopedGLBuffer indexBuffer, ScopedGLBuffer vertexBuffer, ScopedGLVertexArray vao, - std::shared_ptr material) + std::shared_ptr material, std::vector nodeIndices) : m_indexCount(indexCount) , m_indexBuffer(std::move(indexBuffer)) , m_vertexBuffer(std::move(vertexBuffer)) , m_vao(std::move(vao)) , m_material(std::move(material)) + , m_nodeIndices(std::move(nodeIndices)) { } GLPrimitive::GLPrimitive(const Pbr::PrimitiveBuilder& primitiveBuilder, const std::shared_ptr& material) : GLPrimitive((GLsizei)primitiveBuilder.Indices.size(), CreateIndexBuffer(primitiveBuilder), CreateVertexBuffer(primitiveBuilder), - ScopedGLVertexArray{}, std::move(material)) + ScopedGLVertexArray{}, std::move(material), primitiveBuilder.NodeIndicesVector()) { m_vao = CreateVAO(m_vertexBuffer, m_indexBuffer); } diff --git a/src/conformance/framework/pbr/OpenGL/GLPrimitive.h b/src/conformance/framework/pbr/OpenGL/GLPrimitive.h index 5d948470..bc5b2ac0 100644 --- a/src/conformance/framework/pbr/OpenGL/GLPrimitive.h +++ b/src/conformance/framework/pbr/OpenGL/GLPrimitive.h @@ -30,7 +30,7 @@ namespace Pbr GLPrimitive() = delete; GLPrimitive(GLsizei indexCount, ScopedGLBuffer indexBuffer, ScopedGLBuffer vertexBuffer, ScopedGLVertexArray vao, - std::shared_ptr material); + std::shared_ptr material, std::vector nodeIndices); GLPrimitive(const Pbr::PrimitiveBuilder& primitiveBuilder, const std::shared_ptr& material); void UpdateBuffers(const Pbr::PrimitiveBuilder& primitiveBuilder); @@ -47,6 +47,12 @@ namespace Pbr m_material = std::move(material); } + /// Get the nodes that the primitive represents + const std::vector& GetNodes() const + { + return m_nodeIndices; + } + protected: friend class GLModelInstance; void Render(FillMode fillMode) const; @@ -58,5 +64,6 @@ namespace Pbr ScopedGLBuffer m_vertexBuffer; ScopedGLVertexArray m_vao; std::shared_ptr m_material; + std::vector m_nodeIndices; }; } // namespace Pbr diff --git a/src/conformance/framework/pbr/PbrCommon.cpp b/src/conformance/framework/pbr/PbrCommon.cpp index 9cd626ef..1a5f0241 100644 --- a/src/conformance/framework/pbr/PbrCommon.cpp +++ b/src/conformance/framework/pbr/PbrCommon.cpp @@ -121,6 +121,8 @@ namespace Pbr } } + NodeIndices.insert(transformIndex); + return *this; } @@ -204,6 +206,8 @@ namespace Pbr } } + NodeIndices.insert(transformIndex); + return *this; } @@ -251,6 +255,12 @@ namespace Pbr vert.TexCoord0 = uvs[j]; Vertices.push_back(vert); } + NodeIndices.insert(transformIndex); return *this; } + + std::vector PrimitiveBuilder::NodeIndicesVector() const + { + return std::vector(NodeIndices.begin(), NodeIndices.end()); + } } // namespace Pbr diff --git a/src/conformance/framework/pbr/PbrCommon.h b/src/conformance/framework/pbr/PbrCommon.h index 11c0329a..1a12e816 100644 --- a/src/conformance/framework/pbr/PbrCommon.h +++ b/src/conformance/framework/pbr/PbrCommon.h @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -92,6 +93,7 @@ namespace Pbr { std::vector Vertices; std::vector Indices; + std::set NodeIndices; PrimitiveBuilder& AddSphere(float diameter, uint32_t tessellation, Pbr::NodeIndex_t transformIndex = Pbr::RootNodeIndex, RGBAColor vertexColor = RGBA::White); @@ -103,5 +105,7 @@ namespace Pbr RGBAColor vertexColor = RGBA::White); PrimitiveBuilder& AddQuad(XrVector2f sideLengths, XrVector2f textureCoord = {1, 1}, Pbr::NodeIndex_t transformIndex = Pbr::RootNodeIndex, RGBAColor vertexColor = RGBA::White); + + std::vector NodeIndicesVector() const; }; } // namespace Pbr diff --git a/src/conformance/framework/pbr/PbrModel.h b/src/conformance/framework/pbr/PbrModel.h index fe8bb027..30d22453 100644 --- a/src/conformance/framework/pbr/PbrModel.h +++ b/src/conformance/framework/pbr/PbrModel.h @@ -12,6 +12,8 @@ #include "common/xr_linear.h" +#include + #include #include #include @@ -20,6 +22,13 @@ namespace Pbr { + enum class NodeVisibility + { + Invisible, + Visible, + Inherit, + }; + // Node for creating a hierarchy of transforms. These transforms are referenced by vertices in the model's primitives. struct Node { @@ -136,6 +145,9 @@ namespace Pbr { const auto nodeCount = m_model->GetNodeCount(); + m_nodeLocalVisibilities.resize(nodeCount, NodeVisibility::Inherit); + m_resolvedVisibilities.resize(nodeCount, true); + m_nodeLocalTransforms.reserve(m_model->GetNodeCount()); for (const Node& node : m_model->GetNodes()) { m_nodeLocalTransforms.push_back(node.GetLocalTransform()); @@ -146,11 +158,19 @@ namespace Pbr } public: + /// Sets the visibility of a node. Nodes otherwise inherit + void SetNodeVisibility(NodeIndex_t nodeIndex, NodeVisibility visibility) + { + m_nodeLocalVisibilities[nodeIndex] = visibility; + // Visibility is implemented by scaling to 0 + m_resolvedTransformsNeedUpdate = true; + } + /// Overrides the local transform of a node void SetNodeTransform(NodeIndex_t nodeIndex, const XrMatrix4x4f& transform) { m_nodeLocalTransforms[nodeIndex] = transform; - m_nodeLocalTransformsUpdated = true; + m_resolvedTransformsNeedUpdate = true; } /// Combine a transform with the original transform from the asset @@ -164,15 +184,15 @@ namespace Pbr } protected: - bool WereNodeLocalTransformsUpdated() const noexcept + bool ResolvedTransformsNeedUpdate() const noexcept { - return m_nodeLocalTransformsUpdated; + return m_resolvedTransformsNeedUpdate; } - void ClearTransformsUpdatedFlag() noexcept + void MarkResolvedTransformsUpdated() noexcept { - m_nodeLocalTransformsUpdated = false; + m_resolvedTransformsNeedUpdate = false; } - void ResolveTransforms(bool transpose) + void ResolveTransformsAndVisibilities(bool transpose) { const auto& nodes = m_model->GetNodes(); @@ -182,11 +202,18 @@ namespace Pbr XrMatrix4x4f identityMatrix; XrMatrix4x4f_CreateIdentity(&identityMatrix); for (const auto& node : nodes) { - assert(node.GetParentNodeIndex() == Model::RootParentNodeIndex || node.GetParentNodeIndex() < node.GetNodeIndex()); - const XrMatrix4x4f& parentTransform = (node.GetParentNodeIndex() == Model::RootParentNodeIndex) - ? identityMatrix - : m_resolvedTransforms[node.GetParentNodeIndex()]; + bool parentIsRoot = node.GetParentNodeIndex() == Model::RootParentNodeIndex; + assert(parentIsRoot || node.GetParentNodeIndex() < node.GetNodeIndex()); + + bool parentVisibility = (parentIsRoot) ? true : m_resolvedVisibilities[node.GetParentNodeIndex()]; + NodeVisibility nodeVisibility = m_nodeLocalVisibilities[node.GetNodeIndex()]; + + m_resolvedVisibilities[node.GetNodeIndex()] = + nodeVisibility == NodeVisibility::Inherit ? parentVisibility : nodeVisibility == NodeVisibility::Visible; + + const XrMatrix4x4f& parentTransform = (parentIsRoot) ? identityMatrix : m_resolvedTransforms[node.GetParentNodeIndex()]; const XrMatrix4x4f& nodeTransform = m_nodeLocalTransforms[node.GetNodeIndex()]; + if (transpose) { XrMatrix4x4f nodeTransformTranspose; XrMatrix4x4f_Transpose(&nodeTransformTranspose, &nodeTransform); @@ -196,6 +223,14 @@ namespace Pbr XrMatrix4x4f_Multiply(&m_resolvedTransforms[node.GetNodeIndex()], &parentTransform, &nodeTransform); } } + + // After all node transforms and visibilities have been propagated, + // zero the transforms of invisible nodes. + for (const auto& node : nodes) { + if (!m_resolvedVisibilities[node.GetNodeIndex()]) { + XrMatrix4x4f_CreateScale(&m_resolvedTransforms[node.GetNodeIndex()], 0, 0, 0); + } + } } const Model& GetModel() const @@ -208,11 +243,23 @@ namespace Pbr return m_resolvedTransforms; } + bool IsAnyNodeVisible(nonstd::span nodeIndices) const + { + for (NodeIndex_t node : nodeIndices) { + if (m_resolvedVisibilities[node]) { + return true; + } + } + return false; + } + private: - bool m_nodeLocalTransformsUpdated{true}; + bool m_resolvedTransformsNeedUpdate{true}; // Derived classes may depend on this being immutable. std::shared_ptr m_model; + std::vector m_nodeLocalVisibilities; + std::vector m_resolvedVisibilities; // This is initialized to the local transform of every node, // but can be updated for this instance. std::vector m_nodeLocalTransforms; diff --git a/src/conformance/framework/pbr/Vulkan/VkModel.cpp b/src/conformance/framework/pbr/Vulkan/VkModel.cpp index e1e2a307..ccdb5e1a 100644 --- a/src/conformance/framework/pbr/Vulkan/VkModel.cpp +++ b/src/conformance/framework/pbr/Vulkan/VkModel.cpp @@ -46,6 +46,9 @@ namespace Pbr if (primitive.GetMaterial()->Hidden) continue; + if (!IsAnyNodeVisible(primitive.GetNodes())) + continue; + primitive.Render(directCommandBuffer, pbrResources, descriptorSet, renderPass, sampleCount, m_modelConstantBuffer.MakeDescriptor(), m_modelTransformsStructuredBuffer.MakeDescriptor()); } @@ -90,12 +93,12 @@ namespace Pbr void VulkanModelInstance::UpdateTransforms(Pbr::VulkanResources& /* pbrResources */) { // If none of the node transforms have changed, no need to recompute/update the model transform structured buffer. - if (WereNodeLocalTransformsUpdated()) { - ResolveTransforms(false); + if (ResolvedTransformsNeedUpdate()) { + ResolveTransformsAndVisibilities(false); // Update node transform structured buffer. m_modelTransformsStructuredBuffer.Update(GetResolvedTransforms()); - ClearTransformsUpdatedFlag(); + MarkResolvedTransformsUpdated(); } } } // namespace Pbr diff --git a/src/conformance/framework/pbr/Vulkan/VkPrimitive.cpp b/src/conformance/framework/pbr/Vulkan/VkPrimitive.cpp index 03d0f569..fa16771d 100644 --- a/src/conformance/framework/pbr/Vulkan/VkPrimitive.cpp +++ b/src/conformance/framework/pbr/Vulkan/VkPrimitive.cpp @@ -43,14 +43,15 @@ namespace namespace Pbr { VulkanPrimitive::VulkanPrimitive(Conformance::VertexBuffer&& vertexAndIndexBuffer, - std::shared_ptr material) - : m_vertexAndIndexBuffer(std::move(vertexAndIndexBuffer)), m_material(std::move(material)) + std::shared_ptr material, std::vector nodeIndices) + : m_vertexAndIndexBuffer(std::move(vertexAndIndexBuffer)), m_material(std::move(material)), m_nodeIndices(std::move(nodeIndices)) { } VulkanPrimitive::VulkanPrimitive(Pbr::VulkanResources const& pbrResources, const Pbr::PrimitiveBuilder& primitiveBuilder, const std::shared_ptr& material) - : VulkanPrimitive(CreateVertexBuffer(pbrResources.GetDevice(), pbrResources.GetMemoryAllocator(), primitiveBuilder), material) + : VulkanPrimitive(CreateVertexBuffer(pbrResources.GetDevice(), pbrResources.GetMemoryAllocator(), primitiveBuilder), + std::move(material), primitiveBuilder.NodeIndicesVector()) { } diff --git a/src/conformance/framework/pbr/Vulkan/VkPrimitive.h b/src/conformance/framework/pbr/Vulkan/VkPrimitive.h index 520f60c7..987b12bb 100644 --- a/src/conformance/framework/pbr/Vulkan/VkPrimitive.h +++ b/src/conformance/framework/pbr/Vulkan/VkPrimitive.h @@ -35,7 +35,8 @@ namespace Pbr using Collection = std::vector; VulkanPrimitive() = delete; - VulkanPrimitive(Conformance::VertexBuffer&& vertexAndIndexBuffer, std::shared_ptr material); + VulkanPrimitive(Conformance::VertexBuffer&& vertexAndIndexBuffer, std::shared_ptr material, + std::vector nodeIndices); VulkanPrimitive(Pbr::VulkanResources const& pbrResources, const Pbr::PrimitiveBuilder& primitiveBuilder, const std::shared_ptr& material); @@ -51,6 +52,12 @@ namespace Pbr m_material = std::move(material); } + /// Get the nodes that the primitive represents + const std::vector& GetNodes() const + { + return m_nodeIndices; + } + protected: friend class VulkanModelInstance; void Render(Conformance::CmdBuffer& directCommandBuffer, VulkanResources& pbrResources, VkDescriptorSet descriptorSet, @@ -63,5 +70,6 @@ namespace Pbr private: Conformance::VertexBuffer m_vertexAndIndexBuffer; std::shared_ptr m_material; + std::vector m_nodeIndices; }; } // namespace Pbr diff --git a/src/conformance/framework/pbr/Vulkan/VkResources.cpp b/src/conformance/framework/pbr/Vulkan/VkResources.cpp index 17a6e267..721a5803 100644 --- a/src/conformance/framework/pbr/Vulkan/VkResources.cpp +++ b/src/conformance/framework/pbr/Vulkan/VkResources.cpp @@ -373,7 +373,14 @@ namespace Pbr VulkanResources::VulkanResources(VulkanResources&& resources) noexcept = default; - VulkanResources::~VulkanResources() = default; + VulkanResources::~VulkanResources() + { + // stagingBuffers are queued to be cleared in Wait(). If Wait() has not been called, clear them here. + for (auto stagingBuffer : m_impl->Resources.StagingBuffers) { + stagingBuffer.Reset(GetDevice()); + } + m_impl->Resources.StagingBuffers.clear(); + } /* IResources implementations */ std::shared_ptr VulkanResources::CreateFlatMaterial(RGBAColor baseColorFactor, float roughnessFactor, float metallicFactor,