Merge pull request #38517 from lawnjelly/gles3_nvidia_workaround
Add Nvidia Workaround for GLES3
This commit is contained in:
@ -1008,7 +1008,7 @@ void RasterizerCanvasBaseGLES2::finalize() {
|
||||
|
||||
RasterizerCanvasBaseGLES2::RasterizerCanvasBaseGLES2() {
|
||||
#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
|
||||
// Not needed (a priori) on GLES devices
|
||||
use_nvidia_rect_workaround = false;
|
||||
|
||||
@ -621,6 +621,82 @@ static const GLenum gl_primitive[] = {
|
||||
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) {
|
||||
|
||||
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);
|
||||
|
||||
_set_texture_rect_mode(true);
|
||||
|
||||
//set color
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (use_nvidia_rect_workaround) {
|
||||
render_rect_nvidia_workaround(rect, texture);
|
||||
} 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;
|
||||
_set_texture_rect_mode(true);
|
||||
|
||||
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) {
|
||||
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 not use nvidia workaround
|
||||
} break;
|
||||
|
||||
case Item::Command::TYPE_NINEPATCH: {
|
||||
|
||||
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++;
|
||||
} break;
|
||||
|
||||
case Item::Command::TYPE_PRIMITIVE: {
|
||||
|
||||
Item::CommandPrimitive *primitive = static_cast<Item::CommandPrimitive *>(c);
|
||||
@ -2265,4 +2343,10 @@ void RasterizerCanvasGLES3::finalize() {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
RasterizerStorageGLES3 *storage;
|
||||
bool use_nvidia_rect_workaround;
|
||||
|
||||
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_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 finalize();
|
||||
|
||||
Reference in New Issue
Block a user