summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRémi Verschelde <rverschelde@gmail.com>2019-01-14 18:26:41 +0100
committerRémi Verschelde <rverschelde@gmail.com>2019-01-14 19:02:07 +0100
commit02ffc59270f48dc2ea52ae911bbcb80cf15168cf (patch)
tree67f21d889759d95e4ff1dc954b9b1c969324d040
parent6f884cc88409fa1eb25b95f0fe91fc848c1b1481 (diff)
GLES2: Make Nvidia flicker workaround opt-in
It has a big impact on 2D and text rendering performance (cf. #24466) so the solution seems worse than the bug it aims to work around. It's now opt-in via "rendering/quality/2d/gles2_use_nvidia_rect_flicker_workaround" for those who need it and have a simple enough game for the performance drop not to be an issue. Fixes #24466.
-rw-r--r--core/project_settings.cpp2
-rw-r--r--doc/classes/ProjectSettings.xml4
-rw-r--r--drivers/gles2/rasterizer_canvas_gles2.cpp247
-rw-r--r--drivers/gles2/rasterizer_canvas_gles2.h2
-rw-r--r--main/main.cpp3
5 files changed, 137 insertions, 121 deletions
diff --git a/core/project_settings.cpp b/core/project_settings.cpp
index e325c828b8..8d05d7cc74 100644
--- a/core/project_settings.cpp
+++ b/core/project_settings.cpp
@@ -1163,8 +1163,6 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("input/ui_end", action);
input_presets.push_back("input/ui_end");
- //GLOBAL_DEF("display/window/handheld/orientation", "landscape");
-
custom_prop_info["display/window/handheld/orientation"] = PropertyInfo(Variant::STRING, "display/window/handheld/orientation", PROPERTY_HINT_ENUM, "landscape,portrait,reverse_landscape,reverse_portrait,sensor_landscape,sensor_portrait,sensor");
custom_prop_info["rendering/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/threads/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded");
custom_prop_info["physics/2d/thread_model"] = PropertyInfo(Variant::INT, "physics/2d/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded");
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 172a50d779..6b53615535 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -670,6 +670,10 @@
<member name="rendering/limits/time/time_rollover_secs" type="float" setter="" getter="">
Shaders have a time variable that constantly increases. At some point it needs to be rolled back to zero to avoid numerical errors on shader animations. This setting specifies when.
</member>
+ <member name="rendering/quality/2d/gles2_use_nvidia_rect_flicker_workaround" type="bool" setter="" getter="">
+ Some Nvidia GPU drivers have a bug, which produces flickering issues for the [code]draw_rect[/code] method, especially as used in [TileMap]. Refer to https://github.com/godotengine/godot/issues/9913 for details.
+ If [code]true[/code], this option enables a "safe" code path for such Nvidia GPUs, at the cost of performance. This option only impacts the GLES2 rendering backend (so the bug stays if you use GLES3), and only desktop platforms. Default value: [code]false[/code].
+ </member>
<member name="rendering/quality/2d/use_pixel_snap" type="bool" setter="" getter="">
Force snapping of polygons to pixels in 2D rendering. May help in some pixel art styles.
</member>
diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp
index 2152810e8f..b008e18f67 100644
--- a/drivers/gles2/rasterizer_canvas_gles2.cpp
+++ b/drivers/gles2/rasterizer_canvas_gles2.cpp
@@ -489,161 +489,164 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
glDisableVertexAttribArray(VS::ARRAY_COLOR);
glVertexAttrib4fv(VS::ARRAY_COLOR, r->modulate.components);
-//use a more compatible workaround, as this does not fail on nvidia
-#ifdef GLES_OVER_GL
- //more compatible
- state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false);
-
- if (state.canvas_shader.bind()) {
- _set_uniforms();
- state.canvas_shader.use_material((void *)p_material);
- }
+ // On some widespread Nvidia cards, the normal draw method can produce some
+ // flickering in draw_rect and especially TileMap rendering (tiles randomly flicker).
+ // See GH-9913.
+ // To work it around, we use a simpler draw method which does not flicker, but gives
+ // a non negligible performance hit, so it's opt-in (GH-24466).
+ if (use_nvidia_rect_workaround) {
+ state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false);
+
+ if (state.canvas_shader.bind()) {
+ _set_uniforms();
+ state.canvas_shader.use_material((void *)p_material);
+ }
- Vector2 points[4] = {
- r->rect.position,
- r->rect.position + Vector2(r->rect.size.x, 0.0),
- r->rect.position + r->rect.size,
- r->rect.position + Vector2(0.0, r->rect.size.y),
- };
+ Vector2 points[4] = {
+ r->rect.position,
+ r->rect.position + Vector2(r->rect.size.x, 0.0),
+ r->rect.position + r->rect.size,
+ r->rect.position + Vector2(0.0, r->rect.size.y),
+ };
- if (r->rect.size.x < 0) {
- SWAP(points[0], points[1]);
- SWAP(points[2], points[3]);
- }
- if (r->rect.size.y < 0) {
- SWAP(points[0], points[3]);
- SWAP(points[1], points[2]);
- }
+ if (r->rect.size.x < 0) {
+ SWAP(points[0], points[1]);
+ SWAP(points[2], points[3]);
+ }
+ if (r->rect.size.y < 0) {
+ SWAP(points[0], points[3]);
+ SWAP(points[1], points[2]);
+ }
- RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(r->texture, r->normal_map);
+ RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(r->texture, r->normal_map);
- if (texture) {
- Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
+ if (texture) {
+ Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
- Rect2 src_rect = (r->flags & CANVAS_RECT_REGION) ? Rect2(r->source.position * texpixel_size, r->source.size * texpixel_size) : Rect2(0, 0, 1, 1);
+ Rect2 src_rect = (r->flags & CANVAS_RECT_REGION) ? Rect2(r->source.position * texpixel_size, r->source.size * texpixel_size) : Rect2(0, 0, 1, 1);
- Vector2 uvs[4] = {
- src_rect.position,
- src_rect.position + Vector2(src_rect.size.x, 0.0),
- src_rect.position + src_rect.size,
- src_rect.position + Vector2(0.0, src_rect.size.y),
- };
+ Vector2 uvs[4] = {
+ src_rect.position,
+ src_rect.position + Vector2(src_rect.size.x, 0.0),
+ src_rect.position + src_rect.size,
+ src_rect.position + Vector2(0.0, src_rect.size.y),
+ };
- if (r->flags & CANVAS_RECT_TRANSPOSE) {
- SWAP(uvs[1], uvs[3]);
- }
+ if (r->flags & CANVAS_RECT_TRANSPOSE) {
+ SWAP(uvs[1], uvs[3]);
+ }
- if (r->flags & CANVAS_RECT_FLIP_H) {
- SWAP(uvs[0], uvs[1]);
- SWAP(uvs[2], uvs[3]);
- }
- if (r->flags & CANVAS_RECT_FLIP_V) {
- SWAP(uvs[0], uvs[3]);
- SWAP(uvs[1], uvs[2]);
- }
+ if (r->flags & CANVAS_RECT_FLIP_H) {
+ SWAP(uvs[0], uvs[1]);
+ SWAP(uvs[2], uvs[3]);
+ }
+ if (r->flags & CANVAS_RECT_FLIP_V) {
+ SWAP(uvs[0], uvs[3]);
+ SWAP(uvs[1], uvs[2]);
+ }
- state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size);
+ state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size);
- bool untile = false;
+ bool untile = false;
- if (r->flags & CANVAS_RECT_TILE && !(texture->flags & VS::TEXTURE_FLAG_REPEAT)) {
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- untile = true;
- }
+ if (r->flags & CANVAS_RECT_TILE && !(texture->flags & VS::TEXTURE_FLAG_REPEAT)) {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ untile = true;
+ }
- _draw_gui_primitive(4, points, NULL, uvs);
+ _draw_gui_primitive(4, points, NULL, uvs);
- if (untile) {
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ if (untile) {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
+ } else {
+ state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, Vector2());
+ _draw_gui_primitive(4, points, NULL, NULL);
}
- } else {
- state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, Vector2());
- _draw_gui_primitive(4, points, NULL, NULL);
- }
-#else
- //disabled because it fails on buggy nvidia drivers
- _bind_quad_buffer();
+ } else {
+ // This branch is better for performance, but can produce flicker on Nvidia, see above comment.
+ _bind_quad_buffer();
- state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true);
+ state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true);
- if (state.canvas_shader.bind()) {
- _set_uniforms();
- state.canvas_shader.use_material((void *)p_material);
- }
+ if (state.canvas_shader.bind()) {
+ _set_uniforms();
+ state.canvas_shader.use_material((void *)p_material);
+ }
- RasterizerStorageGLES2::Texture *tex = _bind_canvas_texture(r->texture, r->normal_map);
+ RasterizerStorageGLES2::Texture *tex = _bind_canvas_texture(r->texture, r->normal_map);
- if (!tex) {
- Rect2 dst_rect = Rect2(r->rect.position, r->rect.size);
+ if (!tex) {
+ Rect2 dst_rect = Rect2(r->rect.position, r->rect.size);
- if (dst_rect.size.width < 0) {
- dst_rect.position.x += dst_rect.size.width;
- dst_rect.size.width *= -1;
- }
- if (dst_rect.size.height < 0) {
- dst_rect.position.y += dst_rect.size.height;
- dst_rect.size.height *= -1;
- }
+ if (dst_rect.size.width < 0) {
+ dst_rect.position.x += dst_rect.size.width;
+ dst_rect.size.width *= -1;
+ }
+ if (dst_rect.size.height < 0) {
+ dst_rect.position.y += dst_rect.size.height;
+ dst_rect.size.height *= -1;
+ }
- state.canvas_shader.set_uniform(CanvasShaderGLES2::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y));
- state.canvas_shader.set_uniform(CanvasShaderGLES2::SRC_RECT, Color(0, 0, 1, 1));
+ state.canvas_shader.set_uniform(CanvasShaderGLES2::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y));
+ state.canvas_shader.set_uniform(CanvasShaderGLES2::SRC_RECT, Color(0, 0, 1, 1));
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- } else {
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ } else {
- bool untile = false;
+ bool untile = false;
- if (r->flags & CANVAS_RECT_TILE && !(tex->flags & VS::TEXTURE_FLAG_REPEAT)) {
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- untile = true;
- }
+ if (r->flags & CANVAS_RECT_TILE && !(tex->flags & VS::TEXTURE_FLAG_REPEAT)) {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ untile = true;
+ }
- Size2 texpixel_size(1.0 / tex->width, 1.0 / tex->height);
- Rect2 src_rect = (r->flags & CANVAS_RECT_REGION) ? Rect2(r->source.position * texpixel_size, r->source.size * texpixel_size) : Rect2(0, 0, 1, 1);
+ Size2 texpixel_size(1.0 / tex->width, 1.0 / tex->height);
+ Rect2 src_rect = (r->flags & CANVAS_RECT_REGION) ? Rect2(r->source.position * texpixel_size, r->source.size * texpixel_size) : Rect2(0, 0, 1, 1);
- Rect2 dst_rect = Rect2(r->rect.position, r->rect.size);
+ Rect2 dst_rect = Rect2(r->rect.position, r->rect.size);
- if (dst_rect.size.width < 0) {
- dst_rect.position.x += dst_rect.size.width;
- dst_rect.size.width *= -1;
- }
- if (dst_rect.size.height < 0) {
- dst_rect.position.y += dst_rect.size.height;
- dst_rect.size.height *= -1;
- }
+ if (dst_rect.size.width < 0) {
+ dst_rect.position.x += dst_rect.size.width;
+ dst_rect.size.width *= -1;
+ }
+ if (dst_rect.size.height < 0) {
+ dst_rect.position.y += dst_rect.size.height;
+ dst_rect.size.height *= -1;
+ }
- if (r->flags & CANVAS_RECT_FLIP_H) {
- src_rect.size.x *= -1;
- }
+ if (r->flags & CANVAS_RECT_FLIP_H) {
+ src_rect.size.x *= -1;
+ }
- if (r->flags & CANVAS_RECT_FLIP_V) {
- src_rect.size.y *= -1;
- }
+ if (r->flags & CANVAS_RECT_FLIP_V) {
+ src_rect.size.y *= -1;
+ }
- if (r->flags & CANVAS_RECT_TRANSPOSE) {
- dst_rect.size.x *= -1; // Encoding in the dst_rect.z uniform
- }
+ if (r->flags & CANVAS_RECT_TRANSPOSE) {
+ dst_rect.size.x *= -1; // Encoding in the dst_rect.z uniform
+ }
- state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size);
+ state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size);
- state.canvas_shader.set_uniform(CanvasShaderGLES2::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y));
- state.canvas_shader.set_uniform(CanvasShaderGLES2::SRC_RECT, Color(src_rect.position.x, src_rect.position.y, src_rect.size.x, src_rect.size.y));
+ state.canvas_shader.set_uniform(CanvasShaderGLES2::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y));
+ state.canvas_shader.set_uniform(CanvasShaderGLES2::SRC_RECT, Color(src_rect.position.x, src_rect.position.y, src_rect.size.x, src_rect.size.y));
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- if (untile) {
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ if (untile) {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
}
- }
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-#endif
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
} break;
case Item::Command::TYPE_NINEPATCH: {
@@ -1856,4 +1859,10 @@ void RasterizerCanvasGLES2::finalize() {
}
RasterizerCanvasGLES2::RasterizerCanvasGLES2() {
+#ifdef GLES_OVER_GL
+ use_nvidia_rect_workaround = GLOBAL_GET("rendering/quality/2d/gles2_use_nvidia_rect_flicker_workaround");
+#else
+ // Not needed (a priori) on GLES devices
+ use_nvidia_rect_workaround = false;
+#endif
}
diff --git a/drivers/gles2/rasterizer_canvas_gles2.h b/drivers/gles2/rasterizer_canvas_gles2.h
index ddb72d1c63..221427198a 100644
--- a/drivers/gles2/rasterizer_canvas_gles2.h
+++ b/drivers/gles2/rasterizer_canvas_gles2.h
@@ -102,6 +102,8 @@ public:
RasterizerStorageGLES2 *storage;
+ bool use_nvidia_rect_workaround;
+
virtual RID light_internal_create();
virtual void light_internal_update(RID p_rid, Light *p_light);
virtual void light_internal_free(RID p_rid);
diff --git a/main/main.cpp b/main/main.cpp
index e0f9cfb9d9..cbf30af38c 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -880,6 +880,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
GLOBAL_DEF("rendering/quality/driver/driver_fallback", "Best");
ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/driver/driver_fallback", PropertyInfo(Variant::STRING, "rendering/quality/driver/driver_fallback", PROPERTY_HINT_ENUM, "Best,Never"));
+ // Assigning here even though it's GLES2-specific, to be sure that it appears in docs
+ GLOBAL_DEF("rendering/quality/2d/gles2_use_nvidia_rect_flicker_workaround", false);
+
GLOBAL_DEF("display/window/size/width", 1024);
ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/width", PropertyInfo(Variant::INT, "display/window/size/width", PROPERTY_HINT_RANGE, "0,7680,or_greater")); // 8K resolution
GLOBAL_DEF("display/window/size/height", 600);