summaryrefslogtreecommitdiff
path: root/drivers
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 /drivers
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.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gles2/rasterizer_canvas_gles2.cpp247
-rw-r--r--drivers/gles2/rasterizer_canvas_gles2.h2
2 files changed, 130 insertions, 119 deletions
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);