From 434f398b23541ff0359fec11999338d0f2fc2446 Mon Sep 17 00:00:00 2001 From: dengkail Date: Mon, 14 Aug 2023 11:38:53 +0800 Subject: [PATCH] OpenXR loader: add API layer discovery support. Revert "Update local repo to latest." --- .appveyor.yml | 2 +- .gitattributes | 5 +- .github/scripts/CMakePresets.json | 25 - .github/scripts/shared.py | 15 +- .github/workflows/android.yml | 4 +- .github/workflows/msvc-build-preset.yml | 28 +- .github/workflows/windows-matrix.yml | 53 +- .gitignore | 1 - .reuse/dep5 | 26 +- BUILDING.md | 15 - CHANGELOG.SDK.md | 146 -- CMakeLists.txt | 2 - HOTFIX | 1 - LICENSES/Zlib.txt | 11 - changes/sdk/mr.2836.gl.1.md | 4 - changes/sdk/mr.2836.gl.2.md | 5 - changes/sdk/mr.2836.gl.md | 1 - changes/sdk/mr.2840.gl.md | 4 - changes/sdk/mr.414.gh.OpenXR-SDK-Source.md | 1 - include/openxr/openxr_platform_defines.h | 4 - maintainer-scripts/build-aar.sh | 51 +- .../build-and-publish-aar-mavencentral.sh | 4 +- .../build-and-publish-aar-snapshot.sh | 4 +- maintainer-scripts/common.sh | 47 +- maintainer-scripts/publish-aar/gradlew | 2 + maintainer-scripts/publish-aar/gradlew.bat | 2 + .../publish-aar/gradlew.bat.license | 2 - .../publish-aar/gradlew.license | 2 - runClangFormat.sh | 10 +- specification/Makefile | 30 +- specification/loader/api_layer.adoc | 28 +- specification/loader/runtime.adoc | 108 +- specification/registry/xr.xml | 1137 +---------- specification/scripts/cgenerator.py | 4 +- specification/scripts/docgenerator.py | 2 - specification/scripts/findBareNormatives.sh | 82 - specification/scripts/genRef.py | 4 - .../{spec-macros.rb => openxr-macros.rb} | 3 +- .../extension.rb | 132 +- specification/scripts/reg.py | 4 - specification/scripts/reserve_extensions.py | 32 - .../scripts/spec_tools/conventions.py | 2 +- .../scripts/spec_tools/macro_checker_file.py | 6 +- .../scripts/test_check_spec_links.py | 4 +- specification/scripts/xml_consistency.py | 20 +- specification/scripts/xrconventions.py | 2 +- src/CMakeLists.txt | 34 +- src/api_layers/CMakeLists.txt | 28 +- src/api_layers/README.md | 2 +- src/api_layers/XrApiLayer_api_dump.expsym | 5 - .../XrApiLayer_core_validation.expsym | 5 - src/api_layers/api_dump.cpp | 10 +- src/api_layers/core_validation.cpp | 11 +- src/common/filesystem_utils.cpp | 2 +- src/common/filesystem_utils.hpp | 2 +- src/common/gfxwrapper_opengl.c | 260 ++- src/common/gfxwrapper_opengl.h | 10 +- src/common/object_info.cpp | 4 +- src/common/platform_utils.hpp | 5 +- src/external/earcut/include/earcut.hpp | 816 ++++++++ .../earcut/include/earcut.hpp.license | 6 + src/external/jnipp/jnipp.cpp | 7 - src/external/jnipp/jnipp.h | 18 - src/external/jnipp/tests/main.cpp | 16 - .../span-lite/include/nonstd/span.hpp | 1695 +++++++++++++++++ .../type-lite/include/nonstd/type.hpp | 841 ++++++++ src/loader/AndroidManifest.xml | 9 - src/loader/AndroidManifest.xml.in | 18 +- src/loader/CMakeLists.txt | 27 +- src/loader/android_utilities.cpp | 199 +- src/loader/android_utilities.h | 12 + src/loader/api_layer_interface.cpp | 14 +- src/loader/build.gradle | 204 ++ src/loader/loader_instance.cpp | 4 +- src/loader/loader_logger_recorders.cpp | 9 +- src/loader/manifest_file.cpp | 136 +- src/loader/manifest_file.hpp | 4 +- src/loader/openxr-loader.expsym | 59 - src/loader/openxr_loader_for_android.pom | 11 +- src/loader/runtime_interface.cpp | 27 +- src/loader/runtime_interface.hpp | 1 + src/scripts/utility_source_generator.py | 1 - src/scripts/validation_layer_generator.py | 15 +- src/tests/c_compile_test/CMakeLists.txt | 6 +- src/tests/hello_xr/AndroidManifest.xml | 15 +- src/tests/hello_xr/CMakeLists.txt | 10 +- src/tests/hello_xr/build.gradle | 7 +- src/tests/hello_xr/common.h | 4 +- .../gradle/wrapper/gradle-wrapper.jar | Bin 60756 -> 58910 bytes .../gradle/wrapper/gradle-wrapper.properties | 2 +- src/tests/hello_xr/gradlew | 265 ++- src/tests/hello_xr/gradlew.bat | 35 +- src/tests/hello_xr/gradlew.bat.license | 2 - src/tests/hello_xr/gradlew.license | 2 - src/tests/hello_xr/graphicsplugin_opengl.cpp | 6 - src/tests/list/CMakeLists.txt | 6 +- src/tests/list_json/CMakeLists.txt | 40 +- src/tests/list_json/list_json.cpp | 5 +- src/tests/loader_test/CMakeLists.txt | 14 +- src/tests/loader_test/loader_test.cpp | 4 +- src/tests/loader_test/loader_test_utils.hpp | 2 +- .../loader_test/test_layers/CMakeLists.txt | 42 +- .../test_layers/XrApiLayer_test.def | 6 +- .../test_layers/XrApiLayer_test.expsym | 9 - .../loader_test/test_layers/layer_test.cpp | 47 +- .../loader_test/test_runtimes/CMakeLists.txt | 31 +- .../test_runtimes/runtime_test.cpp | 32 +- .../test_runtimes/test_runtime.def | 6 +- .../test_runtimes/test_runtime.expsym | 9 - src/version.cmake | 47 +- src/version.gradle | 26 +- 111 files changed, 4746 insertions(+), 2538 deletions(-) delete mode 100644 HOTFIX delete mode 100644 LICENSES/Zlib.txt delete mode 100644 changes/sdk/mr.2836.gl.1.md delete mode 100644 changes/sdk/mr.2836.gl.2.md delete mode 100644 changes/sdk/mr.2836.gl.md delete mode 100644 changes/sdk/mr.2840.gl.md delete mode 100644 changes/sdk/mr.414.gh.OpenXR-SDK-Source.md delete mode 100644 maintainer-scripts/publish-aar/gradlew.bat.license delete mode 100644 maintainer-scripts/publish-aar/gradlew.license delete mode 100755 specification/scripts/findBareNormatives.sh rename specification/scripts/{spec-macros.rb => openxr-macros.rb} (89%) rename specification/scripts/{spec-macros => openxr-macros}/extension.rb (52%) delete mode 100755 specification/scripts/reserve_extensions.py delete mode 100644 src/api_layers/XrApiLayer_api_dump.expsym delete mode 100644 src/api_layers/XrApiLayer_core_validation.expsym create mode 100644 src/external/earcut/include/earcut.hpp create mode 100644 src/external/earcut/include/earcut.hpp.license create mode 100644 src/external/span-lite/include/nonstd/span.hpp create mode 100644 src/external/type-lite/include/nonstd/type.hpp create mode 100644 src/loader/build.gradle delete mode 100644 src/loader/openxr-loader.expsym delete mode 100644 src/tests/hello_xr/gradlew.bat.license delete mode 100644 src/tests/hello_xr/gradlew.license delete mode 100644 src/tests/loader_test/test_layers/XrApiLayer_test.expsym delete mode 100644 src/tests/loader_test/test_runtimes/test_runtime.expsym diff --git a/.appveyor.yml b/.appveyor.yml index 36bd4b276..f9bae8e25 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: Apache-2.0 -version: 1.0.28.{build} +version: 1.0.27.{build} image: Visual Studio 2017 diff --git a/.gitattributes b/.gitattributes index dcddd89ad..892b854b9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -23,10 +23,7 @@ *.sh eol=lf *.png binary - -# git-lfs big files -*.pdf filter=lfs diff=lfs merge=lfs -text -*.glb filter=lfs diff=lfs merge=lfs -text +*.pdf binary # Shell/python scripts that don't end in .sh specification/makeAllExts eol=lf diff --git a/.github/scripts/CMakePresets.json b/.github/scripts/CMakePresets.json index 6b5467a58..884f9779c 100644 --- a/.github/scripts/CMakePresets.json +++ b/.github/scripts/CMakePresets.json @@ -65,31 +65,6 @@ "CMAKE_SYSTEM_NAME": "WindowsStore", "CMAKE_SYSTEM_VERSION": "10.0" } - }, - { - "name": ".base-cts-msvc", - "generator": "Visual Studio 17 2022", - "hidden": true, - "installDir": "$env{INSTALL_DIR}", - "cacheVariables": { - "DYNAMIC_LOADER": false, - "BUILD_ALL_EXTENSIONS": true - }, - "condition": { - "type": "equals", - "lhs": "${hostSystemName}", - "rhs": "Windows" - } - }, - { - "name": "cts-win32", - "inherits": ".base-cts-msvc", - "architecture": "Win32" - }, - { - "name": "cts-x64", - "inherits": ".base-cts-msvc", - "architecture": "x64" } ] } diff --git a/.github/scripts/shared.py b/.github/scripts/shared.py index c93035156..a4cd31a7f 100644 --- a/.github/scripts/shared.py +++ b/.github/scripts/shared.py @@ -3,7 +3,6 @@ import json import sys -import os from dataclasses import dataclass from itertools import product @@ -26,10 +25,6 @@ def should_skip(self) -> bool: # can switch to just doing x64 for speed of testing # return self.arch != "x64" - def has_cts_build(self) -> bool: - # No UWP CTS right now - return not self.uwp and not self.should_skip() - def preset(self) -> str: if self.uwp: return f"{self.arch.lower()}_uwp" @@ -39,9 +34,6 @@ def preset(self) -> str: def win_artifact_name(self) -> str: return f"loader_{self.preset()}" - def win_cts_artifact_name(self) -> str: - return f"loader_{self.preset()}" - def platform_dirname(self) -> str: if self.uwp: return f"{self.arch}_uwp" @@ -54,14 +46,9 @@ def platform_dirname(self) -> str: BUILD_CONFIGS = [c for c in _UNFILTERED_BUILD_CONFIGS if not c.should_skip()] -CTS_BUILD_CONFIGS = [c for c in _UNFILTERED_BUILD_CONFIGS if c.has_cts_build()] - def output_json(data, variable_name=None): if variable_name: - envfile = os.getenv("GITHUB_ENV") - assert envfile - with open(envfile, "w", encoding="utf-8") as fp: - fp.write(f"{variable_name}={json.dumps(data)}") + print(f"::set-output name={variable_name}::{json.dumps(data)}") else: print(json.dumps(data, indent=4)) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 2df431c54..522b9822d 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -25,7 +25,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Get modern CMake and Ninja - uses: lukka/get-cmake@v3.26.4 + uses: lukka/get-cmake@v3.25.2 - name: set up JDK 11 uses: actions/setup-java@v3 @@ -93,7 +93,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Get modern CMake and Ninja - uses: lukka/get-cmake@v3.26.4 + uses: lukka/get-cmake@v3.25.2 - name: set up JDK 11 uses: actions/setup-java@v3 with: diff --git a/.github/workflows/msvc-build-preset.yml b/.github/workflows/msvc-build-preset.yml index c427dca1c..bb01ca36b 100644 --- a/.github/workflows/msvc-build-preset.yml +++ b/.github/workflows/msvc-build-preset.yml @@ -1,4 +1,4 @@ -# Copyright 2021-2023, Collabora, Ltd. +# Copyright 2021-2022, Collabora, Ltd. # SPDX-License-Identifier: CC0-1.0 on: @@ -9,18 +9,13 @@ on: type: string required: true buildType: - description: "Build configuration" + description: "Build type" type: string - required: true default: RelWithDebInfo artifactName: description: "Artifact name to upload to." type: string required: false - subdir: - description: "Subdir of the workspace to upload as an artifact." - type: string - default: install jobs: msvc-build: @@ -30,18 +25,15 @@ jobs: INSTALL_DIR: "${{ github.workspace }}/install" steps: - uses: actions/checkout@v3 - - - name: Get modern CMake and Ninja - uses: lukka/get-cmake@v3.26.4 - + - uses: lukka/get-cmake@v3.25.2 - name: Add msbuild to PATH uses: microsoft/setup-msbuild@v1.3 - name: Install Vulkan SDK - run: ./.github/scripts/install_vulkan.ps1 - if: "${{ !contains( inputs.preset, 'uwp') }}" - working-directory: "${{ github.workspace }}" + if: ${{ !contains( inputs.preset, 'uwp') }} + working-directory: ${{ github.workspace }} shell: pwsh + run: ./.github/scripts/install_vulkan.ps1 - name: Generate build system shell: pwsh @@ -49,14 +41,14 @@ jobs: Copy-Item .github/scripts/CMakePresets.json . cmake --fresh --preset ${{ inputs.preset }} -S . -B $env:RUNNER_TEMP - name: Build - run: "cmake --build $env:RUNNER_TEMP --parallel --clean-first --config ${{ inputs.buildType }}" + run: cmake --build $env:RUNNER_TEMP --parallel --clean-first --config ${{ inputs.buildType }} - name: Install - run: "cmake --build $env:RUNNER_TEMP --parallel --config ${{ inputs.buildType }} --target install" + run: cmake --build $env:RUNNER_TEMP --parallel --config ${{ inputs.buildType }} --target install - name: Upload Artifacts uses: actions/upload-artifact@v3 if: inputs.artifactName with: - name: "${{ inputs.artifactName }}" - path: "${{ github.workspace }}/${{ inputs.subdir }}" + name: ${{ inputs.artifactName }} + path: ${{ github.workspace }}/install diff --git a/.github/workflows/windows-matrix.yml b/.github/workflows/windows-matrix.yml index 45a1458fe..578cc1a3a 100644 --- a/.github/workflows/windows-matrix.yml +++ b/.github/workflows/windows-matrix.yml @@ -1,4 +1,4 @@ -# Copyright 2021-2023, Collabora, Ltd. +# Copyright 2021-2022, Collabora, Ltd. # SPDX-License-Identifier: CC0-1.0 name: Windows builds @@ -12,34 +12,24 @@ on: workflow_dispatch: jobs: - # generate_matrix: - # runs-on: ubuntu-latest - # outputs: - # matrix: "${{ steps.set-matrix.outputs.matrix }}" - # steps: - # - uses: "actions/checkout@v3" - # - id: set-matrix - # run: "python3 .github/scripts/generate_windows_matrix_build.py matrix" + generate_matrix: + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + steps: + - uses: actions/checkout@v3 + - id: set-matrix + run: python3 .github/scripts/generate_windows_matrix_build.py matrix msvc-build: - # needs: generate_matrix + needs: generate_matrix strategy: fail-fast: true - # TODO: Fix matrix generation? Broke recently due to changes in github actions - # matrix: "${{fromJson(needs.generate_matrix.outputs.matrix)}}" - matrix: - preset: - - win32 - - x64 - - win32_uwp - - x64_uwp - - arm64_uwp - - arm_uwp + matrix: ${{fromJson(needs.generate_matrix.outputs.matrix)}} - uses: "./.github/workflows/msvc-build-preset.yml" + uses: ./.github/workflows/msvc-build-preset.yml with: - preset: "${{ matrix.preset }}" + preset: ${{ matrix.preset }} artifactName: "loader_${{ matrix.preset }}" - buildType: "RelWithDebInfo" organize-and-release-artifacts: if: inputs.organizeAndRelease @@ -47,18 +37,18 @@ jobs: - msvc-build runs-on: ubuntu-latest steps: - - uses: "actions/checkout@v3" + - uses: actions/checkout@v3 - name: Retrieve artifacts - uses: "actions/download-artifact@v3" + uses: actions/download-artifact@v3 with: path: artifacts - name: Organize artifacts - run: 'python .github/scripts/organize_windows_artifacts.py "${{ github.workspace }}" "${{ github.workspace }}/openxr_loader"' + run: python .github/scripts/organize_windows_artifacts.py "${{ github.workspace }}" "${{ github.workspace }}/openxr_loader" - name: Upload combined artifact - uses: "actions/upload-artifact@v3" + uses: actions/upload-artifact@v3 with: name: openxr_loader_windows path: "${{ github.workspace }}/openxr_loader" @@ -66,19 +56,18 @@ jobs: # NuGet stuff now - name: Setup NuGet - uses: "NuGet/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f" + uses: NuGet/setup-nuget@v1 with: nuget-version: "5.x" - - name: Stage loader and headers for NuGet shell: pwsh - run: '${{ github.workspace }}/.azure-pipelines/nuget/stage_nuget.ps1 "${{ github.workspace }}/openxr_loader" "${{ github.workspace }}/specification/Makefile" "${{ github.workspace }}/openxr_loader_staging"' + run: ${{ github.workspace }}/.azure-pipelines/nuget/stage_nuget.ps1 "${{ github.workspace }}/openxr_loader" "${{ github.workspace }}/specification/Makefile" "${{ github.workspace }}/openxr_loader_staging" - name: Pack NuGet package - run: 'nuget pack "${{ github.workspace }}/openxr_loader_staging/OpenXR.Loader.nuspec" -OutputDirectory "${{ github.workspace }}/nuget"' + run: nuget pack ${{ github.workspace }}/openxr_loader_staging/OpenXR.Loader.nuspec -OutputDirectory ${{ github.workspace }}/nuget - name: Upload NuGet artifact - uses: "actions/upload-artifact@v3" + uses: actions/upload-artifact@v3 with: name: NuGet path: "${{ github.workspace }}/nuget" diff --git a/.gitignore b/.gitignore index 13a23f162..03c1a0d79 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,6 @@ pregen/ generated-includes cmake_install.cmake cmake_uninstall.cmake -cmake-build-* # Marker file for a snapshot build SNAPSHOT diff --git a/.reuse/dep5 b/.reuse/dep5 index cefd07650..c4426f94d 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -4,7 +4,6 @@ Upstream-Contact: Ryan Pavlik Source: https://khronos.org/registry/OpenXR/ Files: changes/* - HOTFIX Copyright: 2019-2023, The Khronos Group Inc. License: CC-BY-4.0 @@ -39,27 +38,6 @@ Copyright: 2007-2010 Baptiste Lepilleur and The JsonCpp Authors License: MIT OR LicenseRef-jsoncpp-public-domain Comment: Unmodified, vendored copy of jsoncpp 1.9.5 -Files: src/external/tinygltf/* -Copyright: 2017 Syoyo Fujita, Aurélien Chatelain and many contributors -License: MIT -Comment: Unmodified, vendored copy of a subset of the tiny-gltf repo v2.8.9 - -Files: src/external/tinygltf/json.hpp -Copyright: 2013-2017 Niels Lohmann -License: MIT -Comment: Unmodified, included in tiny-gltf repo. - -Files: src/external/d3dx12/* -Copyright: Copyright (c) Microsoft Corporation. -License: MIT -Comment: Unmodified, vendored copy of DirectX-Headers commit da7aedb - of https://github.com/microsoft/DirectX-Headers filtered to just d3dx12 headers - -Files: src/external/mikktspace/* -Copyright: 2011 by Morten S. Mikkelsen -License: Zlib -Comment: Unmodified, vendored copy of MikkTSpace commit 3e895b4 - Files: src/external/jnipp/* Copyright: 2016-2020, Mitchell Dowd 2020, Collabora, Ltd. @@ -89,7 +67,7 @@ Comment: In-line license comments requested, https://gitlab.khronos.org/openxr/o Files: specification/sources/chapters/extensions/ext/ext_performance_settings.adoc specification/sources/chapters/extensions/ext/ext_thermal_query.adoc -Copyright: 2017-2023, The Khronos Group Inc. +Copyright: 2017-2020, The Khronos Group Inc. License: CC-BY-4.0 Comment: In-line license comments requested, https://gitlab.khronos.org/openxr/openxr/-/issues/1419 @@ -98,7 +76,7 @@ Files: src/conformance/platform_specific/android_resources/mipmap-hdpi/* src/conformance/platform_specific/android_resources/mipmap-xhdpi/* src/conformance/platform_specific/android_resources/mipmap-xxhdpi/* src/conformance/platform_specific/android_resources/mipmap-xxxhdpi/* -Copyright: 2020-2023, The Khronos Group Inc. +Copyright: 2020, The Khronos Group Inc. 2020, Google License: Apache-2.0 Comment: Generated .png versions of an icon, created in Android Studio diff --git a/BUILDING.md b/BUILDING.md index aa2a87c2f..c3a61e6e4 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -142,21 +142,6 @@ cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ../.. make ``` -### macOS - -Building the OpenXR components in this tree on macOS is supported using Xcode -14.0 and newer. You may need to install Xcode Command Line Tools and cmake. - -First, generate the Xcode project file using CMake: - -```cmd -mkdir -p build/macos -cd build/macos -cmake -G "Xcode" ../.. -``` - -Finally, open the build/macos/OPENXR.xcodeproj in Xcode to build the samples. - ### Android ```sh diff --git a/CHANGELOG.SDK.md b/CHANGELOG.SDK.md index babc1ca1a..6f31c2ffd 100644 --- a/CHANGELOG.SDK.md +++ b/CHANGELOG.SDK.md @@ -19,152 +19,6 @@ along with any public pull requests that have been accepted. In this repository in particular, since it is primarily software, pull requests may be integrated as they are accepted even between periodic updates. -## OpenXR SDK 1.0.28 (2023-07-10) - -This release contains improved compatibility and code quality fixes for the -loader, support for loading certain API layers on Android-based devices, and a -number of other improvements, in addition to the new extensions. Additionally, -the loader documentation now describes how OpenXR handles compatibility with -Android API levels of 30 and above: runtimes may need to update accordingly to -support this compatibility solution. - -- **OpenXR SDK 1.0.28.2** hotfix release includes the following fixes - - Loader spec: Fix description of `` element contents: existing - description would fail to install. - ([internal MR 2840](https://gitlab.khronos.org/openxr/openxr/merge_requests/2840), - [internal issue 2053](https://gitlab.khronos.org/openxr/openxr/issues/2053)) - - Android AAR artifacts (loader) and hello_xr: Fix `` element contents. - ([internal MR 2840](https://gitlab.khronos.org/openxr/openxr/merge_requests/2840), - [internal issue 2053](https://gitlab.khronos.org/openxr/openxr/issues/2053)) - - Android AAR artifacts: Fix C++ standard library selection for Android artifacts - in `build-aar.sh` - ([internal MR 2836](https://gitlab.khronos.org/openxr/openxr/merge_requests/2836), - [internal issue 2052](https://gitlab.khronos.org/openxr/openxr/issues/2052)) - - Android AAR artifacts: Use `jar` instead of 7-zip to perform archiving, and - document requirements in `build-aar.sh` - ([internal MR 2836](https://gitlab.khronos.org/openxr/openxr/merge_requests/2836), - [OpenXR-SDK-Source issue 303](https://github.com/KhronosGroup/OpenXR-SDK-Source/issues/303), - [internal issue 1711](https://gitlab.khronos.org/openxr/openxr/issues/1711)) - - build system: Support SDK hotfix versions (fourth version component). - ([internal MR 2836](https://gitlab.khronos.org/openxr/openxr/merge_requests/2836)) -- **OpenXR SDK 1.0.28.1** hotfix release includes the following fix - - API dump layer: Fix build on Windows on ARM64. - ([OpenXR-SDK-Source PR 414](https://github.com/KhronosGroup/OpenXR-SDK-Source/pull/414)) -- Registry - - Added defines to `xr.xml` for extension enum base and enum stride. - ([internal MR 2693](https://gitlab.khronos.org/openxr/openxr/merge_requests/2693), - [OpenXR-Docs issue 148](https://github.com/KhronosGroup/OpenXR-Docs/issues/148), - [internal issue 1979](https://gitlab.khronos.org/openxr/openxr/issues/1979)) - - Extension reservation: Reserve an extension for `XR_EXT_future` - ([internal MR 2631](https://gitlab.khronos.org/openxr/openxr/merge_requests/2631)) - - Extension reservation: Register `ANDROID` author ID and reserve 15 extensions - for it. - ([internal MR 2690](https://gitlab.khronos.org/openxr/openxr/merge_requests/2690)) - - Extension reservation: Reserve extensions for "user presence" and "locate - spaces" - ([internal MR 2705](https://gitlab.khronos.org/openxr/openxr/merge_requests/2705)) - - Extension reservation: Reserve 25 extensions for Magic Leap. - ([internal MR 2778](https://gitlab.khronos.org/openxr/openxr/merge_requests/2778)) - - Extension reservation: Reserve extension for `XR_KHR_extendable_action_binding` - ([internal MR 2779](https://gitlab.khronos.org/openxr/openxr/merge_requests/2779)) - - Fix spelling. - ([internal MR 2766](https://gitlab.khronos.org/openxr/openxr/merge_requests/2766)) - - Fixed the error code specification for `xrGetControllerModelPropertiesMSFT` - function. - ([internal MR 2600](https://gitlab.khronos.org/openxr/openxr/merge_requests/2600)) - - New multi-vendor extension: `XR_EXT_hand_interaction` - ([internal MR 2116](https://gitlab.khronos.org/openxr/openxr/merge_requests/2116)) - - New multi-vendor extension: `XR_EXT_plane_detection` - ([internal MR 2510](https://gitlab.khronos.org/openxr/openxr/merge_requests/2510), - [internal MR 2791](https://gitlab.khronos.org/openxr/openxr/merge_requests/2791)) - - New multi-vendor extension: `XR_EXT_hand_tracking_data_source` - ([internal MR 2568](https://gitlab.khronos.org/openxr/openxr/merge_requests/2568)) - - New vendor extension: `XR_META_passthrough_color_lut` - ([internal MR 2507](https://gitlab.khronos.org/openxr/openxr/merge_requests/2507)) - - New vendor extension: `XR_META_virtual_keyboard` - ([internal MR 2555](https://gitlab.khronos.org/openxr/openxr/merge_requests/2555)) - - New vendor extension: `XR_OPPO_controller_interaction` - ([OpenXR-Docs PR 146](https://github.com/KhronosGroup/OpenXR-Docs/pull/146)) - - Update Magic Leap contact - ([internal MR 2699](https://gitlab.khronos.org/openxr/openxr/merge_requests/2699)) - - `XR_FB_face_tracking`: Non-functional registry change, fixing a problem with - standalone headers. - ([internal MR 2663](https://gitlab.khronos.org/openxr/openxr/merge_requests/2663)) - - `XR_FB_scene`: Introduce `XrSemanticLabelsSupportInfoFB` and bump spec version - to 3. - ([internal MR 2682](https://gitlab.khronos.org/openxr/openxr/merge_requests/2682)) - - `XR_FB_spatial_entity` and `XR_FB_scene`: Add `XR_ERROR_SIZE_INSUFFICIENT` - return code to functions which use the two-call idiom. - ([internal MR 2718](https://gitlab.khronos.org/openxr/openxr/merge_requests/2718)) - - `XR_FB_touch_controller_pro`: Fix XML to require the `touch_controller_pro` - interaction profile for the extension - ([internal MR 2806](https://gitlab.khronos.org/openxr/openxr/merge_requests/2806)) - - registry: Remove extraneous whitespace from some commands. - ([OpenXR-SDK-Source PR 397](https://github.com/KhronosGroup/OpenXR-SDK-Source/pull/397)) - - schematron: Improve self tests. - ([internal MR 2680](https://gitlab.khronos.org/openxr/openxr/merge_requests/2680)) - - schematron: Require vendor tag on interaction profile paths introduced by - extensions. - ([internal MR 2684](https://gitlab.khronos.org/openxr/openxr/merge_requests/2684)) - - scripts: Allow schematron to check an alternate XML file. - ([internal MR 2670](https://gitlab.khronos.org/openxr/openxr/merge_requests/2670)) -- SDK - - Allow compilation of OpenXR SDK on Mac - ([internal MR 2788](https://gitlab.khronos.org/openxr/openxr/merge_requests/2788), - [internal MR 2789](https://gitlab.khronos.org/openxr/openxr/merge_requests/2789), - [internal MR 2790](https://gitlab.khronos.org/openxr/openxr/merge_requests/2790), - [internal MR 2800](https://gitlab.khronos.org/openxr/openxr/merge_requests/2800)) - - Common: Add `stdint.h` include to `platform_utils.hpp` for GCC 13+ - ([OpenXR-SDK-Source PR 406](https://github.com/KhronosGroup/OpenXR-SDK-Source/pull/406)) - - Describe building OpenXR SDK on macOS with Xcode - ([internal MR 2768](https://gitlab.khronos.org/openxr/openxr/merge_requests/2768)) - - Handle clang-format-16 in `runClangFormat.sh`, and adjust source files so its - output matches the earlier version used on CI. - ([internal MR 2666](https://gitlab.khronos.org/openxr/openxr/merge_requests/2666), - [internal MR 2814](https://gitlab.khronos.org/openxr/openxr/merge_requests/2814)) - - Improvement: Fix clang warning `-Wundef`. - ([internal MR 2717](https://gitlab.khronos.org/openxr/openxr/merge_requests/2717)) - - Improvement: Fix leftover warnings when building with `-Wall`. - ([internal MR 2754](https://gitlab.khronos.org/openxr/openxr/merge_requests/2754), - [OpenXR-SDK-Source PR 410](https://github.com/KhronosGroup/OpenXR-SDK-Source/pull/410)) - - Loader: On Android, use a single logcat tag for all parts of the loader. - ([internal MR 2688](https://gitlab.khronos.org/openxr/openxr/merge_requests/2688)) - - Loader: Update the required `queries` elements for an OpenXR application on - Android, so that runtime and layer components loaded in the application process - may access their own package in API >29. - ([internal MR 2708](https://gitlab.khronos.org/openxr/openxr/merge_requests/2708)) - - Loader: Search system directories for API layer manifests on Android - ([internal MR 2709](https://gitlab.khronos.org/openxr/openxr/merge_requests/2709)) - - Loader: Add Product and OEM partition to active runtime search path on Android - ([internal MR 2709](https://gitlab.khronos.org/openxr/openxr/merge_requests/2709)) - - Loader: Improve casting to `uint32_t` edge case handling. - ([internal MR 2745](https://gitlab.khronos.org/openxr/openxr/merge_requests/2745)) - - Loader: Clear possible dangling `next` pointers in `XR_EXT_debug_utils` label - structures. - ([internal MR 2764](https://gitlab.khronos.org/openxr/openxr/merge_requests/2764)) - - Validation Layer: Fix the validation_layer_generator to not check static array - addresses. - ([OpenXR-SDK-Source PR 399](https://github.com/KhronosGroup/OpenXR-SDK-Source/pull/399)) - - api_layers: Update API Layers spec section in README.md - ([internal MR 2753](https://gitlab.khronos.org/openxr/openxr/merge_requests/2753)) - - cmake: Set up alias targets `OpenXR::openxr_loader` and `OpenXR::headers` so - that the loader and headers may be used the same whether you used - `find_package(OpenXR)` on binaries or have included the source tree as a - subproject. - ([internal MR 2793](https://gitlab.khronos.org/openxr/openxr/merge_requests/2793)) - - gradle: Add license for gradlew and gradlew.bat - ([internal MR 2725](https://gitlab.khronos.org/openxr/openxr/merge_requests/2725)) - - gradle: General cleanup and updates of Android build system. - ([internal MR 2796](https://gitlab.khronos.org/openxr/openxr/merge_requests/2796)) - - hello_xr: Enable building with latest Android Studio canary - ([OpenXR-SDK-Source PR 393](https://github.com/KhronosGroup/OpenXR-SDK-Source/pull/393)) - - layers: Code cleanup and calling convention fixes - ([internal MR 2784](https://gitlab.khronos.org/openxr/openxr/merge_requests/2784)) - - loader test: Fix for Windows 32-bit - ([internal MR 2784](https://gitlab.khronos.org/openxr/openxr/merge_requests/2784)) - - loader test: Fix CMake dependencies. - ([internal MR 2776](https://gitlab.khronos.org/openxr/openxr/merge_requests/2776)) - ## OpenXR SDK 1.0.27 (2023-03-21) This release contains a large list of improvements, including interaction diff --git a/CMakeLists.txt b/CMakeLists.txt index 43ab332be..44255b71d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,8 +33,6 @@ set(LOADER_FOLDER "Loader") set(HELPER_FOLDER "Helpers") set(CODEGEN_FOLDER "Generated") set(TESTS_FOLDER "Tests") -set(CONFORMANCE_TESTS_FOLDER "Conformance Test Suite") -set(LOADER_TESTS_FOLDER "Loader Tests") set(API_LAYERS_FOLDER "Layers") set(SAMPLES_FOLDER "Samples") diff --git a/HOTFIX b/HOTFIX deleted file mode 100644 index 0cfbf0888..000000000 --- a/HOTFIX +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/LICENSES/Zlib.txt b/LICENSES/Zlib.txt deleted file mode 100644 index e0e3605ba..000000000 --- a/LICENSES/Zlib.txt +++ /dev/null @@ -1,11 +0,0 @@ -zlib License - -This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source distribution. diff --git a/changes/sdk/mr.2836.gl.1.md b/changes/sdk/mr.2836.gl.1.md deleted file mode 100644 index 67e6433b6..000000000 --- a/changes/sdk/mr.2836.gl.1.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -- issue.2052.gl ---- -Android AAR artifacts: Fix C++ standard library selection for Android artifacts in `build-aar.sh` diff --git a/changes/sdk/mr.2836.gl.2.md b/changes/sdk/mr.2836.gl.2.md deleted file mode 100644 index 143a7d19b..000000000 --- a/changes/sdk/mr.2836.gl.2.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -- issue.303.gh.OpenXR-SDK-Source -- issue.1711.gl ---- -- Android AAR artifacts: Use `jar` instead of 7-zip to perform archiving, and document requirements in `build-aar.sh` diff --git a/changes/sdk/mr.2836.gl.md b/changes/sdk/mr.2836.gl.md deleted file mode 100644 index c87e8a882..000000000 --- a/changes/sdk/mr.2836.gl.md +++ /dev/null @@ -1 +0,0 @@ -- build system: Support SDK hotfix versions (fourth version component). diff --git a/changes/sdk/mr.2840.gl.md b/changes/sdk/mr.2840.gl.md deleted file mode 100644 index 6b00c228b..000000000 --- a/changes/sdk/mr.2840.gl.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -- issue.2053.gl ---- -- Android AAR artifacts (loader) and hello_xr: Fix `` element contents. diff --git a/changes/sdk/mr.414.gh.OpenXR-SDK-Source.md b/changes/sdk/mr.414.gh.OpenXR-SDK-Source.md deleted file mode 100644 index 32614d817..000000000 --- a/changes/sdk/mr.414.gh.OpenXR-SDK-Source.md +++ /dev/null @@ -1 +0,0 @@ -API dump layer: Fix build on Windows on ARM64. diff --git a/include/openxr/openxr_platform_defines.h b/include/openxr/openxr_platform_defines.h index 820b7b3e1..9573c101e 100644 --- a/include/openxr/openxr_platform_defines.h +++ b/include/openxr/openxr_platform_defines.h @@ -103,10 +103,6 @@ typedef unsigned __int64 uint64_t; #endif #endif -#if !defined(XR_CPP_NULLPTR_SUPPORTED) -#define XR_CPP_NULLPTR_SUPPORTED 0 -#endif // !defined(XR_CPP_NULLPTR_SUPPORTED) - #ifdef __cplusplus } #endif diff --git a/maintainer-scripts/build-aar.sh b/maintainer-scripts/build-aar.sh index 867407464..f7bae8bbe 100755 --- a/maintainer-scripts/build-aar.sh +++ b/maintainer-scripts/build-aar.sh @@ -1,64 +1,30 @@ #!/usr/bin/env bash -# Copyright (c) 2020-2023 Collabora, Ltd. +# Copyright (c) 2020-2022 Collabora, Ltd. # # SPDX-License-Identifier: Apache-2.0 -# Builds the .aar Android prefab artifact for the OpenXR Loader. -# Depends on the tools `cmake`, `ninja`, and `jar` (usually shipped with your JDK) -# in addition to an Android NDK. -# -# Requires that ANDROID_NDK_HOME be set in the environment. -# Pass the argument "clean" to wipe build directories before building. -# -# Touch a file named SNAPSHOT in the root directory to -# make a version suffixed with -SNAPSHOT - set -e - -logMsg() { - echo - echo "**** $1" - echo -} - ROOT=$(cd "$(dirname "$0")" && cd .. && pwd) OPENXR_ANDROID_VERSION_SUFFIX= if [ -f "${ROOT}/SNAPSHOT" ]; then OPENXR_ANDROID_VERSION_SUFFIX=-SNAPSHOT - logMsg "Building a -SNAPSHOT version" + echo "Building a -SNAPSHOT version" fi BUILD_DIR=${BUILD_DIR:-${ROOT}/build-android} INSTALL_DIR=${INSTALL_DIR:-${ROOT}/build-android-install} -ANDROID_STL=c++_static +ANDROID_STL=$(grep ext.stl "${ROOT}/src/loader/build.gradle" | sed -E 's/.*"(.*)"/\1/') CONFIG=Release ANDROID_PLATFORM=24 -logMsg "ANDROID_NDK_HOME: ${ANDROID_NDK_HOME}" -logMsg "ANDROID_STL: ${ANDROID_STL}" -logMsg "CONFIG: ${CONFIG}" -logMsg "ANDROID_PLATFORM: ${ANDROID_PLATFORM}" - -logMsg "BUILD_DIR: ${BUILD_DIR}" -logMsg "INSTALL_DIR: ${INSTALL_DIR}" - -logMsg "Wiping install staging dir" rm -rf "${INSTALL_DIR}" - -if [ "$1" = "clean" ]; then - logMsg "Wiping build dir completely" - rm -rf "${BUILD_DIR}" -fi - if [ -d "${BUILD_DIR}" ]; then - logMsg "Removing POM files from build dir" find "${BUILD_DIR}" -name "*.pom" -delete fi for arch in x86 x86_64 armeabi-v7a arm64-v8a; do - logMsg "Configuring and building for arch ${arch}" cmake -S "${ROOT}" \ -B "${BUILD_DIR}/${arch}" \ -G Ninja \ @@ -78,23 +44,16 @@ for arch in x86 x86_64 armeabi-v7a arm64-v8a; do ninja -C "${BUILD_DIR}/${arch}" - logMsg "Installing for arch ${arch}" - for comp in License Headers Loader Prefab; do - # Component-wise install of the build, since we do not want all components cmake -DCMAKE_INSTALL_COMPONENT=${comp} -P "${BUILD_DIR}/${arch}/cmake_install.cmake" done done - -# The name of the POM file that CMake made with our decorated version number DECORATED=$(cd "${BUILD_DIR}/x86/src/loader" && ls openxr_loader*.pom) cp "${BUILD_DIR}/x86/src/loader/${DECORATED}" . DIR=$(pwd) ( - logMsg "Packing AAR file" cd "$INSTALL_DIR/openxr" - AARFILE="$DIR/${DECORATED%.pom}.aar" - jar --create --file="${AARFILE}" ./* - logMsg "AAR file created: ${AARFILE}" + 7za a -r ../openxr.zip ./* + mv ../openxr.zip "$DIR/${DECORATED%.pom}.aar" ) diff --git a/maintainer-scripts/build-and-publish-aar-mavencentral.sh b/maintainer-scripts/build-and-publish-aar-mavencentral.sh index 1568b2fc3..5fd7dbd54 100755 --- a/maintainer-scripts/build-and-publish-aar-mavencentral.sh +++ b/maintainer-scripts/build-and-publish-aar-mavencentral.sh @@ -3,8 +3,8 @@ # # SPDX-License-Identifier: Apache-2.0 set -e -MAINT_SCRIPTS=$(cd "$(dirname "$0")" && pwd) -ROOT=$(cd "$(dirname "$0")" && cd .. && pwd) +MAINT_SCRIPTS=$(cd $(dirname $0) && pwd) +ROOT=$(cd $(dirname $0) && cd .. && pwd) # This file would tell the build scripts to append -SNAPSHOT to the version, make sure it's not there. rm -f "${ROOT}/SNAPSHOT" diff --git a/maintainer-scripts/build-and-publish-aar-snapshot.sh b/maintainer-scripts/build-and-publish-aar-snapshot.sh index 1cf58754b..9c670e81e 100755 --- a/maintainer-scripts/build-and-publish-aar-snapshot.sh +++ b/maintainer-scripts/build-and-publish-aar-snapshot.sh @@ -3,8 +3,8 @@ # # SPDX-License-Identifier: Apache-2.0 set -e -MAINT_SCRIPTS=$(cd "$(dirname "$0")" && pwd) -ROOT=$(cd "$(dirname "$0")" && cd .. && pwd) +MAINT_SCRIPTS=$(cd $(dirname $0) && pwd) +ROOT=$(cd $(dirname $0) && cd .. && pwd) # This file tells the build scripts to append -SNAPSHOT to the version. touch "${ROOT}/SNAPSHOT" diff --git a/maintainer-scripts/common.sh b/maintainer-scripts/common.sh index 370432238..6dac4c02b 100644 --- a/maintainer-scripts/common.sh +++ b/maintainer-scripts/common.sh @@ -193,26 +193,13 @@ getSDKSourceFilenames() { specification/Makefile \ specification/README.md \ specification/requirements.txt \ - src/.clang-format \ - src/.gitignore \ - src/CMakeLists.txt \ - src/api_layers \ - src/cmake \ - src/common \ - src/common_config.h.in \ - src/external/CMakeLists.txt \ - src/external/android-jni-wrappers \ - src/external/jnipp \ - src/external/jsoncpp \ - src/loader \ - src/scripts \ - src/tests \ - src/version.cmake \ - src/version.gradle \ + src/ \ | grep -v "${COMMON_EXCLUDE_PATTERN}" \ | grep -v "conformance" \ | grep -v "template_gen_dispatch" \ + | grep -v "catch2" \ | grep -v "function_info" \ + | grep -v "stb" \ | grep -v "htmldiff" \ | grep -v "katex" } @@ -237,17 +224,17 @@ getSDKFilenames() { .github/workflows/windows-matrix.yml \ specification/registry/*.xml \ include/ \ - src/.clang-format \ src/CMakeLists.txt \ - src/cmake \ - src/common \ + src/version.cmake \ src/common_config.h.in \ + src/common \ + src/cmake \ + src/loader \ src/external/CMakeLists.txt \ - src/external/android-jni-wrappers \ - src/external/jnipp \ src/external/jsoncpp \ - src/loader \ - src/version.cmake \ + src/external/jnipp \ + src/external/android-jni-wrappers \ + src/.clang-format \ | grep -v "${COMMON_EXCLUDE_PATTERN}" \ | grep -v "gfxwrapper" \ | grep -v "include/.gitignore" \ @@ -275,14 +262,12 @@ getConformanceFilenames() { .azure-pipelines/openxr-cts.yml \ .github/dependabot.yml \ .github/scripts \ - .github/workflows/android-cts-build.yml \ .github/workflows/android-cts-pr.yml \ .github/workflows/android-cts-release.yml \ .github/workflows/check_clang_format_and_codespell.yml \ .github/workflows/gradle-wrapper-validation.yml \ .github/workflows/msvc-build-preset.yml \ - .github/workflows/windows-cts-pr.yml \ - .github/workflows/windows-cts-release.yml \ + .github/workflows/windows-matrix.yml \ changes/README.md \ changes/template.md \ changes/.markdownlint.yaml \ @@ -300,18 +285,18 @@ getConformanceFilenames() { specification/Makefile \ specification/README.md \ specification/requirements.txt \ - src/.clang-format \ - src/.gitignore \ - src/CMakeLists.txt \ + src/version.gradle \ src/cmake \ src/common \ - src/common_config.h.in \ src/conformance \ src/external \ src/loader \ src/scripts \ + src/.clang-format \ + src/.gitignore \ + src/CMakeLists.txt \ + src/common_config.h.in \ src/version.cmake \ - src/version.gradle \ | grep -v "${COMMON_EXCLUDE_PATTERN}" \ | grep -v "htmldiff" \ | grep -v "katex" diff --git a/maintainer-scripts/publish-aar/gradlew b/maintainer-scripts/publish-aar/gradlew index 4f906e0c8..0614c4cec 100755 --- a/maintainer-scripts/publish-aar/gradlew +++ b/maintainer-scripts/publish-aar/gradlew @@ -3,6 +3,8 @@ # # Copyright 2015 the original author or authors. # +# 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 diff --git a/maintainer-scripts/publish-aar/gradlew.bat b/maintainer-scripts/publish-aar/gradlew.bat index 107acd32c..5688f0f67 100644 --- a/maintainer-scripts/publish-aar/gradlew.bat +++ b/maintainer-scripts/publish-aar/gradlew.bat @@ -1,6 +1,8 @@ @rem @rem Copyright 2015 the original author or authors. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at diff --git a/maintainer-scripts/publish-aar/gradlew.bat.license b/maintainer-scripts/publish-aar/gradlew.bat.license deleted file mode 100644 index a6bf97621..000000000 --- a/maintainer-scripts/publish-aar/gradlew.bat.license +++ /dev/null @@ -1,2 +0,0 @@ -SPDX-FileCopyrightText: Copyright 2015 the original author or authors. -SPDX-License-Identifier: Apache-2.0 diff --git a/maintainer-scripts/publish-aar/gradlew.license b/maintainer-scripts/publish-aar/gradlew.license deleted file mode 100644 index 69286a081..000000000 --- a/maintainer-scripts/publish-aar/gradlew.license +++ /dev/null @@ -1,2 +0,0 @@ -SPDX-FileCopyrightText: Copyright 2015-2021 the original author or authors. -SPDX-License-Identifier: Apache-2.0 diff --git a/runClangFormat.sh b/runClangFormat.sh index 2fb98a752..49eb9e65b 100755 --- a/runClangFormat.sh +++ b/runClangFormat.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash # Copyright (c) 2017-2023, The Khronos Group Inc. # # SPDX-License-Identifier: Apache-2.0 @@ -18,11 +18,11 @@ set -e ( PREFERRED_CLANG_FORMAT=clang-format-10 - ACCEPTABLE_CLANG_FORMATS="${PREFERRED_CLANG_FORMAT} clang-format-11 clang-format-12 clang-format-13 clang-format-14 clang-format-15 clang-format-16 clang-format" - cd "$(dirname "$0")" + ACCEPTABLE_CLANG_FORMATS="${PREFERRED_CLANG_FORMAT} clang-format-11 clang-format-12 clang-format-13 clang-format-14 clang-format-15 clang-format" + cd "$(dirname $0)" if [ ! "${CLANGFORMAT}" ]; then for tool in ${ACCEPTABLE_CLANG_FORMATS}; do - if which "$tool" > /dev/null 2> /dev/null; then + if which $tool > /dev/null 2> /dev/null; then CLANGFORMAT=$tool break fi @@ -42,6 +42,6 @@ set -e -and -not \( -wholename ./src/external/\* \) \ -and -not \( -wholename ./src/scripts/\* \) \ -and \( -name \*.hpp -or -name \*.h -or -name \*.cpp -or -name \*.c \) \ - -exec "${CLANGFORMAT}" -i -style=file {} + + -exec ${CLANGFORMAT} -i -style=file {} + ) diff --git a/specification/Makefile b/specification/Makefile index 5b69343df..16320e882 100644 --- a/specification/Makefile +++ b/specification/Makefile @@ -32,7 +32,7 @@ ifneq (,$(strip $(VERY_STRICT))) ASCIIDOC := $(ASCIIDOC) --failure-level WARN endif -SPECREVISION = 1.0.28 +SPECREVISION = 1.0.27 REVISION_COMPONENTS = $(subst ., ,$(SPECREVISION)) MAJORMINORVER = $(word 1,$(REVISION_COMPONENTS)).$(word 2,$(REVISION_COMPONENTS)) @@ -53,8 +53,7 @@ GENOPTS = SCRIPTS := ./scripts SPECTOOLS := $(SCRIPTS)/spec_tools -PYAPIMAP := $(GENDIR)/apimap.py -RBAPIMAP := $(GENDIR)/apimap.rb +XRAPI := $(GENDIR)/apimap.py METADIR := $(GENDIR)/meta VK_REF_PAGE_ROOT := https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html @@ -182,7 +181,7 @@ GENSTAMPS := \ $(METADIR)/extinc \ # The actual generated index -GENDEPENDS := $(PYAPIMAP) $(RBAPIMAP) $(GENSTAMPS) $(GENDIR)/index.adoc +GENDEPENDS := $(XRAPI) $(GENSTAMPS) $(GENDIR)/index.adoc # The rule for every genxr-generated file $(GENDEPENDS) $(GENHEADERS): $(BASIC_GENERATED_DEPENDS) @@ -195,10 +194,9 @@ $(GENDEPENDS) $(GENHEADERS): $(BASIC_GENERATED_DEPENDS) $(GENSTAMPS): STAMP_NOTE = (and additional files in $(@D)) # Extra deps -$(GENDIR)/api/apiinc: $(PYAPIMAP) $(SCRIPTS)/docgenerator.py +$(GENDIR)/api/apiinc: $(XRAPI) $(SCRIPTS)/docgenerator.py $(GENDIR)/validity/validinc: $(SCRIPTS)/validitygenerator.py $(SPECTOOLS)/validity.py $(SPECTOOLS)/attributes.py $(SPECTOOLS)/data_structures.py -$(PYAPIMAP): $(SCRIPTS)/pygenerator.py $(SCRIPTS)/docgenerator.py -$(RBAPIMAP): $(SCRIPTS)/rubygenerator.py $(SCRIPTS)/docgenerator.py +$(XRAPI): $(SCRIPTS)/pygenerator.py $(SCRIPTS)/docgenerator.py $(GENHEADERS): $(SCRIPTS)/cgenerator.py $(REFLECTHEADERS): $(SCRIPTS)/creflectiongenerator.py $(SCRIPTS)/jinja_helpers.py $(wildcard $(SCRIPTS)/template_*) @@ -229,7 +227,7 @@ extinc: $(METADIR)/extinc # The actual generated include files GENINCLUDE = $(GENAPI) $(GENVALIDITY) $(GENSYNC) $(GENMETA) .PHONY: generated -generated: $(GENDEPENDS) +generated: $(GENDEPENDS) $(XRAPI) ################################################ # OpenXR Style Guide @@ -248,7 +246,7 @@ ASCIIDOCTOR_TARGETS += $(STYLEGUIDE) # Target-specific variables and deps customizing the AsciiDoctor rule $(STYLEGUIDE): SPECSRC=$(STYLESRC) $(STYLEGUIDE): LOGFILE=$(OUTDIR)/adoc_styleguide_stderr.txt -$(STYLEGUIDE): $(STYLESRC) $(STYLEFILES) $(GENDIR)/validity/validinc $(GENDIR)/api/apiinc $(RBAPIMAP) +$(STYLEGUIDE): $(STYLESRC) $(STYLEFILES) $(GENDIR)/validity/validinc $(GENDIR)/api/apiinc ################################################ @@ -266,7 +264,7 @@ ASCIIDOCTOR_TARGETS += $(LOADERGUIDE) # Target-specific variables and deps customizing the AsciiDoctor rule $(LOADERGUIDE): SPECSRC=$(LOADERSRC) $(LOADERGUIDE): LOGFILE=$(OUTDIR)/adoc_loader_stderr.txt -$(LOADERGUIDE): $(LOADERSRC) $(LOADERFILES) $(RBAPIMAP) +$(LOADERGUIDE): $(LOADERSRC) $(LOADERFILES) ################################################ @@ -353,9 +351,7 @@ ATTRIBOPTS = -a revnumber="$(SPECREVISION)" \ -a appendices=$(APPENDICES) \ $(EXTATTRIBS) -# Look in $(GENERATED) for explicitly required non-extension Ruby, such -# as apimap.rb -ADOCOPTS = --doctype book -a data-uri -I$(GENDIR) -r $(CURDIR)/scripts/spec-macros.rb $(ATTRIBOPTS) +ADOCOPTS = --doctype book -a data-uri -r $(CURDIR)/scripts/openxr-macros.rb $(ATTRIBOPTS) ifneq (,$(strip $(RELEASE))) # No dates or internal commit hashes in release builds for reproducibility @@ -388,7 +384,7 @@ $(ASCIIDOCTOR_TARGETS): OUTSPEC_DOS=$$(cygpath -w $@) ;\ SPECSRC_DOS=$$(cygpath -w $(SPECSRC)) ;\ ATTRIBOPTS_DOS='$(ATTRIBOPTS)' ;\ - ADOCOPTS_DOS="--doctype book -a data-uri -r $$(cygpath -w $(CURDIR)/scripts/spec-macros.rb) $$ATTRIBOPTS_DOS" ;\ + ADOCOPTS_DOS="--doctype book -a data-uri -r $$(cygpath -w $(CURDIR)/scripts/openxr-macros.rb) $$ATTRIBOPTS_DOS" ;\ BATCH_FILE=$$(cygpath -w $$(mktemp)).bat ;\ echo $(ASCIIDOC) $$ADOCOPTS_DOS $(BACKEND_ARGS) --out-file $$OUTSPEC_DOS $$SPECSRC_DOS > $$BATCH_FILE ;\ CMD /C $$BATCH_FILE ;\ @@ -463,7 +459,7 @@ EXTENSION_SOURCES := $(foreach ext,$(patsubst xr_%,%,$(EXTENSIONS_LOWER)),$(call GENREF = $(SCRIPTS)/genRef.py LOGFILE = $(REFPATH)/refpage.log refpages: $(REFPATH)/apispec.txt -$(REFPATH)/apispec.txt: $(SPECFILES) $(EXTENSION_SOURCES) $(GENREF) $(SCRIPTS)/reflib.py $(PYAPIMAP) +$(REFPATH)/apispec.txt: $(SPECFILES) $(EXTENSION_SOURCES) $(GENREF) $(SCRIPTS)/reflib.py $(XRAPI) $(ECHO) "[genRef.py] $(REGISTRY) and spec -> $@" $(ECHO) " (and additional files in $(@D))" $(QUIET)$(MKDIR) "$(REFPATH)" @@ -491,7 +487,7 @@ buildmanpages: $(MANHTML) $(MANHTMLDIR)/openxr.html # This target does not at present, since OpenXR does not alias refpage # content yet. -manaliases: $(PYAPIMAP) +manaliases: $(XRAPI) # This is the single-page ref page. # 'doctype-manpage' allows use of the "book" style but still enable the @@ -640,7 +636,7 @@ clean_dirt: # Clean intermediate generated files # Don't remove OUTDIR, since it contains the config stamp and final output targets clean_generated: - $(RMRF) $(PYAPIMAP) $(RBAPIMAP) $(GENDIR)/index.adoc + $(RMRF) $(XRAPI) $(GENDIR)/index.adoc $(RMRF) $(GENDIR)/api $(GENDIR)/validity $(GENDIR)/hostsynctable $(METADIR) $(REFPATH) # Clean generated targets as well as intermediates. diff --git a/specification/loader/api_layer.adoc b/specification/loader/api_layer.adoc index 2a27f39b2..d81e19355 100644 --- a/specification/loader/api_layer.adoc +++ b/specification/loader/api_layer.adoc @@ -379,7 +379,7 @@ export XR_API_LAYER_PATH=::> with the extension .json. The following directories inside APK assets are used for explicit -and implicit layers: +and implicit layers. ---- openxr/1/api_layers/implicit.d @@ -391,28 +391,6 @@ openxr/1/api_layers/explicit.d The loader accesses these using the Android AssetManager classes. ==== -The loader also looks for system installed API layers in a similar process -as is used for active runtime discovery. -The following system directories are searched for -<> in the following priority -order for implicit and explicit API layers: - -===== Implicit API Layers - -. `/product/etc/openxr/1/api_layers/implicit.d` -. `/odm/etc/openxr/1/api_layers/implicit.d` -. `/oem/etc/openxr/1/api_layers/implicit.d` -. `/system/etc/openxr/1/api_layers/implicit.d` -. `/vendor/etc/openxr/1/api_layers/implicit.d` - -===== Explicit API Layers - -. `/product/etc/openxr/1/api_layers/explicit.d` -. `/oem/etc/openxr/1/api_layers/explicit.d` -. `/vendor/etc/openxr/1/api_layers/explicit.d` -. `/system/etc/openxr/1/api_layers/explicit.d` -. `/odm/etc/openxr/1/api_layers/explicit.d` - [[api-layer-manifest-file-format]] ==== API Layer Manifest File Format ==== @@ -658,7 +636,7 @@ struct XrNegotiateLoaderInfo { }; ---- * pname:structType must: be a valid value of - `<>`. + elink:XrLoaderInterfaceStructs. In this case, it must: specifically be `XR_LOADER_INTERFACE_STRUCT_LOADER_INFO`. * pname:structVersion must: be a valid version of the structure. @@ -723,7 +701,7 @@ struct XrNegotiateApiLayerRequest { }; ---- * pname:structType must: be a valid value of - `<>`. + elink:XrLoaderInterfaceStructs. In this case, it must: specifically be `XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST`. * pname:structVersion must: be a valid version of the structure. diff --git a/specification/loader/runtime.adoc b/specification/loader/runtime.adoc index b6e74d66a..f8aed9c5a 100644 --- a/specification/loader/runtime.adoc +++ b/specification/loader/runtime.adoc @@ -154,14 +154,13 @@ The defined URIs for the ContentProvider authorities are as follows: the `functions/` URI to identify the names of entry points it should query. * `/openxr/__major_ver__/abi/__abi__/runtimes/__package__/functions` - This - URI is for package-specific function name remapping. - Since this is an optional field in the corresponding JSON manifests for - OpenXR, it is optional here as well. - If the active runtime contains "true" in its "has_functions" column, then - this table must exist and be queryable. - No sort order is required to be honored by the content provider. - __package__ is the package name containing the active runtime. - Available columns include: + URI is for package-specific function name remapping. + Since this is an optional field in the corresponding JSON manifests for + OpenXR, it is optional here as well. + If the active runtime contains "true" in its "has_functions" column, then + this table must exist and be queryable. + No sort order is required to be honored by the content provider. + Available columns include: ** `function_name` - Corresponds to the "key" in the JSON manifest field. ** `symbol_name` - Corresponds to the "value" in the JSON manifest field. @@ -169,53 +168,12 @@ Within the loader, the results from either content provider are used to construct an object corresponding to an equivalent JSON runtime manifest file as used on other platforms. -If no runtime is found this way, as a fall-back, a similar process as on -Linux takes place, searching for `active_runtime.json` files in: - -* `/oem/etc/openxr/1` -* `/vendor/etc/openxr/1` -* `/system/etc/openxr/1` - - -[[android-ipc]] -====== Android IPC and Runtime Access -As Android is a permission-limited environment, additional constraints are -placed on runtimes and applications. -In modern versions of Android, applications cannot query arbitrary packages -for arbitrary services that are not pre-declared in the manifest. -To avoid needing to update application manifests for each OpenXR runtime's -requirements, the intent service name -`org.khronos.openxr.OpenXRRuntimeService` (same as used by installable -runtime discovery) is reserved for use by OpenXR runtimes and their -components. -Similarly, the intent service name -`org.khronos.openxr.OpenXRApiLayerService` is reserved for use by OpenXR API -layers and their components. -To target an API level higher than 29, applications must: include provisions -in their manifest to allow them to query for services with these intent -names. -In turn, runtimes and their components that need to locate their originating -package should: query first for packages providing a service for the -relevant intent, then traverse the list of resolutions to find their own -package. -There is no set API provided by an intent service of this name: it exists -solely as a marker of an OpenXR runtime and as a key for retrieving OpenXR -runtime component packages without needing to perform arbitrary package -queries. -This does pose the risk that an application can view all OpenXR runtimes -installed, rather than only the active one. -However, the number of runtimes per device is likely to be very small, and -this opens the smallest weakness possible to achieve the required -functionality. [NOTE] .Note ==== -Applications will require the following `` statements in their -manifest for the loader to locate and load the runtime correctly. -(If building an application using the loader AAR provided by the working -group, beginning with version 1.0.28, these items are included in the AAR -manifest and will be merged into your application manifest automatically.) +Use of a content provider does mean that OpenXR applications on Android will +need the following in their manifest. [source,xml] ``` @@ -223,46 +181,32 @@ manifest and will be merged into your application manifest automatically.) - - - - - - ``` -The permission is needed to contact a system broker. -The provider query is to be able to contact system and installable brokers. -The intent query is for runtimes to look up their own package, which is -required when targeting API levels higher than 29. -It is also recommended to include the following, which could be needed for -haptic feedback: - -[source,xml] -``` - -``` - -Earlier versions of the installable broker also wanted the following -permission, but this is no longer required. -It is harmless to leave it in place, but the broker no longer requires it. +Earlier versions of the installable broker also wanted the following permission, +but this is no longer required. It is harmless to leave it in place, but the broker +no longer requires it. [source,xml] ``` ``` + +Additionally, applications should **not target API levels higher than 29** +for maximum compatibility, as runtimes may need to query and load classes +from their own packages, which are necessarily not listed in the `` +tag above. ==== If no runtime is found this way, as a fall-back, a similar process as on -Linux takes place, searching for `active_runtime.json` files in the -following priority order: +Linux takes place, searching for `active_runtime.json` files in: + +* `/oem/etc/openxr/1` +* `/vendor/etc/openxr/1` +* `/system/etc/openxr/1` + -. `/product/etc/openxr/1` -. `/odm/etc/openxr/1` -. `/oem/etc/openxr/1` -. `/vendor/etc/openxr/1` -. `/system/etc/openxr/1` [[runtime-enumeration]] ==== Runtime Enumeration @@ -504,8 +448,8 @@ If more than one is found, user preferences are used to identify the "active" runtime. The path containing the dynamic library is computed from -`ApplicationInfo.nativeLibraryDir` and the specified ABI, and the filename -is returned using the filename found in the OpenXR metadata value. +`ApplicationInfo.nativeLibraryDir` and the specified ABI, and the +filename is returned using the filename found in the OpenXR metadata value. The "hasFunctions" column is dynamically generated based on the presence of any function metadata entries. @@ -635,7 +579,7 @@ struct XrNegotiateRuntimeRequest { }; ---- * pname:structType must: be a valid value of - `<>`. + elink:XrLoaderInterfaceStructs. In this case, it must specifically be `XR_LOADER_INTERFACE_STRUCT_RUNTIME_REQUEST`. * pname:structVersion must: be a valid version of the structure. diff --git a/specification/registry/xr.xml b/specification/registry/xr.xml index 0fccc5198..388985de7 100644 --- a/specification/registry/xr.xml +++ b/specification/registry/xr.xml @@ -30,7 +30,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - @@ -48,7 +47,7 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - + @@ -131,7 +130,7 @@ maintained in the default branch of the Khronos OpenXR GitHub project. updates them automatically by processing a line at a time. --> // OpenXR current version number. -#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 0, 28) +#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 0, 27) - typedef XrFlags64 XrSemanticLabelsSupportFlagsFB; - typedef XrFlags64 XrHandTrackingAimFlagsFB; @@ -368,13 +358,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. typedef XrFlags64 XrGlobalDimmerFrameEndInfoFlagsML; - - typedef XrFlags64 XrPlaneDetectorFlagsEXT; - typedef XrFlags64 XrPlaneDetectionCapabilityFlagsEXT; - - - typedef XrFlags64 XrVirtualKeyboardInputStateFlagsMETA; - XR_DEFINE_HANDLE(XrInstance) @@ -418,15 +401,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. XR_DEFINE_HANDLE(XrSpaceUserFB) - - XR_DEFINE_HANDLE(XrPassthroughColorLutMETA) - - - XR_DEFINE_HANDLE(XrPlaneDetectorEXT) - - - XR_DEFINE_HANDLE(XrVirtualKeyboardMETA) - @@ -517,9 +491,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - - @@ -537,9 +508,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - - @@ -584,18 +552,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - - - - - - - - - - - float x @@ -636,11 +592,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. float width float height - - float width - float height - float depth - XrOffset2Df offset XrExtent2Df extent @@ -1650,7 +1601,7 @@ maintained in the default branch of the Khronos OpenXR GitHub project. XrTime time - + XrStructureType type @@ -1658,22 +1609,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. XrHandJointsMotionRangeEXT handJointsMotionRange - - - - XrStructureType type - const void* next - uint32_t requestedDataSourceCount - XrHandTrackingDataSourceEXT* requestedDataSources - - - - XrStructureType type - void* next - XrBool32 isActive - XrHandTrackingDataSourceEXT dataSource - - @@ -2467,12 +2402,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. uint32_t vertexCountOutput XrVector2f* vertices - - XrStructureType type - const void* next - XrSemanticLabelsSupportFlagsFB flags - const char* recognizedLabels - @@ -2866,47 +2795,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. XrUuidEXT id - - - uint32_t bufferSize - const uint8_t* buffer - - - - XrStructureType type - const void* next - XrPassthroughColorLutChannelsMETA channels - uint32_t resolution - XrPassthroughColorLutDataMETA data - - - - XrStructureType type - const void* next - XrPassthroughColorLutDataMETA data - - - - XrStructureType type - const void* next - XrPassthroughColorLutMETA colorLut - float weight - - - - XrStructureType type - const void* next - XrPassthroughColorLutMETA sourceColorLut - XrPassthroughColorLutMETA targetColorLut - float weight - - - - XrStructureType type - const void* next - uint32_t maxColorLutResolution - - XrStructureType type @@ -3022,174 +2910,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. float value - - - XrStructureType type - void* next - XrPlaneDetectionCapabilityFlagsEXT supportedFeatures - - - - XrStructureType type - const void* next - XrPlaneDetectorFlagsEXT flags - - - - XrStructureType type - const void* next - XrSpace baseSpace - XrTime time - uint32_t orientationCount - const XrPlaneDetectorOrientationEXT* orientations - uint32_t semanticTypeCount - const XrPlaneDetectorSemanticTypeEXT* semanticTypes - uint32_t maxPlanes - float minArea - XrPosef boundingBoxPose - XrExtent3DfEXT boundingBoxExtent - - - - XrStructureType type - const void* next - XrSpace baseSpace - XrTime time - - - - XrStructureType type - void* next - uint32_t planeLocationCapacityInput - uint32_t planeLocationCountOutput - XrPlaneDetectorLocationEXT* planeLocations - - - - XrStructureType type - void* next - uint64_t planeId - XrSpaceLocationFlags locationFlags - XrPosef pose - XrExtent2Df extents - XrPlaneDetectorOrientationEXT orientation - XrPlaneDetectorSemanticTypeEXT semanticType - uint32_t polygonBufferCount - - - - XrStructureType type - void* next - uint32_t vertexCapacityInput - uint32_t vertexCountOutput - XrVector2f* vertices - - - - - XrStructureType type - void* next - XrBool32 supportsVirtualKeyboard - - - - XrStructureType type - const void* next - - - - XrStructureType type - const void* next - XrVirtualKeyboardLocationTypeMETA locationType - XrSpace space - XrPosef poseInSpace - - - - XrStructureType type - const void* next - XrVirtualKeyboardLocationTypeMETA locationType - XrSpace space - XrPosef poseInSpace - float scale - - - - XrStructureType type - const void* next - XrBool32 visible - - - - XrStructureType type - void* next - int32_t animationIndex - float fraction - - - - XrStructureType type - void* next - uint32_t stateCapacityInput - uint32_t stateCountOutput - XrVirtualKeyboardAnimationStateMETA* states - - - - XrStructureType type - void* next - uint32_t textureWidth - uint32_t textureHeight - uint32_t bufferCapacityInput - uint32_t bufferCountOutput - uint8_t* buffer - - - - XrStructureType type - const void* next - XrVirtualKeyboardInputSourceMETA inputSource - XrSpace inputSpace - XrPosef inputPoseInSpace - XrVirtualKeyboardInputStateFlagsMETA inputState - - - - XrStructureType type - const void* next - const char* textContext - - - - XrStructureType type - const void* next - XrVirtualKeyboardMETA keyboard - char text[XR_MAX_VIRTUAL_KEYBOARD_COMMIT_TEXT_SIZE_META] - - - - XrStructureType type - const void* next - XrVirtualKeyboardMETA keyboard - - - - XrStructureType type - const void* next - XrVirtualKeyboardMETA keyboard - - - - XrStructureType type - const void* next - XrVirtualKeyboardMETA keyboard - - - - XrStructureType type - const void* next - XrVirtualKeyboardMETA keyboard - @@ -3463,12 +3183,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - - - - - @@ -3778,13 +3492,13 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - + - + @@ -3935,12 +3649,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - - - - - @@ -4083,12 +3791,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - - - - - @@ -4168,66 +3870,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -4701,23 +4343,23 @@ maintained in the default branch of the Khronos OpenXR GitHub project. XrResult xrCreateVulkanInstanceKHR - XrInstance instance + XrInstance instance const XrVulkanInstanceCreateInfoKHR* createInfo - VkInstance* vulkanInstance - VkResult* vulkanResult + VkInstance* vulkanInstance + VkResult* vulkanResult XrResult xrCreateVulkanDeviceKHR - XrInstance instance - const XrVulkanDeviceCreateInfoKHR* createInfo - VkDevice* vulkanDevice - VkResult* vulkanResult + XrInstance instance + const XrVulkanDeviceCreateInfoKHR* createInfo + VkDevice* vulkanDevice + VkResult* vulkanResult XrResult xrGetVulkanGraphicsDevice2KHR - XrInstance instance + XrInstance instance const XrVulkanGraphicsDeviceGetInfoKHR* getInfo - VkPhysicalDevice* vulkanPhysicalDevice + VkPhysicalDevice* vulkanPhysicalDevice @@ -4937,7 +4579,7 @@ maintained in the default branch of the Khronos OpenXR GitHub project. uint32_t* bufferCountOutput uint8_t* buffer - + XrResult xrGetControllerModelPropertiesMSFT XrSession session XrControllerModelKeyMSFT modelKey @@ -5187,7 +4829,7 @@ maintained in the default branch of the Khronos OpenXR GitHub project. XrSpace space XrUuidEXT* uuid - + XrResult xrEnumerateSpaceSupportedComponentsFB XrSpace space uint32_t componentTypeCapacityInput @@ -5316,7 +4958,7 @@ maintained in the default branch of the Khronos OpenXR GitHub project. const XrSpaceQueryInfoBaseHeaderFB* info XrAsyncRequestIdFB* requestId - + XrResult xrRetrieveSpaceQueryResultsFB XrSession session XrAsyncRequestIdFB requestId @@ -5354,7 +4996,7 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - + XrResult xrGetSpaceContainerFB XrSession session XrSpace space @@ -5374,19 +5016,19 @@ maintained in the default branch of the Khronos OpenXR GitHub project. XrSpace space XrRect3DfFB* boundingBox3DOutput - + XrResult xrGetSpaceSemanticLabelsFB XrSession session XrSpace space XrSemanticLabelsFB* semanticLabelsOutput - + XrResult xrGetSpaceBoundary2DFB XrSession session XrSpace space XrBoundary2DFB* boundary2DOutput - + XrResult xrGetSpaceRoomLayoutFB XrSession session XrSpace space @@ -5542,25 +5184,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. XrExternalCameraOCULUS* cameras - - - XrResult xrCreatePassthroughColorLutMETA - XrPassthroughFB passthrough - const XrPassthroughColorLutCreateInfoMETA* createInfo - XrPassthroughColorLutMETA* colorLut - - - - XrResult xrDestroyPassthroughColorLutMETA - XrPassthroughColorLutMETA colorLut - - - - XrResult xrUpdatePassthroughColorLutMETA - XrPassthroughColorLutMETA colorLut - const XrPassthroughColorLutUpdateInfoMETA* updateInfo - - XrResult xrEnumeratePerformanceMetricsCounterPathsMETA @@ -5644,120 +5267,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. XrHandTrackerEXT handTracker const XrForceFeedbackCurlApplyLocationsMNDX* locations - - - - XrResult xrCreatePlaneDetectorEXT - XrSession session - const XrPlaneDetectorCreateInfoEXT* createInfo - XrPlaneDetectorEXT* planeDetector - - - - XrResult xrDestroyPlaneDetectorEXT - XrPlaneDetectorEXT planeDetector - - - - XrResult xrBeginPlaneDetectionEXT - XrPlaneDetectorEXT planeDetector - const XrPlaneDetectorBeginInfoEXT* beginInfo - - - - XrResult xrGetPlaneDetectionStateEXT - XrPlaneDetectorEXT planeDetector - XrPlaneDetectionStateEXT* state - - - - XrResult xrGetPlaneDetectionsEXT - XrPlaneDetectorEXT planeDetector - const XrPlaneDetectorGetInfoEXT* info - XrPlaneDetectorLocationsEXT* locations - - - - XrResult xrGetPlanePolygonBufferEXT - XrPlaneDetectorEXT planeDetector - uint64_t planeId - uint32_t polygonBufferIndex - XrPlaneDetectorPolygonBufferEXT* polygonBuffer - - - - - - XrResult xrCreateVirtualKeyboardMETA - XrSession session - const XrVirtualKeyboardCreateInfoMETA* createInfo - XrVirtualKeyboardMETA* keyboard - - - - XrResult xrDestroyVirtualKeyboardMETA - XrVirtualKeyboardMETA keyboard - - - - XrResult xrCreateVirtualKeyboardSpaceMETA - XrSession session - XrVirtualKeyboardMETA keyboard - const XrVirtualKeyboardSpaceCreateInfoMETA* createInfo - XrSpace* keyboardSpace - - - - XrResult xrSuggestVirtualKeyboardLocationMETA - XrVirtualKeyboardMETA keyboard - const XrVirtualKeyboardLocationInfoMETA* locationInfo - - - - XrResult xrGetVirtualKeyboardScaleMETA - XrVirtualKeyboardMETA keyboard - float* scale - - - - XrResult xrSetVirtualKeyboardModelVisibilityMETA - XrVirtualKeyboardMETA keyboard - const XrVirtualKeyboardModelVisibilitySetInfoMETA* modelVisibility - - - - XrResult xrGetVirtualKeyboardModelAnimationStatesMETA - XrVirtualKeyboardMETA keyboard - XrVirtualKeyboardModelAnimationStatesMETA* animationStates - - - - XrResult xrGetVirtualKeyboardDirtyTexturesMETA - XrVirtualKeyboardMETA keyboard - uint32_t textureIdCapacityInput - uint32_t* textureIdCountOutput - uint64_t* textureIds - - - - XrResult xrGetVirtualKeyboardTextureDataMETA - XrVirtualKeyboardMETA keyboard - uint64_t textureId - XrVirtualKeyboardTextureDataMETA* textureData - - - - XrResult xrSendVirtualKeyboardInputMETA - XrVirtualKeyboardMETA keyboard - const XrVirtualKeyboardInputInfoMETA* info - XrPosef* interactorRootPose - - - - XrResult xrChangeVirtualKeyboardTextContextMETA - XrVirtualKeyboardMETA keyboard - const XrVirtualKeyboardTextContextChangeInfoMETA* changeInfo - @@ -6239,50 +5748,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -6330,8 +5795,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - @@ -6939,20 +6402,11 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - - - - - - - - @@ -7188,14 +6642,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - - - - - - - @@ -7514,14 +6960,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - - - - - - - @@ -7544,14 +6982,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - - - - - - - @@ -7708,14 +7138,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - - - - - - - @@ -7791,14 +7213,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - - - - - - - @@ -7812,14 +7226,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - - - - - - - @@ -8075,7 +7481,7 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - + @@ -8256,14 +7662,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - - - - - - - @@ -8583,7 +7981,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - @@ -8659,13 +8056,12 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - + + - - - - + + + @@ -8673,10 +8069,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - - - @@ -8926,7 +8318,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - @@ -9130,61 +8521,10 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + @@ -9560,31 +8900,10 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - + - - - - - - - - - - - - - - - - - - - - - - - + + @@ -9835,17 +9154,10 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - + - - - - - - - @@ -10370,10 +9682,10 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - + - - + + @@ -10498,20 +9810,6 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - - - - - - - - - - - - - @@ -10816,60 +10114,17 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - + - - - - - - - - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -11034,312 +10289,10 @@ maintained in the default branch of the Khronos OpenXR GitHub project. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + + diff --git a/specification/scripts/cgenerator.py b/specification/scripts/cgenerator.py index 790579c82..64300ea50 100644 --- a/specification/scripts/cgenerator.py +++ b/specification/scripts/cgenerator.py @@ -513,7 +513,7 @@ def genCmd(self, cmdinfo, name, alias): self.appendSection('commandPointer', decls[1]) def misracstyle(self): - return self.genOpts.misracstyle + return self.genOpts.misracstyle; def misracppstyle(self): - return self.genOpts.misracppstyle + return self.genOpts.misracppstyle; diff --git a/specification/scripts/docgenerator.py b/specification/scripts/docgenerator.py index 832498e1d..5b5e414aa 100644 --- a/specification/scripts/docgenerator.py +++ b/specification/scripts/docgenerator.py @@ -354,8 +354,6 @@ def genType(self, typeinfo, name, alias): name, category)) else: body = self.genRequirements(name) - if category in ('define',): - body = body.strip() if alias: # If the type is an alias, just emit a typedef declaration body += 'typedef ' + alias + ' ' + name + ';\n' diff --git a/specification/scripts/findBareNormatives.sh b/specification/scripts/findBareNormatives.sh deleted file mode 100755 index a5477b520..000000000 --- a/specification/scripts/findBareNormatives.sh +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright (c) 2018-2023, The Khronos Group Inc. -# -# SPDX-License-Identifier: Apache-2.0 - -# findBareNormatives.sh - search usage of words that are or seem like normatives, -# but lack normative markup/highlighting. -# -# Usage: scripts/findBareNormatives.sh [sources/chapters/...]... -# -# If one or more adoc file paths (relative to specification dir) are provided, -# only those paths are checked; otherwise all chapters are checked. - -set -e - -list_sources() { - ( - cd "$(dirname "$0")/.." - find sources/chapters -name "*.adoc" | grep -v appendix - ) -} - -SOURCES=() -if [ $# -gt 0 ]; then - echo "Only checking $*" - echo "" - SOURCES+=("$@") -else - while IFS='' read -r line; do SOURCES+=("$line"); done < <(list_sources) -fi - -# Base function for grepping through sources for errors -# Params: -# 1. Description of issue being checked for -# All remaining parameters: passed to grep, typically a regex or something like -e regex -e regex -# May set GREPCMD before call to do something other than egrep -grep_sources() { - DESC="$1" - shift - if ${GREPCMD:-grep -P} -n "$@" "${SOURCES[@]}"; then - echo "" - echo "*** Warning: Above lines matched grep with $*" - echo "*** $DESC" - echo "" - echo "" - FAILED="yes" - fi -} - - -# Common Params for the various check markup functions: -# 1. macro first letter (so s in slink) -# 2. description of category -# 3. expectation, completing the sentence "Things like this should..." -# 4. partial regex, which will be appended to the end of markup macro (eg slink:yourregex) - -### -# Actual Checks -### -( - export FAILED= - - cd "$(dirname "$0")/.." - grep_sources \ - "found normative without trailing colon - add colon or rephrase" \ - "\b(cannot|can|may|must|optional|should)\b(?!:)" - - # not looking for "required" because there are too many places we don't want the markup. - - grep_sources \ - "these suggest a normative, but are not normatives used in the OpenXR spec - rephrase" \ - "\b(shall|might|could|would)\b(?!:)" - - - if [ "$FAILED" != "" ]; then - echo "Failures detected" - exit 1 - fi - -) - diff --git a/specification/scripts/genRef.py b/specification/scripts/genRef.py index b5dfa189a..0ddbc2a18 100644 --- a/specification/scripts/genRef.py +++ b/specification/scripts/genRef.py @@ -835,10 +835,6 @@ def genExtension(baseDir, extpath, name, info): # Do not link to spec version or extension name - those ref pages are not created. continue - if req_name.startswith('/interaction_profiles'): - # We do not yet make ref pages for interaction profiles, though we may in the future - continue - if required.get('extends'): # These are either extensions of enumerated types, or const enum # values: neither of which get a ref page - although we could diff --git a/specification/scripts/spec-macros.rb b/specification/scripts/openxr-macros.rb similarity index 89% rename from specification/scripts/spec-macros.rb rename to specification/scripts/openxr-macros.rb index e1ab58083..bd042b2e5 100644 --- a/specification/scripts/spec-macros.rb +++ b/specification/scripts/openxr-macros.rb @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 #require 'asciidoctor/extensions' unless RUBY_ENGINE == 'opal' -RUBY_ENGINE == 'opal' ? (require 'spec-macros/extension') : (require_relative 'spec-macros/extension') +RUBY_ENGINE == 'opal' ? (require 'openxr-macros/extension') : (require_relative 'openxr-macros/extension') # All the inline macros we need Asciidoctor::Extensions.register do @@ -15,7 +15,6 @@ inline_macro RequiredInlineMacro inline_macro ShouldInlineMacro inline_macro ReflinkInlineMacro - inline_macro ApiextInlineMacro inline_macro FlinkInlineMacro inline_macro FnameInlineMacro inline_macro FtextInlineMacro diff --git a/specification/scripts/spec-macros/extension.rb b/specification/scripts/openxr-macros/extension.rb similarity index 52% rename from specification/scripts/spec-macros/extension.rb rename to specification/scripts/openxr-macros/extension.rb index 08f953cac..c28154a89 100644 --- a/specification/scripts/spec-macros/extension.rb +++ b/specification/scripts/openxr-macros/extension.rb @@ -6,16 +6,12 @@ include ::Asciidoctor -# This is the generated map of API interfaces in this spec build -require 'apimap.rb' -$apiNames = APInames.new - -class SpecInlineMacroBase < Extensions::InlineMacroProcessor +class OpenXRInlineMacroBase < Extensions::InlineMacroProcessor use_dsl using_format :short end -class NormativeInlineMacroBase < SpecInlineMacroBase +class NormativeInlineMacroBase < OpenXRInlineMacroBase def text 'normative' end @@ -25,34 +21,8 @@ def process parent, target, attributes end end -class LinkInlineMacroBase < SpecInlineMacroBase - # Check if a link macro target exists - overridden by specific macros - # Default assumption is that it does exist - def exists? target - return true - end - +class LinkInlineMacroBase < OpenXRInlineMacroBase def process parent, target, attributes - if not exists? target - # If the macro target is not in this build, but has an alias, - # substitute that alias as the argument. - # Otherwise, turn the (attempted) link into text, and complain. - if $apiNames.nonexistent.has_key? target - oldtarget = target - target = $apiNames.nonexistent[oldtarget] - msg = 'Rewriting nonexistent link macro target: ' + @name.to_s + ':' + oldtarget + ' to ' + target - Asciidoctor::LoggerManager.logger.info msg - # Fall through - else - # Suppress warnings for apiext: macros as this is such a common case - if @name.to_s != 'apiext' - msg = 'Textifying unknown link macro target: ' + @name.to_s + ':' + target - Asciidoctor::LoggerManager.logger.warn msg - end - return create_inline parent, :quoted, '' + target + '' - end - end - if parent.document.attributes['cross-file-links'] return Inline.new(parent, :anchor, target, :type => :link, :target => (target + '.html')) else @@ -61,21 +31,24 @@ def process parent, target, attributes end end -class CodeInlineMacroBase < SpecInlineMacroBase +class CodeInlineMacroBase < OpenXRInlineMacroBase def process parent, target, attributes - create_inline parent, :quoted, '' + target.gsub('→', '->') + '' + + create_inline parent, :quoted, '' + target + '' end end -class StrongInlineMacroBase < SpecInlineMacroBase +class StrongInlineMacroBase < OpenXRInlineMacroBase def process parent, target, attributes - create_inline parent, :quoted, '' + target.gsub('→', '->') + '' + + create_inline parent, :quoted, '' + target + '' end end -class ParamInlineMacroBase < SpecInlineMacroBase +class ParamInlineMacroBase < OpenXRInlineMacroBase def process parent, target, attributes - create_inline parent, :quoted, '' + target.gsub('→', '->') + '' + + create_inline parent, :quoted, '' + target + '' end end @@ -142,34 +115,14 @@ def text end end -# Generic reference page link to any entity with an anchor/refpage class ReflinkInlineMacro < LinkInlineMacroBase named :reflink - match /reflink:([-\w]+)/ -end - -# Link to an extension appendix/refpage -class ApiextInlineMacro < LinkInlineMacroBase - named :apiext - match /apiext:(\w+)/ - - def exists? target - $apiNames.features.has_key? target - end - - def process parent, target, attributes - node = super parent, target, attributes - create_inline parent, :quoted, %(#{node.convert}) - end + match /reflink:(\w+)/ end class FlinkInlineMacro < LinkInlineMacroBase named :flink match /flink:(\w+)/ - - def exists? target - $apiNames.protos.has_key? target - end end class FnameInlineMacro < StrongInlineMacroBase @@ -190,10 +143,6 @@ class SnameInlineMacro < CodeInlineMacroBase class SlinkInlineMacro < LinkInlineMacroBase named :slink match /slink:(\w+)/ - - def exists? target - $apiNames.structs.has_key? target or $apiNames.handles.has_key? target - end end class StextInlineMacro < CodeInlineMacroBase @@ -204,19 +153,11 @@ class StextInlineMacro < CodeInlineMacroBase class EnameInlineMacro < CodeInlineMacroBase named :ename match /ename:(\w+)/ - - def exists? target - $apiNames.consts.has_key? target - end end class ElinkInlineMacro < LinkInlineMacroBase named :elink match /elink:(\w+)/ - - def exists? target - $apiNames.enums.has_key? target or $apiNames.flags.has_key? target - end end class EtextInlineMacro < CodeInlineMacroBase @@ -224,16 +165,14 @@ class EtextInlineMacro < CodeInlineMacroBase match /etext:([\w\*]+)/ end -# this does not handle any [] at the moment - class PnameInlineMacro < ParamInlineMacroBase named :pname - match /pname:(\w+((\.|→)\w+)*)/ + match /pname:((\w[\w.]*)*\w+)/ end class PtextInlineMacro < ParamInlineMacroBase named :ptext - match /ptext:([\w\*]+((\.|→)[\w\*]+)*)/ + match /ptext:((\w[\w.]*)*\w+)/ end class DnameInlineMacro < CodeInlineMacroBase @@ -244,10 +183,6 @@ class DnameInlineMacro < CodeInlineMacroBase class DlinkInlineMacro < LinkInlineMacroBase named :dlink match /dlink:(\w+)/ - - def exists? target - $apiNames.defines.has_key? target or target.start_with? 'XR_USE' or target.start_with? 'XRAPI' or target == 'XR_NO_STDINT_H' - end end class TnameInlineMacro < CodeInlineMacroBase @@ -258,41 +193,26 @@ class TnameInlineMacro < CodeInlineMacroBase class TlinkInlineMacro < LinkInlineMacroBase named :tlink match /tlink:(\w+)/ - - def exists? target - $apiNames.flags.has_key? target or - $apiNames.funcpointers.has_key? target or - $apiNames.defines.has_key? target - end end class BasetypeInlineMacro < LinkInlineMacroBase named :basetype match /basetype:(\w+)/ - - # def process parent, target, attributes - # if parent.document.attributes['cross-file-links'] - # return Inline.new(parent, :anchor, target, :type => :link, :target => (target + '.html')) - # else - # return Inline.new(parent, :anchor, '' + target + '', :type => :xref, :target => ('#' + target), :attributes => {'fragment' => target, 'refid' => target}) - # end - # end - - def exists? target - $apiNames.basetypes.has_key? target + def process parent, target, attributes + if parent.document.attributes['cross-file-links'] + return Inline.new(parent, :anchor, target, :type => :link, :target => (target + '.html')) + else + return Inline.new(parent, :anchor, '' + target + '', :type => :xref, :target => ('#' + target), :attributes => {'fragment' => target, 'refid' => target}) + end end end -# This does not include the full range of code: use -# It allows embedded periods (field separators) and wildcards if followed by -# another word, and an ending wildcard. - -class CodeInlineMacro < CodeInlineMacroBase +class CodeInlineMacro < StrongInlineMacroBase named :code - match /code:(\w+([.*]\w+)*\**)/ + match /code:([*\w]+)/ end -class SemanticSubpathMacroBase < SpecInlineMacroBase +class SemanticSubpathMacroBase < OpenXRInlineMacroBase def process parent, target, attributes create_inline parent, :quoted, '…' + target + '' end @@ -303,7 +223,7 @@ class SemanticSubpathInlineMacro < SemanticSubpathMacroBase match /subpathname:([\w\/\-\.]+)/ end -class SemanticPathMacroBase < SpecInlineMacroBase +class SemanticPathMacroBase < OpenXRInlineMacroBase def process parent, target, attributes create_inline parent, :quoted, '' + target + '' end @@ -314,7 +234,7 @@ class SemanticPathInlineMacro < SemanticPathMacroBase match /pathname:([\w\/\-\.]+)/ end -class ActionRelatedNameMacroBase < SpecInlineMacroBase +class ActionRelatedNameMacroBase < OpenXRInlineMacroBase def process parent, target, attributes create_inline parent, :quoted, '' + target + '' end diff --git a/specification/scripts/reg.py b/specification/scripts/reg.py index ebe7840cf..91902b0cb 100755 --- a/specification/scripts/reg.py +++ b/specification/scripts/reg.py @@ -1220,10 +1220,6 @@ def generateFeature(self, fname, ftype, dictionary): extname = elem.get('extname') version = elem.get('version') if extname is not None: - # if this enum is not defined in an extension that is being emitted - # then it should not be included in the emitted header file - if re.match(self.genOpts.emitExtensions, extname) is None: - continue; # 'supported' attribute was injected when the element was # moved into the group in Registry.parseTree() supported_list = elem.get('supported').split(",") diff --git a/specification/scripts/reserve_extensions.py b/specification/scripts/reserve_extensions.py deleted file mode 100755 index cb3bf8da9..000000000 --- a/specification/scripts/reserve_extensions.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/python3 -# -# Copyright 2020-2023 The Khronos Group Inc. -# -# SPDX-License-Identifier: Apache-2.0 -""" -Simple script to generate XML to reserve extensions. - -The generated XML still needs to be added to xr.xml and have -PrettyRegistryXML.OpenXR run on it. -""" - -import click - - -@click.command() -@click.option('--extensions', default=1, help='number of extensions to reserve') -@click.argument('vendor') -@click.argument('first_extension', type=int) -def generate_reserved_extensions(vendor: str, first_extension: int, extensions: int): - """Prints extension reservation XML.""" - vendor = vendor.upper() - for num in range(first_extension, first_extension + extensions): - print(" " + f""" - - - - - - - """.strip()) - print() diff --git a/specification/scripts/spec_tools/conventions.py b/specification/scripts/spec_tools/conventions.py index 8d0f07261..2086d8789 100644 --- a/specification/scripts/spec_tools/conventions.py +++ b/specification/scripts/spec_tools/conventions.py @@ -77,7 +77,7 @@ def __init__(self): def formatExtension(self, name): """Mark up an extension name as a link the spec.""" - return 'apiext:{}'.format(name) + return '`<<{}>>`'.format(name) @property @abc.abstractmethod diff --git a/specification/scripts/spec_tools/macro_checker_file.py b/specification/scripts/spec_tools/macro_checker_file.py index 46c9c2ad7..ed5e5d37e 100644 --- a/specification/scripts/spec_tools/macro_checker_file.py +++ b/specification/scripts/spec_tools/macro_checker_file.py @@ -1588,7 +1588,7 @@ def makeSearch(self): def makeMacroMarkup(self, newMacro=None, newEntity=None, data=None): """Construct appropriate markup for referring to an entity. - Typically constructs macro:entity, but can construct apiext:EXTENSION_NAME if the supplied + Typically constructs macro:entity, but can construct `<>` if the supplied entity is identified as an extension. Arguments: @@ -1615,14 +1615,14 @@ def makeMacroMarkup(self, newMacro=None, newEntity=None, data=None): def makeExtensionLink(self, newEntity=None): """Create a correctly-formatted link to an extension. - Result takes the form apiext:EXTENSION_NAME. + Result takes the form `<>`. Argument: newEntity -- The extension name to link to. Defaults to self.entity. """ if not newEntity: newEntity = self.entity - return 'apiext:{}'.format(newEntity) + return '`<<{}>>`'.format(newEntity) def computeExpectedRefPageFromInclude(self, entity): """Compute the expected ref page entity based on an include entity name.""" diff --git a/specification/scripts/test_check_spec_links.py b/specification/scripts/test_check_spec_links.py index b54264703..1eac7d723 100644 --- a/specification/scripts/test_check_spec_links.py +++ b/specification/scripts/test_check_spec_links.py @@ -162,7 +162,7 @@ def test_extension(ckr): # Check formatting of extension names: # the following is the canonical way to refer to an extension # (link wrapped in backticks) - expected_replacement = 'apiext:%s' % EXT + expected_replacement = '`<<%s>>`' % EXT # Extension name mentioned without any markup, should be added assert (loneMsgReplacement(ckr.check('asdf %s asdf' % EXT)) @@ -187,7 +187,7 @@ def test_extension(ckr): == expected_replacement) # This shouldn't cause errors because this is how we want it to look. - assert not ckr.check('asdf apiext:%s asdf' % EXT).messages + assert not ckr.check('asdf `<<%s>>` asdf' % EXT).messages # This doesn't (shouldn't?) cause errors because just backticks on their own # "escape" names from the "missing markup" tests. diff --git a/specification/scripts/xml_consistency.py b/specification/scripts/xml_consistency.py index dda22c749..df31c6d71 100755 --- a/specification/scripts/xml_consistency.py +++ b/specification/scripts/xml_consistency.py @@ -120,7 +120,10 @@ def makeRegistry(self): # and it provides file line info which is useful in messages. try: import lxml.etree as etree + HAS_LXML = True except ImportError: + HAS_LXML = False + if not HAS_LXML: return super().makeRegistry() registryFile = str(SPECIFICATION_DIR / 'registry/xr.xml') @@ -237,7 +240,7 @@ def check_enum_naming(self, enum_type): if bare_end: # If bare_end is set, end is always non-empty because it means it's a bitmask. - assert end + assert(end) if not name.endswith(end) and not stripped_name.endswith(bare_end): self.record_error('Got an enum value whose name does not match the pattern: got', name, 'but expected something that ended with', end, ', or', bare_end, @@ -272,7 +275,7 @@ def get_codes_for_command_and_type(self, cmd_name, type_name): codes = super().get_codes_for_command_and_type(cmd_name, type_name) # Filter out any based on the specific command - if codes is not None and cmd_name.startswith(_DESTROY_PREFIX): + if cmd_name.startswith(_DESTROY_PREFIX): # xrDestroyX should not return XR_ERROR_anything_LOST or XR_anything_LOSS_PENDING codes = {x for x in codes if not x.endswith("_LOST")} codes = {x for x in codes if not x.endswith("_LOSS_PENDING")} @@ -343,7 +346,7 @@ def check_two_call_count_output(self, param_name, param_elem, match): self.record_error('Two-call-idiom call has count parameter', param_name, 'with type', param_type, 'instead of uint32_t') type_elem = param_elem.find('type') - assert type_elem is not None + assert(type_elem is not None) tail = type_elem.tail.strip() if '*' != tail: @@ -367,7 +370,7 @@ def check_two_call_array(self, param_name, param_elem, match): optional, '- expected "true"') type_elem = param_elem.find('type') - assert type_elem is not None + assert(type_elem is not None) tail = type_elem.tail.strip() if '*' not in tail: @@ -375,7 +378,6 @@ def check_two_call_array(self, param_name, param_elem, match): 'that is not a pointer:', type_elem.text, type_elem.tail) length = LengthEntry.parse_len_from_param(param_elem) - assert length is not None if not length[0].other_param_name: self.record_error('Two-call-idiom call has array parameter', param_name, 'whose first length is not another parameter:', length[0]) @@ -442,11 +444,9 @@ def check_two_call_command(self, name, info, params): if not array_param_name: self.record_error('Apparent two-call-idiom call missing an array output parameter') - if (capacity_input_param_match is None or - count_output_param_match is None or - capacity_input_param_name is None or - count_output_param_name is None or - array_param_name is None): + if not capacity_input_param_name or \ + not count_output_param_name or \ + not array_param_name: # If we're missing at least one, stop checking two-call stuff here. return diff --git a/specification/scripts/xrconventions.py b/specification/scripts/xrconventions.py index 6fe3d307b..50efc3101 100644 --- a/specification/scripts/xrconventions.py +++ b/specification/scripts/xrconventions.py @@ -249,7 +249,7 @@ def spec_no_reflow_dirs(self): """Return a set of directories not to automatically descend into when reflowing spec text """ - return tuple() + return ('styleguide',) @property def zero(self): diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f8af1a0df..124acb200 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2023, The Khronos Group Inc. +# Copyright (c) 2017 The Khronos Group Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -14,6 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# Author: +# if(POLICY CMP0075) cmake_policy(SET CMP0075 NEW) @@ -37,9 +39,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore" OR (WIN32 AND CMAKE_GENERATOR_PLATF set(OPENGL_INCOMPATIBLE TRUE) set(VULKAN_INCOMPATIBLE TRUE) message(STATUS "OpenGL/Vulkan disabled due to incompatibility") -elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - set(OPENGL_INCOMPATIBLE TRUE) - message(STATUS "OpenGL disabled as no bindings exist for OpenGL on Darwin") elseif(ANDROID) set(OPENGL_INCOMPATIBLE TRUE) find_path(ANDROID_NATIVE_APP_GLUE android_native_app_glue.h PATHS ${ANDROID_NDK}/sources/android/native_app_glue) @@ -180,20 +179,7 @@ if((OPENGL_FOUND OR OpenGLES_FOUND) AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/comm add_library(android_native_app_glue OBJECT "${ANDROID_NATIVE_APP_GLUE}/android_native_app_glue.c") target_include_directories(android_native_app_glue PUBLIC ${ANDROID_NATIVE_APP_GLUE}) target_compile_options(android_native_app_glue PRIVATE -Wno-unused-parameter) - elseif(APPLE) - set(apple_c_compile_options - -x objective-c++ - ) - target_compile_options(openxr-gfxwrapper PRIVATE - ${apple_c_compile_options} - ) - target_link_libraries(openxr-gfxwrapper PUBLIC - "-framework AppKit" - "-framework Foundation" - "-framework CoreGraphics" - ) endif() - set_target_properties(openxr-gfxwrapper PROPERTIES FOLDER ${HELPER_FOLDER}) message(STATUS "Enabling OpenGL support in hello_xr, loader_test, and conformance, if configured") endif() @@ -206,14 +192,6 @@ endif() # Several files use these compile time platform switches if(WIN32) add_definitions(-DXR_USE_PLATFORM_WIN32) -elseif(APPLE) - if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - if(DARWIN_TARGET_OS_NAME STREQUAL "ios") - add_definitions(-DXR_USE_PLATFORM_IOS) - else() - add_definitions(-DXR_USE_PLATFORM_MACOS) - endif() - endif() elseif(ANDROID) add_definitions(-DXR_USE_PLATFORM_ANDROID) set(OPENXR_ANDROID_VERSION_SUFFIX "" CACHE STRING "Suffix for generated Android artifacts.") @@ -432,11 +410,7 @@ if(NOT MSVC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAG}") endif() endforeach() - if(APPLE) - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-undefined,error") - else() - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") - endif() + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") endif() if(ANDROID) diff --git a/src/api_layers/CMakeLists.txt b/src/api_layers/CMakeLists.txt index 348b6d978..87f88eac2 100644 --- a/src/api_layers/CMakeLists.txt +++ b/src/api_layers/CMakeLists.txt @@ -37,13 +37,6 @@ else() set(LAYER_MANIFEST_PREFIX) endif() -# Windows needs bigobj support since we have generated code. -if(MSVC) - add_compile_options("/bigobj") -elseif(WIN32 AND CMAKE_CXX_COMPILER_ID MATCHES "^Clang|GNU$") - add_compile_options("-Wa,-mbig-obj") -endif() - # Basics for api_dump API Layer gen_xr_layer_json( @@ -70,8 +63,6 @@ run_xr_xml_generate(api_dump_generator.py xr_generated_api_dump.cpp add_library(XrApiLayer_api_dump SHARED api_dump.cpp - XrApiLayer_api_dump.def - ${PROJECT_SOURCE_DIR}/src/common/hex_and_handles.h # target-specific generated files ${GENERATED_OUTPUT} @@ -84,7 +75,7 @@ add_library(XrApiLayer_api_dump SHARED ) set_target_properties(XrApiLayer_api_dump PROPERTIES FOLDER ${API_LAYERS_FOLDER}) -target_link_libraries(XrApiLayer_api_dump PRIVATE Threads::Threads OpenXR::headers) +target_link_libraries(XrApiLayer_api_dump PRIVATE Threads::Threads) target_compile_definitions(XrApiLayer_api_dump PRIVATE ${OPENXR_ALL_SUPPORTED_DEFINES}) add_dependencies(XrApiLayer_api_dump generate_openxr_header @@ -96,6 +87,10 @@ target_include_directories(XrApiLayer_api_dump ${PROJECT_SOURCE_DIR}/src/common ${CMAKE_CURRENT_SOURCE_DIR} + # for OpenXR headers + ${PROJECT_SOURCE_DIR}/include + ${PROJECT_BINARY_DIR}/include + # for generated dispatch table ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/.. @@ -134,8 +129,6 @@ run_xr_xml_generate(validation_layer_generator.py xr_generated_core_validation.c add_library(XrApiLayer_core_validation SHARED core_validation.cpp - XrApiLayer_core_validation.def - ${PROJECT_SOURCE_DIR}/src/common/hex_and_handles.h ${PROJECT_SOURCE_DIR}/src/common/object_info.cpp ${PROJECT_SOURCE_DIR}/src/common/object_info.h @@ -151,7 +144,7 @@ add_library(XrApiLayer_core_validation SHARED ) set_target_properties(XrApiLayer_core_validation PROPERTIES FOLDER ${API_LAYERS_FOLDER}) -target_link_libraries(XrApiLayer_core_validation PRIVATE Threads::Threads OpenXR::headers) +target_link_libraries(XrApiLayer_core_validation PRIVATE Threads::Threads) target_compile_definitions(XrApiLayer_core_validation PRIVATE ${OPENXR_ALL_SUPPORTED_DEFINES}) add_dependencies(XrApiLayer_core_validation generate_openxr_header @@ -161,6 +154,10 @@ target_include_directories(XrApiLayer_core_validation PRIVATE ${PROJECT_SOURCE_DIR}/src/common + # for OpenXR headers + ${PROJECT_SOURCE_DIR}/include + ${PROJECT_BINARY_DIR}/include + # for generated dispatch table ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/.. @@ -195,10 +192,11 @@ if(WIN32) elseif(APPLE) # Apple api_dump-specific information - set_target_properties(XrApiLayer_api_dump PROPERTIES LINK_FLAGS "-Wl,-exported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/XrApiLayer_api_dump.expsym") + set_target_properties(XrApiLayer_api_dump PROPERTIES LINK_FLAGS "-Wl") # Apple core_validation-specific information - set_target_properties(XrApiLayer_core_validation PROPERTIES LINK_FLAGS "-Wl,-exported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/XrApiLayer_core_validation.expsym") + set_target_properties(XrApiLayer_core_validation PROPERTIES LINK_FLAGS "-Wl") + else() # Linux api_dump-specific information set_target_properties(XrApiLayer_api_dump PROPERTIES LINK_FLAGS "-Wl,-Bsymbolic,--exclude-libs,ALL") diff --git a/src/api_layers/README.md b/src/api_layers/README.md index 0d808e76c..662ed69d1 100644 --- a/src/api_layers/README.md +++ b/src/api_layers/README.md @@ -16,7 +16,7 @@ the next enabled API layer, or runtime, which does implement that command. This directory contains several functional API layers which can be used by an OpenXR application. -For more information on API Layers, refer to section 2.7 on the OpenXR +For more information on API Layers, refer to section 2.5 on the OpenXR Specification.
diff --git a/src/api_layers/XrApiLayer_api_dump.expsym b/src/api_layers/XrApiLayer_api_dump.expsym deleted file mode 100644 index ec596832a..000000000 --- a/src/api_layers/XrApiLayer_api_dump.expsym +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) 2019-2023, The Khronos Group Inc. -# -# SPDX-License-Identifier: Apache-2.0 - -_xrNegotiateLoaderApiLayerInterface diff --git a/src/api_layers/XrApiLayer_core_validation.expsym b/src/api_layers/XrApiLayer_core_validation.expsym deleted file mode 100644 index ec596832a..000000000 --- a/src/api_layers/XrApiLayer_core_validation.expsym +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) 2019-2023, The Khronos Group Inc. -# -# SPDX-License-Identifier: Apache-2.0 - -_xrNegotiateLoaderApiLayerInterface diff --git a/src/api_layers/api_dump.cpp b/src/api_layers/api_dump.cpp index 7a1573040..da87d307c 100644 --- a/src/api_layers/api_dump.cpp +++ b/src/api_layers/api_dump.cpp @@ -595,9 +595,9 @@ extern "C" { // Function used to negotiate an interface betewen the loader and an API layer. Each library exposing one or // more API layers needs to expose at least this function. -LAYER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrNegotiateLoaderApiLayerInterface(const XrNegotiateLoaderInfo *loaderInfo, - const char * /*apiLayerName*/, - XrNegotiateApiLayerRequest *apiLayerRequest) { +XrResult LAYER_EXPORT XRAPI_CALL xrNegotiateLoaderApiLayerInterface(const XrNegotiateLoaderInfo *loaderInfo, + const char * /*apiLayerName*/, + XrNegotiateApiLayerRequest *apiLayerRequest) { if (nullptr == loaderInfo || nullptr == apiLayerRequest || loaderInfo->structType != XR_LOADER_INTERFACE_STRUCT_LOADER_INFO || loaderInfo->structVersion != XR_LOADER_INFO_STRUCT_VERSION || loaderInfo->structSize != sizeof(XrNegotiateLoaderInfo) || apiLayerRequest->structType != XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST || @@ -611,8 +611,8 @@ LAYER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrNegotiateLoaderApiLayerInterface(c apiLayerRequest->layerInterfaceVersion = XR_CURRENT_LOADER_API_LAYER_VERSION; apiLayerRequest->layerApiVersion = XR_CURRENT_API_VERSION; - apiLayerRequest->getInstanceProcAddr = ApiDumpLayerXrGetInstanceProcAddr; - apiLayerRequest->createApiLayerInstance = ApiDumpLayerXrCreateApiLayerInstance; + apiLayerRequest->getInstanceProcAddr = reinterpret_cast(ApiDumpLayerXrGetInstanceProcAddr); + apiLayerRequest->createApiLayerInstance = reinterpret_cast(ApiDumpLayerXrCreateApiLayerInstance); return XR_SUCCESS; } diff --git a/src/api_layers/core_validation.cpp b/src/api_layers/core_validation.cpp index c81f50c4a..98e010c0d 100644 --- a/src/api_layers/core_validation.cpp +++ b/src/api_layers/core_validation.cpp @@ -841,9 +841,9 @@ extern "C" { // Function used to negotiate an interface betewen the loader and an API layer. Each library exposing one or // more API layers needs to expose at least this function. -LAYER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrNegotiateLoaderApiLayerInterface(const XrNegotiateLoaderInfo *loaderInfo, - const char * /*apiLayerName*/, - XrNegotiateApiLayerRequest *apiLayerRequest) { +LAYER_EXPORT XrResult XRAPI_CALL xrNegotiateLoaderApiLayerInterface(const XrNegotiateLoaderInfo *loaderInfo, + const char * /*apiLayerName*/, + XrNegotiateApiLayerRequest *apiLayerRequest) { if (nullptr == loaderInfo || nullptr == apiLayerRequest || loaderInfo->structType != XR_LOADER_INTERFACE_STRUCT_LOADER_INFO || loaderInfo->structVersion != XR_LOADER_INFO_STRUCT_VERSION || loaderInfo->structSize != sizeof(XrNegotiateLoaderInfo) || apiLayerRequest->structType != XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST || @@ -857,8 +857,9 @@ LAYER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrNegotiateLoaderApiLayerInterface(c apiLayerRequest->layerInterfaceVersion = XR_CURRENT_LOADER_API_LAYER_VERSION; apiLayerRequest->layerApiVersion = XR_CORE_VALIDATION_API_VERSION; - apiLayerRequest->getInstanceProcAddr = GenValidUsageXrGetInstanceProcAddr; - apiLayerRequest->createApiLayerInstance = CoreValidationXrCreateApiLayerInstance; + apiLayerRequest->getInstanceProcAddr = reinterpret_cast(GenValidUsageXrGetInstanceProcAddr); + apiLayerRequest->createApiLayerInstance = + reinterpret_cast(CoreValidationXrCreateApiLayerInstance); return XR_SUCCESS; } diff --git a/src/common/filesystem_utils.cpp b/src/common/filesystem_utils.cpp index 16e6ff329..d3d4182fb 100644 --- a/src/common/filesystem_utils.cpp +++ b/src/common/filesystem_utils.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017 The Khronos Group Inc. // Copyright (c) 2017 Valve Corporation // Copyright (c) 2017 LunarG, Inc. // diff --git a/src/common/filesystem_utils.hpp b/src/common/filesystem_utils.hpp index 3dea1b2c3..4a5c987e7 100644 --- a/src/common/filesystem_utils.hpp +++ b/src/common/filesystem_utils.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017 The Khronos Group Inc. // Copyright (c) 2017 Valve Corporation // Copyright (c) 2017 LunarG, Inc. // diff --git a/src/common/gfxwrapper_opengl.c b/src/common/gfxwrapper_opengl.c index 8b5c08990..73daccc33 100644 --- a/src/common/gfxwrapper_opengl.c +++ b/src/common/gfxwrapper_opengl.c @@ -15,6 +15,42 @@ System level functionality ================================================================================================================================ */ +#if defined(OS_ANDROID) +static void Print(const char *format, ...) { +#if defined(OS_WINDOWS) + char buffer[4096]; + va_list args; + va_start(args, format); + vsnprintf_s(buffer, 4096, _TRUNCATE, format, args); + va_end(args); + + OutputDebugStringA(buffer); +#elif defined(OS_LINUX) + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + fflush(stdout); +#elif defined(OS_APPLE) + char buffer[4096]; + va_list args; + va_start(args, format); + vsnprintf(buffer, 4096, format, args); + va_end(args); + + NSLog(@"%s", buffer); +#elif defined(OS_ANDROID) + char buffer[4096]; + va_list args; + va_start(args, format); + vsnprintf(buffer, 4096, format, args); + va_end(args); + + __android_log_print(ANDROID_LOG_VERBOSE, "atw", "%s", buffer); +#endif +} +#endif // defined(OS_ANDROID) + static void Error(const char *format, ...) { #if defined(OS_WINDOWS) char buffer[4096]; @@ -223,14 +259,11 @@ Get proc address / extensions #if defined(OS_WINDOWS) PROC GetExtension(const char *functionName) { return wglGetProcAddress(functionName); } #elif defined(OS_APPLE) -void (*GetExtension(const char *functionName))(void) { - (void)functionName; - return NULL; -} +void (*GetExtension(const char *functionName))() { return NULL; } #elif defined(OS_LINUX_XCB) || defined(OS_LINUX_XLIB) || defined(OS_LINUX_XCB_GLX) -void (*GetExtension(const char *functionName))(void) { return glXGetProcAddress((const GLubyte *)functionName); } +void (*GetExtension(const char *functionName))() { return glXGetProcAddress((const GLubyte *)functionName); } #elif defined(OS_ANDROID) || defined(OS_LINUX_WAYLAND) -void (*GetExtension(const char *functionName))(void) { return eglGetProcAddress(functionName); } +void (*GetExtension(const char *functionName))() { return eglGetProcAddress(functionName); } #endif GLint glGetInteger(GLenum pname) { @@ -1629,7 +1662,6 @@ void ksGpuContext_UnsetCurrent(ksGpuContext *context) { #elif defined(OS_LINUX_XCB) xcb_glx_make_current(context->connection, 0, 0, 0); #elif defined(OS_APPLE_MACOS) - (void)context; CGLSetCurrentContext(NULL); #elif defined(OS_ANDROID) || defined(OS_LINUX_WAYLAND) EGL(eglMakeCurrent(context->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); @@ -2989,7 +3021,6 @@ NSAutoreleasePool *autoReleasePool; return YES; } - (void)keyDown:(NSEvent *)event { - (void)event; } @end @@ -3003,7 +3034,6 @@ NSAutoreleasePool *autoReleasePool; return YES; } - (void)keyDown:(NSEvent *)event { - (void)event; } @end @@ -3089,8 +3119,8 @@ bool ksGpuWindow_Create(ksGpuWindow *window, ksDriverInstance *instance, const k } } } - CGDisplayErr cgderr = CGDisplaySetDisplayMode(window->display, bestDisplayMode, NULL); - if (cgderr != CGDisplayNoErr) { + CGDisplayErr err = CGDisplaySetDisplayMode(window->display, bestDisplayMode, NULL); + if (err != CGDisplayNoErr) { CFRelease(displayModes); return false; } @@ -3284,6 +3314,151 @@ bool ksGpuWindow_Create(ksGpuWindow *window, ksDriverInstance *instance, const k #elif defined(OS_ANDROID) +typedef enum // https://developer.android.com/ndk/reference/group___input.html +{ KEY_A = AKEYCODE_A, + KEY_B = AKEYCODE_B, + KEY_C = AKEYCODE_C, + KEY_D = AKEYCODE_D, + KEY_E = AKEYCODE_E, + KEY_F = AKEYCODE_F, + KEY_G = AKEYCODE_G, + KEY_H = AKEYCODE_H, + KEY_I = AKEYCODE_I, + KEY_J = AKEYCODE_J, + KEY_K = AKEYCODE_K, + KEY_L = AKEYCODE_L, + KEY_M = AKEYCODE_M, + KEY_N = AKEYCODE_N, + KEY_O = AKEYCODE_O, + KEY_P = AKEYCODE_P, + KEY_Q = AKEYCODE_Q, + KEY_R = AKEYCODE_R, + KEY_S = AKEYCODE_S, + KEY_T = AKEYCODE_T, + KEY_U = AKEYCODE_U, + KEY_V = AKEYCODE_V, + KEY_W = AKEYCODE_W, + KEY_X = AKEYCODE_X, + KEY_Y = AKEYCODE_Y, + KEY_Z = AKEYCODE_Z, + KEY_RETURN = AKEYCODE_ENTER, + KEY_TAB = AKEYCODE_TAB, + KEY_ESCAPE = AKEYCODE_ESCAPE, + KEY_SHIFT_LEFT = AKEYCODE_SHIFT_LEFT, + KEY_CTRL_LEFT = AKEYCODE_CTRL_LEFT, + KEY_ALT_LEFT = AKEYCODE_ALT_LEFT, + KEY_CURSOR_UP = AKEYCODE_DPAD_UP, + KEY_CURSOR_DOWN = AKEYCODE_DPAD_DOWN, + KEY_CURSOR_LEFT = AKEYCODE_DPAD_LEFT, + KEY_CURSOR_RIGHT = AKEYCODE_DPAD_RIGHT } ksKeyboardKey; + +typedef enum { MOUSE_LEFT = 0, MOUSE_RIGHT = 1 } ksMouseButton; + +static void app_handle_cmd(struct android_app *app, int32_t cmd) { + ksGpuWindow *window = (ksGpuWindow *)app->userData; + + switch (cmd) { + // There is no APP_CMD_CREATE. The ANativeActivity creates the + // application thread from onCreate(). The application thread + // then calls android_main(). + case APP_CMD_START: { + Print("onStart()"); + Print(" APP_CMD_START"); + break; + } + case APP_CMD_RESUME: { + Print("onResume()"); + Print(" APP_CMD_RESUME"); + window->resumed = true; + break; + } + case APP_CMD_PAUSE: { + Print("onPause()"); + Print(" APP_CMD_PAUSE"); + window->resumed = false; + break; + } + case APP_CMD_STOP: { + Print("onStop()"); + Print(" APP_CMD_STOP"); + break; + } + case APP_CMD_DESTROY: { + Print("onDestroy()"); + Print(" APP_CMD_DESTROY"); + window->nativeWindow = NULL; + break; + } + case APP_CMD_INIT_WINDOW: { + Print("surfaceCreated()"); + Print(" APP_CMD_INIT_WINDOW"); + window->nativeWindow = app->window; + break; + } + case APP_CMD_TERM_WINDOW: { + Print("surfaceDestroyed()"); + Print(" APP_CMD_TERM_WINDOW"); + window->nativeWindow = NULL; + break; + } + } +} + +static int32_t app_handle_input(struct android_app *app, AInputEvent *event) { + ksGpuWindow *window = (ksGpuWindow *)app->userData; + + const int type = AInputEvent_getType(event); + if (type == AINPUT_EVENT_TYPE_KEY) { + int keyCode = AKeyEvent_getKeyCode(event); + const int action = AKeyEvent_getAction(event); + if (action == AKEY_EVENT_ACTION_DOWN) { + // Translate controller input to useful keys. + switch (keyCode) { + case AKEYCODE_BUTTON_A: + keyCode = AKEYCODE_Q; + break; + case AKEYCODE_BUTTON_B: + keyCode = AKEYCODE_W; + break; + case AKEYCODE_BUTTON_X: + keyCode = AKEYCODE_E; + break; + case AKEYCODE_BUTTON_Y: + keyCode = AKEYCODE_M; + break; + case AKEYCODE_BUTTON_START: + keyCode = AKEYCODE_L; + break; + case AKEYCODE_BUTTON_SELECT: + keyCode = AKEYCODE_ESCAPE; + break; + } + if (keyCode >= 0 && keyCode < 256) { + window->input.keyInput[keyCode] = true; + return 1; + } + } + return 0; + } else if (type == AINPUT_EVENT_TYPE_MOTION) { + const int source = AInputEvent_getSource(event); + // Events with source == AINPUT_SOURCE_TOUCHSCREEN come from the phone's builtin touch screen. + // Events with source == AINPUT_SOURCE_MOUSE come from the trackpad on the right side of the GearVR. + if (source == AINPUT_SOURCE_TOUCHSCREEN || source == AINPUT_SOURCE_MOUSE) { + const int action = AKeyEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK; + const float x = AMotionEvent_getRawX(event, 0); + const float y = AMotionEvent_getRawY(event, 0); + if (action == AMOTION_EVENT_ACTION_UP) { + window->input.mouseInput[MOUSE_LEFT] = true; + window->input.mouseInputX[MOUSE_LEFT] = (int)x; + window->input.mouseInputY[MOUSE_LEFT] = (int)y; + return 1; + } + return 0; + } + } + return 0; +} + void ksGpuWindow_Destroy(ksGpuWindow *window) { ksGpuContext_Destroy(&window->context); ksGpuDevice_Destroy(&window->device); @@ -3292,8 +3467,52 @@ void ksGpuWindow_Destroy(ksGpuWindow *window) { EGL(eglTerminate(window->display)); window->display = 0; } + + if (window->app != NULL) { + (*window->java.vm)->DetachCurrentThread(window->java.vm); + window->java.vm = NULL; + window->java.env = NULL; + window->java.activity = 0; + } } +static float GetDisplayRefreshRate(const Java_t *java) { + // Retrieve Context.WINDOW_SERVICE. + jclass contextClass = (*java->env)->FindClass(java->env, "android/content/Context"); + jfieldID field_WINDOW_SERVICE = (*java->env)->GetStaticFieldID(java->env, contextClass, "WINDOW_SERVICE", "Ljava/lang/String;"); + jobject WINDOW_SERVICE = (*java->env)->GetStaticObjectField(java->env, contextClass, field_WINDOW_SERVICE); + (*java->env)->DeleteLocalRef(java->env, contextClass); + + // WindowManager windowManager = (WindowManager) activity.getSystemService( Context.WINDOW_SERVICE ); + const jclass activityClass = (*java->env)->GetObjectClass(java->env, java->activity); + const jmethodID getSystemServiceMethodId = + (*java->env)->GetMethodID(java->env, activityClass, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"); + const jobject windowManager = + (*java->env)->CallObjectMethod(java->env, java->activity, getSystemServiceMethodId, WINDOW_SERVICE); + (*java->env)->DeleteLocalRef(java->env, activityClass); + + // Display display = windowManager.getDefaultDisplay(); + const jclass windowManagerClass = (*java->env)->GetObjectClass(java->env, windowManager); + const jmethodID getDefaultDisplayMethodId = + (*java->env)->GetMethodID(java->env, windowManagerClass, "getDefaultDisplay", "()Landroid/view/Display;"); + const jobject display = (*java->env)->CallObjectMethod(java->env, windowManager, getDefaultDisplayMethodId); + (*java->env)->DeleteLocalRef(java->env, windowManagerClass); + + // float refreshRate = display.getRefreshRate(); + const jclass displayClass = (*java->env)->GetObjectClass(java->env, display); + const jmethodID getRefreshRateMethodId = (*java->env)->GetMethodID(java->env, displayClass, "getRefreshRate", "()F"); + const float refreshRate = (*java->env)->CallFloatMethod(java->env, display, getRefreshRateMethodId); + (*java->env)->DeleteLocalRef(java->env, displayClass); + + (*java->env)->DeleteLocalRef(java->env, display); + (*java->env)->DeleteLocalRef(java->env, windowManager); + (*java->env)->DeleteLocalRef(java->env, WINDOW_SERVICE); + + return refreshRate; +} + +struct android_app *global_app; + bool ksGpuWindow_Create(ksGpuWindow *window, ksDriverInstance *instance, const ksGpuQueueInfo *queueInfo, const int queueIndex, const ksGpuSurfaceColorFormat colorFormat, const ksGpuSurfaceDepthFormat depthFormat, const ksGpuSampleCount sampleCount, const int width, const int height, const bool fullscreen) { @@ -3311,6 +3530,25 @@ bool ksGpuWindow_Create(ksGpuWindow *window, ksDriverInstance *instance, const k window->windowActive = false; window->windowExit = false; + window->app = global_app; + window->nativeWindow = NULL; + window->resumed = false; + + if (window->app != NULL) { + window->app->userData = window; + window->app->onAppCmd = app_handle_cmd; + window->app->onInputEvent = app_handle_input; + window->java.vm = window->app->activity->vm; + (*window->java.vm)->AttachCurrentThread(window->java.vm, &window->java.env, NULL); + window->java.activity = window->app->activity->clazz; + + window->windowRefreshRate = GetDisplayRefreshRate(&window->java); + + // Keep the display on and bright. + // Also make sure there is only one "HWC" next to the "FB TARGET" (adb shell dumpsys SurfaceFlinger). + ANativeActivity_setWindowFlags(window->app->activity, AWINDOW_FLAG_FULLSCREEN | AWINDOW_FLAG_KEEP_SCREEN_ON, 0); + } + window->display = eglGetDisplay(EGL_DEFAULT_DISPLAY); EGL(eglInitialize(window->display, &window->majorVersion, &window->minorVersion)); diff --git a/src/common/gfxwrapper_opengl.h b/src/common/gfxwrapper_opengl.h index a4c245d31..1243ae832 100644 --- a/src/common/gfxwrapper_opengl.h +++ b/src/common/gfxwrapper_opengl.h @@ -124,9 +124,9 @@ extern "C" { #elif defined(__APPLE__) #define OS_APPLE #include -#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED +#if __IPHONE_OS_VERSION_MAX_ALLOWED #define OS_APPLE_IOS -#elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED +#elif __MAC_OS_X_VERSION_MAX_ALLOWED #define OS_APPLE_MACOS #endif #elif defined(__linux__) @@ -334,6 +334,7 @@ CGLError CGLUpdateContext(CGLContextObj ctx); #include // for AKEYCODE_ etc. #include // for AWINDOW_FLAG_KEEP_SCREEN_ON #include // for native window JNI +#include #include #include #include @@ -414,7 +415,7 @@ Common defines #define ES_HIGHP "" // GLSL "430" disallows a precision qualifier on a image2D #endif -void GlInitExtensions(void); +void GlInitExtensions(); /* ================================================================================================================================ @@ -988,7 +989,10 @@ typedef struct { EGLDisplay display; EGLint majorVersion; EGLint minorVersion; + struct android_app *app; Java_t java; + ANativeWindow *nativeWindow; + bool resumed; #endif } ksGpuWindow; diff --git a/src/common/object_info.cpp b/src/common/object_info.cpp index 3f8f96bc6..3f6b39c43 100644 --- a/src/common/object_info.cpp +++ b/src/common/object_info.cpp @@ -132,8 +132,6 @@ XrSdkSessionLabel::XrSdkSessionLabel(const XrDebugUtilsLabelEXT& label_info, boo : label_name(label_info.labelName), debug_utils_label(label_info), is_individual_label(individual) { // Update the c string pointer to the one we hold. debug_utils_label.labelName = label_name.c_str(); - // Zero out the next pointer to avoid a dangling pointer - debug_utils_label.next = nullptr; } XrSdkSessionLabelPtr XrSdkSessionLabel::make(const XrDebugUtilsLabelEXT& label_info, bool individual) { @@ -145,7 +143,7 @@ void DebugUtilsData::AddObjectName(uint64_t object_handle, XrObjectType object_t } // We always want to remove the old individual label before we do anything else. -// So, do that in its own method +// So, do that in it's own method void DebugUtilsData::RemoveIndividualLabel(XrSdkSessionLabelList& label_vec) { if (!label_vec.empty() && label_vec.back()->is_individual_label) { label_vec.pop_back(); diff --git a/src/common/platform_utils.hpp b/src/common/platform_utils.hpp index 219d19789..6ea95f4ef 100644 --- a/src/common/platform_utils.hpp +++ b/src/common/platform_utils.hpp @@ -11,7 +11,6 @@ #include "xr_dependencies.h" #include -#include #include // OpenXR paths and registry key locations @@ -60,11 +59,9 @@ static inline char* ImplGetSecureEnv(const char* name) { #elif defined(HAVE___SECURE_GETENV) return __secure_getenv(name); #else -// clang-format off #pragma message( \ "Warning: Falling back to non-secure getenv for environmental" \ "lookups! Consider updating to a different libc.") - // clang-format on return ImplGetEnv(name); #endif @@ -316,7 +313,7 @@ static inline bool PlatformUtilsSetEnv(const char* /* name */, const char* /* va // Intended to be only used as a fallback on Android, with a more open, "native" technique used in most cases static inline bool PlatformGetGlobalRuntimeFileName(uint16_t major_version, std::string& file_name) { // Prefix for the runtime JSON file name - static const char* rt_dir_prefixes[] = {"/product", "/odm", "/oem", "/vendor", "/system"}; + static const char* rt_dir_prefixes[] = {"/oem", "/vendor", "/system"}; static const std::string rt_filename = "/active_runtime.json"; static const std::string subdir = "/etc/openxr/"; for (const auto prefix : rt_dir_prefixes) { diff --git a/src/external/earcut/include/earcut.hpp b/src/external/earcut/include/earcut.hpp new file mode 100644 index 000000000..a73ae87c8 --- /dev/null +++ b/src/external/earcut/include/earcut.hpp @@ -0,0 +1,816 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mapbox { + +namespace util { + +template struct nth { + inline static typename std::tuple_element::type + get(const T& t) { return std::get(t); }; +}; + +} + +namespace detail { + +template +class Earcut { +public: + std::vector indices; + std::size_t vertices = 0; + + template + void operator()(const Polygon& points); + +private: + struct Node { + Node(N index, double x_, double y_) : i(index), x(x_), y(y_) {} + Node(const Node&) = delete; + Node& operator=(const Node&) = delete; + Node(Node&&) = delete; + Node& operator=(Node&&) = delete; + + const N i; + const double x; + const double y; + + // previous and next vertice nodes in a polygon ring + Node* prev = nullptr; + Node* next = nullptr; + + // z-order curve value + int32_t z = 0; + + // previous and next nodes in z-order + Node* prevZ = nullptr; + Node* nextZ = nullptr; + + // indicates whether this is a steiner point + bool steiner = false; + }; + + template Node* linkedList(const Ring& points, const bool clockwise); + Node* filterPoints(Node* start, Node* end = nullptr); + void earcutLinked(Node* ear, int pass = 0); + bool isEar(Node* ear); + bool isEarHashed(Node* ear); + Node* cureLocalIntersections(Node* start); + void splitEarcut(Node* start); + template Node* eliminateHoles(const Polygon& points, Node* outerNode); + Node* eliminateHole(Node* hole, Node* outerNode); + Node* findHoleBridge(Node* hole, Node* outerNode); + bool sectorContainsSector(const Node* m, const Node* p); + void indexCurve(Node* start); + Node* sortLinked(Node* list); + int32_t zOrder(const double x_, const double y_); + Node* getLeftmost(Node* start); + bool pointInTriangle(double ax, double ay, double bx, double by, double cx, double cy, double px, double py) const; + bool isValidDiagonal(Node* a, Node* b); + double area(const Node* p, const Node* q, const Node* r) const; + bool equals(const Node* p1, const Node* p2); + bool intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2); + bool onSegment(const Node* p, const Node* q, const Node* r); + int sign(double val); + bool intersectsPolygon(const Node* a, const Node* b); + bool locallyInside(const Node* a, const Node* b); + bool middleInside(const Node* a, const Node* b); + Node* splitPolygon(Node* a, Node* b); + template Node* insertNode(std::size_t i, const Point& p, Node* last); + void removeNode(Node* p); + + bool hashing; + double minX, maxX; + double minY, maxY; + double inv_size = 0; + + template > + class ObjectPool { + public: + ObjectPool() { } + ObjectPool(std::size_t blockSize_) { + reset(blockSize_); + } + ~ObjectPool() { + clear(); + } + template + T* construct(Args&&... args) { + if (currentIndex >= blockSize) { + currentBlock = alloc_traits::allocate(alloc, blockSize); + allocations.emplace_back(currentBlock); + currentIndex = 0; + } + T* object = ¤tBlock[currentIndex++]; + alloc_traits::construct(alloc, object, std::forward(args)...); + return object; + } + void reset(std::size_t newBlockSize) { + for (auto allocation : allocations) { + alloc_traits::deallocate(alloc, allocation, blockSize); + } + allocations.clear(); + blockSize = std::max(1, newBlockSize); + currentBlock = nullptr; + currentIndex = blockSize; + } + void clear() { reset(blockSize); } + private: + T* currentBlock = nullptr; + std::size_t currentIndex = 1; + std::size_t blockSize = 1; + std::vector allocations; + Alloc alloc; + typedef typename std::allocator_traits alloc_traits; + }; + ObjectPool nodes; +}; + +template template +void Earcut::operator()(const Polygon& points) { + // reset + indices.clear(); + vertices = 0; + + if (points.empty()) return; + + double x; + double y; + int threshold = 80; + std::size_t len = 0; + + for (size_t i = 0; threshold >= 0 && i < points.size(); i++) { + threshold -= static_cast(points[i].size()); + len += points[i].size(); + } + + //estimate size of nodes and indices + nodes.reset(len * 3 / 2); + indices.reserve(len + points[0].size()); + + Node* outerNode = linkedList(points[0], true); + if (!outerNode || outerNode->prev == outerNode->next) return; + + if (points.size() > 1) outerNode = eliminateHoles(points, outerNode); + + // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox + hashing = threshold < 0; + if (hashing) { + Node* p = outerNode->next; + minX = maxX = outerNode->x; + minY = maxY = outerNode->y; + do { + x = p->x; + y = p->y; + minX = std::min(minX, x); + minY = std::min(minY, y); + maxX = std::max(maxX, x); + maxY = std::max(maxY, y); + p = p->next; + } while (p != outerNode); + + // minX, minY and inv_size are later used to transform coords into integers for z-order calculation + inv_size = std::max(maxX - minX, maxY - minY); + inv_size = inv_size != .0 ? (32767. / inv_size) : .0; + } + + earcutLinked(outerNode); + + nodes.clear(); +} + +// create a circular doubly linked list from polygon points in the specified winding order +template template +typename Earcut::Node* +Earcut::linkedList(const Ring& points, const bool clockwise) { + using Point = typename Ring::value_type; + double sum = 0; + const std::size_t len = points.size(); + std::size_t i, j; + Node* last = nullptr; + + // calculate original winding order of a polygon ring + for (i = 0, j = len > 0 ? len - 1 : 0; i < len; j = i++) { + const auto& p1 = points[i]; + const auto& p2 = points[j]; + const double p20 = util::nth<0, Point>::get(p2); + const double p10 = util::nth<0, Point>::get(p1); + const double p11 = util::nth<1, Point>::get(p1); + const double p21 = util::nth<1, Point>::get(p2); + sum += (p20 - p10) * (p11 + p21); + } + + // link points into circular doubly-linked list in the specified winding order + if (clockwise == (sum > 0)) { + for (i = 0; i < len; i++) last = insertNode(vertices + i, points[i], last); + } else { + for (i = len; i-- > 0;) last = insertNode(vertices + i, points[i], last); + } + + if (last && equals(last, last->next)) { + removeNode(last); + last = last->next; + } + + vertices += len; + + return last; +} + +// eliminate colinear or duplicate points +template +typename Earcut::Node* +Earcut::filterPoints(Node* start, Node* end) { + if (!end) end = start; + + Node* p = start; + bool again; + do { + again = false; + + if (!p->steiner && (equals(p, p->next) || area(p->prev, p, p->next) == 0)) { + removeNode(p); + p = end = p->prev; + + if (p == p->next) break; + again = true; + + } else { + p = p->next; + } + } while (again || p != end); + + return end; +} + +// main ear slicing loop which triangulates a polygon (given as a linked list) +template +void Earcut::earcutLinked(Node* ear, int pass) { + if (!ear) return; + + // interlink polygon nodes in z-order + if (!pass && hashing) indexCurve(ear); + + Node* stop = ear; + Node* prev; + Node* next; + + int iterations = 0; + + // iterate through ears, slicing them one by one + while (ear->prev != ear->next) { + iterations++; + prev = ear->prev; + next = ear->next; + + if (hashing ? isEarHashed(ear) : isEar(ear)) { + // cut off the triangle + indices.emplace_back(prev->i); + indices.emplace_back(ear->i); + indices.emplace_back(next->i); + + removeNode(ear); + + // skipping the next vertice leads to less sliver triangles + ear = next->next; + stop = next->next; + + continue; + } + + ear = next; + + // if we looped through the whole remaining polygon and can't find any more ears + if (ear == stop) { + // try filtering points and slicing again + if (!pass) earcutLinked(filterPoints(ear), 1); + + // if this didn't work, try curing all small self-intersections locally + else if (pass == 1) { + ear = cureLocalIntersections(filterPoints(ear)); + earcutLinked(ear, 2); + + // as a last resort, try splitting the remaining polygon into two + } else if (pass == 2) splitEarcut(ear); + + break; + } + } +} + +// check whether a polygon node forms a valid ear with adjacent nodes +template +bool Earcut::isEar(Node* ear) { + const Node* a = ear->prev; + const Node* b = ear; + const Node* c = ear->next; + + if (area(a, b, c) >= 0) return false; // reflex, can't be an ear + + // now make sure we don't have other points inside the potential ear + Node* p = ear->next->next; + + while (p != ear->prev) { + if (pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) && + area(p->prev, p, p->next) >= 0) return false; + p = p->next; + } + + return true; +} + +template +bool Earcut::isEarHashed(Node* ear) { + const Node* a = ear->prev; + const Node* b = ear; + const Node* c = ear->next; + + if (area(a, b, c) >= 0) return false; // reflex, can't be an ear + + // triangle bbox; min & max are calculated like this for speed + const double minTX = std::min(a->x, std::min(b->x, c->x)); + const double minTY = std::min(a->y, std::min(b->y, c->y)); + const double maxTX = std::max(a->x, std::max(b->x, c->x)); + const double maxTY = std::max(a->y, std::max(b->y, c->y)); + + // z-order range for the current triangle bbox; + const int32_t minZ = zOrder(minTX, minTY); + const int32_t maxZ = zOrder(maxTX, maxTY); + + // first look for points inside the triangle in increasing z-order + Node* p = ear->nextZ; + + while (p && p->z <= maxZ) { + if (p != ear->prev && p != ear->next && + pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) && + area(p->prev, p, p->next) >= 0) return false; + p = p->nextZ; + } + + // then look for points in decreasing z-order + p = ear->prevZ; + + while (p && p->z >= minZ) { + if (p != ear->prev && p != ear->next && + pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) && + area(p->prev, p, p->next) >= 0) return false; + p = p->prevZ; + } + + return true; +} + +// go through all polygon nodes and cure small local self-intersections +template +typename Earcut::Node* +Earcut::cureLocalIntersections(Node* start) { + Node* p = start; + do { + Node* a = p->prev; + Node* b = p->next->next; + + // a self-intersection where edge (v[i-1],v[i]) intersects (v[i+1],v[i+2]) + if (!equals(a, b) && intersects(a, p, p->next, b) && locallyInside(a, b) && locallyInside(b, a)) { + indices.emplace_back(a->i); + indices.emplace_back(p->i); + indices.emplace_back(b->i); + + // remove two nodes involved + removeNode(p); + removeNode(p->next); + + p = start = b; + } + p = p->next; + } while (p != start); + + return filterPoints(p); +} + +// try splitting polygon into two and triangulate them independently +template +void Earcut::splitEarcut(Node* start) { + // look for a valid diagonal that divides the polygon into two + Node* a = start; + do { + Node* b = a->next->next; + while (b != a->prev) { + if (a->i != b->i && isValidDiagonal(a, b)) { + // split the polygon in two by the diagonal + Node* c = splitPolygon(a, b); + + // filter colinear points around the cuts + a = filterPoints(a, a->next); + c = filterPoints(c, c->next); + + // run earcut on each half + earcutLinked(a); + earcutLinked(c); + return; + } + b = b->next; + } + a = a->next; + } while (a != start); +} + +// link every hole into the outer loop, producing a single-ring polygon without holes +template template +typename Earcut::Node* +Earcut::eliminateHoles(const Polygon& points, Node* outerNode) { + const size_t len = points.size(); + + std::vector queue; + for (size_t i = 1; i < len; i++) { + Node* list = linkedList(points[i], false); + if (list) { + if (list == list->next) list->steiner = true; + queue.push_back(getLeftmost(list)); + } + } + std::sort(queue.begin(), queue.end(), [](const Node* a, const Node* b) { + return a->x < b->x; + }); + + // process holes from left to right + for (size_t i = 0; i < queue.size(); i++) { + outerNode = eliminateHole(queue[i], outerNode); + } + + return outerNode; +} + +// find a bridge between vertices that connects hole with an outer ring and and link it +template +typename Earcut::Node* +Earcut::eliminateHole(Node* hole, Node* outerNode) { + Node* bridge = findHoleBridge(hole, outerNode); + if (!bridge) { + return outerNode; + } + + Node* bridgeReverse = splitPolygon(bridge, hole); + + // filter collinear points around the cuts + filterPoints(bridgeReverse, bridgeReverse->next); + + // Check if input node was removed by the filtering + return filterPoints(bridge, bridge->next); +} + +// David Eberly's algorithm for finding a bridge between hole and outer polygon +template +typename Earcut::Node* +Earcut::findHoleBridge(Node* hole, Node* outerNode) { + Node* p = outerNode; + double hx = hole->x; + double hy = hole->y; + double qx = -std::numeric_limits::infinity(); + Node* m = nullptr; + + // find a segment intersected by a ray from the hole's leftmost Vertex to the left; + // segment's endpoint with lesser x will be potential connection Vertex + do { + if (hy <= p->y && hy >= p->next->y && p->next->y != p->y) { + double x = p->x + (hy - p->y) * (p->next->x - p->x) / (p->next->y - p->y); + if (x <= hx && x > qx) { + qx = x; + m = p->x < p->next->x ? p : p->next; + if (x == hx) return m; // hole touches outer segment; pick leftmost endpoint + } + } + p = p->next; + } while (p != outerNode); + + if (!m) return 0; + + // look for points inside the triangle of hole Vertex, segment intersection and endpoint; + // if there are no points found, we have a valid connection; + // otherwise choose the Vertex of the minimum angle with the ray as connection Vertex + + const Node* stop = m; + double tanMin = std::numeric_limits::infinity(); + double tanCur = 0; + + p = m; + double mx = m->x; + double my = m->y; + + do { + if (hx >= p->x && p->x >= mx && hx != p->x && + pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p->x, p->y)) { + + tanCur = std::abs(hy - p->y) / (hx - p->x); // tangential + + if (locallyInside(p, hole) && + (tanCur < tanMin || (tanCur == tanMin && (p->x > m->x || sectorContainsSector(m, p))))) { + m = p; + tanMin = tanCur; + } + } + + p = p->next; + } while (p != stop); + + return m; +} + +// whether sector in vertex m contains sector in vertex p in the same coordinates +template +bool Earcut::sectorContainsSector(const Node* m, const Node* p) { + return area(m->prev, m, p->prev) < 0 && area(p->next, m, m->next) < 0; +} + +// interlink polygon nodes in z-order +template +void Earcut::indexCurve(Node* start) { + assert(start); + Node* p = start; + + do { + p->z = p->z ? p->z : zOrder(p->x, p->y); + p->prevZ = p->prev; + p->nextZ = p->next; + p = p->next; + } while (p != start); + + p->prevZ->nextZ = nullptr; + p->prevZ = nullptr; + + sortLinked(p); +} + +// Simon Tatham's linked list merge sort algorithm +// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html +template +typename Earcut::Node* +Earcut::sortLinked(Node* list) { + assert(list); + Node* p; + Node* q; + Node* e; + Node* tail; + int i, numMerges, pSize, qSize; + int inSize = 1; + + for (;;) { + p = list; + list = nullptr; + tail = nullptr; + numMerges = 0; + + while (p) { + numMerges++; + q = p; + pSize = 0; + for (i = 0; i < inSize; i++) { + pSize++; + q = q->nextZ; + if (!q) break; + } + + qSize = inSize; + + while (pSize > 0 || (qSize > 0 && q)) { + + if (pSize == 0) { + e = q; + q = q->nextZ; + qSize--; + } else if (qSize == 0 || !q) { + e = p; + p = p->nextZ; + pSize--; + } else if (p->z <= q->z) { + e = p; + p = p->nextZ; + pSize--; + } else { + e = q; + q = q->nextZ; + qSize--; + } + + if (tail) tail->nextZ = e; + else list = e; + + e->prevZ = tail; + tail = e; + } + + p = q; + } + + tail->nextZ = nullptr; + + if (numMerges <= 1) return list; + + inSize *= 2; + } +} + +// z-order of a Vertex given coords and size of the data bounding box +template +int32_t Earcut::zOrder(const double x_, const double y_) { + // coords are transformed into non-negative 15-bit integer range + int32_t x = static_cast((x_ - minX) * inv_size); + int32_t y = static_cast((y_ - minY) * inv_size); + + x = (x | (x << 8)) & 0x00FF00FF; + x = (x | (x << 4)) & 0x0F0F0F0F; + x = (x | (x << 2)) & 0x33333333; + x = (x | (x << 1)) & 0x55555555; + + y = (y | (y << 8)) & 0x00FF00FF; + y = (y | (y << 4)) & 0x0F0F0F0F; + y = (y | (y << 2)) & 0x33333333; + y = (y | (y << 1)) & 0x55555555; + + return x | (y << 1); +} + +// find the leftmost node of a polygon ring +template +typename Earcut::Node* +Earcut::getLeftmost(Node* start) { + Node* p = start; + Node* leftmost = start; + do { + if (p->x < leftmost->x || (p->x == leftmost->x && p->y < leftmost->y)) + leftmost = p; + p = p->next; + } while (p != start); + + return leftmost; +} + +// check if a point lies within a convex triangle +template +bool Earcut::pointInTriangle(double ax, double ay, double bx, double by, double cx, double cy, double px, double py) const { + return (cx - px) * (ay - py) >= (ax - px) * (cy - py) && + (ax - px) * (by - py) >= (bx - px) * (ay - py) && + (bx - px) * (cy - py) >= (cx - px) * (by - py); +} + +// check if a diagonal between two polygon nodes is valid (lies in polygon interior) +template +bool Earcut::isValidDiagonal(Node* a, Node* b) { + return a->next->i != b->i && a->prev->i != b->i && !intersectsPolygon(a, b) && // dones't intersect other edges + ((locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible + (area(a->prev, a, b->prev) != 0.0 || area(a, b->prev, b) != 0.0)) || // does not create opposite-facing sectors + (equals(a, b) && area(a->prev, a, a->next) > 0 && area(b->prev, b, b->next) > 0)); // special zero-length case +} + +// signed area of a triangle +template +double Earcut::area(const Node* p, const Node* q, const Node* r) const { + return (q->y - p->y) * (r->x - q->x) - (q->x - p->x) * (r->y - q->y); +} + +// check if two points are equal +template +bool Earcut::equals(const Node* p1, const Node* p2) { + return p1->x == p2->x && p1->y == p2->y; +} + +// check if two segments intersect +template +bool Earcut::intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2) { + int o1 = sign(area(p1, q1, p2)); + int o2 = sign(area(p1, q1, q2)); + int o3 = sign(area(p2, q2, p1)); + int o4 = sign(area(p2, q2, q1)); + + if (o1 != o2 && o3 != o4) return true; // general case + + if (o1 == 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1 + if (o2 == 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1 + if (o3 == 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2 + if (o4 == 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2 + + return false; +} + +// for collinear points p, q, r, check if point q lies on segment pr +template +bool Earcut::onSegment(const Node* p, const Node* q, const Node* r) { + return q->x <= std::max(p->x, r->x) && + q->x >= std::min(p->x, r->x) && + q->y <= std::max(p->y, r->y) && + q->y >= std::min(p->y, r->y); +} + +template +int Earcut::sign(double val) { + return (0.0 < val) - (val < 0.0); +} + +// check if a polygon diagonal intersects any polygon segments +template +bool Earcut::intersectsPolygon(const Node* a, const Node* b) { + const Node* p = a; + do { + if (p->i != a->i && p->next->i != a->i && p->i != b->i && p->next->i != b->i && + intersects(p, p->next, a, b)) return true; + p = p->next; + } while (p != a); + + return false; +} + +// check if a polygon diagonal is locally inside the polygon +template +bool Earcut::locallyInside(const Node* a, const Node* b) { + return area(a->prev, a, a->next) < 0 ? + area(a, b, a->next) >= 0 && area(a, a->prev, b) >= 0 : + area(a, b, a->prev) < 0 || area(a, a->next, b) < 0; +} + +// check if the middle Vertex of a polygon diagonal is inside the polygon +template +bool Earcut::middleInside(const Node* a, const Node* b) { + const Node* p = a; + bool inside = false; + double px = (a->x + b->x) / 2; + double py = (a->y + b->y) / 2; + do { + if (((p->y > py) != (p->next->y > py)) && p->next->y != p->y && + (px < (p->next->x - p->x) * (py - p->y) / (p->next->y - p->y) + p->x)) + inside = !inside; + p = p->next; + } while (p != a); + + return inside; +} + +// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits +// polygon into two; if one belongs to the outer ring and another to a hole, it merges it into a +// single ring +template +typename Earcut::Node* +Earcut::splitPolygon(Node* a, Node* b) { + Node* a2 = nodes.construct(a->i, a->x, a->y); + Node* b2 = nodes.construct(b->i, b->x, b->y); + Node* an = a->next; + Node* bp = b->prev; + + a->next = b; + b->prev = a; + + a2->next = an; + an->prev = a2; + + b2->next = a2; + a2->prev = b2; + + bp->next = b2; + b2->prev = bp; + + return b2; +} + +// create a node and util::optionally link it with previous one (in a circular doubly linked list) +template template +typename Earcut::Node* +Earcut::insertNode(std::size_t i, const Point& pt, Node* last) { + Node* p = nodes.construct(static_cast(i), util::nth<0, Point>::get(pt), util::nth<1, Point>::get(pt)); + + if (!last) { + p->prev = p; + p->next = p; + + } else { + assert(last); + p->next = last->next; + p->prev = last; + last->next->prev = p; + last->next = p; + } + return p; +} + +template +void Earcut::removeNode(Node* p) { + p->next->prev = p->prev; + p->prev->next = p->next; + + if (p->prevZ) p->prevZ->nextZ = p->nextZ; + if (p->nextZ) p->nextZ->prevZ = p->prevZ; +} +} + +template +std::vector earcut(const Polygon& poly) { + mapbox::detail::Earcut earcut; + earcut(poly); + return std::move(earcut.indices); +} +} diff --git a/src/external/earcut/include/earcut.hpp.license b/src/external/earcut/include/earcut.hpp.license new file mode 100644 index 000000000..612906b5d --- /dev/null +++ b/src/external/earcut/include/earcut.hpp.license @@ -0,0 +1,6 @@ +Copyright (c) 2015, Mapbox + +SPDX-License-Identifier: ISC + + +From https://github.com/mapbox/earcut.hpp diff --git a/src/external/jnipp/jnipp.cpp b/src/external/jnipp/jnipp.cpp index 8309e54cf..45a8e9d87 100644 --- a/src/external/jnipp/jnipp.cpp +++ b/src/external/jnipp/jnipp.cpp @@ -465,13 +465,6 @@ namespace jni return Object(result, DeleteLocalInput); } - jarray Object::callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const - { - auto result = env()->CallObjectMethodA(_handle, method, (jvalue*) args); - handleJavaExceptions(); - return (jarray)result; - } - byte_t Object::getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const { return env()->GetByteField(_handle, field); diff --git a/src/external/jnipp/jnipp.h b/src/external/jnipp/jnipp.h index 0cda2dd43..017bdd923 100644 --- a/src/external/jnipp/jnipp.h +++ b/src/external/jnipp/jnipp.h @@ -73,7 +73,6 @@ namespace jni // Foward Declarations class Object; - template class Array; /** This namespace is for messy implementation details only. It is not a part @@ -104,9 +103,6 @@ namespace jni std::string valueSig(const Object* obj); inline std::string valueSig(const Object* const* obj) { return valueSig(obj ? *obj : nullptr); } - template - inline std::string valueSig(const Array*) { return "[" + valueSig((TArg*) nullptr); } - template inline std::string valueSig(const TArg(*arg)[n]) { return valueSig((const TArg* const*)arg); } @@ -456,10 +452,7 @@ namespace jni std::string callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const; std::wstring callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const; jni::Object callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const; - jarray callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper const&) const; - template - jni::Array callMethod(method_t method, internal::value_t* args, internal::ReturnTypeWrapper> const&) const; void getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const; bool getFieldValue(field_t field, internal::ReturnTypeWrapper const&) const; @@ -1032,17 +1025,6 @@ namespace jni InitializationException(const char* msg) : Exception(msg) {} }; - /* - Call method returning array: implementation - */ - template - inline jni::Array Object::callMethod(method_t method, internal::value_t* args, - internal::ReturnTypeWrapper> const&) const - { - jarray result = callMethod(method, args, internal::ReturnTypeWrapper{}); - return jni::Array(result, DeleteLocalInput); - } - /* Array Implementation */ diff --git a/src/external/jnipp/tests/main.cpp b/src/external/jnipp/tests/main.cpp index 471484753..7c1adfcb1 100644 --- a/src/external/jnipp/tests/main.cpp +++ b/src/external/jnipp/tests/main.cpp @@ -304,21 +304,6 @@ TEST(Object_call_byNameWithArgs) ASSERT(str2.call("charAt", 1) == L'e'); } -TEST(Object_call_returningArray) { - jni::Object str = jni::Class("java/lang/String").newInstance("Testing"); - - { - auto getBytes = - jni::Class("java/lang/String").getMethod("getBytes", "()[B"); - auto bytes = str.call>(getBytes); - ASSERT(bytes.getLength() == 7); - } - { - auto bytes = str.call>("getBytes"); - ASSERT(bytes.getLength() == 7); - } -} - TEST(Object_makeLocalReference) { jni::Object str = jni::Class("java/lang/String").newInstance("Testing"); @@ -608,7 +593,6 @@ int main() RUN_TEST(Object_call_byName); RUN_TEST(Object_call_withArgs); RUN_TEST(Object_call_byNameWithArgs); - RUN_TEST(Object_call_returningArray); RUN_TEST(Object_makeLocalReference); // jni::Enum Tests diff --git a/src/external/span-lite/include/nonstd/span.hpp b/src/external/span-lite/include/nonstd/span.hpp new file mode 100644 index 000000000..ffac1188b --- /dev/null +++ b/src/external/span-lite/include/nonstd/span.hpp @@ -0,0 +1,1695 @@ +// +// span for C++98 and later. +// Based on http://wg21.link/p0122r7 +// For more information see https://github.com/martinmoene/span-lite +// +// Copyright 2018-2021 Martin Moene +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// SPDX-License-Identifier: BSL-1.0 + +// https://github.com/martinmoene/span-lite/blob/dbb484f6c2060b41afa55653dec99b228013a813/include/nonstd/span.hpp + +#ifndef NONSTD_SPAN_HPP_INCLUDED +#define NONSTD_SPAN_HPP_INCLUDED + +#define span_lite_MAJOR 0 +#define span_lite_MINOR 10 +#define span_lite_PATCH 3 + +#define span_lite_VERSION span_STRINGIFY(span_lite_MAJOR) "." span_STRINGIFY(span_lite_MINOR) "." span_STRINGIFY(span_lite_PATCH) + +#define span_STRINGIFY(x) span_STRINGIFY_(x) +#define span_STRINGIFY_(x) #x + +// span configuration: + +#define span_SPAN_DEFAULT 0 +#define span_SPAN_NONSTD 1 +#define span_SPAN_STD 2 + +// tweak header support: + +#ifdef __has_include +#if __has_include() +#include +#endif +#define span_HAVE_TWEAK_HEADER 1 +#else +#define span_HAVE_TWEAK_HEADER 0 +//# pragma message("span.hpp: Note: Tweak header not supported.") +#endif + +// span selection and configuration: + +#define span_HAVE(feature) (span_HAVE_##feature) + +#ifndef span_CONFIG_SELECT_SPAN +#define span_CONFIG_SELECT_SPAN (span_HAVE_STD_SPAN ? span_SPAN_STD : span_SPAN_NONSTD) +#endif + +#ifndef span_CONFIG_EXTENT_TYPE +#define span_CONFIG_EXTENT_TYPE std::size_t +#endif + +#ifndef span_CONFIG_SIZE_TYPE +#define span_CONFIG_SIZE_TYPE std::size_t +#endif + +#ifdef span_CONFIG_INDEX_TYPE +#error `span_CONFIG_INDEX_TYPE` is deprecated since v0.7.0; it is replaced by `span_CONFIG_SIZE_TYPE`. +#endif + +// span configuration (features): + +#ifndef span_FEATURE_WITH_INITIALIZER_LIST_P2447 +#define span_FEATURE_WITH_INITIALIZER_LIST_P2447 0 +#endif + +#ifndef span_FEATURE_WITH_CONTAINER +#ifdef span_FEATURE_WITH_CONTAINER_TO_STD +#define span_FEATURE_WITH_CONTAINER span_IN_STD(span_FEATURE_WITH_CONTAINER_TO_STD) +#else +#define span_FEATURE_WITH_CONTAINER 0 +#define span_FEATURE_WITH_CONTAINER_TO_STD 0 +#endif +#endif + +#ifndef span_FEATURE_CONSTRUCTION_FROM_STDARRAY_ELEMENT_TYPE +#define span_FEATURE_CONSTRUCTION_FROM_STDARRAY_ELEMENT_TYPE 0 +#endif + +#ifndef span_FEATURE_MEMBER_AT +#define span_FEATURE_MEMBER_AT 0 +#endif + +#ifndef span_FEATURE_MEMBER_BACK_FRONT +#define span_FEATURE_MEMBER_BACK_FRONT 1 +#endif + +#ifndef span_FEATURE_MEMBER_CALL_OPERATOR +#define span_FEATURE_MEMBER_CALL_OPERATOR 0 +#endif + +#ifndef span_FEATURE_MEMBER_SWAP +#define span_FEATURE_MEMBER_SWAP 0 +#endif + +#ifndef span_FEATURE_NON_MEMBER_FIRST_LAST_SUB +#define span_FEATURE_NON_MEMBER_FIRST_LAST_SUB 0 +#elif span_FEATURE_NON_MEMBER_FIRST_LAST_SUB +#define span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_SPAN 1 +#define span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_CONTAINER 1 +#endif + +#ifndef span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_SPAN +#define span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_SPAN 0 +#endif + +#ifndef span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_CONTAINER +#define span_FEATURE_NON_MEMBER_FIRST_LAST_SUB_CONTAINER 0 +#endif + +#ifndef span_FEATURE_COMPARISON +#define span_FEATURE_COMPARISON 0 // Note: C++20 does not provide comparison +#endif + +#ifndef span_FEATURE_SAME +#define span_FEATURE_SAME 0 +#endif + +#if span_FEATURE_SAME && !span_FEATURE_COMPARISON +#error `span_FEATURE_SAME` requires `span_FEATURE_COMPARISON` +#endif + +#ifndef span_FEATURE_MAKE_SPAN +#ifdef span_FEATURE_MAKE_SPAN_TO_STD +#define span_FEATURE_MAKE_SPAN span_IN_STD(span_FEATURE_MAKE_SPAN_TO_STD) +#else +#define span_FEATURE_MAKE_SPAN 0 +#define span_FEATURE_MAKE_SPAN_TO_STD 0 +#endif +#endif + +#ifndef span_FEATURE_BYTE_SPAN +#define span_FEATURE_BYTE_SPAN 0 +#endif + +// Control presence of exception handling (try and auto discover): + +#ifndef span_CONFIG_NO_EXCEPTIONS +#if defined(_MSC_VER) +#include // for _HAS_EXCEPTIONS +#endif +#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS) +#define span_CONFIG_NO_EXCEPTIONS 0 +#else +#define span_CONFIG_NO_EXCEPTIONS 1 +#undef span_CONFIG_CONTRACT_VIOLATION_THROWS +#undef span_CONFIG_CONTRACT_VIOLATION_TERMINATES +#define span_CONFIG_CONTRACT_VIOLATION_THROWS 0 +#define span_CONFIG_CONTRACT_VIOLATION_TERMINATES 1 +#endif +#endif + +// Control pre- and postcondition violation behaviour: + +#if defined(span_CONFIG_CONTRACT_LEVEL_ON) +#define span_CONFIG_CONTRACT_LEVEL_MASK 0x11 +#elif defined(span_CONFIG_CONTRACT_LEVEL_OFF) +#define span_CONFIG_CONTRACT_LEVEL_MASK 0x00 +#elif defined(span_CONFIG_CONTRACT_LEVEL_EXPECTS_ONLY) +#define span_CONFIG_CONTRACT_LEVEL_MASK 0x01 +#elif defined(span_CONFIG_CONTRACT_LEVEL_ENSURES_ONLY) +#define span_CONFIG_CONTRACT_LEVEL_MASK 0x10 +#else +#define span_CONFIG_CONTRACT_LEVEL_MASK 0x11 +#endif + +#if defined(span_CONFIG_CONTRACT_VIOLATION_THROWS) +#define span_CONFIG_CONTRACT_VIOLATION_THROWS_V span_CONFIG_CONTRACT_VIOLATION_THROWS +#else +#define span_CONFIG_CONTRACT_VIOLATION_THROWS_V 0 +#endif + +#if defined(span_CONFIG_CONTRACT_VIOLATION_THROWS) && span_CONFIG_CONTRACT_VIOLATION_THROWS && \ + defined(span_CONFIG_CONTRACT_VIOLATION_TERMINATES) && span_CONFIG_CONTRACT_VIOLATION_TERMINATES +# error Please define none or one of span_CONFIG_CONTRACT_VIOLATION_THROWS and span_CONFIG_CONTRACT_VIOLATION_TERMINATES to 1, but not both. +#endif + +// C++ language version detection (C++20 is speculative): +// Note: VC14.0/1900 (VS2015) lacks too much from C++14. + +#ifndef span_CPLUSPLUS +#if defined(_MSVC_LANG) && !defined(__clang__) +#define span_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG) +#else +#define span_CPLUSPLUS __cplusplus +#endif +#endif + +#define span_CPP98_OR_GREATER (span_CPLUSPLUS >= 199711L) +#define span_CPP11_OR_GREATER (span_CPLUSPLUS >= 201103L) +#define span_CPP14_OR_GREATER (span_CPLUSPLUS >= 201402L) +#define span_CPP17_OR_GREATER (span_CPLUSPLUS >= 201703L) +#define span_CPP20_OR_GREATER (span_CPLUSPLUS >= 202000L) + +// C++ language version (represent 98 as 3): + +#define span_CPLUSPLUS_V (span_CPLUSPLUS / 100 - (span_CPLUSPLUS > 200000 ? 2000 : 1994)) + +#define span_IN_STD(v) (((v) == 98 ? 3 : (v)) >= span_CPLUSPLUS_V) + +#define span_CONFIG(feature) (span_CONFIG_##feature) +#define span_FEATURE(feature) (span_FEATURE_##feature) +#define span_FEATURE_TO_STD(feature) (span_IN_STD(span_FEATURE(feature##_TO_STD))) + +// Use C++20 std::span if available and requested: + +#if span_CPP20_OR_GREATER && defined(__has_include) +#if __has_include( ) +#define span_HAVE_STD_SPAN 1 +#else +#define span_HAVE_STD_SPAN 0 +#endif +#else +#define span_HAVE_STD_SPAN 0 +#endif + +#define span_USES_STD_SPAN \ + ((span_CONFIG_SELECT_SPAN == span_SPAN_STD) || ((span_CONFIG_SELECT_SPAN == span_SPAN_DEFAULT) && span_HAVE_STD_SPAN)) + +// +// Use C++20 std::span: +// + +#if span_USES_STD_SPAN + +#include + +namespace nonstd { + +using std::span; + +// Note: C++20 does not provide comparison +// using std::operator==; +// using std::operator!=; +// using std::operator<; +// using std::operator<=; +// using std::operator>; +// using std::operator>=; +} // namespace nonstd + +#else // span_USES_STD_SPAN + +#include + +// Compiler versions: +// +// MSVC++ 6.0 _MSC_VER == 1200 span_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0) +// MSVC++ 7.0 _MSC_VER == 1300 span_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002) +// MSVC++ 7.1 _MSC_VER == 1310 span_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003) +// MSVC++ 8.0 _MSC_VER == 1400 span_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005) +// MSVC++ 9.0 _MSC_VER == 1500 span_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008) +// MSVC++ 10.0 _MSC_VER == 1600 span_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010) +// MSVC++ 11.0 _MSC_VER == 1700 span_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012) +// MSVC++ 12.0 _MSC_VER == 1800 span_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013) +// MSVC++ 14.0 _MSC_VER == 1900 span_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015) +// MSVC++ 14.1 _MSC_VER >= 1910 span_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017) +// MSVC++ 14.2 _MSC_VER >= 1920 span_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019) + +#if defined(_MSC_VER) && !defined(__clang__) +#define span_COMPILER_MSVC_VER (_MSC_VER) +#define span_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * (5 + (_MSC_VER < 1900))) +#else +#define span_COMPILER_MSVC_VER 0 +#define span_COMPILER_MSVC_VERSION 0 +#endif + +#define span_COMPILER_VERSION(major, minor, patch) (10 * (10 * (major) + (minor)) + (patch)) + +#if defined(__clang__) +#define span_COMPILER_CLANG_VERSION span_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) +#else +#define span_COMPILER_CLANG_VERSION 0 +#endif + +#if defined(__GNUC__) && !defined(__clang__) +#define span_COMPILER_GNUC_VERSION span_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#else +#define span_COMPILER_GNUC_VERSION 0 +#endif + +// half-open range [lo..hi): +#define span_BETWEEN(v, lo, hi) ((lo) <= (v) && (v) < (hi)) + +// Compiler warning suppression: + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundef" +#pragma clang diagnostic ignored "-Wmismatched-tags" +#define span_RESTORE_WARNINGS() _Pragma("clang diagnostic pop") + +#elif defined __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wundef" +#define span_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop") + +#elif span_COMPILER_MSVC_VER >= 1900 +#define span_DISABLE_MSVC_WARNINGS(codes) __pragma(warning(push)) __pragma(warning(disable : codes)) +#define span_RESTORE_WARNINGS() __pragma(warning(pop)) + +// Suppress the following MSVC GSL warnings: +// - C26439, gsl::f.6 : special function 'function' can be declared 'noexcept' +// - C26440, gsl::f.6 : function 'function' can be declared 'noexcept' +// - C26472, gsl::t.1 : don't use a static_cast for arithmetic conversions; +// use brace initialization, gsl::narrow_cast or gsl::narrow +// - C26473: gsl::t.1 : don't cast between pointer types where the source type and the target type are the same +// - C26481: gsl::b.1 : don't use pointer arithmetic. Use span instead +// - C26490: gsl::t.1 : don't use reinterpret_cast + +span_DISABLE_MSVC_WARNINGS(26439 26440 26472 26473 26481 26490) + +#else +#define span_RESTORE_WARNINGS() /*empty*/ +#endif + +// Presence of language and library features: + +#ifdef _HAS_CPP0X +#define span_HAS_CPP0X _HAS_CPP0X +#else +#define span_HAS_CPP0X 0 +#endif + +#define span_CPP11_80 (span_CPP11_OR_GREATER || span_COMPILER_MSVC_VER >= 1400) +#define span_CPP11_90 (span_CPP11_OR_GREATER || span_COMPILER_MSVC_VER >= 1500) +#define span_CPP11_100 (span_CPP11_OR_GREATER || span_COMPILER_MSVC_VER >= 1600) +#define span_CPP11_110 (span_CPP11_OR_GREATER || span_COMPILER_MSVC_VER >= 1700) +#define span_CPP11_120 (span_CPP11_OR_GREATER || span_COMPILER_MSVC_VER >= 1800) +#define span_CPP11_140 (span_CPP11_OR_GREATER || span_COMPILER_MSVC_VER >= 1900) + +#define span_CPP14_000 (span_CPP14_OR_GREATER) +#define span_CPP14_120 (span_CPP14_OR_GREATER || span_COMPILER_MSVC_VER >= 1800) +#define span_CPP14_140 (span_CPP14_OR_GREATER || span_COMPILER_MSVC_VER >= 1900) + +#define span_CPP17_000 (span_CPP17_OR_GREATER) + +// Presence of C++11 language features: + +#define span_HAVE_ALIAS_TEMPLATE span_CPP11_140 +#define span_HAVE_AUTO span_CPP11_100 +#define span_HAVE_CONSTEXPR_11 span_CPP11_140 +#define span_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG span_CPP11_120 +#define span_HAVE_EXPLICIT_CONVERSION span_CPP11_140 +#define span_HAVE_INITIALIZER_LIST span_CPP11_120 +#define span_HAVE_IS_DEFAULT span_CPP11_140 +#define span_HAVE_IS_DELETE span_CPP11_140 +#define span_HAVE_NOEXCEPT span_CPP11_140 +#define span_HAVE_NULLPTR span_CPP11_100 +#define span_HAVE_STATIC_ASSERT span_CPP11_100 + +// Presence of C++14 language features: + +#define span_HAVE_CONSTEXPR_14 span_CPP14_000 + +// Presence of C++17 language features: + +#define span_HAVE_DEPRECATED span_CPP17_000 +#define span_HAVE_NODISCARD span_CPP17_000 +#define span_HAVE_NORETURN span_CPP17_000 + +// MSVC: template parameter deduction guides since Visual Studio 2017 v15.7 + +#if defined(__cpp_deduction_guides) +#define span_HAVE_DEDUCTION_GUIDES 1 +#else +#define span_HAVE_DEDUCTION_GUIDES (span_CPP17_OR_GREATER && !span_BETWEEN(span_COMPILER_MSVC_VER, 1, 1913)) +#endif + +// Presence of C++ library features: + +#define span_HAVE_ADDRESSOF span_CPP17_000 +#define span_HAVE_ARRAY span_CPP11_110 +#define span_HAVE_BYTE span_CPP17_000 +#define span_HAVE_CONDITIONAL span_CPP11_120 +#define span_HAVE_CONTAINER_DATA_METHOD (span_CPP11_140 || (span_COMPILER_MSVC_VER >= 1500 && span_HAS_CPP0X)) +#define span_HAVE_DATA span_CPP17_000 +#define span_HAVE_LONGLONG span_CPP11_80 +#define span_HAVE_REMOVE_CONST span_CPP11_110 +#define span_HAVE_SNPRINTF span_CPP11_140 +#define span_HAVE_STRUCT_BINDING span_CPP11_120 +#define span_HAVE_TYPE_TRAITS span_CPP11_90 + +// Presence of byte-lite: + +#ifdef NONSTD_BYTE_LITE_HPP +#define span_HAVE_NONSTD_BYTE 1 +#else +#define span_HAVE_NONSTD_BYTE 0 +#endif + +// C++ feature usage: + +#if span_HAVE_ADDRESSOF +#define span_ADDRESSOF(x) std::addressof(x) +#else +#define span_ADDRESSOF(x) (&x) +#endif + +#if span_HAVE_CONSTEXPR_11 +#define span_constexpr constexpr +#else +#define span_constexpr /*span_constexpr*/ +#endif + +#if span_HAVE_CONSTEXPR_14 +#define span_constexpr14 constexpr +#else +#define span_constexpr14 /*span_constexpr*/ +#endif + +#if span_HAVE_EXPLICIT_CONVERSION +#define span_explicit explicit +#else +#define span_explicit /*explicit*/ +#endif + +#if span_HAVE_IS_DELETE +#define span_is_delete = delete +#else +#define span_is_delete +#endif + +#if span_HAVE_IS_DELETE +#define span_is_delete_access public +#else +#define span_is_delete_access private +#endif + +#if span_HAVE_NOEXCEPT && !span_CONFIG_CONTRACT_VIOLATION_THROWS_V +#define span_noexcept noexcept +#else +#define span_noexcept /*noexcept*/ +#endif + +#if span_HAVE_NULLPTR +#define span_nullptr nullptr +#else +#define span_nullptr NULL +#endif + +#if span_HAVE_DEPRECATED +#define span_deprecated(msg) [[deprecated(msg)]] +#else +#define span_deprecated(msg) /*[[deprecated]]*/ +#endif + +#if span_HAVE_NODISCARD +#define span_nodiscard [[nodiscard]] +#else +#define span_nodiscard /*[[nodiscard]]*/ +#endif + +#if span_HAVE_NORETURN +#define span_noreturn [[noreturn]] +#else +#define span_noreturn /*[[noreturn]]*/ +#endif + +// Other features: + +#define span_HAVE_CONSTRAINED_SPAN_CONTAINER_CTOR span_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG +#define span_HAVE_ITERATOR_CTOR span_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG + +// Additional includes: + +#if span_HAVE(ADDRESSOF) +#include +#endif + +#if span_HAVE(ARRAY) +#include +#endif + +#if span_HAVE(BYTE) +#include +#endif + +#if span_HAVE(DATA) +#include // for std::data(), std::size() +#endif + +#if span_HAVE(TYPE_TRAITS) +#include +#endif + +#if !span_HAVE(CONSTRAINED_SPAN_CONTAINER_CTOR) +#include +#endif + +#if span_FEATURE(MEMBER_AT) > 1 +#include +#endif + +#if !span_CONFIG(NO_EXCEPTIONS) +#include +#endif + +// Contract violation + +#define span_ELIDE_CONTRACT_EXPECTS (0 == (span_CONFIG_CONTRACT_LEVEL_MASK & 0x01)) +#define span_ELIDE_CONTRACT_ENSURES (0 == (span_CONFIG_CONTRACT_LEVEL_MASK & 0x10)) + +#if span_ELIDE_CONTRACT_EXPECTS +#define span_constexpr_exp span_constexpr +#define span_EXPECTS(cond) /* Expect elided */ +#else +#define span_constexpr_exp span_constexpr14 +#define span_EXPECTS(cond) span_CONTRACT_CHECK("Precondition", cond) +#endif + +#if span_ELIDE_CONTRACT_ENSURES +#define span_constexpr_ens span_constexpr +#define span_ENSURES(cond) /* Ensures elided */ +#else +#define span_constexpr_ens span_constexpr14 +#define span_ENSURES(cond) span_CONTRACT_CHECK("Postcondition", cond) +#endif + +#define span_CONTRACT_CHECK(type, cond) \ + cond ? static_cast(0) \ + : nonstd::span_lite::detail::report_contract_violation(span_LOCATION(__FILE__, __LINE__) ": " type " violation.") + +#ifdef __GNUG__ +#define span_LOCATION(file, line) file ":" span_STRINGIFY(line) +#else +#define span_LOCATION(file, line) file "(" span_STRINGIFY(line) ")" +#endif + +// Method enabling + +#if span_HAVE(DEFAULT_FUNCTION_TEMPLATE_ARG) + +#define span_REQUIRES_0(VA) template ::type = 0> + +#if span_BETWEEN(span_COMPILER_MSVC_VERSION, 1, 140) +// VS 2013 and earlier seem to have trouble with SFINAE for default non-type arguments +#define span_REQUIRES_T(VA) , typename = typename std::enable_if<(VA), nonstd::span_lite::detail::enabler>::type +#else +#define span_REQUIRES_T(VA) , typename std::enable_if<(VA), int>::type = 0 +#endif + +#define span_REQUIRES_R(R, VA) typename std::enable_if<(VA), R>::type + +#define span_REQUIRES_A(VA) , typename std::enable_if<(VA), void*>::type = nullptr + +#else + +#define span_REQUIRES_0(VA) /*empty*/ +#define span_REQUIRES_T(VA) /*empty*/ +#define span_REQUIRES_R(R, VA) R +#define span_REQUIRES_A(VA) /*empty*/ + +#endif + +namespace nonstd { +namespace span_lite { + +// [views.constants], constants + +typedef span_CONFIG_EXTENT_TYPE extent_t; +typedef span_CONFIG_SIZE_TYPE size_t; + +span_constexpr const extent_t dynamic_extent = static_cast(-1); + +template +class span; + +// Tag to select span constructor taking a container (prevent ms-gsl warning C26426): + +struct with_container_t { + span_constexpr with_container_t() span_noexcept {} +}; +const span_constexpr with_container_t with_container; + +// C++11 emulation: + +namespace std11 { + +#if span_HAVE(REMOVE_CONST) + +using std::remove_const; +using std::remove_cv; +using std::remove_volatile; + +#else + +template +struct remove_const { + typedef T type; +}; +template +struct remove_const { + typedef T type; +}; + +template +struct remove_volatile { + typedef T type; +}; +template +struct remove_volatile { + typedef T type; +}; + +template +struct remove_cv { + typedef typename std11::remove_volatile::type>::type type; +}; + +#endif // span_HAVE( REMOVE_CONST ) + +#if span_HAVE(TYPE_TRAITS) + +using std::false_type; +using std::integral_constant; +using std::is_same; +using std::is_signed; +using std::remove_reference; +using std::true_type; + +#else + +template +struct integral_constant { + enum { value = v }; +}; +typedef integral_constant true_type; +typedef integral_constant false_type; + +template +struct is_same : false_type {}; +template +struct is_same : true_type {}; + +template +struct is_signed : false_type {}; +template <> +struct is_signed : true_type {}; +template <> +struct is_signed : true_type {}; +template <> +struct is_signed : true_type {}; + +#endif + +} // namespace std11 + +// C++17 emulation: + +namespace std17 { + +template +struct bool_constant : std11::integral_constant {}; + +#if span_CPP11_120 + +template +using void_t = void; + +#endif + +#if span_HAVE(DATA) + +using std::data; +using std::size; + +#elif span_HAVE(CONSTRAINED_SPAN_CONTAINER_CTOR) + +template +inline span_constexpr auto size(const T (&)[N]) span_noexcept->size_t { + return N; +} + +template +inline span_constexpr auto size(C const& cont) -> decltype(cont.size()) { + return cont.size(); +} + +template +inline span_constexpr auto data(T (&arr)[N]) span_noexcept->T* { + return &arr[0]; +} + +template +inline span_constexpr auto data(C& cont) -> decltype(cont.data()) { + return cont.data(); +} + +template +inline span_constexpr auto data(C const& cont) -> decltype(cont.data()) { + return cont.data(); +} + +template +inline span_constexpr auto data(std::initializer_list il) span_noexcept->E const* { + return il.begin(); +} + +#endif // span_HAVE( DATA ) + +#if span_HAVE(BYTE) +using std::byte; +#elif span_HAVE(NONSTD_BYTE) +using nonstd::byte; +#endif + +} // namespace std17 + +// C++20 emulation: + +namespace std20 { + +#if span_HAVE(DEDUCTION_GUIDES) +template +using iter_reference_t = decltype(*std::declval()); +#endif + +} // namespace std20 + +// Implementation details: + +namespace detail { + +/*enum*/ struct enabler {}; + +template +span_constexpr bool is_positive(T x) { + return std11::is_signed::value ? x >= 0 : true; +} + +#if span_HAVE(TYPE_TRAITS) + +template +struct is_span_oracle : std::false_type {}; + +template +struct is_span_oracle > : std::true_type {}; + +template +struct is_span : is_span_oracle::type> {}; + +template +struct is_std_array_oracle : std::false_type {}; + +#if span_HAVE(ARRAY) + +template +struct is_std_array_oracle > : std::true_type {}; + +#endif + +template +struct is_std_array : is_std_array_oracle::type> {}; + +template +struct is_array : std::false_type {}; + +template +struct is_array : std::true_type {}; + +template +struct is_array : std::true_type {}; + +#if span_CPP11_140 && !span_BETWEEN(span_COMPILER_GNUC_VERSION, 1, 500) + +template +struct has_size_and_data : std::false_type {}; + +template +struct has_size_and_data())), decltype(std17::data(std::declval()))> > + : std::true_type {}; + +template +struct is_compatible_element : std::false_type {}; + +template +struct is_compatible_element()))> > + : std::is_convertible()))>::type (*)[], E (*)[]> {}; + +template +struct is_container + : std17::bool_constant::value && !is_array::value && !is_std_array::value && has_size_and_data::value> {}; + +template +struct is_compatible_container : std17::bool_constant::value && is_compatible_element::value> {}; + +#else // span_CPP11_140 + +template < + class C, + class E span_REQUIRES_T( + (!is_span::value && !is_array::value && !is_std_array::value && + (std::is_convertible()))>::type (*)[], E (*)[]>::value) + // && has_size_and_data< C >::value + )), + class = decltype(std17::size(std::declval())), class = decltype(std17::data(std::declval()))> +struct is_compatible_container : std::true_type {}; + +#endif // span_CPP11_140 + +#endif // span_HAVE( TYPE_TRAITS ) + +#if !span_CONFIG(NO_EXCEPTIONS) +#if span_FEATURE(MEMBER_AT) > 1 + +// format index and size: + +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wlong-long" +#elif defined __GNUC__ +#pragma GCC diagnostic ignored "-Wformat=ll" +#pragma GCC diagnostic ignored "-Wlong-long" +#endif + +span_noreturn inline void throw_out_of_range(size_t idx, size_t size) { + const char fmt[] = "span::at(): index '%lli' is out of range [0..%lli)"; + char buffer[2 * 20 + sizeof fmt]; + sprintf(buffer, fmt, static_cast(idx), static_cast(size)); + + throw std::out_of_range(buffer); +} + +#else // MEMBER_AT + +span_noreturn inline void throw_out_of_range(size_t /*idx*/, size_t /*size*/) { + throw std::out_of_range("span::at(): index outside span"); +} +#endif // MEMBER_AT +#endif // NO_EXCEPTIONS + +#if span_CONFIG(CONTRACT_VIOLATION_THROWS_V) + +struct contract_violation : std::logic_error { + explicit contract_violation(char const *const message) : std::logic_error(message) {} +}; + +inline void report_contract_violation(char const *msg) { throw contract_violation(msg); } + +#else // span_CONFIG( CONTRACT_VIOLATION_THROWS_V ) + +span_noreturn inline void report_contract_violation(char const* /*msg*/) span_noexcept { std::terminate(); } + +#endif // span_CONFIG( CONTRACT_VIOLATION_THROWS_V ) + +} // namespace detail + +// Prevent signed-unsigned mismatch: + +#define span_sizeof(T) static_cast(sizeof(T)) + +template +inline span_constexpr size_t to_size(T size) { + return static_cast(size); +} + +// +// [views.span] - A view over a contiguous, single-dimension sequence of objects +// +template +class span { + public: + // constants and types + + typedef T element_type; + typedef typename std11::remove_cv::type value_type; + + typedef T &reference; + typedef T *pointer; + typedef T const *const_pointer; + typedef T const &const_reference; + + typedef size_t size_type; + typedef extent_t extent_type; + + typedef pointer iterator; + typedef const_pointer const_iterator; + + typedef std::ptrdiff_t difference_type; + + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + // static constexpr extent_type extent = Extent; + enum { extent = Extent }; + + // 26.7.3.2 Constructors, copy, and assignment [span.cons] + + span_REQUIRES_0((Extent == 0) || (Extent == dynamic_extent)) span_constexpr span() span_noexcept : data_(span_nullptr), + size_(0) { + // span_EXPECTS( data() == span_nullptr ); + // span_EXPECTS( size() == 0 ); + } + +#if span_HAVE(ITERATOR_CTOR) + // Didn't yet succeed in combining the next two constructors: + + span_constexpr_exp span(std::nullptr_t, size_type count) : data_(span_nullptr), size_(count) { + span_EXPECTS(data_ == span_nullptr && count == 0); + } + + template ()), element_type &>::value))> + span_constexpr_exp span(It first, size_type count) : data_(to_address(first)), size_(count) { + span_EXPECTS((data_ == span_nullptr && count == 0) || (data_ != span_nullptr && detail::is_positive(count))); + } +#else + span_constexpr_exp span(pointer ptr, size_type count) : data_(ptr), size_(count) { + span_EXPECTS((ptr == span_nullptr && count == 0) || (ptr != span_nullptr && detail::is_positive(count))); + } +#endif + +#if span_HAVE(ITERATOR_CTOR) + template ()), element_type *>::value && + !std::is_convertible::value))> + span_constexpr_exp span(It first, End last) : data_(to_address(first)), size_(to_size(last - first)) { + span_EXPECTS(last - first >= 0); + } +#else + span_constexpr_exp span(pointer first, pointer last) : data_(first), size_(to_size(last - first)) { + span_EXPECTS(last - first >= 0); + } +#endif + + template (N)) && + std::is_convertible::value))> + span_constexpr span(element_type (&arr)[N]) span_noexcept : data_(span_ADDRESSOF(arr[0])), size_(N) {} + +#if span_HAVE(ARRAY) + + template (N)) && + std::is_convertible::value))> +#if span_FEATURE(CONSTRUCTION_FROM_STDARRAY_ELEMENT_TYPE) + span_constexpr span(std::array &arr) span_noexcept +#else + span_constexpr span(std::array &arr) span_noexcept +#endif + : data_(arr.data()), + size_(to_size(arr.size())) { + } + + template (N)) && + std::is_convertible::value)) +#endif + > + span_constexpr span(std::array const &arr) span_noexcept : data_(arr.data()), size_(to_size(arr.size())) { + } + +#endif // span_HAVE( ARRAY ) + +#if span_HAVE(CONSTRAINED_SPAN_CONTAINER_CTOR) + template ::value))> + span_constexpr span(Container &cont) : data_(std17::data(cont)), size_(to_size(std17::size(cont))) {} + + template ::value && + detail::is_compatible_container::value))> + span_constexpr span(Container const &cont) : data_(std17::data(cont)), size_(to_size(std17::size(cont))) {} + +#endif // span_HAVE( CONSTRAINED_SPAN_CONTAINER_CTOR ) + +#if span_FEATURE(WITH_CONTAINER) + + template + span_constexpr span(with_container_t, Container &cont) + : data_(cont.size() == 0 ? span_nullptr : span_ADDRESSOF(cont[0])), size_(to_size(cont.size())) {} + + template + span_constexpr span(with_container_t, Container const &cont) + : data_(cont.size() == 0 ? span_nullptr : const_cast(span_ADDRESSOF(cont[0]))), size_(to_size(cont.size())) {} +#endif + +#if span_FEATURE(WITH_INITIALIZER_LIST_P2447) && span_HAVE(INITIALIZER_LIST) + + // constexpr explicit(extent != dynamic_extent) span(std::initializer_list il) noexcept; + +#if !span_BETWEEN(span_COMPILER_MSVC_VERSION, 120, 130) + + template +#if span_COMPILER_GNUC_VERSION >= 900 // prevent GCC's "-Winit-list-lifetime" + span_constexpr14 explicit span(std::initializer_list il) span_noexcept { + data_ = il.begin(); + size_ = il.size(); + } +#else + span_constexpr explicit span(std::initializer_list il) span_noexcept : data_(il.begin()), size_(il.size()) { + } +#endif + +#endif // MSVC 120 (VS2013) + + template +#if span_COMPILER_GNUC_VERSION >= 900 // prevent GCC's "-Winit-list-lifetime" + span_constexpr14 /*explicit*/ span(std::initializer_list il) span_noexcept { + data_ = il.begin(); + size_ = il.size(); + } +#else + span_constexpr /*explicit*/ span(std::initializer_list il) span_noexcept : data_(il.begin()), size_(il.size()) { + } +#endif + +#endif // P2447 + +#if span_HAVE(IS_DEFAULT) + span_constexpr span(span const &other) span_noexcept = default; + + ~span() span_noexcept = default; + + span_constexpr14 span &operator=(span const &other) span_noexcept = default; +#else + span_constexpr span(span const& other) span_noexcept : data_(other.data_), size_(other.size_) {} + + ~span() span_noexcept {} + + span_constexpr14 span& operator=(span const& other) span_noexcept { + data_ = other.data_; + size_ = other.size_; + + return *this; + } +#endif + + template ::value))> + span_constexpr_exp span(span const &other) span_noexcept : data_(other.data()), + size_(other.size()) { + span_EXPECTS(OtherExtent == dynamic_extent || other.size() == to_size(OtherExtent)); + } + + // 26.7.3.3 Subviews [span.sub] + + template + span_constexpr_exp span first() const { + span_EXPECTS(detail::is_positive(Count) && Count <= size()); + + return span(data(), Count); + } + + template + span_constexpr_exp span last() const { + span_EXPECTS(detail::is_positive(Count) && Count <= size()); + + return span(data() + (size() - Count), Count); + } + +#if span_HAVE(DEFAULT_FUNCTION_TEMPLATE_ARG) + template +#else + template +#endif + span_constexpr_exp span subspan() const { + span_EXPECTS((detail::is_positive(Offset) && Offset <= size()) && + (Count == dynamic_extent || (detail::is_positive(Count) && Count + Offset <= size()))); + + return span( + data() + Offset, Count != dynamic_extent ? Count : (Extent != dynamic_extent ? Extent - Offset : size() - Offset)); + } + + span_constexpr_exp span first(size_type count) const { + span_EXPECTS(detail::is_positive(count) && count <= size()); + + return span(data(), count); + } + + span_constexpr_exp span last(size_type count) const { + span_EXPECTS(detail::is_positive(count) && count <= size()); + + return span(data() + (size() - count), count); + } + + span_constexpr_exp span subspan(size_type offset, + size_type count = static_cast(dynamic_extent)) const { + span_EXPECTS(((detail::is_positive(offset) && offset <= size())) && + (count == static_cast(dynamic_extent) || (detail::is_positive(count) && offset + count <= size()))); + + return span(data() + offset, + count == static_cast(dynamic_extent) ? size() - offset : count); + } + + // 26.7.3.4 Observers [span.obs] + + span_constexpr size_type size() const span_noexcept { return size_; } + + span_constexpr std::ptrdiff_t ssize() const span_noexcept { return static_cast(size_); } + + span_constexpr size_type size_bytes() const span_noexcept { return size() * to_size(sizeof(element_type)); } + + span_nodiscard span_constexpr bool empty() const span_noexcept { return size() == 0; } + + // 26.7.3.5 Element access [span.elem] + + span_constexpr_exp reference operator[](size_type idx) const { + span_EXPECTS(detail::is_positive(idx) && idx < size()); + + return *(data() + idx); + } + +#if span_FEATURE(MEMBER_CALL_OPERATOR) + span_deprecated("replace operator() with operator[]") + + span_constexpr_exp reference + operator()(size_type idx) const { + span_EXPECTS(detail::is_positive(idx) && idx < size()); + + return *(data() + idx); + } +#endif + +#if span_FEATURE(MEMBER_AT) + span_constexpr14 reference at(size_type idx) const { +#if span_CONFIG(NO_EXCEPTIONS) + return this->operator[](idx); +#else + if (!detail::is_positive(idx) || size() <= idx) { + detail::throw_out_of_range(idx, size()); + } + return *(data() + idx); +#endif + } +#endif + + span_constexpr pointer data() const span_noexcept { return data_; } + +#if span_FEATURE(MEMBER_BACK_FRONT) + + span_constexpr_exp reference front() const span_noexcept { + span_EXPECTS(!empty()); + + return *data(); + } + + span_constexpr_exp reference back() const span_noexcept { + span_EXPECTS(!empty()); + + return *(data() + size() - 1); + } + +#endif + + // xx.x.x.x Modifiers [span.modifiers] + +#if span_FEATURE(MEMBER_SWAP) + + span_constexpr14 void swap(span &other) span_noexcept { + using std::swap; + swap(data_, other.data_); + swap(size_, other.size_); + } +#endif + + // 26.7.3.6 Iterator support [span.iterators] + + span_constexpr iterator begin() const span_noexcept { +#if span_CPP11_OR_GREATER + return {data()}; +#else + return iterator(data()); +#endif + } + + span_constexpr iterator end() const span_noexcept { +#if span_CPP11_OR_GREATER + return {data() + size()}; +#else + return iterator(data() + size()); +#endif + } + + span_constexpr const_iterator cbegin() const span_noexcept { +#if span_CPP11_OR_GREATER + return {data()}; +#else + return const_iterator(data()); +#endif + } + + span_constexpr const_iterator cend() const span_noexcept { +#if span_CPP11_OR_GREATER + return {data() + size()}; +#else + return const_iterator(data() + size()); +#endif + } + + span_constexpr reverse_iterator rbegin() const span_noexcept { return reverse_iterator(end()); } + + span_constexpr reverse_iterator rend() const span_noexcept { return reverse_iterator(begin()); } + + span_constexpr const_reverse_iterator crbegin() const span_noexcept { return const_reverse_iterator(cend()); } + + span_constexpr const_reverse_iterator crend() const span_noexcept { return const_reverse_iterator(cbegin()); } + + private: + // Note: C++20 has std::pointer_traits::to_address( it ); + +#if span_HAVE(ITERATOR_CTOR) + static inline span_constexpr pointer to_address(std::nullptr_t) span_noexcept { return nullptr; } + + template + static inline span_constexpr U *to_address(U *p) span_noexcept { + return p; + } + + template ::value))> + static inline span_constexpr pointer to_address(Ptr const &it) span_noexcept { + return to_address(it.operator->()); + } +#endif // span_HAVE( ITERATOR_CTOR ) + + private: + pointer data_; + size_type size_; +}; + +// class template argument deduction guides: + +#if span_HAVE(DEDUCTION_GUIDES) + +template +span(T (&)[N]) -> span(N)>; + +template +span(std::array &) -> span(N)>; + +template +span(std::array const &) -> span(N)>; + +#if span_HAVE(CONSTRAINED_SPAN_CONTAINER_CTOR) + +template +span(Container &) -> span; + +template +span(Container const &) -> span; + +#endif + +// iterator: constraints: It satisfies contiguous_­iterator. + +template +span(It, EndOrSize) -> span >::type>; + +#endif // span_HAVE( DEDUCTION_GUIDES ) + +// 26.7.3.7 Comparison operators [span.comparison] + +#if span_FEATURE(COMPARISON) +#if span_FEATURE(SAME) + +template +inline span_constexpr bool same(span const &l, span const &r) span_noexcept { + return std11::is_same::value && l.size() == r.size() && static_cast(l.data()) == r.data(); +} + +#endif + +template +inline span_constexpr bool operator==(span const &l, span const &r) { + return +#if span_FEATURE(SAME) + same(l, r) || +#endif + (l.size() == r.size() && std::equal(l.begin(), l.end(), r.begin())); +} + +template +inline span_constexpr bool operator<(span const &l, span const &r) { + return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); +} + +template +inline span_constexpr bool operator!=(span const &l, span const &r) { + return !(l == r); +} + +template +inline span_constexpr bool operator<=(span const &l, span const &r) { + return !(r < l); +} + +template +inline span_constexpr bool operator>(span const &l, span const &r) { + return (r < l); +} + +template +inline span_constexpr bool operator>=(span const &l, span const &r) { + return !(l < r); +} + +#endif // span_FEATURE( COMPARISON ) + +// 26.7.2.6 views of object representation [span.objectrep] + +#if span_HAVE(BYTE) || span_HAVE(NONSTD_BYTE) + +// Avoid MSVC 14.1 (1910), VS 2017: warning C4307: '*': integral constant overflow: + +template +struct BytesExtent { +#if span_CPP11_OR_GREATER + enum ET : extent_t { value = span_sizeof(T) * Extent }; +#else + enum ET { value = span_sizeof(T) * Extent }; +#endif +}; + +template +struct BytesExtent { +#if span_CPP11_OR_GREATER + enum ET : extent_t{value = dynamic_extent}; +#else + enum ET { value = dynamic_extent }; +#endif +}; + +template +inline span_constexpr span::value> as_bytes(span spn) span_noexcept { +#if 0 + return { reinterpret_cast< std17::byte const * >( spn.data() ), spn.size_bytes() }; +#else + return span::value>(reinterpret_cast(spn.data()), + spn.size_bytes()); // NOLINT +#endif +} + +template +inline span_constexpr span::value> as_writable_bytes(span spn) span_noexcept { +#if 0 + return { reinterpret_cast< std17::byte * >( spn.data() ), spn.size_bytes() }; +#else + return span::value>(reinterpret_cast(spn.data()), + spn.size_bytes()); // NOLINT +#endif +} + +#endif // span_HAVE( BYTE ) || span_HAVE( NONSTD_BYTE ) + +// 27.8 Container and view access [iterator.container] + +template +span_constexpr std::size_t size(span const &spn) { + return static_cast(spn.size()); +} + +template +span_constexpr std::ptrdiff_t ssize(span const &spn) { + return static_cast(spn.size()); +} + +} // namespace span_lite +} // namespace nonstd + +// make available in nonstd: + +namespace nonstd { + +using span_lite::dynamic_extent; + +using span_lite::span; + +using span_lite::with_container; + +#if span_FEATURE(COMPARISON) +#if span_FEATURE(SAME) +using span_lite::same; +#endif + +using span_lite::operator==; +using span_lite::operator!=; +using span_lite::operator<; +using span_lite::operator<=; +using span_lite::operator>; +using span_lite::operator>=; +#endif + +#if span_HAVE(BYTE) +using span_lite::as_bytes; +using span_lite::as_writable_bytes; +#endif + +using span_lite::size; +using span_lite::ssize; + +} // namespace nonstd + +#endif // span_USES_STD_SPAN + +// make_span() [span-lite extension]: + +#if span_FEATURE(MAKE_SPAN) || span_FEATURE(NON_MEMBER_FIRST_LAST_SUB_SPAN) || span_FEATURE(NON_MEMBER_FIRST_LAST_SUB_CONTAINER) + +#if span_USES_STD_SPAN +#define span_constexpr constexpr +#define span_noexcept noexcept +#define span_nullptr nullptr +#ifndef span_CONFIG_EXTENT_TYPE +#define span_CONFIG_EXTENT_TYPE std::size_t +#endif +using extent_t = span_CONFIG_EXTENT_TYPE; +#endif // span_USES_STD_SPAN + +namespace nonstd { +namespace span_lite { + +template +inline span_constexpr span make_span(T* ptr, size_t count) span_noexcept { + return span(ptr, count); +} + +template +inline span_constexpr span make_span(T* first, T* last) span_noexcept { + return span(first, last); +} + +template +inline span_constexpr span(N)> make_span(T (&arr)[N]) span_noexcept { + return span(N)>(&arr[0], N); +} + +#if span_USES_STD_SPAN || span_HAVE(ARRAY) + +template +inline span_constexpr span(N)> make_span(std::array& arr) span_noexcept { + return span(N)>(arr); +} + +template +inline span_constexpr span(N)> make_span(std::array const& arr) span_noexcept { + return span(N)>(arr); +} + +#endif // span_HAVE( ARRAY ) + +#if span_USES_STD_SPAN || span_HAVE(INITIALIZER_LIST) + +template +inline span_constexpr span make_span(std::initializer_list il) span_noexcept { + return span(il.begin(), il.size()); +} + +#endif // span_HAVE( INITIALIZER_LIST ) + +#if span_USES_STD_SPAN + +template ()))> +inline span_constexpr auto make_span(Container& cont) span_noexcept->span::type> { + return span::type>(cont); +} + +template ()))> +inline span_constexpr auto make_span(Container const& cont) span_noexcept->span::type> { + return span::type>(cont); +} + +#elif span_HAVE(CONSTRAINED_SPAN_CONTAINER_CTOR) && span_HAVE(AUTO) + +template ()))> +inline span_constexpr auto make_span(Container& cont) span_noexcept->span::type> { + return span::type>(cont); +} + +template ()))> +inline span_constexpr auto make_span(Container const& cont) span_noexcept->span::type> { + return span::type>(cont); +} + +#else + +template +inline span_constexpr span make_span(span spn) span_noexcept { + return spn; +} + +template +inline span_constexpr span make_span(std::vector& cont) span_noexcept { + return span(with_container, cont); +} + +template +inline span_constexpr span make_span(std::vector const& cont) span_noexcept { + return span(with_container, cont); +} + +#endif // span_USES_STD_SPAN || ( ... ) + +#if !span_USES_STD_SPAN && span_FEATURE(WITH_CONTAINER) + +template +inline span_constexpr span make_span(with_container_t, Container& cont) span_noexcept { + return span(with_container, cont); +} + +template +inline span_constexpr span make_span(with_container_t, Container const& cont) span_noexcept { + return span(with_container, cont); +} + +#endif // ! span_USES_STD_SPAN && span_FEATURE( WITH_CONTAINER ) + +// extensions: non-member views: +// this feature implies the presence of make_span() + +#if span_FEATURE(NON_MEMBER_FIRST_LAST_SUB_SPAN) + +template +span_constexpr span first(span spn) { + return spn.template first(); +} + +template +span_constexpr span first(span spn, size_t count) { + return spn.first(count); +} + +template +span_constexpr span last(span spn) { + return spn.template last(); +} + +template +span_constexpr span last(span spn, size_t count) { + return spn.last(count); +} + +template +span_constexpr span subspan(span spn) { + return spn.template subspan(); +} + +template +span_constexpr span subspan(span spn, size_t offset, extent_t count = dynamic_extent) { + return spn.subspan(offset, count); +} + +#endif // span_FEATURE( NON_MEMBER_FIRST_LAST_SUB_SPAN ) + +#if span_FEATURE(NON_MEMBER_FIRST_LAST_SUB_CONTAINER) && span_CPP11_120 + +template +span_constexpr auto first(T& t) -> decltype(make_span(t).template first()) { + return make_span(t).template first(); +} + +template +span_constexpr auto first(T& t, size_t count) -> decltype(make_span(t).first(count)) { + return make_span(t).first(count); +} + +template +span_constexpr auto last(T& t) -> decltype(make_span(t).template last()) { + return make_span(t).template last(); +} + +template +span_constexpr auto last(T& t, extent_t count) -> decltype(make_span(t).last(count)) { + return make_span(t).last(count); +} + +template +span_constexpr auto subspan(T& t) -> decltype(make_span(t).template subspan()) { + return make_span(t).template subspan(); +} + +template +span_constexpr auto subspan(T& t, size_t offset, extent_t count = dynamic_extent) -> decltype(make_span(t).subspan(offset, count)) { + return make_span(t).subspan(offset, count); +} + +#endif // span_FEATURE( NON_MEMBER_FIRST_LAST_SUB_CONTAINER ) + +} // namespace span_lite +} // namespace nonstd + +// make available in nonstd: + +namespace nonstd { +using span_lite::make_span; + +#if span_FEATURE(NON_MEMBER_FIRST_LAST_SUB_SPAN) || (span_FEATURE(NON_MEMBER_FIRST_LAST_SUB_CONTAINER) && span_CPP11_120) + +using span_lite::first; +using span_lite::last; +using span_lite::subspan; + +#endif // span_FEATURE( NON_MEMBER_FIRST_LAST_SUB_[SPAN|CONTAINER] ) + +} // namespace nonstd + +#endif // #if span_FEATURE_TO_STD( MAKE_SPAN ) + +#if span_CPP11_OR_GREATER && span_FEATURE(BYTE_SPAN) && (span_HAVE(BYTE) || span_HAVE(NONSTD_BYTE)) + +namespace nonstd { +namespace span_lite { + +template +inline span_constexpr auto byte_span(T& t) span_noexcept->span { + return span(reinterpret_cast(&t), span_sizeof(T)); +} + +template +inline span_constexpr auto byte_span(T const& t) span_noexcept->span { + return span(reinterpret_cast(&t), span_sizeof(T)); +} + +} // namespace span_lite +} // namespace nonstd + +// make available in nonstd: + +namespace nonstd { +using span_lite::byte_span; +} // namespace nonstd + +#endif // span_FEATURE( BYTE_SPAN ) + +#if span_HAVE(STRUCT_BINDING) + +#if span_CPP14_OR_GREATER +#include +#elif span_CPP11_OR_GREATER +#include +namespace std { +template +using tuple_element_t = typename tuple_element::type; +} +#else +namespace std { +template +class tuple_size; /*undefined*/ + +template +class tuple_element; /* undefined */ +} // namespace std +#endif // span_CPP14_OR_GREATER + +namespace std { + +// 26.7.X Tuple interface + +// std::tuple_size<>: + +template +class tuple_size > : public integral_constant(Extent)> {}; + +// std::tuple_size<>: Leave undefined for dynamic extent: + +template +class tuple_size >; + +// std::tuple_element<>: + +template +class tuple_element > { + public: +#if span_HAVE(STATIC_ASSERT) + static_assert(Extent != nonstd::dynamic_extent && I < Extent, "tuple_element: dynamic extent or index out of range"); +#endif + using type = ElementType; +}; + +// std::get<>(), 2 variants: + +template +span_constexpr ElementType& get(nonstd::span& spn) span_noexcept { +#if span_HAVE(STATIC_ASSERT) + static_assert(Extent != nonstd::dynamic_extent && I < Extent, "get<>(span): dynamic extent or index out of range"); +#endif + return spn[I]; +} + +template +span_constexpr ElementType const& get(nonstd::span const& spn) span_noexcept { +#if span_HAVE(STATIC_ASSERT) + static_assert(Extent != nonstd::dynamic_extent && I < Extent, "get<>(span): dynamic extent or index out of range"); +#endif + return spn[I]; +} + +} // end namespace std + +#endif // span_HAVE( STRUCT_BINDING ) + +#if !span_USES_STD_SPAN +span_RESTORE_WARNINGS() +#endif // span_USES_STD_SPAN + +#endif // NONSTD_SPAN_HPP_INCLUDED diff --git a/src/external/type-lite/include/nonstd/type.hpp b/src/external/type-lite/include/nonstd/type.hpp new file mode 100644 index 000000000..a2efe6f81 --- /dev/null +++ b/src/external/type-lite/include/nonstd/type.hpp @@ -0,0 +1,841 @@ +// Copyright 2018-2022 Martin Moene +// +// type-lite, strong types for C++98 and later. +// For more information see https://github.com/martinmoene/type-lite +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// SPDX-License-Identifier: BSL-1.0 + +#ifndef NONSTD_TYPE_HPP_INCLUDED +#define NONSTD_TYPE_HPP_INCLUDED + +#define type_MAJOR 0 +#define type_MINOR 1 +#define type_PATCH 0 + +#define type_VERSION type_STRINGIFY(type_MAJOR) "." type_STRINGIFY(type_MINOR) "." type_STRINGIFY(type_PATCH) + +#define type_STRINGIFY( x ) type_STRINGIFY_( x ) +#define type_STRINGIFY_( x ) #x + +// nonstd type configuration: + +// (none) + +// C++ language version detection (C++23 is speculative): +// Note: VC14.0/1900 (VS2015) lacks too much from C++14. + +#ifndef type_CPLUSPLUS +# if defined(_MSVC_LANG ) && !defined(__clang__) +# define type_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) +# else +# define type_CPLUSPLUS __cplusplus +# endif +#endif + +#define type_CPP98_OR_GREATER ( type_CPLUSPLUS >= 199711L ) +#define type_CPP11_OR_GREATER ( type_CPLUSPLUS >= 201103L ) +#define type_CPP11_OR_GREATER_ ( type_CPLUSPLUS >= 201103L ) +#define type_CPP14_OR_GREATER ( type_CPLUSPLUS >= 201402L ) +#define type_CPP17_OR_GREATER ( type_CPLUSPLUS >= 201703L ) +#define type_CPP20_OR_GREATER ( type_CPLUSPLUS >= 202002L ) +#define type_CPP23_OR_GREATER ( type_CPLUSPLUS >= 202300L ) + +// half-open range [lo..hi): +#define type_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) + +// Compiler versions: +// +// MSVC++ 6.0 _MSC_VER == 1200 type_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0) +// MSVC++ 7.0 _MSC_VER == 1300 type_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002) +// MSVC++ 7.1 _MSC_VER == 1310 type_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003) +// MSVC++ 8.0 _MSC_VER == 1400 type_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005) +// MSVC++ 9.0 _MSC_VER == 1500 type_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008) +// MSVC++ 10.0 _MSC_VER == 1600 type_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010) +// MSVC++ 11.0 _MSC_VER == 1700 type_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012) +// MSVC++ 12.0 _MSC_VER == 1800 type_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013) +// MSVC++ 14.0 _MSC_VER == 1900 type_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015) +// MSVC++ 14.1 _MSC_VER >= 1910 type_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017) +// MSVC++ 14.2 _MSC_VER >= 1920 type_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019) + +#if defined(_MSC_VER ) && !defined(__clang__) +# define type_COMPILER_MSVC_VER (_MSC_VER ) +# define type_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) ) +#else +# define type_COMPILER_MSVC_VER 0 +# define type_COMPILER_MSVC_VERSION 0 +#endif + +#define type_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * (major) + (minor) ) + (patch) ) + +#if defined(__clang__) +# define type_COMPILER_CLANG_VERSION type_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) +#else +# define type_COMPILER_CLANG_VERSION 0 +#endif + +#if defined(__GNUC__) && !defined(__clang__) +# define type_COMPILER_GNUC_VERSION type_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#else +# define type_COMPILER_GNUC_VERSION 0 +#endif + +// Presence of language and library features: + +#ifdef _HAS_CPP0X +# define type_HAS_CPP0X _HAS_CPP0X +#else +# define type_HAS_CPP0X 0 +#endif + +// Unless defined otherwise below, consider VC14 as C++11 for type: + +#if type_COMPILER_MSVC_VER >= 1900 +# undef type_CPP11_OR_GREATER +# define type_CPP11_OR_GREATER 1 +#endif + +#define type_CPP11_90 (type_CPP11_OR_GREATER_ || type_COMPILER_MSVC_VER >= 1500) +#define type_CPP11_100 (type_CPP11_OR_GREATER_ || type_COMPILER_MSVC_VER >= 1600) +#define type_CPP11_110 (type_CPP11_OR_GREATER_ || type_COMPILER_MSVC_VER >= 1700) +#define type_CPP11_120 (type_CPP11_OR_GREATER_ || type_COMPILER_MSVC_VER >= 1800) +#define type_CPP11_140 (type_CPP11_OR_GREATER_ || type_COMPILER_MSVC_VER >= 1900) +#define type_CPP11_141 (type_CPP11_OR_GREATER_ || type_COMPILER_MSVC_VER >= 1910) + +#define type_CPP14_000 (type_CPP14_OR_GREATER) +#define type_CPP17_000 (type_CPP17_OR_GREATER) + +// Presence of C++11 language features: + +#define type_HAVE_CONSTEXPR_11 type_CPP11_140 +#define type_HAVE_EXPLICIT_CONVERSION type_CPP11_140 +#define type_HAVE_IS_DELETE type_CPP11_140 +#define type_HAVE_NOEXCEPT type_CPP11_140 + +// Presence of C++14 language features: + +#define type_HAVE_CONSTEXPR_14 type_CPP14_000 + +// Presence of C++17 language features: + +// no flag + +// Presence of C++ library features: + +#define type_HAVE_STD_HASH type_CPP11_120 + +// C++ feature usage: + +#if type_HAVE_CONSTEXPR_11 +# define type_constexpr constexpr +#else +# define type_constexpr /*constexpr*/ +#endif + +#if type_HAVE_CONSTEXPR_14 +# define type_constexpr14 constexpr +#else +# define type_constexpr14 /*constexpr*/ +#endif + +#if type_HAVE_EXPLICIT_CONVERSION +# define type_explicit explicit +#else +# define type_explicit /*explicit*/ +#endif + +#if type_HAVE_IS_DELETE +# define type_is_delete = delete +#else +# define type_is_delete +#endif + +#if type_HAVE_NOEXCEPT +# define type_noexcept noexcept +#else +# define type_noexcept /*noexcept*/ +#endif + +// Additional includes: + +#if type_HAVE_STD_HASH +# include // std::hash<> +# include // std::move(), std::swap() +# include // std::is_same<> +#else +# include // std::swap() +#endif + +// Method enabling + +#if type_CPP11_OR_GREATER + +#define type_REQUIRES_0(...) \ + template< bool B = (__VA_ARGS__), typename std::enable_if::type = 0 > + +#define type_REQUIRES_T(...) \ + , typename std::enable_if< (__VA_ARGS__), int >::type = 0 + +#define type_REQUIRES_R(R, ...) \ + typename std::enable_if< (__VA_ARGS__), R>::type + +#define type_REQUIRES_A(...) \ + , typename std::enable_if< (__VA_ARGS__), void*>::type = nullptr + +#endif + +/** + * define a type's tag: used to prevent locally-defined struct in C++98. + */ +#if ! type_CPP11_OR_GREATER +# define type_DECLARE_TAG( type_type ) struct type_type##_tag; +#else +# define type_DECLARE_TAG( type_type ) /*tag*/ +#endif + +/** + * define a default-constructible type. + */ +#define type_DEFINE_TYPE( type_name, type_type, underlying_type ) \ + typedef ::nonstd::type_type type_name; + +/** + * define a non-default-constructible type. + */ +#define type_DEFINE_TYPE_ND( type_name, type_type, underlying_type ) \ + typedef ::nonstd::type_type type_name; + +/** + * define a default-constructible sub-type. + */ +#define type_DEFINE_SUBTYPE( sub, super ) \ + struct sub : super { \ + type_constexpr explicit sub(underlying_type const & x = underlying_type() ) : super(x) {} \ + }; + +/** + * define a non-default-constructible sub-type. + */ +#define type_DEFINE_SUBTYPE_ND( sub, super ) \ + struct sub : super { \ + type_constexpr explicit sub(underlying_type const & x) : super(x) {} \ + }; + +/** + * define a function for given type, non-constexpr. + */ +#define type_DEFINE_FUNCTION( type_type, type_function, function ) \ + inline type_type type_function( type_type const & x ) \ + { \ + return type_type( function( x.get() ) ); \ + } + +/** + * define a function for given type, constexpr. + */ +#define type_DEFINE_FUNCTION_CE( type_type, type_function, function ) \ + inline type_constexpr14 type_type type_function( type_type const & x ) \ + { \ + return type_type( function( x.get() ) ); \ + } + +/** + * implementation namespace + */ +namespace nonstd { namespace types { + +// EqualityComparable, comparison functions based on operator==() and operator<(): + +template< typename T, typename U = T > struct is_eq { friend type_constexpr14 bool operator==( T const & x, U const & y ) { return x.get() == y.get(); } }; +template< typename T, typename U = T > struct is_lt { friend type_constexpr14 bool operator< ( T const & x, U const & y ) { return x.get() < y.get(); } }; + +template< typename T, typename U = T > struct is_ne { friend type_constexpr14 bool operator!=( T const & x, U const & y ) { return ! ( x == y ); } }; +template< typename T, typename U = T > struct is_lteq { friend type_constexpr14 bool operator> ( T const & x, U const & y ) { return y < x; } }; +template< typename T, typename U = T > struct is_gt { friend type_constexpr14 bool operator<=( T const & x, U const & y ) { return ! ( y < x ); } }; +template< typename T, typename U = T > struct is_gteq { friend type_constexpr14 bool operator>=( T const & x, U const & y ) { return ! ( x < y ); } }; + +// Logical operations: + +template< typename R, typename T = R > struct logical_not{ friend type_constexpr14 R operator!( T const & x ) { return R( ! x.get() ); } }; + +template< typename R, typename T = R, typename U = R > struct logical_and{ friend type_constexpr14 R operator&&( T const & x, U const & y ) { return R( x.get() && y.get() ); } }; +template< typename R, typename T = R, typename U = R > struct logical_or { friend type_constexpr14 R operator||( T const & x, U const & y ) { return R( x.get() || y.get() ); } }; + +// Arithmetic operations based on operator X=(): + +template< typename R, typename T = R, typename U = R > struct plus { friend type_constexpr14 R operator+( T x, U const & y ) { return x += y; } }; +template< typename R, typename T = R, typename U = R > struct plus2 { friend type_constexpr14 R operator+( T const & x, U y ) { return y += x; } }; +template< typename R, typename T = R, typename U = R > struct minus { friend type_constexpr14 R operator-( T x, U const & y ) { return x -= y; } }; +template< typename R, typename T = R, typename U = R > struct multiplies { friend type_constexpr14 R operator*( T x, U const & y ) { return x *= y; } }; +template< typename R, typename T = R, typename U = R > struct multiplies2{ friend type_constexpr14 R operator*( T const & x, U y ) { return y *= x; } }; +template< typename R, typename T = R, typename U = R > struct divides { friend type_constexpr14 R operator/( T x, U const & y ) { return x /= y; } }; +template< typename R, typename T = R, typename U = R > struct modulus { friend type_constexpr14 R operator%( T x, U const & y ) { return x %= y; } }; + +// Bitwise operations based on operator X=(): + +//template< typename R, typename T = R > struct bit_not{ friend type_constexpr14 R operator~( T const & x ) { return ~x; }; }; + +template< typename R, typename T = R, typename U = R > struct bit_and { friend type_constexpr14 R operator&( T x, U const & y ) { return x &= y; } }; +template< typename R, typename T = R, typename U = R > struct bit_or { friend type_constexpr14 R operator|( T x, U const & y ) { return x |= y; } }; +template< typename R, typename T = R, typename U = R > struct bit_xor { friend type_constexpr14 R operator^( T x, U const & y ) { return x ^= y; } }; + +template< typename R, typename T = R > struct bit_shl { friend type_constexpr14 R operator<<( T x, int const n ) { return x <<= n; } }; +template< typename R, typename T = R > struct bit_shr { friend type_constexpr14 R operator>>( T x, int const n ) { return x >>= n; } }; + +/** + * disallow default construction. + */ +struct no_default_t{}; + +/** + * custom default value + */ +template struct custom_default_t{}; + +/** + * data base class. + */ +template< typename T, typename D = T > +struct data +{ + typedef T underlying_type; + + type_constexpr data() + : value() + {} + +#if type_CPP11_OR_GREATER + type_constexpr explicit data( T v ) + : value( std::move(v) ) + {} +#else + type_constexpr explicit data( T const & v ) + : value( v ) + {} +#endif + +#if type_CPP11_OR_GREATER + type_constexpr14 T & get() & { return value; } + type_constexpr14 T const & get() const & { return value; } + + type_constexpr14 T && get() && { return std::move(value); } + type_constexpr14 T const && get() const && { return std::move(value); } +#else + type_constexpr14 T & get() { return value; } + type_constexpr14 T const & get() const { return value; } +#endif + + void swap( data & other ) + { + using std::swap; + swap( this->value, other.value ); + } + +private: + underlying_type value; +}; + +template +struct default_value +{ + static type_constexpr T get() + { + return T(); + } +}; + +template +struct default_value< T, custom_default_t< T, Val > > +{ + static type_constexpr T get() + { + return Val; + } +}; + +/** + * type, no operators. + */ +template< typename T, typename Tag, typename D = T > +struct type : data +{ +#if type_CPP11_OR_GREATER + type_REQUIRES_0(( + ! std::is_same::value + )) +#endif + type_constexpr type() + : data( default_value::get() ) + {} + +#if type_CPP11_OR_GREATER + type_constexpr explicit type( T v ) + : data( std::move(v) ) + {} +#else + type_constexpr explicit type( T const & v ) + : data( v ) + {} +#endif +}; + +/** + * boolean. + */ +template< typename Tag, typename D = bool > +struct boolean + : type < bool,Tag,D > + , is_eq< boolean > + , is_ne< boolean > + , logical_not< boolean > +{ +private: + // explicit boolean operator return type. + + typedef void ( boolean::*bool_type )() const; + + // address of method used as 'boolean', + + void ERROR_this_type_does_not_support_comparisons() const {} + +public: + // default/initializing constructor. + +#if type_CPP11_OR_GREATER + type_REQUIRES_0( + ! std::is_same::value + ) +#endif + type_constexpr boolean() + : type() + {} + + type_constexpr explicit boolean( bool value ) + : type( value ) + {} + + // safe conversion to 'boolean'; + +#if type_HAVE_EXPLICIT_CONVERSION + type_constexpr explicit operator bool() const + { + return this->get(); + } +#else + type_constexpr operator bool_type() const + { + return this->get() ? &boolean::ERROR_this_type_does_not_support_comparisons : 0; + } +#endif +}; + +/** + * logical, ... + */ +template< typename T, typename Tag, typename D = T > +struct logical + : type< T,Tag,D > + , logical_not< type > + , logical_and< type > + , logical_or < type > +{ +#if type_CPP11_OR_GREATER + type_REQUIRES_0( + ! std::is_same::value + ) +#endif + type_constexpr logical() + : type() + {} + +#if type_CPP11_OR_GREATER + type_constexpr explicit logical( T v ) + : type( std::move(v) ) + {} +#else + type_constexpr explicit logical( T const & v ) + : type( v ) + {} +#endif +}; + +/** + * equality, EqualityComparable. + */ +template< typename T, typename Tag, typename D = T > +struct equality + : type + , is_eq< equality > + , is_ne< equality > +{ +#if type_CPP11_OR_GREATER + type_REQUIRES_0( + ! std::is_same::value + ) +#endif + type_constexpr equality() + : type() + {} + +#if type_CPP11_OR_GREATER + type_constexpr explicit equality( T v ) + : type( std::move(v) ) + {} +#else + type_constexpr explicit equality( T const & v ) + : type( v ) + {} +#endif +}; + +/** + * bits, EqualityComparable and bitwise operators. + */ +template< typename T, typename Tag, typename D = T > +struct bits + : equality< T,Tag,D > +// , bit_not < bits > + , bit_and < bits > + , bit_or < bits > + , bit_xor < bits > + , bit_shl < bits > + , bit_shr < bits > +{ +#if type_CPP11_OR_GREATER + type_REQUIRES_0( + ! std::is_same::value + ) +#endif + type_constexpr bits() + : equality() + {} + +#if type_CPP11_OR_GREATER + type_constexpr explicit bits( T v ) + : equality( std::move(v) ) + {} +#else + type_constexpr explicit bits( T const & v ) + : equality( v ) + {} +#endif + + type_constexpr14 bits operator~ () { return bits( static_cast( ~this->get() ) ); } + + type_constexpr14 bits & operator^=( bits const & other ) { this->get() = this->get() ^ other.get(); return *this; } + type_constexpr14 bits & operator&=( bits const & other ) { this->get() = this->get() & other.get(); return *this; } + type_constexpr14 bits & operator|=( bits const & other ) { this->get() = this->get() | other.get(); return *this; } + + type_constexpr14 bits & operator<<=( int const n ) { this->get() <<= n; return *this; } + type_constexpr14 bits & operator>>=( int const n ) { this->get() >>= n; return *this; } +}; + +/** + * ordered, LessThanComparable. + */ +template< typename T, typename Tag, typename D = T > +struct ordered + : equality + , is_lt < ordered > + , is_gt < ordered > + , is_lteq < ordered > + , is_gteq < ordered > +{ +#if type_CPP11_OR_GREATER + type_REQUIRES_0( + ! std::is_same::value + ) +#endif + type_constexpr ordered() + : equality() + {} + +#if type_CPP11_OR_GREATER + type_constexpr explicit ordered( T v ) + : equality( std::move(v) ) + {} +#else + type_constexpr explicit ordered( T const & v ) + : equality( v ) + {} +#endif +}; + +/** + * numeric, LessThanComparable and ... + */ +template< typename T, typename Tag, typename D = T > +struct numeric + : ordered < T,Tag,D > + , plus < numeric > + , minus < numeric > + , multiplies< numeric > + , divides < numeric > + , modulus < numeric > +{ +#if type_CPP11_OR_GREATER + type_REQUIRES_0( + ! std::is_same::value + ) +#endif + type_constexpr numeric() + : ordered() + {} + +#if type_CPP11_OR_GREATER + type_constexpr explicit numeric( T v ) + : ordered( std::move(v) ) + {} +#else + type_constexpr explicit numeric( T const & v ) + : ordered( v ) + {} +#endif + + type_constexpr14 numeric operator+() const { return *this; } + type_constexpr14 numeric operator-() const { return numeric( -this->get() ); } + + type_constexpr14 numeric & operator++() { return ++this->get(), *this; } + type_constexpr14 numeric & operator--() { return --this->get(), *this; } + + type_constexpr14 numeric operator++( int ) { numeric tmp(*this); ++*this; return tmp; } + type_constexpr14 numeric operator--( int ) { numeric tmp(*this); --*this; return tmp; } + + type_constexpr14 numeric & operator+=( numeric const & other ) { this->get() += other.get(); return *this; } + type_constexpr14 numeric & operator-=( numeric const & other ) { this->get() -= other.get(); return *this; } + type_constexpr14 numeric & operator*=( numeric const & other ) { this->get() *= other.get(); return *this; } + type_constexpr14 numeric & operator/=( numeric const & other ) { this->get() /= other.get(); return *this; } + type_constexpr14 numeric & operator%=( numeric const & other ) { this->get() %= other.get(); return *this; } +}; + +/** + * quantity, keep dimension. + */ +template< typename T, typename Tag, typename D = T > +struct quantity + : ordered < T,Tag,D > + , plus < quantity > + , minus < quantity > + , modulus < quantity > + , multiplies < quantity, quantity, T > + , multiplies2< quantity, T, quantity > + , divides < quantity, quantity, T > +{ +#if type_CPP11_OR_GREATER + type_REQUIRES_0( + ! std::is_same::value + ) +#endif + type_constexpr quantity() + : ordered() + {} + +#if type_CPP11_OR_GREATER + type_constexpr explicit quantity( T v ) + : ordered( std::move(v) ) + {} +#else + type_constexpr explicit quantity( T const & v ) + : ordered( v ) + {} +#endif + + type_constexpr14 quantity operator+() const { return *this; } + type_constexpr14 quantity operator-() const { return quantity( -this->get() ); } + + type_constexpr14 quantity & operator+=( quantity const & other ) { this->get() += other.get(); return *this; } + type_constexpr14 quantity & operator-=( quantity const & other ) { this->get() -= other.get(); return *this; } + + type_constexpr14 quantity & operator*=( T const & y ) { return this->get() *= y, *this; } + type_constexpr14 quantity & operator/=( T const & y ) { return this->get() /= y, *this; } + + type_constexpr14 T operator/( quantity const & y ) { return this->get() / y.get(); } +}; + +/** + * offset for address calculations. + * + * offset + offset => offset + * offset - offset => offset + */ +template< typename T, typename Tag, typename D = T > +struct offset + : ordered< T,Tag,D > + , plus < offset > + , minus < offset > +{ +#if type_CPP11_OR_GREATER + type_REQUIRES_0( + ! std::is_same::value + ) +#endif + type_constexpr offset() + : ordered() + {} + +#if type_CPP11_OR_GREATER + type_constexpr explicit offset( T v ) + : ordered( std::move(v) ) + {} +#else + type_constexpr explicit offset( T const & v ) + : ordered( v ) + {} +#endif + + type_constexpr14 offset & operator+=( offset const & y ) { this->get() += y.get(); return *this; } + type_constexpr14 offset & operator-=( offset const & y ) { this->get() -= y.get(); return *this; } +}; + +/** + * address + * + * address + address => error + * address - address => offset + * address + offset => address + * address - offset => address + * offset + address => address + * offset - address => error + * offset + offset => offset + * offset - offset => offset + */ +template< typename T, typename O, typename Tag, typename D = T > +struct address + : ordered< T,Tag,D > + , plus < address, address, offset < O,Tag,O> > + , plus2< address, offset < O,Tag,O>, address > + , minus< address, address, offset < O,Tag,O> > +{ + typedef offset offset_type; + +#if type_CPP11_OR_GREATER + type_REQUIRES_0( + ! std::is_same::value + ) +#endif + type_constexpr address() + : ordered() + {} + +#if type_CPP11_OR_GREATER + type_constexpr explicit address( T v ) + : ordered( std::move(v) ) + {} +#else + type_constexpr explicit address( T const & v ) + : ordered( v ) + {} +#endif + + type_constexpr14 address & operator+=( offset_type const & y ) { this->get() += y.get(); return *this; } + type_constexpr14 address & operator-=( offset_type const & y ) { this->get() -= y.get(); return *this; } + + friend type_constexpr14 offset_type operator-( address const & x, address const & y ) { return offset_type( x.get() - y.get() ); } +}; + +// swap values. + +template < typename T, typename Tag, typename D > +inline type_constexpr14 void swap( type & x, type & y ) +{ + x.swap( y ); +} + +// the underlying value. + +#if type_CPP11_OR_GREATER + +template< typename T, typename Tag, typename D > +inline type_constexpr14 typename type::underlying_type && +to_value( type && v ) +{ + return std::move( v ).get(); +} + +#endif + +template< typename T, typename Tag, typename D > +inline type_constexpr14 typename type::underlying_type const & +to_value( type const & v ) +{ + return v.get(); +} + +}} // namespace nonstd::types + +#if type_HAVE_STD_HASH + +namespace std { + +template< typename T, typename Tag, typename D > +struct hash< ::nonstd::types::type > +{ +public: + std::size_t operator()( ::nonstd::types::type const & v ) const type_noexcept + { + return std::hash()( v.get() ); + } +}; + +} // namespace std + +namespace nonstd { namespace types { + +template< typename T, typename Tag, typename D > +std::size_t make_hash( type const & v ) type_noexcept +{ + return std::hash<::nonstd::types::type >()( v ); +} + +}} // namespace nonstd::types + +#endif // type_HAVE_STD_HASH + +// make type available in namespace nonstd: + +namespace nonstd { + +using types::no_default_t; +using types::custom_default_t; + +using types::type; +using types::bits; +using types::boolean; +using types::logical; +using types::equality; // equal +using types::ordered; +using types::numeric; +using types::quantity; + +using types::offset; +using types::address; + +using types::swap; +using types::to_value; + +#if type_HAVE_STD_HASH +using types::make_hash; +#endif +} // namespace nonstd + +// stream output. + +#if 0 + +#include + +namespace nonstd { + +template< typename T, typename Tag, typename D > +inline std::ostream & operator<<( std::ostream & os, type v ) +{ + return os << v.get(); +} + +} // namespace nonstd::types + +#endif + +#endif // NONSTD_TYPE_HPP_INCLUDED diff --git a/src/loader/AndroidManifest.xml b/src/loader/AndroidManifest.xml index 2817b34ad..291b1d307 100644 --- a/src/loader/AndroidManifest.xml +++ b/src/loader/AndroidManifest.xml @@ -9,16 +9,7 @@ - - - - - - - - - diff --git a/src/loader/AndroidManifest.xml.in b/src/loader/AndroidManifest.xml.in index 9bd8a4602..4315f57dc 100644 --- a/src/loader/AndroidManifest.xml.in +++ b/src/loader/AndroidManifest.xml.in @@ -1,26 +1,18 @@ + android:versionName="${MAJOR}.${MINOR}.${PATCH}${OPENXR_ANDROID_VERSION_SUFFIX}"> + + - - - - - - - - - - diff --git a/src/loader/CMakeLists.txt b/src/loader/CMakeLists.txt index 22047fbc7..8c89171d3 100644 --- a/src/loader/CMakeLists.txt +++ b/src/loader/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2023, The Khronos Group Inc. +# Copyright (c) 2017 The Khronos Group Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -14,6 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# Author: +# if(WIN32) # Pass version fields as preprocessor for .rc resource version on Windows. @@ -166,11 +168,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux") target_compile_definitions(openxr_loader PRIVATE EXTRASYSCONFDIR="/etc") endif() - set_target_properties(openxr_loader PROPERTIES SOVERSION "${MAJOR}" VERSION "${OPENXR_FULL_VERSION}") + set_target_properties(openxr_loader PROPERTIES SOVERSION "${MAJOR}" VERSION "${MAJOR}.${MINOR}.${PATCH}") add_custom_target( libopenxr_loader.so.${MAJOR}.${MINOR} ALL - COMMAND ${CMAKE_COMMAND} -E create_symlink libopenxr_loader.so.${OPENXR_FULL_VERSION} + COMMAND ${CMAKE_COMMAND} -E create_symlink libopenxr_loader.so.${MAJOR}.${MINOR}.${PATCH} libopenxr_loader.so.${MAJOR}.${MINOR} ) elseif(WIN32) @@ -273,11 +275,7 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") # Make build depend on the version script/export map target_sources(openxr_loader PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/openxr-loader.map) # Add the linker flag. - if(APPLE) - set_target_properties(openxr_loader PROPERTIES LINK_FLAGS "-Wl,-exported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/openxr-loader.expsym") - else() - set_target_properties(openxr_loader PROPERTIES LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/openxr-loader.map") - endif() + set_target_properties(openxr_loader PROPERTIES LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/openxr-loader.map") # For GCC version 7.1 or greater, we need to disable the implicit fallthrough warning since # there's no consistent way to satisfy all compilers until they all accept the C++17 standard if(CMAKE_COMPILER_IS_GNUCC AND NOT (CMAKE_CXX_COMPILER_VERSION LESS 7.1)) @@ -286,10 +284,7 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") endif() add_library(headers INTERFACE) -target_include_directories(headers INTERFACE - $ - $ - $) +target_include_directories(headers INTERFACE $) # We will never actually install here, but it's easier to set something than block all install code. if(ANDROID AND NOT INSTALL_TO_ARCHITECTURE_PREFIXES) @@ -310,10 +305,6 @@ export( NAMESPACE OpenXR:: ) -# Create aliases so that it can be used the same whether vendored as source or found with CMake. -add_library(OpenXR::openxr_loader ALIAS openxr_loader) -add_library(OpenXR::headers ALIAS headers) - if(WIN32 AND NOT INSTALL_TO_ARCHITECTURE_PREFIXES) set(TARGET_DESTINATION cmake) else() @@ -338,7 +329,7 @@ configure_package_config_file( ) write_basic_package_version_file( ${CMAKE_CURRENT_BINARY_DIR}/OpenXRConfigVersion.cmake - VERSION "${OPENXR_FULL_VERSION}" + VERSION "${MAJOR}.${MINOR}.${PATCH}" COMPATIBILITY SameMajorVersion ) install( @@ -401,5 +392,5 @@ elseif(ANDROID AND INSTALL_TO_ARCHITECTURE_PREFIXES) # This gets used directly by build-aar.sh configure_file(${CMAKE_CURRENT_SOURCE_DIR}/openxr_loader_for_android.pom - ${CMAKE_CURRENT_BINARY_DIR}/openxr_loader_for_android-${OPENXR_FULL_VERSION}${OPENXR_ANDROID_VERSION_SUFFIX}.pom) + ${CMAKE_CURRENT_BINARY_DIR}/openxr_loader_for_android-${MAJOR}.${MINOR}.${PATCH}${OPENXR_ANDROID_VERSION_SUFFIX}.pom) endif() diff --git a/src/loader/android_utilities.cpp b/src/loader/android_utilities.cpp index 9a3ad76ce..0f8a970d5 100644 --- a/src/loader/android_utilities.cpp +++ b/src/loader/android_utilities.cpp @@ -19,10 +19,10 @@ #include #include -#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, "OpenXR-Loader", __VA_ARGS__) -#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, "OpenXR-Loader", __VA_ARGS__) -#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "OpenXR-Loader", __VA_ARGS__) -#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, "OpenXR-Loader", __VA_ARGS__) +#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, "openxr_loader", __VA_ARGS__) +#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, "openxr_loader", __VA_ARGS__) +#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "openxr_loader", __VA_ARGS__) +#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, "openxr_loader", __VA_ARGS__) namespace openxr_android { using wrap::android::content::ContentUris; @@ -38,8 +38,12 @@ constexpr auto SYSTEM_AUTHORITY = "org.khronos.openxr.system_runtime_broker"; constexpr auto BASE_PATH = "openxr"; constexpr auto ABI_PATH = "abi"; constexpr auto RUNTIMES_PATH = "runtimes"; +constexpr auto API_LAYERS_PATH = "api_layer"; +constexpr auto IMP_LAYER = "implicit"; +constexpr auto EXP_LAYER = "explicit"; constexpr const char *getBrokerAuthority(bool systemBroker) { return systemBroker ? SYSTEM_AUTHORITY : AUTHORITY; } +constexpr const char *getLayerTypePath(bool isImplicitLayer) { return isImplicitLayer ? IMP_LAYER : EXP_LAYER; } struct BaseColumns { /** @@ -164,6 +168,51 @@ struct Columns : BaseColumns { }; } // namespace functions +namespace api_layer { +/** + * Final path component to this URI. + */ + +/** + * Create a content URI for querying all rows of the implicit/explicit API layer data for a given + * runtime package and major version of OpenXR. + * + * @param systemBroker If the system runtime broker (instead of the installable one) should be queried. + * @param majorVer The major version of OpenXR. + * @param layerType The layer type of the API layer. + * @param abi The Android ABI name in use. + * @return A content URI for the entire table: the function remapping for that runtime. + */ +static Uri makeContentUri(bool systemBroker, int majorVersion, std::string const &layerType, const char *abi) { + auto builder = Uri_Builder::construct(); + builder.scheme("content") + .authority(getBrokerAuthority(systemBroker)) + .appendPath(BASE_PATH) + .appendPath(std::to_string(majorVersion)) + .appendPath(ABI_PATH) + .appendPath(abi) + .appendPath(API_LAYERS_PATH) + .appendPath(getLayerTypePath(layerType == IMP_LAYER)); + return builder.build(); +} +struct Columns : BaseColumns { + // implicit or explicit + static constexpr auto FILE_FORMAT_VERSION = "file_format_version"; + static constexpr auto NAME = "name"; + static constexpr auto NATIVE_LIB_DIR = "native_lib_dir"; + static constexpr auto SO_FILENAME = "so_filename"; + static constexpr auto API_VERSION = "api_version"; + static constexpr auto IMPLEMENTATION_VERSION = "implementation_version"; + static constexpr auto DESCRIPTION = "description"; + static constexpr auto ENABLE_ENVIRONMENT = "enable_environment"; + static constexpr auto DISABLE_ENVIRONMENT = "disable_environment"; + static constexpr auto FUNCTIONS = "functions"; + // extensions names will be combined like "extension1&extension2" + static constexpr auto INSTANCE_EXTENSION_NAMES = "instance_extension_names"; + static constexpr auto INSTANCE_EXTENSION_VERSIONS = "instance_extension_versions"; +}; +} // namespace api_layer + } // namespace static inline jni::Array makeArray(std::initializer_list &&list) { @@ -245,11 +294,13 @@ static int populateFunctions(wrap::android::content::Context const &context, boo return 0; } -/// Get cursor for active runtime, parameterized by whether or not we use the system broker -static bool getActiveRuntimeCursor(wrap::android::content::Context const &context, jni::Array const &projection, - bool systemBroker, Cursor &cursor) { - auto uri = active_runtime::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), ABI); - ALOGI("getActiveRuntimeCursor: Querying URI: %s", uri.toString().c_str()); +/// Get cursor for active runtime or API layer, parameterized by target type and whether or not we use the system broker +static bool getCursor(wrap::android::content::Context const &context, jni::Array const &projection, + std::string const &targetType, bool systemBroker, Cursor &cursor) { + auto uri = (targetType == RUNTIMES_PATH) + ? active_runtime::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), ABI) + : api_layer::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), targetType, ABI); + ALOGI("getCursor: Querying URI: %s", uri.toString().c_str()); try { cursor = context.getContentResolver().query(uri, projection); } catch (const std::exception &e) { @@ -279,10 +330,10 @@ int getActiveRuntimeVirtualManifest(wrap::android::content::Context const &conte // First, try getting the installable broker's provider bool systemBroker = false; Cursor cursor; - if (!getActiveRuntimeCursor(context, projection, systemBroker, cursor)) { + if (!getCursor(context, projection, RUNTIMES_PATH, systemBroker, cursor)) { // OK, try the system broker as a fallback. systemBroker = true; - getActiveRuntimeCursor(context, projection, systemBroker, cursor); + getCursor(context, projection, RUNTIMES_PATH, systemBroker, cursor); } if (cursor.isNull()) { @@ -314,6 +365,132 @@ int getActiveRuntimeVirtualManifest(wrap::android::content::Context const &conte virtualManifest = builder.build(); return 0; } + +static bool populateApiLayerManifest(std::string layerType, Cursor &cursor, std::vector &layerRootNode) { + auto fileFormatVersion = cursor.getString(cursor.getColumnIndex(api_layer::Columns::FILE_FORMAT_VERSION)); + auto name = cursor.getString(cursor.getColumnIndex(api_layer::Columns::NAME)); + auto libDir = cursor.getString(cursor.getColumnIndex(active_runtime::Columns::NATIVE_LIB_DIR)); + auto fileName = cursor.getString(cursor.getColumnIndex(api_layer::Columns::SO_FILENAME)); + auto apiVersion = cursor.getString(cursor.getColumnIndex(api_layer::Columns::API_VERSION)); + auto implementationVersion = cursor.getString(cursor.getColumnIndex(api_layer::Columns::IMPLEMENTATION_VERSION)); + auto description = cursor.getString(cursor.getColumnIndex(api_layer::Columns::DESCRIPTION)); + auto disableEnv = cursor.getString(cursor.getColumnIndex(api_layer::Columns::DISABLE_ENVIRONMENT)); + auto enableEnv = cursor.getString(cursor.getColumnIndex(api_layer::Columns::ENABLE_ENVIRONMENT)); + auto extensionNames = cursor.getString(cursor.getColumnIndex(api_layer::Columns::INSTANCE_EXTENSION_NAMES)); + auto extensionVersions = cursor.getString(cursor.getColumnIndex(api_layer::Columns::INSTANCE_EXTENSION_VERSIONS)); + auto functions = cursor.getString(cursor.getColumnIndex(api_layer::Columns::FUNCTIONS)); + + __android_log_print(ANDROID_LOG_INFO, TAG, "Got api layer: type: %s, name: %s, native lib dir: %s, fileName: %s, functions: %s", + layerType.c_str(), name.c_str(), libDir.c_str(), fileName.c_str(), functions.c_str()); + + Json::Value rootNode(Json::objectValue); + rootNode["file_format_version"] = fileFormatVersion; + rootNode["api_layer"] = Json::objectValue; + rootNode["api_layer"]["name"] = name; + rootNode["api_layer"]["library_path"] = libDir + "/" + fileName; + rootNode["api_layer"]["api_version"] = apiVersion; + rootNode["api_layer"]["implementation_version"] = implementationVersion; + rootNode["api_layer"]["description"] = description; + rootNode["api_layer"]["disable_environment"] = disableEnv; + rootNode["api_layer"]["enable_environment"] = enableEnv; + + rootNode["api_layer"]["instance_extensions"] = Json::Value(Json::arrayValue); + std::vector nameVec; + std::vector versionVec; + // extract extension names + std::istringstream issNames(extensionNames); + std::string item; + while (std::getline(issNames, item, '&')) { + nameVec.push_back(item); + } + // extract extension versions + std::istringstream issVersions(extensionVersions); + while (std::getline(issVersions, item, '&')) { + versionVec.push_back(item); + } + + Json::Value extension(Json::objectValue); + if (nameVec.size() == versionVec.size()) { + for (int i = 0; i < nameVec.size(); ++i) { + extension["name"] = nameVec[i]; + extension["extension_version"] = versionVec[i]; + rootNode["api_layer"]["instance_extensions"].append(extension); + __android_log_print(ANDROID_LOG_INFO, TAG, "extension name: %s, extension version: %s", nameVec[i].c_str(), + versionVec[i].c_str()); + } + } else { + __android_log_print(ANDROID_LOG_INFO, TAG, "api layer extension name not match extension version!"); + } + + std::vector functionNameVec; + std::vector symbolVec; + std::istringstream issFunctions(functions); + while (std::getline(issFunctions, item, '&')) { + std::size_t pos = item.find(':'); + if (pos != item.npos) { + functionNameVec.push_back(item.substr(0, pos)); + symbolVec.push_back(item.substr(pos + 1, item.size())); + } + } + + rootNode["api_layer"]["functions"] = Json::Value(Json::objectValue); + if (functions != "None") { + for (int i = 0; i < functionNameVec.size(); ++i) { + rootNode["api_layer"]["functions"][functionNameVec[i]] = symbolVec[i]; + __android_log_print(ANDROID_LOG_INFO, TAG, "function name: %s, symbol: %s", functionNameVec[i].c_str(), + symbolVec[i].c_str()); + } + } else { + __android_log_print(ANDROID_LOG_INFO, TAG, "functions field not existed!"); + } + + layerRootNode.push_back(rootNode); + + return true; +} + +static void enumerateApiLayerManifests(std::string layerType, wrap::android::content::Context const &context, + jni::Array &projection, std::vector &virtualManifests) { + Cursor cursor; + + getCursor(context, projection, layerType, false, cursor); + if (cursor.isNull()) { + return; + } + cursor.moveToFirst(); + for (int i = 0; i < cursor.getCount(); ++i) { + populateApiLayerManifest(layerType, cursor, virtualManifests); + cursor.moveToNext(); + } + + cursor.close(); +} + +int getApiLayerVirtualManifests(std::string layerType, wrap::android::content::Context const &context, + std::vector &virtualManifests) { + static bool hasQueryBroker = false; + static std::vector implicitLayerManifest; + static std::vector explicitLayerManifest; + + __android_log_print(ANDROID_LOG_INFO, TAG, "Try to get %s API layer from broker!", layerType.c_str()); + if (!hasQueryBroker) { + jni::Array projection = + makeArray({api_layer::Columns::FILE_FORMAT_VERSION, api_layer::Columns::NAME, api_layer::Columns::NATIVE_LIB_DIR, + api_layer::Columns::SO_FILENAME, api_layer::Columns::API_VERSION, api_layer::Columns::IMPLEMENTATION_VERSION, + api_layer::Columns::DESCRIPTION, api_layer::Columns::ENABLE_ENVIRONMENT, + api_layer::Columns::DISABLE_ENVIRONMENT, api_layer::Columns::FUNCTIONS, + api_layer::Columns::INSTANCE_EXTENSION_NAMES, api_layer::Columns::INSTANCE_EXTENSION_VERSIONS}); + + enumerateApiLayerManifests(IMP_LAYER, context, projection, implicitLayerManifest); + enumerateApiLayerManifests(EXP_LAYER, context, projection, explicitLayerManifest); + + hasQueryBroker = true; + } + + virtualManifests = (layerType == IMP_LAYER) ? implicitLayerManifest : explicitLayerManifest; + return 0; +} + } // namespace openxr_android #endif // __ANDROID__ diff --git a/src/loader/android_utilities.h b/src/loader/android_utilities.h index f66c9bf1d..3356fd95e 100644 --- a/src/loader/android_utilities.h +++ b/src/loader/android_utilities.h @@ -27,6 +27,18 @@ using wrap::android::content::Context; * @return 0 on success, something else on failure. */ int getActiveRuntimeVirtualManifest(wrap::android::content::Context const &context, Json::Value &virtualManifest); + +/*! + * Find the implicit/explicit API layers on the system, and return a constructed JSON object representing it. + * + * @param type An String to indicate layer type of API layers, implicit or explicit. + * @param context An Android context, preferably an Activity Context. + * @param[out] virtualManifest The Json::Value to fill with the virtual manifest. + * + * @return 0 on success, something else on failure. + */ +int getApiLayerVirtualManifests(std::string layerType, wrap::android::content::Context const &context, + std::vector &virtualManifests); } // namespace openxr_android #endif // __ANDROID__ diff --git a/src/loader/api_layer_interface.cpp b/src/loader/api_layer_interface.cpp index 5560c31a5..93a225f3e 100644 --- a/src/loader/api_layer_interface.cpp +++ b/src/loader/api_layer_interface.cpp @@ -82,12 +82,6 @@ XrResult ApiLayerInterface::GetApiLayerProperties(const std::string& openxr_comm return result; } - // check for potential overflow before static_cast - if (manifest_files.size() >= UINT32_MAX) { - LoaderLogger::LogErrorMessage(openxr_command, "ApiLayerInterface::GetApiLayerProperties - too many API layers found"); - return XR_ERROR_RUNTIME_FAILURE; - } - manifest_count = static_cast(manifest_files.size()); if (nullptr == outgoing_count) { LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties", @@ -137,8 +131,8 @@ XrResult ApiLayerInterface::GetInstanceExtensionProperties(const std::string& op } bool found = false; - size_t num_files = manifest_files.size(); - for (size_t man_file = 0; man_file < num_files; ++man_file) { + auto num_files = static_cast(manifest_files.size()); + for (uint32_t man_file = 0; man_file < num_files; ++man_file) { // If a layer with the provided name exists, get it's instance extension information. if (manifest_files[man_file]->LayerName() == layer_name) { manifest_files[man_file]->GetInstanceExtensionProperties(extension_properties); @@ -178,8 +172,8 @@ XrResult ApiLayerInterface::GetInstanceExtensionProperties(const std::string& op } // Grab the layer instance extensions information - size_t num_files = manifest_files.size(); - for (size_t man_file = 0; man_file < num_files; ++man_file) { + auto num_files = static_cast(manifest_files.size()); + for (uint32_t man_file = 0; man_file < num_files; ++man_file) { manifest_files[man_file]->GetInstanceExtensionProperties(extension_properties); } } diff --git a/src/loader/build.gradle b/src/loader/build.gradle new file mode 100644 index 000000000..acf7971f9 --- /dev/null +++ b/src/loader/build.gradle @@ -0,0 +1,204 @@ +// Copyright (c) 2020-2023, The Khronos Group Inc. +// +// SPDX-License-Identifier: Apache-2.0 + +// Open this directory in Android Studio, or build with Gradle, +// as one way to create an AAR file of the loader. +// The other way is with maintainer-scripts/build-aar.sh which is simpler. +buildscript { + repositories { + google() + mavenCentral() + } + dependencies { + classpath "com.android.tools.build:gradle:4.1.3" + } +} + +plugins { + id "ru.vyarus.use-python" version "2.3.0" + id "maven-publish" +} + +apply plugin: "com.android.library" + +// These next few lines are just to make the version match the OpenXR release. +def repoRoot = file("../..") +project.ext.repoRoot = repoRoot +apply from: new File(repoRoot, "src/version.gradle") + +repositories { + google() + mavenCentral() +} + +def baseIncludeDir = new File(buildDir, "intermediates/includes") +def includeDir = layout.buildDirectory.file("intermediates/includes/openxr") +def scriptDir = "${project.repoRoot}/specification/scripts" +def registry = "${project.repoRoot}/specification/registry/xr.xml" + +ext.stl = "c++_static" + +// Python is used to generate header files +python { + pip "jinja2:2.10.3" + pip "MarkupSafe:2.0.1" + minPythonVersion = "3.4" + + environment = ["PYTHONPATH": scriptDir] +} + +def ensureDirectory = tasks.register("ensureDirectory") { + doLast { + mkdir(includeDir) + } +} + +// Copy or generate the OpenXR headers for packaging in the prefab AAR. +// Cannot just use ones from the build here, unfortunately. +tasks.addRule("Pattern: stageHeader_") { String taskName -> + if (!taskName.startsWith("stageHeader_")) { + return + } + def headerName = taskName - "stageHeader_" + + def pregenerated = new File(repoRoot, "include/openxr/${headerName}.h") + + if (pregenerated.exists()) { + // if the file exists, our task just copies it. + task(taskName, type: Copy) { + from pregenerated + into includeDir + dependsOn ensureDirectory + } + + } else { + + // if the file does not exist, our task generates it. + task(taskName, type: PythonTask) { + command = ["$scriptDir/genxr.py", + "-registry", + registry, + "-quiet", + "-o", + includeDir.get(), + "${headerName}.h"] + dependsOn ensureDirectory + } + } +} + + +preBuild.dependsOn stageHeader_openxr, + stageHeader_openxr_platform, + stageHeader_openxr_reflection, + stageHeader_openxr_platform_defines + +// Used for publishing/deploying +version = project.versionOpenXR + +android { + compileSdkVersion 29 + buildToolsVersion "30.0.3" + ndkVersion "21.3.6528147" + defaultConfig { + // for Vulkan, need at least 24 + minSdkVersion 24 + + versionName = project.versionOpenXR.toString() + project.versionQualifier + versionCode = project.versionOpenXR.getVersionCode() + externalNativeBuild { + cmake { + arguments "-DANDROID_STL=${stl}", + "-DBUILD_API_LAYERS=OFF", + "-DBUILD_TESTS=OFF", + "-DBUILD_LOADER=ON", + "-DBUILD_CONFORMANCE_TESTS=OFF", + "-DBUILD_ALL_EXTENSIONS=ON" + targets "openxr_loader" + } + } + } + sourceSets { + main { + manifest.srcFile "AndroidManifest.xml" + } + } + + buildTypes { + release { + minifyEnabled false + } + } + + externalNativeBuild { + cmake { + path "${project.repoRoot}/CMakeLists.txt" + } + } + + buildFeatures { + prefabPublishing true + } + prefab { + openxr_loader { + headers "${baseIncludeDir}" + } + } +} + +// Note: While publishing is available in this build file, +// what seems to be a bug in the Android gradle plugin duplicates +// the files in the .aar file, so the alternate approach is recommended for making/publishing +// artifacts for now. + +def siteUrl = "https://github.com/KhronosGroup/OpenXR-SDK-Source" +def gitUrl = "scm:git:https://github.com/KhronosGroup/OpenXR-SDK-Source.git" +publishing { + publications { + // Creates a Maven publication called "maven". + maven(MavenPublication) { + + artifactId "openxr_loader_for_android" + version project.versionOpenXR.toString() + project.versionQualifier + + pom { + name = "OpenXR Loader for Android" + description = "The AAR for the OpenXR Loader as used on Android." + url = siteUrl + + // Set your license + licenses { + license { + name = "The Apache Software License, Version 2.0" + url = "http://www.apache.org/licenses/LICENSE-2.0.txt" + } + // or MIT, but not easy to express clearly in POM. + } + developers { + developer { + name = "The Khronos Group, Inc." + email = "openxr-speceditor AT khronos DOT org" + } + } + scm { + connection = gitUrl + developerConnection = gitUrl + url = siteUrl + } + } + repositories { + maven { + url = uri(layout.buildDirectory.dir("repo")) + } + } + } + + } +} + +// Applies the component for the release build variant. +afterEvaluate { + publishing.publications["maven"].from(components.release) +} + diff --git a/src/loader/loader_instance.cpp b/src/loader/loader_instance.cpp index badd39193..21fc4632b 100644 --- a/src/loader/loader_instance.cpp +++ b/src/loader/loader_instance.cpp @@ -200,8 +200,8 @@ XrResult LoaderInstance::CreateInstance(PFN_xrGetInstanceProcAddr get_instance_p if (!api_layer_interfaces.empty()) { // Initialize an array of ApiLayerNextInfo structs std::unique_ptr next_info_list(new XrApiLayerNextInfo[api_layer_interfaces.size()]); - size_t ni_index = api_layer_interfaces.size() - 1; - for (size_t i = 0; i <= ni_index; i++) { + auto ni_index = static_cast(api_layer_interfaces.size() - 1); + for (uint32_t i = 0; i <= ni_index; i++) { next_info_list[i].structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO; next_info_list[i].structVersion = XR_API_LAYER_NEXT_INFO_STRUCT_VERSION; next_info_list[i].structSize = sizeof(XrApiLayerNextInfo); diff --git a/src/loader/loader_logger_recorders.cpp b/src/loader/loader_logger_recorders.cpp index 32e4687b2..1b3892b89 100644 --- a/src/loader/loader_logger_recorders.cpp +++ b/src/loader/loader_logger_recorders.cpp @@ -160,15 +160,12 @@ bool DebugUtilsLogRecorder::LogMessage(XrLoaderLogMessageSeverityFlagBits messag XrDebugUtilsMessageTypeFlagsEXT utils_type = LoaderLogMessageTypesToDebugUtilsMessageTypes(message_type); // Convert the loader log message into the debug utils log message information - XrDebugUtilsMessengerCallbackDataEXT utils_callback_data{}; - utils_callback_data.type = XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT; + XrDebugUtilsMessengerCallbackDataEXT utils_callback_data = {XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT}; utils_callback_data.messageId = callback_data->message_id; utils_callback_data.functionName = callback_data->command_name; utils_callback_data.message = callback_data->message; - - XrDebugUtilsObjectNameInfoEXT example_utils_info{}; - example_utils_info.type = XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; - std::vector utils_objects(callback_data->object_count, example_utils_info); + std::vector utils_objects(callback_data->object_count, + {XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT}); for (uint8_t object = 0; object < callback_data->object_count; ++object) { utils_objects[object].objectHandle = callback_data->objects[object].handle; utils_objects[object].objectType = callback_data->objects[object].type; diff --git a/src/loader/manifest_file.cpp b/src/loader/manifest_file.cpp index 99f4e8410..b2ea8ef77 100644 --- a/src/loader/manifest_file.cpp +++ b/src/loader/manifest_file.cpp @@ -233,12 +233,6 @@ static void ReadDataFilesInSearchPaths(const std::string &override_env_var, cons relative_home_path += relative_path; CopyIncludedPaths(true, home, relative_home_path, search_path); } -#elif defined(XR_OS_ANDROID) - CopyIncludedPaths(true, "/product/etc", relative_path, search_path); - CopyIncludedPaths(true, "/odm/etc", relative_path, search_path); - CopyIncludedPaths(true, "/oem/etc", relative_path, search_path); - CopyIncludedPaths(true, "/vendor/etc", relative_path, search_path); - CopyIncludedPaths(true, "/system/etc", relative_path, search_path); #else (void)relative_path; #endif @@ -453,8 +447,7 @@ static void GetExtensionProperties(const std::vector &extensio if (it != props.end()) { it->extensionVersion = std::max(it->extensionVersion, ext.extension_version); } else { - XrExtensionProperties prop{}; - prop.type = XR_TYPE_EXTENSION_PROPERTIES; + XrExtensionProperties prop = {XR_TYPE_EXTENSION_PROPERTIES}; strncpy(prop.extensionName, ext.name.c_str(), XR_MAX_EXTENSION_NAME_SIZE - 1); prop.extensionName[XR_MAX_EXTENSION_NAME_SIZE - 1] = '\0'; prop.extensionVersion = ext.extension_version; @@ -730,6 +723,118 @@ void ApiLayerManifestFile::AddManifestFilesAndroid(ManifestFileType type, } #endif // XR_USE_PLATFORM_ANDROID +void ApiLayerManifestFile::CreateIfValid(ManifestFileType type, const Json::Value &root_node, const std::string &filename, + std::vector> &manifest_files) { + std::ostringstream error_ss("ApiLayerManifestFile::CreateIfValid "); + JsonVersion file_version = {}; + if (!ManifestFile::IsValidJson(root_node, file_version)) { + error_ss << "isValidJson indicates " << filename << " is not a valid manifest file."; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + + Json::Value layer_root_node = root_node["api_layer"]; + + // The API Layer manifest file needs the "api_layer" root as well as other sub-nodes. + // If any of those aren't there, fail. + if (layer_root_node.isNull() || layer_root_node["name"].isNull() || !layer_root_node["name"].isString() || + layer_root_node["api_version"].isNull() || !layer_root_node["api_version"].isString() || + layer_root_node["library_path"].isNull() || !layer_root_node["library_path"].isString() || + layer_root_node["implementation_version"].isNull() || !layer_root_node["implementation_version"].isString()) { + error_ss << filename << " is missing required fields. Verify all proper fields exist."; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + if (MANIFEST_TYPE_IMPLICIT_API_LAYER == type) { + bool enabled = true; + // Implicit layers require the disable environment variable. + if (layer_root_node["disable_environment"].isNull() || !layer_root_node["disable_environment"].isString()) { + error_ss << "Implicit layer " << filename << " is missing \"disable_environment\""; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + // Check if there's an enable environment variable provided + if (!layer_root_node["enable_environment"].isNull() && layer_root_node["enable_environment"].isString()) { + std::string env_var = layer_root_node["enable_environment"].asString(); + // If it's not set in the environment, disable the layer + if (!PlatformUtilsGetEnvSet(env_var.c_str())) { + enabled = false; + } + } + // Check for the disable environment variable, which must be provided in the JSON + std::string env_var = layer_root_node["disable_environment"].asString(); + // If the env var is set, disable the layer. Disable env var overrides enable above + if (PlatformUtilsGetEnvSet(env_var.c_str())) { + enabled = false; + } + + // Not enabled, so pretend like it isn't even there. + if (!enabled) { + error_ss << "Implicit layer " << filename << " is disabled"; + LoaderLogger::LogInfoMessage("", error_ss.str()); + return; + } + } + std::string layer_name = layer_root_node["name"].asString(); + std::string api_version_string = layer_root_node["api_version"].asString(); + JsonVersion api_version = {}; + const int num_fields = sscanf(api_version_string.c_str(), "%u.%u", &api_version.major, &api_version.minor); + api_version.patch = 0; + + if ((num_fields != 2) || (api_version.major == 0 && api_version.minor == 0) || + api_version.major > XR_VERSION_MAJOR(XR_CURRENT_API_VERSION)) { + error_ss << "layer " << filename << " has invalid API Version. Skipping layer."; + LoaderLogger::LogWarningMessage("", error_ss.str()); + return; + } + + char *end_ptr; + uint32_t implementation_version = strtol(layer_root_node["implementation_version"].asString().c_str(), &end_ptr, 10); + if (*end_ptr != '\0') { + error_ss << "layer " << filename << " has invalid implementation version."; + LoaderLogger::LogWarningMessage("", error_ss.str()); + } + + std::string library_path = layer_root_node["library_path"].asString(); + + // If the library_path variable has no directory symbol, it's just a file name and should be accessible on the + // global library path. + if (library_path.find('\\') != std::string::npos || library_path.find('/') != std::string::npos) { + // If the library_path is an absolute path, just use that if it exists + if (FileSysUtilsIsAbsolutePath(library_path)) { + if (!FileSysUtilsPathExists(library_path)) { + error_ss << filename << " library " << library_path << " does not appear to exist"; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + } else { + // Otherwise, treat the library path as a relative path based on the JSON file. + std::string combined_path; + std::string file_parent; + if (!FileSysUtilsGetParentPath(filename, file_parent) || + !FileSysUtilsCombinePaths(file_parent, library_path, combined_path) || !FileSysUtilsPathExists(combined_path)) { + error_ss << filename << " library " << combined_path << " does not appear to exist"; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + library_path = combined_path; + } + } + + std::string description; + if (!layer_root_node["description"].isNull() && layer_root_node["description"].isString()) { + description = layer_root_node["description"].asString(); + } + + // Add this layer manifest file + manifest_files.emplace_back( + new ApiLayerManifestFile(type, filename, layer_name, description, api_version, implementation_version, library_path)); + + // Add any extensions to it after the fact. + // Handle any renamed functions + manifest_files.back()->ParseCommon(layer_root_node); +} + void ApiLayerManifestFile::CreateIfValid(ManifestFileType type, const std::string &filename, std::istream &json_stream, LibraryLocator locate_library, std::vector> &manifest_files) { @@ -843,6 +948,7 @@ void ApiLayerManifestFile::CreateIfValid(ManifestFileType type, const std::strin new ApiLayerManifestFile(type, filename, layer_name, description, api_version, implementation_version, library_path)); // Add any extensions to it after the fact. + // Handle any renamed functions manifest_files.back()->ParseCommon(layer_root_node); } @@ -950,5 +1056,19 @@ XrResult ApiLayerManifestFile::FindManifestFiles(ManifestFileType type, ApiLayerManifestFile::AddManifestFilesAndroid(type, manifest_files); #endif // XR_USE_PLATFORM_ANDROID +#if defined(XR_KHR_LOADER_INIT_SUPPORT) + std::vector virtualManifests; + std::string layerType = (type == ManifestFileType::MANIFEST_TYPE_IMPLICIT_API_LAYER) ? "implicit" : "explicit"; + XrResult result = GetPlatformApiLayerVirtualManifests(layerType, virtualManifests); + if (XR_SUCCESS == result) { + for (int i = 0; i < virtualManifests.size(); ++i) { + ApiLayerManifestFile::CreateIfValid(type, virtualManifests[i], "virtual manifest", manifest_files); + } + } else { + LoaderLogger::LogErrorMessage("", "ApiLayerManifestFile::FindManifestFiles - faile to get virtual manifest files."); + assert(0); + } +#endif // XR_KHR_LOADER_INIT_SUPPORT + return XR_SUCCESS; } diff --git a/src/loader/manifest_file.hpp b/src/loader/manifest_file.hpp index 46b842c66..a6b857eaf 100644 --- a/src/loader/manifest_file.hpp +++ b/src/loader/manifest_file.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017 The Khronos Group Inc. // Copyright (c) 2017 Valve Corporation // Copyright (c) 2017 LunarG, Inc. // @@ -99,6 +99,8 @@ class ApiLayerManifestFile : public ManifestFile { static void CreateIfValid(ManifestFileType type, const std::string &filename, std::istream &json_stream, LibraryLocator locate_library, std::vector> &manifest_files); + static void CreateIfValid(ManifestFileType type, const Json::Value &root_node, const std::string &filename, + std::vector> &manifest_files); static void CreateIfValid(ManifestFileType type, const std::string &filename, std::vector> &manifest_files); /// @return false if we could not find the library. diff --git a/src/loader/openxr-loader.expsym b/src/loader/openxr-loader.expsym deleted file mode 100644 index 98a14921f..000000000 --- a/src/loader/openxr-loader.expsym +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (c) 2019-2023, The Khronos Group Inc. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT - -_xrCreateInstance -_xrDestroyInstance -_xrEnumerateApiLayerProperties -_xrEnumerateInstanceExtensionProperties -_xrGetInstanceProcAddr -_xrGetInstanceProperties -_xrPollEvent -_xrResultToString -_xrStructureTypeToString -_xrGetSystem -_xrGetSystemProperties -_xrEnumerateEnvironmentBlendModes -_xrCreateSession -_xrDestroySession -_xrEnumerateReferenceSpaces -_xrCreateReferenceSpace -_xrGetReferenceSpaceBoundsRect -_xrCreateActionSpace -_xrLocateSpace -_xrDestroySpace -_xrEnumerateViewConfigurations -_xrGetViewConfigurationProperties -_xrEnumerateViewConfigurationViews -_xrEnumerateSwapchainFormats -_xrCreateSwapchain -_xrDestroySwapchain -_xrEnumerateSwapchainImages -_xrAcquireSwapchainImage -_xrWaitSwapchainImage -_xrReleaseSwapchainImage -_xrBeginSession -_xrEndSession -_xrRequestExitSession -_xrWaitFrame -_xrBeginFrame -_xrEndFrame -_xrLocateViews -_xrStringToPath -_xrPathToString -_xrCreateActionSet -_xrDestroyActionSet -_xrCreateAction -_xrDestroyAction -_xrSuggestInteractionProfileBindings -_xrAttachSessionActionSets -_xrGetCurrentInteractionProfile -_xrGetActionStateBoolean -_xrGetActionStateFloat -_xrGetActionStateVector2f -_xrGetActionStatePose -_xrSyncActions -_xrEnumerateBoundSourcesForAction -_xrGetInputSourceLocalizedName -_xrApplyHapticFeedback -_xrStopHapticFeedback diff --git a/src/loader/openxr_loader_for_android.pom b/src/loader/openxr_loader_for_android.pom index 1b696ecce..130efb86d 100644 --- a/src/loader/openxr_loader_for_android.pom +++ b/src/loader/openxr_loader_for_android.pom @@ -1,14 +1,13 @@ - + org.khronos.openxr openxr_loader_for_android - @MAJOR@.@MINOR@.@PATCH@@OPENXR_SDK_HOTFIX_VERSION_SUFFIX@@OPENXR_ANDROID_VERSION_SUFFIX@ + @MAJOR@.@MINOR@.@PATCH@@OPENXR_ANDROID_VERSION_SUFFIX@ aar OpenXR Loader for Android The AAR for the OpenXR Loader as used on Android. diff --git a/src/loader/runtime_interface.cpp b/src/loader/runtime_interface.cpp index d9ab86bb5..be89208f3 100644 --- a/src/loader/runtime_interface.cpp +++ b/src/loader/runtime_interface.cpp @@ -146,8 +146,6 @@ std::string GetAndroidNativeLibraryDir() { return LoaderInitData::instance()._na void* Android_Get_Asset_Manager() { return LoaderInitData::instance()._android_asset_manager; } -#endif // XR_KHR_LOADER_INIT_SUPPORT - #ifdef XR_USE_PLATFORM_ANDROID XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest) { using wrap::android::content::Context; @@ -166,8 +164,29 @@ XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest) { out_manifest = virtualManifest; return XR_SUCCESS; } + +XrResult GetPlatformApiLayerVirtualManifests(std::string type, std::vector& out_manifest) { + using wrap::android::content::Context; + auto& initData = LoaderInitData::instance(); + if (!initData.initialized()) { + return XR_ERROR_INITIALIZATION_FAILED; + } + auto context = Context(reinterpret_cast(initData.getData().applicationContext)); + if (context.isNull()) { + return XR_ERROR_INITIALIZATION_FAILED; + } + std::vector virtualManifests; + if (0 != openxr_android::getApiLayerVirtualManifests(type, context, virtualManifests)) { + return XR_ERROR_INITIALIZATION_FAILED; + } + out_manifest = virtualManifests; + return XR_SUCCESS; +} + #endif // XR_USE_PLATFORM_ANDROID +#endif // XR_KHR_LOADER_INIT_SUPPORT + XrResult RuntimeInterface::TryLoadingSingleRuntime(const std::string& openxr_command, std::unique_ptr& manifest_file) { LoaderPlatformLibraryHandle runtime_library = LoaderPlatformLibraryOpen(manifest_file->LibraryPath()); @@ -430,9 +449,7 @@ void RuntimeInterface::GetInstanceExtensionProperties(std::vector 0) { - XrExtensionProperties example_properties{}; - example_properties.type = XR_TYPE_EXTENSION_PROPERTIES; - runtime_extension_properties.resize(count_output, example_properties); + runtime_extension_properties.resize(count_output, {XR_TYPE_EXTENSION_PROPERTIES}); count = count_output; rt_xrEnumerateInstanceExtensionProperties(nullptr, count, &count_output, runtime_extension_properties.data()); } diff --git a/src/loader/runtime_interface.hpp b/src/loader/runtime_interface.hpp index 8d55ec674..3bc159db2 100644 --- a/src/loader/runtime_interface.hpp +++ b/src/loader/runtime_interface.hpp @@ -31,6 +31,7 @@ class Value; //! Initialize loader, where required. XrResult InitializeLoader(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo); XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest); +XrResult GetPlatformApiLayerVirtualManifests(std::string type, std::vector& out_manifest); std::string GetAndroidNativeLibraryDir(); void* Android_Get_Asset_Manager(); #endif diff --git a/src/scripts/utility_source_generator.py b/src/scripts/utility_source_generator.py index c57286970..1db955b5d 100755 --- a/src/scripts/utility_source_generator.py +++ b/src/scripts/utility_source_generator.py @@ -50,7 +50,6 @@ def beginFile(self, genOpts): if self.genOpts.filename == 'xr_generated_dispatch_table.h': preamble += '#pragma once\n' elif self.genOpts.filename == 'xr_generated_dispatch_table.c': - preamble += '#include \n' preamble += '#include "xr_generated_dispatch_table.h"\n' preamble += '#include "xr_dependencies.h"\n' diff --git a/src/scripts/validation_layer_generator.py b/src/scripts/validation_layer_generator.py index c928838d6..ac5698d15 100644 --- a/src/scripts/validation_layer_generator.py +++ b/src/scripts/validation_layer_generator.py @@ -1437,10 +1437,9 @@ def outputParamMemberContents(self, is_command, struct_command_name, param_membe indent) if (param_member.is_handle or self.isEnumType(param_member.type) or (self.isStruct(param_member.type) and not self.isStructAlwaysValid(param_member.type))): - if not param_member.is_static_array: - loop_string += self.writeIndent(indent) - loop_string += 'if (%s) {\n' % (prefixed_param_member_name) - indent = indent + 1 + loop_string += self.writeIndent(indent) + loop_string += 'if (%s) {\n' % (prefixed_param_member_name) + indent = indent + 1 loop_string += self.writeIndent(indent) loop_string += 'for (uint32_t %s = 0; %s < %s; ++%s) {\n' % (loop_param_name, loop_param_name, @@ -1842,14 +1841,12 @@ def outputParamMemberContents(self, is_command, struct_command_name, param_membe param_member_contents += self.writeIndent(indent) param_member_contents += '}\n' if is_loop: + indent = indent - 2 if wrote_loop: - indent = indent - 1 + param_member_contents += self.writeIndent(indent + 1) + param_member_contents += '}\n' param_member_contents += self.writeIndent(indent) param_member_contents += '}\n' - if not param_member.is_static_array: - indent = indent - 1 - param_member_contents += self.writeIndent(indent) - param_member_contents += '}\n' return param_member_contents diff --git a/src/tests/c_compile_test/CMakeLists.txt b/src/tests/c_compile_test/CMakeLists.txt index 0c9ed69a3..e2057bf88 100644 --- a/src/tests/c_compile_test/CMakeLists.txt +++ b/src/tests/c_compile_test/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2023, The Khronos Group Inc. +# Copyright (c) 2017 The Khronos Group Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -14,6 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# Author: +# add_executable(openxr_c_compile_test main.c @@ -33,7 +35,7 @@ if(Vulkan_FOUND) ) endif() -target_link_libraries(openxr_c_compile_test OpenXR::openxr_loader) +target_link_libraries(openxr_c_compile_test openxr_loader) if(MSVC) target_compile_options(openxr_c_compile_test PRIVATE /Zc:wchar_t /Zc:forScope /W4 /WX) endif() diff --git a/src/tests/hello_xr/AndroidManifest.xml b/src/tests/hello_xr/AndroidManifest.xml index f8fb1155a..7cc8a1c68 100644 --- a/src/tests/hello_xr/AndroidManifest.xml +++ b/src/tests/hello_xr/AndroidManifest.xml @@ -20,26 +20,13 @@ android:required="false" android:version="1" /> - + - - - - - - - - - - - - - #include #include -#include #include #include @@ -92,8 +91,7 @@ inline std::string Fmt(const char* fmt, ...) { // The equivalent of C++17 std::size. A helper to get the dimension for an array. template -constexpr size_t ArraySize(const T (&unused)[Size]) noexcept { - (void)unused; +constexpr size_t ArraySize(const T (&/*unused*/)[Size]) noexcept { return Size; } diff --git a/src/tests/hello_xr/gradle/wrapper/gradle-wrapper.jar b/src/tests/hello_xr/gradle/wrapper/gradle-wrapper.jar index 249e5832f090a2944b7473328c07c9755baa3196..62d4c053550b91381bbd28b1afc82d634bf73a8a 100644 GIT binary patch delta 19947 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 D86?w= delta 21827 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 '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi done - -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" -APP_BASE_NAME=${0##*/} +APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum +MAX_FD="maximum" warn () { echo "$*" -} >&2 +} die () { echo echo "$*" echo exit 1 -} >&2 +} # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -121,9 +89,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java + JAVACMD="$JAVA_HOME/jre/sh/java" else - JAVACMD=$JAVA_HOME/bin/java + JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -132,7 +100,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD=java + JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -140,101 +108,80 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi fi -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi # For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg + i=`expr $i + 1` done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" exec "$JAVACMD" "$@" diff --git a/src/tests/hello_xr/gradlew.bat b/src/tests/hello_xr/gradlew.bat index f127cfd49..bf0b614f7 100644 --- a/src/tests/hello_xr/gradlew.bat +++ b/src/tests/hello_xr/gradlew.bat @@ -1,5 +1,7 @@ @rem @rem Copyright 2015 the original author or authors. +@rem +@rem SPDX-License-Identifier: Apache-2.0 @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @@ -14,7 +16,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%"=="" @echo off +@if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +27,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. +if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +42,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute +if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -54,7 +56,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto execute +if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -64,6 +66,21 @@ echo location of your Java installation. goto fail +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + :execute @rem Setup the command line @@ -71,19 +88,17 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd +if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/src/tests/hello_xr/gradlew.bat.license b/src/tests/hello_xr/gradlew.bat.license deleted file mode 100644 index a6bf97621..000000000 --- a/src/tests/hello_xr/gradlew.bat.license +++ /dev/null @@ -1,2 +0,0 @@ -SPDX-FileCopyrightText: Copyright 2015 the original author or authors. -SPDX-License-Identifier: Apache-2.0 diff --git a/src/tests/hello_xr/gradlew.license b/src/tests/hello_xr/gradlew.license deleted file mode 100644 index 69286a081..000000000 --- a/src/tests/hello_xr/gradlew.license +++ /dev/null @@ -1,2 +0,0 @@ -SPDX-FileCopyrightText: Copyright 2015-2021 the original author or authors. -SPDX-License-Identifier: Apache-2.0 diff --git a/src/tests/hello_xr/graphicsplugin_opengl.cpp b/src/tests/hello_xr/graphicsplugin_opengl.cpp index 43e21a3ce..92ab95d75 100644 --- a/src/tests/hello_xr/graphicsplugin_opengl.cpp +++ b/src/tests/hello_xr/graphicsplugin_opengl.cpp @@ -141,10 +141,6 @@ struct OpenGLGraphicsPlugin : public IGraphicsPlugin { // TODO: Just need something other than NULL here for now (for validation). Eventually need // to correctly put in a valid pointer to an wl_display m_graphicsBinding.display = reinterpret_cast(0xFFFFFFFF); -#elif defined(XR_USE_PLATFORM_MACOS) -#error OpenGL bindings for Mac have not been implemented -#else -#error Platform not supported #endif #if !defined(XR_USE_PLATFORM_MACOS) @@ -375,8 +371,6 @@ struct OpenGLGraphicsPlugin : public IGraphicsPlugin { XrGraphicsBindingOpenGLXcbKHR m_graphicsBinding{XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR}; #elif defined(XR_USE_PLATFORM_WAYLAND) XrGraphicsBindingOpenGLWaylandKHR m_graphicsBinding{XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR}; -#elif defined(XR_USE_PLATFORM_MACOS) -#error OpenGL bindings for Mac have not been implemented #else #error Platform not supported #endif diff --git a/src/tests/list/CMakeLists.txt b/src/tests/list/CMakeLists.txt index 3d743bdb1..cf3846af9 100644 --- a/src/tests/list/CMakeLists.txt +++ b/src/tests/list/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2023, The Khronos Group Inc. +# Copyright (c) 2017 The Khronos Group Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -14,6 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# Author: +# add_executable(openxr_runtime_list list.cpp @@ -33,7 +35,7 @@ if(Vulkan_FOUND) ) endif() -target_link_libraries(openxr_runtime_list OpenXR::openxr_loader) +target_link_libraries(openxr_runtime_list openxr_loader) if(MSVC) target_compile_options(openxr_runtime_list PRIVATE /Zc:wchar_t /Zc:forScope /W4 /WX) endif() diff --git a/src/tests/list_json/CMakeLists.txt b/src/tests/list_json/CMakeLists.txt index b4bed34f7..eb9a3f4b3 100644 --- a/src/tests/list_json/CMakeLists.txt +++ b/src/tests/list_json/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2023, The Khronos Group Inc. +# Copyright (c) 2017 The Khronos Group Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -14,6 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# Author: +# file(GLOB LOCAL_HEADERS "*.h") file(GLOB LOCAL_SOURCE "*.cpp") @@ -22,57 +24,61 @@ file(GLOB LOCAL_SOURCE "*.cpp") include_directories(${CMAKE_CURRENT_BINARY_DIR}) if(ANDROID) - add_library(openxr_runtime_list_json MODULE + add_library(list_json MODULE ${LOCAL_SOURCE} ${LOCAL_HEADERS} $) - target_link_libraries(openxr_runtime_list_json ${ANDROID_LIBRARY} ${ANDROID_LOG_LIBRARY}) - target_include_directories(openxr_runtime_list_json PRIVATE ${ANDROID_NATIVE_APP_GLUE}) + target_link_libraries(list_json ${ANDROID_LIBRARY} ${ANDROID_LOG_LIBRARY}) + target_include_directories(list_json PRIVATE ${ANDROID_NATIVE_APP_GLUE}) else() - add_executable(openxr_runtime_list_json + add_executable(list_json ${LOCAL_SOURCE} ${LOCAL_HEADERS}) endif() -set_target_properties(openxr_runtime_list_json PROPERTIES FOLDER ${TESTS_FOLDER}) +set_target_properties(list_json PROPERTIES FOLDER ${SAMPLES_FOLDER}) source_group("Headers" FILES ${LOCAL_HEADERS}) source_group("Shaders" FILES ${VULKAN_SHADERS}) -target_include_directories(openxr_runtime_list_json +target_include_directories(list_json PRIVATE ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/src/common + + # for OpenXR headers + ${PROJECT_SOURCE_DIR}/include + ${PROJECT_BINARY_DIR}/include ) if(Vulkan_FOUND) - target_include_directories(openxr_runtime_list_json + target_include_directories(list_json PRIVATE ${Vulkan_INCLUDE_DIRS} ) endif() -target_link_libraries(openxr_runtime_list_json OpenXR::openxr_loader) +target_link_libraries(list_json openxr_loader) if(WIN32) if(MSVC) - target_compile_definitions(openxr_runtime_list_json PRIVATE _CRT_SECURE_NO_WARNINGS) - target_compile_options(openxr_runtime_list_json PRIVATE /Zc:wchar_t /Zc:forScope /W4 /WX) + target_compile_definitions(list_json PRIVATE _CRT_SECURE_NO_WARNINGS) + target_compile_options(list_json PRIVATE /Zc:wchar_t /Zc:forScope /W4 /WX) endif() - target_link_libraries(openxr_runtime_list_json ole32) + target_link_libraries(list_json ole32) if(MSVC) # Right now can't build this on MinGW because of directxcolors, etc. - target_link_libraries(openxr_runtime_list_json d3d11 d3d12 d3dcompiler dxgi) + target_link_libraries(list_json d3d11 d3d12 d3dcompiler dxgi) else() - target_compile_definitions(openxr_runtime_list_json PRIVATE MISSING_DIRECTX_COLORS) + target_compile_definitions(list_json PRIVATE MISSING_DIRECTX_COLORS) endif() endif() if(Vulkan_LIBRARY) - target_link_libraries(openxr_runtime_list_json ${Vulkan_LIBRARY}) + target_link_libraries(list_json ${Vulkan_LIBRARY}) endif() if(NOT ANDROID) - install(TARGETS openxr_runtime_list_json + install(TARGETS list_json RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - COMPONENT openxr_runtime_list_json) + COMPONENT list_json) endif() diff --git a/src/tests/list_json/list_json.cpp b/src/tests/list_json/list_json.cpp index a0718f444..78cb007b2 100644 --- a/src/tests/list_json/list_json.cpp +++ b/src/tests/list_json/list_json.cpp @@ -38,9 +38,8 @@ #endif // defined(XR_USE_PLATFORM_ANDROID) // The equivalent of C++17 std::size. A helper to get the dimension for an array. -template -constexpr std::size_t ArraySize(const T (&unused)[Size]) noexcept { - (void)unused; +template +constexpr size_t ArraySize(const T (&/*unused*/)[Size]) noexcept { return Size; } diff --git a/src/tests/loader_test/CMakeLists.txt b/src/tests/loader_test/CMakeLists.txt index bf18db138..667582385 100644 --- a/src/tests/loader_test/CMakeLists.txt +++ b/src/tests/loader_test/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2023, The Khronos Group Inc. +# Copyright (c) 2017 The Khronos Group Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -14,19 +14,20 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# Author: +# add_executable(loader_test loader_test_utils.cpp loader_test.cpp ) openxr_add_filesystem_utils(loader_test) -set_target_properties(loader_test PROPERTIES FOLDER ${LOADER_TESTS_FOLDER}) -target_link_libraries(loader_test PRIVATE OpenXR::openxr_loader) +set_target_properties(loader_test PROPERTIES FOLDER ${TESTS_FOLDER}) +target_link_libraries(loader_test PRIVATE openxr_loader) add_dependencies(loader_test generate_openxr_header XrApiLayer_test - XrApiLayer_api_dump test_runtime ) if(TARGET openxr-gfxwrapper) @@ -52,6 +53,11 @@ if(WIN32) target_compile_options(loader_test PRIVATE /Zc:wchar_t /Zc:forScope /W4 /WX) endif() target_link_libraries(loader_test PRIVATE d3d11) + +elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") + # No special options needed. +else() + message(FATAL_ERROR "Unsupported Platform") endif() file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/resources) diff --git a/src/tests/loader_test/loader_test.cpp b/src/tests/loader_test/loader_test.cpp index 29956ae6d..bf1de9d5f 100644 --- a/src/tests/loader_test/loader_test.cpp +++ b/src/tests/loader_test/loader_test.cpp @@ -209,7 +209,7 @@ void TestEnumLayers(uint32_t& total, uint32_t& passed, uint32_t& skipped, uint32 uint32_t num_valid_jsons = 6; // Point to json directory, contains 6 valid json files - LoaderTestSetEnvironmentVariable("XR_API_LAYER_PATH", "./resources/layers"); + LoaderTestSetEnvironmentVariable("XR_API_LAYER_PATH", "resources/layers"); // LoaderTestSetEnvironmentVariable("XR_ENABLE_API_LAYERS", "XrApiLayer_test:XrApiLayer_test_good_relative_path"); // Test number query @@ -360,7 +360,7 @@ void TestEnumInstanceExtensions(uint32_t& total, uint32_t& passed, uint32_t& ski break; default: subtest_name = "with explicit API layers"; - LoaderTestSetEnvironmentVariable("XR_API_LAYER_PATH", "./resources/layers"); + LoaderTestSetEnvironmentVariable("XR_API_LAYER_PATH", "resources/layers"); LoaderTestSetEnvironmentVariable("XR_ENABLE_API_LAYERS", "XrApiLayer_test"); break; } diff --git a/src/tests/loader_test/loader_test_utils.hpp b/src/tests/loader_test/loader_test_utils.hpp index 60870544e..f854f156b 100644 --- a/src/tests/loader_test/loader_test_utils.hpp +++ b/src/tests/loader_test/loader_test_utils.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017 The Khronos Group Inc. // Copyright (c) 2017 Valve Corporation // Copyright (c) 2017 LunarG, Inc. // diff --git a/src/tests/loader_test/test_layers/CMakeLists.txt b/src/tests/loader_test/test_layers/CMakeLists.txt index d19ee3ada..b4100fc5f 100644 --- a/src/tests/loader_test/test_layers/CMakeLists.txt +++ b/src/tests/loader_test/test_layers/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2023, The Khronos Group Inc. +# Copyright (c) 2017 The Khronos Group Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -14,6 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# Author: +# # Force all compilers to output to binary folder without additional output (like Windows adds "Debug" and "Release" folders) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) @@ -28,13 +30,13 @@ endforeach(OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES) add_library(XrApiLayer_test SHARED layer_test.cpp - XrApiLayer_test.def ) -set_target_properties(XrApiLayer_test PROPERTIES FOLDER ${LOADER_TESTS_FOLDER}) +set_target_properties(XrApiLayer_test PROPERTIES FOLDER ${TESTS_FOLDER}) add_dependencies(XrApiLayer_test xr_global_generated_files generate_openxr_header + generated_layer_json_files ) target_include_directories(XrApiLayer_test PRIVATE ${PROJECT_SOURCE_DIR}/src @@ -52,20 +54,34 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows") # Turn off transitional "changed behavior" warning message for Visual Studio versions prior to 2015. # The changed behavior is that constructor initializers are now fixed to clear the struct members. target_compile_options(XrApiLayer_test PRIVATE "$<$,$,19>>:/wd4351>") + gen_xr_layer_json( + ${PROJECT_BINARY_DIR}/src/tests/loader_test/resources/layers/XrApiLayer_test.json + test + ${CMAKE_CURRENT_BINARY_DIR}/XrApiLayer_test.dll + 1 + Test_description + -b + ) + FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/XrApiLayer_test.def DEF_FILE) + add_custom_target(copy-test-def-file ALL + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DEF_FILE} ${CMAKE_CURRENT_BINARY_DIR}/XrApiLayer_test.def + VERBATIM + ) + set_target_properties(copy-test-def-file PROPERTIES FOLDER ${HELPER_FOLDER}) elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") set_target_properties(XrApiLayer_test PROPERTIES LINK_FLAGS "-Wl,-Bsymbolic,--exclude-libs,ALL") -elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - set_target_properties(XrApiLayer_test PROPERTIES LINK_FLAGS "-Wl,-exported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/XrApiLayer_test.expsym") + gen_xr_layer_json( + ${PROJECT_BINARY_DIR}/src/tests/loader_test/resources/layers/XrApiLayer_test.json + test + ${CMAKE_CURRENT_BINARY_DIR}/libXrApiLayer_test.so + 1 + Test_description + -b + ) endif() -gen_xr_layer_json( +add_custom_target(generated_layer_json_files DEPENDS ${PROJECT_BINARY_DIR}/src/tests/loader_test/resources/layers/XrApiLayer_test.json - test - ${CMAKE_CURRENT_BINARY_DIR}/$ - 1 - Test_description - -b ) +set_target_properties(generated_layer_json_files PROPERTIES FOLDER ${CODEGEN_FOLDER}) -# Add generated file to our sources so we depend on it, and thus trigger generation. -target_sources(XrApiLayer_test PRIVATE ${PROJECT_BINARY_DIR}/src/tests/loader_test/resources/layers/XrApiLayer_test.json) diff --git a/src/tests/loader_test/test_layers/XrApiLayer_test.def b/src/tests/loader_test/test_layers/XrApiLayer_test.def index 16cfc9fb1..3a63931ed 100644 --- a/src/tests/loader_test/test_layers/XrApiLayer_test.def +++ b/src/tests/loader_test/test_layers/XrApiLayer_test.def @@ -1,7 +1,7 @@ ;;;; Begin Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; -; Copyright (c) 2017-2023, The Khronos Group Inc. +; Copyright (c) 2017 The Khronos Group Inc. ; Copyright (c) 2017 Valve Corporation ; Copyright (c) 2017 LunarG, Inc. ; @@ -26,8 +26,4 @@ LIBRARY XrApiLayer_test EXPORTS xrNegotiateLoaderApiLayerInterface -TestLayerAlwaysFailNegotiateLoaderApiLayerInterface -TestLayerNullGipaNegotiateLoaderApiLayerInterface -TestLayerInvalidInterfaceNegotiateLoaderApiLayerInterface -TestLayerInvalidApiNegotiateLoaderApiLayerInterface diff --git a/src/tests/loader_test/test_layers/XrApiLayer_test.expsym b/src/tests/loader_test/test_layers/XrApiLayer_test.expsym deleted file mode 100644 index 532325b63..000000000 --- a/src/tests/loader_test/test_layers/XrApiLayer_test.expsym +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2019-2023, The Khronos Group Inc. -# -# SPDX-License-Identifier: Apache-2.0 - -_xrNegotiateLoaderApiLayerInterface -_TestLayerAlwaysFailNegotiateLoaderApiLayerInterface -_TestLayerNullGipaNegotiateLoaderApiLayerInterface -_TestLayerInvalidInterfaceNegotiateLoaderApiLayerInterface -_TestLayerInvalidApiNegotiateLoaderApiLayerInterface diff --git a/src/tests/loader_test/test_layers/layer_test.cpp b/src/tests/loader_test/test_layers/layer_test.cpp index 535a52db9..2f8131c72 100644 --- a/src/tests/loader_test/test_layers/layer_test.cpp +++ b/src/tests/loader_test/test_layers/layer_test.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017 The Khronos Group Inc. // Copyright (c) 2017 Valve Corporation // Copyright (c) 2017 LunarG, Inc. // @@ -36,15 +36,15 @@ #define LAYER_EXPORT __declspec(dllexport) #endif +extern "C" { std::map g_next_gipa_map; -static XRAPI_ATTR XrResult XRAPI_CALL LayerTestXrCreateInstance(const XrInstanceCreateInfo * /* info */, - XrInstance * /* instance */) { +XRAPI_ATTR XrResult XRAPI_CALL LayerTestXrCreateInstance(const XrInstanceCreateInfo * /* info */, XrInstance * /* instance */) { // In a layer, LayerTestXrCreateApiLayerInstance is called instead of this function. This should not be called. return XR_ERROR_FUNCTION_UNSUPPORTED; } -static XRAPI_ATTR XrResult XRAPI_CALL LayerTestXrDestroyInstance(XrInstance instance) { +XRAPI_ATTR XrResult XRAPI_CALL LayerTestXrDestroyInstance(XrInstance instance) { // Call down to the next xrDestroyInstance. PFN_xrVoidFunction nextDestroyInstance{nullptr}; XrResult res = g_next_gipa_map[instance](instance, "xrDestroyInstance", &nextDestroyInstance); @@ -59,8 +59,7 @@ static XRAPI_ATTR XrResult XRAPI_CALL LayerTestXrDestroyInstance(XrInstance inst return res; } -static XRAPI_ATTR XrResult XRAPI_CALL LayerTestXrGetInstanceProcAddr(XrInstance instance, const char *name, - PFN_xrVoidFunction *function) { +XRAPI_ATTR XrResult XRAPI_CALL LayerTestXrGetInstanceProcAddr(XrInstance instance, const char *name, PFN_xrVoidFunction *function) { if (0 == strcmp(name, "xrGetInstanceProcAddr")) { *function = reinterpret_cast(LayerTestXrGetInstanceProcAddr); } else if (0 == strcmp(name, "xrCreateInstance")) { @@ -84,9 +83,8 @@ static XRAPI_ATTR XrResult XRAPI_CALL LayerTestXrGetInstanceProcAddr(XrInstance return it->second(instance, name, function); } -static XRAPI_ATTR XrResult XRAPI_CALL LayerTestXrCreateApiLayerInstance(const XrInstanceCreateInfo *info, - const XrApiLayerCreateInfo *apiLayerInfo, - XrInstance *instance) { +XRAPI_ATTR XrResult XRAPI_CALL LayerTestXrCreateApiLayerInstance(const XrInstanceCreateInfo *info, + const XrApiLayerCreateInfo *apiLayerInfo, XrInstance *instance) { // Call down to the next layer's xrCreateApiLayerInstance. // Clone the XrApiLayerCreateInfo, but move to the next XrApiLayerNextInfo in the chain. nextInfo will be null // if the loader's terminator function is going to be called (between the layer and the runtime) but this is OK @@ -104,13 +102,10 @@ static XRAPI_ATTR XrResult XRAPI_CALL LayerTestXrCreateApiLayerInstance(const Xr return XR_SUCCESS; } -extern "C" { - // Function used to negotiate an interface betewen the loader and a layer. Each library exposing one or // more layers needs to expose at least this function. -LAYER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrNegotiateLoaderApiLayerInterface(const XrNegotiateLoaderInfo *loaderInfo, - const char *layerName, - XrNegotiateApiLayerRequest *layerRequest) { +LAYER_EXPORT XrResult XRAPI_CALL xrNegotiateLoaderApiLayerInterface(const XrNegotiateLoaderInfo *loaderInfo, const char *layerName, + XrNegotiateApiLayerRequest *layerRequest) { if (nullptr == loaderInfo || nullptr == layerRequest || loaderInfo->structType != XR_LOADER_INTERFACE_STRUCT_LOADER_INFO || loaderInfo->structVersion != XR_LOADER_INFO_STRUCT_VERSION || loaderInfo->structSize != sizeof(XrNegotiateLoaderInfo) || layerRequest->structType != XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST || @@ -132,14 +127,16 @@ LAYER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrNegotiateLoaderApiLayerInterface(c } // Always fail -LAYER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL TestLayerAlwaysFailNegotiateLoaderApiLayerInterface( - const XrNegotiateLoaderInfo * /* loaderInfo */, const char * /* layerName */, XrNegotiateApiLayerRequest * /* layerRequest */) { +LAYER_EXPORT XrResult TestlayerAlwaysFailNegotiateLoaderApiLayerInterface(const XrNegotiateLoaderInfo * /* loaderInfo */, + const char * /* layerName */, + XrNegotiateApiLayerRequest * /* layerRequest */) { return XR_ERROR_INITIALIZATION_FAILED; } // Pass, but return NULL for the layer's xrGetInstanceProcAddr -LAYER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL TestLayerNullGipaNegotiateLoaderApiLayerInterface( - const XrNegotiateLoaderInfo *loaderInfo, const char *layerName, XrNegotiateApiLayerRequest *layerRequest) { +LAYER_EXPORT XrResult TestLayerNullGipaNegotiateLoaderApiLayerInterface(const XrNegotiateLoaderInfo *loaderInfo, + const char *layerName, + XrNegotiateApiLayerRequest *layerRequest) { if (nullptr == loaderInfo || nullptr == layerRequest || loaderInfo->structType != XR_LOADER_INTERFACE_STRUCT_LOADER_INFO || loaderInfo->structVersion != XR_LOADER_INFO_STRUCT_VERSION || loaderInfo->structSize != sizeof(XrNegotiateLoaderInfo) || layerRequest->structType != XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST || @@ -159,8 +156,9 @@ LAYER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL TestLayerNullGipaNegotiateLoaderApiL } // Pass, but return invalid interface version -LAYER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL TestLayerInvalidInterfaceNegotiateLoaderApiLayerInterface( - const XrNegotiateLoaderInfo *loaderInfo, const char *layerName, XrNegotiateApiLayerRequest *layerRequest) { +LAYER_EXPORT XrResult TestLayerInvalidInterfaceNegotiateLoaderApiLayerInterface(const XrNegotiateLoaderInfo *loaderInfo, + const char *layerName, + XrNegotiateApiLayerRequest *layerRequest) { if (nullptr == loaderInfo || nullptr == layerRequest || loaderInfo->structType != XR_LOADER_INTERFACE_STRUCT_LOADER_INFO || loaderInfo->structVersion != XR_LOADER_INFO_STRUCT_VERSION || loaderInfo->structSize != sizeof(XrNegotiateLoaderInfo) || layerRequest->structType != XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST || @@ -174,14 +172,15 @@ LAYER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL TestLayerInvalidInterfaceNegotiateLo (void)layerName; layerRequest->layerInterfaceVersion = 0; layerRequest->layerApiVersion = XR_MAKE_VERSION(0, 1, 0); - layerRequest->getInstanceProcAddr = LayerTestXrGetInstanceProcAddr; + layerRequest->getInstanceProcAddr = reinterpret_cast(LayerTestXrGetInstanceProcAddr); return XR_SUCCESS; } // Pass, but return invalid API version -LAYER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL TestLayerInvalidApiNegotiateLoaderApiLayerInterface( - const XrNegotiateLoaderInfo *loaderInfo, const char *layerName, XrNegotiateApiLayerRequest *layerRequest) { +LAYER_EXPORT XrResult TestLayerInvalidApiNegotiateLoaderApiLayerInterface(const XrNegotiateLoaderInfo *loaderInfo, + const char *layerName, + XrNegotiateApiLayerRequest *layerRequest) { if (nullptr == loaderInfo || nullptr == layerRequest || loaderInfo->structType != XR_LOADER_INTERFACE_STRUCT_LOADER_INFO || loaderInfo->structVersion != XR_LOADER_INFO_STRUCT_VERSION || loaderInfo->structSize != sizeof(XrNegotiateLoaderInfo) || layerRequest->structType != XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST || @@ -195,7 +194,7 @@ LAYER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL TestLayerInvalidApiNegotiateLoaderAp (void)layerName; layerRequest->layerInterfaceVersion = XR_CURRENT_LOADER_API_LAYER_VERSION; layerRequest->layerApiVersion = 0; - layerRequest->getInstanceProcAddr = LayerTestXrGetInstanceProcAddr; + layerRequest->getInstanceProcAddr = reinterpret_cast(LayerTestXrGetInstanceProcAddr); return XR_SUCCESS; } diff --git a/src/tests/loader_test/test_runtimes/CMakeLists.txt b/src/tests/loader_test/test_runtimes/CMakeLists.txt index 06bed7339..43d7a43ac 100644 --- a/src/tests/loader_test/test_runtimes/CMakeLists.txt +++ b/src/tests/loader_test/test_runtimes/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2017-2023, The Khronos Group Inc. +# Copyright (c) 2017 The Khronos Group Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -14,6 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# Author: +# # Force all compilers to output to binary folder without additional output (like Windows adds "Debug" and "Release" folders) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) @@ -28,9 +30,8 @@ endforeach(OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES) add_library(test_runtime SHARED runtime_test.cpp - test_runtime.def ) -set_target_properties(test_runtime PROPERTIES FOLDER ${LOADER_TESTS_FOLDER}) +set_target_properties(test_runtime PROPERTIES FOLDER ${TESTS_FOLDER}) add_dependencies(test_runtime xr_global_generated_files @@ -64,17 +65,25 @@ if(WIN32) # Turn off transitional "changed behavior" warning message for Visual Studio versions prior to 2015. # The changed behavior is that constructor initializers are now fixed to clear the struct members. target_compile_options(test_runtime PRIVATE "$<$,$,19>>:/wd4351>") + gen_xr_runtime_json( + ${PROJECT_BINARY_DIR}/src/tests/loader_test/resources/runtimes/test_runtime.json + ${CMAKE_CURRENT_BINARY_DIR}/test_runtime.dll + -b + ) + FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/test_runtime.def DEF_FILE) + add_custom_target(copy-test_runtime-def-file ALL + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DEF_FILE} ${CMAKE_CURRENT_BINARY_DIR}/test_runtime.def + VERBATIM + ) + set_target_properties(copy-test_runtime-def-file PROPERTIES FOLDER ${HELPER_FOLDER}) elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") set_target_properties(test_runtime PROPERTIES LINK_FLAGS "-Wl,-Bsymbolic,--exclude-libs,ALL") -elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - set_target_properties(test_runtime PROPERTIES LINK_FLAGS "-Wl,-exported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/test_runtime.expsym") + gen_xr_runtime_json( + ${PROJECT_BINARY_DIR}/src/tests/loader_test/resources/runtimes/test_runtime.json + ${CMAKE_CURRENT_BINARY_DIR}/libtest_runtime.so + -b + ) endif() -gen_xr_runtime_json( - ${PROJECT_BINARY_DIR}/src/tests/loader_test/resources/runtimes/test_runtime.json - ${CMAKE_CURRENT_BINARY_DIR}/$ - -b -) - # Add generated file to our sources so we depend on it, and thus trigger generation. target_sources(test_runtime PRIVATE ${PROJECT_BINARY_DIR}/src/tests/loader_test/resources/runtimes/test_runtime.json) diff --git a/src/tests/loader_test/test_runtimes/runtime_test.cpp b/src/tests/loader_test/test_runtimes/runtime_test.cpp index 03be08966..7b30e63cb 100644 --- a/src/tests/loader_test/test_runtimes/runtime_test.cpp +++ b/src/tests/loader_test/test_runtimes/runtime_test.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, The Khronos Group Inc. +// Copyright (c) 2017 The Khronos Group Inc. // Copyright (c) 2017 Valve Corporation // Copyright (c) 2017 LunarG, Inc. // @@ -35,17 +35,19 @@ #define RUNTIME_EXPORT #endif -static XRAPI_ATTR XrResult XRAPI_CALL RuntimeTestXrCreateInstance(const XrInstanceCreateInfo * /* info */, XrInstance *instance) { +extern "C" { + +XRAPI_ATTR XrResult XRAPI_CALL RuntimeTestXrCreateInstance(const XrInstanceCreateInfo * /* info */, XrInstance *instance) { *instance = (XrInstance)1; return XR_SUCCESS; } -static XRAPI_ATTR XrResult XRAPI_CALL RuntimeTestXrDestroyInstance(XrInstance /* instance */) { return XR_SUCCESS; } +XRAPI_ATTR XrResult XRAPI_CALL RuntimeTestXrDestroyInstance(XrInstance /* instance */) { return XR_SUCCESS; } -static XRAPI_ATTR XrResult XRAPI_CALL RuntimeTestXrEnumerateInstanceExtensionProperties(const char *layerName, - uint32_t propertyCapacityInput, - uint32_t *propertyCountOutput, - XrExtensionProperties *properties) { +XRAPI_ATTR XrResult XRAPI_CALL RuntimeTestXrEnumerateInstanceExtensionProperties(const char *layerName, + uint32_t propertyCapacityInput, + uint32_t *propertyCountOutput, + XrExtensionProperties *properties) { if (nullptr != layerName) { return XR_ERROR_API_LAYER_NOT_PRESENT; } @@ -60,8 +62,8 @@ static XRAPI_ATTR XrResult XRAPI_CALL RuntimeTestXrEnumerateInstanceExtensionPro return XR_SUCCESS; } -static XRAPI_ATTR XrResult XRAPI_CALL RuntimeTestXrGetSystem(XrInstance instance, const XrSystemGetInfo * /* getInfo */, - XrSystemId *systemId) { +XRAPI_ATTR XrResult XRAPI_CALL RuntimeTestXrGetSystem(XrInstance instance, const XrSystemGetInfo * /* getInfo */, + XrSystemId *systemId) { if (instance == XR_NULL_HANDLE) { return XR_ERROR_HANDLE_INVALID; } @@ -69,8 +71,8 @@ static XRAPI_ATTR XrResult XRAPI_CALL RuntimeTestXrGetSystem(XrInstance instance return XR_SUCCESS; } -static XRAPI_ATTR XrResult XRAPI_CALL RuntimeTestXrGetSystemProperties(XrInstance instance, XrSystemId systemId, - XrSystemProperties *properties) { +XRAPI_ATTR XrResult XRAPI_CALL RuntimeTestXrGetSystemProperties(XrInstance instance, XrSystemId systemId, + XrSystemProperties *properties) { if (instance == XR_NULL_HANDLE) { return XR_ERROR_HANDLE_INVALID; } @@ -86,8 +88,8 @@ static XRAPI_ATTR XrResult XRAPI_CALL RuntimeTestXrGetSystemProperties(XrInstanc return XR_SUCCESS; } -static XRAPI_ATTR XrResult XRAPI_CALL RuntimeTestXrGetInstanceProcAddr(XrInstance instance, const char *name, - PFN_xrVoidFunction *function) { +XRAPI_ATTR XrResult XRAPI_CALL RuntimeTestXrGetInstanceProcAddr(XrInstance instance, const char *name, + PFN_xrVoidFunction *function) { if (0 == strcmp(name, "xrGetInstanceProcAddr")) { *function = reinterpret_cast(RuntimeTestXrGetInstanceProcAddr); } else if (0 == strcmp(name, "xrEnumerateInstanceExtensionProperties")) { @@ -111,8 +113,6 @@ static XRAPI_ATTR XrResult XRAPI_CALL RuntimeTestXrGetInstanceProcAddr(XrInstanc return *function ? XR_SUCCESS : XR_ERROR_FUNCTION_UNSUPPORTED; } -extern "C" { - // Function used to negotiate an interface betewen the loader and a runtime. RUNTIME_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrNegotiateLoaderRuntimeInterface(const XrNegotiateLoaderInfo *loaderInfo, XrNegotiateRuntimeRequest *runtimeRequest) { @@ -129,7 +129,7 @@ RUNTIME_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrNegotiateLoaderRuntimeInterface( runtimeRequest->runtimeInterfaceVersion = XR_CURRENT_LOADER_RUNTIME_VERSION; runtimeRequest->runtimeApiVersion = XR_CURRENT_API_VERSION; - runtimeRequest->getInstanceProcAddr = RuntimeTestXrGetInstanceProcAddr; + runtimeRequest->getInstanceProcAddr = reinterpret_cast(RuntimeTestXrGetInstanceProcAddr); return XR_SUCCESS; } diff --git a/src/tests/loader_test/test_runtimes/test_runtime.def b/src/tests/loader_test/test_runtimes/test_runtime.def index 099a07464..3474cd812 100644 --- a/src/tests/loader_test/test_runtimes/test_runtime.def +++ b/src/tests/loader_test/test_runtimes/test_runtime.def @@ -1,7 +1,7 @@ ;;;; Begin Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; -; Copyright (c) 2017-2023, The Khronos Group Inc. +; Copyright (c) 2017 The Khronos Group Inc. ; Copyright (c) 2017 Valve Corporation ; Copyright (c) 2017 LunarG, Inc. ; @@ -26,8 +26,4 @@ LIBRARY test_runtime EXPORTS xrNegotiateLoaderRuntimeInterface -TestRuntimeAlwaysFailNegotiateLoaderRuntimeInterface -TestRuntimeNullGipaNegotiateLoaderRuntimeInterface -TestRuntimeInvalidInterfaceNegotiateLoaderRuntimeInterface -TestRuntimeInvalidApiNegotiateLoaderRuntimeInterface diff --git a/src/tests/loader_test/test_runtimes/test_runtime.expsym b/src/tests/loader_test/test_runtimes/test_runtime.expsym deleted file mode 100644 index fdcb2a70c..000000000 --- a/src/tests/loader_test/test_runtimes/test_runtime.expsym +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2019-2023, The Khronos Group Inc. -# -# SPDX-License-Identifier: Apache-2.0 - -_xrNegotiateLoaderRuntimeInterface -_TestRuntimeAlwaysFailNegotiateLoaderRuntimeInterface -_TestRuntimeNullGipaNegotiateLoaderRuntimeInterface -_TestRuntimeInvalidInterfaceNegotiateLoaderRuntimeInterface -_TestRuntimeInvalidApiNegotiateLoaderRuntimeInterface diff --git a/src/version.cmake b/src/version.cmake index 5e64c70d2..d863918df 100644 --- a/src/version.cmake +++ b/src/version.cmake @@ -18,45 +18,26 @@ set(MAJOR "0") set(MINOR "0") set(PATCH "0") -set(OPENXR_SDK_HOTFIX_VERSION) if(EXISTS "${PROJECT_SOURCE_DIR}/specification/registry/xr.xml") - file(STRINGS ${PROJECT_SOURCE_DIR}/specification/registry/xr.xml lines REGEX "#define XR_CURRENT_API_VERSION") + file(STRINGS ${PROJECT_SOURCE_DIR}/specification/registry/xr.xml lines REGEX "#define XR_CURRENT_API_VERSION") else() - file(STRINGS ${PROJECT_SOURCE_DIR}/include/openxr/openxr.h lines REGEX "#define XR_CURRENT_API_VERSION") + file(STRINGS ${PROJECT_SOURCE_DIR}/include/openxr/openxr.h lines REGEX "#define XR_CURRENT_API_VERSION") endif() - list(LENGTH lines len) if(${len} EQUAL 1) list(GET lines 0 cur_line) - - # Grab just the stuff in the parentheses of XR_MAKE_VERSION( ), - # by replacing the whole line with the stuff in the parentheses - string(REGEX REPLACE "^.+\\(([^\)]+)\\).+$" "\\1" VERSION_WITH_WHITESPACE ${cur_line}) - - # Remove whitespace - string(REPLACE " " "" VERSION_NO_WHITESPACE ${VERSION_WITH_WHITESPACE}) - - # Grab components - string(REGEX REPLACE "^([0-9]+)\\,[0-9]+\\,[0-9]+" "\\1" MAJOR "${VERSION_NO_WHITESPACE}") - string(REGEX REPLACE "^[0-9]+\\,([0-9]+)\\,[0-9]+" "\\1" MINOR "${VERSION_NO_WHITESPACE}") - string(REGEX REPLACE "^[0-9]+\\,[0-9]+\\,([0-9]+)" "\\1" PATCH "${VERSION_NO_WHITESPACE}") + # Erase everything up to the open parentheses + string(REGEX REPLACE "^[^\(]+" "" VERSION_BEFORE_ERASED ${cur_line}) + # Erase everything after the close parentheses + string(REGEX REPLACE "[^\)]+$" "" VERSION_AFTER_ERASED ${VERSION_BEFORE_ERASED}) + # Erase the parentheses + string(REPLACE "(" "" VERSION_AFTER_ERASED2 ${VERSION_AFTER_ERASED}) + string(REPLACE ")" "" VERSION_AFTER_ERASED3 ${VERSION_AFTER_ERASED2}) + string(REPLACE " " "" VERSION_AFTER_ERASED4 ${VERSION_AFTER_ERASED3}) + string(REGEX REPLACE "^([0-9]+)\\,[0-9]+\\,[0-9]+" "\\1" MAJOR "${VERSION_AFTER_ERASED4}") + string(REGEX REPLACE "^[0-9]+\\,([0-9]+)\\,[0-9]+" "\\1" MINOR "${VERSION_AFTER_ERASED4}") + string(REGEX REPLACE "^[0-9]+\\,[0-9]+\\,([0-9]+)" "\\1" PATCH "${VERSION_AFTER_ERASED4}") else() - message(FATAL_ERROR "Unable to fetch major/minor/patch version from registry or header") -endif() - -# Check for an SDK hotfix version indicator file. -if(EXISTS "${PROJECT_SOURCE_DIR}/HOTFIX") - file(STRINGS "${PROJECT_SOURCE_DIR}/HOTFIX" OPENXR_SDK_HOTFIX_VERSION) -endif() -if(OPENXR_SDK_HOTFIX_VERSION) - set(OPENXR_SDK_HOTFIX_VERSION_SUFFIX ".${OPENXR_SDK_HOTFIX_VERSION}") -endif() - -set(OPENXR_VERSION "${MAJOR}.${MINOR}.${PATCH}") -set(OPENXR_FULL_VERSION "${OPENXR_VERSION}${OPENXR_SDK_HOTFIX_VERSION_SUFFIX}") - -if(PROJECT_NAME STREQUAL "OPENXR") - # Only show the message if we aren't a subproject - message(STATUS "OpenXR ${OPENXR_FULL_VERSION}") + message(FATAL_ERROR "Unable to fetch major/minor version from registry or header") endif() diff --git a/src/version.gradle b/src/version.gradle index bd2aa6589..32cf7bf3d 100644 --- a/src/version.gradle +++ b/src/version.gradle @@ -6,8 +6,6 @@ class OpenXRVersion { public int major; public int minor; public int patch; - public boolean hasHotfix; - public int hotfix; /// Returns a version code for Android usage. int getVersionCode() { @@ -19,22 +17,17 @@ class OpenXRVersion { @Override String toString() { - if (hasHotfix) { - "${major}.${minor}.${patch}.${hotfix}" - } else { - "${major}.${minor}.${patch}" - } + "${major}.${minor}.${patch}" } /** * Parses the registry (as a text file) or the openxr.h header to get the version. * @param project Gradle project - * @param registryOrHeaderFile registry or header File - * @param hotfixFile HOTFIX File + * @param fn registry or header filename * @return version parsed */ - static def parseOpenXRVersionFile(def registryOrHeaderFile, def hotfixFile) { - def matches = registryOrHeaderFile.readLines().find { + static def parseOpenXRVersionFile(Project project, def fn) { + def matches = project.file(fn).readLines().find { it.contains('XR_CURRENT_API_VERSION') } =~ ~/\(([^\)]+)\)/ def components = matches[0][1].split(',').collect { it.replace(' ', '').trim() } @@ -42,11 +35,6 @@ class OpenXRVersion { version.major = Integer.parseInt(components[0]) version.minor = Integer.parseInt(components[1]) version.patch = Integer.parseInt(components[2]) - - if (hotfixFile.exists()) { - version.hasHotfix = true - version.hotfix = Integer.parseInt(hotfixFile.text.trim()) - } version } } @@ -54,10 +42,8 @@ class OpenXRVersion { class OpenXRVersionPlugin implements Plugin { void apply(Project project) { - def registryFile = project.file("${project.repoRoot}/specification/registry/xr.xml") - def hotfixFile = project.file("${project.repoRoot}/HOTFIX") - - project.ext.versionOpenXR = OpenXRVersion.parseOpenXRVersionFile(registryFile, hotfixFile) + project.ext.versionOpenXR = OpenXRVersion.parseOpenXRVersionFile(project, + "${project.repoRoot}/specification/registry/xr.xml") project.group = "org.khronos.openxr" if (project.file("${project.repoRoot}/SNAPSHOT").exists()) {