From bd5ff205b2c1f6ebeeab94bb8dc02a2ff725f628 Mon Sep 17 00:00:00 2001 From: Marcin Zawiejski Date: Mon, 20 Aug 2018 02:10:14 +0200 Subject: Revert "Batch GLES2 draw calls" This reverts commit f55039b194bbbd8d797b667d67e5677fb429d356. The GLES2 batching seems to require more testing and tweaking in order to actually make the performance better on Android devices. It's been proved with #21184 that the current implementation has it's drawbacks therefore I suggest reverting the commit for now. --- drivers/gles2/rasterizer_canvas_gles2.cpp | 947 +++++++++++++----------------- drivers/gles2/rasterizer_canvas_gles2.h | 46 +- drivers/gles2/rasterizer_gles2.cpp | 5 +- drivers/gles2/rasterizer_storage_gles2.h | 4 +- drivers/gles2/shader_gles2.cpp | 14 +- drivers/gles2/shader_gles2.h | 1 - drivers/gles2/shaders/canvas.glsl | 33 ++ 7 files changed, 454 insertions(+), 596 deletions(-) (limited to 'drivers/gles2') diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp index f7b49c627d..d6fbf04353 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.cpp +++ b/drivers/gles2/rasterizer_canvas_gles2.cpp @@ -64,13 +64,9 @@ void RasterizerCanvasGLES2::_set_uniforms() { state.canvas_shader.set_uniform(CanvasShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size); } - - state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, state.uniforms.texpixel_size); } void RasterizerCanvasGLES2::canvas_begin() { - data.primitive = GL_TRIANGLES; - data.texture = GL_NONE; state.canvas_shader.bind(); if (storage->frame.current_rt) { @@ -99,7 +95,6 @@ void RasterizerCanvasGLES2::canvas_begin() { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); - data.texture = storage->resources.white_tex; glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); glDisableVertexAttribArray(VS::ARRAY_COLOR); @@ -130,7 +125,7 @@ void RasterizerCanvasGLES2::canvas_begin() { state.uniforms.extra_matrix = Transform2D(); _set_uniforms(); - state.prev_uniforms = state.uniforms; + _bind_quad_buffer(); } void RasterizerCanvasGLES2::canvas_end() { @@ -148,7 +143,6 @@ void RasterizerCanvasGLES2::canvas_end() { RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map) { RasterizerStorageGLES2::Texture *tex_return = NULL; - GLuint newtexid; if (p_texture.is_valid()) { @@ -158,7 +152,8 @@ RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(con state.current_tex = RID(); state.current_tex_ptr = NULL; - newtexid = storage->resources.white_tex; + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); } else { @@ -172,7 +167,8 @@ RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(con texture->render_target->used_in_frame = true; } - newtexid = texture->tex_id; + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture->tex_id); state.current_tex = p_texture; state.current_tex_ptr = texture; @@ -183,15 +179,8 @@ RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(con state.current_tex = RID(); state.current_tex_ptr = NULL; - newtexid = storage->resources.white_tex; - } - - if (data.texture != newtexid) { - _flush(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, newtexid); - data.texture = newtexid; + glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); } return tex_return; @@ -201,154 +190,217 @@ void RasterizerCanvasGLES2::_set_texture_rect_mode(bool p_enable, bool p_ninepat } void RasterizerCanvasGLES2::_draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor) { - _begin(GL_TRIANGLES); - _prepare(p_vertex_count, p_index_count); - Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset; + glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); - bool single; - Color color; + uint32_t buffer_ofs = 0; + + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vector2) * p_vertex_count, p_vertices); + glEnableVertexAttribArray(VS::ARRAY_VERTEX); + glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), NULL); + buffer_ofs += sizeof(Vector2) * p_vertex_count; if (p_singlecolor) { - single = true; - color = *p_colors; + glDisableVertexAttribArray(VS::ARRAY_COLOR); + Color m = *p_colors; + glVertexAttrib4f(VS::ARRAY_COLOR, m.r, m.g, m.b, m.a); } else if (!p_colors) { - single = true; - color = Color(1, 1, 1, 1); + glDisableVertexAttribArray(VS::ARRAY_COLOR); + glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); + } else { + glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors); + glEnableVertexAttribArray(VS::ARRAY_COLOR); + glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), ((uint8_t *)0) + buffer_ofs); + buffer_ofs += sizeof(Color) * p_vertex_count; + } + + if (p_uvs) { + glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs); + glEnableVertexAttribArray(VS::ARRAY_TEX_UV); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), ((uint8_t *)0) + buffer_ofs); + buffer_ofs += sizeof(Vector2) * p_vertex_count; } else { - single = false; + glDisableVertexAttribArray(VS::ARRAY_TEX_UV); } - const bool use_single_color = single; - const Color single_color = color; + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(int) * p_index_count, p_indices); + + glDrawElements(GL_TRIANGLES, p_index_count, GL_UNSIGNED_INT, 0); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} - for (int i = 0; i < p_vertex_count; ++i) { - v->v = p_vertices[i]; +void RasterizerCanvasGLES2::_draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor) { - if (use_single_color) - v->c = single_color; - else - v->c = p_colors[i]; + glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); - if (p_uvs) - v->uv = p_uvs[i]; - else - v->uv = Vector2(); + uint32_t buffer_ofs = 0; - ++v; + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vector2) * p_vertex_count, p_vertices); + glEnableVertexAttribArray(VS::ARRAY_VERTEX); + glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), (uint8_t *)0); + buffer_ofs += sizeof(Vector2) * p_vertex_count; + + if (p_singlecolor) { + glDisableVertexAttribArray(VS::ARRAY_COLOR); + Color m = *p_colors; + glVertexAttrib4f(VS::ARRAY_COLOR, m.r, m.g, m.b, m.a); + } else if (!p_colors) { + glDisableVertexAttribArray(VS::ARRAY_COLOR); + glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); + } else { + glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors); + glEnableVertexAttribArray(VS::ARRAY_COLOR); + glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), ((uint8_t *)0) + buffer_ofs); + buffer_ofs += sizeof(Color) * p_vertex_count; } - memcpy(data.mem_index_buffer + data.mem_index_buffer_offset, p_indices, p_index_count * sizeof(int)); + if (p_uvs) { + glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs); + glEnableVertexAttribArray(VS::ARRAY_TEX_UV); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), ((uint8_t *)0) + buffer_ofs); + } else { + glDisableVertexAttribArray(VS::ARRAY_TEX_UV); + } - _commit(p_vertex_count, p_index_count); + glDrawArrays(p_primitive, 0, p_vertex_count); + + glBindBuffer(GL_ARRAY_BUFFER, 0); } -void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip, RasterizerStorageGLES2::Material *p_material) { +void RasterizerCanvasGLES2::_draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs) { - int command_count = p_item->commands.size(); - Item::Command **commands = p_item->commands.ptrw(); + static const GLenum prim[5] = { GL_POINTS, GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLE_FAN }; - for (int i = 0; i < command_count; i++) { + int color_offset = 0; + int uv_offset = 0; + int stride = 2; - Item::Command *command = commands[i]; + if (p_colors) { + color_offset = stride; + stride += 4; + } - if (command->type != Item::Command::TYPE_RECT && state.tiled) { - _flush(); - _untile(); - } + if (p_uvs) { + uv_offset = stride; + stride += 2; + } - switch (command->type) { + float buffer_data[(2 + 2 + 4) * 4]; - case Item::Command::TYPE_LINE: { - const Item::CommandLine *line = static_cast(command); + for (int i = 0; i < p_points; i++) { + buffer_data[stride * i + 0] = p_vertices[i].x; + buffer_data[stride * i + 1] = p_vertices[i].y; + } - if (line->width <= 1) { - const int p_vertex_count = 2; - const int p_index_count = 2; + if (p_colors) { + for (int i = 0; i < p_points; i++) { + buffer_data[stride * i + color_offset + 0] = p_colors[i].r; + buffer_data[stride * i + color_offset + 1] = p_colors[i].g; + buffer_data[stride * i + color_offset + 2] = p_colors[i].b; + buffer_data[stride * i + color_offset + 3] = p_colors[i].a; + } + } - _begin(GL_LINES); - _prepare(p_vertex_count, p_index_count); + if (p_uvs) { + for (int i = 0; i < p_points; i++) { + buffer_data[stride * i + uv_offset + 0] = p_uvs[i].x; + buffer_data[stride * i + uv_offset + 1] = p_uvs[i].y; + } + } - _bind_shader(p_material); - _bind_canvas_texture(RID(), RID()); + glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); + glBufferSubData(GL_ARRAY_BUFFER, 0, p_points * stride * 4 * sizeof(float), buffer_data); - Vertex vertices[p_vertex_count]; + glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, stride * sizeof(float), NULL); - vertices[0].v = Vector2(line->from.x, line->from.y); - vertices[0].c = line->color; - vertices[0].uv = Vector2(); + if (p_colors) { + glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, stride * sizeof(float), (uint8_t *)0 + color_offset * sizeof(float)); + glEnableVertexAttribArray(VS::ARRAY_COLOR); + } - vertices[1].v = Vector2(line->to.x, line->to.y); - vertices[1].c = line->color; - vertices[1].uv = Vector2(); + if (p_uvs) { + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, stride * sizeof(float), (uint8_t *)0 + uv_offset * sizeof(float)); + glEnableVertexAttribArray(VS::ARRAY_TEX_UV); + } - memcpy(data.mem_vertex_buffer + data.mem_vertex_buffer_offset, vertices, sizeof(vertices)); + glDrawArrays(prim[p_points], 0, p_points); - const int indices[p_index_count] = { 0, 1 }; + glBindBuffer(GL_ARRAY_BUFFER, 0); +} - memcpy(data.mem_index_buffer + data.mem_index_buffer_offset, indices, sizeof(indices)); +void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip, RasterizerStorageGLES2::Material *p_material) { - _commit(p_vertex_count, p_index_count); - } else { - const int p_vertex_count = 4; - const int p_index_count = 6; + int command_count = p_item->commands.size(); + Item::Command **commands = p_item->commands.ptrw(); - _begin(GL_TRIANGLES); - _prepare(p_vertex_count, p_index_count); + for (int i = 0; i < command_count; i++) { - _bind_shader(p_material); - _bind_canvas_texture(RID(), RID()); + Item::Command *command = commands[i]; - Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset; + switch (command->type) { - Vector2 t = (line->from - line->to).normalized().tangent() * line->width * 0.5; + case Item::Command::TYPE_LINE: { - v[0].v = line->from - t; - v[0].c = line->color; - v[0].uv = Vector2(); + Item::CommandLine *line = static_cast(command); - v[1].v = line->from + t; - v[1].c = line->color; - v[1].uv = Vector2(); + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false); + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } - v[2].v = line->to + t; - v[2].c = line->color; - v[2].uv = Vector2(); + _bind_canvas_texture(RID(), RID()); + + glDisableVertexAttribArray(VS::ARRAY_COLOR); + glVertexAttrib4fv(VS::ARRAY_COLOR, line->color.components); - v[3].v = line->to - t; - v[3].c = line->color; - v[3].uv = Vector2(); + state.canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX, state.uniforms.modelview_matrix); - const int indices[p_index_count] = { - 0, 1, 2, - 2, 3, 0 + if (line->width <= 1) { + Vector2 verts[2] = { + Vector2(line->from.x, line->from.y), + Vector2(line->to.x, line->to.y) }; - memcpy(data.mem_index_buffer + data.mem_index_buffer_offset, indices, sizeof(indices)); + _draw_gui_primitive(2, verts, NULL, NULL); + } else { + Vector2 t = (line->from - line->to).normalized().tangent() * line->width * 0.5; - _commit(p_vertex_count, p_index_count); - } + Vector2 verts[4] = { + line->from - t, + line->from + t, + line->to + t, + line->to - t + }; + _draw_gui_primitive(4, verts, NULL, NULL); + } } break; case Item::Command::TYPE_RECT: { - const int p_vertex_count = 4; - const int p_index_count = 6; - - _begin(GL_TRIANGLES); - _prepare(p_vertex_count, p_index_count); Item::CommandRect *r = static_cast(command); - _bind_shader(p_material); + glDisableVertexAttribArray(VS::ARRAY_COLOR); + glVertexAttrib4fv(VS::ARRAY_COLOR, r->modulate.components); - Rect2 src_rect; - Rect2 dst_rect; + _bind_quad_buffer(); + + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true); + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false); + 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); if (!tex) { - 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; @@ -359,28 +411,24 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur dst_rect.size.height *= -1; } - src_rect = Rect2(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 { - const bool tiled = r->flags & CANVAS_RECT_TILE && !(tex->flags & VS::TEXTURE_FLAG_REPEAT); + bool untile = false; - if (tiled != state.tiled) { - _flush(); - - if (tiled) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - state.tiled = true; - } else { - _untile(); - } + 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); - src_rect = (r->flags & CANVAS_RECT_REGION) ? Rect2(r->source.position * texpixel_size, r->source.size * texpixel_size) : Rect2(0, 0, 1, 1); - 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; @@ -393,61 +441,48 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur if (r->flags & CANVAS_RECT_FLIP_H) { src_rect.size.x *= -1; - src_rect.position.x -= src_rect.size.width; } + if (r->flags & CANVAS_RECT_FLIP_V) { src_rect.size.y *= -1; - src_rect.position.y -= src_rect.size.height; } + if (r->flags & CANVAS_RECT_TRANSPOSE) { dst_rect.size.x *= -1; // Encoding in the dst_rect.z uniform } - state.uniforms.texpixel_size = texpixel_size; - } - - Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset; - - // 0,0 - v[0].v = dst_rect.position; - v[0].c = r->modulate; - v[0].uv = src_rect.position; + state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); - // 0,1 - v[1].v = Vector2(dst_rect.position.x, dst_rect.position.y + dst_rect.size.y); - v[1].c = r->modulate; - v[1].uv = Vector2(src_rect.position.x, src_rect.position.y + 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)); - // 1,1 - v[2].v = Vector2(dst_rect.position.x + dst_rect.size.x, dst_rect.position.y + dst_rect.size.y); - v[2].c = r->modulate; - v[2].uv = Vector2(src_rect.position.x + src_rect.size.x, src_rect.position.y + src_rect.size.y); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - // 1,0 - v[3].v = Vector2(dst_rect.position.x + dst_rect.size.x, dst_rect.position.y); - v[3].c = r->modulate; - v[3].uv = Vector2(src_rect.position.x + src_rect.size.x, src_rect.position.y); - - const int indices[p_index_count] = { - 0, 1, 2, - 2, 3, 0 - }; + 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); + } + } - memcpy(data.mem_index_buffer + data.mem_index_buffer_offset, indices, sizeof(int) * p_index_count); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - _commit(p_vertex_count, p_index_count); } break; case Item::Command::TYPE_NINEPATCH: { - const int p_vertex_count = 16; - const int p_index_count = 54; - - _begin(GL_TRIANGLES); - _prepare(p_vertex_count, p_index_count); Item::CommandNinePatch *np = static_cast(command); - _bind_shader(p_material); + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, true); + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } + + glDisableVertexAttribArray(VS::ARRAY_COLOR); + glVertexAttrib4fv(VS::ARRAY_COLOR, np->color.components); + RasterizerStorageGLES2::Texture *tex = _bind_canvas_texture(np->texture, np->normal_map); if (!tex) { @@ -457,7 +492,8 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur Size2 texpixel_size(1.0 / tex->width, 1.0 / tex->height); - state.uniforms.texpixel_size = texpixel_size; + // state.canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX, state.uniforms.modelview_matrix); + state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); Rect2 source = np->source; if (source.size.x == 0 && source.size.y == 0) { @@ -469,334 +505,255 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur // this buffer contains [ POS POS UV UV ] * - Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset; + float buffer[16 * 2 + 16 * 2]; - v[0].v = np->rect.position; - v[0].c = np->color; - v[0].uv = source.position * texpixel_size; + { - v[1].v = np->rect.position + Vector2(np->margin[MARGIN_LEFT], 0); - v[1].c = np->color; - v[1].uv = (source.position + Vector2(np->margin[MARGIN_LEFT], 0)) * texpixel_size; + // first row - v[2].v = np->rect.position + Vector2(np->rect.size.x - np->margin[MARGIN_RIGHT], 0); - v[2].c = np->color; - v[2].uv = (source.position + Vector2(source.size.x - np->margin[MARGIN_RIGHT], 0)) * texpixel_size; + buffer[(0 * 4 * 4) + 0] = np->rect.position.x; + buffer[(0 * 4 * 4) + 1] = np->rect.position.y; - v[3].v = np->rect.position + Vector2(np->rect.size.x, 0); - v[3].c = np->color; - v[3].uv = (source.position + Vector2(source.size.x, 0)) * texpixel_size; + buffer[(0 * 4 * 4) + 2] = source.position.x * texpixel_size.x; + buffer[(0 * 4 * 4) + 3] = source.position.y * texpixel_size.y; - v[4].v = np->rect.position + Vector2(0, np->margin[MARGIN_TOP]); - v[4].c = np->color; - v[4].uv = (source.position + Vector2(0, np->margin[MARGIN_TOP])) * texpixel_size; + buffer[(0 * 4 * 4) + 4] = np->rect.position.x + np->margin[MARGIN_LEFT]; + buffer[(0 * 4 * 4) + 5] = np->rect.position.y; - v[5].v = np->rect.position + Vector2(np->margin[MARGIN_LEFT], np->margin[MARGIN_TOP]); - v[5].c = np->color; - v[5].uv = (source.position + Vector2(np->margin[MARGIN_LEFT], np->margin[MARGIN_TOP])) * texpixel_size; + buffer[(0 * 4 * 4) + 6] = (source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x; + buffer[(0 * 4 * 4) + 7] = source.position.y * texpixel_size.y; - v[6].v = np->rect.position + Vector2(np->rect.size.x - np->margin[MARGIN_RIGHT], np->margin[MARGIN_TOP]); - v[6].c = np->color; - v[6].uv = (source.position + Vector2(source.size.x - np->margin[MARGIN_RIGHT], np->margin[MARGIN_TOP])) * texpixel_size; + buffer[(0 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[MARGIN_RIGHT]; + buffer[(0 * 4 * 4) + 9] = np->rect.position.y; - v[7].v = np->rect.position + Vector2(np->rect.size.x, np->margin[MARGIN_TOP]); - v[7].c = np->color; - v[7].uv = (source.position + Vector2(source.size.x, np->margin[MARGIN_TOP])) * texpixel_size; + buffer[(0 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x; + buffer[(0 * 4 * 4) + 11] = source.position.y * texpixel_size.y; - v[8].v = np->rect.position + Vector2(0, np->rect.size.y - np->margin[MARGIN_BOTTOM]); - v[8].c = np->color; - v[8].uv = (source.position + Vector2(0, source.size.y - np->margin[MARGIN_BOTTOM])) * texpixel_size; + buffer[(0 * 4 * 4) + 12] = np->rect.position.x + np->rect.size.x; + buffer[(0 * 4 * 4) + 13] = np->rect.position.y; - v[9].v = np->rect.position + Vector2(np->margin[MARGIN_LEFT], np->rect.size.y - np->margin[MARGIN_BOTTOM]); - v[9].c = np->color; - v[9].uv = (source.position + Vector2(np->margin[MARGIN_LEFT], source.size.y - np->margin[MARGIN_BOTTOM])) * texpixel_size; + buffer[(0 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x; + buffer[(0 * 4 * 4) + 15] = source.position.y * texpixel_size.y; - v[10].v = np->rect.position + np->rect.size - Vector2(np->margin[MARGIN_RIGHT], np->margin[MARGIN_BOTTOM]); - v[10].c = np->color; - v[10].uv = (source.position + source.size - Vector2(np->margin[MARGIN_RIGHT], np->margin[MARGIN_BOTTOM])) * texpixel_size; + // second row - v[11].v = np->rect.position + np->rect.size - Vector2(0, np->margin[MARGIN_BOTTOM]); - v[11].c = np->color; - v[11].uv = (source.position + source.size - Vector2(0, np->margin[MARGIN_BOTTOM])) * texpixel_size; + buffer[(1 * 4 * 4) + 0] = np->rect.position.x; + buffer[(1 * 4 * 4) + 1] = np->rect.position.y + np->margin[MARGIN_TOP]; - v[12].v = np->rect.position + Vector2(0, np->rect.size.y); - v[12].c = np->color; - v[12].uv = (source.position + Vector2(0, source.size.y)) * texpixel_size; + buffer[(1 * 4 * 4) + 2] = source.position.x * texpixel_size.x; + buffer[(1 * 4 * 4) + 3] = (source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y; - v[13].v = np->rect.position + Vector2(np->margin[MARGIN_LEFT], np->rect.size.y); - v[13].c = np->color; - v[13].uv = (source.position + Vector2(np->margin[MARGIN_LEFT], source.size.y)) * texpixel_size; + buffer[(1 * 4 * 4) + 4] = np->rect.position.x + np->margin[MARGIN_LEFT]; + buffer[(1 * 4 * 4) + 5] = np->rect.position.y + np->margin[MARGIN_TOP]; - v[14].v = np->rect.position + np->rect.size - Vector2(np->margin[MARGIN_RIGHT], 0); - v[14].c = np->color; - v[14].uv = (source.position + source.size - Vector2(np->margin[MARGIN_RIGHT], 0)) * texpixel_size; + buffer[(1 * 4 * 4) + 6] = (source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x; + buffer[(1 * 4 * 4) + 7] = (source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y; - v[15].v = np->rect.position + np->rect.size; - v[15].c = np->color; - v[15].uv = (source.position + source.size) * texpixel_size; + buffer[(1 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[MARGIN_RIGHT]; + buffer[(1 * 4 * 4) + 9] = np->rect.position.y + np->margin[MARGIN_TOP]; - memcpy(data.mem_index_buffer + data.mem_index_buffer_offset, data.ninepatch_elements, sizeof(data.ninepatch_elements)); + buffer[(1 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x; + buffer[(1 * 4 * 4) + 11] = (source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y; - _commit(p_vertex_count, p_index_count - (np->draw_center ? 0 : 6)); - } break; + buffer[(1 * 4 * 4) + 12] = np->rect.position.x + np->rect.size.x; + buffer[(1 * 4 * 4) + 13] = np->rect.position.y + np->margin[MARGIN_TOP]; - case Item::Command::TYPE_CIRCLE: { - Item::CommandCircle *circle = static_cast(command); + buffer[(1 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x; + buffer[(1 * 4 * 4) + 15] = (source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y; - _bind_shader(p_material); + // thrid row - const int num_points = 32; + buffer[(2 * 4 * 4) + 0] = np->rect.position.x; + buffer[(2 * 4 * 4) + 1] = np->rect.position.y + np->rect.size.y - np->margin[MARGIN_BOTTOM]; - Vector2 points[num_points + 1]; - points[num_points] = circle->pos; + buffer[(2 * 4 * 4) + 2] = source.position.x * texpixel_size.x; + buffer[(2 * 4 * 4) + 3] = (source.position.y + source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y; - int indices[num_points * 3]; + buffer[(2 * 4 * 4) + 4] = np->rect.position.x + np->margin[MARGIN_LEFT]; + buffer[(2 * 4 * 4) + 5] = np->rect.position.y + np->rect.size.y - np->margin[MARGIN_BOTTOM]; - for (int i = 0; i < num_points; i++) { - points[i] = circle->pos + Vector2(Math::sin(i * Math_PI * 2.0 / num_points), Math::cos(i * Math_PI * 2.0 / num_points)) * circle->radius; - indices[i * 3 + 0] = i; - indices[i * 3 + 1] = (i + 1) % num_points; - indices[i * 3 + 2] = num_points; - } + buffer[(2 * 4 * 4) + 6] = (source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x; + buffer[(2 * 4 * 4) + 7] = (source.position.y + source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y; - _bind_canvas_texture(RID(), RID()); - - _draw_polygon(indices, num_points * 3, num_points + 1, points, NULL, &circle->color, true); - } break; + buffer[(2 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[MARGIN_RIGHT]; + buffer[(2 * 4 * 4) + 9] = np->rect.position.y + np->rect.size.y - np->margin[MARGIN_BOTTOM]; - case Item::Command::TYPE_POLYGON: { - Item::CommandPolygon *polygon = static_cast(command); + buffer[(2 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x; + buffer[(2 * 4 * 4) + 11] = (source.position.y + source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y; - const int *indices = polygon->indices.ptr(); - if (!indices) // self-intersecting polygon - break; + buffer[(2 * 4 * 4) + 12] = np->rect.position.x + np->rect.size.x; + buffer[(2 * 4 * 4) + 13] = np->rect.position.y + np->rect.size.y - np->margin[MARGIN_BOTTOM]; - _bind_shader(p_material); - RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(polygon->texture, polygon->normal_map); + buffer[(2 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x; + buffer[(2 * 4 * 4) + 15] = (source.position.y + source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y; - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.uniforms.texpixel_size = texpixel_size; - } - - _draw_polygon(indices, polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); - } break; - - case Item::Command::TYPE_POLYLINE: { - Item::CommandPolyLine *pline = static_cast(command); + // fourth row - if (pline->triangles.size()) { - const int p_vertex_count = pline->triangles.size(); - const int p_triangle_count = p_vertex_count - 2; - const int p_index_count = p_triangle_count * 3; + buffer[(3 * 4 * 4) + 0] = np->rect.position.x; + buffer[(3 * 4 * 4) + 1] = np->rect.position.y + np->rect.size.y; - _begin(GL_TRIANGLES); - _prepare(p_vertex_count, p_index_count); + buffer[(3 * 4 * 4) + 2] = source.position.x * texpixel_size.x; + buffer[(3 * 4 * 4) + 3] = (source.position.y + source.size.y) * texpixel_size.y; - _bind_shader(p_material); - _bind_canvas_texture(RID(), RID()); + buffer[(3 * 4 * 4) + 4] = np->rect.position.x + np->margin[MARGIN_LEFT]; + buffer[(3 * 4 * 4) + 5] = np->rect.position.y + np->rect.size.y; - const Vector2 *t = pline->triangles.ptr(); - Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset; + buffer[(3 * 4 * 4) + 6] = (source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x; + buffer[(3 * 4 * 4) + 7] = (source.position.y + source.size.y) * texpixel_size.y; - const bool p_singlecolor = pline->triangle_colors.size() == 1; - const Color *p_colors = pline->triangle_colors.ptr(); + buffer[(3 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[MARGIN_RIGHT]; + buffer[(3 * 4 * 4) + 9] = np->rect.position.y + np->rect.size.y; - bool single; - Color color; + buffer[(3 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x; + buffer[(3 * 4 * 4) + 11] = (source.position.y + source.size.y) * texpixel_size.y; - if (pline->triangle_colors.size() == 1) { - single = true; - color = *p_colors; - } else if (!p_colors) { - single = true; - color = Color(1, 1, 1, 1); - } else { - single = false; - } + buffer[(3 * 4 * 4) + 12] = np->rect.position.x + np->rect.size.x; + buffer[(3 * 4 * 4) + 13] = np->rect.position.y + np->rect.size.y; - const bool use_single_color = single; - const Color single_color = color; + buffer[(3 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x; + buffer[(3 * 4 * 4) + 15] = (source.position.y + source.size.y) * texpixel_size.y; - for (int i = 0; i < p_vertex_count; ++i) { - if (use_single_color) - v->c = single_color; - else - v->c = p_colors[i]; + // print_line(String::num((source.position.y + source.size.y) * texpixel_size.y)); + } - v->uv = Vector2(); - v->v = t[i]; + glBindBuffer(GL_ARRAY_BUFFER, data.ninepatch_vertices); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * (16 + 16) * 2, buffer); - ++v; - } + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ninepatch_elements); - for (int i = 0; i < p_triangle_count; ++i) { - const int indices[3] = { - i, i + 1, i + 2 - }; + glEnableVertexAttribArray(VS::ARRAY_VERTEX); + glEnableVertexAttribArray(VS::ARRAY_TEX_UV); - memcpy(data.mem_index_buffer + data.mem_index_buffer_offset + i * 3, indices, sizeof(indices)); - } + glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), NULL); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (uint8_t *)0 + (sizeof(float) * 2)); - _commit(p_vertex_count, p_index_count); - } else { - _begin(GL_LINES); + glDrawElements(GL_TRIANGLES, 18 * 3 - (np->draw_center ? 0 : 6), GL_UNSIGNED_BYTE, NULL); - _bind_shader(p_material); - _bind_canvas_texture(RID(), RID()); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - const Color *p_colors = pline->line_colors.ptr(); + } break; - bool single; - Color color; + case Item::Command::TYPE_CIRCLE: { - if (pline->line_colors.size() == 1) { - single = true; - color = *p_colors; - } else if (!p_colors) { - single = true; - color = Color(1, 1, 1, 1); - } else { - single = false; - } + Item::CommandCircle *circle = static_cast(command); - const bool use_single_color = single; - const Color single_color = color; + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false); - const Vector2 *p_lines = pline->lines.ptr(); + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } - if (pline->multiline) { - const int p_lines_count = pline->lines.size() / 2; + static const int num_points = 32; - for (int i = 0; i < p_lines_count; ++i) { - const int p_vertex_count = 2; - const int p_index_count = 2; + Vector2 points[num_points + 1]; + points[num_points] = circle->pos; - _prepare(p_vertex_count, p_index_count); + int indices[num_points * 3]; - Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset; + for (int i = 0; i < num_points; i++) { + points[i] = circle->pos + Vector2(Math::sin(i * Math_PI * 2.0 / num_points), Math::cos(i * Math_PI * 2.0 / num_points)) * circle->radius; + indices[i * 3 + 0] = i; + indices[i * 3 + 1] = (i + 1) % num_points; + indices[i * 3 + 2] = num_points; + } - for (int j = 0; j < 2; ++j) { - if (use_single_color) - v->c = single_color; - else - v->c = p_colors[i]; + _bind_canvas_texture(RID(), RID()); - v->uv = Vector2(); - v->v = p_lines[i * 2 + j]; + _draw_polygon(indices, num_points * 3, num_points + 1, points, NULL, &circle->color, true); + } break; - ++v; - } + case Item::Command::TYPE_POLYGON: { - const int indices[p_index_count] = { 0, 1 }; + Item::CommandPolygon *polygon = static_cast(command); - memcpy(data.mem_index_buffer + data.mem_index_buffer_offset, indices, sizeof(indices)); + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, true); - _commit(p_vertex_count, p_index_count); - } - } else { - const int p_vertex_count = pline->lines.size(); - const int p_lines_count = p_vertex_count - 1; - const int p_index_count = p_lines_count * 2; + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } - _prepare(p_vertex_count, p_index_count); + RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(polygon->texture, polygon->normal_map); - _bind_shader(p_material); - _bind_canvas_texture(RID(), RID()); + if (texture) { + Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); + state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); + } - Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset; + _draw_polygon(polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); + } break; - for (int i = 0; i < p_vertex_count; ++i) { - if (use_single_color) - v->c = single_color; - else - v->c = p_colors[i]; + case Item::Command::TYPE_POLYLINE: { + Item::CommandPolyLine *pline = static_cast(command); - v->uv = Vector2(); - v->v = p_lines[i]; + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false); - ++v; - } + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } - for (int i = 0; i < p_lines_count; ++i) { - const int indices[2] = { i, i + 1 }; + _bind_canvas_texture(RID(), RID()); - memcpy(data.mem_index_buffer + data.mem_index_buffer_offset + i * 2, indices, sizeof(indices)); + if (pline->triangles.size()) { + _draw_generic(GL_TRIANGLE_STRIP, pline->triangles.size(), pline->triangles.ptr(), NULL, pline->triangle_colors.ptr(), pline->triangle_colors.size() == 1); + } else { + if (pline->multiline) { + int todo = pline->lines.size() / 2; + int max_per_call = data.polygon_buffer_size / (sizeof(real_t) * 4); + int offset = 0; + + while (todo) { + int to_draw = MIN(max_per_call, todo); + _draw_generic(GL_LINES, to_draw * 2, &pline->lines.ptr()[offset], NULL, pline->line_colors.size() == 1 ? pline->line_colors.ptr() : &pline->line_colors.ptr()[offset], pline->line_colors.size() == 1); + todo -= to_draw; + offset += to_draw * 2; } - - _commit(p_vertex_count, p_index_count); + } else { + _draw_generic(GL_LINES, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1); } } } break; case Item::Command::TYPE_PRIMITIVE: { + Item::CommandPrimitive *primitive = static_cast(command); + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, true); - const GLenum prim[5] = { GL_POINTS, GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLE_FAN }; + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } ERR_CONTINUE(primitive->points.size() < 1); - _bind_shader(p_material); RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(primitive->texture, primitive->normal_map); if (texture) { Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.uniforms.texpixel_size = texpixel_size; + state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); } - const int p_vertex_count = primitive->points.size(); - const int p_index_count = p_vertex_count; - - _begin(prim[p_vertex_count]); - _prepare(p_vertex_count, p_index_count); - - Vertex *v = data.mem_vertex_buffer + data.mem_vertex_buffer_offset; - int *index = data.mem_index_buffer + data.mem_index_buffer_offset; - - Color c; - bool p_single_color; - - const Color *p_colors = primitive->colors.ptr(); - const Vector2 *p_uvs = primitive->uvs.ptr(); - const Vector2 *p_points = primitive->points.ptr(); - if (primitive->colors.size() == 1 && primitive->points.size() > 1) { - p_single_color = true; - c = primitive->colors[0]; + Color c = primitive->colors[0]; + glVertexAttrib4f(VS::ARRAY_COLOR, c.r, c.g, c.b, c.a); } else if (primitive->colors.empty()) { - p_single_color = true; - c = Color(1, 1, 1, 1); - } else { - p_single_color = false; - } - - const bool use_single_color = p_single_color; - const Color single_color = c; - - for (int i = 0; i < p_vertex_count; ++i) { - if (use_single_color) - v->c = single_color; - else - v->c = p_colors[i]; - - if (p_uvs) - v->uv = p_uvs[i]; - else - v->uv = Vector2(); - - v->v = p_points[i]; - - index[i] = i; - - ++v; + glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); } - _commit(p_vertex_count, p_index_count); + _draw_gui_primitive(primitive->points.size(), primitive->points.ptr(), primitive->colors.ptr(), primitive->uvs.ptr()); } break; case Item::Command::TYPE_TRANSFORM: { Item::CommandTransform *transform = static_cast(command); state.uniforms.extra_matrix = transform->xform; + state.canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX, state.uniforms.extra_matrix); } break; case Item::Command::TYPE_PARTICLES: { @@ -859,7 +816,6 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); - data.texture = storage->resources.white_tex; int last_blend_mode = -1; @@ -869,9 +825,8 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons Item *ci = p_item_list; - Item *material_owner = ci->material_owner ? ci->material_owner : ci; - if (current_clip != ci->final_clip_owner) { + current_clip = ci->final_clip_owner; if (current_clip) { @@ -895,6 +850,8 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons } } + Item *material_owner = ci->material_owner ? ci->material_owner : ci; + RID material = material_owner->material; RasterizerStorageGLES2::Material *material_ptr = storage->material_owner.getornull(material); @@ -1024,10 +981,8 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons state.uniforms.extra_matrix = Transform2D(); _set_uniforms(); - _canvas_item_render_commands(p_item_list, NULL, reclip, material_ptr); - // TODO: figure out when to _flush to get better batching results - _flush(); + _canvas_item_render_commands(p_item_list, NULL, reclip, material_ptr); rebind_shader = true; // hacked in for now. @@ -1042,8 +997,6 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons p_item_list = p_item_list->next; } - _flush(); - if (current_clip) { glDisable(GL_SCISSOR_TEST); } @@ -1082,40 +1035,17 @@ void RasterizerCanvasGLES2::reset_canvas() { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } -void RasterizerCanvasGLES2::draw_generic_textured_rect(const Rect2 &dst_rect, const Rect2 &src_rect) { - - const int p_index_count = 6; - const int p_vertex_count = 4; - - Vertex v[p_vertex_count]; - Color c(1, 1, 1, 1); - - // 0,0 - v[0].v = dst_rect.position; - v[0].c = c; - v[0].uv = src_rect.position; - - // 0,1 - v[1].v = Vector2(dst_rect.position.x, dst_rect.position.y + dst_rect.size.y); - v[1].c = c; - v[1].uv = Vector2(src_rect.position.x, src_rect.position.y + src_rect.size.y); - - // 1,1 - v[2].v = Vector2(dst_rect.position.x + dst_rect.size.x, dst_rect.position.y + dst_rect.size.y); - v[2].c = c; - v[2].uv = Vector2(src_rect.position.x + src_rect.size.x, src_rect.position.y + src_rect.size.y); - - // 1,0 - v[3].v = Vector2(dst_rect.position.x + dst_rect.size.x, dst_rect.position.y); - v[3].c = c; - v[3].uv = Vector2(src_rect.position.x + src_rect.size.x, src_rect.position.y); +void RasterizerCanvasGLES2::_bind_quad_buffer() { + glBindBuffer(GL_ARRAY_BUFFER, data.canvas_quad_vertices); + glEnableVertexAttribArray(VS::ARRAY_VERTEX); + glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, 0, NULL); +} +void RasterizerCanvasGLES2::draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src) { - const int indices[p_index_count] = { - 0, 1, 2, - 2, 3, 0 - }; + state.canvas_shader.set_uniform(CanvasShaderGLES2::DST_RECT, Color(p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y)); + state.canvas_shader.set_uniform(CanvasShaderGLES2::SRC_RECT, Color(p_src.position.x, p_src.position.y, p_src.size.x, p_src.size.y)); - _draw(GL_TRIANGLES, p_vertex_count, v, p_index_count, indices); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } void RasterizerCanvasGLES2::draw_window_margins(int *black_margin, RID *black_image) { @@ -1123,36 +1053,60 @@ void RasterizerCanvasGLES2::draw_window_margins(int *black_margin, RID *black_im void RasterizerCanvasGLES2::initialize() { + // quad buffer + { + glGenBuffers(1, &data.canvas_quad_vertices); + glBindBuffer(GL_ARRAY_BUFFER, data.canvas_quad_vertices); + + const float qv[8] = { + 0, 0, + 0, 1, + 1, 1, + 1, 0 + }; + + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, qv, GL_STATIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + // polygon buffer { uint32_t poly_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_buffer_size_kb", 128); poly_size *= 1024; poly_size = MAX(poly_size, (2 + 2 + 4) * 4 * sizeof(float)); - glGenBuffers(1, &data.vertex_buffer); - glBindBuffer(GL_ARRAY_BUFFER, data.vertex_buffer); + glGenBuffers(1, &data.polygon_buffer); + glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); glBufferData(GL_ARRAY_BUFFER, poly_size, NULL, GL_DYNAMIC_DRAW); - data.vertex_buffer_size = poly_size; + data.polygon_buffer_size = poly_size; glBindBuffer(GL_ARRAY_BUFFER, 0); uint32_t index_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_index_size_kb", 128); index_size *= 1024; // kb - glGenBuffers(1, &data.index_buffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.index_buffer); + glGenBuffers(1, &data.polygon_index_buffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_size, NULL, GL_DYNAMIC_DRAW); - - data.index_buffer_size = index_size; - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } // ninepatch buffers { // array buffer + glGenBuffers(1, &data.ninepatch_vertices); + glBindBuffer(GL_ARRAY_BUFFER, data.ninepatch_vertices); + + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * (16 + 16) * 2, NULL, GL_DYNAMIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + + // element buffer + glGenBuffers(1, &data.ninepatch_elements); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ninepatch_elements); #define _EIDX(y, x) (y * 4 + x) - const int elems[3 * 2 * 9] = { + uint8_t elems[3 * 2 * 9] = { // first row @@ -1196,25 +1150,15 @@ void RasterizerCanvasGLES2::initialize() { ; #undef _EIDX - memcpy(data.ninepatch_elements, elems, sizeof(elems)); - } + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elems), elems, GL_STATIC_DRAW); - { - const uint32_t size = data.vertex_buffer_size / sizeof(Vertex); - data.mem_vertex_buffer = (Vertex *)memalloc(sizeof(Vertex) * size); - data.mem_vertex_buffer_offset = 0; - data.mem_vertex_buffer_size = size; - } - - { - const uint32_t size = data.index_buffer_size / sizeof(int); - data.mem_index_buffer = (int *)memalloc(sizeof(int) * size); - data.mem_index_buffer_offset = 0; - data.mem_index_buffer_size = size; + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } state.canvas_shader.init(); + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true); + state.canvas_shader.bind(); } @@ -1223,92 +1167,3 @@ void RasterizerCanvasGLES2::finalize() { RasterizerCanvasGLES2::RasterizerCanvasGLES2() { } - -void RasterizerCanvasGLES2::_begin(const GLuint p_primitive) { - if (data.primitive != p_primitive) { - _flush(); - data.primitive = p_primitive; - } -} - -void RasterizerCanvasGLES2::_prepare(const int p_vertex_count, const int p_index_count) { - if (data.mem_vertex_buffer_size - data.mem_vertex_buffer_offset < p_vertex_count || - data.mem_index_buffer_size - data.mem_index_buffer_offset < p_index_count) { - _flush(); - } -} - -void RasterizerCanvasGLES2::_draw(const GLuint p_primitive, const int p_vertex_count, const Vertex *p_vertices, const int p_index_count, const int *p_indices) { - glBindBuffer(GL_ARRAY_BUFFER, data.vertex_buffer); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vertex) * p_vertex_count, p_vertices); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.index_buffer); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(int) * p_index_count, p_indices); - - glEnableVertexAttribArray(VS::ARRAY_VERTEX); - glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), NULL); - - glEnableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), ((uint8_t *)0) + sizeof(Vector2)); - - glEnableVertexAttribArray(VS::ARRAY_TEX_UV); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), ((uint8_t *)0) + sizeof(Vector2) + sizeof(Color)); - - glDrawElements(p_primitive, p_index_count, GL_UNSIGNED_INT, 0); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -} - -void RasterizerCanvasGLES2::_flush() { - if (data.mem_vertex_buffer_offset) { - _draw(data.primitive, data.mem_vertex_buffer_offset, data.mem_vertex_buffer, data.mem_index_buffer_offset, data.mem_index_buffer); - } - - data.mem_vertex_buffer_offset = 0; - data.mem_index_buffer_offset = 0; -} - -void RasterizerCanvasGLES2::_commit(const int p_vertex_count, const int p_index_count) { - ERR_FAIL_COND(!p_vertex_count); - ERR_FAIL_COND(!p_index_count); - - if (state.uniforms.extra_matrix != state.prev_uniforms.extra_matrix || - state.uniforms.final_modulate != state.prev_uniforms.final_modulate || - state.uniforms.modelview_matrix != state.prev_uniforms.modelview_matrix || - state.uniforms.projection_matrix != state.prev_uniforms.projection_matrix || - state.uniforms.texpixel_size != state.prev_uniforms.texpixel_size || - state.uniforms.time != state.prev_uniforms.time) { - - _set_uniforms(); - state.prev_uniforms = state.uniforms; - _flush(); - } - - const int new_index_offset = data.mem_index_buffer_offset + p_index_count; - - for (int i = data.mem_index_buffer_offset; i < new_index_offset; ++i) - data.mem_index_buffer[i] += data.mem_vertex_buffer_offset; - - data.mem_vertex_buffer_offset += p_vertex_count; - data.mem_index_buffer_offset = new_index_offset; -} - -void RasterizerCanvasGLES2::_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); - - state.tiled = false; -} - -void RasterizerCanvasGLES2::_bind_shader(RasterizerStorageGLES2::Material *p_material) { - if (!state.canvas_shader.is_dirty()) { - return; - } - - _flush(); - - if (state.canvas_shader.bind()) { - state.canvas_shader.use_material((void *)p_material); - } -} diff --git a/drivers/gles2/rasterizer_canvas_gles2.h b/drivers/gles2/rasterizer_canvas_gles2.h index d5a122e533..cda3ec79e7 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.h +++ b/drivers/gles2/rasterizer_canvas_gles2.h @@ -50,44 +50,23 @@ public: Color final_modulate; float time; - - Size2 texpixel_size; - }; - - struct Vertex { - Vector2 v; - Color c; - Vector2 uv; }; struct Data { - GLuint vertex_buffer; - GLuint index_buffer; - - uint32_t vertex_buffer_size; - uint32_t index_buffer_size; - - int ninepatch_elements[3 * 2 * 9]; + GLuint canvas_quad_vertices; + GLuint polygon_buffer; + GLuint polygon_index_buffer; - int *mem_index_buffer; - uint32_t mem_index_buffer_offset; - uint32_t mem_index_buffer_size; + uint32_t polygon_buffer_size; - Vertex *mem_vertex_buffer; - uint32_t mem_vertex_buffer_offset; - uint32_t mem_vertex_buffer_size; + GLuint ninepatch_vertices; + GLuint ninepatch_elements; - GLuint primitive; - GLuint texture; } data; struct State { Uniforms uniforms; - Uniforms prev_uniforms; - - bool tiled; - bool canvas_texscreen_used; CanvasShaderGLES2 canvas_shader; // CanvasShadowShaderGLES3 canvas_shadow_shader; @@ -120,16 +99,9 @@ public: _FORCE_INLINE_ void _set_texture_rect_mode(bool p_enable, bool p_ninepatch = false); + _FORCE_INLINE_ void _draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs); _FORCE_INLINE_ void _draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor); - - _FORCE_INLINE_ void _begin(const GLuint p_primitive); - _FORCE_INLINE_ void _prepare(const int p_vertex_count, const int p_index_count); - _FORCE_INLINE_ void _commit(const int p_vertex_count, const int p_index_count); - - _FORCE_INLINE_ void _flush(); - _FORCE_INLINE_ void _draw(const GLuint p_primitive, const int p_vertex_count, const Vertex *p_vertices, const int p_index_count, const int *p_indices); - - _FORCE_INLINE_ void _untile(); + _FORCE_INLINE_ void _draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor); _FORCE_INLINE_ void _canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip, RasterizerStorageGLES2::Material *p_material); _FORCE_INLINE_ void _copy_texscreen(const Rect2 &p_rect); @@ -142,8 +114,8 @@ public: virtual void reset_canvas(); RasterizerStorageGLES2::Texture *_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map); - _FORCE_INLINE_ void _bind_shader(RasterizerStorageGLES2::Material *p_material); + void _bind_quad_buffer(); void draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src); void initialize(); diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index 165ffc0412..a1a0b9e2c6 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -345,6 +345,9 @@ void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Re RasterizerStorageGLES2::RenderTarget *rt = storage->render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); + canvas->state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true); + canvas->state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false); + canvas->state.canvas_shader.set_custom_shader(0); canvas->state.canvas_shader.bind(); @@ -356,7 +359,7 @@ void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Re // TODO normals - canvas->draw_generic_textured_rect(p_screen_rect, Rect2(0, 1, 1, -1)); + canvas->draw_generic_textured_rect(p_screen_rect, Rect2(0, 0, 1, -1)); glBindTexture(GL_TEXTURE_2D, 0); canvas->canvas_end(); diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index 38c0ccaac2..c1fbf73254 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -252,7 +252,7 @@ public: int mipmaps; bool active; - GLuint tex_id; + GLenum tex_id; uint16_t stored_cube_sides; @@ -429,8 +429,6 @@ public: bool uses_screen_texture; bool uses_screen_uv; bool uses_time; - bool uses_modelview_matrix; - bool uses_vertex; } canvas_item; diff --git a/drivers/gles2/shader_gles2.cpp b/drivers/gles2/shader_gles2.cpp index 89c1b6490d..e9b58cb272 100644 --- a/drivers/gles2/shader_gles2.cpp +++ b/drivers/gles2/shader_gles2.cpp @@ -122,11 +122,13 @@ GLint ShaderGLES2::get_uniform_location(int p_index) const { } bool ShaderGLES2::bind() { - if (!is_dirty()) - return false; - conditional_version = new_conditional_version; - version = get_current_version(); + if (active != this || !version || new_conditional_version.key != conditional_version.key) { + conditional_version = new_conditional_version; + version = get_current_version(); + } else { + return false; + } ERR_FAIL_COND_V(!version, false); @@ -1107,7 +1109,3 @@ ShaderGLES2::ShaderGLES2() { ShaderGLES2::~ShaderGLES2() { finish(); } - -bool ShaderGLES2::is_dirty() const { - return active != this || !version || new_conditional_version.key != conditional_version.key; -} diff --git a/drivers/gles2/shader_gles2.h b/drivers/gles2/shader_gles2.h index 99513abfe9..cb515c199c 100644 --- a/drivers/gles2/shader_gles2.h +++ b/drivers/gles2/shader_gles2.h @@ -208,7 +208,6 @@ public: GLint get_uniform_location(int p_index) const; static _FORCE_INLINE_ ShaderGLES2 *get_active() { return active; } - bool is_dirty() const; bool bind(); void unbind(); void bind_uniforms(); diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl index a63c7675d8..29d81bb2c4 100644 --- a/drivers/gles2/shaders/canvas.glsl +++ b/drivers/gles2/shaders/canvas.glsl @@ -20,6 +20,13 @@ varying vec4 color_interp; uniform highp vec2 color_texpixel_size; +#ifdef USE_TEXTURE_RECT + +uniform vec4 dst_rect; +uniform vec4 src_rect; + +#endif + uniform highp float time; VERTEX_SHADER_GLOBALS @@ -37,9 +44,35 @@ void main() { vec4 color = color_attrib; +#ifdef USE_TEXTURE_RECT + + if (dst_rect.z < 0.0) { // Transpose is encoded as negative dst_rect.z + uv_interp = src_rect.xy + abs(src_rect.zw) * vertex.yx; + } else { + uv_interp = src_rect.xy + abs(src_rect.zw) * vertex; + } + + vec4 outvec = vec4(0.0, 0.0, 0.0, 1.0); + + // This is what is done in the GLES 3 bindings and should + // take care of flipped rects. + // + // But it doesn't. + // I don't know why, will need to investigate further. + + outvec.xy = dst_rect.xy + abs(dst_rect.zw) * select(vertex, vec2(1.0, 1.0) - vertex, lessThan(src_rect.zw, vec2(0.0, 0.0))); + + // outvec.xy = dst_rect.xy + abs(dst_rect.zw) * vertex; +#else vec4 outvec = vec4(vertex.xy, 0.0, 1.0); +#ifdef USE_UV_ATTRIBUTE uv_interp = uv_attrib; +#else + uv_interp = vertex.xy; +#endif + +#endif { vec2 src_vtx=outvec.xy; -- cgit v1.2.3