diff --git a/.github/actions/coverage-ci/action.yml b/.github/actions/coverage-ci/action.yml index 69e3ea2e39..1151cdc31b 100644 --- a/.github/actions/coverage-ci/action.yml +++ b/.github/actions/coverage-ci/action.yml @@ -28,10 +28,19 @@ runs: lfs_sha: ${{inputs.lfs_sha}} cache_postfix: cache-0 + # Python is needed in case Mesa must be built + - name: Extract python version + id: python_ver + uses: f3d-app/extract-version-action@main + with: + file: ${{inputs.versions_file}} + name: python + - name: Install all F3D dependencies uses: ./source/.github/actions/generic-dependencies with: versions_file: ${{inputs.versions_file}} + python_version: ${{steps.python_ver.outputs.extract}} - name: Install VTK dependency uses: ./source/.github/actions/vtk-install-dep diff --git a/.github/actions/f3d-dependencies/action.yml b/.github/actions/f3d-dependencies/action.yml index 7261c4a51e..a64312b802 100644 --- a/.github/actions/f3d-dependencies/action.yml +++ b/.github/actions/f3d-dependencies/action.yml @@ -16,6 +16,20 @@ inputs: runs: using: "composite" steps: + - name: Install LLVM dependency + uses: ./source/.github/actions/llvm-install-dep + with: + versions_file: ${{inputs.versions_file}} + mindeps_label: ${{inputs.mindeps_label}} + cpu: ${{inputs.cpu}} + + - name: Install MESA + uses: ./source/.github/actions/mesa-install-dep + with: + versions_file: ${{inputs.versions_file}} + mindeps_label: ${{inputs.mindeps_label}} + cpu: ${{inputs.cpu}} + - name: Install OCCT dependency uses: ./source/.github/actions/occt-install-dep with: diff --git a/.github/actions/generic-ci/action.yml b/.github/actions/generic-ci/action.yml index 12fcb4f0bf..5e7f571858 100644 --- a/.github/actions/generic-ci/action.yml +++ b/.github/actions/generic-ci/action.yml @@ -60,6 +60,14 @@ runs: lfs_sha: ${{inputs.lfs_sha}} cache_postfix: cache-0 + - name: Extract python version + id: python_ver + uses: f3d-app/extract-version-action@main + with: + file: ${{inputs.versions_file}} + name: python + minver_label: ${{inputs.mindeps_label == 'mindeps' && 'minver' || ''}} + - name: Install all F3D dependencies uses: ./source/.github/actions/generic-dependencies with: @@ -67,6 +75,7 @@ runs: optdeps_label: ${{inputs.optdeps_label}} mindeps_label: ${{inputs.mindeps_label}} cpu: ${{inputs.cpu}} + python_version: ${{steps.python_ver.outputs.extract}} - name: Install VTK dependency uses: ./source/.github/actions/vtk-install-dep @@ -77,26 +86,11 @@ runs: cpu: ${{inputs.cpu}} vtk_version: ${{inputs.vtk_version}} - - name: Extract python version - id: python_ver - uses: f3d-app/extract-version-action@main - with: - file: ${{inputs.versions_file}} - name: python - minver_label: ${{inputs.mindeps_label == 'mindeps' && 'minver' || ''}} - - - name: Set up Python - if: inputs.optdeps_label == 'optdeps' - uses: actions/setup-python@v6 - with: - python-version: ${{steps.python_ver.outputs.extract}} - # numpy pinned to 2.2.X until python 3.10 support is dropped - name: Install Python dependencies if: inputs.optdeps_label == 'optdeps' shell: bash run: | - python -m pip install --upgrade pip python -m pip install pytest==9.0.3 python -m pip install pybind11_stubgen python -m pip install numpy==2.2.6 @@ -130,7 +124,7 @@ runs: working-directory: ${{github.workspace}} run: echo "PATH=$env:PATH;$(pwd)\dependencies\install\bin\;$(pwd)\dependencies\install\lib\;$(pwd)\install\bin\;"| Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - name: Set DYLD_LIBRARY_PATH on macOS for OSPRay dynamic loading + - name: Set DYLD_LIBRARY_PATH on macOS for OSPRay/OSMesa dynamic loading if: | runner.os == 'macOS' && inputs.optdeps_label == 'optdeps' @@ -195,13 +189,14 @@ runs: -DF3D_PLUGIN_BUILD_VDB=${{ inputs.optdeps_label == 'optdeps' && 'ON' || 'OFF' }} -DF3D_PLUGIN_OCCT_COLORING_SUPPORT=${{ inputs.mindeps_label != 'mindeps' && 'ON' || 'OFF' }} -DF3D_STRICT_BUILD=ON + -DF3D_TESTING_ENABLE_WGL_TESTS=${{ runner.os == 'Windows' && 'ON' || 'OFF' }} -DF3D_TESTING_ENABLE_EGL_TESTS=${{ runner.os == 'Linux' && 'ON' || 'OFF' }} -DF3D_TESTING_ENABLE_EXTERNAL_GLFW=${{ (runner.os == 'Linux' && inputs.rendering_backend == 'auto') && 'ON' || 'OFF' }} -DF3D_TESTING_ENABLE_EXTERNAL_QT=${{ (runner.os == 'Linux' && inputs.rendering_backend == 'auto') && 'ON' || 'OFF' }} -DF3D_TESTING_ENABLE_ILLUSTRATION_TESTS=${{ (runner.os == 'Linux' && inputs.vtk_version == 'commit' && inputs.build_type == 'standard') && 'ON' || 'OFF' }} -DF3D_TESTING_ENABLE_GLX_TESTS=${{ (runner.os == 'Linux' && inputs.rendering_backend == 'auto') && 'ON' || 'OFF' }} -DF3D_TESTING_ENABLE_LONG_TIMEOUT_TESTS=${{ (runner.os == 'Linux' || runner.os == 'Windows') && 'ON' || 'OFF' }} - -DF3D_TESTING_ENABLE_OSMESA_TESTS=${{ runner.os == 'Linux' && 'ON' || 'OFF' }} + -DF3D_TESTING_ENABLE_OSMESA_TESTS=ON -DF3D_TESTING_DISABLE_CATCH_ALL=ON -DF3D_TESTING_FORCE_RENDERING_BACKEND=${{ inputs.rendering_backend }} -DF3D_WINDOWS_BUILD_CONSOLE_APPLICATION=ON @@ -220,52 +215,37 @@ runs: shell: bash run: Xvfb $DISPLAY -screen 0 1280x1024x24 & + # We install a proper WGL Mesa driver for regular tests + # This is needed because F3D_TESTING_ENABLE_WGL_TESTS options is enabled - name: Install Mesa Windows if: runner.os == 'Windows' uses: f3d-app/install-mesa-windows-action@v2 with: path: ${{github.workspace}}\build\bin_Release - - name: Install Mesa Windows Python - if: runner.os == 'Windows' - uses: f3d-app/install-mesa-windows-action@v2 - with: - path: ${{github.workspace}}\build\Release\f3d - - # A EGL test is crashing in the CI but not locally - - name: Set CI test exception for Linux EGL - if: runner.os == 'Linux' && - inputs.rendering_backend != 'auto' - shell: bash - run: echo "F3D_CTEST_EXCEPTIONS=(TestSDKExternalWindowEGL)" >> $GITHUB_ENV - # numpy makes pytest crashing on Windows in the CI but not locally, skipping for now - name: Set CI test exception for Windows if: runner.os == 'Windows' shell: bash run: echo "F3D_CTEST_EXCEPTIONS=(test_scene_zero_copy)" >> $GITHUB_ENV - # Certain tests are failing on macOS with GPU pass through - # https://github.com/f3d-app/f3d/issues/792 - # https://github.com/f3d-app/f3d/issues/1534 - # https://github.com/f3d-app/f3d/issues/2268 - # https://github.com/f3d-app/f3d/issues/3047 + # Certain tests are failing on macOS software rendering + # OSMesa is used for VTK > 9.6, remove when it's dropped - name: Set CI test exception for macOS x86_64 if: | runner.os == 'macOS' && - inputs.cpu == 'x86_64' + inputs.cpu == 'x86_64' && + inputs.rendering_backend == 'auto' shell: bash run: echo "F3D_CTEST_EXCEPTIONS=(TestDXF)|(TestPipedDXF)|(TestScalarsCell)|(TestXCAFColors)|(TestInteractionAnimationSlow)|(TestInteractionFocalPointPickingPoints)|(TestInteractionCycleAnimation)|(TestInteractionCycleComp)|(TestGLTFRigArmature)|(TestInteractionNoModelScrollWheel)|(TestInteractionNoModelScrollBar)|(TestInteractionTAA)|(TestInteractionPointCloudTAA)|(TestInteractionStochasticTAA)" >> $GITHUB_ENV - # Certain tests are failing on macOS arm64 for unknown reasons - # https://github.com/f3d-app/f3d/issues/1276 - # https://github.com/f3d-app/f3d/issues/792 - # https://github.com/f3d-app/f3d/issues/1534 - # https://github.com/f3d-app/f3d/issues/3047 + # Certain tests are failing on macOS software rendering + # OSMesa is used for VTK > 9.6, remove when it's dropped - name: Set CI test exception for macOS arm64 if: | runner.os == 'macOS' && - inputs.cpu == 'arm64' + inputs.cpu == 'arm64' && + inputs.rendering_backend == 'auto' shell: bash run: echo "F3D_CTEST_EXCEPTIONS=(TestDepthPeelingToneMapping)|(TestDepthPeeling)|(TestTextureColor)|(TestDXF)|(TestPipedDXF)|(TestScalarsCell)|(TestXCAFColors)|(TestGrid)|(TestConfig)|(TestGLTFDracoImporter)|(TestInteractionActors)|(TestInteractionFocalPointPickingPoints)|(TestInteractionCycleAnimation)|(TestInteractionAnimationSlow)|(TestInteractionConfigFileInteractions)|(TestGLTFRigArmature)|(TestInteractionRollCameraRotation)|(TestInteractionDragRotateVertical)|(TestInteractionCheatsheet)|(TestMaxSizeAboveMultiFile)|(TestAxesCustomColor)|(TestInteractionTAA)|(TestInteractionStochasticTAA)|(TestInteractionPointCloudTAA)|(TestSDKNotification)|(TestUnlitOBJOpacity)|(TestInteractionGridReflectionChanged)|(TestUSDRigArmatureWithOpacity)" >> $GITHUB_ENV @@ -300,12 +280,6 @@ runs: cmake --install . --component configuration cmake --install . --component colormaps - - name: Install Mesa Windows in install - if: runner.os == 'Windows' - uses: f3d-app/install-mesa-windows-action@v2 - with: - path: ${{github.workspace}}\install\bin - - name: Build and configure python externally if: | inputs.optdeps_label == 'optdeps' && @@ -337,14 +311,6 @@ runs: working-directory: ${{github.workspace}} run: cmake --build build_examples --config Release - - name: Install Mesa Windows examples - if: | - runner.os == 'Windows' && - inputs.static_label == 'no-static' - uses: f3d-app/install-mesa-windows-action@v2 - with: - path: ${{github.workspace}}\build_examples\*\*\Release - # older VTK version create different renderings so they are not tested - name: Test libf3d examples if: inputs.static_label == 'no-static' diff --git a/.github/actions/generic-dependencies/action.yml b/.github/actions/generic-dependencies/action.yml index ccc7bd57fd..6f55aa557d 100644 --- a/.github/actions/generic-dependencies/action.yml +++ b/.github/actions/generic-dependencies/action.yml @@ -16,6 +16,10 @@ inputs: description: "CPU architecture to build for" required: false default: "x86_64" + python_version: + description: "Python version to use for the CI" + required: false + default: "3.14" runs: using: "composite" @@ -25,6 +29,15 @@ runs: run: | [[ "${{ inputs.versions_file }}" ]] || { echo "versions_file is empty" ; exit 1; } + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: ${{ inputs.python_version }} + + - name: Upgrade pip + shell: bash + run: python -m pip install --upgrade pip + - name: Install VTK dependencies uses: ./source/.github/actions/vtk-dependencies with: diff --git a/.github/actions/llvm-install-dep/action.yml b/.github/actions/llvm-install-dep/action.yml new file mode 100644 index 0000000000..ab0a3992c0 --- /dev/null +++ b/.github/actions/llvm-install-dep/action.yml @@ -0,0 +1,105 @@ +name: "Install LLVM Dependency" +description: "Install LLVM Dependency using cache when possible" +inputs: + versions_file: + description: "File to recover versions from" + required: true + mindeps_label: + description: "Label to flag for minimum versions dependencies" + required: false + default: "no-mindeps" + cpu: + description: "CPU architecture to build for" + required: false + default: "x86_64" + +runs: + using: "composite" + steps: + - name: Check required inputs + shell: bash + run: | + [[ "${{inputs.versions_file}}" ]] || { echo "versions_file is empty" ; exit 1; } + + - name: Extract llvm version + id: llvm_ver + uses: f3d-app/extract-version-action@main + with: + file: ${{inputs.versions_file}} + name: llvm + minver_label: ${{inputs.mindeps_label == 'mindeps' && 'minver' || ''}} + + - name: Extract global cache index + id: global_idx + uses: f3d-app/extract-version-action@main + with: + file: ${{inputs.versions_file}} + special_name: global_cache_index + + - name: Cache llvm + id: cache-llvm + continue-on-error: true # https://github.com/actions/cache/issues/1754 + uses: actions/cache/restore@v6 + with: + path: dependencies/llvm_install + key: llvm-${{steps.llvm_ver.outputs.extract}}-${{runner.os}}-${{inputs.cpu}}-${{steps.global_idx.outputs.extract}}-1 + + - name: Checkout LLVM + if: steps.cache-llvm.outputs.cache-hit != 'true' + uses: actions/checkout@v7 + with: + repository: llvm/llvm-project + submodules: true + path: "./dependencies/llvm" + ref: llvmorg-${{steps.llvm_ver.outputs.extract}} + + - name: Setup LLVM + if: steps.cache-llvm.outputs.cache-hit != 'true' + working-directory: ${{github.workspace}}/dependencies + shell: bash + run: | + mkdir llvm_build + mkdir llvm_install + + - name: Configure LLVM + if: steps.cache-llvm.outputs.cache-hit != 'true' + working-directory: ${{github.workspace}}/dependencies/llvm_build + shell: bash + run: > + cmake ../llvm/llvm + -DCMAKE_BUILD_TYPE=Release + -DCMAKE_INSTALL_PREFIX="../llvm_install" + -DLLVM_TARGETS_TO_BUILD="host" + -DLLVM_ENABLE_PROJECTS="" + -DLLVM_BUILD_TOOLS=ON + -DLLVM_BUILD_TESTS=OFF + -DLLVM_BUILD_EXAMPLES=OFF + -DLLVM_BUILD_BENCHMARKS=OFF + -DLLVM_INCLUDE_TESTS=OFF + -DLLVM_INCLUDE_EXAMPLES=OFF + -DLLVM_INCLUDE_BENCHMARKS=OFF + -DLLVM_INCLUDE_DOCS=OFF + -DLLVM_ENABLE_ZLIB=OFF + -DLLVM_ENABLE_ZSTD=OFF + -DLLVM_ENABLE_LIBXML2=OFF + -DLLVM_ENABLE_RTTI=OFF + ${{ runner.os == 'macOS' && '-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON -DCMAKE_OSX_DEPLOYMENT_TARGET=14.0' || null }} + ${{ runner.os == 'Windows' && '-Ax64 -DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL' || null }} + + - name: Build LLVM + if: steps.cache-llvm.outputs.cache-hit != 'true' + working-directory: ${{github.workspace}}/dependencies/llvm_build + shell: bash + run: cmake --build . --parallel 2 --target install --config Release + + - name: Copy to install + working-directory: ${{github.workspace}}/dependencies/llvm_install + shell: bash + run: cp -r ./* ../install/ + + - name: Save cache + if: steps.cache-llvm.outputs.cache-hit != 'true' + uses: actions/cache/save@v6 + with: + key: ${{ steps.cache-llvm.outputs.cache-primary-key }} + path: dependencies/llvm_install diff --git a/.github/actions/mesa-install-dep/action.yml b/.github/actions/mesa-install-dep/action.yml new file mode 100644 index 0000000000..efdf4679a1 --- /dev/null +++ b/.github/actions/mesa-install-dep/action.yml @@ -0,0 +1,136 @@ +name: "Install Mesa Dependency" +description: "Install Mesa Dependency using cache when possible" +inputs: + versions_file: + description: "File to recover versions from" + required: true + mindeps_label: + description: "Label to flag for minimum versions dependencies" + required: false + default: "no-mindeps" + cpu: + description: "CPU architecture to build for" + required: false + default: "x86_64" + +runs: + using: "composite" + steps: + - name: Check required inputs + shell: bash + run: | + [[ "${{inputs.versions_file}}" ]] || { echo "versions_file is empty" ; exit 1; } + + - name: Extract mesa version + id: mesa_ver + uses: f3d-app/extract-version-action@main + with: + file: ${{inputs.versions_file}} + name: mesa + minver_label: ${{inputs.mindeps_label == 'mindeps' && 'minver' || ''}} + + - name: Extract global cache index + id: global_idx + uses: f3d-app/extract-version-action@main + with: + file: ${{inputs.versions_file}} + special_name: global_cache_index + + - name: Cache mesa + id: cache-mesa + continue-on-error: true # https://github.com/actions/cache/issues/1754 + uses: actions/cache/restore@v6 + with: + path: dependencies/mesa_install + key: mesa-${{steps.mesa_ver.outputs.extract}}-${{runner.os}}-${{inputs.cpu}}-${{steps.global_idx.outputs.extract}}-8 + + - name: Setup MSVC (Windows) + if: steps.cache-mesa.outputs.cache-hit != 'true' && runner.os == 'Windows' + uses: TheMrMilchmann/setup-msvc-dev@v4 + with: + arch: x64 + + # https://github.com/ilammy/msvc-dev-cmd#caveats + - name: Remove Git link.exe (Windows) + if: steps.cache-mesa.outputs.cache-hit != 'true' && runner.os == 'Windows' + shell: bash + run: rm $(which link.exe) + + - name: Install Python dependencies + if: steps.cache-mesa.outputs.cache-hit != 'true' + shell: bash + run: | + python -m pip install meson mako packaging PyYAML + + - name: Install Flex/Bison (Windows) + if: steps.cache-mesa.outputs.cache-hit != 'true' && runner.os == 'Windows' + shell: bash + run: choco install winflexbison3 --no-progress -y + + - name: Install Flex/Bison (Linux) + if: steps.cache-mesa.outputs.cache-hit != 'true' && runner.os == 'Linux' + shell: bash + run: apt-get install -y bison byacc flex pkg-config ninja-build libzstd-dev + + - name: Checkout mesa + if: steps.cache-mesa.outputs.cache-hit != 'true' + shell: bash + run: git clone --recurse-submodules --depth 1 --branch mesa-${{steps.mesa_ver.outputs.extract}} https://gitlab.freedesktop.org/mesa/mesa.git dependencies/mesa + + - name: Setup mesa + if: steps.cache-mesa.outputs.cache-hit != 'true' + working-directory: ${{github.workspace}}/dependencies + shell: bash + run: | + mkdir mesa_build + mkdir mesa_install + + - name: Add LLVM to PATH to find llvm-config + if: steps.cache-mesa.outputs.cache-hit != 'true' + shell: bash + run: echo "$GITHUB_WORKSPACE/dependencies/install/bin" >> "$GITHUB_PATH" + + - name: Configure mesa + if: steps.cache-mesa.outputs.cache-hit != 'true' + working-directory: ${{github.workspace}}/dependencies + shell: bash + run: > + meson setup mesa_build mesa + --prefix=$(pwd)/mesa_install + --buildtype=release + -Db_ndebug=true + -Dosmesa=true + -Dcpp_rtti=false + -Dgallium-drivers=llvmpipe + -Dvulkan-drivers=[] + -Dopengl=true + -Dgles1=disabled + -Dgles2=disabled + -Degl=disabled + -Dglx=disabled + -Dxlib-lease=disabled + -Dxmlconfig=disabled + -Dexpat=disabled + -Dplatforms=[] + -Dshared-glapi=disabled + -Dllvm=enabled + -Dshared-llvm=disabled + -Dzlib=disabled + + - name: Build mesa + if: steps.cache-mesa.outputs.cache-hit != 'true' + working-directory: ${{github.workspace}}/dependencies/mesa_build + shell: bash + run: ninja -j2 install + + - name: Copy to install + working-directory: ${{github.workspace}}/dependencies/mesa_install + shell: bash + run: cp -r ./* ../install/ + + - name: Save cache + if: steps.cache-mesa.outputs.cache-hit != 'true' + uses: actions/cache/save@v6 + with: + key: ${{ steps.cache-mesa.outputs.cache-primary-key }} + path: dependencies/mesa_install diff --git a/.github/actions/python-ci/action.yml b/.github/actions/python-ci/action.yml index 1dbdb39e96..0b81348957 100644 --- a/.github/actions/python-ci/action.yml +++ b/.github/actions/python-ci/action.yml @@ -37,6 +37,7 @@ runs: with: versions_file: ${{inputs.versions_file}} cpu: ${{inputs.cpu}} + python_version: ${{ inputs.python_version }} - name: Install VTK dependency uses: ./source/.github/actions/vtk-install-dep @@ -44,16 +45,10 @@ runs: versions_file: ${{inputs.versions_file}} cpu: ${{inputs.cpu}} - - name: Set up Python - uses: actions/setup-python@v6 - with: - python-version: ${{ inputs.python_version }} - # numpy pinned to 2.2.X until python 3.10 support is dropped - name: Install Python dependencies shell: bash run: | - python -m pip install --upgrade pip python -m pip install pytest==9.0.3 python -m pip install pyopengltk==0.0.4 python -m pip install PySide6==6.11.1 @@ -122,6 +117,7 @@ runs: shell: bash run: Xvfb $DISPLAY -screen 0 1280x1024x24 & + # Needed for examples/libf3d/python/qt6/test_minimal_qt6.py - name: Install Mesa Windows if: runner.os == 'Windows' uses: f3d-app/install-mesa-windows-action@v2 diff --git a/.github/actions/sanitizer-ci/action.yml b/.github/actions/sanitizer-ci/action.yml index 61edb1d10f..884de74281 100644 --- a/.github/actions/sanitizer-ci/action.yml +++ b/.github/actions/sanitizer-ci/action.yml @@ -32,10 +32,19 @@ runs: lfs_sha: ${{inputs.lfs_sha}} cache_postfix: cache-0 + # Python is needed in case Mesa must be built + - name: Extract python version + id: python_ver + uses: f3d-app/extract-version-action@main + with: + file: ${{inputs.versions_file}} + name: python + - name: Install all F3D dependencies uses: ./source/.github/actions/generic-dependencies with: versions_file: ${{inputs.versions_file}} + python_version: ${{steps.python_ver.outputs.extract}} - name: Install VTK dependency uses: ./source/.github/actions/vtk-install-dep diff --git a/.github/actions/static-analysis-ci/action.yml b/.github/actions/static-analysis-ci/action.yml index 5b1b7125c8..8d9acc63ff 100644 --- a/.github/actions/static-analysis-ci/action.yml +++ b/.github/actions/static-analysis-ci/action.yml @@ -25,10 +25,19 @@ runs: lfs_sha: ${{inputs.lfs_sha}} cache_postfix: cache-0 + # Python is needed in case Mesa must be built + - name: Extract python version + id: python_ver + uses: f3d-app/extract-version-action@main + with: + file: ${{inputs.versions_file}} + name: python + - name: Install all F3D dependencies uses: ./source/.github/actions/generic-dependencies with: versions_file: ${{inputs.versions_file}} + python_version: ${{steps.python_ver.outputs.extract}} - name: Install VTK dependency uses: ./source/.github/actions/vtk-install-dep diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ecb05f9e7a..b34a71511c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -264,6 +264,8 @@ jobs: fetch-depth: 0 lfs: false + # OSMesa is supported on macOS from 9.6.20260701 + # Since it's more robust than Apple's software renderer, we use it for the macOS ARM CI - name: Generic CI uses: ./source/.github/actions/generic-ci with: @@ -271,6 +273,7 @@ jobs: vtk_version: ${{matrix.vtk_version}} cpu: x86_64 lfs_sha: ${{ needs.cache_lfs.outputs.lfs_sha}} + rendering_backend: ${{matrix.vtk_version == 'commit' && 'osmesa' || 'auto'}} #---------------------------------------------------------------------------- # MacOS ARM CI: Build and test, cross-vtk build matrix with a few optional builds @@ -308,6 +311,8 @@ jobs: fetch-depth: 0 lfs: false + # OSMesa is supported on macOS from 9.6.20260701 + # Since it's more robust than Apple's software renderer, we use it for the macOS ARM CI - name: Generic CI uses: ./source/.github/actions/generic-ci with: @@ -315,6 +320,7 @@ jobs: vtk_version: ${{matrix.vtk_version}} bundle_label: ${{matrix.bundle_label}} static_label: ${{matrix.static_label}} + rendering_backend: ${{matrix.vtk_version == 'commit' && 'osmesa' || 'auto'}} cpu: arm64 lfs_sha: ${{ needs.cache_lfs.outputs.lfs_sha}} diff --git a/.github/workflows/versions.json b/.github/workflows/versions.json index d65af75a5d..e3f867f325 100644 --- a/.github/workflows/versions.json +++ b/.github/workflows/versions.json @@ -9,7 +9,8 @@ "TBB is set at v2021.13.1 because OpenUSD seems to not support more recent versions: https://github.com/PixarAnimationStudios/OpenUSD/issues/3878 and https://github.com/PixarAnimationStudios/OpenUSD/issues/4078", "sqlite is using a common-superbuild hash as it is not a CMake project", "OpenEXR v3.0.1 is actually not using OpenJPH", - "zlib is fixed at v1.3.1 until https://github.com/madler/zlib/issues/1181 is fixed" + "zlib is fixed at v1.3.1 until https://github.com/madler/zlib/issues/1181 is fixed", + "mesa is fixed at 25.0.7 because OSMesa has been removed from 25.1.0" ], "alembic": { "version": "1.8.11", @@ -47,6 +48,14 @@ "version": "26", "min_version": "17" }, + "llvm": { + "version": "22.1.8", + "min_version": "22.1.8" + }, + "mesa": { + "version": "25.0.7", + "min_version": "24.3.4" + }, "occt": { "version": "V8_0_0", "min_version": "V7_6_3" diff --git a/CMakeLists.txt b/CMakeLists.txt index d311ba1412..e005c98ee0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -207,9 +207,10 @@ list(APPEND f3d_link_options_public ${f3d_sanitizer_link_options}) option(BUILD_TESTING "Build the tests" OFF) cmake_dependent_option(F3D_TESTING_ENABLE_RENDERING_TESTS "Enable rendering tests" ON "BUILD_TESTING" OFF) cmake_dependent_option(F3D_TESTING_ENABLE_LONG_TIMEOUT_TESTS "Enable long timeout tests" OFF "BUILD_TESTING" OFF) +cmake_dependent_option(F3D_TESTING_ENABLE_WGL_TESTS "Enable tests that require a Windows driver with OpenGL >= 3.2" ON "F3D_TESTING_ENABLE_RENDERING_TESTS AND WIN32" OFF) cmake_dependent_option(F3D_TESTING_ENABLE_GLX_TESTS "Enable tests that require a X server running on Linux" ON "F3D_TESTING_ENABLE_RENDERING_TESTS AND UNIX AND NOT APPLE" OFF) -cmake_dependent_option(F3D_TESTING_ENABLE_EGL_TESTS "Enable tests that require EGL to run" ON "F3D_TESTING_ENABLE_RENDERING_TESTS AND UNIX AND NOT APPLE" OFF) -cmake_dependent_option(F3D_TESTING_ENABLE_OSMESA_TESTS "Enable tests that require OSMESA to run" OFF "F3D_TESTING_ENABLE_RENDERING_TESTS AND UNIX AND NOT APPLE" OFF) +cmake_dependent_option(F3D_TESTING_ENABLE_EGL_TESTS "Enable tests that require EGL to run" ON "F3D_TESTING_ENABLE_RENDERING_TESTS AND NOT APPLE" OFF) +cmake_dependent_option(F3D_TESTING_ENABLE_OSMESA_TESTS "Enable tests that require OSMESA to run" OFF "F3D_TESTING_ENABLE_RENDERING_TESTS" OFF) cmake_dependent_option(F3D_TESTING_DISABLE_CATCH_ALL "Disable the catch all exception code in main for improved testing" OFF "BUILD_TESTING" OFF) cmake_dependent_option(F3D_TESTING_ENABLE_ILLUSTRATION_TESTS "Enable documentation illustration tests" OFF "BUILD_TESTING" OFF) diff --git a/application/testing/tests.backends.cmake b/application/testing/tests.backends.cmake index 7f4559fd06..8f612ff1e1 100644 --- a/application/testing/tests.backends.cmake +++ b/application/testing/tests.backends.cmake @@ -4,16 +4,23 @@ f3d_test(NAME TestRenderingBackendAuto DATA cow.vtp RENDERING_BACKEND auto) f3d_test(NAME TestRenderingBackendInvalid DATA cow.vtp RENDERING_BACKEND invalid ARGS --verbose REGEXP "rendering-backend value is invalid, falling back to" NO_BASELINE) if(F3D_TESTING_ENABLE_OSMESA_TESTS) - f3d_test(NAME TestRenderingBackenListOSMesa ARGS --list-rendering-backends NO_RENDER NO_BASELINE REGEXP "osmesa: available") + if (NOT APPLE OR VTK_VERSION VERSION_GREATER_EQUAL 9.6.20260701) + f3d_test(NAME TestRenderingBackenListOSMesa ARGS --list-rendering-backends NO_RENDER NO_BASELINE REGEXP "osmesa: available") + endif() endif() -if(WIN32) +if(F3D_TESTING_ENABLE_WGL_TESTS) f3d_test(NAME TestRenderingBackendWGL DATA cow.vtp RENDERING_BACKEND wgl) f3d_test(NAME TestRenderingBackendWGLCheckClass DATA cow.vtp RENDERING_BACKEND wgl ARGS --verbose REGEXP "vtkF3DWGLRenderWindow" NO_BASELINE) f3d_test(NAME TestRenderingBackendWindowsAutoCheckClass DATA cow.vtp ARGS --verbose REGEXP "vtkF3DWGLRenderWindow" NO_BASELINE) - f3d_test(NAME TestRenderingBackendGLXFailure DATA cow.vtp RENDERING_BACKEND glx REGEXP "Cannot use a GLX context on this platform" NO_BASELINE) f3d_test(NAME TestRenderingBackenListWGL ARGS --list-rendering-backends NO_RENDER NO_BASELINE REGEXP "wgl: available") -elseif(APPLE) +endif() + +if(WIN32 OR APPLE) + f3d_test(NAME TestRenderingBackendGLXFailure DATA cow.vtp RENDERING_BACKEND glx REGEXP "Cannot use a GLX context on this platform" NO_BASELINE) +endif() + +if(APPLE) f3d_test(NAME TestRenderingBackenListCOCOA ARGS --list-rendering-backends NO_RENDER NO_BASELINE REGEXP "cocoa: available") endif() diff --git a/application/testing/tests.custom.cmake b/application/testing/tests.custom.cmake index f9bb457b9c..44df467ff0 100644 --- a/application/testing/tests.custom.cmake +++ b/application/testing/tests.custom.cmake @@ -31,3 +31,14 @@ if (APPLE) add_test(NAME f3d::TestAppleCmdMod COMMAND $ --output=${CMAKE_BINARY_DIR}/Testing/Temporary/TestAppleCmdMod.png --reference=${F3D_SOURCE_DIR}/testing/baselines/TestAppleCmdMod.png --resolution=400,400) set_tests_properties(f3d::TestAppleCmdMod PROPERTIES ENVIRONMENT "CTEST_F3D_NO_DATA_FORCE_RENDER=1") endif () + +# Test EGL/OSMesa load failure by loading fake libraries like libEGL.so located in ${F3D_SOURCE_DIR}/testing/data +if (UNIX AND NOT APPLE) + add_test(NAME f3d::TestEGLLoadFailure COMMAND $ --output=${CMAKE_BINARY_DIR}/Testing/Temporary/egl.png --rendering-backend=egl --verbose) + set_tests_properties(f3d::TestEGLLoadFailure PROPERTIES PASS_REGULAR_EXPRESSION "Cannot find EGL library") + set_tests_properties(f3d::TestEGLLoadFailure PROPERTIES ENVIRONMENT "LD_LIBRARY_PATH=${F3D_SOURCE_DIR}/testing/data") + + add_test(NAME f3d::TestOSMesaLoadFailure COMMAND $ --output=${CMAKE_BINARY_DIR}/Testing/Temporary/osmesa.png --rendering-backend=osmesa --verbose) + set_tests_properties(f3d::TestOSMesaLoadFailure PROPERTIES PASS_REGULAR_EXPRESSION "Cannot find OSMesa library") + set_tests_properties(f3d::TestOSMesaLoadFailure PROPERTIES ENVIRONMENT "LD_LIBRARY_PATH=${F3D_SOURCE_DIR}/testing/data") +endif () diff --git a/application/testing/tests.features.cmake b/application/testing/tests.features.cmake index 3d2edf6413..818634ee5d 100644 --- a/application/testing/tests.features.cmake +++ b/application/testing/tests.features.cmake @@ -129,8 +129,8 @@ if(VTK_VERSION VERSION_GREATER_EQUAL 9.5.20251001) endif() ## Volume -f3d_test(NAME TestVolume DATA HeadMRVolume.mhd ARGS -v --camera-position=127.5,-400,127.5 --camera-view-up=0,0,1) -f3d_test(NAME TestVolumeInverse DATA HeadMRVolume.mhd ARGS -vi --camera-position=127.5,-400,127.5 --camera-view-up=0,0,1 THRESHOLD 0.05) # Small rendering differences due to volume rendering +f3d_test(NAME TestVolume DATA HeadMRVolume.mhd ARGS -v --camera-position=127.5,-400,127.5 --camera-view-up=0,0,1 THRESHOLD 0.08) # Small rendering differences on macOS OSMesa +f3d_test(NAME TestVolumeInverse DATA HeadMRVolume.mhd ARGS -vi --camera-position=127.5,-400,127.5 --camera-view-up=0,0,1 THRESHOLD 0.11) # Small rendering differences on macOS OSMesa f3d_test(NAME TestVolumeMag DATA vase_4comp.vti ARGS -vb) f3d_test(NAME TestVolumeComp DATA vase_4comp.vti ARGS -vb --coloring-component=3 LONG_TIMEOUT) f3d_test(NAME TestVolumeDirect DATA vase_4comp.vti ARGS -vb --coloring-component=-2) @@ -320,7 +320,7 @@ if(VTK_VERSION VERSION_GREATER_EQUAL 9.5.20251001) endif() ## Skinning -if(APPLE) # MacOS does not support OpenGL 4.3 +if(APPLE AND NOT F3D_TESTING_FORCE_RENDERING_BACKEND STREQUAL "osmesa") # MacOS driver does not support OpenGL 4.3 f3d_test(NAME TestSkinningManyBonesFailure DATA tube_254bones.glb ARGS --verbose REGEXP "which requires OpenGL" NO_BASELINE) else() if(VTK_VERSION VERSION_GREATER_EQUAL 9.4.20241219) # The baseline changed with armature support diff --git a/application/testing/tests.interaction.cmake b/application/testing/tests.interaction.cmake index 76949f78ca..ca470197d8 100644 --- a/application/testing/tests.interaction.cmake +++ b/application/testing/tests.interaction.cmake @@ -11,7 +11,7 @@ f3d_test(NAME TestInteractionCycleCellInvalidIndex DATA waveletArrays.vti INTERA f3d_test(NAME TestInteractionCycleBlending DATA suzanne.ply ARGS --opacity=0.8 INTERACTION LONG_TIMEOUT) #PPPPP # Cycle to ddp f3d_test(NAME TestInteractionVolumeCycle DATA waveletArrays.vti ARGS INTERACTION) #VSS f3d_test(NAME TestInteractionVolumeAfterColoring DATA waveletArrays.vti ARGS INTERACTION) #SSSV -f3d_test(NAME TestInteractionVolumeInverse DATA HeadMRVolume.mhd ARGS --camera-position=127.5,-400,127.5 --camera-view-up=0,0,1 INTERACTION THRESHOLD 0.05) #VI #Small rendering differences due to volume rendering +f3d_test(NAME TestInteractionVolumeInverse DATA HeadMRVolume.mhd ARGS --camera-position=127.5,-400,127.5 --camera-view-up=0,0,1 INTERACTION THRESHOLD 0.11) #VI #Small rendering differences on macOS OSMesa f3d_test(NAME TestInteractionCorrectCameraForVolumeSwitch ARGS --no-config -v DATA dragon.vtu INTERACTION UI) #v f3d_test(NAME TestInteractionMultiFileVolume DATA multi ARGS --multi-file-mode=all INTERACTION) #SSVB f3d_test(NAME TestInteractionPointCloud DATA pointsCloud.vtp ARGS --point-sprites-size=20 INTERACTION) #O diff --git a/doc/dev/06-TESTING.md b/doc/dev/06-TESTING.md index 12c8b1342d..9a096bbf33 100644 --- a/doc/dev/06-TESTING.md +++ b/doc/dev/06-TESTING.md @@ -10,6 +10,7 @@ There are a few CMake options to configure the F3D testing framework: - `F3D_TESTING_ENABLE_RENDERING_TESTS`: An option to enable/disable test that require rendering capabilities, on by default. - `F3D_TESTING_ENABLE_LONG_TIMEOUT_TESTS`: Certain tests can take some time to run, off by default, requires rendering tests. - `F3D_TESTING_FORCE_RENDERING_BACKEND`: Configure the rendering backend to use. Can be `auto` (default), `glx`, `wgl`, `egl` or `osmesa`. +- `F3D_TESTING_ENABLE_WGL_TESTS`: Enable tests requiring a Windows OpenGL >= 3.2 driver. - `F3D_TESTING_ENABLE_GLX_TESTS`: Enable tests requiring a X11 server running on Linux. - `F3D_TESTING_ENABLE_OSMESA_TESTS`: Enable tests requiring OSMesa dependency. - `F3D_TESTING_ENABLE_EGL_TESTS`: Enable tests requiring EGL dependency. diff --git a/doc/libf3d/06-MIGRATION.md b/doc/libf3d/06-MIGRATION.md index e906b9d42a..c8970c9055 100644 --- a/doc/libf3d/06-MIGRATION.md +++ b/doc/libf3d/06-MIGRATION.md @@ -51,3 +51,8 @@ The `jump_to_frame` and `jump_to_keyframe` commands no longer take a second bool ## ui.animation_progress The `ui.animation_progress` option (CLI `--animation-progress`) was a boolean toggling a progress bar during animation playback. It is now a string selecting the progress bar mode: `none` (hidden), `default` (the progress bar alone) or `advanced` (the progress bar with time range, animation name, current time labels and keyframe markers). Replace `true` with `default` (or `advanced`) and `false` with `none`. + +## Context symbol + +The function `f3d::context::getSymbol` function is now expecting a library full path or a filename. +The library prefix and extension is not appended automatically anymore. diff --git a/doc/user/12-DESKTOP_INTEGRATION.md b/doc/user/12-DESKTOP_INTEGRATION.md index 7a2f24f3a5..a44cdc8a92 100644 --- a/doc/user/12-DESKTOP_INTEGRATION.md +++ b/doc/user/12-DESKTOP_INTEGRATION.md @@ -4,17 +4,15 @@ F3D can be integrated in the desktop experience. ## Linux -### Thumbnails - For Linux desktop integration, F3D rely on mime types files as defined by the [XDG standard](https://specifications.freedesktop.org/mime-apps-spec/latest-single/), .thumbnailer file as specified [here](https://wiki.archlinux.org/title/File_manager_functionality#Thumbnail_previews) and .desktop file as specified [here](https://wiki.archlinux.org/title/desktop_entries). Many file managers use this mechanism, including nautilus, thunar, pcmanfm and caja. The simplest way to obtain desktop integration on Linux is to use a package for your distribution, or the .deb binary release package we provide if compatible with your distribution. In other cases, the binary release archive can be used like this: -0. Make sure `~/.local/bin` is part of your `PATH` -1. Extract F3D binary release archive in `~/.local/` -2. Update your [mime database](https://linux.die.net/man/1/update-mime-database) pointing to `~/.local/share/mime` -3. Update your [desktop database](https://linuxcommandlibrary.com/man/update-desktop-database) pointing to `~/.local/share/application` +1. Make sure `~/.local/bin` is part of your `PATH` +2. Extract F3D binary release archive in `~/.local/` +3. Update your [mime database](https://linux.die.net/man/1/update-mime-database) pointing to `~/.local/share/mime` +4. Update your [desktop database](https://linuxcommandlibrary.com/man/update-desktop-database) pointing to `~/.local/share/application` ```bash export PATH=$PATH:~/.local/bin @@ -23,32 +21,6 @@ update-mime-database ~/.local/share/mime/ update-desktop-database ~/.local/share/applications ``` -### Rendering - -F3D supports rendering in environments with limited graphical contexts, including sandboxes or without Xorg running. -In most cases, the default behavior will automatically detect which capabilities are available and use the right rendering backend, -it is possible to specify it using the `--rendering-backend` CLI option. - -- If `libEGL.so` is available, you can use: `--rendering-backend=egl`. -- If `libOSMesa.so` is available, you can use: `--rendering-backend=osmesa`. -- When using `--rendering-backend=auto`, F3D will try to load the following libraries in order and use the first one it was able to load and use: - - `libGLX.so` - - `libEGL.so` - - `libOSMesa.so` - -You can use that feature for thumbnail generation whenever needed (e.g., Nautilus or other sandboxing file browser), -by creating/modifying your [thumbnail config file](06-CONFIGURATION_FILE.md), eg:`~/.config/f3d/thumbnail.json`: - -```json -[ - { - "options": { - "rendering-backend": "egl" - } - } -] -``` - If you use the portable archive, make sure to extract it somewhere the sandboxing system has access to, eg: Nautilus uses `bwrap` and gives it access to `/usr` but not to `/opt`. ## Windows @@ -75,6 +47,37 @@ regsvr32 /u F3DShellExtension.dll There is no support for thumbnails on MacOS, the .dmg binary release provides automatic file openings. +## Rendering backends + +F3D supports rendering in environments with limited graphical contexts, including sandboxes or without Xorg running on Linux. +In most cases, the default behavior will automatically detect which capabilities are available and use the right rendering backend, +it is possible to specify it using the `--rendering-backend` CLI option. + +- If EGL is available, you can use: `--rendering-backend=egl`. The following libraries are attempted to be loaded dynamically (in that order): + - `libEGL.so.1`, `libEGL.so` on Linux + - `libEGL.dll`, `EGL.dll` on Windows +- If OSMesa is available, you can use: `--rendering-backend=osmesa`. The following libraries are attempted to be loaded dynamically (in that order): + - `libOSMesa.so.8`, `libOSMesa.so.6`, `libOSMesa.so` on Linux + - `osmesa.dll` on Windows + - `libOSMesa.8.dylib`, `libOSMesa.6.dylib`, `libOSMesa.dylib` on macOS +- When using `--rendering-backend=auto`, F3D have the following logic: + - On Linux, check if a X server is running, in which case GLX is used. Otherwise, try to load EGL library and fallback on OSMesa if not available. + - On Windows, check if the OpenGL driver supports OpenGL 3.2, in which case WGL is used. Otherwise, try to load EGL library and fallback on OSMesa if not available. + - On macOS, always use COCOA. To use OSMesa, you must use `--rendering-backend=osmesa`. + +You can use that feature for thumbnail generation whenever needed (e.g., Nautilus or other sandboxing file browser), +by creating/modifying your [thumbnail config file](06-CONFIGURATION_FILE.md), eg:`~/.config/f3d/thumbnail.json`: + +```json +[ + { + "options": { + "rendering-backend": "egl" + } + } +] +``` + ## Limitations - TIFF files are excluded from the thumbnailer to avoid conflicts with other better 2D thumbnailers. diff --git a/java/testing/CMakeLists.txt b/java/testing/CMakeLists.txt index 969733b1fb..f4d87894d2 100644 --- a/java/testing/CMakeLists.txt +++ b/java/testing/CMakeLists.txt @@ -49,5 +49,6 @@ foreach(test_file ${javaf3dTests_list}) set_tests_properties(libf3d_bindings_java::${TName} PROPERTIES LABELS "libf3d;bindings;java" DISABLED ${java_test_disabled} + TIMEOUT 180 ) endforeach() diff --git a/library/public/context.h b/library/public/context.h index f30cca8c77..5c4709ddb5 100644 --- a/library/public/context.h +++ b/library/public/context.h @@ -66,10 +66,9 @@ class F3D_EXPORT context [[nodiscard]] static function osmesa(); /** - * Create a context function from a library name and a function name. - * The library name must be specified without its prefix and extension. - * For example, `getSymbol("EGL", "eglGetProcAddress")` looks for the symbol - * `eglGetProcAddress` in the library `libEGL.so` on Linux. + * Create a context function from a library filename and a function name. + * The library name must be specified with its prefix and extension. + * It can be a full path or a library name that can be found in the system library path. * Throw a loading_exception if it fails to find the library or a symbol_exception * if the lib does not contains the expected symbol. */ diff --git a/library/public/engine.h b/library/public/engine.h index 71781b531e..55a14b3217 100644 --- a/library/public/engine.h +++ b/library/public/engine.h @@ -41,8 +41,8 @@ class F3D_EXPORT engine /** * Create an engine with an automatic window. * Optionally, the window can be hidden by setting offscreen to true. - * Linux: Try GLX, then EGL, then OSMesa. - * Windows: Try Win32, then EGL, then OSMesa. + * Linux: GLX if a X server is running, otherwise EGL if available, otherwise OSMesa. + * Windows: Win32 if it supports OpenGL >= 3.2, otherwise EGL if available, otherwise OSMesa. * macOS: Always use Cocoa. * * Throws a context::loading_exception if a needed graphic library cannot be loaded. @@ -88,6 +88,7 @@ class F3D_EXPORT engine * Create an engine with an offscreen EGL window. * If several GPU are available, the environment variable * `VTK_DEFAULT_EGL_DEVICE_INDEX` allows its selection. + * Not supported on macOS. * * Throws a context::loading_exception if a needed graphic library cannot be loaded. * Throws a context::symbol_exception if a needed symbol cannot be found in graphic library. @@ -98,6 +99,7 @@ class F3D_EXPORT engine /** * Create an engine with an offscreen OSMesa window. + * On macOS, VTK >= 9.6.20260630 is required. * * Throws a context::loading_exception if a needed graphic library cannot be loaded. * Throws a context::symbol_exception if a needed symbol cannot be found in graphic library. diff --git a/library/src/context.cxx b/library/src/context.cxx index 964e58b4df..7f93e4376c 100644 --- a/library/src/context.cxx +++ b/library/src/context.cxx @@ -18,11 +18,12 @@ namespace f3d //---------------------------------------------------------------------------- context::function context::getSymbol(std::string_view lib, std::string_view func) { - std::string libName = vtksys::DynamicLoader::LibPrefix(); - libName += lib; - libName += vtksys::DynamicLoader::LibExtension(); - - vtksys::DynamicLoader::LibraryHandle handle = vtksys::DynamicLoader::OpenLibrary(libName); +#ifdef _WIN32 + // on Windows vtksys::DynamicLoader::OpenLibrary behaves differently (it expects a full path) + vtksys::DynamicLoader::LibraryHandle handle = LoadLibraryA(lib.data()); +#else + vtksys::DynamicLoader::LibraryHandle handle = vtksys::DynamicLoader::OpenLibrary(lib.data()); +#endif if (!handle) { @@ -46,7 +47,7 @@ context::function context::getSymbol(std::string_view lib, std::string_view func context::function context::glx() { #if defined(VTK_USE_X) - return getSymbol("GLX", "glXGetProcAddress"); + return getSymbol("libGLX.so", "glXGetProcAddress"); #else throw loading_exception("Cannot use a GLX context on this platform"); #endif @@ -91,7 +92,22 @@ context::function context::egl() { #if defined(VTK_OPENGL_HAS_EGL) gladLoaderLoadEGL(EGL_NO_DISPLAY); - return getSymbol("EGL", "eglGetProcAddress"); + +#ifdef _WIN32 + for (const auto& lib : { "libEGL.dll", "EGL.dll" }) +#else + for (const auto& lib : { "libEGL.so.1", "libEGL.so" }) +#endif + { + try + { + return getSymbol(lib, "eglGetProcAddress"); + } + catch (const loading_exception&) + { + } + } + throw loading_exception("Cannot find EGL library"); #else throw loading_exception("Cannot use a EGL context on this platform"); #endif @@ -100,10 +116,25 @@ context::function context::egl() //---------------------------------------------------------------------------- context::function context::osmesa() { -#if defined(__linux__) || defined(__FreeBSD__) - return getSymbol("OSMesa", "OSMesaGetProcAddress"); -#elif _WIN32 - return getSymbol("osmesa", "OSMesaGetProcAddress"); +#if (defined(__APPLE__) && VTK_VERSION_NUMBER >= VTK_VERSION_CHECK(9, 6, 20260701)) || \ + defined(__linux__) || defined(__FreeBSD__) || defined(_WIN32) +#ifdef _WIN32 + for (const auto& lib : { "osmesa.dll" }) +#elif __APPLE__ + for (const auto& lib : { "libOSMesa.8.dylib", "libOSMesa.6.dylib", "libOSMesa.dylib" }) +#else + for (const auto& lib : { "libOSMesa.so.8", "libOSMesa.so.6", "libOSMesa.so" }) +#endif + { + try + { + return getSymbol(lib, "OSMesaGetProcAddress"); + } + catch (const loading_exception&) + { + } + } + throw loading_exception("Cannot find OSMesa library"); #else throw loading_exception("Cannot use a OSMesa context on this platform"); #endif diff --git a/library/src/window_impl.cxx b/library/src/window_impl.cxx index 86b34355aa..5325441237 100644 --- a/library/src/window_impl.cxx +++ b/library/src/window_impl.cxx @@ -72,7 +72,17 @@ class window_impl::internals { // Override VTK logic #ifdef _WIN32 - return vtkSmartPointer::New(); + vtkSmartPointer wglRenWin = + vtkSmartPointer::New(); + if (!wglRenWin->SupportsOpenGL()) + { + // Can happen when a remote desktop is used, in that case we fallback on OSMesa + return vtkSmartPointer::New(); + } + else + { + return wglRenWin; + } #elif defined(__linux__) || defined(__FreeBSD__) #if defined(VTK_USE_X) // try GLX diff --git a/library/testing/CMakeLists.txt b/library/testing/CMakeLists.txt index 7465da4620..b94b926193 100644 --- a/library/testing/CMakeLists.txt +++ b/library/testing/CMakeLists.txt @@ -78,6 +78,7 @@ configure_file("${F3D_SOURCE_DIR}/testing/recordings/TestSDKInteractorDropFullSc "${CMAKE_BINARY_DIR}/TestSDKInteractorDropFullScene.log") # world.obj; S set(libf3dSDKTests_link_libs "") +set(libf3dSDKTests_include_dirs "") # External window tests option(F3D_TESTING_ENABLE_EXTERNAL_GLFW "Test external GLFW" OFF) @@ -97,9 +98,13 @@ if(F3D_TESTING_ENABLE_EXTERNAL_QT) endif() endif() if(F3D_TESTING_ENABLE_OSMESA_TESTS) - find_library(OSMesa_LIB OSMesa REQUIRED) - list(APPEND libf3dSDKTests_list TestSDKExternalWindowOSMesa.cxx) - list(APPEND libf3dSDKTests_link_libs "${OSMesa_LIB}") + if (NOT APPLE OR VTK_VERSION VERSION_GREATER_EQUAL 9.6.20260701) + find_library(OSMesa_LIB OSMesa REQUIRED) + find_path(OSMesa_INCLUDE_DIR GL/osmesa.h REQUIRED) + list(APPEND libf3dSDKTests_list TestSDKExternalWindowOSMesa.cxx) + list(APPEND libf3dSDKTests_link_libs "${OSMesa_LIB}") + list(APPEND libf3dSDKTests_include_dirs "${OSMesa_INCLUDE_DIR}") + endif() endif() if(F3D_TESTING_ENABLE_GLX_TESTS) find_package(OpenGL COMPONENTS GLX REQUIRED) @@ -112,7 +117,7 @@ if(F3D_TESTING_ENABLE_EGL_TESTS) list(APPEND libf3dSDKTests_list TestSDKExternalWindowEGL.cxx) list(APPEND libf3dSDKTests_link_libs OpenGL::EGL) endif() -if(WIN32) +if(F3D_TESTING_ENABLE_WGL_TESTS) find_package(OpenGL COMPONENTS OpenGL REQUIRED) list(APPEND libf3dSDKTests_list TestSDKExternalWindowWGL.cxx) list(APPEND libf3dSDKTests_link_libs OpenGL::GL) @@ -163,7 +168,7 @@ list(APPEND libf3dSDKTestsNoRender_list # Add all the ADD_TEST for each test foreach (test ${libf3dSDKTests_list}) get_filename_component (TName ${test} NAME_WE) - add_test (NAME libf3d::${TName} COMMAND libf3dSDKTests ${TName} "${F3D_SOURCE_DIR}/testing/" "${CMAKE_BINARY_DIR}/Testing/Temporary/" "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") + add_test (NAME libf3d::${TName} COMMAND libf3dSDKTests ${TName} "${F3D_SOURCE_DIR}/testing/" "${CMAKE_BINARY_DIR}/Testing/Temporary/" "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}" "${F3D_TESTING_FORCE_RENDERING_BACKEND}") set_tests_properties(libf3d::${TName} PROPERTIES LABELS "libf3d" TIMEOUT 60 @@ -208,6 +213,7 @@ endif() set_tests_properties(libf3d::TestSDKUtils PROPERTIES ENVIRONMENT "F3D_TEST_ENV_STANDARD=TestEnv;F3D_TEST_ENV_EXTENDED=TestËnv;F3D_TEST_ENV_UTF8=🤔;") +target_include_directories(libf3dSDKTests PRIVATE ${libf3dSDKTests_include_dirs}) target_link_libraries(libf3dSDKTests libf3d ${libf3dSDKTests_link_libs}) target_compile_options(libf3dSDKTests PUBLIC ${f3d_compile_options_public} PRIVATE ${f3d_compile_options_private}) target_link_options(libf3dSDKTests PUBLIC ${f3d_link_options_public}) diff --git a/library/testing/TestSDKAnimation.cxx b/library/testing/TestSDKAnimation.cxx index 6f31eb1c91..74abe72223 100644 --- a/library/testing/TestSDKAnimation.cxx +++ b/library/testing/TestSDKAnimation.cxx @@ -1,4 +1,5 @@ #include "PseudoUnitTest.h" +#include "TestSDKHelpers.h" #include #include @@ -6,10 +7,11 @@ using namespace std::string_literals; -int TestSDKAnimation([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKAnimation([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::scene& sce = eng.getScene(); f3d::interactor& inter = eng.getInteractor(); diff --git a/library/testing/TestSDKCamera.cxx b/library/testing/TestSDKCamera.cxx index 7ec56c7357..6568a13221 100644 --- a/library/testing/TestSDKCamera.cxx +++ b/library/testing/TestSDKCamera.cxx @@ -11,12 +11,13 @@ #include #include -int TestSDKCamera([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKCamera([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; f3d::log::setVerboseLevel(f3d::log::VerboseLevel::DEBUG); - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::window& win = eng.getWindow(); f3d::camera& cam = win.getCamera(); diff --git a/library/testing/TestSDKCompareWithFile.cxx b/library/testing/TestSDKCompareWithFile.cxx index 0738501992..d90d9c2510 100644 --- a/library/testing/TestSDKCompareWithFile.cxx +++ b/library/testing/TestSDKCompareWithFile.cxx @@ -5,11 +5,12 @@ #include #include -int TestSDKCompareWithFile([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKCompareWithFile([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::scene& sce = eng.getScene(); f3d::window& win = eng.getWindow(); win.setSize(300, 300); diff --git a/library/testing/TestSDKConsole.cxx b/library/testing/TestSDKConsole.cxx index bb86a8eea4..ae3707cdb5 100644 --- a/library/testing/TestSDKConsole.cxx +++ b/library/testing/TestSDKConsole.cxx @@ -4,7 +4,7 @@ #include #include -int TestSDKConsole([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKConsole([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; @@ -14,7 +14,8 @@ int TestSDKConsole([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) f3d::log::setUseColoring(false); f3d::log::warn("Message in console"); - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::options& opt = eng.getOptions(); opt.ui.console = true; diff --git a/library/testing/TestSDKDropZone.cxx b/library/testing/TestSDKDropZone.cxx index ba1f1a5d90..db01368dc9 100644 --- a/library/testing/TestSDKDropZone.cxx +++ b/library/testing/TestSDKDropZone.cxx @@ -5,11 +5,12 @@ #include #include -int TestSDKDropZone([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKDropZone([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::window& win = eng.getWindow(); f3d::options& opt = eng.getOptions(); win.setSize(300, 300); diff --git a/library/testing/TestSDKDropZoneDeprecated.cxx b/library/testing/TestSDKDropZoneDeprecated.cxx index ee76d93357..804c0ffff2 100644 --- a/library/testing/TestSDKDropZoneDeprecated.cxx +++ b/library/testing/TestSDKDropZoneDeprecated.cxx @@ -16,11 +16,12 @@ #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif -int TestSDKDropZoneDeprecated([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKDropZoneDeprecated([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::window& win = eng.getWindow(); f3d::options& opt = eng.getOptions(); win.setSize(300, 300); diff --git a/library/testing/TestSDKDropZoneMinSize.cxx b/library/testing/TestSDKDropZoneMinSize.cxx index d82cdb3437..27b022d7ab 100644 --- a/library/testing/TestSDKDropZoneMinSize.cxx +++ b/library/testing/TestSDKDropZoneMinSize.cxx @@ -1,14 +1,16 @@ #include "PseudoUnitTest.h" +#include "TestSDKHelpers.h" #include #include #include -int TestSDKDropZoneMinSize(int, char*[]) +int TestSDKDropZoneMinSize(int, char* argv[]) { PseudoUnitTest test; - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::window& win = eng.getWindow(); f3d::options& opt = eng.getOptions(); diff --git a/library/testing/TestSDKDropZoneNoLogo.cxx b/library/testing/TestSDKDropZoneNoLogo.cxx index 224348cf8e..e9d36404e4 100644 --- a/library/testing/TestSDKDropZoneNoLogo.cxx +++ b/library/testing/TestSDKDropZoneNoLogo.cxx @@ -5,11 +5,12 @@ #include #include -int TestSDKDropZoneNoLogo([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKDropZoneNoLogo([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::window& win = eng.getWindow(); f3d::options& opt = eng.getOptions(); win.setSize(300, 300); diff --git a/library/testing/TestSDKDynamicBackgroundColor.cxx b/library/testing/TestSDKDynamicBackgroundColor.cxx index a9b6738452..9e4a18c05b 100644 --- a/library/testing/TestSDKDynamicBackgroundColor.cxx +++ b/library/testing/TestSDKDynamicBackgroundColor.cxx @@ -6,11 +6,12 @@ #include #include -int TestSDKDynamicBackgroundColor([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKDynamicBackgroundColor([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::scene& sce = eng.getScene(); f3d::window& win = eng.getWindow(); f3d::options& opt = eng.getOptions(); diff --git a/library/testing/TestSDKDynamicFontFile.cxx b/library/testing/TestSDKDynamicFontFile.cxx index 14b2276a0d..6b8eea5030 100644 --- a/library/testing/TestSDKDynamicFontFile.cxx +++ b/library/testing/TestSDKDynamicFontFile.cxx @@ -6,11 +6,12 @@ #include #include -int TestSDKDynamicFontFile([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKDynamicFontFile([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::scene& sce = eng.getScene(); f3d::window& win = eng.getWindow(); f3d::options& opt = eng.getOptions(); diff --git a/library/testing/TestSDKDynamicHDRI.cxx b/library/testing/TestSDKDynamicHDRI.cxx index fa370b88e4..7cbeac29b7 100644 --- a/library/testing/TestSDKDynamicHDRI.cxx +++ b/library/testing/TestSDKDynamicHDRI.cxx @@ -10,13 +10,14 @@ #include -int TestSDKDynamicHDRI([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKDynamicHDRI([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; f3d::log::setVerboseLevel(f3d::log::VerboseLevel::INFO); - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::scene& sce = eng.getScene(); f3d::window& win = eng.getWindow(); diff --git a/library/testing/TestSDKDynamicLightIntensity.cxx b/library/testing/TestSDKDynamicLightIntensity.cxx index f12dba1d74..4f73faa962 100644 --- a/library/testing/TestSDKDynamicLightIntensity.cxx +++ b/library/testing/TestSDKDynamicLightIntensity.cxx @@ -6,11 +6,12 @@ #include #include -int TestSDKDynamicLightIntensity([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKDynamicLightIntensity([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::scene& scene = eng.getScene(); f3d::window& win = eng.getWindow(); f3d::options& opt = eng.getOptions(); diff --git a/library/testing/TestSDKDynamicProperties.cxx b/library/testing/TestSDKDynamicProperties.cxx index 8247e26559..9cd420e864 100644 --- a/library/testing/TestSDKDynamicProperties.cxx +++ b/library/testing/TestSDKDynamicProperties.cxx @@ -6,11 +6,12 @@ #include #include -int TestSDKDynamicProperties([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKDynamicProperties([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::scene& sce = eng.getScene(); f3d::window& win = eng.getWindow(); f3d::options& opt = eng.getOptions(); diff --git a/library/testing/TestSDKDynamicUpDirection.cxx b/library/testing/TestSDKDynamicUpDirection.cxx index b213e82be8..d7a8eb76eb 100644 --- a/library/testing/TestSDKDynamicUpDirection.cxx +++ b/library/testing/TestSDKDynamicUpDirection.cxx @@ -7,11 +7,12 @@ #include #include -int TestSDKDynamicUpDirection([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKDynamicUpDirection([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::scene& sce = eng.getScene(); f3d::window& win = eng.getWindow(); f3d::options& opt = eng.getOptions(); diff --git a/library/testing/TestSDKEngineExceptions.cxx b/library/testing/TestSDKEngineExceptions.cxx index 387bc251e2..ce2f1b14db 100644 --- a/library/testing/TestSDKEngineExceptions.cxx +++ b/library/testing/TestSDKEngineExceptions.cxx @@ -57,7 +57,7 @@ int TestSDKEngineExceptions([[maybe_unused]] int argc, [[maybe_unused]] char* ar std::ignore = f3d::engine::createExternal(f3d::context::getSymbol("invalid", "invalid")); }); test.expect("create external engine with invalid symbol", [&]() { - std::ignore = f3d::engine::createExternal(f3d::context::getSymbol("GLX", "invalid")); + std::ignore = f3d::engine::createExternal(f3d::context::getSymbol("libGLX.so", "invalid")); }); #endif diff --git a/library/testing/TestSDKExternalWindowEGL.cxx b/library/testing/TestSDKExternalWindowEGL.cxx index cdf27b2fdc..f20efa5243 100644 --- a/library/testing/TestSDKExternalWindowEGL.cxx +++ b/library/testing/TestSDKExternalWindowEGL.cxx @@ -4,6 +4,7 @@ #include "engine.h" #include +#include int TestSDKExternalWindowEGL([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) { @@ -11,6 +12,37 @@ int TestSDKExternalWindowEGL([[maybe_unused]] int argc, [[maybe_unused]] char* a EGLDisplay eglDpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT = + reinterpret_cast(eglGetProcAddress("eglQueryDevicesEXT")); + PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = + reinterpret_cast( + eglGetProcAddress("eglGetPlatformDisplayEXT")); + PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT = + reinterpret_cast(eglGetProcAddress("eglQueryDeviceStringEXT")); + + EGLDeviceEXT devices[16]; + EGLint numDev = 0; + + if (eglQueryDevicesEXT) + { + eglQueryDevicesEXT(16, devices, &numDev); + + if (eglQueryDeviceStringEXT) + { + for (int i = 0; i < numDev; ++i) + { + const char* deviceExts = eglQueryDeviceStringEXT(devices[i], EGL_EXTENSIONS); + std::cout << "EGL device " << i << " extensions: " << (deviceExts ? deviceExts : "(none)") + << '\n'; + } + } + + if (numDev > 0 && eglGetPlatformDisplayEXT) + { + eglDpy = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, devices[0], nullptr); + } + } + // initialize EGLint major, minor; eglInitialize(eglDpy, &major, &minor); @@ -45,6 +77,8 @@ int TestSDKExternalWindowEGL([[maybe_unused]] int argc, [[maybe_unused]] char* a eng.getWindow(), std::string(argv[1]) + "baselines/", argv[2], "TestSDKExternalWindowEGL")); // terminate EGL when finished + eglDestroyContext(eglDpy, eglCtx); + eglDestroySurface(eglDpy, eglSurf); eglTerminate(eglDpy); return test.result(); diff --git a/library/testing/TestSDKExternalWindowOSMesa.cxx b/library/testing/TestSDKExternalWindowOSMesa.cxx index 29c638db0f..a0ce4f8f34 100644 --- a/library/testing/TestSDKExternalWindowOSMesa.cxx +++ b/library/testing/TestSDKExternalWindowOSMesa.cxx @@ -3,6 +3,13 @@ #include "engine.h" +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#define GLAPI extern +#include +#endif + #include int TestSDKExternalWindowOSMesa([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) @@ -13,7 +20,10 @@ int TestSDKExternalWindowOSMesa([[maybe_unused]] int argc, [[maybe_unused]] char std::vector buffer(size[0] * size[1] * 4); // Create an OSMesa context - OSMesaContext ctx = OSMesaCreateContext(OSMESA_RGBA, nullptr); + static const int attribs[] = { OSMESA_FORMAT, OSMESA_RGBA, OSMESA_DEPTH_BITS, 32, OSMESA_PROFILE, + OSMESA_CORE_PROFILE, OSMESA_CONTEXT_MAJOR_VERSION, 3, OSMESA_CONTEXT_MINOR_VERSION, 2, 0 }; + + OSMesaContext ctx = OSMesaCreateContextAttribs(attribs, nullptr); if (!ctx) { std::cerr << "OSMesa context creation failed!\n"; diff --git a/library/testing/TestSDKHelpers.h b/library/testing/TestSDKHelpers.h index fde5b1f043..a351fd8ad9 100644 --- a/library/testing/TestSDKHelpers.h +++ b/library/testing/TestSDKHelpers.h @@ -1,6 +1,7 @@ #ifndef TestSDKHelpers_h #define TestSDKHelpers_h +#include #include #include @@ -10,6 +11,20 @@ namespace TestSDKHelpers { +inline f3d::engine CreateOffscreenEngine(const std::string& renderingBackend) +{ + if (renderingBackend == "osmesa") + { + return f3d::engine::createOSMesa(); + } + + if (renderingBackend == "egl") + { + return f3d::engine::createEGL(); + } + + return f3d::engine::create(true); +} inline bool RenderTest(const f3d::image& img, const std::string& baselinePath, const std::string& outputPath, const std::string& name, double threshold = 0.05) diff --git a/library/testing/TestSDKInteractorCallBack.cxx b/library/testing/TestSDKInteractorCallBack.cxx index a6969edbf4..df7ab4810e 100644 --- a/library/testing/TestSDKInteractorCallBack.cxx +++ b/library/testing/TestSDKInteractorCallBack.cxx @@ -11,11 +11,12 @@ using mod_t = f3d::interaction_bind_t::ModifierKeys; -int TestSDKInteractorCallBack([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKInteractorCallBack([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::scene& sce = eng.getScene(); f3d::window& win = eng.getWindow(); f3d::interactor& inter = eng.getInteractor(); diff --git a/library/testing/TestSDKInteractorCommand.cxx b/library/testing/TestSDKInteractorCommand.cxx index 819a5ea2fe..72953b26a9 100644 --- a/library/testing/TestSDKInteractorCommand.cxx +++ b/library/testing/TestSDKInteractorCommand.cxx @@ -1,4 +1,5 @@ #include "PseudoUnitTest.h" +#include "TestSDKHelpers.h" #include #include @@ -6,9 +7,10 @@ #include #include -int TestSDKInteractorCommand([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKInteractorCommand([[maybe_unused]] int argc, char* argv[]) { - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::options& options = eng.getOptions(); f3d::interactor& inter = eng.getInteractor(); diff --git a/library/testing/TestSDKInteractorDocumentation.cxx b/library/testing/TestSDKInteractorDocumentation.cxx index 4c2bf306e6..09b82dfabd 100644 --- a/library/testing/TestSDKInteractorDocumentation.cxx +++ b/library/testing/TestSDKInteractorDocumentation.cxx @@ -1,4 +1,5 @@ #include "PseudoUnitTest.h" +#include "TestSDKHelpers.h" #include #include @@ -10,9 +11,10 @@ constexpr int nBindsCamera = 9; constexpr std::string_view initDoc = "Orthographic Projection"; constexpr std::string_view initVal = "Unset"; -int TestSDKInteractorDocumentation([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKInteractorDocumentation([[maybe_unused]] int argc, char* argv[]) { - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::interactor& inter = eng.getInteractor(); // Avoid testing something that changes often diff --git a/library/testing/TestSDKInteractorDropFullScene.cxx b/library/testing/TestSDKInteractorDropFullScene.cxx index 1a74a0e232..6b8cd82fb3 100644 --- a/library/testing/TestSDKInteractorDropFullScene.cxx +++ b/library/testing/TestSDKInteractorDropFullScene.cxx @@ -8,11 +8,12 @@ #include -int TestSDKInteractorDropFullScene([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKInteractorDropFullScene([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); std::ignore = eng.getOptions(); f3d::window& win = eng.getWindow(); f3d::interactor& inter = eng.getInteractor(); diff --git a/library/testing/TestSDKMultiColoring.cxx b/library/testing/TestSDKMultiColoring.cxx index 77b1ad6c5d..ef25d474ca 100644 --- a/library/testing/TestSDKMultiColoring.cxx +++ b/library/testing/TestSDKMultiColoring.cxx @@ -9,12 +9,13 @@ #include -int TestSDKMultiColoring([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKMultiColoring([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; f3d::log::setVerboseLevel(f3d::log::VerboseLevel::DEBUG); - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::scene& sce = eng.getScene(); f3d::options& opt = eng.getOptions(); diff --git a/library/testing/TestSDKMultiOptions.cxx b/library/testing/TestSDKMultiOptions.cxx index b847827a77..b45a012027 100644 --- a/library/testing/TestSDKMultiOptions.cxx +++ b/library/testing/TestSDKMultiOptions.cxx @@ -9,12 +9,13 @@ #include -int TestSDKMultiOptions([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKMultiOptions([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; f3d::log::setVerboseLevel(f3d::log::VerboseLevel::DEBUG); - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::scene& sce = eng.getScene(); f3d::options& opt = eng.getOptions(); f3d::window& win = eng.getWindow(); diff --git a/library/testing/TestSDKNotification.cxx b/library/testing/TestSDKNotification.cxx index 5cb1a82a84..e54a6850fc 100644 --- a/library/testing/TestSDKNotification.cxx +++ b/library/testing/TestSDKNotification.cxx @@ -17,8 +17,11 @@ int TestSDKNotification([[maybe_unused]] int argc, [[maybe_unused]] char* argv[] std::string dataPath = std::string(argv[1]) + "data/cow.vtp"; std::string baselinePath = std::string(argv[1]) + "baselines/"; std::string outputPath = std::string(argv[2]); + std::string renderingBackend = std::string(argv[4]); - f3d::engine eng = f3d::engine::create(true); + f3d::log::setVerboseLevel(f3d::log::VerboseLevel::DEBUG); + + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::window& win = eng.getWindow(); f3d::options& opt = eng.getOptions(); f3d::scene& sce = eng.getScene(); diff --git a/library/testing/TestSDKRenderFinalShader.cxx b/library/testing/TestSDKRenderFinalShader.cxx index ee64b654d5..02433ad038 100644 --- a/library/testing/TestSDKRenderFinalShader.cxx +++ b/library/testing/TestSDKRenderFinalShader.cxx @@ -6,11 +6,12 @@ #include #include -int TestSDKRenderFinalShader([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKRenderFinalShader([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::window& win = eng.getWindow(); win.setSize(300, 300); diff --git a/library/testing/TestSDKScene.cxx b/library/testing/TestSDKScene.cxx index fc86e06b42..6cef36d20f 100644 --- a/library/testing/TestSDKScene.cxx +++ b/library/testing/TestSDKScene.cxx @@ -13,7 +13,8 @@ int TestSDKScene([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) PseudoUnitTest test; f3d::log::setVerboseLevel(f3d::log::VerboseLevel::DEBUG); - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = argv[4]; + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::scene& sce = eng.getScene(); f3d::window& win = eng.getWindow().setSize(300, 300); @@ -62,7 +63,7 @@ int TestSDKScene([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) // invalid reader { - f3d::engine engine = f3d::engine::create(true); + f3d::engine engine = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); engine.getOptions().scene.force_reader = "INVALID"; f3d::scene& scene = engine.getScene(); test.expect( diff --git a/library/testing/TestSDKSceneFromBuffer.cxx b/library/testing/TestSDKSceneFromBuffer.cxx index 95d09eb5f3..7e89352ebc 100644 --- a/library/testing/TestSDKSceneFromBuffer.cxx +++ b/library/testing/TestSDKSceneFromBuffer.cxx @@ -6,12 +6,13 @@ #include #include -int TestSDKSceneFromBuffer([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKSceneFromBuffer([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; f3d::log::setVerboseLevel(f3d::log::VerboseLevel::DEBUG); - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::scene& sce = eng.getScene(); f3d::options& opt = eng.getOptions(); diff --git a/library/testing/TestSDKSceneFromMemory.cxx b/library/testing/TestSDKSceneFromMemory.cxx index a0549c585a..d848ae1189 100644 --- a/library/testing/TestSDKSceneFromMemory.cxx +++ b/library/testing/TestSDKSceneFromMemory.cxx @@ -6,12 +6,13 @@ #include #include -int TestSDKSceneFromMemory([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKSceneFromMemory([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; f3d::log::setVerboseLevel(f3d::log::VerboseLevel::DEBUG); - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::scene& sce = eng.getScene(); f3d::window& win = eng.getWindow().setSize(300, 300); diff --git a/library/testing/TestSDKSceneFromMemoryZeroCopy.cxx b/library/testing/TestSDKSceneFromMemoryZeroCopy.cxx index f25c9ec906..d8d3d20ceb 100644 --- a/library/testing/TestSDKSceneFromMemoryZeroCopy.cxx +++ b/library/testing/TestSDKSceneFromMemoryZeroCopy.cxx @@ -310,12 +310,13 @@ class AnimatedZeroCopyMesh : public f3d::mesh_view const WavyGridMesh& Grid; }; -int TestSDKSceneFromMemoryZeroCopy([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKSceneFromMemoryZeroCopy([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; f3d::log::setVerboseLevel(f3d::log::VerboseLevel::DEBUG); - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::scene& sce = eng.getScene(); f3d::interactor& inter = eng.getInteractor(); f3d::window& win = eng.getWindow().setSize(500, 500); diff --git a/library/testing/TestSDKSceneFromMemoryZeroCopyExceptions.cxx b/library/testing/TestSDKSceneFromMemoryZeroCopyExceptions.cxx index 1648c6a8d8..7ae3feb540 100644 --- a/library/testing/TestSDKSceneFromMemoryZeroCopyExceptions.cxx +++ b/library/testing/TestSDKSceneFromMemoryZeroCopyExceptions.cxx @@ -8,13 +8,13 @@ #include #include -int TestSDKSceneFromMemoryZeroCopyExceptions( - [[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKSceneFromMemoryZeroCopyExceptions([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; f3d::log::setVerboseLevel(f3d::log::VerboseLevel::DEBUG); - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::scene& sce = eng.getScene(); test.expect("add nullptr", [&]() { sce.add(nullptr); }); diff --git a/library/testing/TestSDKSceneInvalidHeader.cxx b/library/testing/TestSDKSceneInvalidHeader.cxx index dbf267d41e..77f08d203c 100644 --- a/library/testing/TestSDKSceneInvalidHeader.cxx +++ b/library/testing/TestSDKSceneInvalidHeader.cxx @@ -5,12 +5,13 @@ #include #include -int TestSDKSceneInvalidHeader([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKSceneInvalidHeader([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; f3d::log::setVerboseLevel(f3d::log::VerboseLevel::DEBUG); - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::scene& sce = eng.getScene(); // Test file logic diff --git a/library/testing/TestSDKTriggerInteractions.cxx b/library/testing/TestSDKTriggerInteractions.cxx index b59e2b7246..88d694253b 100644 --- a/library/testing/TestSDKTriggerInteractions.cxx +++ b/library/testing/TestSDKTriggerInteractions.cxx @@ -8,17 +8,19 @@ struct TestTriggerHelper { - TestTriggerHelper(std::string dataPath, std::string baselinePath, std::string outputPath) + TestTriggerHelper(std::string dataPath, std::string baselinePath, std::string outputPath, + std::string renderingBackend) : DataPath(std::move(dataPath)) , BaselinePath(std::move(baselinePath)) , OutputPath(std::move(outputPath)) + , RenderingBackend(std::move(renderingBackend)) { } template void operator()(Func&& func) const { - f3d::engine engine = f3d::engine::create(true); + f3d::engine engine = TestSDKHelpers::CreateOffscreenEngine(this->RenderingBackend); engine.getWindow().setSize(300, 300); engine.getScene().add(this->DataPath); engine.getWindow().render(); @@ -44,14 +46,15 @@ struct TestTriggerHelper std::string DataPath; std::string BaselinePath; std::string OutputPath; + std::string RenderingBackend; }; -int TestSDKTriggerInteractions([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKTriggerInteractions([[maybe_unused]] int argc, char* argv[]) { try { - TestTriggerHelper helper( - std::string(argv[1]) + "/data/cow.vtp", std::string(argv[1]) + "baselines/", argv[2]); + TestTriggerHelper helper(std::string(argv[1]) + "/data/cow.vtp", + std::string(argv[1]) + "baselines/", argv[2], argv[4]); // Trigger mouse wheel backward and check if it zoomed out helper("TestSDKTriggerInteractionsWheelBackward", [](f3d::engine& engine) { diff --git a/library/testing/TestSDKUI.cxx b/library/testing/TestSDKUI.cxx index ef339daddf..b1b9e3a25f 100644 --- a/library/testing/TestSDKUI.cxx +++ b/library/testing/TestSDKUI.cxx @@ -7,11 +7,12 @@ #include #include -int TestSDKUI([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +int TestSDKUI([[maybe_unused]] int argc, char* argv[]) { PseudoUnitTest test; - f3d::engine eng = f3d::engine::create(true); + std::string renderingBackend = std::string(argv[4]); + f3d::engine eng = TestSDKHelpers::CreateOffscreenEngine(renderingBackend); f3d::window& win = eng.getWindow(); win.setSize(300, 300); diff --git a/library/testing/TestTestSDKHelpers.cxx b/library/testing/TestTestSDKHelpers.cxx index 1042e11a32..d01729984c 100644 --- a/library/testing/TestTestSDKHelpers.cxx +++ b/library/testing/TestTestSDKHelpers.cxx @@ -12,6 +12,18 @@ int TestTestSDKHelpers([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) { PseudoUnitTest test; + // Coverage of CreateOffscreenEngine + for (auto backend : { "osmesa", "egl", "auto" }) + { + try + { + std::ignore = TestSDKHelpers::CreateOffscreenEngine(backend); + } + catch (...) + { + } + } + f3d::engine eng = f3d::engine::create(true); f3d::scene& scene = eng.getScene(); f3d::window& win = eng.getWindow(); diff --git a/python/testing/CMakeLists.txt b/python/testing/CMakeLists.txt index c97d1faa58..2278664bed 100644 --- a/python/testing/CMakeLists.txt +++ b/python/testing/CMakeLists.txt @@ -48,6 +48,7 @@ foreach(test ${pyf3dTests_list}) LABELS "libf3d;bindings;python" ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}$<${F3D_MULTI_CONFIG_GENERATOR}:/$>" FAIL_REGULAR_EXPRESSION "[^X]FAILURES" + TIMEOUT 180 ) if (NOT F3D_TESTING_ENABLE_RENDERING_TESTS AND NOT ${test} IN_LIST pyf3dTestsNoRender_list) set_tests_properties(libf3d_bindings_py::${TName} PROPERTIES DISABLED ON) diff --git a/testing/data/libEGL.so b/testing/data/libEGL.so new file mode 100644 index 0000000000..ab06427c9c --- /dev/null +++ b/testing/data/libEGL.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:78cb0873d9e8dc6829e02c9802fe4dc6658a50c0dcde1b3515bbd87f82097bf7 +size 20 diff --git a/testing/data/libEGL.so.1 b/testing/data/libEGL.so.1 new file mode 100644 index 0000000000..ab06427c9c --- /dev/null +++ b/testing/data/libEGL.so.1 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:78cb0873d9e8dc6829e02c9802fe4dc6658a50c0dcde1b3515bbd87f82097bf7 +size 20 diff --git a/testing/data/libOSMesa.so b/testing/data/libOSMesa.so new file mode 100644 index 0000000000..f26c6c707c --- /dev/null +++ b/testing/data/libOSMesa.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c21a3d04c57298f153b0e30104d4c84466954c734284b6692d9a12c9cb2a8e4f +size 23 diff --git a/testing/data/libOSMesa.so.6 b/testing/data/libOSMesa.so.6 new file mode 100644 index 0000000000..f26c6c707c --- /dev/null +++ b/testing/data/libOSMesa.so.6 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c21a3d04c57298f153b0e30104d4c84466954c734284b6692d9a12c9cb2a8e4f +size 23 diff --git a/testing/data/libOSMesa.so.8 b/testing/data/libOSMesa.so.8 new file mode 100644 index 0000000000..f26c6c707c --- /dev/null +++ b/testing/data/libOSMesa.so.8 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c21a3d04c57298f153b0e30104d4c84466954c734284b6692d9a12c9cb2a8e4f +size 23 diff --git a/vtkext/public/module/F3DUtils.cxx b/vtkext/public/module/F3DUtils.cxx index d0fe8db887..78fc9656b6 100644 --- a/vtkext/public/module/F3DUtils.cxx +++ b/vtkext/public/module/F3DUtils.cxx @@ -83,6 +83,7 @@ double F3DUtils::getDPIScale() if (dpi == 0) { vtkWarningWithObjectMacro(nullptr, "Fail to get DPI."); + dpi = baseDPI; } #endif