diff --git a/.gitattributes b/.gitattributes index fa2e3ac3..006bcaff 100644 --- a/.gitattributes +++ b/.gitattributes @@ -25,8 +25,9 @@ *.png binary # git-lfs big files -*.pdf filter=lfs diff=lfs merge=lfs -text -*.glb filter=lfs diff=lfs merge=lfs -text +*.pdf filter=lfs diff=lfs merge=lfs -text +*.glb filter=lfs diff=lfs merge=lfs -text +src/conformance/**/*.png filter=lfs diff=lfs merge=lfs -text # Shell/python scripts that don't end in .sh specification/makeAllExts eol=lf diff --git a/.gitignore b/.gitignore index 2e8bce12..64c5b37d 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ generated-includes cmake_install.cmake cmake_uninstall.cmake cmake-build-* +specification/vendor/bundle/ # Marker file for a snapshot build SNAPSHOT diff --git a/changes/conformance/mr.2882.gl.md b/changes/conformance/mr.2882.gl.md new file mode 100644 index 00000000..cf9b73bc --- /dev/null +++ b/changes/conformance/mr.2882.gl.md @@ -0,0 +1 @@ +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 new file mode 100644 index 00000000..561e6194 --- /dev/null +++ b/changes/conformance/mr.3247.gl.md @@ -0,0 +1 @@ +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 new file mode 100644 index 00000000..de2028b6 --- /dev/null +++ b/changes/conformance/mr.3329.gl.md @@ -0,0 +1 @@ +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 new file mode 100644 index 00000000..46c4f98b --- /dev/null +++ b/changes/conformance/mr.3345.gl.md @@ -0,0 +1 @@ +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 new file mode 100644 index 00000000..e6faac7d --- /dev/null +++ b/changes/conformance/mr.3350.gl.md @@ -0,0 +1 @@ +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 new file mode 100644 index 00000000..623f4374 --- /dev/null +++ b/changes/conformance/mr.3355.gl.md @@ -0,0 +1 @@ +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 new file mode 100644 index 00000000..04ccf5d1 --- /dev/null +++ b/changes/conformance/mr.3356.gl.md @@ -0,0 +1 @@ +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 new file mode 100644 index 00000000..932734ab --- /dev/null +++ b/changes/conformance/mr.3357.gl.1.md @@ -0,0 +1,4 @@ +--- +- 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 new file mode 100644 index 00000000..ab483f38 --- /dev/null +++ b/changes/conformance/mr.3357.gl.md @@ -0,0 +1 @@ +Fix: Dangling pointer in action test. diff --git a/changes/conformance/mr.3358.gl.md b/changes/conformance/mr.3358.gl.md new file mode 100644 index 00000000..8c4dddf7 --- /dev/null +++ b/changes/conformance/mr.3358.gl.md @@ -0,0 +1 @@ +Improvement: Improve readability of test sources. diff --git a/maintainer-scripts/common.sh b/maintainer-scripts/common.sh index c406ad29..2f2a036c 100644 --- a/maintainer-scripts/common.sh +++ b/maintainer-scripts/common.sh @@ -154,6 +154,7 @@ getSDKSourceFilenames() { checkCodespell \ CMakeLists.txt \ format_file.sh \ + open-in-docker.sh \ LICENSE \ openxr-codespell.exclude \ runClangFormat.sh \ diff --git a/specification/Makefile b/specification/Makefile index 226be4b7..f9608ca7 100644 --- a/specification/Makefile +++ b/specification/Makefile @@ -7,7 +7,13 @@ SHELL = /usr/bin/env bash QUIET ?= @ VERYQUIET ?= @ PYTHON ?= python3 +ifneq (,$(strip $(BUNDLER))) +ASCIIDOC ?= bundle exec asciidoctor --trace +HEXAPDF ?= bundle exec hexapdf +else ASCIIDOC ?= asciidoctor +HEXAPDF ?= hexapdf +endif RM = rm -f RMRF = rm -rf MKDIR = mkdir -p @@ -33,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.36 +SPECREVISION = 1.1.37 REVISION_COMPONENTS = $(subst ., ,$(SPECREVISION)) MAJORMINORVER = $(word 1,$(REVISION_COMPONENTS)).$(word 2,$(REVISION_COMPONENTS)) @@ -343,7 +349,7 @@ pdfA4: $(PDFA4SPEC) ASCIIDOCTOR_TARGETS += $(PDFSPEC) $(PDFA4SPEC) # Target-specific variables and deps customizing the AsciiDoctor rule -$(PDFSPEC) $(PDFA4SPEC): BACKEND_ARGS=--backend pdf --require asciidoctor-pdf -a compress -r ./scripts/pdf-index-customizer.rb +$(PDFSPEC) $(PDFA4SPEC): BACKEND_ARGS=--backend pdf --require asciidoctor-pdf -a compress --require ./scripts/pdf-index-customizer.rb $(PDFSPEC): PAGESIZE=LETTER $(PDFA4SPEC): PAGESIZE=A4 $(PDFSPEC) $(PDFA4SPEC): $(COMMONDOCS) @@ -647,14 +653,17 @@ $(REGISTRYOUTDIR)/headers/openxr: | $(REGISTRYOUTDIR)/headers $(QUIET)$(MKDIR) "$@" release-htmlpdf: html pdf $(REGISTRYOUTDIR)/pdf $(REGISTRYOUTDIR)/html - -asciidoctor-pdf-optimize $(PDFSPEC) - $(QUIET)$(CP) $(PDFSPEC) $(REGISTRYOUTDIR)/pdf/$(SPEC_FILENAME_STEM).pdf + $(ECHO) "[hexapdf] $(call MAKE_RELATIVE,$(REGISTRYOUTDIR)/pdf/$(SPEC_FILENAME_STEM).pdf)" + $(QUIET)$(HEXAPDF) optimize --force $(PDFSPEC) $(REGISTRYOUTDIR)/pdf/$(SPEC_FILENAME_STEM).pdf + $(ECHO) "[cp] $(call MAKE_RELATIVE,$(REGISTRYOUTDIR)/html/$(SPEC_FILENAME_STEM).html)" $(QUIET)$(CP) $(HTMLSPEC) $(REGISTRYOUTDIR)/html/$(SPEC_FILENAME_STEM).html .PHONY: release-htmlpdf release: release-htmlpdf manhtmlpages loader styleguide extprocess | $(REGISTRYOUTDIR) $(REGISTRYOUTDIR)/man + $(ECHO) "[cp] $(call MAKE_RELATIVE,$(REGISTRYOUTDIR))/{styleguide,extprocess,loader}.html" $(QUIET)$(CP) $(OUTDIR)/styleguide.html $(OUTDIR)/extprocess.html $(OUTDIR)/loader.html $(REGISTRYOUTDIR) + $(ECHO) "[cp] $(REGISTRYOUTDIR)/man/html" $(QUIET)$(CP) -R $(MANHTMLDIR) $(REGISTRYOUTDIR)/man/html .PHONY: release diff --git a/specification/README.md b/specification/README.md index 8cd8479c..dac636c8 100644 --- a/specification/README.md +++ b/specification/README.md @@ -8,10 +8,13 @@ SPDX-License-Identifier: CC-BY-4.0 Before building the specification, install the necessary prerequisite tools as described later in this document. -You may instead choose to use the `open-in-docker.sh` script, -which will mount the repository in a container built from an image with all the necessary tools installed. -See that script for more details. -You can find the associated Dockerfile at https://github.com/KhronosGroup/DockerContainers/blob/master/Dockerfile.openxr +You may instead choose to use the `open-in-docker.sh` script, available in the +OpenXR-Docs (spec source) and OpenXR-SDK-Source (SDK, for loader docs build) +repo as well as the internal monorepo. This script which will mount the +repository in a container built from an image with all the necessary tools +installed: these are regularly pushed to Docker Hub. See that script for more +details. You can find the associated Dockerfile at + ## Conditional Inclusion of Extensions @@ -91,6 +94,10 @@ specified by the Makefile variable `$(OUTDIR)` (by default, It is recommended to build these targets using a "helper" script from above, unless you want to only build the core spec without any extensions. +Most of these are not supported if building in `OpenXR-SDK-Source`: this +repository is mostly software, and the only contained AsciiDoc content is the +loader design document source. + These targets are currently supported. * API spec: @@ -119,6 +126,10 @@ For example: make styleguide ``` +Many of these are not supported if building in `OpenXR-SDK-Source`: this +repository is mostly software, and the only contained AsciiDoc content is the +loader design document source. + * "OpenXR Documentation and Extensions" guide (aka Style Guide): * `styleguide` - Single-file HTML5 in `$(OUTDIR)/styleguide.html` * OpenXR Extensions Process guide: @@ -219,7 +230,8 @@ parts you don't use) completely before trying to install. > Asciidoctor-pdf versions before `1.5.0.alpha15` have issues with multi-page valid usage blocks, in that the background only renders for the first page. `alpha.15` fixes this issue (as well as a few others); do not use prior -versions. +versions. On the other hand, versions later than 1.6.2 break our index +customization script, so 1.6.2 is ideal. Only the `asciidoctor` and `rouge` gems (and their dependencies) are needed if you do not intend to build PDF versions of the spec and supporting documents. @@ -230,6 +242,14 @@ people submitting MRs with substantial changes to the Specification are responsible for verifying that their branches build *both* `html` and `pdf` targets. +The easiest way to get the right version of these gems is to use "bundler": + +```sh +bundle install +``` + +Then, pass `BUNDLER=1` to each `make` (or wrapper script) invocation. + ### Platforms and System Packages #### Windows diff --git a/specification/registry/xr.xml b/specification/registry/xr.xml index c552f0b5..bc61f4b8 100644 --- a/specification/registry/xr.xml +++ b/specification/registry/xr.xml @@ -58,6 +58,7 @@ maintained in the default branch of the Khronos OpenXR GitHub project. + @@ -133,7 +134,16 @@ 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, 36) +#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 1, 37) + + + // OpenXR 1.0 version number +#define XR_API_VERSION_1_0 XR_MAKE_VERSION(1, 0, XR_VERSION_PATCH(XR_CURRENT_API_VERSION)) + + // OpenXR 1.1 version number +#define XR_API_VERSION_1_1 XR_MAKE_VERSION(1, 1, XR_VERSION_PATCH(XR_CURRENT_API_VERSION)) @@ -8627,7 +8642,7 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( - + @@ -10612,6 +10627,12 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( + + + + + + @@ -15214,6 +15235,55 @@ typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/specification/scripts/extensionmetadocgenerator.py b/specification/scripts/extensionmetadocgenerator.py index fa034ed7..64006560 100644 --- a/specification/scripts/extensionmetadocgenerator.py +++ b/specification/scripts/extensionmetadocgenerator.py @@ -154,6 +154,7 @@ def specLink(self, xrefName, xrefText, isRefpage = False): def conditionalLinkCoreAPI(self, apiVersion, linkSuffix, isRefpage): versionMatch = re.match(f"{self.conventions.api_version_prefix}(\\d+)_(\\d+)", apiVersion) + assert versionMatch major = versionMatch.group(1) minor = versionMatch.group(2) @@ -295,9 +296,7 @@ def makeMetafile(self, extensions, SPV_deps, isRefpage = False): separator = '' else: separator = '+' - write(separator + '\n--\n' + - dependencyMarkup(self.depends) + - '--', file=fp) + write(f"{separator}\n--\n{dependencyMarkup(self.depends)}--", file=fp) else: # Do not specify the base API redundantly, but put something # here to avoid formatting trouble. @@ -328,10 +327,7 @@ def versionKey(name): names = sorted(sorted(interacts), key=versionKey) for name in names: - if "_VERSION_" in name: - write(f"* Interacts with {self.conventions.formatVersion(name)}", file=fp) - else: - write(f"* Interacts with {self.conventions.formatExtension(name)}", file=fp) + write(f"* Interacts with {self.conventions.formatVersionOrExtension(name)}", file=fp) if self.name in SPV_deps: self.writeTag('SPIR-V Dependencies', None, isRefpage, fp) diff --git a/specification/scripts/parse_dependency.py b/specification/scripts/parse_dependency.py index 08f04875..b4b05550 100755 --- a/specification/scripts/parse_dependency.py +++ b/specification/scripts/parse_dependency.py @@ -126,7 +126,7 @@ def push_first(toks): exprStack.append(toks[0]) # An identifier (version or extension name) -dependencyIdent = Word(alphanums + '_') +dependencyIdent = Word(f"{alphanums}_") # Infix expression for depends expressions dependencyExpr = pp.infixNotation(dependencyIdent, @@ -303,7 +303,7 @@ def markupTraverse(expr, level = 0, root = True): - root - True only on initial call""" if level > 0: - prefix = '{nbsp}{nbsp}' * level * 2 + ' ' + prefix = f"{'{nbsp}{nbsp}' * level * 2} " else: prefix = '' str = '' @@ -318,9 +318,9 @@ def markupTraverse(expr, level = 0, root = True): str = str + markupTraverse(elem, level = nextlevel, root = False) elif elem in ('+', ','): - str = str + f'{prefix}{opMarkupAsciidoc(elem)} +\n' + str = f"{str}{prefix}{opMarkupAsciidoc(elem)} +\n" else: - str = str + f'{prefix}{leafMarkupAsciidoc(elem)} +\n' + str = f"{str}{prefix}{leafMarkupAsciidoc(elem)} +\n" return str diff --git a/specification/scripts/reg.py b/specification/scripts/reg.py index bb3ec774..801b2f5d 100755 --- a/specification/scripts/reg.py +++ b/specification/scripts/reg.py @@ -771,7 +771,7 @@ def parseTree(self): stage_flag = enum.get('alias') featureName = elem.get('depends') if elem.get('depends') is not None else featureInfo.name if stage_flag in sync_pipeline_stage_condition: - sync_pipeline_stage_condition[stage_flag] += "," + featureName + sync_pipeline_stage_condition[stage_flag] += f",{featureName}" else: sync_pipeline_stage_condition[stage_flag] = featureName elif groupName == "VkAccessFlagBits2": @@ -780,7 +780,7 @@ def parseTree(self): access_flag = enum.get('alias') featureName = elem.get('depends') if elem.get('depends') is not None else featureInfo.name if access_flag in sync_access_condition: - sync_access_condition[access_flag] += "," + featureName + sync_access_condition[access_flag] += f",{featureName}" else: sync_access_condition[access_flag] = featureName diff --git a/specification/scripts/update_version.py b/specification/scripts/update_version.py index f2340538..42373745 100755 --- a/specification/scripts/update_version.py +++ b/specification/scripts/update_version.py @@ -31,13 +31,10 @@ print('Replacing version lines in the registry') for line in fileinput.input('registry/xr.xml', inplace=True): printed = False - if 'XR_CURRENT_API_VERSION' in line: + if 'XR_CURRENT_API_VERSION' in line: if 'XR_MAKE_VERSION' in line: printed = True print('#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(%s, %s, %s)' % spec_version) - if 'type name' in line: - printed = True - print(' ') if not printed: print(f"{line}", end='') diff --git a/specification/scripts/xml_consistency.py b/specification/scripts/xml_consistency.py index e1915c99..3cf7b4a7 100755 --- a/specification/scripts/xml_consistency.py +++ b/specification/scripts/xml_consistency.py @@ -242,7 +242,7 @@ def check_enum_naming(self, enum_type): stripped_enum_type = stripped_enum_type.replace("FlagBits", "") # This is how we apply the "convert type to enum value name" transform: pretend it's a structure type, # then replace "XR_TYPE_" with the generic prefix "XR_" - start = self.conventions.generate_structure_type_from_name(stripped_enum_type).replace("XR_TYPE", "XR") + "_" + start = f"{self.conventions.generate_structure_type_from_name(stripped_enum_type).replace('XR_TYPE', 'XR')}_" value_names = get_enum_value_names(self.db.registry, enum_type) diff --git a/src/common/platform_utils.hpp b/src/common/platform_utils.hpp index 42570cd1..d047c17d 100644 --- a/src/common/platform_utils.hpp +++ b/src/common/platform_utils.hpp @@ -325,6 +325,8 @@ static inline std::string PlatformUtilsGetSecureEnv(const char* name) { #elif defined(XR_OS_ANDROID) +#include + static inline bool PlatformUtilsGetEnvSet(const char* /* name */) { // Stub func return false; @@ -355,6 +357,37 @@ static inline bool PlatformGetGlobalRuntimeFileName(uint16_t major_version, std: return false; } + +// Android system properties are sufficiently different from environment variables that we are not re-using +// PlatformUtilsGetEnv for this purpose +static inline std::string PlatformUtilsGetAndroidSystemProperty(const char* name) { + std::string result; + const prop_info* pi = __system_property_find(name); + if (pi == nullptr) { + return {}; + } + +#if __ANDROID_API__ >= 26 + // use callback to retrieve > 92 character sys prop values, if available + __system_property_read_callback( + pi, + [](void* cookie, const char*, const char* value, uint32_t) { + auto property_value = reinterpret_cast(cookie); + *property_value = value; + }, + reinterpret_cast(&result)); +#endif // __ANDROID_API__ >= 26 + // fallback to __system_property_get if no value retrieved via callback + if (result.empty()) { + char value[PROP_VALUE_MAX] = {}; + if (__system_property_get(name, value) != 0) { + result = value; + } + } + + return result; +} + #else // Not Linux, Apple, nor Windows static inline bool PlatformUtilsGetEnvSet(const char* /* name */) { diff --git a/src/conformance/build.gradle b/src/conformance/build.gradle index f7b17424..6897d202 100644 --- a/src/conformance/build.gradle +++ b/src/conformance/build.gradle @@ -22,9 +22,15 @@ task copyAssets(type: Copy) { include '*.otf' } + // immersive images + from('conformance_test/composition_assets') { + include '*.png' + } + // sample images from('conformance_test/composition_examples') { include '*.png' + include '*.jpg' } from('conformance_test/gltf_examples') { include '*.png' diff --git a/src/conformance/conformance_test/CMakeLists.txt b/src/conformance/conformance_test/CMakeLists.txt index 8a8cbabf..b8c257e9 100644 --- a/src/conformance/conformance_test/CMakeLists.txt +++ b/src/conformance/conformance_test/CMakeLists.txt @@ -30,6 +30,8 @@ file( file( GLOB ASSETS + "composition_assets/*.png" + "composition_examples/*.jpg" "composition_examples/*.png" "SourceCodePro-Regular.otf" "gltf_examples/*.glb" diff --git a/src/conformance/conformance_test/composition_assets/equirect_8k.png b/src/conformance/conformance_test/composition_assets/equirect_8k.png new file mode 100644 index 00000000..89fbaa7b --- /dev/null +++ b/src/conformance/conformance_test/composition_assets/equirect_8k.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:879d5f6d2a6d41a775f6e9fee34a43575ada147f272987abdac8c5f54873054e +size 1876865 diff --git a/src/conformance/conformance_test/composition_assets/equirect_8k.png.license b/src/conformance/conformance_test/composition_assets/equirect_8k.png.license new file mode 100644 index 00000000..cca73d04 --- /dev/null +++ b/src/conformance/conformance_test/composition_assets/equirect_8k.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2019-2024, The Khronos Group Inc. + +SPDX-License-Identifier: Apache-2.0 diff --git a/src/conformance/conformance_test/composition_assets/equirect_central_90.png b/src/conformance/conformance_test/composition_assets/equirect_central_90.png new file mode 100644 index 00000000..b21599cd --- /dev/null +++ b/src/conformance/conformance_test/composition_assets/equirect_central_90.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:505d2c7e0b96b7f9491b27f37b852dc7002248f021b264c1c2def04e01229c60 +size 343176 diff --git a/src/conformance/conformance_test/composition_assets/equirect_central_90.png.license b/src/conformance/conformance_test/composition_assets/equirect_central_90.png.license new file mode 100644 index 00000000..cca73d04 --- /dev/null +++ b/src/conformance/conformance_test/composition_assets/equirect_central_90.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2019-2024, The Khronos Group Inc. + +SPDX-License-Identifier: Apache-2.0 diff --git a/src/conformance/conformance_test/composition_assets/equirect_central_90_from_equirect_8k.pto b/src/conformance/conformance_test/composition_assets/equirect_central_90_from_equirect_8k.pto new file mode 100644 index 00000000..829df265 --- /dev/null +++ b/src/conformance/conformance_test/composition_assets/equirect_central_90_from_equirect_8k.pto @@ -0,0 +1,54 @@ +# hugin project file +#hugin_ptoversion 2 +p f2 w2048 h2048 v90 k0 E0 R0 n"TIFF_m c:LZW r:CROP" +m i0 + +# image lines +#-hugin cropFactor=1 +i w8192 h4096 f4 v360 Ra0 Rb0 Rc0 Rd0 Re0 Eev0 Er1 Eb1 r0 p0 y0 TrX0 TrY0 TrZ0 Tpy0 Tpp0 j0 a0 b0 c0 d0 e0 g0 t0 Va1 Vb0 Vc0 Vd0 Vx0 Vy0 Vm5 n"equirect_8k.png" + + +# specify variables that should be optimized +v Ra0 +v Rb0 +v Rc0 +v Rd0 +v Re0 +v Vb0 +v Vc0 +v Vd0 +v + + +# control points + +#hugin_optimizeReferenceImage 0 +#hugin_blender enblend +#hugin_remapper nona +#hugin_enblendOptions +#hugin_enfuseOptions +#hugin_hdrmergeOptions -m avg -c +#hugin_verdandiOptions +#hugin_edgeFillMode 0 +#hugin_edgeFillKeepInput false +#hugin_outputLDRBlended true +#hugin_outputLDRLayers false +#hugin_outputLDRExposureRemapped false +#hugin_outputLDRExposureLayers false +#hugin_outputLDRExposureBlended false +#hugin_outputLDRStacks false +#hugin_outputLDRExposureLayersFused false +#hugin_outputHDRBlended false +#hugin_outputHDRLayers false +#hugin_outputHDRStacks false +#hugin_outputLayersCompression LZW +#hugin_outputImageType png +#hugin_outputImageTypeCompression LZW +#hugin_outputJPEGQuality 90 +#hugin_outputImageTypeHDR exr +#hugin_outputImageTypeHDRCompression LZW +#hugin_outputStacksMinOverlap 0.7 +#hugin_outputLayersExposureDiff 0.5 +#hugin_outputRangeCompression 0 +#hugin_optimizerMasterSwitch 1 +#hugin_optimizerPhotoMasterSwitch 21 diff --git a/src/conformance/conformance_test/composition_assets/equirect_central_90_from_equirect_8k.pto.license b/src/conformance/conformance_test/composition_assets/equirect_central_90_from_equirect_8k.pto.license new file mode 100644 index 00000000..cca73d04 --- /dev/null +++ b/src/conformance/conformance_test/composition_assets/equirect_central_90_from_equirect_8k.pto.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2019-2024, The Khronos Group Inc. + +SPDX-License-Identifier: Apache-2.0 diff --git a/src/conformance/conformance_test/composition_assets/test_cube.blend b/src/conformance/conformance_test/composition_assets/test_cube.blend new file mode 100644 index 00000000..bc6d966b Binary files /dev/null and b/src/conformance/conformance_test/composition_assets/test_cube.blend differ diff --git a/src/conformance/conformance_test/composition_assets/test_cube.blend.license b/src/conformance/conformance_test/composition_assets/test_cube.blend.license new file mode 100644 index 00000000..cca73d04 --- /dev/null +++ b/src/conformance/conformance_test/composition_assets/test_cube.blend.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2019-2024, The Khronos Group Inc. + +SPDX-License-Identifier: Apache-2.0 diff --git a/src/conformance/conformance_test/composition_examples/equirect_central_90.jpg b/src/conformance/conformance_test/composition_examples/equirect_central_90.jpg new file mode 100644 index 00000000..fae1142e Binary files /dev/null and b/src/conformance/conformance_test/composition_examples/equirect_central_90.jpg differ diff --git a/src/conformance/conformance_test/composition_examples/equirect_central_90.jpg.license b/src/conformance/conformance_test/composition_examples/equirect_central_90.jpg.license new file mode 100644 index 00000000..cca73d04 --- /dev/null +++ b/src/conformance/conformance_test/composition_examples/equirect_central_90.jpg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2019-2024, The Khronos Group Inc. + +SPDX-License-Identifier: Apache-2.0 diff --git a/src/conformance/conformance_test/composition_examples/equirect_finite.jpg b/src/conformance/conformance_test/composition_examples/equirect_finite.jpg new file mode 100644 index 00000000..65a52d87 Binary files /dev/null and b/src/conformance/conformance_test/composition_examples/equirect_finite.jpg differ diff --git a/src/conformance/conformance_test/composition_examples/equirect_finite.jpg.license b/src/conformance/conformance_test/composition_examples/equirect_finite.jpg.license new file mode 100644 index 00000000..cca73d04 --- /dev/null +++ b/src/conformance/conformance_test/composition_examples/equirect_finite.jpg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2019-2024, The Khronos Group Inc. + +SPDX-License-Identifier: Apache-2.0 diff --git a/src/conformance/conformance_test/composition_examples/equirect_finite_pose.jpg b/src/conformance/conformance_test/composition_examples/equirect_finite_pose.jpg new file mode 100644 index 00000000..d3974921 Binary files /dev/null and b/src/conformance/conformance_test/composition_examples/equirect_finite_pose.jpg differ diff --git a/src/conformance/conformance_test/composition_examples/equirect_finite_pose.jpg.license b/src/conformance/conformance_test/composition_examples/equirect_finite_pose.jpg.license new file mode 100644 index 00000000..cca73d04 --- /dev/null +++ b/src/conformance/conformance_test/composition_examples/equirect_finite_pose.jpg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2019-2024, The Khronos Group Inc. + +SPDX-License-Identifier: Apache-2.0 diff --git a/src/conformance/conformance_test/composition_examples/equirect_local_space.jpg b/src/conformance/conformance_test/composition_examples/equirect_local_space.jpg new file mode 100644 index 00000000..d684bbde Binary files /dev/null and b/src/conformance/conformance_test/composition_examples/equirect_local_space.jpg differ diff --git a/src/conformance/conformance_test/composition_examples/equirect_local_space.jpg.license b/src/conformance/conformance_test/composition_examples/equirect_local_space.jpg.license new file mode 100644 index 00000000..cca73d04 --- /dev/null +++ b/src/conformance/conformance_test/composition_examples/equirect_local_space.jpg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2019-2024, The Khronos Group Inc. + +SPDX-License-Identifier: Apache-2.0 diff --git a/src/conformance/conformance_test/composition_examples/equirect_view_space.jpg b/src/conformance/conformance_test/composition_examples/equirect_view_space.jpg new file mode 100644 index 00000000..881ecfe3 Binary files /dev/null and b/src/conformance/conformance_test/composition_examples/equirect_view_space.jpg differ diff --git a/src/conformance/conformance_test/composition_examples/equirect_view_space.jpg.license b/src/conformance/conformance_test/composition_examples/equirect_view_space.jpg.license new file mode 100644 index 00000000..cca73d04 --- /dev/null +++ b/src/conformance/conformance_test/composition_examples/equirect_view_space.jpg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2019-2024, The Khronos Group Inc. + +SPDX-License-Identifier: Apache-2.0 diff --git a/src/conformance/conformance_test/composition_examples/ext_plane_detection_contour.png b/src/conformance/conformance_test/composition_examples/ext_plane_detection_contour.png index 6147309d..ac77c0e9 100644 Binary files a/src/conformance/conformance_test/composition_examples/ext_plane_detection_contour.png and b/src/conformance/conformance_test/composition_examples/ext_plane_detection_contour.png differ diff --git a/src/conformance/conformance_test/composition_examples/eye_visibility.png b/src/conformance/conformance_test/composition_examples/eye_visibility.png index b2925372..61c3916c 100644 Binary files a/src/conformance/conformance_test/composition_examples/eye_visibility.png and b/src/conformance/conformance_test/composition_examples/eye_visibility.png differ diff --git a/src/conformance/conformance_test/composition_examples/grip_and_aim_pose.png b/src/conformance/conformance_test/composition_examples/grip_and_aim_pose.png index 77f21451..6e6fea12 100644 Binary files a/src/conformance/conformance_test/composition_examples/grip_and_aim_pose.png and b/src/conformance/conformance_test/composition_examples/grip_and_aim_pose.png differ diff --git a/src/conformance/conformance_test/composition_examples/grip_axes_diagram.png b/src/conformance/conformance_test/composition_examples/grip_axes_diagram.png index 4f601866..b08b409b 100644 Binary files a/src/conformance/conformance_test/composition_examples/grip_axes_diagram.png and b/src/conformance/conformance_test/composition_examples/grip_axes_diagram.png differ diff --git a/src/conformance/conformance_test/composition_examples/local_floor.png b/src/conformance/conformance_test/composition_examples/local_floor.png index d86b5f0a..1d00ef2c 100644 Binary files a/src/conformance/conformance_test/composition_examples/local_floor.png and b/src/conformance/conformance_test/composition_examples/local_floor.png differ diff --git a/src/conformance/conformance_test/composition_examples/palm_pose.png b/src/conformance/conformance_test/composition_examples/palm_pose.png index d9203ff8..339df1d4 100644 Binary files a/src/conformance/conformance_test/composition_examples/palm_pose.png and b/src/conformance/conformance_test/composition_examples/palm_pose.png differ diff --git a/src/conformance/conformance_test/composition_examples/projection_array.png b/src/conformance/conformance_test/composition_examples/projection_array.png index e42043bf..8cfb9b4e 100644 Binary files a/src/conformance/conformance_test/composition_examples/projection_array.png and b/src/conformance/conformance_test/composition_examples/projection_array.png differ diff --git a/src/conformance/conformance_test/composition_examples/projection_depth.png b/src/conformance/conformance_test/composition_examples/projection_depth.png index fd39f0a3..32d94b29 100644 Binary files a/src/conformance/conformance_test/composition_examples/projection_depth.png and b/src/conformance/conformance_test/composition_examples/projection_depth.png differ diff --git a/src/conformance/conformance_test/composition_examples/projection_mutable.png b/src/conformance/conformance_test/composition_examples/projection_mutable.png index 05bdab3d..31a00411 100644 Binary files a/src/conformance/conformance_test/composition_examples/projection_mutable.png and b/src/conformance/conformance_test/composition_examples/projection_mutable.png differ diff --git a/src/conformance/conformance_test/composition_examples/projection_separate.png b/src/conformance/conformance_test/composition_examples/projection_separate.png index e42043bf..8cfb9b4e 100644 Binary files a/src/conformance/conformance_test/composition_examples/projection_separate.png and b/src/conformance/conformance_test/composition_examples/projection_separate.png differ diff --git a/src/conformance/conformance_test/composition_examples/projection_wide.png b/src/conformance/conformance_test/composition_examples/projection_wide.png index e42043bf..8cfb9b4e 100644 Binary files a/src/conformance/conformance_test/composition_examples/projection_wide.png and b/src/conformance/conformance_test/composition_examples/projection_wide.png differ diff --git a/src/conformance/conformance_test/composition_examples/quad_hands.png b/src/conformance/conformance_test/composition_examples/quad_hands.png index 5c2bd324..d8b234cd 100644 Binary files a/src/conformance/conformance_test/composition_examples/quad_hands.png and b/src/conformance/conformance_test/composition_examples/quad_hands.png differ diff --git a/src/conformance/conformance_test/composition_examples/quad_occlusion.png b/src/conformance/conformance_test/composition_examples/quad_occlusion.png index 00f1467c..c2b282e1 100644 Binary files a/src/conformance/conformance_test/composition_examples/quad_occlusion.png and b/src/conformance/conformance_test/composition_examples/quad_occlusion.png differ diff --git a/src/conformance/conformance_test/composition_examples/quad_poses.png b/src/conformance/conformance_test/composition_examples/quad_poses.png index ba02bc42..ce1b6b62 100644 Binary files a/src/conformance/conformance_test/composition_examples/quad_poses.png and b/src/conformance/conformance_test/composition_examples/quad_poses.png differ diff --git a/src/conformance/conformance_test/composition_examples/source_alpha_blending.png b/src/conformance/conformance_test/composition_examples/source_alpha_blending.png index d1c576aa..fd1cadb2 100644 Binary files a/src/conformance/conformance_test/composition_examples/source_alpha_blending.png and b/src/conformance/conformance_test/composition_examples/source_alpha_blending.png differ diff --git a/src/conformance/conformance_test/composition_examples/stale_swapchain.png b/src/conformance/conformance_test/composition_examples/stale_swapchain.png index 91afdfb8..4207f0b4 100644 Binary files a/src/conformance/conformance_test/composition_examples/stale_swapchain.png and b/src/conformance/conformance_test/composition_examples/stale_swapchain.png differ diff --git a/src/conformance/conformance_test/composition_examples/subimage.png b/src/conformance/conformance_test/composition_examples/subimage.png index 8b246003..79833f2b 100644 Binary files a/src/conformance/conformance_test/composition_examples/subimage.png and b/src/conformance/conformance_test/composition_examples/subimage.png differ diff --git a/src/conformance/conformance_test/composition_examples/visibility_mask_with_red.png b/src/conformance/conformance_test/composition_examples/visibility_mask_with_red.png index 4b976588..4af3bc41 100644 Binary files a/src/conformance/conformance_test/composition_examples/visibility_mask_with_red.png and b/src/conformance/conformance_test/composition_examples/visibility_mask_with_red.png differ diff --git a/src/conformance/conformance_test/conformance_test.cpp b/src/conformance/conformance_test/conformance_test.cpp index 180f23d8..0a26537d 100644 --- a/src/conformance/conformance_test/conformance_test.cpp +++ b/src/conformance/conformance_test/conformance_test.cpp @@ -267,9 +267,9 @@ namespace GlobalData& globalData = GetGlobalData(); globalData.options.desiredApiVersion = arg; if (striequal(globalData.options.desiredApiVersion.c_str(), "1.0")) - globalData.options.desiredApiVersionValue = XR_MAKE_VERSION(1, 0, XR_VERSION_PATCH(XR_CURRENT_API_VERSION)); + globalData.options.desiredApiVersionValue = XR_API_VERSION_1_0; else if (striequal(globalData.options.desiredApiVersion.c_str(), "1.1")) - globalData.options.desiredApiVersionValue = XR_MAKE_VERSION(1, 1, XR_VERSION_PATCH(XR_CURRENT_API_VERSION)); + globalData.options.desiredApiVersionValue = XR_API_VERSION_1_1; else { ReportConsoleOnlyF("invalid arg: %s", globalData.options.desiredApiVersion.c_str()); return ParserResult::runtimeError("invalid OpenXR version '" + arg + "' passed on command line"); diff --git a/src/conformance/conformance_test/gltf_examples/AlphaBlendModeTest.png b/src/conformance/conformance_test/gltf_examples/AlphaBlendModeTest.png index ae72e16c..af01faf5 100644 Binary files a/src/conformance/conformance_test/gltf_examples/AlphaBlendModeTest.png and b/src/conformance/conformance_test/gltf_examples/AlphaBlendModeTest.png differ diff --git a/src/conformance/conformance_test/gltf_examples/MetalRoughSpheres.png b/src/conformance/conformance_test/gltf_examples/MetalRoughSpheres.png index f48b789b..63a69049 100644 Binary files a/src/conformance/conformance_test/gltf_examples/MetalRoughSpheres.png and b/src/conformance/conformance_test/gltf_examples/MetalRoughSpheres.png differ diff --git a/src/conformance/conformance_test/gltf_examples/MetalRoughSpheresNoTextures.png b/src/conformance/conformance_test/gltf_examples/MetalRoughSpheresNoTextures.png index 99b214ca..fac4c8c7 100644 Binary files a/src/conformance/conformance_test/gltf_examples/MetalRoughSpheresNoTextures.png and b/src/conformance/conformance_test/gltf_examples/MetalRoughSpheresNoTextures.png differ diff --git a/src/conformance/conformance_test/gltf_examples/NormalTangentMirrorTest.png b/src/conformance/conformance_test/gltf_examples/NormalTangentMirrorTest.png index 0dd664b1..64440975 100644 Binary files a/src/conformance/conformance_test/gltf_examples/NormalTangentMirrorTest.png and b/src/conformance/conformance_test/gltf_examples/NormalTangentMirrorTest.png differ diff --git a/src/conformance/conformance_test/gltf_examples/NormalTangentTest.png b/src/conformance/conformance_test/gltf_examples/NormalTangentTest.png index 3c063ce5..1a93fbc9 100644 Binary files a/src/conformance/conformance_test/gltf_examples/NormalTangentTest.png and b/src/conformance/conformance_test/gltf_examples/NormalTangentTest.png differ diff --git a/src/conformance/conformance_test/gltf_examples/TextureSettingsTest.png b/src/conformance/conformance_test/gltf_examples/TextureSettingsTest.png index b9f56fe6..7bf2b29d 100644 Binary files a/src/conformance/conformance_test/gltf_examples/TextureSettingsTest.png and b/src/conformance/conformance_test/gltf_examples/TextureSettingsTest.png differ diff --git a/src/conformance/conformance_test/gltf_examples/VertexColorTest.png b/src/conformance/conformance_test/gltf_examples/VertexColorTest.png index 4f982406..c05b019a 100644 Binary files a/src/conformance/conformance_test/gltf_examples/VertexColorTest.png and b/src/conformance/conformance_test/gltf_examples/VertexColorTest.png differ diff --git a/src/conformance/conformance_test/pbr_assets/brdf_lut.png b/src/conformance/conformance_test/pbr_assets/brdf_lut.png index bb5d52f0..4f29f300 100644 Binary files a/src/conformance/conformance_test/pbr_assets/brdf_lut.png and b/src/conformance/conformance_test/pbr_assets/brdf_lut.png differ diff --git a/src/conformance/conformance_test/test_LayerComposition.cpp b/src/conformance/conformance_test/test_LayerComposition.cpp index 474f6988..076da97b 100644 --- a/src/conformance/conformance_test/test_LayerComposition.cpp +++ b/src/conformance/conformance_test/test_LayerComposition.cpp @@ -530,7 +530,7 @@ namespace Conformance XrPosefCPP()}; XRC_CHECK_THROW_XRCMD(xrCreateReferenceSpace(session, &spaceCreateInfo, &space)); } - gripSpaces.push_back(std::move(space)); + gripSpaces.push_back(space); } // Create 10x10cm L and R quads @@ -720,7 +720,7 @@ namespace Conformance }).Loop(); } - TEST_CASE("ProjectionDepth", "[composition][interactive][no_auto][XR_KHR_composition_layer_depth][XR_FB_composition_layer_depth_test]") + TEST_CASE("ProjectionDepth", "[XR_KHR_composition_layer_depth][XR_FB_composition_layer_depth_test][composition][interactive][no_auto]") { GlobalData& globalData = GetGlobalData(); if (!globalData.IsInstanceExtensionSupported(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME)) { diff --git a/src/conformance/conformance_test/test_SessionState.cpp b/src/conformance/conformance_test/test_SessionState.cpp index cdc381ee..645a23ce 100644 --- a/src/conformance/conformance_test/test_SessionState.cpp +++ b/src/conformance/conformance_test/test_SessionState.cpp @@ -77,7 +77,7 @@ namespace Conformance return false; }; - XrEventDataSessionStateChanged evt; + XrEventDataSessionStateChanged evt{}; REQUIRE(waitForNextSessionState(&evt) == true); REQUIRE_MSG(evt.state == XR_SESSION_STATE_IDLE, "Unexpected session state " << evt.state); diff --git a/src/conformance/conformance_test/test_SpaceOffsets.cpp b/src/conformance/conformance_test/test_SpaceOffsets.cpp index 568413f3..6b5a920d 100644 --- a/src/conformance/conformance_test/test_SpaceOffsets.cpp +++ b/src/conformance/conformance_test/test_SpaceOffsets.cpp @@ -125,7 +125,7 @@ namespace Conformance const XrSwapchain swapchain = compositionHelper.CreateSwapchain(compositionHelper.DefaultColorSwapchainCreateInfo( viewProperties[j].recommendedImageRectWidth, viewProperties[j].recommendedImageRectHeight)); const_cast(projLayer->views[j].subImage) = compositionHelper.MakeDefaultSubImage(swapchain, 0); - swapchains.push_back(swapchain); + swapchains.emplace_back(swapchain); } } @@ -263,7 +263,7 @@ namespace Conformance XRC_CHECK_THROW_XRCMD(xrCreateActionSpace(compositionHelper.GetSession(), &spaceCreateInfo, &handSpace)); handSpaces.spaces.emplace_back(pose, handSpace); } - spaces.push_back(std::move(handSpaces)); + spaces.emplace_back(std::move(handSpaces)); } constexpr XrVector3f gnomonScale{0.025f, 0.025f, 0.025f}; @@ -510,7 +510,7 @@ namespace Conformance } if (spaceLocation.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) { - cubes.push_back(Cube{spaceLocation.pose, liveCubeScale}); + cubes.emplace_back(spaceLocation.pose, liveCubeScale); } } } @@ -530,7 +530,7 @@ namespace Conformance return tint; }; for (const auto& pastPose : space.pastPosesInLocalSpace) { - meshes.push_back(MeshDrawable{pastGnomonMesh, pastPose, gnomonScale, dimNonFailed()}); + meshes.emplace_back(pastGnomonMesh, pastPose, gnomonScale, dimNonFailed()); } struct predictionTrail @@ -554,12 +554,7 @@ namespace Conformance auto predictedDisplayTimeAtStep = frameState.predictedDisplayTime + step * frameState.predictedDisplayPeriod; gnomon.doSimulationStep({0.f, 0.f, 0.f}, predictedDisplayTimeAtStep); - meshes.push_back(MeshDrawable{ - trail.mesh, - gnomon.pose, - gnomonScale, - dimNonFailed(trail.tint), - }); + meshes.emplace_back(trail.mesh, gnomon.pose, gnomonScale, dimNonFailed(trail.tint)); } } } diff --git a/src/conformance/conformance_test/test_Swapchains.cpp b/src/conformance/conformance_test/test_Swapchains.cpp index 61c65c7a..c7b7ed1b 100644 --- a/src/conformance/conformance_test/test_Swapchains.cpp +++ b/src/conformance/conformance_test/test_Swapchains.cpp @@ -53,7 +53,7 @@ namespace Conformance XrSwapchainImageWaitInfo imageWaitInfo{XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO}; imageWaitInfo.timeout = XR_INFINITE_DURATION; - // acquire/wait/render/release all the images. + // Acquire/wait/render/release all the images. for (uint32_t i = 0; i < colorImageCount; ++i) { CAPTURE(i); uint32_t colorImageIndex = UINT32_MAX; @@ -603,12 +603,11 @@ namespace Conformance swapchainImages->GetColorImageArray())); DoRenderTest(swapchainImages, colorImageCount, colorCreateInfo, colorSwapchain.get()); + GetGlobalData().graphicsPlugin->Flush(); } // SwapchainScoped will have xrDestroySwapchain - // now we need to flush GetGlobalData().graphicsPlugin->ClearSwapchainCache(); - GetGlobalData().graphicsPlugin->Flush(); } } } diff --git a/src/conformance/conformance_test/test_XR_EXT_debug_utils.cpp b/src/conformance/conformance_test/test_XR_EXT_debug_utils.cpp index 5d8a4483..36431e4b 100644 --- a/src/conformance/conformance_test/test_XR_EXT_debug_utils.cpp +++ b/src/conformance/conformance_test/test_XR_EXT_debug_utils.cpp @@ -244,7 +244,7 @@ namespace Conformance return *it; } - TEST_CASE("XR_EXT_debug_utils", "") + TEST_CASE("XR_EXT_debug_utils", "[XR_EXT_debug_utils]") { GlobalData& globalData = GetGlobalData(); diff --git a/src/conformance/conformance_test/test_XR_EXT_dpad_binding.cpp b/src/conformance/conformance_test/test_XR_EXT_dpad_binding.cpp index fb0a7b01..87786b5b 100644 --- a/src/conformance/conformance_test/test_XR_EXT_dpad_binding.cpp +++ b/src/conformance/conformance_test/test_XR_EXT_dpad_binding.cpp @@ -827,7 +827,7 @@ namespace Conformance } } - TEST_CASE("XR_EXT_dpad_binding", "") + TEST_CASE("XR_EXT_dpad_binding", "[XR_EXT_dpad_binding]") { GlobalData& globalData = GetGlobalData(); if (!globalData.IsInstanceExtensionSupported(XR_EXT_DPAD_BINDING_EXTENSION_NAME) || @@ -1151,7 +1151,7 @@ namespace Conformance } } - TEST_CASE("XR_EXT_dpad_binding-interactive_thumbstick", "[actions][interactive][no_auto]") + TEST_CASE("XR_EXT_dpad_binding-interactive_thumbstick", "[XR_EXT_dpad_binding][actions][interactive][no_auto]") { GlobalData& globalData = GetGlobalData(); if (!globalData.IsInstanceExtensionSupported(XR_EXT_DPAD_BINDING_EXTENSION_NAME) || @@ -1230,7 +1230,7 @@ namespace Conformance } } - TEST_CASE("XR_EXT_dpad_binding-interactive_trackpad", "[actions][interactive][no_auto]") + TEST_CASE("XR_EXT_dpad_binding-interactive_trackpad", "[XR_EXT_dpad_binding][actions][interactive][no_auto]") { GlobalData& globalData = GetGlobalData(); if (!globalData.IsInstanceExtensionSupported(XR_EXT_DPAD_BINDING_EXTENSION_NAME) || 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 04a662a5..ae8d6d66 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 @@ -270,7 +270,7 @@ namespace Conformance } } - TEST_CASE("XR_EXT_eye_gaze_interaction", "[scenario][interactive][no_auto][XR_EXT_eye_gaze_interaction]") + TEST_CASE("XR_EXT_eye_gaze_interaction", "[XR_EXT_eye_gaze_interaction][scenario][interactive][no_auto]") { GlobalData& globalData = GetGlobalData(); if (!globalData.IsInstanceExtensionSupported(XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME)) { @@ -369,7 +369,7 @@ namespace Conformance } } - TEST_CASE("XR_EXT_eye_gaze_interaction-interactive_gaze_only", "[scenario][interactive][no_auto][XR_EXT_eye_gaze_interaction]") + TEST_CASE("XR_EXT_eye_gaze_interaction-interactive_gaze_only", "[XR_EXT_eye_gaze_interaction][scenario][interactive][no_auto]") { GlobalData& globalData = GetGlobalData(); 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 c399f534..eefac984 100644 --- a/src/conformance/conformance_test/test_XR_EXT_hand_tracking.cpp +++ b/src/conformance/conformance_test/test_XR_EXT_hand_tracking.cpp @@ -37,7 +37,7 @@ namespace Conformance MakeSystemPropertiesBoolChecker(XrSystemHandTrackingPropertiesEXT{XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT}, &XrSystemHandTrackingPropertiesEXT::supportsHandTracking); - TEST_CASE("XR_EXT_hand_tracking-create-destroy", "") + TEST_CASE("XR_EXT_hand_tracking-create-destroy", "[XR_EXT_hand_tracking]") { GlobalData& globalData = GetGlobalData(); if (!globalData.IsInstanceExtensionSupported(XR_EXT_HAND_TRACKING_EXTENSION_NAME)) { @@ -96,7 +96,7 @@ namespace Conformance } } - TEST_CASE("XR_EXT_hand_tracking-simple-queries") + TEST_CASE("XR_EXT_hand_tracking-simple-queries", "[XR_EXT_hand_tracking]") { GlobalData& globalData = GetGlobalData(); if (!globalData.IsInstanceExtensionSupported(XR_EXT_HAND_TRACKING_EXTENSION_NAME)) { @@ -296,7 +296,7 @@ namespace Conformance } // Purpose: Ensure that if the hand tracking extension is enabled, you can see some hands! - TEST_CASE("XR_EXT_hand_tracking-interactive", "[scenario][interactive][no_auto]") + TEST_CASE("XR_EXT_hand_tracking-interactive", "[XR_EXT_hand_tracking][scenario][interactive][no_auto]") { const char* instructions = "Small cubes are rendered to represent the joints of each hand. " 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 14e4c267..ec790ee0 100644 --- a/src/conformance/conformance_test/test_XR_EXT_palm_pose.cpp +++ b/src/conformance/conformance_test/test_XR_EXT_palm_pose.cpp @@ -691,7 +691,7 @@ namespace Conformance XrVector3f gripSurfaceXDirection{}; XrQuaternionf_RotateVector3f(&gripSurfaceXDirection, &gripSurfaceLocation.pose.orientation, &xAxis); double xAngleDiff = angleDeg(xAxis, gripSurfaceXDirection); - REQUIRE(xAngleDiff < 45.0f); + REQUIRE(xAngleDiff < 75.0f); } { @@ -714,7 +714,7 @@ namespace Conformance XrVector3f gripSurfaceYDirection{}; XrQuaternionf_RotateVector3f(&gripSurfaceYDirection, &gripSurfaceLocation.pose.orientation, &yAxis); double yAngleDiff = angleDeg(zMAxis, gripSurfaceYDirection); - REQUIRE(std::abs(yAngleDiff) < 45.0f); + REQUIRE(std::abs(yAngleDiff) < 85.0f); } if (i == 0) { @@ -726,12 +726,13 @@ namespace Conformance REQUIRE(gripSurfaceZDirection.x < 0); } else { - // Test that the z axis (direction from the palm center to the wrist) of grip surface points "to the right" in grip space. + // Test that the z axis (direction from the palm center to the wrist) of grip surface points not significantly to the left in grip space, + // i.e. the part of the hand between wrist and grip_surface pose does not point through the controller handle. // This should be true for all usual controllers. If this is not true for your controller, you may need to adapt or discard this test. XrVector3f zAxis = {0, 0, 1}; XrVector3f gripSurfaceZDirection{}; XrQuaternionf_RotateVector3f(&gripSurfaceZDirection, &gripSurfaceLocation.pose.orientation, &zAxis); - REQUIRE(gripSurfaceZDirection.x > 0); + REQUIRE(gripSurfaceZDirection.x >= -10); } { 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 4a0027d0..9516c6e5 100644 --- a/src/conformance/conformance_test/test_XR_EXT_plane_detection.cpp +++ b/src/conformance/conformance_test/test_XR_EXT_plane_detection.cpp @@ -405,7 +405,7 @@ namespace Conformance REQUIRE(XR_SUCCESS == xrDestroyPlaneDetectorEXT(detection)); } - TEST_CASE("XR_EXT_plane_detection-V", "[scenario][interactive][no_auto][XR_EXT_plane_detection]") + TEST_CASE("XR_EXT_plane_detection-V", "[XR_EXT_plane_detection][scenario][interactive][no_auto]") { RunPlaneTest({XR_PLANE_DETECTOR_ORIENTATION_VERTICAL_EXT}, "Planes should be rendered at the vertical surfaces, " @@ -413,7 +413,7 @@ namespace Conformance "Press the select button on either controller to pass the test."); } - TEST_CASE("XR_EXT_plane_detection-HU", "[scenario][interactive][no_auto][XR_EXT_plane_detection]") + TEST_CASE("XR_EXT_plane_detection-HU", "[XR_EXT_plane_detection][scenario][interactive][no_auto]") { RunPlaneTest({XR_PLANE_DETECTOR_ORIENTATION_HORIZONTAL_UPWARD_EXT}, "Planes should be rendered at the horizontal surfaces with upward normals, " @@ -421,7 +421,7 @@ namespace Conformance "Press the select button on either controller to pass the test."); } - TEST_CASE("XR_EXT_plane_detection-HD", "[scenario][interactive][no_auto][XR_EXT_plane_detection]") + TEST_CASE("XR_EXT_plane_detection-HD", "[XR_EXT_plane_detection][scenario][interactive][no_auto]") { RunPlaneTest({XR_PLANE_DETECTOR_ORIENTATION_HORIZONTAL_DOWNWARD_EXT}, "Planes should be rendered at the horizontal surfaces with downward normals, " @@ -429,21 +429,21 @@ namespace Conformance "Press the select button on either controller to pass the test."); } - TEST_CASE("XR_EXT_plane_detection-A", "[scenario][interactive][no_auto][XR_EXT_plane_detection]") + TEST_CASE("XR_EXT_plane_detection-A", "[XR_EXT_plane_detection][scenario][interactive][no_auto]") { RunPlaneTest({XR_PLANE_DETECTOR_ORIENTATION_ARBITRARY_EXT}, "Planes should be rendered at the non horizontal/vertical surfaces. " "Press the select button on either controller to pass the test."); } - TEST_CASE("XR_EXT_plane_detection-empty-list", "[scenario][interactive][no_auto][XR_EXT_plane_detection]") + TEST_CASE("XR_EXT_plane_detection-empty-list", "[XR_EXT_plane_detection][scenario][interactive][no_auto]") { RunPlaneTest({}, "All planes should be rendered. " "Press the select button on either controller to pass the test."); } - TEST_CASE("XR_EXT_plane_detection-nullptr", "[scenario][interactive][no_auto][XR_EXT_plane_detection]") + TEST_CASE("XR_EXT_plane_detection-nullptr", "[XR_EXT_plane_detection][scenario][interactive][no_auto]") { RunPlaneTest({}, "All planes should be rendered. " @@ -451,25 +451,25 @@ namespace Conformance XR_PLANE_DETECTOR_SEMANTIC_TYPE_UNDEFINED_EXT, true); } - TEST_CASE("XR_EXT_plane_detection-ceiling", "[scenario][interactive][no_auto][XR_EXT_plane_detection]") + TEST_CASE("XR_EXT_plane_detection-ceiling", "[XR_EXT_plane_detection][scenario][interactive][no_auto]") { RunPlaneTest({XR_PLANE_DETECTOR_ORIENTATION_HORIZONTAL_DOWNWARD_EXT}, "Make sure a ceiling is detected in the scene.", XR_PLANE_DETECTOR_SEMANTIC_TYPE_CEILING_EXT); } - TEST_CASE("XR_EXT_plane_detection-floor", "[scenario][interactive][no_auto][XR_EXT_plane_detection]") + TEST_CASE("XR_EXT_plane_detection-floor", "[XR_EXT_plane_detection][scenario][interactive][no_auto]") { RunPlaneTest({XR_PLANE_DETECTOR_ORIENTATION_HORIZONTAL_UPWARD_EXT}, "Make sure a floor is detected in the scene.", XR_PLANE_DETECTOR_SEMANTIC_TYPE_FLOOR_EXT); } - TEST_CASE("XR_EXT_plane_detection-wall", "[scenario][interactive][no_auto][XR_EXT_plane_detection]") + TEST_CASE("XR_EXT_plane_detection-wall", "[XR_EXT_plane_detection][scenario][interactive][no_auto]") { RunPlaneTest({XR_PLANE_DETECTOR_ORIENTATION_VERTICAL_EXT}, "Make sure a wall is detected in the scene.", XR_PLANE_DETECTOR_SEMANTIC_TYPE_WALL_EXT); } - TEST_CASE("XR_EXT_plane_detection-platform", "[scenario][interactive][no_auto][XR_EXT_plane_detection]") + TEST_CASE("XR_EXT_plane_detection-platform", "[XR_EXT_plane_detection][scenario][interactive][no_auto]") { RunPlaneTest({XR_PLANE_DETECTOR_ORIENTATION_HORIZONTAL_UPWARD_EXT}, "Make sure a platform is detected in the scene.", XR_PLANE_DETECTOR_SEMANTIC_TYPE_PLATFORM_EXT); @@ -833,25 +833,25 @@ namespace Conformance REQUIRE(XR_SUCCESS == xrDestroyPlaneDetectorEXT(detection)); } - TEST_CASE("XR_EXT_plane_detection-contour-HU", "[scenario][interactive][no_auto][XR_EXT_plane_detection]") + TEST_CASE("XR_EXT_plane_detection-contour-HU", "[XR_EXT_plane_detection][scenario][interactive][no_auto]") { RunPlaneContourTest({XR_PLANE_DETECTOR_ORIENTATION_HORIZONTAL_UPWARD_EXT}, "ext_plane_detection_contour.png", "This should show the plane contours of all upward horizontal planes."); } - TEST_CASE("XR_EXT_plane_detection-contour-HD", "[scenario][interactive][no_auto][XR_EXT_plane_detection]") + TEST_CASE("XR_EXT_plane_detection-contour-HD", "[XR_EXT_plane_detection][scenario][interactive][no_auto]") { RunPlaneContourTest({XR_PLANE_DETECTOR_ORIENTATION_HORIZONTAL_DOWNWARD_EXT}, "ext_plane_detection_contour.png", "This should show the plane contours of all downward horizontal planes."); } - TEST_CASE("XR_EXT_plane_detection-contour-V", "[scenario][interactive][no_auto][XR_EXT_plane_detection]") + TEST_CASE("XR_EXT_plane_detection-contour-V", "[XR_EXT_plane_detection][scenario][interactive][no_auto]") { RunPlaneContourTest({XR_PLANE_DETECTOR_ORIENTATION_VERTICAL_EXT}, "ext_plane_detection_contour.png", "This should show the plane contours of all vertical planes."); } - TEST_CASE("XR_EXT_plane_detection-contour-A", "[scenario][interactive][no_auto][XR_EXT_plane_detection]") + TEST_CASE("XR_EXT_plane_detection-contour-A", "[XR_EXT_plane_detection][scenario][interactive][no_auto]") { RunPlaneContourTest({XR_PLANE_DETECTOR_ORIENTATION_ARBITRARY_EXT}, "ext_plane_detection_contour.png", "This should show the plane contours of all non vertical / horizontal (arbitrary) planes."); diff --git a/src/conformance/conformance_test/test_XR_EXT_thermal_query.cpp b/src/conformance/conformance_test/test_XR_EXT_thermal_query.cpp index f2037772..8bb28fad 100644 --- a/src/conformance/conformance_test/test_XR_EXT_thermal_query.cpp +++ b/src/conformance/conformance_test/test_XR_EXT_thermal_query.cpp @@ -26,7 +26,7 @@ namespace Conformance { - TEST_CASE("XR_EXT_thermal_query", "") + TEST_CASE("XR_EXT_thermal_query", "[XR_EXT_thermal_query]") { GlobalData& globalData = GetGlobalData(); if (!globalData.IsInstanceExtensionSupported("XR_EXT_thermal_query")) { diff --git a/src/conformance/conformance_test/test_XR_KHR_D3D11_enable.cpp b/src/conformance/conformance_test/test_XR_KHR_D3D11_enable.cpp index e463959a..9a766cc5 100644 --- a/src/conformance/conformance_test/test_XR_KHR_D3D11_enable.cpp +++ b/src/conformance/conformance_test/test_XR_KHR_D3D11_enable.cpp @@ -36,7 +36,7 @@ using namespace Microsoft::WRL; namespace Conformance { - TEST_CASE("XR_KHR_D3D11_enable", "") + TEST_CASE("XR_KHR_D3D11_enable", "[XR_KHR_D3D11_enable]") { GlobalData& globalData = GetGlobalData(); if (!globalData.IsInstanceExtensionEnabled(XR_KHR_D3D11_ENABLE_EXTENSION_NAME)) { diff --git a/src/conformance/conformance_test/test_XR_KHR_D3D12_enable.cpp b/src/conformance/conformance_test/test_XR_KHR_D3D12_enable.cpp index 92d555f1..2c1453d3 100644 --- a/src/conformance/conformance_test/test_XR_KHR_D3D12_enable.cpp +++ b/src/conformance/conformance_test/test_XR_KHR_D3D12_enable.cpp @@ -35,7 +35,7 @@ using namespace Microsoft::WRL; namespace Conformance { - TEST_CASE("XR_KHR_D3D12_enable", "") + TEST_CASE("XR_KHR_D3D12_enable", "[XR_KHR_D3D12_enable]") { GlobalData& globalData = GetGlobalData(); if (!globalData.IsInstanceExtensionEnabled(XR_KHR_D3D12_ENABLE_EXTENSION_NAME)) { diff --git a/src/conformance/conformance_test/test_XR_KHR_OpenGL_ES_enable.cpp b/src/conformance/conformance_test/test_XR_KHR_OpenGL_ES_enable.cpp index 38a8959c..19b07ada 100644 --- a/src/conformance/conformance_test/test_XR_KHR_OpenGL_ES_enable.cpp +++ b/src/conformance/conformance_test/test_XR_KHR_OpenGL_ES_enable.cpp @@ -32,7 +32,7 @@ namespace Conformance { - TEST_CASE("XR_KHR_opengl_es_enable", "") + TEST_CASE("XR_KHR_opengl_es_enable", "[XR_KHR_opengl_es_enable]") { GlobalData& globalData = GetGlobalData(); if (!globalData.IsInstanceExtensionEnabled(XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME)) { diff --git a/src/conformance/conformance_test/test_XR_KHR_OpenGL_enable.cpp b/src/conformance/conformance_test/test_XR_KHR_OpenGL_enable.cpp index 6f5368a7..cfce8e15 100644 --- a/src/conformance/conformance_test/test_XR_KHR_OpenGL_enable.cpp +++ b/src/conformance/conformance_test/test_XR_KHR_OpenGL_enable.cpp @@ -33,7 +33,7 @@ namespace Conformance { - TEST_CASE("XR_KHR_opengl_enable", "") + TEST_CASE("XR_KHR_opengl_enable", "[XR_KHR_opengl_enable]") { GlobalData& globalData = GetGlobalData(); if (!globalData.IsInstanceExtensionEnabled(XR_KHR_OPENGL_ENABLE_EXTENSION_NAME)) { diff --git a/src/conformance/conformance_test/test_XR_KHR_composition_layer_cube.cpp b/src/conformance/conformance_test/test_XR_KHR_composition_layer_cube.cpp index bc8e839b..c5886de9 100644 --- a/src/conformance/conformance_test/test_XR_KHR_composition_layer_cube.cpp +++ b/src/conformance/conformance_test/test_XR_KHR_composition_layer_cube.cpp @@ -14,6 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "composition_utils.h" #include "conformance_framework.h" #include "conformance_utils.h" #include "utilities/generator.h" @@ -32,7 +33,7 @@ namespace Conformance { // This implements an automated programmatic test of the cubemap layer. However, a separate visual // test is required in order to validate that it looks correct. - TEST_CASE("XR_KHR_composition_layer_cube", "") + TEST_CASE("XR_KHR_composition_layer_cube", "[XR_KHR_composition_layer_cube]") { GlobalData& globalData = GetGlobalData(); if (!globalData.IsInstanceExtensionSupported(XR_KHR_COMPOSITION_LAYER_CUBE_EXTENSION_NAME)) { @@ -81,7 +82,7 @@ namespace Conformance for (XrSpace space : session.spaceVector) { for (XrEyeVisibility eyeVisibility : eyeVisibilityArray) { std::array orientationTestArray{ - XrQuaternionf{0, 0, 0, 1}, // No rotation; looking down the +x axis + Quat::Identity, // No rotation; looking down the +x axis XrQuaternionf{0, 0.7071f, 0, 0.7071f}, // 90 degree rotation around y axis; looking down the -z axis. XrQuaternionf{0, 0, 0.7071f, 0.7071f}, // 90 degree rotation around z axis; looking down the +y axis. XrQuaternionf{-0.709f, 0.383f, -0.381f, -0.454f} // Misc value. diff --git a/src/conformance/conformance_test/test_XR_KHR_composition_layer_cylinder.cpp b/src/conformance/conformance_test/test_XR_KHR_composition_layer_cylinder.cpp index 9fd04593..b1e532f5 100644 --- a/src/conformance/conformance_test/test_XR_KHR_composition_layer_cylinder.cpp +++ b/src/conformance/conformance_test/test_XR_KHR_composition_layer_cylinder.cpp @@ -32,7 +32,7 @@ namespace Conformance { // This implements an automated programmatic test of the cylinder layer. However, a separate visual // test is required in order to validate that it looks correct. - TEST_CASE("XR_KHR_composition_layer_cylinder", "") + TEST_CASE("XR_KHR_composition_layer_cylinder", "[XR_KHR_composition_layer_cylinder]") { GlobalData& globalData = GetGlobalData(); if (!globalData.IsInstanceExtensionSupported(XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME)) { diff --git a/src/conformance/conformance_test/test_XR_KHR_composition_layer_depth.cpp b/src/conformance/conformance_test/test_XR_KHR_composition_layer_depth.cpp index 2fb6b576..31884f10 100644 --- a/src/conformance/conformance_test/test_XR_KHR_composition_layer_depth.cpp +++ b/src/conformance/conformance_test/test_XR_KHR_composition_layer_depth.cpp @@ -30,7 +30,7 @@ namespace Conformance { // This implements an automated programmatic test of depth layers. However, a separate visual // test is required in order to validate that it looks correct. - TEST_CASE("XR_KHR_composition_layer_depth", "") + TEST_CASE("XR_KHR_composition_layer_depth", "[XR_KHR_composition_layer_depth]") { GlobalData& globalData = GetGlobalData(); if (!globalData.IsInstanceExtensionSupported(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME)) { diff --git a/src/conformance/conformance_test/test_XR_KHR_composition_layer_equirect.cpp b/src/conformance/conformance_test/test_XR_KHR_composition_layer_equirect.cpp index 3a38b4bb..627e9653 100644 --- a/src/conformance/conformance_test/test_XR_KHR_composition_layer_equirect.cpp +++ b/src/conformance/conformance_test/test_XR_KHR_composition_layer_equirect.cpp @@ -14,25 +14,31 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "RGBAImage.h" +#include "composition_utils.h" #include "conformance_framework.h" #include "conformance_utils.h" +#include "utilities/array_size.h" #include "utilities/bitmask_generator.h" #include "utilities/bitmask_to_string.h" -#include "utilities/generator.h" #include "utilities/xrduration_literals.h" #include +#include +#include #include #include -#include +#include +#include +#include #include namespace Conformance { // This implements an automated programmatic test of the equirect layer. However, a separate visual // test is required in order to validate that it looks correct. - TEST_CASE("XR_KHR_composition_layer_equirect", "") + TEST_CASE("XR_KHR_composition_layer_equirect", "[XR_KHR_composition_layer_equirect]") { GlobalData& globalData = GetGlobalData(); if (!globalData.IsInstanceExtensionSupported(XR_KHR_COMPOSITION_LAYER_EQUIRECT_EXTENSION_NAME)) { @@ -97,7 +103,7 @@ namespace Conformance for (float radius : radiusTestArray) { std::array orientationTestArray{ - XrQuaternionf{0, 0, 0, 1}, // No rotation; looking down the +x axis + Quat::Identity, // No rotation; looking down the +x axis XrQuaternionf{0, 0.7071f, 0, 0.7071f}, // 90 degree rotation around y axis; looking down the -z axis. XrQuaternionf{0, 0, 0.7071f, 0.7071f}, // 90 degree rotation around z axis; looking down the +y axis. XrQuaternionf{-0.709f, 0.383f, -0.381f, -0.454f} // Misc value. @@ -170,4 +176,169 @@ namespace Conformance frameIterator.RunToSessionState(XR_SESSION_STATE_STOPPING); } + + struct EquirectTestCase + { + + const char* name; + const char* description; + XrReferenceSpaceType spaceType; + XrPosef pose; + float radius; + XrVector2f scale; + XrVector2f bias; + const char* imagePath; + XrRect2Df crop; // normalised + const char* exampleImagePath; + }; + + const EquirectTestCase equirectTestCases[] = { + { + "Full sphere at infinity", + "A 360 view of the inside of a cube at infinity", + XR_REFERENCE_SPACE_TYPE_LOCAL, + {Quat::Identity, {0, 0, 0}}, + 0.0, // infinity + {1.0, 1.0}, + {0.0, 0.0}, + "equirect_8k.png", + {{0, 0}, {1, 1}}, + "equirect_local_space.jpg", + }, + { + "Full sphere at infinity (view space)", + "A 360 view of the inside of a cube at infinity, rendered in view space", + XR_REFERENCE_SPACE_TYPE_VIEW, + {Quat::Identity, {0, 0, 0}}, + 0.0, // infinity + {1.0, 1.0}, + {0.0, 0.0}, + "equirect_8k.png", + {{0, 0}, {1, 1}}, + "equirect_view_space.jpg", + }, + { + "Full sphere at 2m", + "A 2m sphere with the same cube test image. " + "Example is shown from above and to the left of the origin to make the perspective effect clear.", + XR_REFERENCE_SPACE_TYPE_LOCAL, + {Quat::Identity, {0, 0, 0}}, + 2.0, + {1.0, 1.0}, + {0.0, 0.0}, + "equirect_8k.png", + {{0, 0}, {1, 1}}, + "equirect_finite.jpg", + }, + { + "Full sphere at 2m with pose", + "A 2m sphere with the same cube test image, forward by 1.5m and rotated downward", + XR_REFERENCE_SPACE_TYPE_LOCAL, + {Quat::FromAxisAngle({1, 0, 0}, Math::DegToRad(45)), {0, 0, -1.5}}, + 2.0, + {1.0, 1.0}, + {0.0, 0.0}, + "equirect_8k.png", + {{0, 0}, {1, 1}}, + "equirect_finite_pose.jpg", + }, + { + "90 degree section at infinity (cropped file)", + "A 90 degree section in both latitude and longitude, rendered at infinity", + XR_REFERENCE_SPACE_TYPE_LOCAL, + {Quat::Identity, {0, 0, 0}}, + 0.0, // infinity + {0.25, 0.5}, + {0.0, 0.0}, + "equirect_central_90.png", + {{0, 0}, {1, 1}}, + "equirect_central_90.jpg", + }, + { + "90 degree section at infinity (cropped image extents)", + "A 90 degree section in both latitude and longitude, rendered at infinity", + XR_REFERENCE_SPACE_TYPE_LOCAL, + {Quat::Identity, {0, 0, 0}}, + 0.0, // infinity + {0.25, 0.5}, + {0.0, 0.0}, + "equirect_8k.png", + {{3 / 8., 2 / 8.}, {1 / 4., 2 / 4.}}, + "equirect_central_90.jpg", + }, + }; + + static RGBAImageCache& EquirectImageCache() + { + static RGBAImageCache imageCache{}; + imageCache.Init(); + return imageCache; + } + TEST_CASE("XR_KHR_composition_layer_equirect-interactive", "[composition][interactive][no_auto]") + { + GlobalData& globalData = GetGlobalData(); + + if (!globalData.IsInstanceExtensionSupported(XR_KHR_COMPOSITION_LAYER_EQUIRECT_EXTENSION_NAME)) { + SKIP(XR_KHR_COMPOSITION_LAYER_EQUIRECT_EXTENSION_NAME " not supported"); + } + + auto testCaseIdx = GENERATE(Catch::Generators::range(0, ArraySize(equirectTestCases))); + auto testCase = equirectTestCases[testCaseIdx]; + // technically redundant because GENERATE() makes a "section", but this makes the test more usable. + DYNAMIC_SECTION("Test condition name: " << testCase.name) + { + INFO("Test condition description: " << testCase.description); + std::string testTitle = SubtestTitle("Equirect layer", testCaseIdx, equirectTestCases); + CompositionHelper compositionHelper(testTitle.c_str(), {XR_KHR_COMPOSITION_LAYER_EQUIRECT_EXTENSION_NAME}); + + std::ostringstream oss; + oss << testTitle << ": " << testCase.name << '\n'; + oss << testCase.description << '\n'; + + InteractiveLayerManager interactiveLayerManager(compositionHelper, testCase.exampleImagePath, oss.str().c_str()); + compositionHelper.GetInteractionManager().AttachActionSets(); + compositionHelper.BeginSession(); + + const XrSpace space = compositionHelper.CreateReferenceSpace(testCase.spaceType); + + std::shared_ptr image = EquirectImageCache().Load(testCase.imagePath); + int32_t imageWidth = image->width; + int32_t imageHeight = image->height; + + XrSwapchainCreateInfo createInfo = compositionHelper.DefaultColorSwapchainCreateInfo( + imageWidth, imageHeight, XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT, GetGlobalData().graphicsPlugin->GetSRGBA8Format()); + + // copying to this swapchain, not rendering to it + createInfo.usageFlags |= XR_SWAPCHAIN_USAGE_TRANSFER_DST_BIT; + + XrSwapchain swapchain = compositionHelper.CreateSwapchain(createInfo); + + compositionHelper.AcquireWaitReleaseImage(swapchain, [&](const XrSwapchainImageBaseHeader* swapchainImage) { + GetGlobalData().graphicsPlugin->CopyRGBAImage(swapchainImage, 0, *image); + }); + + XrCompositionLayerEquirectKHR equirectLayer{XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR}; + equirectLayer.space = space; + equirectLayer.eyeVisibility = XR_EYE_VISIBILITY_BOTH; + equirectLayer.subImage.swapchain = swapchain; + equirectLayer.subImage.imageRect = CropImage(imageWidth, imageHeight, testCase.crop); + equirectLayer.subImage.imageArrayIndex = 0; + equirectLayer.pose = testCase.pose; + equirectLayer.radius = testCase.radius; + equirectLayer.scale = testCase.scale; + equirectLayer.bias = testCase.bias; + + interactiveLayerManager.AddBackgroundLayer(&equirectLayer); + + RenderLoop(compositionHelper.GetSession(), [&](const XrFrameState& frameState) { + if (!interactiveLayerManager.EndFrame(frameState)) { + // user has marked this test as complete + SUCCEED("User has marked this test as passed"); + return false; + } + return true; + }).Loop(); + } + } + } // namespace Conformance diff --git a/src/conformance/conformance_test/test_XR_KHR_composition_layer_equirect2.cpp b/src/conformance/conformance_test/test_XR_KHR_composition_layer_equirect2.cpp new file mode 100644 index 00000000..6188bc99 --- /dev/null +++ b/src/conformance/conformance_test/test_XR_KHR_composition_layer_equirect2.cpp @@ -0,0 +1,212 @@ +// Copyright (c) 2019-2024, The Khronos Group Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "RGBAImage.h" +#include "composition_utils.h" +#include "conformance_framework.h" +#include "conformance_utils.h" +#include "utilities/array_size.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace Conformance +{ + namespace + { + static const float pi = std::acos(-1.0f); + } + struct Equirect2TestCase + { + + const char* name; + const char* description; + XrReferenceSpaceType spaceType; + XrPosef pose; + float radius; + float centralHorizontalAngle; + float upperVerticalAngle; + float lowerVerticalAngle; + const char* imagePath; + XrRect2Df crop; // normalised + const char* exampleImagePath; + }; + + const Equirect2TestCase equirect2TestCases[] = { + { + "Full sphere at infinity", + "A 360 view of the inside of a cube at infinity", + XR_REFERENCE_SPACE_TYPE_LOCAL, + {Quat::Identity, {0, 0, 0}}, + 0.0f, // infinity + pi * 2.f, + pi / 2.f, + -pi / 2.f, + "equirect_8k.png", + {{0, 0}, {1, 1}}, + "equirect_local_space.jpg", + }, + { + "Full sphere at infinity (view space)", + "A 360 view of the inside of a cube at infinity, rendered in view space", + XR_REFERENCE_SPACE_TYPE_VIEW, + {Quat::Identity, {0, 0, 0}}, + 0.0f, // infinity + pi * 2.f, + pi / 2.f, + -pi / 2.f, + "equirect_8k.png", + {{0, 0}, {1, 1}}, + "equirect_view_space.jpg", + }, + { + "Full sphere at 2m", + "A 2m sphere with the same cube test image. " + "Example is shown from above and to the left of the origin to make the perspective effect clear.", + XR_REFERENCE_SPACE_TYPE_LOCAL, + {Quat::Identity, {0, 0, 0}}, + 2.0f, + pi * 2.f, + pi / 2.f, + -pi / 2.f, + "equirect_8k.png", + {{0, 0}, {1, 1}}, + "equirect_finite.jpg", + }, + { + "Full sphere at 2m with pose", + "A 2m sphere with the same cube test image, forward by 1.5m and rotated downward", + XR_REFERENCE_SPACE_TYPE_LOCAL, + {Quat::FromAxisAngle({1, 0, 0}, Math::DegToRad(45)), {0, 0, -1.5}}, + 2.0f, + pi * 2.f, + pi / 2.f, + -pi / 2.f, + "equirect_8k.png", + {{0, 0}, {1, 1}}, + "equirect_finite_pose.jpg", + }, + { + "90 degree section at infinity (cropped file)", + "A 90 degree section in both latitude and longitude, rendered at infinity", + XR_REFERENCE_SPACE_TYPE_LOCAL, + {Quat::Identity, {0, 0, 0}}, + 0.0, // infinity + pi / 2.f, + pi / 4.f, + -pi / 4.f, + "equirect_central_90.png", + {{0, 0}, {1, 1}}, + "equirect_central_90.jpg", + }, + { + "90 degree section at infinity (cropped image extents)", + "A 90 degree section in both latitude and longitude, rendered at infinity", + XR_REFERENCE_SPACE_TYPE_LOCAL, + {Quat::Identity, {0, 0, 0}}, + 0.0, // infinity + pi / 2.f, + pi / 4.f, + -pi / 4.f, + "equirect_8k.png", + {{3 / 8., 2 / 8.}, {1 / 4., 2 / 4.}}, + "equirect_central_90.jpg", + }, + }; + + static RGBAImageCache& Equirect2ImageCache() + { + static RGBAImageCache imageCache{}; + imageCache.Init(); + return imageCache; + } + TEST_CASE("XR_KHR_composition_layer_equirect2-interactive", "[composition][interactive][no_auto]") + { + GlobalData& globalData = GetGlobalData(); + + if (!globalData.IsInstanceExtensionSupported(XR_KHR_COMPOSITION_LAYER_EQUIRECT2_EXTENSION_NAME)) { + SKIP(XR_KHR_COMPOSITION_LAYER_EQUIRECT2_EXTENSION_NAME " not supported"); + } + + auto testCaseIdx = GENERATE(Catch::Generators::range(0, ArraySize(equirect2TestCases))); + auto testCase = equirect2TestCases[testCaseIdx]; + // technically redundant because GENERATE() makes a "section", but this makes the test more usable. + DYNAMIC_SECTION("Test condition name: " << testCase.name) + { + INFO("Test condition description: " << testCase.description); + + std::string testTitle = SubtestTitle("Equirect2 layer", testCaseIdx, equirect2TestCases); + CompositionHelper compositionHelper(testTitle.c_str(), {XR_KHR_COMPOSITION_LAYER_EQUIRECT2_EXTENSION_NAME}); + + std::ostringstream oss; + oss << testTitle << ": " << testCase.name << '\n'; + oss << testCase.description << '\n'; + + InteractiveLayerManager interactiveLayerManager(compositionHelper, testCase.exampleImagePath, oss.str().c_str()); + compositionHelper.GetInteractionManager().AttachActionSets(); + compositionHelper.BeginSession(); + + const XrSpace space = compositionHelper.CreateReferenceSpace(testCase.spaceType); + + std::shared_ptr image = Equirect2ImageCache().Load(testCase.imagePath); + int32_t imageWidth = image->width; + int32_t imageHeight = image->height; + + XrSwapchainCreateInfo createInfo = compositionHelper.DefaultColorSwapchainCreateInfo( + imageWidth, imageHeight, XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT, GetGlobalData().graphicsPlugin->GetSRGBA8Format()); + + // copying to this swapchain, not rendering to it + createInfo.usageFlags |= XR_SWAPCHAIN_USAGE_TRANSFER_DST_BIT; + + XrSwapchain swapchain = compositionHelper.CreateSwapchain(createInfo); + + compositionHelper.AcquireWaitReleaseImage(swapchain, [&](const XrSwapchainImageBaseHeader* swapchainImage) { + GetGlobalData().graphicsPlugin->CopyRGBAImage(swapchainImage, 0, *image); + }); + + XrCompositionLayerEquirect2KHR equirect2Layer{XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR}; + equirect2Layer.space = space; + equirect2Layer.eyeVisibility = XR_EYE_VISIBILITY_BOTH; + equirect2Layer.subImage.swapchain = swapchain; + equirect2Layer.subImage.imageRect = CropImage(imageWidth, imageHeight, testCase.crop); + equirect2Layer.subImage.imageArrayIndex = 0; + equirect2Layer.pose = testCase.pose; + equirect2Layer.radius = testCase.radius; + equirect2Layer.centralHorizontalAngle = testCase.centralHorizontalAngle; + equirect2Layer.upperVerticalAngle = testCase.upperVerticalAngle; + equirect2Layer.lowerVerticalAngle = testCase.lowerVerticalAngle; + + interactiveLayerManager.AddBackgroundLayer(&equirect2Layer); + + RenderLoop(compositionHelper.GetSession(), [&](const XrFrameState& frameState) { + if (!interactiveLayerManager.EndFrame(frameState)) { + // user has marked this test as complete + SUCCEED("User has marked this test as passed"); + return false; + } + return true; + }).Loop(); + } + } + +} // namespace Conformance diff --git a/src/conformance/conformance_test/test_XR_KHR_convert_timespec_time.cpp b/src/conformance/conformance_test/test_XR_KHR_convert_timespec_time.cpp index e0d17d01..93be80e2 100644 --- a/src/conformance/conformance_test/test_XR_KHR_convert_timespec_time.cpp +++ b/src/conformance/conformance_test/test_XR_KHR_convert_timespec_time.cpp @@ -31,7 +31,7 @@ namespace Conformance { - TEST_CASE("XR_KHR_convert_timespec_time", "") + TEST_CASE("XR_KHR_convert_timespec_time", "[XR_KHR_convert_timespec_time]") { #ifndef XR_USE_TIMESPEC SKIP("XR_KHR_convert_timespec_time test not enabled in CTS"); diff --git a/src/conformance/conformance_test/test_XR_KHR_visibility_mask.cpp b/src/conformance/conformance_test/test_XR_KHR_visibility_mask.cpp index 9a10a02e..a1559c03 100644 --- a/src/conformance/conformance_test/test_XR_KHR_visibility_mask.cpp +++ b/src/conformance/conformance_test/test_XR_KHR_visibility_mask.cpp @@ -330,7 +330,7 @@ namespace Conformance return {mesh, bgColor}; } - TEST_CASE("XR_KHR_visibility_mask-interactive", "[scenario][interactive][no_auto][XR_KHR_visibility_mask]") + TEST_CASE("XR_KHR_visibility_mask-interactive", "[XR_KHR_visibility_mask][scenario][interactive][no_auto]") { // successcodes="XR_SUCCESS,XR_SESSION_LOSS_PENDING" // errorcodes="XR_ERROR_HANDLE_INVALID,XR_ERROR_INSTANCE_LOST,XR_ERROR_RUNTIME_FAILURE,XR_ERROR_VALIDATION_FAILURE, diff --git a/src/conformance/conformance_test/test_XR_KHR_vulkan_enable.cpp b/src/conformance/conformance_test/test_XR_KHR_vulkan_enable.cpp index 408e18d5..0afddd34 100644 --- a/src/conformance/conformance_test/test_XR_KHR_vulkan_enable.cpp +++ b/src/conformance/conformance_test/test_XR_KHR_vulkan_enable.cpp @@ -33,7 +33,7 @@ namespace Conformance { - TEST_CASE("XR_KHR_vulkan_enable", "") + TEST_CASE("XR_KHR_vulkan_enable", "[XR_KHR_vulkan_enable]") { GlobalData& globalData = GetGlobalData(); if (!globalData.IsInstanceExtensionEnabled(XR_KHR_VULKAN_ENABLE_EXTENSION_NAME)) { diff --git a/src/conformance/conformance_test/test_XR_KHR_vulkan_enable2.cpp b/src/conformance/conformance_test/test_XR_KHR_vulkan_enable2.cpp index ce5c23f2..1e1deb65 100644 --- a/src/conformance/conformance_test/test_XR_KHR_vulkan_enable2.cpp +++ b/src/conformance/conformance_test/test_XR_KHR_vulkan_enable2.cpp @@ -33,7 +33,7 @@ namespace Conformance { - TEST_CASE("XR_KHR_vulkan_enable2", "") + TEST_CASE("XR_KHR_vulkan_enable2", "[XR_KHR_vulkan_enable2]") { GlobalData& globalData = GetGlobalData(); if (!globalData.IsInstanceExtensionEnabled(XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME)) { diff --git a/src/conformance/conformance_test/test_XR_KHR_win32_convert_performance_counter_time.cpp b/src/conformance/conformance_test/test_XR_KHR_win32_convert_performance_counter_time.cpp index b8283cd0..db5eab68 100644 --- a/src/conformance/conformance_test/test_XR_KHR_win32_convert_performance_counter_time.cpp +++ b/src/conformance/conformance_test/test_XR_KHR_win32_convert_performance_counter_time.cpp @@ -30,7 +30,7 @@ namespace Conformance { - TEST_CASE("XR_KHR_win32_convert_performance_counter_time", "") + TEST_CASE("XR_KHR_win32_convert_performance_counter_time", "[XR_KHR_win32_convert_performance_counter_time]") { GlobalData& globalData = GetGlobalData(); if (!globalData.IsInstanceExtensionSupported(XR_KHR_WIN32_CONVERT_PERFORMANCE_COUNTER_TIME_EXTENSION_NAME)) { diff --git a/src/conformance/conformance_test/test_XR_META_performance_metrics.cpp b/src/conformance/conformance_test/test_XR_META_performance_metrics.cpp index c6db2d35..e199ebaa 100644 --- a/src/conformance/conformance_test/test_XR_META_performance_metrics.cpp +++ b/src/conformance/conformance_test/test_XR_META_performance_metrics.cpp @@ -29,7 +29,7 @@ namespace Conformance { - TEST_CASE("XR_META_performance_metrics", "") + TEST_CASE("XR_META_performance_metrics", "[XR_META_performance_metrics]") { GlobalData& globalData = GetGlobalData(); diff --git a/src/conformance/conformance_test/test_XR_MND_headless.cpp b/src/conformance/conformance_test/test_XR_MND_headless.cpp index 0b940185..eb6e9d7d 100644 --- a/src/conformance/conformance_test/test_XR_MND_headless.cpp +++ b/src/conformance/conformance_test/test_XR_MND_headless.cpp @@ -24,7 +24,7 @@ namespace Conformance { - TEST_CASE("XR_MND_headless", "") + TEST_CASE("XR_MND_headless", "[XR_MND_headless]") { GlobalData& globalData = GetGlobalData(); 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 c1372e85..7f88d5e1 100644 --- a/src/conformance/conformance_test/test_XR_MSFT_controller_model.cpp +++ b/src/conformance/conformance_test/test_XR_MSFT_controller_model.cpp @@ -111,7 +111,7 @@ namespace Conformance } }; - TEST_CASE("XR_MSFT_controller_model-simple", "") + TEST_CASE("XR_MSFT_controller_model-simple", "[XR_MSFT_controller_model]") { GlobalData& globalData = GetGlobalData(); @@ -125,7 +125,7 @@ namespace Conformance ext.CheckInvalidModelKey(session, XR_NULL_CONTROLLER_MODEL_KEY_MSFT); } - TEST_CASE("XR_MSFT_controller_model", "") + TEST_CASE("XR_MSFT_controller_model", "[XR_MSFT_controller_model]") { GlobalData& globalData = GetGlobalData(); @@ -307,7 +307,7 @@ namespace Conformance } } - TEST_CASE("XR_MSFT_controller_model-interactive", "[scenario][interactive][no_auto]") + TEST_CASE("XR_MSFT_controller_model-interactive", "[XR_MSFT_controller_model][scenario][interactive][no_auto]") { GlobalData& globalData = GetGlobalData(); 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 92af1df8..b52774ec 100644 --- a/src/conformance/conformance_test/test_XR_VARJO_quad_views.cpp +++ b/src/conformance/conformance_test/test_XR_VARJO_quad_views.cpp @@ -205,8 +205,8 @@ namespace Conformance } // Explicitly naming view config type and ignoring whatever was configured on the command line - CompositionHelper compositionHelper("Quad Views", instance.get(), - XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO_WITH_FOVEATED_INSET); + CompositionHelper compositionHelper("Quad Views", instance.get(), XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO_WITH_FOVEATED_INSET, + true); InteractiveLayerManager interactiveLayerManager(compositionHelper, "projection_separate.png", "Stereo inset views."); XrSession session = compositionHelper.GetSession(); diff --git a/src/conformance/conformance_test/test_actions.cpp b/src/conformance/conformance_test/test_actions.cpp index f4a8a93e..b4540777 100644 --- a/src/conformance/conformance_test/test_actions.cpp +++ b/src/conformance/conformance_test/test_actions.cpp @@ -337,6 +337,10 @@ namespace Conformance satisfied[i] = kInteractionAvailabilities[i].IsSatisfiedBy(features); } } + // cannot copy, cannot move + InteractionAvailabilityEval(InteractionAvailabilityEval&&) = delete; + InteractionAvailabilityEval(const InteractionAvailabilityEval&) = delete; + std::array satisfied{}; }; @@ -603,7 +607,7 @@ namespace Conformance XrInteractionProfileSuggestedBinding bindings{XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING}; bindings.countSuggestedBindings = 1; - + XrActionSuggestedBinding suggestedBindings{}; XrAction boolAction; XrAction floatAction; XrAction vectorAction; @@ -658,7 +662,7 @@ namespace Conformance selectedAction = hapticAction; } - XrActionSuggestedBinding suggestedBindings{selectedAction, StringToPath(instance, pathData.Path)}; + suggestedBindings = XrActionSuggestedBinding{selectedAction, StringToPath(instance, pathData.Path)}; bindings.suggestedBindings = &suggestedBindings; CAPTURE(kInteractionAvailabilities[(size_t)pathData.Availability]); if (SatisfiedByDefault(pathData.Availability)) { @@ -699,6 +703,8 @@ namespace Conformance TEST_CASE("xrSuggestInteractionProfileBindings_interactive", "[actions][interactive]") { CompositionHelper compositionHelper("xrSuggestInteractionProfileBindings"); + XrInstance instance = compositionHelper.GetInstance(); + XrSession session = compositionHelper.GetSession(); compositionHelper.BeginSession(); ActionLayerManager actionLayerManager(compositionHelper); @@ -707,7 +713,7 @@ namespace Conformance XrActionSetCreateInfo actionSetCreateInfo{XR_TYPE_ACTION_SET_CREATE_INFO}; strcpy(actionSetCreateInfo.localizedActionSetName, "test action set localized name"); strcpy(actionSetCreateInfo.actionSetName, "test_action_set_name"); - REQUIRE_RESULT(xrCreateActionSet(compositionHelper.GetInstance(), &actionSetCreateInfo, &actionSet), XR_SUCCESS); + REQUIRE_RESULT(xrCreateActionSet(instance, &actionSetCreateInfo, &actionSet), XR_SUCCESS); XrAction selectActionA{XR_NULL_HANDLE}; XrActionCreateInfo actionCreateInfo{XR_TYPE_ACTION_CREATE_INFO}; @@ -727,28 +733,26 @@ namespace Conformance bool leftUnderTest = GetGlobalData().leftHandUnderTest; const char* pathStr = leftUnderTest ? "/user/hand/left" : "/user/hand/right"; - XrPath path{StringToPath(compositionHelper.GetInstance(), pathStr)}; + XrPath path{StringToPath(instance, pathStr)}; std::shared_ptr inputDevice = - CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), compositionHelper.GetInstance(), - compositionHelper.GetSession(), - StringToPath(compositionHelper.GetInstance(), GetSimpleInteractionProfile().InteractionProfilePathString), - path, GetSimpleInteractionProfile().InputSourcePaths); + CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, + StringToPath(instance, GetSimpleInteractionProfile().InteractionProfilePathString), path, + GetSimpleInteractionProfile().InputSourcePaths); compositionHelper.GetInteractionManager().AddActionSet(actionSet); std::string selectPathStr = std::string(pathStr) + "/input/select/click"; - XrPath selectPath = StringToPath(compositionHelper.GetInstance(), selectPathStr); + XrPath selectPath = StringToPath(instance, selectPathStr); XrActionSuggestedBinding testBinding = {selectActionA, selectPath}; XrInteractionProfileSuggestedBinding bindings{XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING}; - bindings.interactionProfile = StringToPath(compositionHelper.GetInstance(), "/interaction_profiles/khr/simple_controller"); + bindings.interactionProfile = StringToPath(instance, "/interaction_profiles/khr/simple_controller"); bindings.countSuggestedBindings = 1; bindings.suggestedBindings = &testBinding; - REQUIRE_RESULT(xrSuggestInteractionProfileBindings(compositionHelper.GetInstance(), &bindings), XR_SUCCESS); + REQUIRE_RESULT(xrSuggestInteractionProfileBindings(instance, &bindings), XR_SUCCESS); // Calling attach on the interaction manager will call xrSuggestInteractionProfileBindings with the bindings provided here, overwriting the previous bindings compositionHelper.GetInteractionManager().AddActionBindings( - StringToPath(compositionHelper.GetInstance(), GetSimpleInteractionProfile().InteractionProfilePathString), - {{{selectActionB, selectPath}}}); + StringToPath(instance, GetSimpleInteractionProfile().InteractionProfilePathString), {{{selectActionB, selectPath}}}); compositionHelper.GetInteractionManager().AttachActionSets(); actionLayerManager.WaitForSessionFocusWithMessage(); @@ -767,11 +771,11 @@ namespace Conformance // selectActionA should have had its bindings discarded and replaced by selectActionB's bindings getInfo.action = selectActionA; - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &booleanActionState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &booleanActionState), XR_SUCCESS); REQUIRE_FALSE(booleanActionState.isActive); getInfo.action = selectActionB; - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &booleanActionState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &booleanActionState), XR_SUCCESS); REQUIRE(booleanActionState.isActive); } } @@ -1025,6 +1029,8 @@ namespace Conformance auto suggestBindingsAndGetCurrentInteractionProfile = [](bool reverse, bool nullPathExpected, const std::string& topLevelPathString) { CompositionHelper compositionHelper("xrSuggestInteractionProfileBindings_order"); + XrInstance instance = compositionHelper.GetInstance(); + XrSession session = compositionHelper.GetSession(); compositionHelper.BeginSession(); ActionLayerManager actionLayerManager(compositionHelper); @@ -1033,7 +1039,7 @@ namespace Conformance XrActionSetCreateInfo actionSetCreateInfo{XR_TYPE_ACTION_SET_CREATE_INFO}; strcpy(actionSetCreateInfo.localizedActionSetName, "test action set localized name"); strcpy(actionSetCreateInfo.actionSetName, "test_action_set_name"); - REQUIRE_RESULT(xrCreateActionSet(compositionHelper.GetInstance(), &actionSetCreateInfo, &actionSet), XR_SUCCESS); + REQUIRE_RESULT(xrCreateActionSet(instance, &actionSetCreateInfo, &actionSet), XR_SUCCESS); XrAction boolAction{XR_NULL_HANDLE}; XrActionCreateInfo actionCreateInfo{XR_TYPE_ACTION_CREATE_INFO}; @@ -1052,7 +1058,7 @@ namespace Conformance return; } std::string interactionProfileName = interactionProfile.InteractionProfilePathString; - XrPath interactionProfilePath = StringToPath(compositionHelper.GetInstance(), interactionProfileName); + XrPath interactionProfilePath = StringToPath(instance, interactionProfileName); bool bindingSuggested = false; for (auto& bindings : interactionProfile.InputSourcePaths) { @@ -1065,7 +1071,7 @@ namespace Conformance if (!SatisfiedByDefault(bindings.Availability)) { continue; } - XrActionSuggestedBinding binding = {boolAction, StringToPath(compositionHelper.GetInstance(), bindings.Path)}; + XrActionSuggestedBinding binding = {boolAction, StringToPath(instance, bindings.Path)}; interactionManager.AddActionBindings(interactionProfilePath, {binding}); bindingSuggested = true; } @@ -1089,12 +1095,11 @@ namespace Conformance } // Hardcoded path valid for simple controller - XrPath userHandLeftXrPath{StringToPath(compositionHelper.GetInstance(), topLevelPathString)}; + XrPath userHandLeftXrPath{StringToPath(instance, topLevelPathString)}; std::shared_ptr inputDevice = - CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), compositionHelper.GetInstance(), - compositionHelper.GetSession(), - StringToPath(compositionHelper.GetInstance(), GetSimpleInteractionProfile().InteractionProfilePathString), - userHandLeftXrPath, GetSimpleInteractionProfile().InputSourcePaths); + CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, + StringToPath(instance, GetSimpleInteractionProfile().InteractionProfilePathString), userHandLeftXrPath, + GetSimpleInteractionProfile().InputSourcePaths); // This function calls xrSuggestInteractionProfileBindings() before attaching the actionsets interactionManager.AttachActionSets(&interactionProfileOrder); @@ -1103,10 +1108,8 @@ namespace Conformance inputDevice->SetDeviceActive(/*state = */ true, /*skipInteraction = */ false, boolAction, actionSet); actionLayerManager.WaitForSessionFocusWithMessage(); XrInteractionProfileState interactionProfileState{XR_TYPE_INTERACTION_PROFILE_STATE}; - REQUIRE_RESULT( - xrGetCurrentInteractionProfile(compositionHelper.GetSession(), - StringToPath(compositionHelper.GetInstance(), topLevelPathString), &interactionProfileState), - XR_SUCCESS); + REQUIRE_RESULT(xrGetCurrentInteractionProfile(session, StringToPath(instance, topLevelPathString), &interactionProfileState), + XR_SUCCESS); // Are we expecting the topLevelPath to have a active input? if (nullPathExpected) { @@ -1121,7 +1124,7 @@ namespace Conformance REQUIRE(interactionProfileState.interactionProfile != XR_NULL_PATH); // XrPaths are only valid for the lifetime of the instance so we return a string - return PathToString(compositionHelper.GetInstance(), interactionProfileState.interactionProfile); + return PathToString(instance, interactionProfileState.interactionProfile); } }; @@ -1148,18 +1151,19 @@ namespace Conformance TEST_CASE("xrGetCurrentInteractionProfile", "[actions][interactive]") { CompositionHelper compositionHelper("xrGetCurrentInteractionProfile"); + XrInstance instance = compositionHelper.GetInstance(); + XrSession session = compositionHelper.GetSession(); compositionHelper.BeginSession(); ActionLayerManager actionLayerManager(compositionHelper); - XrPath simpleControllerInteractionProfile = - StringToPath(compositionHelper.GetInstance(), GetSimpleInteractionProfile().InteractionProfilePathString); + XrPath simpleControllerInteractionProfile = StringToPath(instance, GetSimpleInteractionProfile().InteractionProfilePathString); XrActionSet actionSet{XR_NULL_HANDLE}; XrActionSetCreateInfo actionSetCreateInfo{XR_TYPE_ACTION_SET_CREATE_INFO}; strcpy(actionSetCreateInfo.localizedActionSetName, "test action set localized name"); strcpy(actionSetCreateInfo.actionSetName, "test_action_set_name"); - REQUIRE_RESULT(xrCreateActionSet(compositionHelper.GetInstance(), &actionSetCreateInfo, &actionSet), XR_SUCCESS); + REQUIRE_RESULT(xrCreateActionSet(instance, &actionSetCreateInfo, &actionSet), XR_SUCCESS); XrAction selectAction{XR_NULL_HANDLE}; XrActionCreateInfo actionCreateInfo{XR_TYPE_ACTION_CREATE_INFO}; @@ -1168,19 +1172,17 @@ namespace Conformance strcpy(actionCreateInfo.actionName, "test_select_action"); REQUIRE_RESULT(xrCreateAction(actionSet, &actionCreateInfo, &selectAction), XR_SUCCESS); - XrPath leftHandPath{StringToPath(compositionHelper.GetInstance(), "/user/hand/left")}; + XrPath leftHandPath{StringToPath(instance, "/user/hand/left")}; std::shared_ptr leftHandInputDevice = - CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), compositionHelper.GetInstance(), - compositionHelper.GetSession(), - StringToPath(compositionHelper.GetInstance(), GetSimpleInteractionProfile().InteractionProfilePathString), - leftHandPath, GetSimpleInteractionProfile().InputSourcePaths); + CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, + StringToPath(instance, GetSimpleInteractionProfile().InteractionProfilePathString), leftHandPath, + GetSimpleInteractionProfile().InputSourcePaths); - XrPath rightHandPath{StringToPath(compositionHelper.GetInstance(), "/user/hand/right")}; + XrPath rightHandPath{StringToPath(instance, "/user/hand/right")}; std::shared_ptr rightHandInputDevice = - CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), compositionHelper.GetInstance(), - compositionHelper.GetSession(), - StringToPath(compositionHelper.GetInstance(), GetSimpleInteractionProfile().InteractionProfilePathString), - rightHandPath, GetSimpleInteractionProfile().InputSourcePaths); + CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, + StringToPath(instance, GetSimpleInteractionProfile().InteractionProfilePathString), rightHandPath, + GetSimpleInteractionProfile().InputSourcePaths); XrActionsSyncInfo syncInfo{XR_TYPE_ACTIONS_SYNC_INFO}; XrActiveActionSet activeActionSet{actionSet}; @@ -1195,9 +1197,9 @@ namespace Conformance compositionHelper.GetInteractionManager().AddActionSet(actionSet); compositionHelper.GetInteractionManager().AddActionBindings( - StringToPath(compositionHelper.GetInstance(), GetSimpleInteractionProfile().InteractionProfilePathString), - {{{selectAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/select/click")}, - {selectAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/select/click")}}}); + StringToPath(instance, GetSimpleInteractionProfile().InteractionProfilePathString), + {{{selectAction, StringToPath(instance, "/user/hand/left/input/select/click")}, + {selectAction, StringToPath(instance, "/user/hand/right/input/select/click")}}}); compositionHelper.GetInteractionManager().AttachActionSets(); { @@ -1205,13 +1207,11 @@ namespace Conformance { INFO("Basic usage"); - REQUIRE_RESULT(xrGetCurrentInteractionProfile(compositionHelper.GetSession(), leftHandPath, &interactionProfileState), - XR_SUCCESS); + REQUIRE_RESULT(xrGetCurrentInteractionProfile(session, leftHandPath, &interactionProfileState), XR_SUCCESS); } { INFO("XR_NULL_PATH topLevelPath"); - REQUIRE_RESULT(xrGetCurrentInteractionProfile(compositionHelper.GetSession(), XR_NULL_PATH, &interactionProfileState), - XR_ERROR_PATH_INVALID); + REQUIRE_RESULT(xrGetCurrentInteractionProfile(session, XR_NULL_PATH, &interactionProfileState), XR_ERROR_PATH_INVALID); } OPTIONAL_INVALID_HANDLE_VALIDATION_INFO { @@ -1222,21 +1222,19 @@ namespace Conformance { INFO("Invalid top level path"); XrPath invalidTopLevelPath = (XrPath)0x1234; - REQUIRE_RESULT( - xrGetCurrentInteractionProfile(compositionHelper.GetSession(), invalidTopLevelPath, &interactionProfileState), - XR_ERROR_PATH_INVALID); + REQUIRE_RESULT(xrGetCurrentInteractionProfile(session, invalidTopLevelPath, &interactionProfileState), + XR_ERROR_PATH_INVALID); } { INFO("Unsupported top level path"); - XrPath unsupportedTopLevelPath = StringToPath(compositionHelper.GetInstance(), "/invalid/top/level/path"); - REQUIRE_RESULT( - xrGetCurrentInteractionProfile(compositionHelper.GetSession(), unsupportedTopLevelPath, &interactionProfileState), - XR_ERROR_PATH_UNSUPPORTED); + XrPath unsupportedTopLevelPath = StringToPath(instance, "/invalid/top/level/path"); + REQUIRE_RESULT(xrGetCurrentInteractionProfile(session, unsupportedTopLevelPath, &interactionProfileState), + XR_ERROR_PATH_UNSUPPORTED); } { INFO("Invalid type"); interactionProfileState = XrInteractionProfileState{XR_TYPE_ACTION_CREATE_INFO}; - REQUIRE_RESULT(xrGetCurrentInteractionProfile(compositionHelper.GetSession(), leftHandPath, &interactionProfileState), + REQUIRE_RESULT(xrGetCurrentInteractionProfile(session, leftHandPath, &interactionProfileState), XR_ERROR_VALIDATION_FAILURE); interactionProfileState = XrInteractionProfileState{XR_TYPE_INTERACTION_PROFILE_STATE}; } @@ -1271,13 +1269,11 @@ namespace Conformance REQUIRE(ReadUntilEvent(XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED, 1s)); if (globalData.leftHandUnderTest) { - REQUIRE_RESULT(xrGetCurrentInteractionProfile(compositionHelper.GetSession(), leftHandPath, &interactionProfileState), - XR_SUCCESS); + REQUIRE_RESULT(xrGetCurrentInteractionProfile(session, leftHandPath, &interactionProfileState), XR_SUCCESS); REQUIRE(simpleControllerInteractionProfile == interactionProfileState.interactionProfile); } if (globalData.rightHandUnderTest) { - REQUIRE_RESULT(xrGetCurrentInteractionProfile(compositionHelper.GetSession(), rightHandPath, &interactionProfileState), - XR_SUCCESS); + REQUIRE_RESULT(xrGetCurrentInteractionProfile(session, rightHandPath, &interactionProfileState), XR_SUCCESS); REQUIRE(simpleControllerInteractionProfile == interactionProfileState.interactionProfile); } } @@ -1291,25 +1287,24 @@ namespace Conformance if (globalData.IsInstanceExtensionSupported(XR_EXT_ACTIVE_ACTION_SET_PRIORITY_EXTENSION_NAME)) extensions.push_back(XR_EXT_ACTIVE_ACTION_SET_PRIORITY_EXTENSION_NAME); CompositionHelper compositionHelper("xrSyncActions", extensions); + XrInstance instance = compositionHelper.GetInstance(); + XrSession session = compositionHelper.GetSession(); ActionLayerManager actionLayerManager(compositionHelper); - XrPath simpleControllerInteractionProfile = - StringToPath(compositionHelper.GetInstance(), GetSimpleInteractionProfile().InteractionProfilePathString); + XrPath simpleControllerInteractionProfile = StringToPath(instance, GetSimpleInteractionProfile().InteractionProfilePathString); std::string leftHandPathString = "/user/hand/left"; - XrPath leftHandPath{StringToPath(compositionHelper.GetInstance(), "/user/hand/left")}; + XrPath leftHandPath{StringToPath(instance, "/user/hand/left")}; std::shared_ptr leftHandInputDevice = - CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), compositionHelper.GetInstance(), - compositionHelper.GetSession(), simpleControllerInteractionProfile, leftHandPath, - GetSimpleInteractionProfile().InputSourcePaths); + CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, + simpleControllerInteractionProfile, leftHandPath, GetSimpleInteractionProfile().InputSourcePaths); std::string rightHandPathString = "/user/hand/right"; - XrPath rightHandPath{StringToPath(compositionHelper.GetInstance(), "/user/hand/right")}; + XrPath rightHandPath{StringToPath(instance, "/user/hand/right")}; std::shared_ptr rightHandInputDevice = - CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), compositionHelper.GetInstance(), - compositionHelper.GetSession(), simpleControllerInteractionProfile, rightHandPath, - GetSimpleInteractionProfile().InputSourcePaths); + CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, + simpleControllerInteractionProfile, rightHandPath, GetSimpleInteractionProfile().InputSourcePaths); bool leftUnderTest = GetGlobalData().leftHandUnderTest; std::string defaultDevicePathStr = leftUnderTest ? leftHandPathString : rightHandPathString; @@ -1320,7 +1315,7 @@ namespace Conformance XrActionSetCreateInfo actionSetCreateInfo{XR_TYPE_ACTION_SET_CREATE_INFO}; strcpy(actionSetCreateInfo.localizedActionSetName, "test action set localized name"); strcpy(actionSetCreateInfo.actionSetName, "test_action_set_name"); - REQUIRE_RESULT(xrCreateActionSet(compositionHelper.GetInstance(), &actionSetCreateInfo, &actionSet), XR_SUCCESS); + REQUIRE_RESULT(xrCreateActionSet(instance, &actionSetCreateInfo, &actionSet), XR_SUCCESS); XrAction action{XR_NULL_HANDLE}; XrActionCreateInfo actionCreateInfo{XR_TYPE_ACTION_CREATE_INFO}; @@ -1346,7 +1341,7 @@ namespace Conformance { INFO("No action sets attached"); - REQUIRE_RESULT_SUCCEEDED(xrSyncActions(compositionHelper.GetSession(), &syncInfo)); + REQUIRE_RESULT_SUCCEEDED(xrSyncActions(session, &syncInfo)); } { INFO("With action sets attached"); @@ -1354,13 +1349,13 @@ namespace Conformance compositionHelper.GetInteractionManager().AddActionSet(actionSet); compositionHelper.GetInteractionManager().AttachActionSets(); - REQUIRE_RESULT_SUCCEEDED(xrSyncActions(compositionHelper.GetSession(), &syncInfo)); + REQUIRE_RESULT_SUCCEEDED(xrSyncActions(session, &syncInfo)); } } SECTION("Active action sets") { XrInteractionProfileState interactionProfileState{XR_TYPE_INTERACTION_PROFILE_STATE}; - REQUIRE_RESULT(xrGetCurrentInteractionProfile(compositionHelper.GetSession(), defaultDevicePath, &interactionProfileState), + REQUIRE_RESULT(xrGetCurrentInteractionProfile(session, defaultDevicePath, &interactionProfileState), XR_ERROR_ACTIONSET_NOT_ATTACHED); compositionHelper.GetInteractionManager().AddActionSet(actionSet); @@ -1368,9 +1363,7 @@ namespace Conformance { INFO("Interaction profile selection changes must: only happen when flink:xrSyncActions is called."); - REQUIRE_RESULT( - xrGetCurrentInteractionProfile(compositionHelper.GetSession(), defaultDevicePath, &interactionProfileState), - XR_SUCCESS); + REQUIRE_RESULT(xrGetCurrentInteractionProfile(session, defaultDevicePath, &interactionProfileState), XR_SUCCESS); // per spec: "Interaction profile selection changes must: only happen when flink:xrSyncActions is called." REQUIRE(interactionProfileState.interactionProfile == XR_NULL_PATH); } @@ -1380,9 +1373,9 @@ namespace Conformance syncInfo.activeActionSets = &activeActionSet; syncInfo.countActiveActionSets = 1; - REQUIRE_RESULT(xrSyncActions(compositionHelper.GetSession(), &syncInfo), XR_SESSION_NOT_FOCUSED); + REQUIRE_RESULT(xrSyncActions(session, &syncInfo), XR_SESSION_NOT_FOCUSED); - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &actionStateBoolean), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &actionStateBoolean), XR_SUCCESS); REQUIRE_FALSE(actionStateBoolean.isActive); } } @@ -1393,7 +1386,7 @@ namespace Conformance SECTION("Parameter validation") { std::string selectPathStr = defaultDevicePathStr + "/input/select/click"; - XrPath selectPath = StringToPath(compositionHelper.GetInstance(), selectPathStr); + XrPath selectPath = StringToPath(instance, selectPathStr); compositionHelper.GetInteractionManager().AddActionSet(actionSet); compositionHelper.GetInteractionManager().AddActionBindings(simpleControllerInteractionProfile, {{action, selectPath}}); compositionHelper.GetInteractionManager().AttachActionSets(); @@ -1415,7 +1408,7 @@ namespace Conformance actionLayerManager.SyncActionsUntilFocusWithMessage(syncInfo); - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &actionStateBoolean), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &actionStateBoolean), XR_SUCCESS); REQUIRE(actionStateBoolean.isActive); REQUIRE_FALSE(actionStateBoolean.currentState); @@ -1426,11 +1419,11 @@ namespace Conformance actionLayerManager.SyncActionsUntilFocusWithMessage(syncInfo); - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &actionStateBoolean), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &actionStateBoolean), XR_SUCCESS); REQUIRE(actionStateBoolean.isActive); REQUIRE(actionStateBoolean.currentState); - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &actionStateBoolean), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &actionStateBoolean), XR_SUCCESS); REQUIRE(actionStateBoolean.isActive); REQUIRE(actionStateBoolean.currentState); } @@ -1443,8 +1436,7 @@ namespace Conformance WaitUntilPredicateWithTimeout( [&]() { actionLayerManager.GetRenderLoop().IterateFrame(); - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &actionStateBoolean), - XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &actionStateBoolean), XR_SUCCESS); REQUIRE(actionStateBoolean.isActive); REQUIRE(actionStateBoolean.currentState); return false; @@ -1458,8 +1450,7 @@ namespace Conformance WaitUntilPredicateWithTimeout( [&]() { actionLayerManager.GetRenderLoop().IterateFrame(); - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &actionStateBoolean), - XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &actionStateBoolean), XR_SUCCESS); REQUIRE_FALSE(actionStateBoolean.isActive); REQUIRE_FALSE(actionStateBoolean.currentState); return false; @@ -1484,7 +1475,7 @@ namespace Conformance strcpy(setCreateInfo.actionSetName, "high_priority_action_set"); strcpy(setCreateInfo.localizedActionSetName, "high priority action set"); setCreateInfo.priority = 3; - REQUIRE_RESULT(xrCreateActionSet(compositionHelper.GetInstance(), &setCreateInfo, &highPriorityActionSet), XR_SUCCESS); + REQUIRE_RESULT(xrCreateActionSet(instance, &setCreateInfo, &highPriorityActionSet), XR_SUCCESS); XrAction highPrioritySelectAction{XR_NULL_HANDLE}; XrAction highPrioritySelectAction2{XR_NULL_HANDLE}; @@ -1504,7 +1495,7 @@ namespace Conformance strcpy(setCreateInfo.actionSetName, "low_priority_action_set"); strcpy(setCreateInfo.localizedActionSetName, "low priority action set"); setCreateInfo.priority = 2; - REQUIRE_RESULT(xrCreateActionSet(compositionHelper.GetInstance(), &setCreateInfo, &lowPriorityActionSet), XR_SUCCESS); + REQUIRE_RESULT(xrCreateActionSet(instance, &setCreateInfo, &lowPriorityActionSet), XR_SUCCESS); XrAction lowPrioritySelectAction{XR_NULL_HANDLE}; XrAction lowPriorityMenuAction{XR_NULL_HANDLE}; @@ -1525,21 +1516,18 @@ namespace Conformance compositionHelper.GetInteractionManager().AddActionBindings( simpleControllerInteractionProfile, { - {highPrioritySelectAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/select/click")}, - {highPrioritySelectAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/select/click")}, - {highPrioritySelectAction2, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/select/click")}, - {highPrioritySelectAction2, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/select/click")}, - {lowPrioritySelectAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/select/click")}, - {lowPrioritySelectAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/select/click")}, - {lowPriorityMenuAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/menu/click")}, - {lowPriorityMenuAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/menu/click")}, - {lowPrioritySelectAndMenuAction, - StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/select/click")}, - {lowPrioritySelectAndMenuAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/menu/click")}, - {lowPrioritySelectAndMenuAction, - StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/select/click")}, - {lowPrioritySelectAndMenuAction, - StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/menu/click")}, + {highPrioritySelectAction, StringToPath(instance, "/user/hand/left/input/select/click")}, + {highPrioritySelectAction, StringToPath(instance, "/user/hand/right/input/select/click")}, + {highPrioritySelectAction2, StringToPath(instance, "/user/hand/left/input/select/click")}, + {highPrioritySelectAction2, StringToPath(instance, "/user/hand/right/input/select/click")}, + {lowPrioritySelectAction, StringToPath(instance, "/user/hand/left/input/select/click")}, + {lowPrioritySelectAction, StringToPath(instance, "/user/hand/right/input/select/click")}, + {lowPriorityMenuAction, StringToPath(instance, "/user/hand/left/input/menu/click")}, + {lowPriorityMenuAction, StringToPath(instance, "/user/hand/right/input/menu/click")}, + {lowPrioritySelectAndMenuAction, StringToPath(instance, "/user/hand/left/input/select/click")}, + {lowPrioritySelectAndMenuAction, StringToPath(instance, "/user/hand/left/input/menu/click")}, + {lowPrioritySelectAndMenuAction, StringToPath(instance, "/user/hand/right/input/select/click")}, + {lowPrioritySelectAndMenuAction, StringToPath(instance, "/user/hand/right/input/menu/click")}, }); compositionHelper.GetInteractionManager().AddActionSet(highPriorityActionSet); @@ -1563,7 +1551,7 @@ namespace Conformance getInfo.action = action; getInfo.subactionPath = subactionPath; XrActionStateBoolean booleanData{XR_TYPE_ACTION_STATE_BOOLEAN}; - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &booleanData), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &booleanData), XR_SUCCESS); return static_cast(booleanData.isActive); }; @@ -1820,14 +1808,12 @@ namespace Conformance XrActionSet subactionPathFreeActionSet{XR_NULL_HANDLE}; strcpy(actionSetCreateInfo.localizedActionSetName, "test action set localized name 2"); strcpy(actionSetCreateInfo.actionSetName, "test_action_set_name_2"); - REQUIRE_RESULT(xrCreateActionSet(compositionHelper.GetInstance(), &actionSetCreateInfo, &subactionPathFreeActionSet), - XR_SUCCESS); + REQUIRE_RESULT(xrCreateActionSet(instance, &actionSetCreateInfo, &subactionPathFreeActionSet), XR_SUCCESS); XrActionSet unboundActionActionSet{XR_NULL_HANDLE}; strcpy(actionSetCreateInfo.localizedActionSetName, "test action set localized name 5"); strcpy(actionSetCreateInfo.actionSetName, "test_action_set_name_5"); - REQUIRE_RESULT(xrCreateActionSet(compositionHelper.GetInstance(), &actionSetCreateInfo, &unboundActionActionSet), - XR_SUCCESS); + REQUIRE_RESULT(xrCreateActionSet(instance, &actionSetCreateInfo, &unboundActionActionSet), XR_SUCCESS); XrAction leftHandAction{XR_NULL_HANDLE}; actionCreateInfo.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT; @@ -1850,9 +1836,8 @@ namespace Conformance REQUIRE_RESULT(xrCreateAction(unboundActionActionSet, &actionCreateInfo, &unboundAction), XR_SUCCESS); compositionHelper.GetInteractionManager().AddActionBindings( - simpleControllerInteractionProfile, - {{leftHandAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/select/click")}, - {rightHandAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/select/click")}}); + simpleControllerInteractionProfile, {{leftHandAction, StringToPath(instance, "/user/hand/left/input/select/click")}, + {rightHandAction, StringToPath(instance, "/user/hand/right/input/select/click")}}); compositionHelper.GetInteractionManager().AddActionSet(actionSet); compositionHelper.GetInteractionManager().AddActionSet(subactionPathFreeActionSet); compositionHelper.GetInteractionManager().AddActionSet(unboundActionActionSet); @@ -1882,18 +1867,17 @@ namespace Conformance actionLayerManager.SyncActionsUntilFocusWithMessage(syncInfo); getInfo.action = leftHandAction; - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &actionStateBoolean), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &actionStateBoolean), XR_SUCCESS); REQUIRE(actionStateBoolean.isActive); getInfo.action = rightHandAction; - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &actionStateBoolean), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &actionStateBoolean), XR_SUCCESS); REQUIRE_FALSE(actionStateBoolean.isActive); { INFO("Values match those specified for isActive == XR_FALSE"); // Set these to the wrong thing if not active, to make sure runtime overwrites the values PoisonStructContents(actionStateBoolean); - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &actionStateBoolean), - XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &actionStateBoolean), XR_SUCCESS); REQUIRE_FALSE(actionStateBoolean.isActive); // The conformance layer will verify that the other fields have been cleared appropriately. } @@ -1905,19 +1889,18 @@ namespace Conformance actionLayerManager.SyncActionsUntilFocusWithMessage(syncInfo); getInfo.action = leftHandAction; - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &actionStateBoolean), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &actionStateBoolean), XR_SUCCESS); REQUIRE_FALSE(actionStateBoolean.isActive); getInfo.action = rightHandAction; - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &actionStateBoolean), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &actionStateBoolean), XR_SUCCESS); REQUIRE(actionStateBoolean.isActive); # { INFO("Values match those specified for isActive == XR_FALSE"); // Set these to the wrong thing if not active, to make sure runtime overwrites the values PoisonStructContents(actionStateBoolean); - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &actionStateBoolean), - XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &actionStateBoolean), XR_SUCCESS); REQUIRE(actionStateBoolean.isActive); // The conformance layer will verify that the other fields have been cleared appropriately. } @@ -1933,11 +1916,11 @@ namespace Conformance actionLayerManager.SyncActionsUntilFocusWithMessage(syncInfo); getInfo.action = leftHandAction; - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &actionStateBoolean), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &actionStateBoolean), XR_SUCCESS); REQUIRE(actionStateBoolean.isActive); getInfo.action = rightHandAction; - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &actionStateBoolean), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &actionStateBoolean), XR_SUCCESS); REQUIRE(actionStateBoolean.isActive); } @@ -1952,13 +1935,12 @@ namespace Conformance INFO("Subaction path used but not declared"); subactionPathFreeActiveActionSet.subactionPath = defaultDevicePath; - REQUIRE_RESULT(xrSyncActions(compositionHelper.GetSession(), &syncInfo), XR_ERROR_PATH_UNSUPPORTED); + REQUIRE_RESULT(xrSyncActions(session, &syncInfo), XR_ERROR_PATH_UNSUPPORTED); XrActionSet unattachedActionSet{XR_NULL_HANDLE}; strcpy(actionSetCreateInfo.localizedActionSetName, "test action set localized name 3"); strcpy(actionSetCreateInfo.actionSetName, "test_action_set_name_3"); - REQUIRE_RESULT(xrCreateActionSet(compositionHelper.GetInstance(), &actionSetCreateInfo, &unattachedActionSet), - XR_SUCCESS); + REQUIRE_RESULT(xrCreateActionSet(instance, &actionSetCreateInfo, &unattachedActionSet), XR_SUCCESS); INFO("Unbound action"); syncInfo.activeActionSets = &unboundActionActiveActionSet; @@ -1969,19 +1951,19 @@ namespace Conformance XrActiveActionSet activeActionSet2 = {unattachedActionSet}; syncInfo.countActiveActionSets = 1; syncInfo.activeActionSets = &activeActionSet2; - REQUIRE_RESULT(xrSyncActions(compositionHelper.GetSession(), &syncInfo), XR_ERROR_ACTIONSET_NOT_ATTACHED); + REQUIRE_RESULT(xrSyncActions(session, &syncInfo), XR_ERROR_ACTIONSET_NOT_ATTACHED); XrActiveActionSet bothSets[2] = {{actionSet}, {unattachedActionSet}}; syncInfo.countActiveActionSets = 2; syncInfo.activeActionSets = bothSets; - REQUIRE_RESULT(xrSyncActions(compositionHelper.GetSession(), &syncInfo), XR_ERROR_ACTIONSET_NOT_ATTACHED); + REQUIRE_RESULT(xrSyncActions(session, &syncInfo), XR_ERROR_ACTIONSET_NOT_ATTACHED); } { INFO("Invalid subaction path"); syncInfo.countActiveActionSets = 1; syncInfo.activeActionSets = &activeActionSet; activeActionSet.subactionPath = (XrPath)0x1234; - REQUIRE_RESULT(xrSyncActions(compositionHelper.GetSession(), &syncInfo), XR_ERROR_PATH_INVALID); + REQUIRE_RESULT(xrSyncActions(session, &syncInfo), XR_ERROR_PATH_INVALID); } } } @@ -2005,16 +1987,18 @@ namespace Conformance auto TestInteractionProfile = [&](const InteractionProfileAvailMetadata& ipMetadata, const std::string& topLevelPathString) { CompositionHelper compositionHelper("Input device state query"); + XrInstance instance = compositionHelper.GetInstance(); + XrSession session = compositionHelper.GetSession(); compositionHelper.BeginSession(); ActionLayerManager actionLayerManager(compositionHelper); actionLayerManager.WaitForSessionFocusWithMessage(); - XrPath interactionProfile = StringToPath(compositionHelper.GetInstance(), ipMetadata.InteractionProfilePathString); - XrPath inputDevicePath{StringToPath(compositionHelper.GetInstance(), topLevelPathString.data())}; + XrPath interactionProfile = StringToPath(instance, ipMetadata.InteractionProfilePathString); + XrPath inputDevicePath{StringToPath(instance, topLevelPathString.data())}; std::shared_ptr inputDevice = - CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), compositionHelper.GetInstance(), - compositionHelper.GetSession(), interactionProfile, inputDevicePath, ipMetadata.InputSourcePaths); + CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, interactionProfile, + inputDevicePath, ipMetadata.InputSourcePaths); XrActionSet actionSet{XR_NULL_HANDLE}; @@ -2024,7 +2008,7 @@ namespace Conformance XrActionSetCreateInfo actionSetCreateInfo{XR_TYPE_ACTION_SET_CREATE_INFO}; strcpy(actionSetCreateInfo.localizedActionSetName, localizedActionSetName.c_str()); strcpy(actionSetCreateInfo.actionSetName, actionSetName.c_str()); - REQUIRE_RESULT(xrCreateActionSet(compositionHelper.GetInstance(), &actionSetCreateInfo, &actionSet), XR_SUCCESS); + REQUIRE_RESULT(xrCreateActionSet(instance, &actionSetCreateInfo, &actionSet), XR_SUCCESS); uint32_t uniqueActionNameCounter = 0; auto GetActionNames = [&uniqueActionNameCounter]() mutable -> std::tuple { @@ -2094,7 +2078,7 @@ namespace Conformance strcpy(actionCreateInfo.actionName, std::get<0>(actionNames).c_str()); REQUIRE_RESULT(xrCreateAction(actionSet, &actionCreateInfo, &action), XR_SUCCESS); - XrPath bindingPath = StringToPath(compositionHelper.GetInstance(), inputSourceData.Path); + XrPath bindingPath = StringToPath(instance, inputSourceData.Path); compositionHelper.GetInteractionManager().AddActionBindings(interactionProfile, {{action, bindingPath}}); ActionInfo info{}; @@ -2139,7 +2123,7 @@ namespace Conformance REQUIRE_RESULT(xrCreateAction(actionSet, &actionCreateInfo, &xAction), XR_SUCCESS); std::string xSubBindingPath = std::string(inputSourceData.Path) + "/x"; - bindingPath = StringToPath(compositionHelper.GetInstance(), xSubBindingPath); + bindingPath = StringToPath(instance, xSubBindingPath); compositionHelper.GetInteractionManager().AddActionBindings(interactionProfile, {{xAction, bindingPath}}); actionNames = GetActionNames(); @@ -2148,7 +2132,7 @@ namespace Conformance REQUIRE_RESULT(xrCreateAction(actionSet, &actionCreateInfo, &yAction), XR_SUCCESS); std::string ySubBindingPath = std::string(inputSourceData.Path) + "/y"; - bindingPath = StringToPath(compositionHelper.GetInstance(), ySubBindingPath); + bindingPath = StringToPath(instance, ySubBindingPath); compositionHelper.GetInteractionManager().AddActionBindings(interactionProfile, {{yAction, bindingPath}}); break; } @@ -2237,7 +2221,7 @@ namespace Conformance strcpy(actionCreateInfo.actionName, std::get<0>(actionNames).c_str()); REQUIRE_RESULT(xrCreateAction(actionSet, &actionCreateInfo, &action), XR_SUCCESS); - XrPath bindingPath = StringToPath(compositionHelper.GetInstance(), inputSourceData.Path); + XrPath bindingPath = StringToPath(instance, inputSourceData.Path); compositionHelper.GetInteractionManager().AddActionBindings(interactionProfile, {{action, bindingPath}}); ActionInfo info{}; @@ -2268,7 +2252,7 @@ namespace Conformance continue; } - XrPath bindingPath = StringToPath(compositionHelper.GetInstance(), inputSourceData.Path); + XrPath bindingPath = StringToPath(instance, inputSourceData.Path); compositionHelper.GetInteractionManager().AddActionBindings(interactionProfile, {{action, bindingPath}}); } @@ -2323,8 +2307,7 @@ namespace Conformance actionLayerManager.SyncActionsUntilFocusWithMessage(syncInfo); XrInteractionProfileState interactionProfileState{XR_TYPE_INTERACTION_PROFILE_STATE}; - REQUIRE_RESULT(xrGetCurrentInteractionProfile(compositionHelper.GetSession(), inputDevicePath, &interactionProfileState), - XR_SUCCESS); + REQUIRE_RESULT(xrGetCurrentInteractionProfile(session, inputDevicePath, &interactionProfileState), XR_SUCCESS); REQUIRE(interactionProfile == interactionProfileState.interactionProfile); XrActionStateBoolean booleanState{XR_TYPE_ACTION_STATE_BOOLEAN}; @@ -2350,11 +2333,11 @@ namespace Conformance XrActionStateVector2f previousVectorState{XR_TYPE_ACTION_STATE_VECTOR2F}; getInfo.action = allBooleanAction.Action; - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &previousBoolState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &previousBoolState), XR_SUCCESS); getInfo.action = allFloatAction.Action; - REQUIRE_RESULT(xrGetActionStateFloat(compositionHelper.GetSession(), &getInfo, &previousFloatState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateFloat(session, &getInfo, &previousFloatState), XR_SUCCESS); getInfo.action = allVectorAction.Action; - REQUIRE_RESULT(xrGetActionStateVector2f(compositionHelper.GetSession(), &getInfo, &previousVectorState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateVector2f(session, &getInfo, &previousVectorState), XR_SUCCESS); // Synthetic values for automation (these loop around by cStepSize in x then y order). float synthesizedX = 0.f; @@ -2377,12 +2360,11 @@ namespace Conformance actionLayerManager.SyncActionsUntilFocusWithMessage(syncInfo); getInfo.action = allBooleanAction.Action; - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &combinedBoolState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &combinedBoolState), XR_SUCCESS); getInfo.action = allFloatAction.Action; - REQUIRE_RESULT(xrGetActionStateFloat(compositionHelper.GetSession(), &getInfo, &combinedFloatState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateFloat(session, &getInfo, &combinedFloatState), XR_SUCCESS); getInfo.action = allVectorAction.Action; - REQUIRE_RESULT(xrGetActionStateVector2f(compositionHelper.GetSession(), &getInfo, &combinedVectorState), - XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateVector2f(session, &getInfo, &combinedVectorState), XR_SUCCESS); REQUIRE((bool)combinedBoolState.isActive == (booleanActions.size() > 0)); REQUIRE((bool)combinedFloatState.isActive == (floatActions.size() > 0)); @@ -2465,7 +2447,7 @@ namespace Conformance for (auto& actionInfo : booleanActions) { getInfo.action = actionInfo.Action; - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &booleanState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &booleanState), XR_SUCCESS); if (booleanState.isActive) { auto key = int32_t(booleanState.currentState); update(key, actionInfo); @@ -2478,7 +2460,7 @@ namespace Conformance for (auto& actionInfo : floatActions) { getInfo.action = actionInfo.Action; - REQUIRE_RESULT(xrGetActionStateFloat(compositionHelper.GetSession(), &getInfo, &floatState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateFloat(session, &getInfo, &floatState), XR_SUCCESS); if (floatState.isActive) { auto key = int32_t(std::roundf(floatState.currentState / cStepSize)); update(key, actionInfo); @@ -2492,7 +2474,7 @@ namespace Conformance for (auto& actionInfo : vectorActions) { getInfo.action = actionInfo.Action; - REQUIRE_RESULT(xrGetActionStateVector2f(compositionHelper.GetSession(), &getInfo, &vectorState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateVector2f(session, &getInfo, &vectorState), XR_SUCCESS); if (vectorState.isActive) { auto i = int32_t(std::roundf(vectorState.currentState.x / cStepSize)) + cStepSizeOffset; auto j = int32_t(std::roundf(vectorState.currentState.y / cStepSize)) + cStepSizeOffset; @@ -2509,7 +2491,7 @@ namespace Conformance // Verify the x action matches the parent vector. getInfo.action = actionInfo.XAction; - REQUIRE_RESULT(xrGetActionStateFloat(compositionHelper.GetSession(), &getInfo, &floatState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateFloat(session, &getInfo, &floatState), XR_SUCCESS); REQUIRE(floatState.isActive); REQUIRE(floatState.currentState == vectorState.currentState.x); ++combinedFloatCount; @@ -2529,7 +2511,7 @@ namespace Conformance // Verify the y action matches the parent vector. getInfo.action = actionInfo.YAction; - REQUIRE_RESULT(xrGetActionStateFloat(compositionHelper.GetSession(), &getInfo, &floatState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateFloat(session, &getInfo, &floatState), XR_SUCCESS); REQUIRE(floatState.isActive); REQUIRE(floatState.currentState == vectorState.currentState.y); ++combinedFloatCount; @@ -2601,20 +2583,17 @@ namespace Conformance } } for (const auto& actionInfo : booleanActions) { - inputDevice->SetButtonStateBool(StringToPath(compositionHelper.GetInstance(), actionInfo.Data.Path), - synthesizedX > 0.5f, true); + inputDevice->SetButtonStateBool(StringToPath(instance, actionInfo.Data.Path), synthesizedX > 0.5f, true); } for (const auto& actionInfo : floatActions) { - inputDevice->SetButtonStateFloat(StringToPath(compositionHelper.GetInstance(), actionInfo.Data.Path), - synthesizedX, 0, true); + inputDevice->SetButtonStateFloat(StringToPath(instance, actionInfo.Data.Path), synthesizedX, 0, true); } for (const auto& actionInfo : vectorActions) { float x = (synthesizedX - 0.5f) * 2.f; float y = (synthesizedY - 0.5f) * 2.f; - inputDevice->SetButtonStateVector2(StringToPath(compositionHelper.GetInstance(), actionInfo.Data.Path), - {x, y}, 0, true); + inputDevice->SetButtonStateVector2(StringToPath(instance, actionInfo.Data.Path), {x, y}, 0, true); } } @@ -2664,19 +2643,19 @@ namespace Conformance getInfo.action = poseActionData.Action; actionLayerManager.SyncActionsUntilFocusWithMessage(syncInfo); - REQUIRE_RESULT(xrGetActionStatePose(compositionHelper.GetSession(), &getInfo, &poseState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStatePose(session, &getInfo, &poseState), XR_SUCCESS); REQUIRE(poseState.isActive); inputDevice->SetDeviceActive(false); actionLayerManager.SyncActionsUntilFocusWithMessage(syncInfo); - REQUIRE_RESULT(xrGetActionStatePose(compositionHelper.GetSession(), &getInfo, &poseState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStatePose(session, &getInfo, &poseState), XR_SUCCESS); REQUIRE_FALSE(poseState.isActive); inputDevice->SetDeviceActive(true); actionLayerManager.SyncActionsUntilFocusWithMessage(syncInfo); - REQUIRE_RESULT(xrGetActionStatePose(compositionHelper.GetSession(), &getInfo, &poseState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStatePose(session, &getInfo, &poseState), XR_SUCCESS); REQUIRE(poseState.isActive); } } @@ -2688,7 +2667,7 @@ namespace Conformance for (const auto& hapticActionData : hapticActions) { CAPTURE(hapticActionData.Data.Path); - XrPath inputSourcePath = StringToPath(compositionHelper.GetInstance(), booleanActions[0].Data.Path); + XrPath inputSourcePath = StringToPath(instance, booleanActions[0].Data.Path); XrHapticActionInfo hapticActionInfo{XR_TYPE_HAPTIC_ACTION_INFO}; hapticActionInfo.action = hapticActionData.Action; @@ -2705,8 +2684,7 @@ namespace Conformance actionLayerManager.SyncActionsUntilFocusWithMessage(syncInfo); for (const auto& booleanActionData : booleanActions) { getInfo.action = booleanActionData.Action; - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &booleanState), - XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &booleanState), XR_SUCCESS); if (booleanState.changedSinceLastSync && booleanState.currentState) { currentBooleanAction = booleanActionData.Action; return true; @@ -2720,9 +2698,9 @@ namespace Conformance actionLayerManager.Sleep_For(3s); hapticPacket.duration = std::chrono::duration_cast(3s).count(); - REQUIRE_RESULT(xrApplyHapticFeedback(compositionHelper.GetSession(), &hapticActionInfo, - reinterpret_cast(&hapticPacket)), - XR_SUCCESS); + REQUIRE_RESULT( + xrApplyHapticFeedback(session, &hapticActionInfo, reinterpret_cast(&hapticPacket)), + XR_SUCCESS); { // For automation only @@ -2744,16 +2722,16 @@ namespace Conformance inputDevice->SetButtonStateBool(inputSourcePath, false, true); } - REQUIRE_RESULT(xrStopHapticFeedback(compositionHelper.GetSession(), &hapticActionInfo), XR_SUCCESS); + REQUIRE_RESULT(xrStopHapticFeedback(session, &hapticActionInfo), XR_SUCCESS); actionLayerManager.DisplayMessage("Press any button when you feel the short haptic pulse"); actionLayerManager.IterateFrame(); actionLayerManager.Sleep_For(3s); hapticPacket.duration = XR_MIN_HAPTIC_DURATION; - REQUIRE_RESULT(xrApplyHapticFeedback(compositionHelper.GetSession(), &hapticActionInfo, - reinterpret_cast(&hapticPacket)), - XR_SUCCESS); + REQUIRE_RESULT( + xrApplyHapticFeedback(session, &hapticActionInfo, reinterpret_cast(&hapticPacket)), + XR_SUCCESS); { inputDevice->SetButtonStateBool(inputSourcePath, false, true); @@ -2785,27 +2763,27 @@ namespace Conformance INFO("Boolean->Float"); for (const auto& booleanToFloatActionData : floatActionsCoercedToBoolean) { CAPTURE(booleanToFloatActionData.Data.Path); - XrPath inputSourcePath = StringToPath(compositionHelper.GetInstance(), booleanToFloatActionData.Data.Path); + XrPath inputSourcePath = 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); - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &booleanState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &booleanState), XR_SUCCESS); REQUIRE(booleanState.isActive); REQUIRE_FALSE(booleanState.currentState); inputDevice->SetButtonStateFloat(inputSourcePath, 1.0f, cEpsilon, false, actionSet); - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &booleanState), XR_SUCCESS); + 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); - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &booleanState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &booleanState), XR_SUCCESS); REQUIRE(booleanState.isActive); REQUIRE_FALSE(booleanState.currentState); REQUIRE(booleanState.lastChangeTime > 0); @@ -2814,27 +2792,27 @@ namespace Conformance INFO("Float->Boolean"); for (const auto& floatToBooleanActionData : booleanActionsCoercedToFloat) { CAPTURE(floatToBooleanActionData.Data.Path); - XrPath inputSourcePath = StringToPath(compositionHelper.GetInstance(), floatToBooleanActionData.Data.Path); + XrPath inputSourcePath = StringToPath(instance, floatToBooleanActionData.Data.Path); XrActionStateGetInfo getInfo{XR_TYPE_ACTION_STATE_GET_INFO}; getInfo.action = floatToBooleanActionData.Action; inputDevice->SetButtonStateBool(inputSourcePath, false, false, actionSet); - REQUIRE_RESULT(xrGetActionStateFloat(compositionHelper.GetSession(), &getInfo, &floatState), XR_SUCCESS); + 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); - REQUIRE_RESULT(xrGetActionStateFloat(compositionHelper.GetSession(), &getInfo, &floatState), XR_SUCCESS); + 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); - REQUIRE_RESULT(xrGetActionStateFloat(compositionHelper.GetSession(), &getInfo, &floatState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateFloat(session, &getInfo, &floatState), XR_SUCCESS); REQUIRE(floatState.isActive); REQUIRE(floatState.currentState == Catch::Approx(0.0f).margin(cLargeEpsilon)); REQUIRE(floatState.lastChangeTime > 0); @@ -2849,22 +2827,22 @@ namespace Conformance if (actionData.Data.Type == XR_ACTION_TYPE_BOOLEAN_INPUT) { XrActionStateBoolean state{XR_TYPE_ACTION_STATE_BOOLEAN}; - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &state), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &state), XR_SUCCESS); REQUIRE_FALSE(state.isActive); } else if (actionData.Data.Type == XR_ACTION_TYPE_FLOAT_INPUT) { XrActionStateFloat state{XR_TYPE_ACTION_STATE_FLOAT}; - REQUIRE_RESULT(xrGetActionStateFloat(compositionHelper.GetSession(), &getInfo, &state), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateFloat(session, &getInfo, &state), XR_SUCCESS); REQUIRE_FALSE(state.isActive); } else if (actionData.Data.Type == XR_ACTION_TYPE_VECTOR2F_INPUT) { XrActionStateVector2f state{XR_TYPE_ACTION_STATE_VECTOR2F}; - REQUIRE_RESULT(xrGetActionStateVector2f(compositionHelper.GetSession(), &getInfo, &state), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateVector2f(session, &getInfo, &state), XR_SUCCESS); REQUIRE_FALSE(state.isActive); } else if (actionData.Data.Type == XR_ACTION_TYPE_POSE_INPUT) { XrActionStatePose state{XR_TYPE_ACTION_STATE_POSE}; - REQUIRE_RESULT(xrGetActionStatePose(compositionHelper.GetSession(), &getInfo, &state), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStatePose(session, &getInfo, &state), XR_SUCCESS); REQUIRE_FALSE(state.isActive); } } @@ -2892,16 +2870,18 @@ namespace Conformance TEST_CASE("StateQueryFunctionsAndHaptics", "[actions]") { CompositionHelper compositionHelper("Input device state query"); + XrInstance instance = compositionHelper.GetInstance(); + XrSession session = compositionHelper.GetSession(); XrActionSet actionSet{XR_NULL_HANDLE}; XrActionSetCreateInfo actionSetCreateInfo{XR_TYPE_ACTION_SET_CREATE_INFO}; strcpy(actionSetCreateInfo.localizedActionSetName, "test action set localized name"); strcpy(actionSetCreateInfo.actionSetName, "test_action_set_name"); - REQUIRE_RESULT(xrCreateActionSet(compositionHelper.GetInstance(), &actionSetCreateInfo, &actionSet), XR_SUCCESS); + REQUIRE_RESULT(xrCreateActionSet(instance, &actionSetCreateInfo, &actionSet), XR_SUCCESS); - XrPath leftHandPath = StringToPath(compositionHelper.GetInstance(), "/user/hand/left"); - XrPath rightHandPath = StringToPath(compositionHelper.GetInstance(), "/user/hand/right"); - XrPath gamepadPath = StringToPath(compositionHelper.GetInstance(), "/user/gamepad"); + XrPath leftHandPath = StringToPath(instance, "/user/hand/left"); + XrPath rightHandPath = StringToPath(instance, "/user/hand/right"); + XrPath gamepadPath = StringToPath(instance, "/user/gamepad"); XrPath bothHands[] = {leftHandPath, rightHandPath}; XrAction booleanAction{XR_NULL_HANDLE}; @@ -2954,13 +2934,12 @@ namespace Conformance ActionLayerManager actionLayerManager(compositionHelper); actionLayerManager.WaitForSessionFocusWithMessage(); - XrPath simpleControllerInteractionProfile = - StringToPath(compositionHelper.GetInstance(), GetSimpleInteractionProfile().InteractionProfilePathString); + XrPath simpleControllerInteractionProfile = StringToPath(instance, GetSimpleInteractionProfile().InteractionProfilePathString); - XrPath leftHandSelectClickPath = StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/select/click"); - XrPath rightHandSelectClickPath = StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/select/click"); - XrPath leftHandMenuClickPath = StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/menu/click"); - XrPath rightHandMenuClickPath = StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/menu/click"); + XrPath leftHandSelectClickPath = StringToPath(instance, "/user/hand/left/input/select/click"); + XrPath rightHandSelectClickPath = StringToPath(instance, "/user/hand/right/input/select/click"); + XrPath leftHandMenuClickPath = StringToPath(instance, "/user/hand/left/input/menu/click"); + XrPath rightHandMenuClickPath = StringToPath(instance, "/user/hand/right/input/menu/click"); compositionHelper.GetInteractionManager().AddActionSet(actionSet); compositionHelper.GetInteractionManager().AddActionBindings(simpleControllerInteractionProfile, @@ -2991,16 +2970,16 @@ namespace Conformance SECTION("Basic usage") { getInfo.action = booleanAction; - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &booleanState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &booleanState), XR_SUCCESS); getInfo.action = floatAction; - REQUIRE_RESULT(xrGetActionStateFloat(compositionHelper.GetSession(), &getInfo, &floatState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateFloat(session, &getInfo, &floatState), XR_SUCCESS); getInfo.action = vectorAction; - REQUIRE_RESULT(xrGetActionStateVector2f(compositionHelper.GetSession(), &getInfo, &vectorState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStateVector2f(session, &getInfo, &vectorState), XR_SUCCESS); getInfo.action = poseAction; - REQUIRE_RESULT(xrGetActionStatePose(compositionHelper.GetSession(), &getInfo, &poseState), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStatePose(session, &getInfo, &poseState), XR_SUCCESS); } OPTIONAL_INVALID_HANDLE_VALIDATION_SECTION { @@ -3020,143 +2999,116 @@ namespace Conformance getInfo.action = poseAction; REQUIRE_RESULT(xrGetActionStatePose(invalidSession, &getInfo, &poseState), XR_ERROR_HANDLE_INVALID); - REQUIRE_RESULT(xrApplyHapticFeedback(compositionHelper.GetSession(), &hapticActionInfo, - reinterpret_cast(&hapticPacket)), - XR_SUCCESS); - REQUIRE_RESULT(xrStopHapticFeedback(compositionHelper.GetSession(), &hapticActionInfo), XR_SUCCESS); + REQUIRE_RESULT( + xrApplyHapticFeedback(session, &hapticActionInfo, reinterpret_cast(&hapticPacket)), + XR_SUCCESS); + REQUIRE_RESULT(xrStopHapticFeedback(session, &hapticActionInfo), XR_SUCCESS); } SECTION("Invalid action") { getInfo.action = (XrAction)0x1234; - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &booleanState), - XR_ERROR_HANDLE_INVALID); - REQUIRE_RESULT(xrGetActionStateFloat(compositionHelper.GetSession(), &getInfo, &floatState), - XR_ERROR_HANDLE_INVALID); - REQUIRE_RESULT(xrGetActionStateVector2f(compositionHelper.GetSession(), &getInfo, &vectorState), - XR_ERROR_HANDLE_INVALID); - REQUIRE_RESULT(xrGetActionStatePose(compositionHelper.GetSession(), &getInfo, &poseState), XR_ERROR_HANDLE_INVALID); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &booleanState), XR_ERROR_HANDLE_INVALID); + REQUIRE_RESULT(xrGetActionStateFloat(session, &getInfo, &floatState), XR_ERROR_HANDLE_INVALID); + REQUIRE_RESULT(xrGetActionStateVector2f(session, &getInfo, &vectorState), XR_ERROR_HANDLE_INVALID); + REQUIRE_RESULT(xrGetActionStatePose(session, &getInfo, &poseState), XR_ERROR_HANDLE_INVALID); hapticActionInfo.action = getInfo.action; - REQUIRE_RESULT(xrApplyHapticFeedback(compositionHelper.GetSession(), &hapticActionInfo, - reinterpret_cast(&hapticPacket)), - XR_ERROR_HANDLE_INVALID); - REQUIRE_RESULT(xrStopHapticFeedback(compositionHelper.GetSession(), &hapticActionInfo), XR_ERROR_HANDLE_INVALID); + REQUIRE_RESULT( + xrApplyHapticFeedback(session, &hapticActionInfo, reinterpret_cast(&hapticPacket)), + XR_ERROR_HANDLE_INVALID); + REQUIRE_RESULT(xrStopHapticFeedback(session, &hapticActionInfo), XR_ERROR_HANDLE_INVALID); } } SECTION("Invalid subaction path") { getInfo.subactionPath = (XrPath)0x1234; getInfo.action = booleanAction; - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &booleanState), XR_ERROR_PATH_INVALID); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &booleanState), XR_ERROR_PATH_INVALID); getInfo.action = floatAction; - REQUIRE_RESULT(xrGetActionStateFloat(compositionHelper.GetSession(), &getInfo, &floatState), XR_ERROR_PATH_INVALID); + REQUIRE_RESULT(xrGetActionStateFloat(session, &getInfo, &floatState), XR_ERROR_PATH_INVALID); getInfo.action = vectorAction; - REQUIRE_RESULT(xrGetActionStateVector2f(compositionHelper.GetSession(), &getInfo, &vectorState), XR_ERROR_PATH_INVALID); + REQUIRE_RESULT(xrGetActionStateVector2f(session, &getInfo, &vectorState), XR_ERROR_PATH_INVALID); getInfo.action = poseAction; - REQUIRE_RESULT(xrGetActionStatePose(compositionHelper.GetSession(), &getInfo, &poseState), XR_ERROR_PATH_INVALID); + REQUIRE_RESULT(xrGetActionStatePose(session, &getInfo, &poseState), XR_ERROR_PATH_INVALID); hapticActionInfo.subactionPath = getInfo.subactionPath; - REQUIRE_RESULT(xrApplyHapticFeedback(compositionHelper.GetSession(), &hapticActionInfo, - reinterpret_cast(&hapticPacket)), + REQUIRE_RESULT(xrApplyHapticFeedback(session, &hapticActionInfo, reinterpret_cast(&hapticPacket)), XR_ERROR_PATH_INVALID); - REQUIRE_RESULT(xrStopHapticFeedback(compositionHelper.GetSession(), &hapticActionInfo), XR_ERROR_PATH_INVALID); + REQUIRE_RESULT(xrStopHapticFeedback(session, &hapticActionInfo), XR_ERROR_PATH_INVALID); } SECTION("Unspecified subaction path") { getInfo.subactionPath = gamepadPath; getInfo.action = booleanAction; - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &booleanState), - XR_ERROR_PATH_UNSUPPORTED); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &booleanState), XR_ERROR_PATH_UNSUPPORTED); getInfo.action = floatAction; - REQUIRE_RESULT(xrGetActionStateFloat(compositionHelper.GetSession(), &getInfo, &floatState), XR_ERROR_PATH_UNSUPPORTED); + REQUIRE_RESULT(xrGetActionStateFloat(session, &getInfo, &floatState), XR_ERROR_PATH_UNSUPPORTED); getInfo.action = vectorAction; - REQUIRE_RESULT(xrGetActionStateVector2f(compositionHelper.GetSession(), &getInfo, &vectorState), - XR_ERROR_PATH_UNSUPPORTED); + REQUIRE_RESULT(xrGetActionStateVector2f(session, &getInfo, &vectorState), XR_ERROR_PATH_UNSUPPORTED); getInfo.action = poseAction; - REQUIRE_RESULT(xrGetActionStatePose(compositionHelper.GetSession(), &getInfo, &poseState), XR_ERROR_PATH_UNSUPPORTED); + REQUIRE_RESULT(xrGetActionStatePose(session, &getInfo, &poseState), XR_ERROR_PATH_UNSUPPORTED); hapticActionInfo.subactionPath = getInfo.subactionPath; - REQUIRE_RESULT(xrApplyHapticFeedback(compositionHelper.GetSession(), &hapticActionInfo, - reinterpret_cast(&hapticPacket)), + REQUIRE_RESULT(xrApplyHapticFeedback(session, &hapticActionInfo, reinterpret_cast(&hapticPacket)), XR_ERROR_PATH_UNSUPPORTED); - REQUIRE_RESULT(xrStopHapticFeedback(compositionHelper.GetSession(), &hapticActionInfo), XR_ERROR_PATH_UNSUPPORTED); + REQUIRE_RESULT(xrStopHapticFeedback(session, &hapticActionInfo), XR_ERROR_PATH_UNSUPPORTED); { INFO("Action created with no subaction paths, cannot be queried with any"); getInfo.action = confirmAction; getInfo.subactionPath = leftHandPath; - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &booleanState), - XR_ERROR_PATH_UNSUPPORTED); + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &booleanState), XR_ERROR_PATH_UNSUPPORTED); } } SECTION("Type mismatch") { getInfo.action = booleanAction; hapticActionInfo.action = booleanAction; - REQUIRE_RESULT(xrGetActionStateFloat(compositionHelper.GetSession(), &getInfo, &floatState), - XR_ERROR_ACTION_TYPE_MISMATCH); - REQUIRE_RESULT(xrGetActionStateVector2f(compositionHelper.GetSession(), &getInfo, &vectorState), - XR_ERROR_ACTION_TYPE_MISMATCH); - REQUIRE_RESULT(xrGetActionStatePose(compositionHelper.GetSession(), &getInfo, &poseState), - XR_ERROR_ACTION_TYPE_MISMATCH); - REQUIRE_RESULT(xrApplyHapticFeedback(compositionHelper.GetSession(), &hapticActionInfo, - reinterpret_cast(&hapticPacket)), + REQUIRE_RESULT(xrGetActionStateFloat(session, &getInfo, &floatState), XR_ERROR_ACTION_TYPE_MISMATCH); + REQUIRE_RESULT(xrGetActionStateVector2f(session, &getInfo, &vectorState), XR_ERROR_ACTION_TYPE_MISMATCH); + REQUIRE_RESULT(xrGetActionStatePose(session, &getInfo, &poseState), XR_ERROR_ACTION_TYPE_MISMATCH); + REQUIRE_RESULT(xrApplyHapticFeedback(session, &hapticActionInfo, reinterpret_cast(&hapticPacket)), XR_ERROR_ACTION_TYPE_MISMATCH); - REQUIRE_RESULT(xrStopHapticFeedback(compositionHelper.GetSession(), &hapticActionInfo), XR_ERROR_ACTION_TYPE_MISMATCH); + REQUIRE_RESULT(xrStopHapticFeedback(session, &hapticActionInfo), XR_ERROR_ACTION_TYPE_MISMATCH); getInfo.action = floatAction; hapticActionInfo.action = floatAction; - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &booleanState), + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &booleanState), XR_ERROR_ACTION_TYPE_MISMATCH); + REQUIRE_RESULT(xrGetActionStateVector2f(session, &getInfo, &vectorState), XR_ERROR_ACTION_TYPE_MISMATCH); + REQUIRE_RESULT(xrGetActionStatePose(session, &getInfo, &poseState), XR_ERROR_ACTION_TYPE_MISMATCH); + REQUIRE_RESULT(xrApplyHapticFeedback(session, &hapticActionInfo, reinterpret_cast(&hapticPacket)), XR_ERROR_ACTION_TYPE_MISMATCH); - REQUIRE_RESULT(xrGetActionStateVector2f(compositionHelper.GetSession(), &getInfo, &vectorState), - XR_ERROR_ACTION_TYPE_MISMATCH); - REQUIRE_RESULT(xrGetActionStatePose(compositionHelper.GetSession(), &getInfo, &poseState), - XR_ERROR_ACTION_TYPE_MISMATCH); - REQUIRE_RESULT(xrApplyHapticFeedback(compositionHelper.GetSession(), &hapticActionInfo, - reinterpret_cast(&hapticPacket)), - XR_ERROR_ACTION_TYPE_MISMATCH); - REQUIRE_RESULT(xrStopHapticFeedback(compositionHelper.GetSession(), &hapticActionInfo), XR_ERROR_ACTION_TYPE_MISMATCH); + REQUIRE_RESULT(xrStopHapticFeedback(session, &hapticActionInfo), XR_ERROR_ACTION_TYPE_MISMATCH); getInfo.action = vectorAction; hapticActionInfo.action = vectorAction; - REQUIRE_RESULT(xrGetActionStateBoolean(compositionHelper.GetSession(), &getInfo, &booleanState), - XR_ERROR_ACTION_TYPE_MISMATCH); - REQUIRE_RESULT(xrGetActionStateFloat(compositionHelper.GetSession(), &getInfo, &floatState), + REQUIRE_RESULT(xrGetActionStateBoolean(session, &getInfo, &booleanState), XR_ERROR_ACTION_TYPE_MISMATCH); + REQUIRE_RESULT(xrGetActionStateFloat(session, &getInfo, &floatState), XR_ERROR_ACTION_TYPE_MISMATCH); + REQUIRE_RESULT(xrGetActionStatePose(session, &getInfo, &poseState), XR_ERROR_ACTION_TYPE_MISMATCH); + REQUIRE_RESULT(xrApplyHapticFeedback(session, &hapticActionInfo, reinterpret_cast(&hapticPacket)), XR_ERROR_ACTION_TYPE_MISMATCH); - REQUIRE_RESULT(xrGetActionStatePose(compositionHelper.GetSession(), &getInfo, &poseState), - XR_ERROR_ACTION_TYPE_MISMATCH); - REQUIRE_RESULT(xrApplyHapticFeedback(compositionHelper.GetSession(), &hapticActionInfo, - reinterpret_cast(&hapticPacket)), - XR_ERROR_ACTION_TYPE_MISMATCH); - REQUIRE_RESULT(xrStopHapticFeedback(compositionHelper.GetSession(), &hapticActionInfo), XR_ERROR_ACTION_TYPE_MISMATCH); + REQUIRE_RESULT(xrStopHapticFeedback(session, &hapticActionInfo), XR_ERROR_ACTION_TYPE_MISMATCH); getInfo.action = poseAction; hapticActionInfo.action = poseAction; - REQUIRE_RESULT(xrGetActionStateFloat(compositionHelper.GetSession(), &getInfo, &floatState), - XR_ERROR_ACTION_TYPE_MISMATCH); - REQUIRE_RESULT(xrGetActionStateFloat(compositionHelper.GetSession(), &getInfo, &floatState), + REQUIRE_RESULT(xrGetActionStateFloat(session, &getInfo, &floatState), XR_ERROR_ACTION_TYPE_MISMATCH); + REQUIRE_RESULT(xrGetActionStateFloat(session, &getInfo, &floatState), XR_ERROR_ACTION_TYPE_MISMATCH); + REQUIRE_RESULT(xrGetActionStateVector2f(session, &getInfo, &vectorState), XR_ERROR_ACTION_TYPE_MISMATCH); + REQUIRE_RESULT(xrApplyHapticFeedback(session, &hapticActionInfo, reinterpret_cast(&hapticPacket)), XR_ERROR_ACTION_TYPE_MISMATCH); - REQUIRE_RESULT(xrGetActionStateVector2f(compositionHelper.GetSession(), &getInfo, &vectorState), - XR_ERROR_ACTION_TYPE_MISMATCH); - REQUIRE_RESULT(xrApplyHapticFeedback(compositionHelper.GetSession(), &hapticActionInfo, - reinterpret_cast(&hapticPacket)), - XR_ERROR_ACTION_TYPE_MISMATCH); - REQUIRE_RESULT(xrStopHapticFeedback(compositionHelper.GetSession(), &hapticActionInfo), XR_ERROR_ACTION_TYPE_MISMATCH); + REQUIRE_RESULT(xrStopHapticFeedback(session, &hapticActionInfo), XR_ERROR_ACTION_TYPE_MISMATCH); getInfo.action = hapticAction; hapticActionInfo.action = hapticAction; - REQUIRE_RESULT(xrGetActionStateFloat(compositionHelper.GetSession(), &getInfo, &floatState), - XR_ERROR_ACTION_TYPE_MISMATCH); - REQUIRE_RESULT(xrGetActionStateFloat(compositionHelper.GetSession(), &getInfo, &floatState), - XR_ERROR_ACTION_TYPE_MISMATCH); - REQUIRE_RESULT(xrGetActionStateVector2f(compositionHelper.GetSession(), &getInfo, &vectorState), - XR_ERROR_ACTION_TYPE_MISMATCH); + REQUIRE_RESULT(xrGetActionStateFloat(session, &getInfo, &floatState), XR_ERROR_ACTION_TYPE_MISMATCH); + REQUIRE_RESULT(xrGetActionStateFloat(session, &getInfo, &floatState), XR_ERROR_ACTION_TYPE_MISMATCH); + REQUIRE_RESULT(xrGetActionStateVector2f(session, &getInfo, &vectorState), XR_ERROR_ACTION_TYPE_MISMATCH); } } } @@ -3168,17 +3120,18 @@ namespace Conformance // - the other is created after. // These two action spaces should both return (the same) valid data. CompositionHelper compositionHelper("action_space_creation_pre_suggest"); + XrInstance instance = compositionHelper.GetInstance(); + XrSession session = compositionHelper.GetSession(); compositionHelper.BeginSession(); ActionLayerManager actionLayerManager(compositionHelper); - XrPath simpleControllerInteractionProfile = - StringToPath(compositionHelper.GetInstance(), GetSimpleInteractionProfile().InteractionProfilePathString); + XrPath simpleControllerInteractionProfile = StringToPath(instance, GetSimpleInteractionProfile().InteractionProfilePathString); XrActionSet actionSet{XR_NULL_HANDLE}; XrActionSetCreateInfo actionSetCreateInfo{XR_TYPE_ACTION_SET_CREATE_INFO}; strcpy(actionSetCreateInfo.localizedActionSetName, "test action set localized name"); strcpy(actionSetCreateInfo.actionSetName, "test_action_set_name"); - REQUIRE_RESULT(xrCreateActionSet(compositionHelper.GetInstance(), &actionSetCreateInfo, &actionSet), XR_SUCCESS); + REQUIRE_RESULT(xrCreateActionSet(instance, &actionSetCreateInfo, &actionSet), XR_SUCCESS); XrAction poseAction{XR_NULL_HANDLE}; XrActionCreateInfo createInfo{XR_TYPE_ACTION_CREATE_INFO}; @@ -3194,17 +3147,15 @@ namespace Conformance earlySpaceCreateInfo.poseInActionSpace = XrPosefCPP(); earlySpaceCreateInfo.action = poseAction; XrSpace earlyActionSpace{XR_NULL_HANDLE}; - REQUIRE_RESULT(xrCreateActionSpace(compositionHelper.GetSession(), &earlySpaceCreateInfo, &earlyActionSpace), XR_SUCCESS); + REQUIRE_RESULT(xrCreateActionSpace(session, &earlySpaceCreateInfo, &earlyActionSpace), XR_SUCCESS); std::shared_ptr leftHandInputDevice = CreateTestDevice( - &actionLayerManager, &compositionHelper.GetInteractionManager(), compositionHelper.GetInstance(), - compositionHelper.GetSession(), simpleControllerInteractionProfile, - StringToPath(compositionHelper.GetInstance(), "/user/hand/left"), GetSimpleInteractionProfile().InputSourcePaths); + &actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, simpleControllerInteractionProfile, + StringToPath(instance, "/user/hand/left"), GetSimpleInteractionProfile().InputSourcePaths); compositionHelper.GetInteractionManager().AddActionSet(actionSet); compositionHelper.GetInteractionManager().AddActionBindings( - simpleControllerInteractionProfile, - {{poseAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/grip/pose")}}); + simpleControllerInteractionProfile, {{poseAction, StringToPath(instance, "/user/hand/left/input/grip/pose")}}); compositionHelper.GetInteractionManager().AttachActionSets(); // Create an ActionSpace after xrSuggestInteractionProfileBindings @@ -3212,7 +3163,7 @@ namespace Conformance lateSpaceCreateInfo.poseInActionSpace = XrPosefCPP(); lateSpaceCreateInfo.action = poseAction; XrSpace lateActionSpace{XR_NULL_HANDLE}; - REQUIRE_RESULT(xrCreateActionSpace(compositionHelper.GetSession(), &lateSpaceCreateInfo, &lateActionSpace), XR_SUCCESS); + REQUIRE_RESULT(xrCreateActionSpace(session, &lateSpaceCreateInfo, &lateActionSpace), XR_SUCCESS); actionLayerManager.WaitForSessionFocusWithMessage(); @@ -3220,7 +3171,7 @@ namespace Conformance XrReferenceSpaceCreateInfo createSpaceInfo{XR_TYPE_REFERENCE_SPACE_CREATE_INFO}; createSpaceInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL; createSpaceInfo.poseInReferenceSpace = XrPosefCPP(); - REQUIRE_RESULT(xrCreateReferenceSpace(compositionHelper.GetSession(), &createSpaceInfo, &localSpace), XR_SUCCESS); + REQUIRE_RESULT(xrCreateReferenceSpace(session, &createSpaceInfo, &localSpace), XR_SUCCESS); leftHandInputDevice->SetDeviceActive(true); @@ -3253,20 +3204,21 @@ namespace Conformance GlobalData& globalData = GetGlobalData(); CompositionHelper compositionHelper("Action Spaces"); + XrInstance instance = compositionHelper.GetInstance(); + XrSession session = compositionHelper.GetSession(); compositionHelper.BeginSession(); ActionLayerManager actionLayerManager(compositionHelper); - XrPath simpleControllerInteractionProfile = - StringToPath(compositionHelper.GetInstance(), GetSimpleInteractionProfile().InteractionProfilePathString); - XrPath leftHandPath{StringToPath(compositionHelper.GetInstance(), "/user/hand/left")}; - XrPath rightHandPath{StringToPath(compositionHelper.GetInstance(), "/user/hand/right")}; + XrPath simpleControllerInteractionProfile = StringToPath(instance, GetSimpleInteractionProfile().InteractionProfilePathString); + XrPath leftHandPath{StringToPath(instance, "/user/hand/left")}; + XrPath rightHandPath{StringToPath(instance, "/user/hand/right")}; const XrPath bothHands[2] = {leftHandPath, rightHandPath}; XrActionSet actionSet{XR_NULL_HANDLE}; XrActionSetCreateInfo actionSetCreateInfo{XR_TYPE_ACTION_SET_CREATE_INFO}; strcpy(actionSetCreateInfo.localizedActionSetName, "test action set localized name"); strcpy(actionSetCreateInfo.actionSetName, "test_action_set_name"); - REQUIRE_RESULT(xrCreateActionSet(compositionHelper.GetInstance(), &actionSetCreateInfo, &actionSet), XR_SUCCESS); + REQUIRE_RESULT(xrCreateActionSet(instance, &actionSetCreateInfo, &actionSet), XR_SUCCESS); XrAction poseAction{XR_NULL_HANDLE}; XrActionCreateInfo createInfo{XR_TYPE_ACTION_CREATE_INFO}; @@ -3278,20 +3230,17 @@ namespace Conformance REQUIRE_RESULT(xrCreateAction(actionSet, &createInfo, &poseAction), XR_SUCCESS); std::shared_ptr leftHandInputDevice = - CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), compositionHelper.GetInstance(), - compositionHelper.GetSession(), simpleControllerInteractionProfile, leftHandPath, - GetSimpleInteractionProfile().InputSourcePaths); + CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, + simpleControllerInteractionProfile, leftHandPath, GetSimpleInteractionProfile().InputSourcePaths); std::shared_ptr rightHandInputDevice = - CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), compositionHelper.GetInstance(), - compositionHelper.GetSession(), simpleControllerInteractionProfile, rightHandPath, - GetSimpleInteractionProfile().InputSourcePaths); + CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, + simpleControllerInteractionProfile, rightHandPath, GetSimpleInteractionProfile().InputSourcePaths); compositionHelper.GetInteractionManager().AddActionSet(actionSet); compositionHelper.GetInteractionManager().AddActionBindings( - simpleControllerInteractionProfile, - {{poseAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/grip/pose")}, - {poseAction, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/grip/pose")}}); + simpleControllerInteractionProfile, {{poseAction, StringToPath(instance, "/user/hand/left/input/grip/pose")}, + {poseAction, StringToPath(instance, "/user/hand/right/input/grip/pose")}}); compositionHelper.GetInteractionManager().AttachActionSets(); actionLayerManager.WaitForSessionFocusWithMessage(); @@ -3304,7 +3253,7 @@ namespace Conformance XrReferenceSpaceCreateInfo createSpaceInfo{XR_TYPE_REFERENCE_SPACE_CREATE_INFO}; createSpaceInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL; createSpaceInfo.poseInReferenceSpace = {{0, 0, 0, 1}, {0, 0, 0}}; - REQUIRE_RESULT(xrCreateReferenceSpace(compositionHelper.GetSession(), &createSpaceInfo, &localSpace), XR_SUCCESS); + REQUIRE_RESULT(xrCreateReferenceSpace(session, &createSpaceInfo, &localSpace), XR_SUCCESS); XrActionSpaceCreateInfo spaceCreateInfo{XR_TYPE_ACTION_SPACE_CREATE_INFO}; spaceCreateInfo.poseInActionSpace = {{0, 0, 0, 1}, {0, 0, 0}}; @@ -3312,17 +3261,17 @@ namespace Conformance // Can track left or right, but may: only switch at xrSyncActions. XrSpace actionSpaceWithoutSubactionPath{XR_NULL_HANDLE}; - REQUIRE_RESULT(xrCreateActionSpace(compositionHelper.GetSession(), &spaceCreateInfo, &actionSpaceWithoutSubactionPath), XR_SUCCESS); + REQUIRE_RESULT(xrCreateActionSpace(session, &spaceCreateInfo, &actionSpaceWithoutSubactionPath), XR_SUCCESS); // Only tracks left spaceCreateInfo.subactionPath = leftHandPath; XrSpace leftSpace{XR_NULL_HANDLE}; - REQUIRE_RESULT(xrCreateActionSpace(compositionHelper.GetSession(), &spaceCreateInfo, &leftSpace), XR_SUCCESS); + REQUIRE_RESULT(xrCreateActionSpace(session, &spaceCreateInfo, &leftSpace), XR_SUCCESS); // Only tracks right spaceCreateInfo.subactionPath = rightHandPath; XrSpace rightSpace{XR_NULL_HANDLE}; - REQUIRE_RESULT(xrCreateActionSpace(compositionHelper.GetSession(), &spaceCreateInfo, &rightSpace), XR_SUCCESS); + REQUIRE_RESULT(xrCreateActionSpace(session, &spaceCreateInfo, &rightSpace), XR_SUCCESS); if (globalData.leftHandUnderTest) { leftHandInputDevice->SetDeviceActive(true); @@ -3476,8 +3425,7 @@ namespace Conformance { XrActionStateGetInfo getInfo{XR_TYPE_ACTION_STATE_GET_INFO}; getInfo.action = poseAction; - REQUIRE_RESULT(xrGetActionStatePose(compositionHelper.GetSession(), &getInfo, &poseActionState), - XR_ERROR_HANDLE_INVALID); + REQUIRE_RESULT(xrGetActionStatePose(session, &getInfo, &poseActionState), XR_ERROR_HANDLE_INVALID); } REQUIRE_RESULT(xrLocateSpace(actionSpaceWithoutSubactionPath, localSpace, @@ -3527,7 +3475,7 @@ namespace Conformance auto getActionStatePoseActive = [&] { const auto getInfo = XrActionStateGetInfo{XR_TYPE_ACTION_STATE_GET_INFO, nullptr, poseAction, controllerSubactionPath}; XrActionStatePose statePose{XR_TYPE_ACTION_STATE_POSE}; - REQUIRE_RESULT(xrGetActionStatePose(compositionHelper.GetSession(), &getInfo, &statePose), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStatePose(session, &getInfo, &statePose), XR_SUCCESS); return statePose.isActive == XR_TRUE; }; @@ -3651,7 +3599,7 @@ namespace Conformance const auto getInfo = XrActionStateGetInfo{XR_TYPE_ACTION_STATE_GET_INFO, nullptr, poseAction, controllerSubactionPath}; XrActionStatePose statePose{XR_TYPE_ACTION_STATE_POSE}; - REQUIRE_RESULT(xrGetActionStatePose(compositionHelper.GetSession(), &getInfo, &statePose), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStatePose(session, &getInfo, &statePose), XR_SUCCESS); REQUIRE(statePose.isActive == XR_FALSE); } { @@ -3661,7 +3609,7 @@ namespace Conformance const auto getInfo = XrActionStateGetInfo{XR_TYPE_ACTION_STATE_GET_INFO, nullptr, poseAction, XR_NULL_PATH}; XrActionStatePose statePose{XR_TYPE_ACTION_STATE_POSE}; - REQUIRE_RESULT(xrGetActionStatePose(compositionHelper.GetSession(), &getInfo, &statePose), XR_SUCCESS); + REQUIRE_RESULT(xrGetActionStatePose(session, &getInfo, &statePose), XR_SUCCESS); REQUIRE(statePose.isActive == XR_FALSE); } } @@ -3706,8 +3654,7 @@ namespace Conformance XrActionStatePose poseActionState{XR_TYPE_ACTION_STATE_POSE}; XrActionStateGetInfo getInfo{XR_TYPE_ACTION_STATE_GET_INFO}; getInfo.action = poseAction; - REQUIRE_RESULT(xrGetActionStatePose(compositionHelper.GetSession(), &getInfo, &poseActionState), - XR_ERROR_HANDLE_INVALID); + REQUIRE_RESULT(xrGetActionStatePose(session, &getInfo, &poseActionState), XR_ERROR_HANDLE_INVALID); } } } @@ -3717,12 +3664,14 @@ namespace Conformance TEST_CASE("xrEnumerateBoundSourcesForAction_and_xrGetInputSourceLocalizedName", "[actions][interactive]") { CompositionHelper compositionHelper("BoundSources and LocalizedName"); + XrInstance instance = compositionHelper.GetInstance(); + XrSession session = compositionHelper.GetSession(); XrActionSet actionSet{XR_NULL_HANDLE}; XrActionSetCreateInfo actionSetCreateInfo{XR_TYPE_ACTION_SET_CREATE_INFO}; strcpy(actionSetCreateInfo.localizedActionSetName, "test action set localized name"); strcpy(actionSetCreateInfo.actionSetName, "test_action_set_name"); - REQUIRE_RESULT(xrCreateActionSet(compositionHelper.GetInstance(), &actionSetCreateInfo, &actionSet), XR_SUCCESS); + REQUIRE_RESULT(xrCreateActionSet(instance, &actionSetCreateInfo, &actionSet), XR_SUCCESS); XrAction action{XR_NULL_HANDLE}; XrActionCreateInfo actionCreateInfo{XR_TYPE_ACTION_CREATE_INFO}; @@ -3739,18 +3688,17 @@ namespace Conformance bool leftUnderTest = GetGlobalData().leftHandUnderTest; const char* pathStr = leftUnderTest ? "/user/hand/left" : "/user/hand/right"; - XrPath path{StringToPath(compositionHelper.GetInstance(), pathStr)}; + XrPath path{StringToPath(instance, pathStr)}; std::shared_ptr inputDevice = - CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), compositionHelper.GetInstance(), - compositionHelper.GetSession(), - StringToPath(compositionHelper.GetInstance(), GetSimpleInteractionProfile().InteractionProfilePathString), - path, GetSimpleInteractionProfile().InputSourcePaths); + CreateTestDevice(&actionLayerManager, &compositionHelper.GetInteractionManager(), instance, session, + StringToPath(instance, GetSimpleInteractionProfile().InteractionProfilePathString), path, + GetSimpleInteractionProfile().InputSourcePaths); compositionHelper.GetInteractionManager().AddActionSet(actionSet); compositionHelper.GetInteractionManager().AddActionBindings( - StringToPath(compositionHelper.GetInstance(), "/interaction_profiles/khr/simple_controller"), - {{action, StringToPath(compositionHelper.GetInstance(), "/user/hand/left/input/select/click")}, - {action, StringToPath(compositionHelper.GetInstance(), "/user/hand/right/input/select/click")}}); + StringToPath(instance, "/interaction_profiles/khr/simple_controller"), + {{action, StringToPath(instance, "/user/hand/left/input/select/click")}, + {action, StringToPath(instance, "/user/hand/right/input/select/click")}}); compositionHelper.GetInteractionManager().AttachActionSets(); inputDevice->SetDeviceActive(true); @@ -3766,14 +3714,13 @@ namespace Conformance info.action = action; SECTION("Basic usage") { - std::vector enumerateResult = - REQUIRE_TWO_CALL(XrPath, {}, xrEnumerateBoundSourcesForAction, compositionHelper.GetSession(), &info); + std::vector enumerateResult = REQUIRE_TWO_CALL(XrPath, {}, xrEnumerateBoundSourcesForAction, session, &info); // Note that runtimes may return bound sources even when not focused, though they don't have to actionLayerManager.SyncActionsUntilFocusWithMessage(syncInfo); - enumerateResult = REQUIRE_TWO_CALL(XrPath, {}, xrEnumerateBoundSourcesForAction, compositionHelper.GetSession(), &info); + enumerateResult = REQUIRE_TWO_CALL(XrPath, {}, xrEnumerateBoundSourcesForAction, session, &info); REQUIRE(enumerateResult.size() > 0); @@ -3782,42 +3729,35 @@ namespace Conformance SECTION("xrGetInputSourceLocalizedName") { getInfo.whichComponents = XR_INPUT_SOURCE_LOCALIZED_NAME_USER_PATH_BIT; - std::string localizedStringResult = - REQUIRE_TWO_CALL(char, {}, xrGetInputSourceLocalizedName, compositionHelper.GetSession(), &getInfo).data(); + std::string localizedStringResult = REQUIRE_TWO_CALL(char, {}, xrGetInputSourceLocalizedName, session, &getInfo).data(); REQUIRE_FALSE(localizedStringResult.empty()); getInfo.whichComponents = XR_INPUT_SOURCE_LOCALIZED_NAME_INTERACTION_PROFILE_BIT; - localizedStringResult = - REQUIRE_TWO_CALL(char, {}, xrGetInputSourceLocalizedName, compositionHelper.GetSession(), &getInfo).data(); + localizedStringResult = REQUIRE_TWO_CALL(char, {}, xrGetInputSourceLocalizedName, session, &getInfo).data(); REQUIRE_FALSE(localizedStringResult.empty()); getInfo.whichComponents = XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT; - localizedStringResult = - REQUIRE_TWO_CALL(char, {}, xrGetInputSourceLocalizedName, compositionHelper.GetSession(), &getInfo).data(); + localizedStringResult = REQUIRE_TWO_CALL(char, {}, xrGetInputSourceLocalizedName, session, &getInfo).data(); REQUIRE_FALSE(localizedStringResult.empty()); getInfo.whichComponents = XR_INPUT_SOURCE_LOCALIZED_NAME_USER_PATH_BIT | XR_INPUT_SOURCE_LOCALIZED_NAME_INTERACTION_PROFILE_BIT; - localizedStringResult = - REQUIRE_TWO_CALL(char, {}, xrGetInputSourceLocalizedName, compositionHelper.GetSession(), &getInfo).data(); + localizedStringResult = REQUIRE_TWO_CALL(char, {}, xrGetInputSourceLocalizedName, session, &getInfo).data(); REQUIRE_FALSE(localizedStringResult.empty()); getInfo.whichComponents = XR_INPUT_SOURCE_LOCALIZED_NAME_USER_PATH_BIT | XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT; - localizedStringResult = - REQUIRE_TWO_CALL(char, {}, xrGetInputSourceLocalizedName, compositionHelper.GetSession(), &getInfo).data(); + localizedStringResult = REQUIRE_TWO_CALL(char, {}, xrGetInputSourceLocalizedName, session, &getInfo).data(); REQUIRE_FALSE(localizedStringResult.empty()); getInfo.whichComponents = XR_INPUT_SOURCE_LOCALIZED_NAME_INTERACTION_PROFILE_BIT | XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT; - localizedStringResult = - REQUIRE_TWO_CALL(char, {}, xrGetInputSourceLocalizedName, compositionHelper.GetSession(), &getInfo).data(); + localizedStringResult = REQUIRE_TWO_CALL(char, {}, xrGetInputSourceLocalizedName, session, &getInfo).data(); REQUIRE_FALSE(localizedStringResult.empty()); getInfo.whichComponents = XR_INPUT_SOURCE_LOCALIZED_NAME_USER_PATH_BIT | XR_INPUT_SOURCE_LOCALIZED_NAME_INTERACTION_PROFILE_BIT | XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT; - localizedStringResult = - REQUIRE_TWO_CALL(char, {}, xrGetInputSourceLocalizedName, compositionHelper.GetSession(), &getInfo).data(); + localizedStringResult = REQUIRE_TWO_CALL(char, {}, xrGetInputSourceLocalizedName, session, &getInfo).data(); REQUIRE_FALSE(localizedStringResult.empty()); uint32_t sourceCountOutput; @@ -3825,20 +3765,17 @@ namespace Conformance SECTION("Invalid components") { getInfo.whichComponents = 0; - REQUIRE_RESULT( - xrGetInputSourceLocalizedName(compositionHelper.GetSession(), &getInfo, 0, &sourceCountOutput, &buffer), - XR_ERROR_VALIDATION_FAILURE); + REQUIRE_RESULT(xrGetInputSourceLocalizedName(session, &getInfo, 0, &sourceCountOutput, &buffer), + XR_ERROR_VALIDATION_FAILURE); } SECTION("Invalid path") { getInfo.sourcePath = XR_NULL_PATH; - REQUIRE_RESULT( - xrGetInputSourceLocalizedName(compositionHelper.GetSession(), &getInfo, 0, &sourceCountOutput, &buffer), - XR_ERROR_PATH_INVALID); + REQUIRE_RESULT(xrGetInputSourceLocalizedName(session, &getInfo, 0, &sourceCountOutput, &buffer), + XR_ERROR_PATH_INVALID); getInfo.sourcePath = (XrPath)0x1234; - REQUIRE_RESULT( - xrGetInputSourceLocalizedName(compositionHelper.GetSession(), &getInfo, 0, &sourceCountOutput, &buffer), - XR_ERROR_PATH_INVALID); + REQUIRE_RESULT(xrGetInputSourceLocalizedName(session, &getInfo, 0, &sourceCountOutput, &buffer), + XR_ERROR_PATH_INVALID); } } } @@ -3857,7 +3794,7 @@ namespace Conformance info.action = (XrAction)0x1234; uint32_t sourceCountOutput; XrPath buffer; - REQUIRE_RESULT(xrEnumerateBoundSourcesForAction(compositionHelper.GetSession(), &info, 0, &sourceCountOutput, &buffer), + REQUIRE_RESULT(xrEnumerateBoundSourcesForAction(session, &info, 0, &sourceCountOutput, &buffer), XR_ERROR_HANDLE_INVALID); } } diff --git a/src/conformance/conformance_test/test_glTFRendering.cpp b/src/conformance/conformance_test/test_glTFRendering.cpp index 8c5b571e..21010dcb 100644 --- a/src/conformance/conformance_test/test_glTFRendering.cpp +++ b/src/conformance/conformance_test/test_glTFRendering.cpp @@ -95,7 +95,7 @@ namespace Conformance spaceCreateInfo.subactionPath = subactionPaths[i]; spaceCreateInfo.poseInActionSpace = XrPosefCPP{}; XRC_CHECK_THROW_XRCMD(xrCreateActionSpace(session, &spaceCreateInfo, &space)); - gripSpaces.emplace_back(std::move(space)); + gripSpaces.emplace_back(space); } } diff --git a/src/conformance/conformance_test/test_xrCreateSession.cpp b/src/conformance/conformance_test/test_xrCreateSession.cpp index 43e3ef5d..3a82ec1f 100644 --- a/src/conformance/conformance_test/test_xrCreateSession.cpp +++ b/src/conformance/conformance_test/test_xrCreateSession.cpp @@ -157,5 +157,36 @@ namespace Conformance REQUIRE(destroyInstanceResult == XR_SUCCESS); } } + + SECTION("not calling xrDestroySession") + { + GlobalData& globalData = GetGlobalData(); + + for (int i = 0; i < 2; ++i) { + CAPTURE(i); + + std::shared_ptr graphicsPlugin; + + AutoBasicInstance instance{AutoBasicInstance::createSystemId}; + XrSystemId systemId = instance.systemId; + + if (!globalData.options.graphicsPlugin.empty()) { + REQUIRE_NOTHROW(graphicsPlugin = Conformance::CreateGraphicsPlugin(globalData.options.graphicsPlugin.c_str(), + globalData.GetPlatformPlugin())); + REQUIRE(graphicsPlugin->Initialize()); + } + + REQUIRE(graphicsPlugin->InitializeDevice(instance, systemId)); + + XrSessionCreateInfo sessionCreateInfo{XR_TYPE_SESSION_CREATE_INFO, nullptr, 0, systemId}; + sessionCreateInfo.next = graphicsPlugin->GetGraphicsBinding(); + + XrSession session = XR_NULL_HANDLE_CPP; + REQUIRE(xrCreateSession(instance, &sessionCreateInfo, &session) == XR_SUCCESS); + + // leak the session handle + // AutoBasicInstance will cleanup for us + } + } } } // namespace Conformance diff --git a/src/conformance/framework/RGBAImage.cpp b/src/conformance/framework/RGBAImage.cpp index db6c0c9f..9fb9032c 100644 --- a/src/conformance/framework/RGBAImage.cpp +++ b/src/conformance/framework/RGBAImage.cpp @@ -252,7 +252,7 @@ namespace Conformance RGBA8Color* const destImageRow = pixels.data() + (destY * width); for (int cx = 0; cx < characterWidth; cx++) { - const int destX = (int)(bakedChar.xoff + xadvance + 0.5f) + cx; + const int destX = (int)std::lround(bakedChar.xoff + xadvance) + cx; if (destX < 0 || destX >= width || destX < rect.offset.x || destX >= rect.offset.x + rect.extent.width) { continue; // Don't bother copying if out of bounds. } @@ -348,7 +348,9 @@ namespace Conformance void RGBAImageCache::Init() { - m_cacheMutex = std::make_unique(); + if (!m_cacheMutex) { + m_cacheMutex = std::make_unique(); + } } std::shared_ptr RGBAImageCache::Load(const char* path) diff --git a/src/conformance/framework/action_utils.h b/src/conformance/framework/action_utils.h index 6922083e..efbf2c31 100644 --- a/src/conformance/framework/action_utils.h +++ b/src/conformance/framework/action_utils.h @@ -34,32 +34,74 @@ namespace Conformance extern const std::chrono::nanoseconds kActionWaitDelay; - // Manages showing a quad with help text. + /// Manages showing a quad with help text. struct ActionLayerManager : public ITestMessageDisplay { ActionLayerManager(CompositionHelper& compositionHelper); - EventReader& GetEventReader() + /// Access the contained @ref EventReader + EventReader& GetEventReader() noexcept { return m_eventReader; } - RenderLoop& GetRenderLoop() + /// Access the contained @ref RenderLoop + RenderLoop& GetRenderLoop() noexcept { return m_renderLoop; } + /// Wait until your callback returns true, while displaying a text message on the display. + /// + /// This helper: + /// + /// - DOES submit frames + /// - DOES NOT call `xrSyncActions` + /// - DOES NOT poll events through this object's EventReader (though the CompositionHelper will poll events) bool WaitWithMessage(const char* waitMessage, std::function frameCallback); + /// Submit frames until focus is available, based on waiting for the session state event, + /// in case focus was lost at some point. + /// + /// This helper: + /// + /// - DOES submit frames (wraps a call to @ref WaitWithMessage) + /// - DOES NOT call `xrSyncActions` + /// - DOES call `xrPollEvent` + /// - DOES poll events through this object's EventReader void WaitForSessionFocusWithMessage(); + /// Waits until xrLocateSpace reports that position/orientation valid flags match @p expectLocatability. + /// + /// This helper: + /// + /// - DOES submit frames (wraps a call to @ref WaitWithMessage) + /// - DOES NOT call `xrSyncActions` - you must call it beforehand at least once with the right action set(s) to make + /// your action space active! + /// - DOES NOT poll events through this object's EventReader (though the CompositionHelper will poll events) + /// + /// @param hand Hand name for message + /// bool WaitForLocatability(const std::string& hand, XrSpace space, XrSpace localSpace, XrSpaceLocation* location, bool expectLocatability); - // Sync until focus is available, in case focus was lost at some point. + /// Sync actions until focus is available, observed by xrSyncActions returning XR_SUCCESS instead of XR_SESSION_NOT_FOCUSED, + /// in case focus was lost at some point. + /// + /// This helper: + /// + /// - DOES submit frames (wraps a call to @ref WaitWithMessage) + /// - DOES call `xrSyncActions` - if you do not want to sync actions, see @ref WaitForSessionFocusWithMessage + /// - DOES NOT poll events through this object's EventReader (though the CompositionHelper will poll events) void SyncActionsUntilFocusWithMessage(const XrActionsSyncInfo& syncInfo); - // "Sleep", but keep the render loop going on this thread + /// "Sleep", but keep the render loop going on this thread + /// + /// This helper: + /// + /// - DOES submit frames + /// - DOES NOT call `xrSyncActions` + /// - DOES NOT poll events through this object's EventReader (though the CompositionHelper will poll events) template void Sleep_For(const std::chrono::duration& sleep_duration) { @@ -69,8 +111,19 @@ namespace Conformance } } + /// Call `xrEndFrame` via the @ref CompositionHelper, then let it poll for events to decide whether to stop. + /// + /// If there was a call to @ref DisplayMessage, a layer for the message will be submitted. bool EndFrame(const XrFrameState& frameState); + + /// Calls `xrWaitFrame`, `xrBeginFrame`, and `xrEndFrame`, delegating to the owned @ref RenderLoop void IterateFrame() override; + + /// Display a message on the console and in the immersive environment. + /// + /// Prepares a static swapchain with the message for use the next time @ref EndFrame is called, + /// directly or indirectly, through this helper object. + /// (Does not directly submit frames!) void DisplayMessage(const std::string& message) override; private: diff --git a/src/conformance/framework/composition_utils.h b/src/conformance/framework/composition_utils.h index 569801d6..2e934ae7 100644 --- a/src/conformance/framework/composition_utils.h +++ b/src/conformance/framework/composition_utils.h @@ -64,7 +64,12 @@ namespace Conformance { } + /// Call `xrWaitFrame`, `xrBeginFrame`, `xrEndFrame`. + /// Returns whatever your @ref EndFrame function returned bool IterateFrame(); + + /// Call @ref IterateFrame repeatedly until your @ref EndFrame returns false, + /// checking that no exceptions are thrown void Loop(); XrTime GetLastPredictedDisplayTime() const; diff --git a/src/conformance/framework/conformance_utils.cpp b/src/conformance/framework/conformance_utils.cpp index b0c65f19..43112439 100644 --- a/src/conformance/framework/conformance_utils.cpp +++ b/src/conformance/framework/conformance_utils.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -1058,6 +1059,13 @@ namespace Conformance } } + std::string SubtestTitle(const char* testName, size_t subtestIdx, size_t subtestCount) + { + std::ostringstream os; + os << testName << ": subtest " << (subtestIdx + 1) << " of " << subtestCount; + return os.str(); + } + // Encapsulates xrEnumerateSwapchainFormats/xrCreateSwapchain XrResult CreateColorSwapchain(XrSession session, IGraphicsPlugin* graphicsPlugin, XrSwapchain* swapchain, XrExtent2Di* widthHeight, uint32_t arraySize, bool cubemap, XrSwapchainCreateInfo* createInfoReturn) diff --git a/src/conformance/framework/conformance_utils.h b/src/conformance/framework/conformance_utils.h index d883a74d..1624cf63 100644 --- a/src/conformance/framework/conformance_utils.h +++ b/src/conformance/framework/conformance_utils.h @@ -674,6 +674,10 @@ namespace Conformance /// @relates AutoBasicSession std::ostream& operator<<(std::ostream& os, AutoBasicSession const& sess); + /// Calls your @p predicate repeatedly, pausing @p delay in between, until either it returns `true` or @p timeout has elapsed. + /// + /// @note This does not inherently submit frames and is thus likely to cause problems if a session is running unless your predicate submits a frame! + /// It is intended for use outside of a frame loop. bool WaitUntilPredicateWithTimeout(const std::function& predicate, const std::chrono::nanoseconds timeout, const std::chrono::nanoseconds delay); @@ -853,4 +857,24 @@ namespace Conformance s.type = type; s.next = next; } + + /// Make a test title given a short test name, a subtest index, and the number of subtests. + std::string SubtestTitle(const char* testName, size_t subtestIdx, size_t subtestCount); + + /// Make a test title given a short test name, a subtest index, and the array of subtests. + template + inline std::string SubtestTitle(const char* testName, size_t subtestIdx, const T (&subtestArray)[Size]) + { + (void)subtestArray; + return SubtestTitle(testName, subtestIdx, Size); + } + + /// Make pixel subrects based on normalized subrects and pixel dimensions + inline XrRect2Di CropImage(int32_t width, int32_t height, XrRect2Df crop) + { + return { + {int32_t(crop.offset.x * width), int32_t(crop.offset.y * height)}, + {int32_t(crop.extent.width * width), int32_t(crop.extent.height * height)}, + }; + } } // namespace Conformance diff --git a/src/conformance/framework/graphics_plugin_d3d12.cpp b/src/conformance/framework/graphics_plugin_d3d12.cpp index 667142e7..2bb891f1 100644 --- a/src/conformance/framework/graphics_plugin_d3d12.cpp +++ b/src/conformance/framework/graphics_plugin_d3d12.cpp @@ -1012,6 +1012,8 @@ namespace Conformance const XrSwapchainImageBaseHeader* colorSwapchainImage, const RenderParams& params) { if (params.cubes.empty() && params.meshes.empty() && params.glTFs.empty()) { + // Early exit, but need to wait as being done at end of method + WaitForGpu(); return; } D3D12SwapchainImageData* swapchainData; diff --git a/src/conformance/framework/graphics_plugin_opengl.cpp b/src/conformance/framework/graphics_plugin_opengl.cpp index e0edc7b3..ee2e24de 100644 --- a/src/conformance/framework/graphics_plugin_opengl.cpp +++ b/src/conformance/framework/graphics_plugin_opengl.cpp @@ -267,7 +267,11 @@ namespace Conformance OpenGLFallbackDepthTexture() = default; ~OpenGLFallbackDepthTexture() { - Reset(); + if (Allocated()) { + // As implementation as ::Reset(), but should not throw in destructor + glDeleteTextures(1, &m_texture); + } + m_texture = 0; } void Reset() { diff --git a/src/conformance/framework/pbr/PbrMaterial.h b/src/conformance/framework/pbr/PbrMaterial.h index d6223f7a..ee911ad3 100644 --- a/src/conformance/framework/pbr/PbrMaterial.h +++ b/src/conformance/framework/pbr/PbrMaterial.h @@ -100,7 +100,7 @@ namespace Pbr mutable bool m_parametersChanged{true}; std::aligned_storage_t m_parametersStorage; - ConstantBufferData m_parameters; + ConstantBufferData m_parameters{}; BlendState m_alphaBlended{BlendState::NotAlphaBlended}; DoubleSided m_doubleSided{DoubleSided::NotDoubleSided}; diff --git a/src/conformance/framework/platform_plugin_posix.cpp b/src/conformance/framework/platform_plugin_posix.cpp index 84ce9d19..0370eb9b 100644 --- a/src/conformance/framework/platform_plugin_posix.cpp +++ b/src/conformance/framework/platform_plugin_posix.cpp @@ -66,7 +66,7 @@ namespace Conformance } private: - bool initialized; + bool initialized{}; }; std::shared_ptr CreatePlatformPlugin() diff --git a/src/conformance/platform_specific/android_resources/mipmap-hdpi/ic_launcher.png b/src/conformance/platform_specific/android_resources/mipmap-hdpi/ic_launcher.png index 2d33730e..be5977cb 100644 Binary files a/src/conformance/platform_specific/android_resources/mipmap-hdpi/ic_launcher.png and b/src/conformance/platform_specific/android_resources/mipmap-hdpi/ic_launcher.png differ diff --git a/src/conformance/platform_specific/android_resources/mipmap-hdpi/ic_launcher_round.png b/src/conformance/platform_specific/android_resources/mipmap-hdpi/ic_launcher_round.png index 2d33730e..be5977cb 100644 Binary files a/src/conformance/platform_specific/android_resources/mipmap-hdpi/ic_launcher_round.png and b/src/conformance/platform_specific/android_resources/mipmap-hdpi/ic_launcher_round.png differ diff --git a/src/conformance/platform_specific/android_resources/mipmap-mdpi/ic_launcher.png b/src/conformance/platform_specific/android_resources/mipmap-mdpi/ic_launcher.png index eaa38980..b2766b76 100644 Binary files a/src/conformance/platform_specific/android_resources/mipmap-mdpi/ic_launcher.png and b/src/conformance/platform_specific/android_resources/mipmap-mdpi/ic_launcher.png differ diff --git a/src/conformance/platform_specific/android_resources/mipmap-mdpi/ic_launcher_round.png b/src/conformance/platform_specific/android_resources/mipmap-mdpi/ic_launcher_round.png index eaa38980..b2766b76 100644 Binary files a/src/conformance/platform_specific/android_resources/mipmap-mdpi/ic_launcher_round.png and b/src/conformance/platform_specific/android_resources/mipmap-mdpi/ic_launcher_round.png differ diff --git a/src/conformance/platform_specific/android_resources/mipmap-xhdpi/ic_launcher.png b/src/conformance/platform_specific/android_resources/mipmap-xhdpi/ic_launcher.png index 4d86949e..0ba9b3d2 100644 Binary files a/src/conformance/platform_specific/android_resources/mipmap-xhdpi/ic_launcher.png and b/src/conformance/platform_specific/android_resources/mipmap-xhdpi/ic_launcher.png differ diff --git a/src/conformance/platform_specific/android_resources/mipmap-xhdpi/ic_launcher_round.png b/src/conformance/platform_specific/android_resources/mipmap-xhdpi/ic_launcher_round.png index 4d86949e..0ba9b3d2 100644 Binary files a/src/conformance/platform_specific/android_resources/mipmap-xhdpi/ic_launcher_round.png and b/src/conformance/platform_specific/android_resources/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/src/conformance/platform_specific/android_resources/mipmap-xxhdpi/ic_launcher.png b/src/conformance/platform_specific/android_resources/mipmap-xxhdpi/ic_launcher.png index 0599c2d2..8d187d05 100644 Binary files a/src/conformance/platform_specific/android_resources/mipmap-xxhdpi/ic_launcher.png and b/src/conformance/platform_specific/android_resources/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src/conformance/platform_specific/android_resources/mipmap-xxhdpi/ic_launcher_round.png b/src/conformance/platform_specific/android_resources/mipmap-xxhdpi/ic_launcher_round.png index 0599c2d2..8d187d05 100644 Binary files a/src/conformance/platform_specific/android_resources/mipmap-xxhdpi/ic_launcher_round.png and b/src/conformance/platform_specific/android_resources/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/src/conformance/platform_specific/android_resources/mipmap-xxxhdpi/ic_launcher.png b/src/conformance/platform_specific/android_resources/mipmap-xxxhdpi/ic_launcher.png index 61152a64..94403b46 100644 Binary files a/src/conformance/platform_specific/android_resources/mipmap-xxxhdpi/ic_launcher.png and b/src/conformance/platform_specific/android_resources/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src/conformance/platform_specific/android_resources/mipmap-xxxhdpi/ic_launcher_round.png b/src/conformance/platform_specific/android_resources/mipmap-xxxhdpi/ic_launcher_round.png index 61152a64..94403b46 100644 Binary files a/src/conformance/platform_specific/android_resources/mipmap-xxxhdpi/ic_launcher_round.png and b/src/conformance/platform_specific/android_resources/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/src/loader/manifest_file.cpp b/src/loader/manifest_file.cpp index 0caf05c9..ca212d34 100644 --- a/src/loader/manifest_file.cpp +++ b/src/loader/manifest_file.cpp @@ -773,8 +773,7 @@ void ApiLayerManifestFile::AddManifestFilesAndroid(const std::string &openxr_com } std::istringstream json_stream(std::string{buf, length}); - CreateIfValid(ManifestFileType::MANIFEST_TYPE_EXPLICIT_API_LAYER, filename, json_stream, - &ApiLayerManifestFile::LocateLibraryInAssets, manifest_files); + CreateIfValid(type, filename, json_stream, &ApiLayerManifestFile::LocateLibraryInAssets, manifest_files); } } #endif // defined(XR_USE_PLATFORM_ANDROID) && defined(XR_KHR_LOADER_INIT_SUPPORT)