Skip to content

Commit

Permalink
Memory cleanup and optimizations
Browse files Browse the repository at this point in the history
- Returns an empty list when there's not registered plugins, thus preventing the creation of spurious iterator objects

- Inline `Godot#getRotatedValues(...)` given it only had a single caller. This allows to remove the allocation of a float array on each call and replace it with float variables

- Disable sensor events by default. Sensor events can fired at 10-100s Hz taking cpu and memory resources. Now the use of sensor data is behind a project setting allowing projects that have use of it to enable it, while other projects don't pay the cost for a feature they don't use

- Create a pool of specialized input `Runnable` objects to prevent spurious, unbounded `Runnable` allocations

- Disable showing the boot logo for Android XR projects

- Delete locale references of jni strings
  • Loading branch information
m4gr3d committed Aug 16, 2024
1 parent 2f2d1a7 commit a57a99f
Show file tree
Hide file tree
Showing 14 changed files with 626 additions and 188 deletions.
5 changes: 5 additions & 0 deletions core/config/project_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1570,6 +1570,11 @@ ProjectSettings::ProjectSettings() {

GLOBAL_DEF("collada/use_ambient", false);

// Input settings
GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_long_press_as_right_click", false);
GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_pan_and_scale_gestures", false);
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "input_devices/pointing/android/rotary_input_scroll_axis", PROPERTY_HINT_ENUM, "Horizontal,Vertical"), 1);

// These properties will not show up in the dialog. If you want to exclude whole groups, use add_hidden_prefix().
GLOBAL_DEF_INTERNAL("application/config/features", PackedStringArray());
GLOBAL_DEF_INTERNAL("internationalization/locale/translation_remaps", PackedStringArray());
Expand Down
33 changes: 33 additions & 0 deletions core/input/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -513,21 +513,49 @@ void Input::joy_connection_changed(int p_idx, bool p_connected, const String &p_

Vector3 Input::get_gravity() const {
_THREAD_SAFE_METHOD_

#ifdef DEBUG_ENABLED
if (!gravity_enabled) {
WARN_PRINT_ONCE("`input_devices/sensors/enable_gravity` is not enabled in project settings.");
}
#endif

return gravity;
}

Vector3 Input::get_accelerometer() const {
_THREAD_SAFE_METHOD_

#ifdef DEBUG_ENABLED
if (!accelerometer_enabled) {
WARN_PRINT_ONCE("`input_devices/sensors/enable_accelerometer` is not enabled in project settings.");
}
#endif

return accelerometer;
}

Vector3 Input::get_magnetometer() const {
_THREAD_SAFE_METHOD_

#ifdef DEBUG_ENABLED
if (!magnetometer_enabled) {
WARN_PRINT_ONCE("`input_devices/sensors/enable_magnetometer` is not enabled in project settings.");
}
#endif

return magnetometer;
}

Vector3 Input::get_gyroscope() const {
_THREAD_SAFE_METHOD_

#ifdef DEBUG_ENABLED
if (!gyroscope_enabled) {
WARN_PRINT_ONCE("`input_devices/sensors/enable_gyroscope` is not enabled in project settings.");
}
#endif

return gyroscope;
}

Expand Down Expand Up @@ -1683,6 +1711,11 @@ Input::Input() {
// Always use standard behavior in the editor.
legacy_just_pressed_behavior = false;
}

accelerometer_enabled = GLOBAL_DEF_RST_BASIC("input_devices/sensors/enable_accelerometer", false);
gravity_enabled = GLOBAL_DEF_RST_BASIC("input_devices/sensors/enable_gravity", false);
gyroscope_enabled = GLOBAL_DEF_RST_BASIC("input_devices/sensors/enable_gyroscope", false);
magnetometer_enabled = GLOBAL_DEF_RST_BASIC("input_devices/sensors/enable_magnetometer", false);
}

Input::~Input() {
Expand Down
4 changes: 4 additions & 0 deletions core/input/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,13 @@ class Input : public Object {
RBSet<JoyButton> joy_buttons_pressed;
RBMap<JoyAxis, float> _joy_axis;
//RBMap<StringName,int> custom_action_press;
bool gravity_enabled = false;
Vector3 gravity;
bool accelerometer_enabled = false;
Vector3 accelerometer;
bool magnetometer_enabled = false;
Vector3 magnetometer;
bool gyroscope_enabled = false;
Vector3 gyroscope;
Vector2 mouse_pos;
int64_t mouse_window = 0;
Expand Down
12 changes: 12 additions & 0 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1422,6 +1422,18 @@
<member name="input_devices/pointing/emulate_touch_from_mouse" type="bool" setter="" getter="" default="false">
If [code]true[/code], sends touch input events when clicking or dragging the mouse.
</member>
<member name="input_devices/sensors/enable_accelerometer" type="bool" setter="" getter="" default="false">
If [code]true[/code], the accelerometer sensor is enabled and [method Input.get_accelerometer] returns valid data.
</member>
<member name="input_devices/sensors/enable_gravity" type="bool" setter="" getter="" default="false">
If [code]true[/code], the gravity sensor is enabled and [method Input.get_gravity] returns valid data.
</member>
<member name="input_devices/sensors/enable_gyroscope" type="bool" setter="" getter="" default="false">
If [code]true[/code], the gyroscope sensor is enabled and [method Input.get_gyroscope] returns valid data.
</member>
<member name="input_devices/sensors/enable_magnetometer" type="bool" setter="" getter="" default="false">
If [code]true[/code], the magnetometer sensor is enabled and [method Input.get_magnetometer] returns valid data.
</member>
<member name="internationalization/locale/fallback" type="String" setter="" getter="" default="&quot;en&quot;">
The locale to fall back to if a translation isn't available in a given language. If left empty, [code]en[/code] (English) will be used.
</member>
Expand Down
3 changes: 0 additions & 3 deletions main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2942,9 +2942,6 @@ Error Main::setup2(bool p_show_boot_logo) {
id->set_emulate_mouse_from_touch(bool(GLOBAL_DEF_BASIC("input_devices/pointing/emulate_mouse_from_touch", true)));
}

GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_long_press_as_right_click", false);
GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_pan_and_scale_gestures", false);
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "input_devices/pointing/android/rotary_input_scroll_axis", PROPERTY_HINT_ENUM, "Horizontal,Vertical"), 1);
OS::get_singleton()->benchmark_end_measure("Startup", "Setup Window and Boot");
}

Expand Down
149 changes: 59 additions & 90 deletions platform/android/java/lib/src/org/godotengine/godot/Godot.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ import android.content.res.Configuration
import android.content.res.Resources
import android.graphics.Color
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.os.*
import android.util.Log
Expand All @@ -53,6 +51,7 @@ import androidx.core.view.WindowInsetsAnimationCompat
import androidx.core.view.WindowInsetsCompat
import com.google.android.vending.expansion.downloader.*
import org.godotengine.godot.input.GodotEditText
import org.godotengine.godot.input.GodotInputHandler
import org.godotengine.godot.io.directory.DirectoryAccessHandler
import org.godotengine.godot.io.file.FileAccessHandler
import org.godotengine.godot.plugin.GodotPluginRegistry
Expand All @@ -73,6 +72,7 @@ import java.io.InputStream
import java.lang.Exception
import java.security.MessageDigest
import java.util.*
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicReference

/**
Expand All @@ -81,7 +81,7 @@ import java.util.concurrent.atomic.AtomicReference
* Can be hosted by [Activity], [Fragment] or [Service] android components, so long as its
* lifecycle methods are properly invoked.
*/
class Godot(private val context: Context) : SensorEventListener {
class Godot(private val context: Context) {

private companion object {
private val TAG = Godot::class.java.simpleName
Expand All @@ -99,15 +99,23 @@ class Godot(private val context: Context) : SensorEventListener {
private val pluginRegistry: GodotPluginRegistry by lazy {
GodotPluginRegistry.getPluginRegistry()
}

private val accelerometer_enabled = AtomicBoolean(false)
private val mAccelerometer: Sensor? by lazy {
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
}

private val gravity_enabled = AtomicBoolean(false)
private val mGravity: Sensor? by lazy {
mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY)
}

private val magnetometer_enabled = AtomicBoolean(false)
private val mMagnetometer: Sensor? by lazy {
mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
}

private val gyroscope_enabled = AtomicBoolean(false)
private val mGyroscope: Sensor? by lazy {
mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)
}
Expand All @@ -127,6 +135,7 @@ class Godot(private val context: Context) : SensorEventListener {
val fileAccessHandler = FileAccessHandler(context)
val netUtils = GodotNetUtils(context)
private val commandLineFileParser = CommandLineFileParser()
private val godotInputHandler = GodotInputHandler(context, this)

/**
* Task to run when the engine terminates.
Expand Down Expand Up @@ -154,6 +163,17 @@ class Godot(private val context: Context) : SensorEventListener {
private var renderViewInitialized = false
private var primaryHost: GodotHost? = null

/**
* Tracks whether we're in the RESUMED lifecycle state.
* See [onResume] and [onPause]
*/
private var resumed = false

/**
* Tracks whether [onGodotSetupCompleted] fired.
*/
private val godotMainLoopStarted = AtomicBoolean(false)

var io: GodotIO? = null

private var commandLine : MutableList<String> = ArrayList<String>()
Expand Down Expand Up @@ -416,10 +436,10 @@ class Godot(private val context: Context) : SensorEventListener {
if (!meetsVulkanRequirements(activity.packageManager)) {
throw IllegalStateException(activity.getString(R.string.error_missing_vulkan_requirements_message))
}
GodotVulkanRenderView(host, this)
GodotVulkanRenderView(host, this, godotInputHandler)
} else {
// Fallback to openGl
GodotGLRenderView(host, this, xrMode, useDebugOpengl)
GodotGLRenderView(host, this, godotInputHandler, xrMode, useDebugOpengl)
}

if (host == primaryHost) {
Expand Down Expand Up @@ -520,23 +540,13 @@ class Godot(private val context: Context) : SensorEventListener {

fun onResume(host: GodotHost) {
Log.v(TAG, "OnResume: $host")
resumed = true
if (host != primaryHost) {
return
}

renderView?.onActivityResumed()
if (mAccelerometer != null) {
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME)
}
if (mGravity != null) {
mSensorManager.registerListener(this, mGravity, SensorManager.SENSOR_DELAY_GAME)
}
if (mMagnetometer != null) {
mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME)
}
if (mGyroscope != null) {
mSensorManager.registerListener(this, mGyroscope, SensorManager.SENSOR_DELAY_GAME)
}
registerSensorsIfNeeded()
if (useImmersive) {
val window = requireActivity().window
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
Expand All @@ -551,14 +561,34 @@ class Godot(private val context: Context) : SensorEventListener {
}
}

private fun registerSensorsIfNeeded() {
if (!resumed || !godotMainLoopStarted.get()) {
return
}

if (accelerometer_enabled.get() && mAccelerometer != null) {
mSensorManager.registerListener(godotInputHandler, mAccelerometer, SensorManager.SENSOR_DELAY_GAME)
}
if (gravity_enabled.get() && mGravity != null) {
mSensorManager.registerListener(godotInputHandler, mGravity, SensorManager.SENSOR_DELAY_GAME)
}
if (magnetometer_enabled.get() && mMagnetometer != null) {
mSensorManager.registerListener(godotInputHandler, mMagnetometer, SensorManager.SENSOR_DELAY_GAME)
}
if (gyroscope_enabled.get() && mGyroscope != null) {
mSensorManager.registerListener(godotInputHandler, mGyroscope, SensorManager.SENSOR_DELAY_GAME)
}
}

fun onPause(host: GodotHost) {
Log.v(TAG, "OnPause: $host")
resumed = false
if (host != primaryHost) {
return
}

renderView?.onActivityPaused()
mSensorManager.unregisterListener(this)
mSensorManager.unregisterListener(godotInputHandler)
for (plugin in pluginRegistry.allPlugins) {
plugin.onMainPause()
}
Expand Down Expand Up @@ -659,6 +689,16 @@ class Godot(private val context: Context) : SensorEventListener {
*/
private fun onGodotMainLoopStarted() {
Log.v(TAG, "OnGodotMainLoopStarted")
godotMainLoopStarted.set(true)

accelerometer_enabled.set(java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/sensors/enable_accelerometer")))
gravity_enabled.set(java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/sensors/enable_gravity")))
gyroscope_enabled.set(java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/sensors/enable_gyroscope")))
magnetometer_enabled.set(java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/sensors/enable_magnetometer")))

runOnUiThread {
registerSensorsIfNeeded()
}

for (plugin in pluginRegistry.allPlugins) {
plugin.onGodotMainLoopStarted()
Expand Down Expand Up @@ -858,77 +898,6 @@ class Godot(private val context: Context) : SensorEventListener {
}
}

private fun getRotatedValues(values: FloatArray?): FloatArray? {
if (values == null || values.size != 3) {
return null
}
val rotatedValues = FloatArray(3)
when (windowManager.defaultDisplay.rotation) {
Surface.ROTATION_0 -> {
rotatedValues[0] = values[0]
rotatedValues[1] = values[1]
rotatedValues[2] = values[2]
}
Surface.ROTATION_90 -> {
rotatedValues[0] = -values[1]
rotatedValues[1] = values[0]
rotatedValues[2] = values[2]
}
Surface.ROTATION_180 -> {
rotatedValues[0] = -values[0]
rotatedValues[1] = -values[1]
rotatedValues[2] = values[2]
}
Surface.ROTATION_270 -> {
rotatedValues[0] = values[1]
rotatedValues[1] = -values[0]
rotatedValues[2] = values[2]
}
}
return rotatedValues
}

override fun onSensorChanged(event: SensorEvent) {
if (renderView == null) {
return
}

val rotatedValues = getRotatedValues(event.values)

when (event.sensor.type) {
Sensor.TYPE_ACCELEROMETER -> {
rotatedValues?.let {
renderView?.queueOnRenderThread {
GodotLib.accelerometer(-it[0], -it[1], -it[2])
}
}
}
Sensor.TYPE_GRAVITY -> {
rotatedValues?.let {
renderView?.queueOnRenderThread {
GodotLib.gravity(-it[0], -it[1], -it[2])
}
}
}
Sensor.TYPE_MAGNETIC_FIELD -> {
rotatedValues?.let {
renderView?.queueOnRenderThread {
GodotLib.magnetometer(-it[0], -it[1], -it[2])
}
}
}
Sensor.TYPE_GYROSCOPE -> {
rotatedValues?.let {
renderView?.queueOnRenderThread {
GodotLib.gyroscope(it[0], it[1], it[2])
}
}
}
}
}

override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}

/**
* Used by the native code (java_godot_wrapper.h) to vibrate the device.
* @param durationMs
Expand Down Expand Up @@ -1063,7 +1032,7 @@ class Godot(private val context: Context) : SensorEventListener {

@Keep
private fun initInputDevices() {
renderView?.initInputDevices()
godotInputHandler.initInputDevices()
}

@Keep
Expand Down
Loading

0 comments on commit a57a99f

Please sign in to comment.