diff options
author | Rémi Verschelde <rverschelde@gmail.com> | 2019-01-14 18:26:41 +0100 |
---|---|---|
committer | Rémi Verschelde <rverschelde@gmail.com> | 2019-01-14 19:02:07 +0100 |
commit | 02ffc59270f48dc2ea52ae911bbcb80cf15168cf (patch) | |
tree | 67f21d889759d95e4ff1dc954b9b1c969324d040 /drivers | |
parent | 6f884cc88409fa1eb25b95f0fe91fc848c1b1481 (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.cpp | 247 | ||||
-rw-r--r-- | drivers/gles2/rasterizer_canvas_gles2.h | 2 |
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); |