From e17cecf54a4e98ede77e87a08d33742463bddca5 Mon Sep 17 00:00:00 2001 From: Alexander Hartmann Date: Fri, 19 Jan 2024 00:07:28 +0100 Subject: [PATCH] Fix Compatibility Rendering (GLES3) on old and low budget devices. Co-Authored-By: joined72 <19651914+joined72@users.noreply.github.com> --- drivers/gles3/rasterizer_gles3.cpp | 17 +++++++- drivers/gles3/rasterizer_gles3.h | 1 + drivers/gles3/shaders/canvas.glsl | 43 +++++++++++++------ drivers/gles3/shaders/scene.glsl | 5 ++- drivers/gles3/storage/config.cpp | 5 +++ drivers/gles3/storage/config.h | 2 + .../godotengine/godot/gl/GLSurfaceView.java | 19 +++++++- .../xr/regular/RegularContextFactory.java | 10 +++-- 8 files changed, 84 insertions(+), 18 deletions(-) diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 14ef0f40cf2..da2320c23d5 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -194,6 +194,11 @@ typedef void(GLAPIENTRY *DebugMessageCallbackARB)(DEBUGPROCARB callback, const v void RasterizerGLES3::initialize() { Engine::get_singleton()->print_header(vformat("OpenGL API %s - Compatibility - Using Device: %s - %s", RS::get_singleton()->get_video_adapter_api_version(), RS::get_singleton()->get_video_adapter_vendor(), RS::get_singleton()->get_video_adapter_name())); + + // FLIP XY Bug: Are more devices affected? + // Confirmed so far: all Adreno 3xx + // ok on some tested Adreno devices: 4xx, 5xx and 6xx + flip_xy_bugfix = GLES3::Config::get_singleton()->adreno_3xx_compatibility; } void RasterizerGLES3::finalize() { @@ -398,8 +403,18 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display } Vector2i screen_rect_end = p_screen_rect.get_end(); + + // Adreno (TM) 3xx devices have a bug that create wrong Landscape rotation of 180 degree + // Reversing both the X and Y axis is equivalent to rotating 180 degrees + bool flip_x = false; + if (flip_xy_bugfix && screen_rect_end.x > screen_rect_end.y) { + flip_y = !flip_y; + flip_x = !flip_x; + } + glBlitFramebuffer(0, 0, rt->size.x, rt->size.y, - p_screen_rect.position.x, flip_y ? screen_rect_end.y : p_screen_rect.position.y, screen_rect_end.x, flip_y ? p_screen_rect.position.y : screen_rect_end.y, + flip_x ? screen_rect_end.x : p_screen_rect.position.x, flip_y ? screen_rect_end.y : p_screen_rect.position.y, + flip_x ? p_screen_rect.position.x : screen_rect_end.x, flip_y ? p_screen_rect.position.y : screen_rect_end.y, GL_COLOR_BUFFER_BIT, GL_NEAREST); if (read_fbo != 0) { diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h index fc1315035b1..8d52dc23655 100644 --- a/drivers/gles3/rasterizer_gles3.h +++ b/drivers/gles3/rasterizer_gles3.h @@ -55,6 +55,7 @@ private: float delta = 0; double time_total = 0.0; + bool flip_xy_bugfix = false; static bool gles_over_gl; diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index 80e28cf9fc5..8da7d7dc807 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -187,8 +187,31 @@ void main() { #endif // !USE_INSTANCING #else // !USE_ATTRIBUTES - vec2 vertex_base_arr[6] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0), vec2(0.0, 0.0), vec2(1.0, 1.0)); - vec2 vertex_base = vertex_base_arr[gl_VertexID % 6]; + + // crash on Adreno 320/330 + //vec2 vertex_base_arr[6] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0), vec2(0.0, 0.0), vec2(1.0, 1.0)); + //vec2 vertex_base = vertex_base_arr[gl_VertexID % 6]; + //----------------------------------------- + // ID | 0 | 1 | 2 | 3 | 4 | 5 | + //----------------------------------------- + // X | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 | 1.0 | + // Y | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 1.0 | + //----------------------------------------- + // no crash or freeze on all Adreno 3xx with 'if / else if' and slightly faster! + int vertex_id = gl_VertexID % 6; + vec2 vertex_base; + if (vertex_id == 0) + vertex_base = vec2(0.0, 0.0); + else if (vertex_id == 1) + vertex_base = vec2(0.0, 1.0); + else if (vertex_id == 2) + vertex_base = vec2(1.0, 1.0); + else if (vertex_id == 3) + vertex_base = vec2(1.0, 0.0); + else if (vertex_id == 4) + vertex_base = vec2(0.0, 0.0); + else if (vertex_id == 5) + vertex_base = vec2(1.0, 1.0); vec2 uv = read_draw_data_src_rect.xy + abs(read_draw_data_src_rect.zw) * ((read_draw_data_flags & FLAGS_TRANSPOSE_RECT) != uint(0) ? vertex_base.yx : vertex_base.xy); vec4 color = read_draw_data_modulation; @@ -475,16 +498,12 @@ vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv void light_blend_compute(uint light_base, vec4 light_color, inout vec3 color) { uint blend_mode = light_array[light_base].flags & LIGHT_FLAGS_BLEND_MASK; - switch (blend_mode) { - case LIGHT_FLAGS_BLEND_MODE_ADD: { - color.rgb += light_color.rgb * light_color.a; - } break; - case LIGHT_FLAGS_BLEND_MODE_SUB: { - color.rgb -= light_color.rgb * light_color.a; - } break; - case LIGHT_FLAGS_BLEND_MODE_MIX: { - color.rgb = mix(color.rgb, light_color.rgb, light_color.a); - } break; + if (blend_mode == LIGHT_FLAGS_BLEND_MODE_ADD) { + color.rgb += light_color.rgb * light_color.a; + } else if (blend_mode == LIGHT_FLAGS_BLEND_MODE_SUB) { + color.rgb -= light_color.rgb * light_color.a; + } else if (blend_mode == LIGHT_FLAGS_BLEND_MODE_MIX) { + color.rgb = mix(color.rgb, light_color.rgb, light_color.a); } } diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 27c292d1635..a6db90c3f54 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -1200,7 +1200,10 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f vec3 spot_dir = spot_lights[idx].direction; float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights[idx].cone_angle); float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights[idx].cone_angle)); - spot_attenuation *= 1.0 - pow(spot_rim, spot_lights[idx].cone_attenuation); + + mediump float cone_attenuation = spot_lights[idx].cone_attenuation; + spot_attenuation *= 1.0 - pow(spot_rim, cone_attenuation); + vec3 color = spot_lights[idx].color; float size_A = 0.0; diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp index 5d01ab03466..1a41b60836e 100644 --- a/drivers/gles3/storage/config.cpp +++ b/drivers/gles3/storage/config.cpp @@ -166,6 +166,11 @@ Config::Config() { max_renderable_elements = GLOBAL_GET("rendering/limits/opengl/max_renderable_elements"); max_renderable_lights = GLOBAL_GET("rendering/limits/opengl/max_renderable_lights"); max_lights_per_object = GLOBAL_GET("rendering/limits/opengl/max_lights_per_object"); + + //Adreno 3xx Compatibility + const String rendering_device_name = String::utf8((const char *)glGetString(GL_RENDERER)); + //TODO: Check the number between 300 and 399(?) + adreno_3xx_compatibility = (rendering_device_name.left(13) == "Adreno (TM) 3"); } Config::~Config() { diff --git a/drivers/gles3/storage/config.h b/drivers/gles3/storage/config.h index 1c0a5178bd0..c3ab65f0bc0 100644 --- a/drivers/gles3/storage/config.h +++ b/drivers/gles3/storage/config.h @@ -91,6 +91,8 @@ public: bool rt_msaa_multiview_supported = false; bool multiview_supported = false; + bool adreno_3xx_compatibility = false; + #ifdef ANDROID_ENABLED PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC eglFramebufferTextureMultiviewOVR = nullptr; PFNGLTEXSTORAGE3DMULTISAMPLEPROC eglTexStorage3DMultisample = nullptr; diff --git a/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java b/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java index ef97aaeab94..bd8c58ad69b 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java @@ -1673,7 +1673,24 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback mWantRenderNotification = true; mRequestRender = true; mRenderComplete = false; - mFinishDrawingRunnable = finishDrawing; + + // fix lost old callback when continuous call requestRenderAndNotify + // + // If continuous call requestRenderAndNotify before trigger old + // callback, old callback will lose, cause VRI will wait for SV's + // draw to finish forever not calling finishDraw. + // https://android.googlesource.com/platform/frameworks/base/+/044fce0b826f2da3a192aac56785b5089143e693%5E%21/ + //+++++++++++++++++++++++++++++++++++++++++++++++++++ + final Runnable oldCallback = mFinishDrawingRunnable; + mFinishDrawingRunnable = () -> { + if (oldCallback != null) { + oldCallback.run(); + } + if (finishDrawing != null) { + finishDrawing.run(); + } + }; + //---------------------------------------------------- sGLThreadManager.notifyAll(); } diff --git a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java index 01ee41e30b2..1f0d8592b31 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java +++ b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java @@ -66,11 +66,15 @@ public class RegularContextFactory implements GLSurfaceView.EGLContextFactory { GLUtils.checkEglError(TAG, "Before eglCreateContext", egl); EGLContext context; + int[] debug_attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 3, _EGL_CONTEXT_FLAGS_KHR, _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL10.EGL_NONE }; + int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL10.EGL_NONE }; if (mUseDebugOpengl) { - int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 3, _EGL_CONTEXT_FLAGS_KHR, _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL10.EGL_NONE }; - context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); + context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, debug_attrib_list); + if (context == null || context == EGL10.EGL_NO_CONTEXT) { + Log.w(TAG, "creating 'OpenGL Debug' context failed"); + context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); + } } else { - int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL10.EGL_NONE }; context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); } GLUtils.checkEglError(TAG, "After eglCreateContext", egl);