Add Swappy & Pre-Transformed Swapchain

- Adds Swappy for Android for stable frame pacing
- Implements pre-transformed Swapchain so that Godot's compositor is in
charge of rotating the screen instead of Android's compositor
(performance optimization for phones that don't have HW rotator)

============================

The work was performed by collaboration of TheForge and Google. I am
merely splitting it up into smaller PRs and cleaning it up.

Changes from original PR:

- Removed "display/window/frame_pacing/android/target_frame_rate" option
to use Engine::get_max_fps instead.
- Target framerate can be changed at runtime using Engine::set_max_fps.
- Swappy is enabled by default.
- Added documentation.
- enable_auto_swap setting is replaced with swappy_mode.
This commit is contained in:
Matias N. Goldberg 2024-05-05 19:15:56 -03:00
parent 92e51fca72
commit aaa0e2fddf
23 changed files with 1064 additions and 14 deletions

View file

@ -95,6 +95,15 @@ def install_ndk_if_needed(env: "SConsEnvironment"):
env["ANDROID_NDK_ROOT"] = get_android_ndk_root(env)
def detect_swappy():
archs = ["arm64-v8a", "armeabi-v7a", "x86", "x86_64"]
has_swappy = True
for arch in archs:
if not os.path.isfile("thirdparty/swappy-frame-pacing/" + arch + "/libswappy_static.a"):
has_swappy = False
return has_swappy
def configure(env: "SConsEnvironment"):
# Validate arch.
supported_arches = ["x86_32", "x86_64", "arm32", "arm64"]
@ -176,19 +185,42 @@ def configure(env: "SConsEnvironment"):
)
)
has_swappy = detect_swappy()
if not has_swappy:
print_warning(
"Swappy Frame Pacing not detected! It is strongly recommended you download it from https://github.com/darksylinc/godot-swappy/releases and extract it so that the following files can be found:\n"
+ " thirdparty/swappy-frame-pacing/arm64-v8a/libswappy_static.a\n"
+ " thirdparty/swappy-frame-pacing/armeabi-v7a/libswappy_static.a\n"
+ " thirdparty/swappy-frame-pacing/x86/libswappy_static.a\n"
+ " thirdparty/swappy-frame-pacing/x86_64/libswappy_static.a\n"
+ "Without Swappy, Godot apps on Android will inevitable suffer stutter and struggle to keep consistent 30/60/90/120 fps. Though Swappy cannot guarantee your app will be stutter-free, not having Swappy will guarantee there will be stutter even on the best phones and the most simple of scenes."
)
if env["swappy"]:
print_error("Use build option `swappy=no` to ignore missing Swappy dependency and build without it.")
sys.exit(255)
if get_min_sdk_version(env["ndk_platform"]) >= 24:
env.Append(CPPDEFINES=[("_FILE_OFFSET_BITS", 64)])
if env["arch"] == "x86_32":
# The NDK adds this if targeting API < 24, so we can drop it when Godot targets it at least
env.Append(CCFLAGS=["-mstackrealign"])
if has_swappy:
env.Append(LIBPATH=["../../thirdparty/swappy-frame-pacing/x86"])
elif env["arch"] == "x86_64":
if has_swappy:
env.Append(LIBPATH=["../../thirdparty/swappy-frame-pacing/x86_64"])
elif env["arch"] == "arm32":
env.Append(CCFLAGS="-march=armv7-a -mfloat-abi=softfp".split())
env.Append(CPPDEFINES=["__ARM_ARCH_7__", "__ARM_ARCH_7A__"])
env.Append(CPPDEFINES=["__ARM_NEON__"])
if has_swappy:
env.Append(LIBPATH=["../../thirdparty/swappy-frame-pacing/armeabi-v7a"])
elif env["arch"] == "arm64":
env.Append(CCFLAGS=["-mfix-cortex-a53-835769"])
env.Append(CPPDEFINES=["__ARM_ARCH_8A__"])
if has_swappy:
env.Append(LIBPATH=["../../thirdparty/swappy-frame-pacing/arm64-v8a"])
env.Append(CCFLAGS=["-ffp-contract=off"])
@ -203,6 +235,9 @@ def configure(env: "SConsEnvironment"):
if env["vulkan"]:
env.Append(CPPDEFINES=["VULKAN_ENABLED", "RD_ENABLED"])
if has_swappy:
env.Append(CPPDEFINES=["SWAPPY_FRAME_PACING_ENABLED"])
env.Append(LIBS=["swappy_static"])
if not env["use_volk"]:
env.Append(LIBS=["vulkan"])