fix small window in bottom left bug. Mali Mediatek fixes

This commit is contained in:
izzy2lost
2026-03-08 10:55:12 -04:00
parent 0171b268e6
commit 02bcd8dd17
6 changed files with 95 additions and 22 deletions
+15 -11
View File
@@ -201,14 +201,9 @@ static std::string ToLowerAscii(std::string value) {
static std::string ResolveAndroidAudioDriverHint() {
// OpenSL ES is preferred over AAudio because AAudio exclusively requests
// MMAP no-IRQ low-latency outputs (AUDIO_OUTPUT_FLAG_MMAP_NOIRQ). On some
// devices (e.g. Honor/Huawei with Android 14+, Snapdragon 8 Gen 3/Adreno 840)
// the MMAP output count is capped and openDirectOutput fails when the limit
// is reached, leaving the audio stream permanently inactive (isActive:0) and
// hanging the audio thread with 1ms timeouts in AudioStreamInternal_Client.
// AAudio is deliberately excluded from the default chain: if OpenSL ES fails
// for any reason, "android" (standard AudioTrack) is the next safe fallback.
// "dummy" is the silent no-op driver used as a last resort so that audio
// failure never prevents the emulator from starting.
// devices the MMAP output count is capped and openDirectOutput fails when
// the limit is reached, leaving the audio stream inactive. The standard
// Android AudioTrack backend remains the safe fallback.
constexpr const char* kDefaultAudioDriverHint = "openslES,android,dummy";
const char* value = SDL_getenv("XEMU_ANDROID_AUDIO_DRIVER");
if (!value || value[0] == '\0') {
@@ -227,7 +222,10 @@ static std::string ResolveAndroidAudioDriverHint() {
return "aaudio,android,dummy";
}
if (normalized == "android" || normalized == "audiotrack") {
return "android,dummy";
// Legacy recovery: a saved "android" preference should no longer force
// AudioTrack first, because that path was found to exit immediately on
// some devices. Fall back to the old OpenSL ES-first behavior.
return "openslES,android,dummy";
}
if (normalized == "null" || normalized == "none" || normalized == "dummy") {
return "dummy";
@@ -723,7 +721,7 @@ struct EmulatorSettings {
bool hrtf = true;
bool cache_shaders = true;
bool hard_fpu = true;
bool vsync = false;
bool vsync = true;
bool skip_boot_anim = false;
};
@@ -983,8 +981,14 @@ static SetupFiles SyncSetupFiles() {
emuSettings.filtering = "nearest";
}
}
emuSettings.vsync = GetPrefBool(env, activity, "setting_vsync", false);
emuSettings.vsync = GetPrefBool(env, activity, "setting_vsync", true);
out.audio_driver = GetPrefString(env, activity, "setting_audio_driver");
{
std::string normalized = ToLowerAscii(out.audio_driver);
if (normalized == "android" || normalized == "audiotrack") {
out.audio_driver = "openslES";
}
}
int displayMode = GetPrefInt(env, activity, "setting_display_mode", 0);
xemu_android_set_display_mode_setting(displayMode);
@@ -76,7 +76,7 @@ static void xemu_settings_apply_defaults(void)
CONFIG_DISPLAY_WINDOW_STARTUP_SIZE_1280X960;
g_config.display.window.last_width = 640;
g_config.display.window.last_height = 480;
g_config.display.window.vsync = false;
g_config.display.window.vsync = true;
g_config.display.ui.show_menubar = true;
g_config.display.ui.show_notifications = true;
g_config.display.ui.hide_cursor = true;
@@ -392,8 +392,8 @@ bool xemu_settings_load(void)
if (auto audio_driver = android_cfg["audio_driver"].value<std::string>()) {
std::string driver = *audio_driver;
std::string normalized = to_lower_ascii(driver);
if (normalized == "audiotrack") {
setenv("XEMU_ANDROID_AUDIO_DRIVER", "android", 1);
if (normalized == "audiotrack" || normalized == "android") {
setenv("XEMU_ANDROID_AUDIO_DRIVER", "opensles", 1);
} else if (normalized == "opensl" || normalized == "opensles") {
setenv("XEMU_ANDROID_AUDIO_DRIVER", "opensles", 1);
} else if (normalized == "auto" || normalized == "default") {
@@ -7,12 +7,14 @@ import android.hardware.input.InputManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.InputDevice
import android.view.KeyEvent
import android.view.View
import android.view.ViewGroup
import android.view.WindowInsets
import android.view.WindowInsetsController
import android.view.WindowManager
import android.widget.BaseAdapter
import android.widget.FrameLayout
import android.widget.ImageView
@@ -33,6 +35,7 @@ class MainActivity : SDLActivity(), InputManager.InputDeviceListener {
const val EXTRA_AUTO_LOAD_SNAPSHOT_SLOT = "com.izzy2lost.x1box.extra.AUTO_LOAD_SNAPSHOT_SLOT"
private const val SNAPSHOT_PREVIEW_HEADER_SIZE = 12
private const val TOTAL_SNAPSHOT_SLOTS = 10
private const val TAG = "MainActivity"
}
private data class SnapshotSlotPreview(
@@ -60,11 +63,13 @@ class MainActivity : SDLActivity(), InputManager.InputDeviceListener {
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
keepScreenOn = true
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
val requestedSlot = intent?.getIntExtra(EXTRA_AUTO_LOAD_SNAPSHOT_SLOT, 0) ?: 0
if (requestedSlot in 1..TOTAL_SNAPSHOT_SLOTS) {
startupSnapshotSlot = requestedSlot
@@ -155,6 +160,8 @@ class MainActivity : SDLActivity(), InputManager.InputDeviceListener {
override fun onResume() {
super.onResume()
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
mLayout?.keepScreenOn = true
// Register virtual controller after SDL is initialized
// Use a delay to ensure SDL is fully ready
@@ -272,6 +279,7 @@ class MainActivity : SDLActivity(), InputManager.InputDeviceListener {
}
override fun onDestroy() {
Log.i(TAG, "onDestroy()")
inGameMenuDialog?.dismiss()
inGameMenuDialog = null
@@ -283,9 +291,25 @@ class MainActivity : SDLActivity(), InputManager.InputDeviceListener {
}
inputManager?.unregisterInputDeviceListener(this)
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
super.onDestroy()
}
override fun onUserLeaveHint() {
Log.i(TAG, "onUserLeaveHint()")
super.onUserLeaveHint()
}
override fun onTrimMemory(level: Int) {
Log.i(TAG, "onTrimMemory(level=$level)")
super.onTrimMemory(level)
}
override fun onLowMemory() {
Log.w(TAG, "onLowMemory()")
super.onLowMemory()
}
// Manual control methods (for settings/preferences)
fun toggleOnScreenController() {
isControllerVisible = !isControllerVisible
@@ -166,7 +166,7 @@ class SettingsActivity : AppCompatActivity() {
switchHrtf.isChecked = prefs.getBoolean("setting_hrtf", true)
switchShaders.isChecked = prefs.getBoolean("setting_cache_shaders", true)
switchFpu.isChecked = prefs.getBoolean("setting_hard_fpu", true)
switchVsync.isChecked = prefs.getBoolean("setting_vsync", false)
switchVsync.isChecked = prefs.getBoolean("setting_vsync", true)
switchSkipBootAnim.isChecked =
prefs.getBoolean("setting_skip_boot_anim", false)
+8 -4
View File
@@ -67,6 +67,7 @@ MString *pgraph_glsl_gen_geom(const GeomState *state, GenGeomGlslOptions opts)
bool need_triz = false;
bool need_linez = false;
bool need_point_size = false;
const char *layout_in = NULL;
const char *layout_out = NULL;
const char *body = NULL;
@@ -99,6 +100,7 @@ MString *pgraph_glsl_gen_geom(const GeomState *state, GenGeomGlslOptions opts)
" emit_line(2, 0, dz);\n";
} else {
assert(polygon_mode == POLY_MODE_POINT);
need_point_size = true;
layout_out = "layout(points, max_vertices = 3) out;\n";
body = " mat4 pz = calc_triz(0, 1, 2);\n"
" emit_vertex(0, mat4(pz[0], pz[0], pz[0], pz[3]));\n"
@@ -134,11 +136,14 @@ MString *pgraph_glsl_gen_geom(const GeomState *state, GenGeomGlslOptions opts)
const char *point_size_expr =
opts.gles ? "v_vtxPointSize[index]" : "gl_in[index].gl_PointSize";
mstring_append(output,
"void emit_vertex(int index, mat4 pz) {\n"
" gl_Position = gl_in[index].gl_Position;\n");
if (need_point_size) {
mstring_append_fmt(output, " gl_PointSize = %s;\n", point_size_expr);
}
mstring_append_fmt(
output,
"void emit_vertex(int index, mat4 pz) {\n"
" gl_Position = gl_in[index].gl_Position;\n"
" gl_PointSize = %s;\n"
" vtxD0 = v_vtxD0[%s];\n"
" vtxD1 = v_vtxD1[%s];\n"
" vtxB0 = v_vtxB0[%s];\n"
@@ -155,7 +160,6 @@ MString *pgraph_glsl_gen_geom(const GeomState *state, GenGeomGlslOptions opts)
" vtxPointSize = v_vtxPointSize[index];\n"
" EmitVertex();\n"
"}\n",
point_size_expr,
provoking_index,
provoking_index,
provoking_index,
+44 -3
View File
@@ -128,6 +128,7 @@ static void toggle_full_screen(struct sdl2_console *scon);
#ifdef __ANDROID__
static bool g_android_gl_bgra_supported = true;
static bool g_android_force_finish_before_swap = false;
static bool g_android_paused = false;
static bool g_android_should_quit = false;
static uint64_t g_android_frame_counter = 0;
@@ -218,6 +219,8 @@ static void sdl2_gl_render_texture(struct sdl2_console *scon,
{
int w = 0;
int h = 0;
int ww = 0;
int wh = 0;
int vx = 0;
int vy = 0;
int vw;
@@ -232,6 +235,7 @@ static void sdl2_gl_render_texture(struct sdl2_console *scon,
android_log_gl_error("blit-start");
SDL_GL_GetDrawableSize(scon->real_window, &w, &h);
SDL_GetWindowSize(scon->real_window, &ww, &wh);
if (w <= 0) {
w = 1;
}
@@ -255,6 +259,15 @@ static void sdl2_gl_render_texture(struct sdl2_console *scon,
}
}
#ifdef __ANDROID__
if ((g_android_frame_counter % 60) == 0) {
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"present drawable=%dx%d window=%dx%d viewport=%d,%d %dx%d tex=%u flip=%d mode=%d",
w, h, ww, wh, vx, vy, vw, vh,
(unsigned)tex, flip ? 1 : 0, g_android_display_mode);
}
#endif
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(vx, vy, vw, vh);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
@@ -969,6 +982,7 @@ static void sdl2_display_very_early_init(DisplayOptions *o)
int min_window_height = 480;
int window_width = min_window_width;
int window_height = min_window_height;
SDL_DisplayMode disp_mode;
const int res_table[][2] = {
{640, 480},
@@ -998,6 +1012,22 @@ static void sdl2_display_very_early_init(DisplayOptions *o)
window_height = min_window_height;
}
#ifdef __ANDROID__
/* Android should always present into the full activity surface. Using the
* desktop-style startup window size here lets narrow-height devices fall
* into the "display smaller than requested window" path and clamps the SDL
* window to 640x480, which is exactly the bottom-left tiny box symptom.
*/
if (SDL_GetCurrentDisplayMode(0, &disp_mode) == 0) {
if (disp_mode.w > 0) {
window_width = disp_mode.w;
}
if (disp_mode.h > 0) {
window_height = disp_mode.h;
}
}
#endif
// On Android, always use OpenGL window even for Vulkan because Vulkan
// needs GL context for external memory display presentation
#ifdef __ANDROID__
@@ -1021,12 +1051,13 @@ static void sdl2_display_very_early_init(DisplayOptions *o)
g_free(title);
SDL_SetWindowMinimumSize(m_window, min_window_width, min_window_height);
SDL_DisplayMode disp_mode;
SDL_GetCurrentDisplayMode(SDL_GetWindowDisplayIndex(m_window), &disp_mode);
#ifndef __ANDROID__
if (disp_mode.w < window_width || disp_mode.h < window_height) {
SDL_SetWindowSize(m_window, min_window_width, min_window_height);
SDL_SetWindowPosition(m_window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
}
#endif
m_context = SDL_GL_CreateContext(m_window);
@@ -1111,6 +1142,12 @@ static void sdl2_display_very_early_init(DisplayOptions *o)
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"GL_EXT_texture_format_BGRA8888=%s",
g_android_gl_bgra_supported ? "yes" : "no");
if ((vendor && strstr(vendor, "ARM")) ||
(renderer && strstr(renderer, "Mali"))) {
g_android_force_finish_before_swap = true;
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"android: force glFinish before swap enabled");
}
}
#endif
@@ -1318,7 +1355,7 @@ void xemu_android_display_loop(void)
}
#ifdef __ANDROID__
xemu_android_refresh_frame_limit_from_env();
SDL_GL_SetSwapInterval(g_config.display.window.vsync ? 1 : 0);
SDL_GL_SetSwapInterval(1);
xemu_hud_init(m_window, m_context);
#endif
tcg_register_init_ctx();
@@ -1641,7 +1678,11 @@ void sdl2_gl_refresh(DisplayChangeListener *dcl)
qemu_mutex_unlock_main_loop();
#ifdef __ANDROID__
glFlush();
if (g_android_force_finish_before_swap) {
glFinish();
} else {
glFlush();
}
#else
glFinish();
#endif