Merge pull request #87352 from Alex2782/fix_opengl_es3
Fix Compatibility Rendering (GLES3) on old and low budget devices.
This commit is contained in:
commit
7359ec7a57
8 changed files with 84 additions and 18 deletions
|
@ -194,6 +194,11 @@ typedef void(GLAPIENTRY *DebugMessageCallbackARB)(DEBUGPROCARB callback, const v
|
||||||
|
|
||||||
void RasterizerGLES3::initialize() {
|
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()));
|
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() {
|
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();
|
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,
|
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);
|
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||||
|
|
||||||
if (read_fbo != 0) {
|
if (read_fbo != 0) {
|
||||||
|
|
|
@ -55,6 +55,7 @@ private:
|
||||||
float delta = 0;
|
float delta = 0;
|
||||||
|
|
||||||
double time_total = 0.0;
|
double time_total = 0.0;
|
||||||
|
bool flip_xy_bugfix = false;
|
||||||
|
|
||||||
static bool gles_over_gl;
|
static bool gles_over_gl;
|
||||||
|
|
||||||
|
|
|
@ -187,8 +187,31 @@ void main() {
|
||||||
#endif // !USE_INSTANCING
|
#endif // !USE_INSTANCING
|
||||||
|
|
||||||
#else // !USE_ATTRIBUTES
|
#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);
|
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;
|
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) {
|
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;
|
uint blend_mode = light_array[light_base].flags & LIGHT_FLAGS_BLEND_MASK;
|
||||||
|
|
||||||
switch (blend_mode) {
|
if (blend_mode == LIGHT_FLAGS_BLEND_MODE_ADD) {
|
||||||
case LIGHT_FLAGS_BLEND_MODE_ADD: {
|
color.rgb += light_color.rgb * light_color.a;
|
||||||
color.rgb += light_color.rgb * light_color.a;
|
} else if (blend_mode == LIGHT_FLAGS_BLEND_MODE_SUB) {
|
||||||
} break;
|
color.rgb -= light_color.rgb * light_color.a;
|
||||||
case LIGHT_FLAGS_BLEND_MODE_SUB: {
|
} else if (blend_mode == LIGHT_FLAGS_BLEND_MODE_MIX) {
|
||||||
color.rgb -= light_color.rgb * light_color.a;
|
color.rgb = mix(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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
vec3 spot_dir = spot_lights[idx].direction;
|
||||||
float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights[idx].cone_angle);
|
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));
|
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;
|
vec3 color = spot_lights[idx].color;
|
||||||
|
|
||||||
float size_A = 0.0;
|
float size_A = 0.0;
|
||||||
|
|
|
@ -166,6 +166,11 @@ Config::Config() {
|
||||||
max_renderable_elements = GLOBAL_GET("rendering/limits/opengl/max_renderable_elements");
|
max_renderable_elements = GLOBAL_GET("rendering/limits/opengl/max_renderable_elements");
|
||||||
max_renderable_lights = GLOBAL_GET("rendering/limits/opengl/max_renderable_lights");
|
max_renderable_lights = GLOBAL_GET("rendering/limits/opengl/max_renderable_lights");
|
||||||
max_lights_per_object = GLOBAL_GET("rendering/limits/opengl/max_lights_per_object");
|
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() {
|
Config::~Config() {
|
||||||
|
|
|
@ -91,6 +91,8 @@ public:
|
||||||
bool rt_msaa_multiview_supported = false;
|
bool rt_msaa_multiview_supported = false;
|
||||||
bool multiview_supported = false;
|
bool multiview_supported = false;
|
||||||
|
|
||||||
|
bool adreno_3xx_compatibility = false;
|
||||||
|
|
||||||
#ifdef ANDROID_ENABLED
|
#ifdef ANDROID_ENABLED
|
||||||
PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC eglFramebufferTextureMultiviewOVR = nullptr;
|
PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC eglFramebufferTextureMultiviewOVR = nullptr;
|
||||||
PFNGLTEXSTORAGE3DMULTISAMPLEPROC eglTexStorage3DMultisample = nullptr;
|
PFNGLTEXSTORAGE3DMULTISAMPLEPROC eglTexStorage3DMultisample = nullptr;
|
||||||
|
|
|
@ -1673,7 +1673,24 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
||||||
mWantRenderNotification = true;
|
mWantRenderNotification = true;
|
||||||
mRequestRender = true;
|
mRequestRender = true;
|
||||||
mRenderComplete = false;
|
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();
|
sGLThreadManager.notifyAll();
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,11 +66,15 @@ public class RegularContextFactory implements GLSurfaceView.EGLContextFactory {
|
||||||
|
|
||||||
GLUtils.checkEglError(TAG, "Before eglCreateContext", egl);
|
GLUtils.checkEglError(TAG, "Before eglCreateContext", egl);
|
||||||
EGLContext context;
|
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) {
|
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, debug_attrib_list);
|
||||||
context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, 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 {
|
} else {
|
||||||
int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL10.EGL_NONE };
|
|
||||||
context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
|
context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
|
||||||
}
|
}
|
||||||
GLUtils.checkEglError(TAG, "After eglCreateContext", egl);
|
GLUtils.checkEglError(TAG, "After eglCreateContext", egl);
|
||||||
|
|
Loading…
Reference in a new issue