diff --git a/.github/workflows/macos_builds.yml b/.github/workflows/macos_builds.yml index 41ce8da56f77..97342852e56f 100644 --- a/.github/workflows/macos_builds.yml +++ b/.github/workflows/macos_builds.yml @@ -8,6 +8,7 @@ env: SCONS_FLAGS: >- dev_mode=yes module_text_server_fb_enabled=yes + angle=yes "accesskit_sdk_path=${{ github.workspace }}/accesskit-c-0.21.1/" jobs: @@ -72,17 +73,28 @@ jobs: fi continue-on-error: true + - name: Setup ANGLE + id: angle + run: | + if python ./misc/scripts/install_angle.py; then + echo "ANGLE_ENABLED=yes" >> "$GITHUB_OUTPUT" + else + echo "::warning::macOS: ANGLE installation failed, building without ANGLE support." + echo "ANGLE_ENABLED=no" >> "$GITHUB_OUTPUT" + fi + continue-on-error: true + - name: Compilation (x86_64) uses: ./.github/actions/godot-build with: - scons-flags: ${{ env.SCONS_FLAGS }} ${{ matrix.scons-flags }} arch=x86_64 vulkan=${{ steps.vulkan-sdk.outputs.VULKAN_ENABLED }} + scons-flags: ${{ env.SCONS_FLAGS }} ${{ matrix.scons-flags }} arch=x86_64 vulkan=${{ steps.vulkan-sdk.outputs.VULKAN_ENABLED }} angle=${{ steps.angle.outputs.ANGLE_ENABLED }} platform: macos target: ${{ matrix.target }} - name: Compilation (arm64) uses: ./.github/actions/godot-build with: - scons-flags: ${{ env.SCONS_FLAGS }} ${{ matrix.scons-flags }} arch=arm64 vulkan=${{ steps.vulkan-sdk.outputs.VULKAN_ENABLED }} + scons-flags: ${{ env.SCONS_FLAGS }} ${{ matrix.scons-flags }} arch=arm64 vulkan=${{ steps.vulkan-sdk.outputs.VULKAN_ENABLED }} angle=${{ steps.angle.outputs.ANGLE_ENABLED }} platform: macos target: ${{ matrix.target }} diff --git a/.github/workflows/windows_builds.yml b/.github/workflows/windows_builds.yml index 5943bf54a892..572eb3299e7b 100644 --- a/.github/workflows/windows_builds.yml +++ b/.github/workflows/windows_builds.yml @@ -9,7 +9,7 @@ env: dev_mode=yes module_text_server_fb_enabled=yes debug_symbols=no - "angle_libs=${{ github.workspace }}/" + angle=yes "accesskit_sdk_path=${{ github.workspace }}/accesskit-c-0.21.1/" SCONS_CACHE_MSVC_CONFIG: true PYTHONIOENCODING: utf8 @@ -85,15 +85,15 @@ jobs: continue-on-error: true - name: Download pre-built ANGLE static libraries - uses: dsaltares/fetch-gh-release-asset@1.1.2 - with: - repo: godotengine/godot-angle-static - version: tags/chromium/6601.2 - file: godot-angle-static-x86_64-${{ matrix.compiler == 'gcc' && 'gcc' || 'msvc' }}-release.zip - target: angle/angle.zip - - - name: Extract pre-built ANGLE static libraries - run: Expand-Archive -Force angle/angle.zip ${{ github.workspace }}/ + shell: sh + id: angle + run: | + if python ./misc/scripts/install_angle.py; then + echo "ANGLE_ENABLED=yes" >> "$GITHUB_OUTPUT" + else + echo "::warning::Windows: ANGLE installation failed, building without ANGLE support." + echo "ANGLE_ENABLED=no" >> "$GITHUB_OUTPUT" + fi - name: Download pre-built AccessKit uses: dsaltares/fetch-gh-release-asset@1.1.2 @@ -109,7 +109,7 @@ jobs: - name: Compilation uses: ./.github/actions/godot-build with: - scons-flags: ${{ env.SCONS_FLAGS }} ${{ matrix.scons-flags }} d3d12=${{ steps.d3d12-sdk.outputs.D3D12_ENABLED }} + scons-flags: ${{ env.SCONS_FLAGS }} ${{ matrix.scons-flags }} d3d12=${{ steps.d3d12-sdk.outputs.D3D12_ENABLED }} angle=${{ steps.angle.outputs.ANGLE_ENABLED }} platform: windows target: ${{ matrix.target }} diff --git a/SConstruct b/SConstruct index 2b79b4f310de..2ed8f332b623 100644 --- a/SConstruct +++ b/SConstruct @@ -197,6 +197,9 @@ opts.Add(BoolVariable("xaudio2", "Enable the XAudio2 audio driver on supported p opts.Add(BoolVariable("vulkan", "Enable the Vulkan rendering driver", True)) opts.Add(BoolVariable("opengl3", "Enable the OpenGL/GLES3 rendering driver", True)) opts.Add(BoolVariable("d3d12", "Enable the Direct3D 12 rendering driver on supported platforms", False)) +opts.Add( + BoolVariable("angle", "Enable the ANGLE rendering driver for OpenGL/GLES3 fallback on supported platforms", False) +) opts.Add(BoolVariable("metal", "Enable the Metal rendering driver on supported platforms (Apple arm64 only)", False)) opts.Add(BoolVariable("use_volk", "Use the volk library to load the Vulkan loader dynamically", True)) opts.Add(BoolVariable("accesskit", "Use AccessKit C SDK", True)) diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index c54528d08fec..fbf500c37254 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -2980,7 +2980,7 @@ - [code]opengl3[/code], OpenGL 3.3 on desktop platforms, OpenGL ES 3.0 on mobile platforms, WebGL 2.0 on web. - [code]opengl3_angle[/code], OpenGL ES 3.0 using the ANGLE compatibility layer, supported on macOS (over native OpenGL) and Windows (over Direct3D 11). - [code]opengl3_es[/code], OpenGL ES 3.0 on Linux/BSD. - [b]Note:[/b] The availability of these options depends on whether the engine was compiled with support for them (determined by SCons options [code]opengl3[/code] and [code]angle_libs[/code]). + [b]Note:[/b] The availability of these options depends on whether the engine was compiled with support for them (determined by SCons options [code]opengl3[/code] and [code]angle[/code]). [b]Note:[/b] The actual rendering driver may be automatically changed by the engine as a result of a fallback, or a user-specified command line argument. To get the actual rendering driver that is used at runtime, use [method RenderingServer.get_current_rendering_driver_name] instead of reading this project setting's value. diff --git a/misc/scripts/install_angle.py b/misc/scripts/install_angle.py new file mode 100755 index 000000000000..358b118c93bf --- /dev/null +++ b/misc/scripts/install_angle.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python + +import os +import platform +import shutil +import sys +import urllib.request + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../")) + +from misc.utility.color import Ansi, color_print + +# Base Godot dependencies path +# If cross-compiling (no LOCALAPPDATA), we install in `bin` +deps_folder = os.getenv("LOCALAPPDATA") +if deps_folder: + deps_folder = os.path.join(deps_folder, "Godot", "build_deps") +else: + deps_folder = os.path.join("bin", "build_deps") + +# ANGLE +# Check for latest version: https://github.com/godotengine/godot-angle-static/releases/latest +angle_version = "chromium/7219" +angle_folder = os.path.join(deps_folder, "angle") + +# Create dependencies folder +if not os.path.exists(deps_folder): + os.makedirs(deps_folder) + +# Mesa NIR +print(f"Downloading ANGLE {angle_version} ...") +archs = [ + "arm64-llvm", + "x86_32-gcc", + "x86_32-llvm", + "x86_64-gcc", + "x86_64-llvm", +] +if platform.system() == "Windows": + # Only download MSVC libraries if we can build using it. + archs.append("arm64-msvc") + archs.append("x86_32-msvc") + archs.append("x86_64-msvc") +elif platform.system() == "Darwin": + # Only download macOS/iOS libraries if we can build for these platforms. + archs.append("arm64-ios") + archs.append("arm64-ios-sim") + archs.append("arm64-macos") + archs.append("x86_64-macos") + +for arch in archs: + angle_filename = f"godot-angle-static-{arch}-release.zip" + angle_archive = os.path.join(deps_folder, angle_filename) + angle_folder = os.path.join(deps_folder, f"angle-{arch}") + + if os.path.isfile(angle_archive): + os.remove(angle_archive) + print(f"Downloading ANGLE {angle_filename} ...") + urllib.request.urlretrieve( + f"https://github.com/godotengine/godot-angle-static/releases/download/{angle_version}/{angle_filename}", + angle_archive, + ) + if os.path.exists(angle_folder): + print(f"Removing existing local ANGLE installation in {angle_folder} ...") + shutil.rmtree(angle_folder) + print(f"Extracting ANGLE {angle_filename} to {angle_folder} ...") + shutil.unpack_archive(angle_archive, angle_folder) + os.remove(angle_archive) +print("ANGLE installed successfully.\n") + +# Complete message +color_print(f'{Ansi.GREEN}All ANGLE components were installed to "{deps_folder}" successfully!') +color_print(f'{Ansi.GREEN}You can now build Godot with statically linked ANGLE by running "scons angle=yes".') diff --git a/misc/scripts/install_d3d12_sdk_windows.py b/misc/scripts/install_d3d12_sdk_windows.py index e449248df658..33527326d932 100755 --- a/misc/scripts/install_d3d12_sdk_windows.py +++ b/misc/scripts/install_d3d12_sdk_windows.py @@ -63,9 +63,9 @@ "x86_64-llvm", "x86_64-msvc", ]: - mesa_filename = "godot-nir-static-" + arch + "-release.zip" + mesa_filename = f"godot-nir-static-{arch}-release.zip" mesa_archive = os.path.join(deps_folder, mesa_filename) - mesa_folder = os.path.join(deps_folder, "mesa-" + arch) + mesa_folder = os.path.join(deps_folder, f"mesa-{arch}") if os.path.isfile(mesa_archive): os.remove(mesa_archive) diff --git a/platform/macos/detect.py b/platform/macos/detect.py index de2f7bb25983..4a06aa99d9a4 100644 --- a/platform/macos/detect.py +++ b/platform/macos/detect.py @@ -27,6 +27,22 @@ def can_build(): def get_opts(): from SCons.Variables import BoolVariable, EnumVariable + # ANGLE dependencies folders. + build_deps_folder = os.path.join(str(os.getenv("HOME")), "Library", "Application Support") + if os.path.exists(build_deps_folder): + build_deps_folder = os.path.join(build_deps_folder, "Godot", "build_deps") + else: + # Cross-compiling, the deps install script puts things in `bin`. + # Getting an absolute path to it is a bit hacky in Python. + try: + import inspect + + caller_frame = inspect.stack()[1] + caller_script_dir = os.path.dirname(os.path.abspath(caller_frame[1])) + build_deps_folder = os.path.join(caller_script_dir, "bin", "build_deps") + except Exception: # Give up. + build_deps_folder = "" + return [ ("osxcross_sdk", "OSXCross SDK version", "darwin16"), ("SWIFT_FRONTEND", "Path to the swift-frontend binary", ""), @@ -37,7 +53,11 @@ def get_opts(): BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN)", False), BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN)", False), BoolVariable("use_coverage", "Use instrumentation codes in the binary (e.g. for code coverage)", False), - ("angle_libs", "Path to the ANGLE static libraries", ""), + ( + "angle_libs", + "Path to the ANGLE static libraries", + os.path.join(build_deps_folder, "angle"), + ), ( "bundle_sign_identity", "The 'Full Name', 'Common Name' or SHA-1 hash of the signing identity used to sign editor .app bundle.", @@ -251,7 +271,12 @@ def configure(env: "SConsEnvironment"): env.Append(CPPDEFINES=["GLES3_ENABLED"]) if env["angle_libs"] != "": env.AppendUnique(CPPDEFINES=["EGL_STATIC"]) - env.Append(LINKFLAGS=["-L" + env["angle_libs"]]) + + angle_libs = env["angle_libs"] + if os.path.exists(env["angle_libs"] + "-" + env["arch"] + "-llvm"): + angle_libs = env["angle_libs"] + "-" + env["arch"] + "-llvm" + env.Append(LINKFLAGS=["-L" + angle_libs]) + env.Append(LINKFLAGS=["-lANGLE.macos." + env["arch"]]) env.Append(LINKFLAGS=["-lEGL.macos." + env["arch"]]) env.Append(LINKFLAGS=["-lGLES.macos." + env["arch"]]) diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 28861ffa1268..1c28147c84a1 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -166,10 +166,10 @@ def get_opts(): mingw = os.getenv("MINGW_PREFIX", "") - # Direct3D 12 SDK dependencies folder. - d3d12_deps_folder = os.getenv("LOCALAPPDATA") - if d3d12_deps_folder: - d3d12_deps_folder = os.path.join(d3d12_deps_folder, "Godot", "build_deps") + # Direct3D 12 SDK and ANGLE dependencies folders. + build_deps_folder = os.getenv("LOCALAPPDATA") + if build_deps_folder: + build_deps_folder = os.path.join(build_deps_folder, "Godot", "build_deps") else: # Cross-compiling, the deps install script puts things in `bin`. # Getting an absolute path to it is a bit hacky in Python. @@ -178,9 +178,9 @@ def get_opts(): caller_frame = inspect.stack()[1] caller_script_dir = os.path.dirname(os.path.abspath(caller_frame[1])) - d3d12_deps_folder = os.path.join(caller_script_dir, "bin", "build_deps") + build_deps_folder = os.path.join(caller_script_dir, "bin", "build_deps") except Exception: # Give up. - d3d12_deps_folder = "" + build_deps_folder = "" return [ ("mingw_prefix", "MinGW prefix", mingw), @@ -194,28 +194,37 @@ def get_opts(): BoolVariable("debug_crt", "Compile with MSVC's debug CRT (/MDd)", False), BoolVariable("incremental_link", "Use MSVC incremental linking. May increase or decrease build times.", False), BoolVariable("silence_msvc", "Silence MSVC's cl/link stdout bloat, redirecting any errors to stderr.", True), - ("angle_libs", "Path to the ANGLE static libraries", ""), + BoolVariable( + "angle", + "Path to the ANGLE static libraries (required for OpenGL to Direct3D 11 fallback on old GPUs)", + True, + ), + ( + "angle_libs", + "Path to the ANGLE static libraries", + os.path.join(build_deps_folder, "angle"), + ), # Direct3D 12 support. ( "mesa_libs", "Path to the MESA/NIR static libraries (required for D3D12)", - os.path.join(d3d12_deps_folder, "mesa"), + os.path.join(build_deps_folder, "mesa"), ), ( "agility_sdk_path", "Path to the Agility SDK distribution (optional for D3D12)", - os.path.join(d3d12_deps_folder, "agility_sdk"), + os.path.join(build_deps_folder, "agility_sdk"), ), BoolVariable( "agility_sdk_multiarch", - "Whether the Agility SDK DLLs will be stored in arch-specific subdirectories", + "Whether the Agility SDK DLLs will be stored in architecture-specific subdirectories", False, ), BoolVariable("use_pix", "Use PIX (Performance tuning and debugging for DirectX 12) runtime", False), ( "pix_path", "Path to the PIX runtime distribution (optional for D3D12)", - os.path.join(d3d12_deps_folder, "pix"), + os.path.join(build_deps_folder, "pix"), ), ] @@ -469,9 +478,12 @@ def spawn_capture(sh, escape, cmd, args, env): if env["opengl3"]: env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"]) - if env["angle_libs"] != "": + if env["angle"] and env["angle_libs"] != "": + angle_libs = env["angle_libs"] + if os.path.exists(env["angle_libs"] + "-" + env["arch"] + "-msvc"): + angle_libs = env["angle_libs"] + "-" + env["arch"] + "-msvc" env.AppendUnique(CPPDEFINES=["EGL_STATIC"]) - env.Append(LIBPATH=[env["angle_libs"]]) + env.Append(LIBPATH=[angle_libs]) LIBS += [ "libANGLE.windows." + env["arch"] + prebuilt_lib_extra_suffix, "libEGL.windows." + env["arch"] + prebuilt_lib_extra_suffix, @@ -861,9 +873,14 @@ def configure_mingw(env: "SConsEnvironment"): if env["opengl3"]: env.Append(CPPDEFINES=["GLES3_ENABLED"]) - if env["angle_libs"] != "": + if env["angle"] and env["angle_libs"] != "": + angle_libs = env["angle_libs"] + if env["use_llvm"] and os.path.exists(env["angle_libs"] + "-" + env["arch"] + "-llvm"): + angle_libs = env["angle_libs"] + "-" + env["arch"] + "-llvm" + elif not env["use_llvm"] and os.path.exists(env["angle_libs"] + "-" + env["arch"] + "-gcc"): + angle_libs = env["angle_libs"] + "-" + env["arch"] + "-gcc" env.AppendUnique(CPPDEFINES=["EGL_STATIC"]) - env.Append(LIBPATH=[env["angle_libs"]]) + env.Append(LIBPATH=[angle_libs]) env.Append( LIBS=[ "EGL.windows." + env["arch"],