From 64309740ec4b7a9703fbdef205943e2989e2c456 Mon Sep 17 00:00:00 2001 From: izzy2lost Date: Sun, 29 Mar 2026 08:12:24 -0400 Subject: [PATCH] Port hakuX Android flush and GLES stability fixes --- hw/xbox/nv2a/pgraph/gl/display.c | 2 ++ hw/xbox/nv2a/pgraph/gl/renderer.c | 24 ++++++++++++++++++++++-- hw/xbox/nv2a/pgraph/gl/renderer.h | 2 ++ hw/xbox/nv2a/pgraph/gl/shaders.c | 25 ++++++++++++++++++++++--- hw/xbox/nv2a/pgraph/glsl/geom.c | 6 ++---- ui/xemu.c | 9 ++++++++- 6 files changed, 58 insertions(+), 10 deletions(-) diff --git a/hw/xbox/nv2a/pgraph/gl/display.c b/hw/xbox/nv2a/pgraph/gl/display.c index ec4aed9763..abdca33b02 100644 --- a/hw/xbox/nv2a/pgraph/gl/display.c +++ b/hw/xbox/nv2a/pgraph/gl/display.c @@ -410,6 +410,7 @@ static void render_display_pvideo_overlay(NV2AState *d) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); uint8_t *tex_rgba = convert_texture_data__CR8YB8CB8YA8( d->vram_ptr + base + offset, in_width, in_height, in_pitch); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, in_width, in_height, 0, GL_RGBA, @@ -478,6 +479,7 @@ static void render_display(NV2AState *d, SurfaceBinding *surface) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); r->gl_display_buffer_internal_format = disp_ifmt; r->gl_display_buffer_width = width; r->gl_display_buffer_height = height; diff --git a/hw/xbox/nv2a/pgraph/gl/renderer.c b/hw/xbox/nv2a/pgraph/gl/renderer.c index 08767b9a7b..f4332d243b 100644 --- a/hw/xbox/nv2a/pgraph/gl/renderer.c +++ b/hw/xbox/nv2a/pgraph/gl/renderer.c @@ -107,12 +107,32 @@ static void pgraph_gl_init(NV2AState *d, Error **errp) #ifdef __ANDROID__ const char *exts = (const char *)glGetString(GL_EXTENSIONS); + const char *glsl_version = (const char *)glGetString( + GL_SHADING_LANGUAGE_VERSION); + int glsl_es_major = 0; + int glsl_es_minor = 0; r->bgra_supported = gl_extension_supported(exts, "GL_EXT_texture_format_BGRA8888") || gl_extension_supported(exts, "GL_OES_texture_format_BGRA8888") || gl_extension_supported(exts, "GL_EXT_texture_format_BGRA8888_OES"); + r->gles_version = 300; + if (glsl_version != NULL) { + while (*glsl_version != '\0' && !g_ascii_isdigit(*glsl_version)) { + glsl_version++; + } + if (sscanf(glsl_version, "%d.%d", &glsl_es_major, &glsl_es_minor) == + 2) { + r->gles_version = glsl_es_major * 100 + glsl_es_minor * 10; + } + } + r->geometry_shaders_supported = + r->gles_version >= 320 || + gl_extension_supported(exts, "GL_EXT_geometry_shader") || + gl_extension_supported(exts, "GL_OES_geometry_shader"); __android_log_print(ANDROID_LOG_INFO, "xemu-android", - "pgraph_gl_init: bgra_supported=%s", - r->bgra_supported ? "yes" : "no"); + "pgraph_gl_init: bgra_supported=%s geom_shader=%s glsl_es=%d", + r->bgra_supported ? "yes" : "no", + r->geometry_shaders_supported ? "yes" : "no", + r->gles_version); #endif #if DEBUG_NV2A_GL diff --git a/hw/xbox/nv2a/pgraph/gl/renderer.h b/hw/xbox/nv2a/pgraph/gl/renderer.h index 9f066b6852..c6428d041d 100644 --- a/hw/xbox/nv2a/pgraph/gl/renderer.h +++ b/hw/xbox/nv2a/pgraph/gl/renderer.h @@ -269,6 +269,8 @@ typedef struct PGRAPHGLState { #ifdef __ANDROID__ bool bgra_supported; + bool geometry_shaders_supported; + int gles_version; #endif } PGRAPHGLState; diff --git a/hw/xbox/nv2a/pgraph/gl/shaders.c b/hw/xbox/nv2a/pgraph/gl/shaders.c index 07642cfefd..35e4829b15 100644 --- a/hw/xbox/nv2a/pgraph/gl/shaders.c +++ b/hw/xbox/nv2a/pgraph/gl/shaders.c @@ -255,13 +255,18 @@ static void generate_shaders(PGRAPHGLState *r, ShaderBinding *binding) ShaderModuleCacheKey key; #ifdef __ANDROID__ const bool gles = true; - const int gles_version = 320; + const int gles_version = r->gles_version; #else const bool gles = false; const int gles_version = 0; #endif bool need_geometry_shader = pgraph_glsl_need_geom(&state->geom); +#ifdef __ANDROID__ + if (need_geometry_shader && !r->geometry_shaders_supported) { + need_geometry_shader = false; + } +#endif if (need_geometry_shader) { memset(&key, 0, sizeof(key)); key.kind = GL_GEOMETRY_SHADER; @@ -292,9 +297,23 @@ static void generate_shaders(PGRAPHGLState *r, ShaderBinding *binding) glLinkProgram(program); GLint linked = 0; glGetProgramiv(program, GL_LINK_STATUS, &linked); + binding->gl_primitive_mode = + get_gl_primitive_mode(state->geom.primitive_mode); if(!linked) { GLchar log[2048]; glGetProgramInfoLog(program, 2048, NULL, log); +#ifdef __ANDROID__ + __android_log_print(ANDROID_LOG_ERROR, "xemu-android", + "nv2a: shader linking failed: %s", log); + binding->gl_program = 0; + binding->initialized = true; + memset(binding->uniform_locs.vsh, 0xFF, + sizeof(binding->uniform_locs.vsh)); + memset(binding->uniform_locs.psh, 0xFF, + sizeof(binding->uniform_locs.psh)); + glDeleteProgram(program); + return; +#endif fprintf(stderr, "nv2a: shader linking failed: %s\n", log); abort(); } @@ -302,8 +321,6 @@ static void generate_shaders(PGRAPHGLState *r, ShaderBinding *binding) glUseProgram(program); binding->gl_program = program; - binding->gl_primitive_mode = - get_gl_primitive_mode(state->geom.primitive_mode); binding->initialized = true; set_texture_sampler_uniforms(binding); @@ -581,6 +598,8 @@ static void shader_cache_entry_init(Lru *lru, LruNode *node, const void *state) binding->cached = false; binding->program = NULL; binding->save_thread = NULL; + memset(binding->uniform_locs.vsh, 0xFF, sizeof(binding->uniform_locs.vsh)); + memset(binding->uniform_locs.psh, 0xFF, sizeof(binding->uniform_locs.psh)); } static void shader_cache_entry_post_evict(Lru *lru, LruNode *node) diff --git a/hw/xbox/nv2a/pgraph/glsl/geom.c b/hw/xbox/nv2a/pgraph/glsl/geom.c index 64e957b654..c70565d9f8 100644 --- a/hw/xbox/nv2a/pgraph/glsl/geom.c +++ b/hw/xbox/nv2a/pgraph/glsl/geom.c @@ -134,13 +134,11 @@ MString *pgraph_glsl_gen_geom(const GeomState *state, GenGeomGlslOptions opts) pgraph_glsl_get_vtx_header(output, opts.vulkan, state->smooth_shading, false, false, false); - 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); + if (need_point_size && !opts.gles) { + mstring_append(output, " gl_PointSize = gl_in[index].gl_PointSize;\n"); } mstring_append_fmt( output, diff --git a/ui/xemu.c b/ui/xemu.c index 64c987bef4..9aa9c195df 100644 --- a/ui/xemu.c +++ b/ui/xemu.c @@ -34,6 +34,7 @@ #include "qemu/rcu.h" #include "qemu-version.h" #include "qemu-main.h" +#include "block/block-global-state.h" #include "qapi/error.h" #include "qapi/qapi-commands-block.h" #include "qobject/qdict.h" @@ -823,10 +824,16 @@ void sdl2_poll_events(struct sdl2_console *scon) #ifdef __ANDROID__ case SDL_APP_TERMINATING: g_android_should_quit = true; + bdrv_flush_all(); __android_log_print(ANDROID_LOG_INFO, "xemu-android", - "android: app terminating"); + "android: app terminating, flushed"); break; case SDL_APP_WILLENTERBACKGROUND: + bdrv_flush_all(); + g_android_paused = true; + __android_log_print(ANDROID_LOG_INFO, "xemu-android", + "android: app background, flushed"); + break; case SDL_APP_DIDENTERBACKGROUND: g_android_paused = true; __android_log_print(ANDROID_LOG_INFO, "xemu-android",