Merge pull request #38517 from lawnjelly/gles3_nvidia_workaround
Add Nvidia Workaround for GLES3
This commit is contained in:
commit
d038a7e42d
|
@ -1034,9 +1034,9 @@
|
||||||
<member name="rendering/limits/time/time_rollover_secs" type="float" setter="" getter="" default="3600">
|
<member name="rendering/limits/time/time_rollover_secs" type="float" setter="" getter="" default="3600">
|
||||||
Shaders have a time variable that constantly increases. At some point, it needs to be rolled back to zero to avoid precision errors on shader animations. This setting specifies when (in seconds).
|
Shaders have a time variable that constantly increases. At some point, it needs to be rolled back to zero to avoid precision errors on shader animations. This setting specifies when (in seconds).
|
||||||
</member>
|
</member>
|
||||||
<member name="rendering/quality/2d/gles2_use_nvidia_rect_flicker_workaround" type="bool" setter="" getter="" default="false">
|
<member name="rendering/quality/2d/use_nvidia_rect_flicker_workaround" type="bool" setter="" getter="" default="false">
|
||||||
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 [url=https://github.com/godotengine/godot/issues/9913]GitHub issue 9913[/url] for details.
|
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 [url=https://github.com/godotengine/godot/issues/9913]GitHub issue 9913[/url] 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.
|
If [code]true[/code], this option enables a "safe" code path for such NVIDIA GPUs at the cost of performance. This option affects GLES2 and GLES3 rendering, but only on desktop platforms.
|
||||||
</member>
|
</member>
|
||||||
<member name="rendering/quality/2d/use_pixel_snap" type="bool" setter="" getter="" default="false">
|
<member name="rendering/quality/2d/use_pixel_snap" type="bool" setter="" getter="" default="false">
|
||||||
If [code]true[/code], forces snapping of polygons to pixels in 2D rendering. May help in some pixel art styles.
|
If [code]true[/code], forces snapping of polygons to pixels in 2D rendering. May help in some pixel art styles.
|
||||||
|
|
|
@ -1008,7 +1008,7 @@ void RasterizerCanvasBaseGLES2::finalize() {
|
||||||
|
|
||||||
RasterizerCanvasBaseGLES2::RasterizerCanvasBaseGLES2() {
|
RasterizerCanvasBaseGLES2::RasterizerCanvasBaseGLES2() {
|
||||||
#ifdef GLES_OVER_GL
|
#ifdef GLES_OVER_GL
|
||||||
use_nvidia_rect_workaround = GLOBAL_GET("rendering/quality/2d/gles2_use_nvidia_rect_flicker_workaround");
|
use_nvidia_rect_workaround = GLOBAL_GET("rendering/quality/2d/use_nvidia_rect_flicker_workaround");
|
||||||
#else
|
#else
|
||||||
// Not needed (a priori) on GLES devices
|
// Not needed (a priori) on GLES devices
|
||||||
use_nvidia_rect_workaround = false;
|
use_nvidia_rect_workaround = false;
|
||||||
|
|
|
@ -621,6 +621,82 @@ static const GLenum gl_primitive[] = {
|
||||||
GL_TRIANGLE_FAN
|
GL_TRIANGLE_FAN
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void RasterizerCanvasGLES3::render_rect_nvidia_workaround(const Item::CommandRect *p_rect, const RasterizerStorageGLES3::Texture *p_texture) {
|
||||||
|
|
||||||
|
_set_texture_rect_mode(false);
|
||||||
|
|
||||||
|
if (p_texture) {
|
||||||
|
|
||||||
|
bool untile = false;
|
||||||
|
|
||||||
|
if (p_rect->flags & CANVAS_RECT_TILE && !(p_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
Size2 texpixel_size(1.0 / p_texture->width, 1.0 / p_texture->height);
|
||||||
|
|
||||||
|
state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, p_rect->flags & CANVAS_RECT_CLIP_UV);
|
||||||
|
|
||||||
|
Vector2 points[4] = {
|
||||||
|
p_rect->rect.position,
|
||||||
|
p_rect->rect.position + Vector2(p_rect->rect.size.x, 0.0),
|
||||||
|
p_rect->rect.position + p_rect->rect.size,
|
||||||
|
p_rect->rect.position + Vector2(0.0, p_rect->rect.size.y),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (p_rect->rect.size.x < 0) {
|
||||||
|
SWAP(points[0], points[1]);
|
||||||
|
SWAP(points[2], points[3]);
|
||||||
|
}
|
||||||
|
if (p_rect->rect.size.y < 0) {
|
||||||
|
SWAP(points[0], points[3]);
|
||||||
|
SWAP(points[1], points[2]);
|
||||||
|
}
|
||||||
|
Rect2 src_rect = (p_rect->flags & CANVAS_RECT_REGION) ? Rect2(p_rect->source.position * texpixel_size, p_rect->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),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (p_rect->flags & CANVAS_RECT_TRANSPOSE) {
|
||||||
|
SWAP(uvs[1], uvs[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_rect->flags & CANVAS_RECT_FLIP_H) {
|
||||||
|
SWAP(uvs[0], uvs[1]);
|
||||||
|
SWAP(uvs[2], uvs[3]);
|
||||||
|
}
|
||||||
|
if (p_rect->flags & CANVAS_RECT_FLIP_V) {
|
||||||
|
SWAP(uvs[0], uvs[3]);
|
||||||
|
SWAP(uvs[1], uvs[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, false);
|
||||||
|
|
||||||
|
Vector2 points[4] = {
|
||||||
|
p_rect->rect.position,
|
||||||
|
p_rect->rect.position + Vector2(p_rect->rect.size.x, 0.0),
|
||||||
|
p_rect->rect.position + p_rect->rect.size,
|
||||||
|
p_rect->rect.position + Vector2(0.0, p_rect->rect.size.y),
|
||||||
|
};
|
||||||
|
|
||||||
|
_draw_gui_primitive(4, points, NULL, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip) {
|
void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip) {
|
||||||
|
|
||||||
int cc = p_item->commands.size();
|
int cc = p_item->commands.size();
|
||||||
|
@ -740,83 +816,86 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur
|
||||||
|
|
||||||
Item::CommandRect *rect = static_cast<Item::CommandRect *>(c);
|
Item::CommandRect *rect = static_cast<Item::CommandRect *>(c);
|
||||||
|
|
||||||
_set_texture_rect_mode(true);
|
|
||||||
|
|
||||||
//set color
|
//set color
|
||||||
glVertexAttrib4f(VS::ARRAY_COLOR, rect->modulate.r, rect->modulate.g, rect->modulate.b, rect->modulate.a);
|
glVertexAttrib4f(VS::ARRAY_COLOR, rect->modulate.r, rect->modulate.g, rect->modulate.b, rect->modulate.a);
|
||||||
|
|
||||||
RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(rect->texture, rect->normal_map);
|
RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(rect->texture, rect->normal_map);
|
||||||
|
|
||||||
if (texture) {
|
if (use_nvidia_rect_workaround) {
|
||||||
|
render_rect_nvidia_workaround(rect, texture);
|
||||||
bool untile = false;
|
|
||||||
|
|
||||||
if (rect->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;
|
|
||||||
}
|
|
||||||
|
|
||||||
Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
|
|
||||||
Rect2 src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * texpixel_size, rect->source.size * texpixel_size) : Rect2(0, 0, 1, 1);
|
|
||||||
Rect2 dst_rect = Rect2(rect->rect.position, rect->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 (rect->flags & CANVAS_RECT_FLIP_H) {
|
|
||||||
src_rect.size.x *= -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rect->flags & CANVAS_RECT_FLIP_V) {
|
|
||||||
src_rect.size.y *= -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rect->flags & CANVAS_RECT_TRANSPOSE) {
|
|
||||||
dst_rect.size.x *= -1; // Encoding in the dst_rect.z uniform
|
|
||||||
}
|
|
||||||
|
|
||||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
|
|
||||||
|
|
||||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y));
|
|
||||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::SRC_RECT, Color(src_rect.position.x, src_rect.position.y, src_rect.size.x, src_rect.size.y));
|
|
||||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, rect->flags & CANVAS_RECT_CLIP_UV);
|
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
||||||
storage->info.render._2d_draw_call_count++;
|
|
||||||
|
|
||||||
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 {
|
} else {
|
||||||
Rect2 dst_rect = Rect2(rect->rect.position, rect->rect.size);
|
|
||||||
|
|
||||||
if (dst_rect.size.width < 0) {
|
_set_texture_rect_mode(true);
|
||||||
dst_rect.position.x += dst_rect.size.width;
|
|
||||||
dst_rect.size.width *= -1;
|
if (texture) {
|
||||||
|
|
||||||
|
bool untile = false;
|
||||||
|
|
||||||
|
if (rect->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;
|
||||||
|
}
|
||||||
|
|
||||||
|
Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
|
||||||
|
Rect2 src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * texpixel_size, rect->source.size * texpixel_size) : Rect2(0, 0, 1, 1);
|
||||||
|
Rect2 dst_rect = Rect2(rect->rect.position, rect->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 (rect->flags & CANVAS_RECT_FLIP_H) {
|
||||||
|
src_rect.size.x *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rect->flags & CANVAS_RECT_FLIP_V) {
|
||||||
|
src_rect.size.y *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rect->flags & CANVAS_RECT_TRANSPOSE) {
|
||||||
|
dst_rect.size.x *= -1; // Encoding in the dst_rect.z uniform
|
||||||
|
}
|
||||||
|
|
||||||
|
state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
|
||||||
|
|
||||||
|
state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y));
|
||||||
|
state.canvas_shader.set_uniform(CanvasShaderGLES3::SRC_RECT, Color(src_rect.position.x, src_rect.position.y, src_rect.size.x, src_rect.size.y));
|
||||||
|
state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, rect->flags & CANVAS_RECT_CLIP_UV);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||||
|
storage->info.render._2d_draw_call_count++;
|
||||||
|
|
||||||
|
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 {
|
||||||
|
Rect2 dst_rect = Rect2(rect->rect.position, rect->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;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y));
|
||||||
|
state.canvas_shader.set_uniform(CanvasShaderGLES3::SRC_RECT, Color(0, 0, 1, 1));
|
||||||
|
state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, false);
|
||||||
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||||
|
storage->info.render._2d_draw_call_count++;
|
||||||
}
|
}
|
||||||
if (dst_rect.size.height < 0) {
|
} // if not use nvidia workaround
|
||||||
dst_rect.position.y += dst_rect.size.height;
|
|
||||||
dst_rect.size.height *= -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y));
|
|
||||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::SRC_RECT, Color(0, 0, 1, 1));
|
|
||||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, false);
|
|
||||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
||||||
storage->info.render._2d_draw_call_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Item::Command::TYPE_NINEPATCH: {
|
case Item::Command::TYPE_NINEPATCH: {
|
||||||
|
|
||||||
Item::CommandNinePatch *np = static_cast<Item::CommandNinePatch *>(c);
|
Item::CommandNinePatch *np = static_cast<Item::CommandNinePatch *>(c);
|
||||||
|
@ -858,7 +937,6 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur
|
||||||
|
|
||||||
storage->info.render._2d_draw_call_count++;
|
storage->info.render._2d_draw_call_count++;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Item::Command::TYPE_PRIMITIVE: {
|
case Item::Command::TYPE_PRIMITIVE: {
|
||||||
|
|
||||||
Item::CommandPrimitive *primitive = static_cast<Item::CommandPrimitive *>(c);
|
Item::CommandPrimitive *primitive = static_cast<Item::CommandPrimitive *>(c);
|
||||||
|
@ -2265,4 +2343,10 @@ void RasterizerCanvasGLES3::finalize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
RasterizerCanvasGLES3::RasterizerCanvasGLES3() {
|
RasterizerCanvasGLES3::RasterizerCanvasGLES3() {
|
||||||
|
// Not needed (a priori) on GLES devices
|
||||||
|
use_nvidia_rect_workaround = false;
|
||||||
|
|
||||||
|
#ifdef GLES_OVER_GL
|
||||||
|
use_nvidia_rect_workaround = GLOBAL_GET("rendering/quality/2d/use_nvidia_rect_flicker_workaround");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,6 +95,7 @@ public:
|
||||||
} state;
|
} state;
|
||||||
|
|
||||||
RasterizerStorageGLES3 *storage;
|
RasterizerStorageGLES3 *storage;
|
||||||
|
bool use_nvidia_rect_workaround;
|
||||||
|
|
||||||
struct LightInternal : public RID_Data {
|
struct LightInternal : public RID_Data {
|
||||||
|
|
||||||
|
@ -146,6 +147,7 @@ public:
|
||||||
|
|
||||||
void draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src);
|
void draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src);
|
||||||
void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample);
|
void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample);
|
||||||
|
void render_rect_nvidia_workaround(const Item::CommandRect *p_rect, const RasterizerStorageGLES3::Texture *p_texture);
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
void finalize();
|
void finalize();
|
||||||
|
|
|
@ -995,8 +995,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
||||||
|
|
||||||
GLOBAL_DEF("rendering/quality/driver/fallback_to_gles2", false);
|
GLOBAL_DEF("rendering/quality/driver/fallback_to_gles2", false);
|
||||||
|
|
||||||
// Assigning here even though it's GLES2-specific, to be sure that it appears in docs
|
// Assigning here, to be sure that it appears in docs
|
||||||
GLOBAL_DEF("rendering/quality/2d/gles2_use_nvidia_rect_flicker_workaround", false);
|
GLOBAL_DEF("rendering/quality/2d/use_nvidia_rect_flicker_workaround", false);
|
||||||
|
|
||||||
GLOBAL_DEF("display/window/size/width", 1024);
|
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
|
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
|
||||||
|
|
Loading…
Reference in New Issue