diff --git a/.gitattributes b/.gitattributes index 47b33cec..fc66749c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,5 +7,5 @@ *.pro eol=lf *.properties eol=lf *.xml eol=lf - gradlew eol=lf +*.vrs filter=lfs diff=lfs merge=lfs -text diff --git a/.github/workflows/build-addon-on-push.yml b/.github/workflows/build-addon-on-push.yml index 7dab3f70..bef34817 100644 --- a/.github/workflows/build-addon-on-push.yml +++ b/.github/workflows/build-addon-on-push.yml @@ -187,9 +187,15 @@ jobs: runs-on: [Windows, self-hosted, gpu] needs: build + env: + GODOT_VERSION: "4.3-beta2" + XRSIM_VERSION: "65.0.0" + steps: - name: Checkout code uses: actions/checkout@v3 + with: + lfs: 'true' - name: Install Chocolatey run: | @@ -201,8 +207,7 @@ jobs: - name: Download Godot run: | - # @todo Download an actual Godot build! - Invoke-WebRequest -Uri "https://github.com/godotengine/godot-builds/releases/download/4.3-beta2/Godot_v4.3-beta2_win64.exe.zip" -OutFile "godot.zip" + Invoke-WebRequest -Uri "https://github.com/godotengine/godot-builds/releases/download/${{ env.GODOT_VERSION }}/Godot_v${{ env.GODOT_VERSION }}_win64.exe.zip" -OutFile "godot.zip" - name: Extract Godot run: | @@ -214,7 +219,7 @@ jobs: - name: Download Meta XR Simulator run: | - Invoke-WebRequest -Uri "https://npm.developer.oculus.com/com.meta.xr.simulator/-/com.meta.xr.simulator-65.0.0.tgz" -OutFile MetaXRSimulator.tgz + Invoke-WebRequest -Uri "https://npm.developer.oculus.com/com.meta.xr.simulator/-/com.meta.xr.simulator-${{ env.XRSIM_VERSION }}.tgz" -OutFile MetaXRSimulator.tgz - name: Extract Meta XR Simulator run: | @@ -242,16 +247,35 @@ jobs: name: build-files-windows path: build-files-windows - - name: Copy Windows build of the addon into the demo project + - name: Copy Windows build of the addon into the demo and samples project run: | mkdir -p demo/addons/godotopenxrvendors/.bin/windows/ cp -r build-files-windows/* demo/addons/godotopenxrvendors/.bin/windows/ - - name: Import the demo project + $sampleProjects = Get-ChildItem -Path "samples/" -Directory + foreach ($project in $sampleProjects) { + cp -r demo/addons "$($project.FullName)/" + } + + - name: Import the demo and sample projects run: | - $godot = "Godot_v4.3-beta2_win64.exe" + $godot = "Godot_v${{ env.GODOT_VERSION }}_win64.exe" + + Write-Output "" + Write-Output " ** Importing demo project" + Write-Output "" + Start-Process -FilePath "$godot" -ArgumentList "--path demo --import --headless" -NoNewWindow -Wait + $sampleProjects = Get-ChildItem -Path "samples/" -Directory + foreach ($project in $sampleProjects) { + Write-Output "" + Write-Output " ** Importing project $($project.Name)" + Write-Output "" + + Start-Process -FilePath "$godot" -ArgumentList "--path $($project.FullName) --import --headless" -NoNewWindow -Wait + } + - name: Launch a synthetic environment run: | # Ensure a synthetic environment isn't already running. @@ -267,7 +291,12 @@ jobs: run: | $jsonPath = "$env:AppData\MetaXR\MetaXrSimulator\persistent_data.json" - $vrsFiles = Get-ChildItem -Path tests/vrs -Filter *.vrs + $demoVrsFiles = Get-ChildItem -Path "demo/tests/" -Recurse -Filter *.vrs + $sampleVrsFiles = Get-ChildItem -Path "samples/*/tests/" -Recurse -Filter *.vrs + $vrsFiles = @() + $vrsFiles += $demoVrsFiles + $vrsFiles += $sampleVrsFiles + foreach ($file in $vrsFiles) { $replayPath = Join-Path -Path $file.DirectoryName -ChildPath ($file.BaseName + "-replay.vrs") $jsonContent = @{ @@ -285,11 +314,17 @@ jobs: Set-Content -Path $jsonPath -Value $jsonContent echo "$jsonContent" - $godot = "Godot_v4.3-beta2_win64.exe" + $godot = "Godot_v${{ env.GODOT_VERSION }}_win64.exe" $timeout = 300 $waitTime = 0 - $process = Start-Process -FilePath "$godot" -ArgumentList "--path demo --rendering-method mobile --verbose -- --quit-with-openxr" -NoNewWindow -PassThru + $projectPath = (Get-Item $file.DirectoryName).Parent + + Write-Output "" + Write-Output " ** Running VRS $($file.Name) on $($projectPath.Name) project" + Write-Output "" + + $process = Start-Process -FilePath "$godot" -ArgumentList "--path $($projectPath.FullName) --rendering-method mobile --verbose -- --xrsim-automated-tests" -NoNewWindow -PassThru while ($process.HasExited -eq $false -and $waitTime -lt $timeout) { Start-Sleep -Seconds 1 @@ -317,14 +352,17 @@ jobs: - name: Copy vrs_pixmatch.py from Meta XR Simulator run: | $scriptsPath = "C:\Meta\package\MetaXRSimulator\scripts" - cp "$scriptsPath\requirements.txt" tests\vrs\ - cp "$scriptsPath\vrs_pixmatch.py" tests\vrs\ + mkdir test-scripts + cp "$scriptsPath/requirements.txt" test-scripts/ + cp "$scriptsPath/vrs_pixmatch.py" test-scripts/ - name: Upload VRS artifacts uses: actions/upload-artifact@v3 with: name: ReplayVRS - path: tests/vrs/**/* + path: | + test-scripts/ + **/*/tests/*.vrs compare_vrs_replay: name: "Compare VRS replay" @@ -349,23 +387,27 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -r tests/vrs/requirements.txt + pip install -r tests/vrs/test-scripts/requirements.txt - name: Compare VRS replay with expected recordings run: | cd tests/vrs/ # Fix bugs in vrs_pixmatch.py script. - patch -p0 < ../../thirdparty/meta_xr_simulator/vrs_pixmatch.patch + (cd test-scripts && patch -p0 < ../../../thirdparty/meta_xr_simulator/vrs_pixmatch.patch) mkdir diffs - for replay in *-replay.vrs; do + for replay in $(find . -name \*-replay.vrs); do + echo " ==> Checking $replay..." expected=$(echo $replay | sed -e 's/-replay.vrs$/.vrs/') - python vrs_pixmatch.py "$replay" "$expected" --threshold 0.4 --best_match_pixels_diff_threshold 40000 --diffs_output_path diffs + diff_path="diffs/$replay" + mkdir -p "$diff_path" + python test-scripts/vrs_pixmatch.py "$replay" "$expected" --threshold 0.4 --best_match_pixels_diff_threshold 40000 --diffs_output_path "$diff_path" done - name: Upload VRS diff artifacts uses: actions/upload-artifact@v3 + if: always() with: name: ReplayVRSDiff path: tests/vrs/diffs/**/* diff --git a/demo/main.gd b/demo/main.gd index 1416a168..61e332a1 100644 --- a/demo/main.gd +++ b/demo/main.gd @@ -51,7 +51,7 @@ func _ready(): func _on_session_stopping() -> void: - if "--quit-with-openxr" in OS.get_cmdline_user_args(): + if "--xrsim-automated-tests" in OS.get_cmdline_user_args(): # When we're running tests via the XR Simulator, it will end the OpenXR # session automatically, and in that case, we want to quit. get_tree().quit() diff --git a/demo/tests/test1.vrs b/demo/tests/test1.vrs new file mode 100644 index 00000000..b530c9c8 --- /dev/null +++ b/demo/tests/test1.vrs @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3012723bcc789feb2d3ca222f1f966adee40336b651f64f05334597fa99f575e +size 5534256 diff --git a/samples/fb-composition-layers-sample/example_panel.gd b/samples/fb-composition-layers-sample/example_panel.gd index 6e432b40..9c066263 100644 --- a/samples/fb-composition-layers-sample/example_panel.gd +++ b/samples/fb-composition-layers-sample/example_panel.gd @@ -12,7 +12,10 @@ func _ready() -> void: $Label.text = display_string func _process(delta: float) -> void: - $Label.position = Vector2(start_pos.x + (100.0 * sin(Time.get_ticks_msec() * 0.001 * 2)), start_pos.y) + if not "--xrsim-automated-tests" in OS.get_cmdline_user_args(): + # When we're running tests via the XR Simulator, we don't want the text + # to be animated, which can lead to differences in the screenshots. + $Label.position = Vector2(start_pos.x + (100.0 * sin(Time.get_ticks_msec() * 0.001 * 2)), start_pos.y) func update_pointers(p_position_left: Vector2, p_position_right: Vector2) -> void: pointer_left.position = size * p_position_left - (0.5 * pointer_left.size) diff --git a/samples/fb-composition-layers-sample/main.gd b/samples/fb-composition-layers-sample/main.gd index bce94c17..20a4c02f 100644 --- a/samples/fb-composition-layers-sample/main.gd +++ b/samples/fb-composition-layers-sample/main.gd @@ -35,6 +35,7 @@ var xr_interface : XRInterface = null func _ready(): xr_interface = XRServer.find_interface("OpenXR") if xr_interface and xr_interface.is_initialized(): + xr_interface.session_stopping.connect(self._on_session_stopping) var vp: Viewport = get_viewport() vp.use_xr = true DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED) @@ -46,6 +47,13 @@ func _ready(): add_child(node_3d) +func _on_session_stopping() -> void: + if "--xrsim-automated-tests" in OS.get_cmdline_user_args(): + # When we're running tests via the XR Simulator, it will end the OpenXR + # session automatically, and in that case, we want to quit. + get_tree().quit() + + func _process(_delta: float) -> void: var ray_intersection_left: Vector2 var ray_intersection_right: Vector2 diff --git a/samples/fb-composition-layers-sample/tests/test1.vrs b/samples/fb-composition-layers-sample/tests/test1.vrs new file mode 100644 index 00000000..9495b6c8 --- /dev/null +++ b/samples/fb-composition-layers-sample/tests/test1.vrs @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c62f8f3e93d3aeae449aba1e60948e5d8c2886d3c29b4b383c939d6caa651563 +size 12648550 diff --git a/samples/fb-hand-tracking-sample/main.gd b/samples/fb-hand-tracking-sample/main.gd index 2871742f..ed6a01c0 100644 --- a/samples/fb-hand-tracking-sample/main.gd +++ b/samples/fb-hand-tracking-sample/main.gd @@ -39,11 +39,19 @@ var right_capsules_loaded := false func _ready() -> void: openxr_interface = XRServer.find_interface("OpenXR") if openxr_interface and openxr_interface.initialize(): + openxr_interface.session_stopping.connect(self._on_session_stopping) get_viewport().use_xr = true DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED) fb_capsule_ext = Engine.get_singleton("OpenXRFbHandTrackingCapsulesExtensionWrapper") +func _on_session_stopping() -> void: + if "--xrsim-automated-tests" in OS.get_cmdline_user_args(): + # When we're running tests via the XR Simulator, it will end the OpenXR + # session automatically, and in that case, we want to quit. + get_tree().quit() + + func _process(delta): if countdown_to_group_hand_meshes > 0: countdown_to_group_hand_meshes -= 1 diff --git a/samples/fb-passthrough-sample/geometry.gd b/samples/fb-passthrough-sample/geometry.gd index fa4e82f6..33e07894 100644 --- a/samples/fb-passthrough-sample/geometry.gd +++ b/samples/fb-passthrough-sample/geometry.gd @@ -2,4 +2,7 @@ extends OpenXRFbPassthroughGeometry func _process(delta: float) -> void: - position.x = 3 * sin(Time.get_ticks_msec() / 1000.0) + if not "--xrsim-automated-tests" in OS.get_cmdline_user_args(): + # When we're running tests via the XR Simulator, we don't want the text + # to be animated, which can lead to differences in the screenshots. + position.x = 3 * sin(Time.get_ticks_msec() / 1000.0) diff --git a/samples/fb-passthrough-sample/main.gd b/samples/fb-passthrough-sample/main.gd index b81ec4a6..63727c62 100644 --- a/samples/fb-passthrough-sample/main.gd +++ b/samples/fb-passthrough-sample/main.gd @@ -30,6 +30,7 @@ var countdown_to_recenter_hmd: int = 3 func _ready() -> void: openxr_interface = XRServer.find_interface("OpenXR") if openxr_interface and openxr_interface.initialize(): + openxr_interface.session_stopping.connect(self._on_session_stopping) get_viewport().use_xr = true DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED) @@ -55,6 +56,13 @@ func _ready() -> void: mono_map_mat.albedo_texture = curve_texture +func _on_session_stopping() -> void: + if "--xrsim-automated-tests" in OS.get_cmdline_user_args(): + # When we're running tests via the XR Simulator, it will end the OpenXR + # session automatically, and in that case, we want to quit. + get_tree().quit() + + func _process(_delta: float) -> void: if countdown_to_recenter_hmd > 0: countdown_to_recenter_hmd -= 1 diff --git a/samples/fb-passthrough-sample/tests/test1.vrs b/samples/fb-passthrough-sample/tests/test1.vrs new file mode 100644 index 00000000..b3125dfb --- /dev/null +++ b/samples/fb-passthrough-sample/tests/test1.vrs @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:50cfb919dd9e47797dfb173bdd4ed8a5eddd198104eac55787271cb63ae3df74 +size 97017992 diff --git a/tests/vrs/simulation1.vrs b/tests/vrs/simulation1.vrs deleted file mode 100644 index d647b6db..00000000 Binary files a/tests/vrs/simulation1.vrs and /dev/null differ