diff options
author | Juan Linietsky <reduzio@gmail.com> | 2019-06-24 16:13:06 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2020-02-11 11:53:27 +0100 |
commit | 1b4281b895f3046ea972256182b18696a25f8316 (patch) | |
tree | 5f6b9c1600a4354f17b29e430a447d08f93ecf25 /servers/visual | |
parent | 42b44f43ee52eb664d3610d0fdae0eff14c00f0a (diff) |
basic 2D engine is more or less working with Vulkan, including editor.
Still a lot to do
Diffstat (limited to 'servers/visual')
-rw-r--r-- | servers/visual/rasterizer/rasterizer.h | 176 | ||||
-rw-r--r-- | servers/visual/rasterizer/rasterizer_canvas_rd.cpp | 866 | ||||
-rw-r--r-- | servers/visual/rasterizer/rasterizer_canvas_rd.h | 84 | ||||
-rw-r--r-- | servers/visual/rasterizer/rasterizer_rd.cpp | 4 | ||||
-rw-r--r-- | servers/visual/rasterizer/rasterizer_rd.h | 1 | ||||
-rw-r--r-- | servers/visual/rasterizer/rasterizer_storage_rd.cpp | 229 | ||||
-rw-r--r-- | servers/visual/rasterizer/rasterizer_storage_rd.h | 23 | ||||
-rw-r--r-- | servers/visual/rasterizer/render_pipeline_vertex_format_cache_rd.cpp | 5 | ||||
-rw-r--r-- | servers/visual/rasterizer/shaders/canvas.glsl | 56 | ||||
-rw-r--r-- | servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl | 34 | ||||
-rw-r--r-- | servers/visual/rendering_device.h | 5 | ||||
-rw-r--r-- | servers/visual/visual_server_canvas.cpp | 184 | ||||
-rw-r--r-- | servers/visual/visual_server_canvas.h | 4 | ||||
-rw-r--r-- | servers/visual/visual_server_raster.h | 4 | ||||
-rw-r--r-- | servers/visual/visual_server_viewport.cpp | 13 | ||||
-rw-r--r-- | servers/visual/visual_server_wrap_mt.h | 4 |
16 files changed, 1101 insertions, 591 deletions
diff --git a/servers/visual/rasterizer/rasterizer.h b/servers/visual/rasterizer/rasterizer.h index c70056ea9a..bb7c51f79b 100644 --- a/servers/visual/rasterizer/rasterizer.h +++ b/servers/visual/rasterizer/rasterizer.h @@ -182,10 +182,12 @@ public: virtual RID texture_2d_create(const Ref<Image> &p_image) = 0; virtual RID texture_2d_layered_create(const Vector<Ref<Image> > &p_layers, VS::TextureLayeredType p_layered_type) = 0; virtual RID texture_3d_create(const Vector<Ref<Image> > &p_slices) = 0; //all slices, then all the mipmaps, must be coherent + virtual RID texture_proxy_create(RID p_base) = 0; //all slices, then all the mipmaps, must be coherent virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; //mostly used for video and streaming virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; virtual void texture_3d_update(RID p_texture, const Ref<Image> &p_image, int p_depth, int p_mipmap) = 0; + virtual void texture_proxy_update(RID p_proxy, RID p_base) = 0; //these two APIs can be used together or in combination with the others. virtual RID texture_2d_placeholder_create() = 0; @@ -212,10 +214,9 @@ public: virtual void texture_debug_usage(List<VS::TextureInfo> *r_info) = 0; - virtual void texture_set_proxy(RID p_proxy, RID p_base) = 0; virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) = 0; - virtual Size2 texture_size_with_proxy(RID p_proxy) const = 0; + virtual Size2 texture_size_with_proxy(RID p_proxy) = 0; /* SKY API */ @@ -553,7 +554,12 @@ public: virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) = 0; virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) = 0; virtual bool render_target_was_used(RID p_render_target) = 0; - virtual void render_target_clear_used_flag(RID p_render_target) = 0; + virtual void render_target_set_as_unused(RID p_render_target) = 0; + + virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color) = 0; + virtual bool render_target_is_clear_requested(RID p_render_target) = 0; + virtual Color render_target_get_clear_request_color(RID p_render_target) = 0; + virtual void render_target_disable_clear_request(RID p_render_target) = 0; /* CANVAS SHADOW */ @@ -702,22 +708,50 @@ public: } }; + typedef uint64_t PolygonID; + virtual PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) = 0; + virtual void free_polygon(PolygonID p_polygon) = 0; + + //also easier to wrap to avoid mistakes + struct Polygon { + + PolygonID polygon_id; + Rect2 rect_cache; + + _FORCE_INLINE_ void create(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) { + ERR_FAIL_COND(polygon_id != 0); + { + uint32_t pc = p_points.size(); + const Vector2 *v2 = p_points.ptr(); + rect_cache.position = *v2; + for (uint32_t i = 1; i < pc; i++) { + rect_cache.expand_to(v2[i]); + } + } + polygon_id = singleton->request_polygon(p_indices, p_points, p_colors, p_uvs, p_bones, p_weights); + } + + _FORCE_INLINE_ Polygon() { polygon_id = 0; } + _FORCE_INLINE_ ~Polygon() { + if (polygon_id) singleton->free_polygon(polygon_id); + } + }; + + //item + struct Item { struct Command { enum Type { - TYPE_LINE, - TYPE_POLYLINE, TYPE_RECT, TYPE_NINEPATCH, - TYPE_PRIMITIVE, TYPE_POLYGON, + TYPE_PRIMITIVE, TYPE_MESH, TYPE_MULTIMESH, TYPE_PARTICLES, - TYPE_CIRCLE, TYPE_TRANSFORM, TYPE_CLIP_IGNORE, }; @@ -726,29 +760,6 @@ public: virtual ~Command() {} }; - struct CommandLine : public Command { - - Point2 from, to; - Color color; - float width; - bool antialiased; - CommandLine() { type = TYPE_LINE; } - }; - struct CommandPolyLine : public Command { - - bool antialiased; - bool multiline; - Vector<Point2> triangles; - Vector<Color> triangle_colors; - Vector<Point2> lines; - Vector<Color> line_colors; - CommandPolyLine() { - type = TYPE_POLYLINE; - antialiased = false; - multiline = false; - } - }; - struct CommandRect : public Command { Rect2 rect; @@ -782,37 +793,27 @@ public: } }; - struct CommandPrimitive : public Command { + struct CommandPolygon : public Command { - Vector<Point2> points; - Vector<Point2> uvs; - Vector<Color> colors; - float width; + VS::PrimitiveType primitive; + Polygon polygon; Color specular_shininess; TextureBinding texture_binding; - CommandPrimitive() { - type = TYPE_PRIMITIVE; - width = 1; + CommandPolygon() { + type = TYPE_POLYGON; } }; - struct CommandPolygon : public Command { - - Vector<int> indices; - Vector<Point2> points; - Vector<Point2> uvs; - Vector<Color> colors; - Vector<int> bones; - Vector<float> weights; - int count; - bool antialiased; + struct CommandPrimitive : public Command { + uint32_t point_count; + Vector2 points[4]; + Vector2 uvs[4]; + Color colors[4]; Color specular_shininess; TextureBinding texture_binding; - - CommandPolygon() { - type = TYPE_POLYGON; - count = 0; + CommandPrimitive() { + type = TYPE_PRIMITIVE; } }; @@ -842,14 +843,6 @@ public: CommandParticles() { type = TYPE_PARTICLES; } }; - struct CommandCircle : public Command { - - Point2 pos; - float radius; - Color color; - CommandCircle() { type = TYPE_CIRCLE; } - }; - struct CommandTransform : public Command { Transform2D xform; @@ -930,37 +923,6 @@ public: Rect2 r; switch (c->type) { - case Item::Command::TYPE_LINE: { - - const Item::CommandLine *line = static_cast<const Item::CommandLine *>(c); - r.position = line->from; - r.expand_to(line->to); - } break; - case Item::Command::TYPE_POLYLINE: { - - const Item::CommandPolyLine *pline = static_cast<const Item::CommandPolyLine *>(c); - if (pline->triangles.size()) { - for (int j = 0; j < pline->triangles.size(); j++) { - - if (j == 0) { - r.position = pline->triangles[j]; - } else { - r.expand_to(pline->triangles[j]); - } - } - } else { - - for (int j = 0; j < pline->lines.size(); j++) { - - if (j == 0) { - r.position = pline->lines[j]; - } else { - r.expand_to(pline->lines[j]); - } - } - } - - } break; case Item::Command::TYPE_RECT: { const Item::CommandRect *crect = static_cast<const Item::CommandRect *>(c); @@ -972,22 +934,21 @@ public: const Item::CommandNinePatch *style = static_cast<const Item::CommandNinePatch *>(c); r = style->rect; } break; - case Item::Command::TYPE_PRIMITIVE: { - const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c); - r.position = primitive->points[0]; - for (int j = 1; j < primitive->points.size(); j++) { - r.expand_to(primitive->points[j]); - } - } break; case Item::Command::TYPE_POLYGON: { const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(c); - int l = polygon->points.size(); - const Point2 *pp = &polygon->points[0]; - r.position = pp[0]; - for (int j = 1; j < l; j++) { - r.expand_to(pp[j]); + r = polygon->polygon.rect_cache; + } break; + case Item::Command::TYPE_PRIMITIVE: { + + const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c); + for (int j = 0; j < primitive->point_count; j++) { + if (j == 0) { + r.position = primitive->points[0]; + } else { + r.expand_to(primitive->points[j]); + } } } break; case Item::Command::TYPE_MESH: { @@ -1015,12 +976,6 @@ public: } } break; - case Item::Command::TYPE_CIRCLE: { - - const Item::CommandCircle *circle = static_cast<const Item::CommandCircle *>(c); - r.position = Point2(-circle->radius, -circle->radius) + circle->pos; - r.size = Point2(circle->radius * 2.0, circle->radius * 2.0); - } break; case Item::Command::TYPE_TRANSFORM: { const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c); @@ -1083,7 +1038,7 @@ public: } }; - virtual void canvas_render_items(RID p_to_render_target, bool p_clear, const Color &p_clear_color, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform) = 0; + virtual void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform) = 0; virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) = 0; struct LightOccluderInstance { @@ -1142,6 +1097,7 @@ public: //lens distorted parameters for VR should go here }; + virtual void prepare_for_blitting_render_targets() = 0; virtual void blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount) = 0; virtual void end_frame(bool p_swap_buffers) = 0; diff --git a/servers/visual/rasterizer/rasterizer_canvas_rd.cpp b/servers/visual/rasterizer/rasterizer_canvas_rd.cpp index 61f3c1ffa1..eef127eeeb 100644 --- a/servers/visual/rasterizer/rasterizer_canvas_rd.cpp +++ b/servers/visual/rasterizer/rasterizer_canvas_rd.cpp @@ -1,5 +1,5 @@ #include "rasterizer_canvas_rd.h" - +#include "core/math/math_funcs.h" void RasterizerCanvasRD::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) { p_mat4[0] = p_transform.elements[0][0]; @@ -33,6 +33,16 @@ void RasterizerCanvasRD::_update_transform_2d_to_mat2x4(const Transform2D &p_tra p_mat2x4[7] = p_transform.elements[2][1]; } +void RasterizerCanvasRD::_update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3) { + + p_mat2x3[0] = p_transform.elements[0][0]; + p_mat2x3[1] = p_transform.elements[0][1]; + p_mat2x3[2] = p_transform.elements[1][0]; + p_mat2x3[3] = p_transform.elements[1][1]; + p_mat2x3[4] = p_transform.elements[2][0]; + p_mat2x3[5] = p_transform.elements[2][1]; +} + void RasterizerCanvasRD::_update_transform_to_mat4(const Transform &p_transform, float *p_mat4) { p_mat4[0] = p_transform.basis.elements[0][0]; @@ -53,6 +63,70 @@ void RasterizerCanvasRD::_update_transform_to_mat4(const Transform &p_transform, p_mat4[15] = 1; } +RID RasterizerCanvasRD::_create_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat, RID p_multimesh) { + + Vector<RD::Uniform> uniform_set; + + { // COLOR TEXTURE + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 1; + RID texture = storage->texture_get_rd_texture(p_texture); + if (!texture.is_valid()) { + //use default white texture + texture = default_textures.white_texture; + } + u.ids.push_back(texture); + uniform_set.push_back(u); + } + + { // NORMAL TEXTURE + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 2; + RID texture = storage->texture_get_rd_texture(p_normalmap); + if (!texture.is_valid()) { + //use default normal texture + texture = default_textures.normal_texture; + } + u.ids.push_back(texture); + uniform_set.push_back(u); + } + + { // SPECULAR TEXTURE + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 3; + RID texture = storage->texture_get_rd_texture(p_specular); + if (!texture.is_valid()) { + //use default white texture + texture = default_textures.white_texture; + } + u.ids.push_back(texture); + uniform_set.push_back(u); + } + + { // SAMPLER + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_SAMPLER; + u.binding = 4; + RID sampler = default_samplers.samplers[p_filter][p_repeat]; + ERR_FAIL_COND_V(sampler.is_null(), RID()); + u.ids.push_back(sampler); + uniform_set.push_back(u); + } + + { // MULTIMESH TEXTURE BUFFER + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE_BUFFER; + u.binding = 5; + u.ids.push_back(default_textures.default_multimesh_tb); + uniform_set.push_back(u); + } + + return RD::get_singleton()->uniform_set_create(uniform_set, shader.default_version_rd_shader, 0); +} + RasterizerCanvas::TextureBindingID RasterizerCanvasRD::request_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat, RID p_multimesh) { if (p_filter == VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT) { @@ -99,77 +173,7 @@ RasterizerCanvas::TextureBindingID RasterizerCanvasRD::request_texture_binding(R } if (binding->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(binding->uniform_set)) { - //needs to be re-created - - /* from GLSL: - layout(set = 0, binding = 1) uniform texture2D color_texture; - layout(set = 0, binding = 2) uniform texture2D normal_texture; - layout(set = 0, binding = 3) uniform texture2D specular_texture; - layout(set = 0, binding = 4) uniform sampler texture_sampler; - - layout(set = 0, binding = 5) uniform textureBuffer instancing_buffer; - */ - - Vector<RD::Uniform> uniform_set; - - { // COLOR TEXTURE - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 1; - RID texture = storage->texture_get_rd_texture(p_texture); - if (!texture.is_valid()) { - //use default white texture - texture = default_textures.white_texture; - } - u.ids.push_back(texture); - uniform_set.push_back(u); - } - - { // NORMAL TEXTURE - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 2; - RID texture = storage->texture_get_rd_texture(p_normalmap); - if (!texture.is_valid()) { - //use default normal texture - texture = default_textures.normal_texture; - } - u.ids.push_back(texture); - uniform_set.push_back(u); - } - - { // SPECULAR TEXTURE - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 3; - RID texture = storage->texture_get_rd_texture(p_specular); - if (!texture.is_valid()) { - //use default white texture - texture = default_textures.white_texture; - } - u.ids.push_back(texture); - uniform_set.push_back(u); - } - - { // SAMPLER - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; - u.binding = 4; - RID sampler = default_samplers.samplers[p_filter][p_repeat]; - ERR_FAIL_COND_V(sampler.is_null(), 0); - u.ids.push_back(sampler); - uniform_set.push_back(u); - } - - { // MULTIMESH TEXTURE BUFFER - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE_BUFFER; - u.binding = 5; - u.ids.push_back(default_textures.default_multimesh_tb); - uniform_set.push_back(u); - } - - binding->uniform_set = RD::get_singleton()->uniform_set_create(uniform_set, shader.default_version_rd_shader, 0); + binding->uniform_set = _create_texture_binding(p_texture, p_normalmap, p_specular, p_filter, p_repeat, p_multimesh); } return id; @@ -191,7 +195,7 @@ void RasterizerCanvasRD::_dispose_bindings() { while (bindings.to_dispose_list.first()) { TextureBinding *binding = bindings.to_dispose_list.first()->self(); - if (binding->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(binding->uniform_set)) { + if (binding->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(binding->uniform_set)) { RD::get_singleton()->free(binding->uniform_set); } @@ -202,14 +206,302 @@ void RasterizerCanvasRD::_dispose_bindings() { } } -void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RenderTargetFormat p_render_target_format, RD::TextureSamples p_samples, const Color &p_modulate, const Transform2D &p_canvas_transform_inverse) { +RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, const Vector<int> &p_bones, const Vector<float> &p_weights) { + + // Care must be taken to generate array formats + // in ways where they could be reused, so we will + // put single-occuring elements first, and repeated + // elements later. This way the generated formats are + // the same no matter the length of the arrays. + // This dramatically reduces the amount of pipeline objects + // that need to be created for these formats. + + uint32_t vertex_count = p_points.size(); + uint32_t base_offset = 0; + uint32_t stride = 2; //vertices always repeat + if ((uint32_t)p_colors.size() == vertex_count) { + stride += 4; + } else { + base_offset += 4; + } + if ((uint32_t)p_uvs.size() == vertex_count) { + stride += 2; + } else { + base_offset += 2; + } + if ((uint32_t)p_bones.size() == vertex_count * 4) { + stride += 4; + } else { + base_offset += 4; + } + if ((uint32_t)p_weights.size() == vertex_count * 4) { + stride += 4; + } else { + base_offset += 4; + } + + uint32_t buffer_size = base_offset + stride * p_points.size(); + + PoolVector<uint8_t> polygon_buffer; + polygon_buffer.resize(buffer_size * sizeof(float)); + Vector<RD::VertexDescription> descriptions; + descriptions.resize(5); + + { + PoolVector<uint8_t>::Read r = polygon_buffer.read(); + float *fptr = (float *)r.ptr(); + uint32_t *uptr = (uint32_t *)r.ptr(); + uint32_t single_offset = 0; + + { //vertices + RD::VertexDescription vd; + vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; + vd.offset = base_offset * sizeof(float); + vd.location = VS::ARRAY_VERTEX; + vd.stride = stride * sizeof(float); + + descriptions.write[0] = vd; + + const Vector2 *points_ptr = p_points.ptr(); + + for (uint32_t i = 0; i < vertex_count; i++) { + fptr[base_offset + i * stride + 0] = points_ptr[i].x; + fptr[base_offset + i * stride + 1] = points_ptr[i].y; + } + + base_offset += 2; + } + + //colors + if ((uint32_t)p_colors.size() == vertex_count) { + RD::VertexDescription vd; + vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + vd.offset = base_offset * sizeof(float); + vd.location = VS::ARRAY_COLOR; + vd.stride = stride * sizeof(float); + + descriptions.write[1] = vd; + + const Color *color_ptr = p_colors.ptr(); + + for (uint32_t i = 0; i < vertex_count; i++) { + fptr[base_offset + i * stride + 0] = color_ptr[i].r; + fptr[base_offset + i * stride + 1] = color_ptr[i].g; + fptr[base_offset + i * stride + 2] = color_ptr[i].b; + fptr[base_offset + i * stride + 3] = color_ptr[i].a; + } + base_offset += 4; + } else { + RD::VertexDescription vd; + vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + vd.offset = single_offset * sizeof(float); + vd.location = VS::ARRAY_COLOR; + vd.stride = 0; + + descriptions.write[1] = vd; + + Color color = p_colors.size() ? p_colors[0] : Color(1, 1, 1, 1); + fptr[single_offset + 0] = color.r; + fptr[single_offset + 1] = color.g; + fptr[single_offset + 2] = color.b; + fptr[single_offset + 3] = color.a; + + single_offset += 4; + } + + //uvs + if ((uint32_t)p_uvs.size() == vertex_count) { + RD::VertexDescription vd; + vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; + vd.offset = base_offset * sizeof(float); + vd.location = VS::ARRAY_TEX_UV; + vd.stride = stride * sizeof(float); + + descriptions.write[2] = vd; + + const Vector2 *uv_ptr = p_uvs.ptr(); + + for (uint32_t i = 0; i < vertex_count; i++) { + fptr[base_offset + i * stride + 0] = uv_ptr[i].x; + fptr[base_offset + i * stride + 1] = uv_ptr[i].y; + } + base_offset += 2; + } else { + RD::VertexDescription vd; + vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; + vd.offset = single_offset * sizeof(float); + vd.location = VS::ARRAY_TEX_UV; + vd.stride = 0; + + descriptions.write[2] = vd; + + Vector2 uv; + fptr[single_offset + 0] = uv.x; + fptr[single_offset + 1] = uv.y; + + single_offset += 2; + } + + //bones + if ((uint32_t)p_indices.size() == vertex_count * 4) { + RD::VertexDescription vd; + vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT; + vd.offset = base_offset * sizeof(float); + vd.location = VS::ARRAY_BONES; + vd.stride = stride * sizeof(float); + + descriptions.write[3] = vd; + + const int *bone_ptr = p_bones.ptr(); + + for (uint32_t i = 0; i < vertex_count; i++) { + uptr[base_offset + i * stride + 0] = bone_ptr[i * 4 + 0]; + uptr[base_offset + i * stride + 1] = bone_ptr[i * 4 + 1]; + uptr[base_offset + i * stride + 2] = bone_ptr[i * 4 + 2]; + uptr[base_offset + i * stride + 3] = bone_ptr[i * 4 + 3]; + } + + base_offset += 4; + } else { + RD::VertexDescription vd; + vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT; + vd.offset = single_offset * sizeof(float); + vd.location = VS::ARRAY_BONES; + vd.stride = 0; + + descriptions.write[3] = vd; + + uptr[single_offset + 0] = 0; + uptr[single_offset + 1] = 0; + uptr[single_offset + 2] = 0; + uptr[single_offset + 3] = 0; + single_offset += 4; + } + + //bones + if ((uint32_t)p_weights.size() == vertex_count * 4) { + RD::VertexDescription vd; + vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + vd.offset = base_offset * sizeof(float); + vd.location = VS::ARRAY_WEIGHTS; + vd.stride = stride * sizeof(float); + + descriptions.write[4] = vd; + + const float *weight_ptr = p_weights.ptr(); + + for (uint32_t i = 0; i < vertex_count; i++) { + fptr[base_offset + i * stride + 0] = weight_ptr[i * 4 + 0]; + fptr[base_offset + i * stride + 1] = weight_ptr[i * 4 + 1]; + fptr[base_offset + i * stride + 2] = weight_ptr[i * 4 + 2]; + fptr[base_offset + i * stride + 3] = weight_ptr[i * 4 + 3]; + } + + base_offset += 4; + } else { + RD::VertexDescription vd; + vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + vd.offset = single_offset * sizeof(float); + vd.location = VS::ARRAY_WEIGHTS; + vd.stride = 0; + + descriptions.write[4] = vd; + + fptr[single_offset + 0] = 0.0; + fptr[single_offset + 1] = 0.0; + fptr[single_offset + 2] = 0.0; + fptr[single_offset + 3] = 0.0; + single_offset += 4; + } + + //check that everything is as it should be + ERR_FAIL_COND_V(single_offset != (base_offset - stride), 0); + ERR_FAIL_COND_V(((base_offset - stride) + stride * vertex_count) != buffer_size, 0); + } + + RD::VertexFormatID vertex_id = RD::get_singleton()->vertex_format_create(descriptions); + ERR_FAIL_COND_V(vertex_id == RD::INVALID_ID, 0); + + PolygonBuffers pb; + pb.vertex_buffer = RD::get_singleton()->vertex_buffer_create(polygon_buffer.size(), polygon_buffer); + Vector<RID> buffers; + buffers.resize(descriptions.size()); + for (int i = 0; i < descriptions.size(); i++) { + buffers.write[i] = pb.vertex_buffer; + } + pb.vertex_array = RD::get_singleton()->vertex_array_create(p_points.size(), vertex_id, buffers); + + if (p_indices.size()) { + //create indices, as indices were requested + PoolVector<uint8_t> index_buffer; + index_buffer.resize(p_indices.size() * sizeof(int32_t)); + { + PoolVector<uint8_t>::Write w = index_buffer.write(); + copymem(w.ptr(), p_indices.ptr(), sizeof(int32_t) * p_indices.size()); + } + pb.index_buffer = RD::get_singleton()->index_buffer_create(p_indices.size(), RD::INDEX_BUFFER_FORMAT_UINT32, index_buffer); + pb.indices = RD::get_singleton()->index_array_create(pb.index_buffer, 0, p_indices.size()); + } + + pb.vertex_format_id = vertex_id; + + PolygonID id = polygon_buffers.last_id++; + + polygon_buffers.polygons[id] = pb; + + return id; +} + +void RasterizerCanvasRD::free_polygon(PolygonID p_polygon) { + + PolygonBuffers *pb_ptr = polygon_buffers.polygons.getptr(p_polygon); + ERR_FAIL_COND(!pb_ptr); + + PolygonBuffers &pb = *pb_ptr; + + if (pb.indices.is_valid()) { + RD::get_singleton()->free(pb.indices); + } + if (pb.index_buffer.is_valid()) { + RD::get_singleton()->free(pb.index_buffer); + } + + RD::get_singleton()->free(pb.vertex_array); + RD::get_singleton()->free(pb.vertex_buffer); + + polygon_buffers.polygons.erase(p_polygon); +} + +Size2i RasterizerCanvasRD::_bind_texture_binding(TextureBindingID p_binding, RD::DrawListID p_draw_list) { + + TextureBinding **texture_binding_ptr = bindings.texture_bindings.getptr(p_binding); + ERR_FAIL_COND_V(!texture_binding_ptr, Size2i()); + TextureBinding *texture_binding = *texture_binding_ptr; + + if (!RD::get_singleton()->uniform_set_is_valid(texture_binding->uniform_set)) { + //texture may have changed (erased or replaced, see if we can fix) + texture_binding->uniform_set = _create_texture_binding(texture_binding->key.texture, texture_binding->key.normalmap, texture_binding->key.specular, texture_binding->key.texture_filter, texture_binding->key.texture_repeat, texture_binding->key.multimesh); + ERR_FAIL_COND_V(!texture_binding->uniform_set.is_valid(), Size2i(1, 1)); + } + + RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, texture_binding->uniform_set, 0); + if (texture_binding->key.texture.is_valid()) { + return storage->texture_2d_get_size(texture_binding->key.texture); + } else { + return Size2i(1, 1); + } +} + +//////////////////// +void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RenderTargetFormat p_render_target_format, RD::TextureSamples p_samples, const Color &p_modulate, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip) { int cc = p_item->commands.size(); const Item::Command *const *commands = p_item->commands.ptr(); //create an empty push constant PushConstant push_constant; - _update_transform_2d_to_mat2x4(p_canvas_transform_inverse * p_item->final_transform, push_constant.world); + Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform; + _update_transform_2d_to_mat2x3(base_transform, push_constant.world); for (int i = 0; i < 4; i++) { push_constant.modulation[i] = 0; push_constant.ninepatch_margins[i] = 0; @@ -226,120 +518,14 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ PipelineVariants *pipeline_variants = &shader.pipeline_variants; + bool reclip = false; + for (int i = 0; i < cc; i++) { const Item::Command *c = commands[i]; push_constant.flags = 0; //reset on each command for sanity switch (c->type) { -#if 0 - case Item::Command::TYPE_LINE: { - - Item::CommandLine *line = static_cast<Item::CommandLine *>(c); - _set_texture_rect_mode(false); - - _bind_canvas_texture(RID(), RID()); - - glVertexAttrib4f(VS::ARRAY_COLOR, line->color.r, line->color.g, line->color.b, line->color.a); - - if (line->width <= 1) { - Vector2 verts[2] = { - Vector2(line->from.x, line->from.y), - Vector2(line->to.x, line->to.y) - }; - -#ifdef GLES_OVER_GL - if (line->antialiased) - glEnable(GL_LINE_SMOOTH); -#endif - //glLineWidth(line->width); - _draw_gui_primitive(2, verts, NULL, NULL); - -#ifdef GLES_OVER_GL - if (line->antialiased) - glDisable(GL_LINE_SMOOTH); -#endif - } else { - //thicker line - - Vector2 t = (line->from - line->to).normalized().tangent() * line->width * 0.5; - - Vector2 verts[4] = { - line->from - t, - line->from + t, - line->to + t, - line->to - t, - }; - - //glLineWidth(line->width); - _draw_gui_primitive(4, verts, NULL, NULL); -#ifdef GLES_OVER_GL - if (line->antialiased) { - glEnable(GL_LINE_SMOOTH); - for (int j = 0; j < 4; j++) { - Vector2 vertsl[2] = { - verts[j], - verts[(j + 1) % 4], - }; - _draw_gui_primitive(2, vertsl, NULL, NULL); - } - glDisable(GL_LINE_SMOOTH); - } -#endif - } - - } break; - case Item::Command::TYPE_POLYLINE: { - - Item::CommandPolyLine *pline = static_cast<Item::CommandPolyLine *>(c); - _set_texture_rect_mode(false); - - _bind_canvas_texture(RID(), RID()); - - 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); -#ifdef GLES_OVER_GL - glEnable(GL_LINE_SMOOTH); - if (pline->multiline) { - //needs to be different - } else { - _draw_generic(GL_LINE_LOOP, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1); - } - glDisable(GL_LINE_SMOOTH); -#endif - } else { - -#ifdef GLES_OVER_GL - if (pline->antialiased) - glEnable(GL_LINE_SMOOTH); -#endif - - 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; - } - - } else { - - _draw_generic(GL_LINE_STRIP, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1); - } - -#ifdef GLES_OVER_GL - if (pline->antialiased) - glDisable(GL_LINE_SMOOTH); -#endif - } - - } break; -#endif case Item::Command::TYPE_RECT: { const Item::CommandRect *rect = static_cast<const Item::CommandRect *>(c); @@ -354,18 +540,9 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ Size2 texpixel_size; { - TextureBinding **texture_binding_ptr = bindings.texture_bindings.getptr(rect->texture_binding.binding_id); - ERR_CONTINUE(!texture_binding_ptr); - TextureBinding *texture_binding = *texture_binding_ptr; - - RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, texture_binding->uniform_set, 0); - if (texture_binding->key.texture.is_valid()) { - Size2i tex_size = storage->texture_2d_get_size(texture_binding->key.texture); - if (tex_size.x != 0 && tex_size.y != 0) { - texpixel_size.x = 1.0 / tex_size.x; - texpixel_size.y = 1.0 / tex_size.y; - } - } + texpixel_size = _bind_texture_binding(rect->texture_binding.binding_id, p_draw_list); + texpixel_size.x = 1.0 / texpixel_size.x; + texpixel_size.y = 1.0 / texpixel_size.y; } Rect2 src_rect; @@ -457,17 +634,9 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ Size2 texpixel_size; { - TextureBinding **texture_binding_ptr = bindings.texture_bindings.getptr(np->texture_binding.binding_id); - ERR_CONTINUE(!texture_binding_ptr); - TextureBinding *texture_binding = *texture_binding_ptr; - RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, texture_binding->uniform_set, 0); - if (texture_binding->key.texture.is_valid()) { - Size2i tex_size = storage->texture_2d_get_size(texture_binding->key.texture); - if (tex_size.x != 0 && tex_size.y != 0) { - texpixel_size.x = 1.0 / tex_size.x; - texpixel_size.y = 1.0 / tex_size.y; - } - } + texpixel_size = _bind_texture_binding(np->texture_binding.binding_id, p_draw_list); + texpixel_size.x = 1.0 / texpixel_size.x; + texpixel_size.y = 1.0 / texpixel_size.y; } Rect2 src_rect; @@ -491,7 +660,7 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ push_constant.modulation[0] = np->color.r * p_modulate.r; push_constant.modulation[1] = np->color.g * p_modulate.g; push_constant.modulation[2] = np->color.b * p_modulate.b; - push_constant.modulation[3] = np->color.a; + push_constant.modulation[3] = np->color.a * p_modulate.a; push_constant.src_rect[0] = src_rect.position.x; push_constant.src_rect[1] = src_rect.position.y; @@ -523,54 +692,92 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ RD::get_singleton()->draw_list_draw(p_draw_list, true); } break; -#if 0 -case Item::Command::TYPE_PRIMITIVE : { + case Item::Command::TYPE_POLYGON: { - Item::CommandPrimitive *primitive = static_cast<Item::CommandPrimitive *>(c); - _set_texture_rect_mode(false); + const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(c); + + PolygonBuffers *pb = polygon_buffers.polygons.getptr(polygon->polygon.polygon_id); + ERR_CONTINUE(!pb); + //bind pipeline + { + static const PipelineVariant variant[VS::PRIMITIVE_MAX] = { PIPELINE_VARIANT_ATTRIBUTE_POINTS, PIPELINE_VARIANT_ATTRIBUTE_LINES, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES }; + ERR_CONTINUE(polygon->primitive < 0 || polygon->primitive >= VS::PRIMITIVE_MAX); + RID pipeline = pipeline_variants->variants[p_render_target_format][variant[polygon->primitive]].get_render_pipeline(pb->vertex_format_id, p_samples); + RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline); + } - ERR_CONTINUE(primitive->points.size() < 1); + if (polygon->primitive == VS::PRIMITIVE_LINES) { + //not supported in most hardware, so pointless + //RD::get_singleton()->draw_list_set_line_width(p_draw_list, polygon->line_width); + } - RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(primitive->texture, primitive->normal_map); + //bind textures - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); + Size2 texpixel_size; + { + texpixel_size = _bind_texture_binding(polygon->texture_binding.binding_id, p_draw_list); + texpixel_size.x = 1.0 / texpixel_size.x; + texpixel_size.y = 1.0 / texpixel_size.y; } - if (primitive->colors.size() == 1 && primitive->points.size() > 1) { - Color col = primitive->colors[0]; - glVertexAttrib4f(VS::ARRAY_COLOR, col.r, col.g, col.b, col.a); + push_constant.modulation[0] = p_modulate.r; + push_constant.modulation[1] = p_modulate.g; + push_constant.modulation[2] = p_modulate.b; + push_constant.modulation[3] = p_modulate.a; - } else if (primitive->colors.empty()) { - glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); + for (int j = 0; j < 4; j++) { + push_constant.src_rect[j] = 0; + push_constant.dst_rect[j] = 0; + push_constant.ninepatch_margins[j] = 0; } - _draw_gui_primitive(primitive->points.size(), primitive->points.ptr(), primitive->colors.ptr(), primitive->uvs.ptr()); + push_constant.color_texture_pixel_size[0] = texpixel_size.x; + push_constant.color_texture_pixel_size[1] = texpixel_size.y; + + RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant)); + RD::get_singleton()->draw_list_bind_vertex_array(p_draw_list, pb->vertex_array); + if (pb->indices.is_valid()) { + RD::get_singleton()->draw_list_bind_index_array(p_draw_list, pb->indices); + } + RD::get_singleton()->draw_list_draw(p_draw_list, pb->indices.is_valid()); } break; - case Item::Command::TYPE_POLYGON: { + case Item::Command::TYPE_PRIMITIVE: { - Item::CommandPolygon *polygon = static_cast<Item::CommandPolygon *>(c); - _set_texture_rect_mode(false); + const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c); - RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(polygon->texture, polygon->normal_map); + //bind pipeline + { + static const PipelineVariant variant[4] = { PIPELINE_VARIANT_PRIMITIVE_POINTS, PIPELINE_VARIANT_PRIMITIVE_LINES, PIPELINE_VARIANT_PRIMITIVE_TRIANGLES, PIPELINE_VARIANT_PRIMITIVE_TRIANGLES }; + ERR_CONTINUE(primitive->point_count == 0 || primitive->point_count > 4); + RID pipeline = pipeline_variants->variants[p_render_target_format][variant[primitive->point_count - 1]].get_render_pipeline(RD::INVALID_ID, p_samples); + RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline); + } - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); + //bind textures + + { + _bind_texture_binding(primitive->texture_binding.binding_id, p_draw_list); } - _draw_polygon(polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1, polygon->bones.ptr(), polygon->weights.ptr()); -#ifdef GLES_OVER_GL - if (polygon->antialiased) { - glEnable(GL_LINE_SMOOTH); - _draw_generic(GL_LINE_LOOP, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); - glDisable(GL_LINE_SMOOTH); + for (uint32_t j = 0; j < primitive->point_count; j++) { + push_constant.points[j * 2 + 0] = primitive->points[j].x; + push_constant.points[j * 2 + 1] = primitive->points[j].y; + push_constant.uvs[j * 2 + 0] = primitive->uvs[j].x; + push_constant.uvs[j * 2 + 1] = primitive->uvs[j].y; + Color col = primitive->colors[j] * p_modulate; + push_constant.colors[j * 2 + 0] = (uint32_t(Math::make_half_float(col.g)) << 16) | Math::make_half_float(col.r); + push_constant.colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b); } -#endif + RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant)); + + RD::get_singleton()->draw_list_bind_index_array(p_draw_list, primitive_arrays.index_array[primitive->point_count - 1]); + + RD::get_singleton()->draw_list_draw(p_draw_list, true); } break; + +#if 0 case Item::Command::TYPE_MESH: { Item::CommandMesh *mesh = static_cast<Item::CommandMesh *>(c); @@ -850,70 +1057,43 @@ case Item::Command::TYPE_PRIMITIVE : { _set_texture_rect_mode(false); } break; - case Item::Command::TYPE_CIRCLE: { - - _set_texture_rect_mode(false); - - Item::CommandCircle *circle = static_cast<Item::CommandCircle *>(c); - static const int numpoints = 32; - Vector2 points[numpoints + 1]; - points[numpoints] = circle->pos; - int indices[numpoints * 3]; - - for (int j = 0; j < numpoints; j++) { - - points[j] = circle->pos + Vector2(Math::sin(j * Math_PI * 2.0 / numpoints), Math::cos(j * Math_PI * 2.0 / numpoints)) * circle->radius; - indices[j * 3 + 0] = j; - indices[j * 3 + 1] = (j + 1) % numpoints; - indices[j * 3 + 2] = numpoints; - } - - _bind_canvas_texture(RID(), RID()); - _draw_polygon(indices, numpoints * 3, numpoints + 1, points, NULL, &circle->color, true, NULL, NULL); - - //_draw_polygon(numpoints*3,indices,points,NULL,&circle->color,RID(),true); - //canvas_draw_circle(circle->indices.size(),circle->indices.ptr(),circle->points.ptr(),circle->uvs.ptr(),circle->colors.ptr(),circle->texture,circle->colors.size()==1); - } break; +#endif case Item::Command::TYPE_TRANSFORM: { - Item::CommandTransform *transform = static_cast<Item::CommandTransform *>(c); - state.extra_matrix = transform->xform; - state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX, state.extra_matrix); + const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c); + base_transform = base_transform * transform->xform; + _update_transform_2d_to_mat2x3(base_transform, push_constant.world); } break; case Item::Command::TYPE_CLIP_IGNORE: { - Item::CommandClipIgnore *ci = static_cast<Item::CommandClipIgnore *>(c); + const Item::CommandClipIgnore *ci = static_cast<const Item::CommandClipIgnore *>(c); if (current_clip) { if (ci->ignore != reclip) { - if (ci->ignore) { - glDisable(GL_SCISSOR_TEST); + if (ci->ignore) { + RD::get_singleton()->draw_list_disable_scissor(p_draw_list); reclip = true; } else { - glEnable(GL_SCISSOR_TEST); - //glScissor(viewport.x+current_clip->final_clip_rect.pos.x,viewport.y+ (viewport.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.height)), - //current_clip->final_clip_rect.size.width,current_clip->final_clip_rect.size.height); - int y = storage->frame.current_rt->height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.y); - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) - y = current_clip->final_clip_rect.position.y; - - glScissor(current_clip->final_clip_rect.position.x, y, current_clip->final_clip_rect.size.x, current_clip->final_clip_rect.size.y); - + RD::get_singleton()->draw_list_enable_scissor(p_draw_list, current_clip->final_clip_rect); reclip = false; } } } } break; -#endif } } + + if (current_clip && reclip) { + //will make it re-enable clipping if needed afterwards + current_clip = NULL; + } } -void RasterizerCanvasRD::_render_items(RID p_to_render_target, bool p_clear, const Color &p_clear_color, int p_item_count, const Color &p_modulate, const Transform2D &p_transform) { +void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, const Color &p_modulate, const Transform2D &p_transform) { Item *current_clip = NULL; @@ -923,12 +1103,15 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, bool p_clear, con RID framebuffer = storage->render_target_get_rd_framebuffer(p_to_render_target); Vector<Color> clear_colors; - if (p_clear) { - clear_colors.push_back(p_clear_color); + bool clear = false; + if (storage->render_target_is_clear_requested(p_to_render_target)) { + clear = true; + clear_colors.push_back(storage->render_target_get_clear_request_color(p_to_render_target)); + storage->render_target_disable_clear_request(p_to_render_target); } #warning TODO obtain from framebuffer format eventually when this is implemented RD::TextureSamples texture_samples = RD::TEXTURE_SAMPLES_1; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, p_clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, clear_colors); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, clear_colors); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, state.canvas_state_uniform_set, 3); @@ -953,10 +1136,10 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, bool p_clear, con if (false) { //not skeleton - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, shader.default_material_uniform_set, 1); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, shader.default_skeleton_uniform_set, 1); } - _render_item(draw_list, ci, render_target_format, texture_samples, p_modulate, canvas_transform_inverse); + _render_item(draw_list, ci, render_target_format, texture_samples, p_modulate, canvas_transform_inverse, current_clip); } RD::get_singleton()->draw_list_end(); @@ -979,7 +1162,7 @@ void RasterizerCanvasRD::_update_canvas_state_uniform_set() { state.canvas_state_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader, 3); // uses index 3 } -void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, bool p_clear, const Color &p_clear_color, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform) { +void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform) { int item_count = 0; @@ -1008,10 +1191,9 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, bool p_clea bool backbuffer_copy = ci->copy_back_buffer; // || shader uses SCREEN_TEXTURE if (!ci->next || backbuffer_copy || item_count == MAX_RENDER_ITEMS - 1) { - _render_items(p_to_render_target, p_clear, p_clear_color, item_count, p_modulate, p_canvas_transform); + _render_items(p_to_render_target, item_count, p_modulate, p_canvas_transform); //then reset item_count = 0; - p_clear = false; } if (ci->copy_back_buffer) { @@ -1170,8 +1352,10 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { Vector<String> variants; variants.push_back(""); //none by default is first variant variants.push_back("#define USE_NINEPATCH\n"); //ninepatch is the second variant - variants.push_back("#define USE_VERTEX_ARRAYS\n"); //vertex arrays is the last variant - variants.push_back("#define USE_POINT_SIZE\n"); //for point drawing + variants.push_back("#define USE_PRIMITIVE\n"); //primitve is the third + variants.push_back("#define USE_PRIMITIVE\n#define USE_POINT_SIZE\n"); //points need point size + variants.push_back("#define USE_ATTRIBUTES\n"); // attributes for vertex arrays + variants.push_back("#define USE_ATTRIBUTES\n#define USE_POINT_SIZE\n"); //attributes with point size shader.canvas_shader.initialize(variants); shader.default_version = shader.canvas_shader.version_create(); @@ -1195,11 +1379,29 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { for (int i = 0; i < RENDER_TARGET_FORMAT_MAX; i++) { RD::FramebufferFormatID fb_format = shader.framebuffer_formats[i]; for (int j = 0; j < PIPELINE_VARIANT_MAX; j++) { - RD::RenderPrimitive primitive[PIPELINE_VARIANT_MAX] = { RD::RENDER_PRIMITIVE_TRIANGLES, RD::RENDER_PRIMITIVE_TRIANGLES, RD::RENDER_PRIMITIVE_TRIANGLES, RD::RENDER_PRIMITIVE_LINES, RD::RENDER_PRIMITIVE_POINTS }; - ShaderVariant shader_variants[PIPELINE_VARIANT_MAX] = { SHADER_VARIANT_QUAD, SHADER_VARIANT_NINEPATCH, SHADER_VARIANT_VERTICES, SHADER_VARIANT_VERTICES, SHADER_VARIANT_POINTS }; + RD::RenderPrimitive primitive[PIPELINE_VARIANT_MAX] = { + RD::RENDER_PRIMITIVE_TRIANGLES, + RD::RENDER_PRIMITIVE_TRIANGLES, + RD::RENDER_PRIMITIVE_TRIANGLES, + RD::RENDER_PRIMITIVE_LINES, + RD::RENDER_PRIMITIVE_POINTS, + RD::RENDER_PRIMITIVE_TRIANGLES, + RD::RENDER_PRIMITIVE_LINES, + RD::RENDER_PRIMITIVE_POINTS, + }; + ShaderVariant shader_variants[PIPELINE_VARIANT_MAX] = { + SHADER_VARIANT_QUAD, + SHADER_VARIANT_NINEPATCH, + SHADER_VARIANT_PRIMITIVE, + SHADER_VARIANT_PRIMITIVE, + SHADER_VARIANT_PRIMITIVE_POINTS, + SHADER_VARIANT_ATTRIBUTES, + SHADER_VARIANT_ATTRIBUTES, + SHADER_VARIANT_ATTRIBUTES_POINTS + }; RID shader_variant = shader.canvas_shader.version_get_shader(shader.default_version, shader_variants[j]); - shader.pipeline_variants.variants[i][j].setup(shader_variant, fb_format, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_blend(), j == PIPELINE_VARIANT_LINES ? RD::DYNAMIC_STATE_LINE_WIDTH : 0); + shader.pipeline_variants.variants[i][j].setup(shader_variant, fb_format, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_blend(), 0); } } @@ -1216,6 +1418,11 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { } } + { + //polygon buffers + polygon_buffers.last_id = 1; + } + { // default index buffer PoolVector<uint8_t> pv; @@ -1230,17 +1437,24 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { p32[4] = 2; p32[5] = 3; } - RID index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv); - shader.quad_index_array = RD::get_singleton()->index_array_create(index_buffer, 0, 6); + shader.quad_index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv); + shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 6); + } + + { //primitive + primitive_arrays.index_array[0] = shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 1); + primitive_arrays.index_array[1] = shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 2); + primitive_arrays.index_array[2] = shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 3); + primitive_arrays.index_array[3] = shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 6); } { //default skeleton buffer - shader.default_material_skeleton_uniform = RD::get_singleton()->uniform_buffer_create(sizeof(SkeletonUniform)); + shader.default_skeleton_uniform = RD::get_singleton()->uniform_buffer_create(sizeof(SkeletonUniform)); SkeletonUniform su; _update_transform_2d_to_mat4(Transform2D(), su.skeleton_inverse); _update_transform_2d_to_mat4(Transform2D(), su.skeleton_transform); - RD::get_singleton()->buffer_update(shader.default_material_skeleton_uniform, 0, sizeof(SkeletonUniform), &su); + RD::get_singleton()->buffer_update(shader.default_skeleton_uniform, 0, sizeof(SkeletonUniform), &su); } { //default material uniform set @@ -1248,7 +1462,7 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { RD::Uniform u; u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 2; - u.ids.push_back(shader.default_material_skeleton_uniform); + u.ids.push_back(shader.default_skeleton_uniform); default_material_uniforms.push_back(u); u.ids.clear(); @@ -1257,8 +1471,68 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { u.ids.push_back(default_textures.default_multimesh_tb); default_material_uniforms.push_back(u); - shader.default_material_uniform_set = RD::get_singleton()->uniform_set_create(default_material_uniforms, shader.default_version_rd_shader, 1); + shader.default_skeleton_uniform_set = RD::get_singleton()->uniform_set_create(default_material_uniforms, shader.canvas_shader.version_get_shader(shader.default_version, SHADER_VARIANT_ATTRIBUTES), 2); } ERR_FAIL_COND(sizeof(PushConstant) != 128); } + +RasterizerCanvasRD::~RasterizerCanvasRD() { + + //canvas state + + if (state.canvas_state_buffer.is_valid()) { + RD::get_singleton()->free(state.canvas_state_buffer); + } + + if (state.canvas_state_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(state.canvas_state_uniform_set)) { + RD::get_singleton()->free(state.canvas_state_uniform_set); + } + + //bindings + { + + free_texture_binding(bindings.default_empty); + + //dispose pending + _dispose_bindings(); + //anything remains? + if (bindings.texture_bindings.size()) { + ERR_PRINT("Some texture bindings were not properly freed (leaked canvasitems?"); + const TextureBindingID *key = NULL; + while ((key = bindings.texture_bindings.next(key))) { + TextureBinding *tb = bindings.texture_bindings[*key]; + tb->reference_count = 1; + free_texture_binding(*key); + } + //dispose pending + _dispose_bindings(); + } + } + + //shaders + + RD::get_singleton()->free(shader.default_skeleton_uniform_set); + RD::get_singleton()->free(shader.default_skeleton_uniform); + shader.canvas_shader.version_free(shader.default_version); + + //buffers + RD::get_singleton()->free(shader.quad_index_array); + RD::get_singleton()->free(shader.quad_index_buffer); + + //pipelines don't need freeing, they are all gone after shaders are gone + + //samplers + for (int i = 1; i < VS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) { + for (int j = 1; j < VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) { + RD::get_singleton()->free(default_samplers.samplers[i][j]); + } + } + + //textures + RD::get_singleton()->free(default_textures.white_texture); + RD::get_singleton()->free(default_textures.black_texture); + RD::get_singleton()->free(default_textures.normal_texture); + RD::get_singleton()->free(default_textures.aniso_texture); + RD::get_singleton()->free(default_textures.default_multimesh_tb); +} diff --git a/servers/visual/rasterizer/rasterizer_canvas_rd.h b/servers/visual/rasterizer/rasterizer_canvas_rd.h index dbe6e7b394..911a3b6225 100644 --- a/servers/visual/rasterizer/rasterizer_canvas_rd.h +++ b/servers/visual/rasterizer/rasterizer_canvas_rd.h @@ -14,8 +14,10 @@ class RasterizerCanvasRD : public RasterizerCanvas { enum ShaderVariant { SHADER_VARIANT_QUAD, SHADER_VARIANT_NINEPATCH, - SHADER_VARIANT_VERTICES, - SHADER_VARIANT_POINTS, + SHADER_VARIANT_PRIMITIVE, + SHADER_VARIANT_PRIMITIVE_POINTS, + SHADER_VARIANT_ATTRIBUTES, + SHADER_VARIANT_ATTRIBUTES_POINTS, SHADER_VARIANT_MAX }; @@ -51,9 +53,12 @@ class RasterizerCanvasRD : public RasterizerCanvas { enum PipelineVariant { PIPELINE_VARIANT_QUAD, PIPELINE_VARIANT_NINEPATCH, - PIPELINE_VARIANT_TRIANGLES, - PIPELINE_VARIANT_LINES, - PIPELINE_VARIANT_POINTS, + PIPELINE_VARIANT_PRIMITIVE_TRIANGLES, + PIPELINE_VARIANT_PRIMITIVE_LINES, + PIPELINE_VARIANT_PRIMITIVE_POINTS, + PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES, + PIPELINE_VARIANT_ATTRIBUTE_LINES, + PIPELINE_VARIANT_ATTRIBUTE_POINTS, PIPELINE_VARIANT_MAX }; struct PipelineVariants { @@ -65,12 +70,13 @@ class RasterizerCanvasRD : public RasterizerCanvas { RD::FramebufferFormatID framebuffer_formats[RENDER_TARGET_FORMAT_MAX]; RID default_version; RID default_version_rd_shader; + RID quad_index_buffer; RID quad_index_array; PipelineVariants pipeline_variants; // default_skeleton uniform set - RID default_material_skeleton_uniform; - RID default_material_uniform_set; + RID default_skeleton_uniform; + RID default_skeleton_uniform_set; } shader; @@ -126,6 +132,7 @@ class RasterizerCanvasRD : public RasterizerCanvas { TextureBindingID default_empty; } bindings; + RID _create_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat, RID p_multimesh); void _dispose_bindings(); struct { RID white_texture; @@ -143,6 +150,31 @@ class RasterizerCanvasRD : public RasterizerCanvas { VS::CanvasItemTextureRepeat default_repeat; } default_samplers; + /******************/ + /**** POLYGONS ****/ + /******************/ + + struct PolygonBuffers { + RD::VertexFormatID vertex_format_id; + RID vertex_buffer; + RID vertex_array; + RID index_buffer; + RID indices; + }; + + struct { + HashMap<PolygonID, PolygonBuffers> polygons; + PolygonID last_id; + } polygon_buffers; + + /********************/ + /**** PRIMITIVES ****/ + /********************/ + + struct { + RID index_array[4]; + } primitive_arrays; + /*******************/ /**** MATERIALS ****/ /*******************/ @@ -171,15 +203,26 @@ class RasterizerCanvasRD : public RasterizerCanvas { } state; struct PushConstant { - float world[8]; - float modulation[4]; - float ninepatch_margins[4]; - float dst_rect[4]; - float src_rect[4]; + float world[6]; uint32_t flags; uint32_t specular_shininess; - float color_texture_pixel_size[2]; - uint32_t pad[4]; + union { + //rect + struct { + float modulation[4]; + float ninepatch_margins[4]; + float dst_rect[4]; + float src_rect[4]; + float color_texture_pixel_size[2]; + uint32_t pad[6]; + }; + //primitive + struct { + float points[8]; // vec2 points[4] + uint32_t colors[8]; // colors encoded as half + float uvs[8]; // vec2 points[4] + }; + }; }; struct SkeletonUniform { @@ -193,10 +236,12 @@ class RasterizerCanvasRD : public RasterizerCanvas { Item *items[MAX_RENDER_ITEMS]; - void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderTargetFormat p_render_target_format, RenderingDevice::TextureSamples p_samples, const Color &p_modulate, const Transform2D &p_canvas_transform_inverse); - void _render_items(RID p_to_render_target, bool p_clear, const Color &p_clear_color, int p_item_count, const Color &p_modulate, const Transform2D &p_transform); + Size2i _bind_texture_binding(TextureBindingID p_binding, RenderingDevice::DrawListID p_draw_list); + void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderTargetFormat p_render_target_format, RenderingDevice::TextureSamples p_samples, const Color &p_modulate, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip); + void _render_items(RID p_to_render_target, int p_item_count, const Color &p_modulate, const Transform2D &p_transform); void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4); + void _update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3); void _update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4); void _update_transform_to_mat4(const Transform &p_transform, float *p_mat4); @@ -207,11 +252,14 @@ public: TextureBindingID request_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VS::CanvasItemTextureFilter p_filter, VS::CanvasItemTextureRepeat p_repeat, RID p_multimesh); void free_texture_binding(TextureBindingID p_binding); + PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()); + void free_polygon(PolygonID p_polygon); + RID light_internal_create() { return RID(); } void light_internal_update(RID p_rid, Light *p_light) {} void light_internal_free(RID p_rid) {} - void canvas_render_items(RID p_to_render_target, bool p_clear, const Color &p_clear_color, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform); + void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform); void canvas_debug_viewport_shadows(Light *p_lights_with_shadow){}; @@ -223,7 +271,7 @@ public: void update(); RasterizerCanvasRD(RasterizerStorageRD *p_storage); - ~RasterizerCanvasRD() {} + ~RasterizerCanvasRD(); }; #endif // RASTERIZER_CANVAS_RD_H diff --git a/servers/visual/rasterizer/rasterizer_rd.cpp b/servers/visual/rasterizer/rasterizer_rd.cpp index 83c722b5d2..62449fafb4 100644 --- a/servers/visual/rasterizer/rasterizer_rd.cpp +++ b/servers/visual/rasterizer/rasterizer_rd.cpp @@ -1,5 +1,9 @@ #include "rasterizer_rd.h" +void RasterizerRD::prepare_for_blitting_render_targets() { + RD::get_singleton()->prepare_screen_for_drawing(); +} + void RasterizerRD::blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount) { RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin_for_screen(p_screen); diff --git a/servers/visual/rasterizer/rasterizer_rd.h b/servers/visual/rasterizer/rasterizer_rd.h index fb5945fa4d..b895f48065 100644 --- a/servers/visual/rasterizer/rasterizer_rd.h +++ b/servers/visual/rasterizer/rasterizer_rd.h @@ -29,6 +29,7 @@ public: void initialize(); void begin_frame(double frame_step); + void prepare_for_blitting_render_targets(); void blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount); void end_frame(bool p_swap_buffers); diff --git a/servers/visual/rasterizer/rasterizer_storage_rd.cpp b/servers/visual/rasterizer/rasterizer_storage_rd.cpp index e120b86ba3..d38d0c62c8 100644 --- a/servers/visual/rasterizer/rasterizer_storage_rd.cpp +++ b/servers/visual/rasterizer/rasterizer_storage_rd.cpp @@ -486,6 +486,7 @@ RID RasterizerStorageRD::texture_2d_create(const Ref<Image> &p_image) { texture.layers = 1; texture.mipmaps = p_image->get_mipmap_count() + 1; texture.depth = 1; + texture.format = p_image->get_format(); texture.rd_type = RD::TEXTURE_TYPE_2D; texture.rd_format = ret_format.format; @@ -532,6 +533,8 @@ RID RasterizerStorageRD::texture_2d_create(const Ref<Image> &p_image) { texture.width_2d = texture.width; texture.height_2d = texture.height; texture.is_render_target = false; + texture.rd_view = rd_view; + texture.is_proxy = false; #warning TODO this is temporary to get things to work texture.image_cache_2d = p_image; @@ -549,6 +552,28 @@ RID RasterizerStorageRD::texture_3d_create(const Vector<Ref<Image> > &p_slices) return RID(); } +RID RasterizerStorageRD::texture_proxy_create(RID p_base) { + Texture *tex = texture_owner.getornull(p_base); + ERR_FAIL_COND_V(!tex, RID()); + Texture proxy_tex = *tex; + + proxy_tex.rd_view.format_override = tex->rd_format; + proxy_tex.rd_texture = RD::get_singleton()->texture_create_shared(proxy_tex.rd_view, tex->rd_texture); + if (proxy_tex.rd_texture_srgb.is_valid()) { + proxy_tex.rd_view.format_override = tex->rd_format_srgb; + proxy_tex.rd_texture_srgb = RD::get_singleton()->texture_create_shared(proxy_tex.rd_view, tex->rd_texture); + } + proxy_tex.proxy_to = p_base; + proxy_tex.is_render_target = false; + proxy_tex.is_proxy = true; + proxy_tex.proxies.clear(); + + RID rid = texture_owner.make_rid(proxy_tex); + + tex->proxies.push_back(rid); + return rid; +} + void RasterizerStorageRD::_texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_immediate) { ERR_FAIL_COND(p_image.is_null() || p_image->empty()); @@ -581,6 +606,46 @@ void RasterizerStorageRD::texture_2d_update(RID p_texture, const Ref<Image> &p_i void RasterizerStorageRD::texture_3d_update(RID p_texture, const Ref<Image> &p_image, int p_depth, int p_mipmap) { } +void RasterizerStorageRD::texture_proxy_update(RID p_texture, RID p_proxy_to) { + + Texture *tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND(!tex); + ERR_FAIL_COND(!tex->is_proxy); + Texture *proxy_to = texture_owner.getornull(p_proxy_to); + ERR_FAIL_COND(!proxy_to); + ERR_FAIL_COND(proxy_to->is_proxy); + + if (tex->proxy_to.is_valid()) { + //unlink proxy + if (RD::get_singleton()->texture_is_valid(tex->rd_texture)) { + RD::get_singleton()->free(tex->rd_texture); + tex->rd_texture = RID(); + } + if (RD::get_singleton()->texture_is_valid(tex->rd_texture_srgb)) { + RD::get_singleton()->free(tex->rd_texture_srgb); + tex->rd_texture_srgb = RID(); + } + Texture *prev_tex = texture_owner.getornull(tex->proxy_to); + ERR_FAIL_COND(!prev_tex); + prev_tex->proxies.erase(p_texture); + } + + *tex = *proxy_to; + + tex->proxy_to = p_proxy_to; + tex->is_render_target = false; + tex->is_proxy = true; + tex->proxies.clear(); + proxy_to->proxies.push_back(p_texture); + + tex->rd_view.format_override = tex->rd_format; + tex->rd_texture = RD::get_singleton()->texture_create_shared(tex->rd_view, proxy_to->rd_texture); + if (tex->rd_texture_srgb.is_valid()) { + tex->rd_view.format_override = tex->rd_format_srgb; + tex->rd_texture_srgb = RD::get_singleton()->texture_create_shared(tex->rd_view, proxy_to->rd_texture); + } +} + //these two APIs can be used together or in combination with the others. RID RasterizerStorageRD::texture_2d_placeholder_create() { @@ -629,20 +694,34 @@ void RasterizerStorageRD::texture_replace(RID p_texture, RID p_by_texture) { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND(!tex); + ERR_FAIL_COND(tex->proxy_to.is_valid()); //cant replace proxy Texture *by_tex = texture_owner.getornull(p_by_texture); ERR_FAIL_COND(!by_tex); + ERR_FAIL_COND(by_tex->proxy_to.is_valid()); //cant replace proxy if (tex == by_tex) { return; } - RD::get_singleton()->free(tex->rd_texture); if (tex->rd_texture_srgb.is_valid()) { RD::get_singleton()->free(tex->rd_texture_srgb); } + RD::get_singleton()->free(tex->rd_texture); + + Vector<RID> proxies_to_update = tex->proxies; + Vector<RID> proxies_to_redirect = by_tex->proxies; *tex = *by_tex; + tex->proxies = proxies_to_update; //restore proxies, so they can be updated + + for (int i = 0; i < proxies_to_update.size(); i++) { + texture_proxy_update(proxies_to_update[i], p_texture); + } + for (int i = 0; i < proxies_to_redirect.size(); i++) { + texture_proxy_update(proxies_to_redirect[i], p_texture); + } + //delete last, so proxies can be updated texture_owner.free(p_by_texture); } void RasterizerStorageRD::texture_set_size_override(RID p_texture, int p_width, int p_height) { @@ -650,7 +729,7 @@ void RasterizerStorageRD::texture_set_size_override(RID p_texture, int p_width, ERR_FAIL_COND(!tex); ERR_FAIL_COND(tex->type != Texture::TYPE_2D); tex->width_2d = p_width; - tex->height_2d = p_width; + tex->height_2d = p_height; } void RasterizerStorageRD::texture_set_path(RID p_texture, const String &p_path) { @@ -673,8 +752,8 @@ void RasterizerStorageRD::texture_set_proxy(RID p_proxy, RID p_base) { void RasterizerStorageRD::texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) { } -Size2 RasterizerStorageRD::texture_size_with_proxy(RID p_proxy) const { - return Size2(); +Size2 RasterizerStorageRD::texture_size_with_proxy(RID p_proxy) { + return texture_2d_get_size(p_proxy); } /* RENDER TARGET API */ @@ -685,9 +764,6 @@ void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) { if (rt->framebuffer.is_valid()) { RD::get_singleton()->free(rt->framebuffer); } - if (rt->color_srgb.is_valid()) { - RD::get_singleton()->free(rt->color_srgb); - } if (rt->color.is_valid()) { RD::get_singleton()->free(rt->color); @@ -695,14 +771,19 @@ void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) { rt->framebuffer = RID(); rt->color = RID(); - rt->color_srgb = RID(); rt->dirty = true; - rt->texture_dirty = true; } void RasterizerStorageRD::_update_render_target(RenderTarget *rt) { + if (rt->texture.is_null()) { + //create a placeholder until updated + rt->texture = texture_2d_placeholder_create(); + Texture *tex = texture_owner.getornull(rt->texture); + tex->is_render_target = true; + } + _clear_render_target(rt); if (rt->size.width == 0 || rt->size.height == 0) { @@ -732,14 +813,6 @@ void RasterizerStorageRD::_update_render_target(RenderTarget *rt) { rt->color = RD::get_singleton()->texture_create(rd_format, rd_view); ERR_FAIL_COND(rt->color.is_null()); - if (rt->color_format_srgb != RD::DATA_FORMAT_MAX) { - rd_view.format_override = rt->color_format_srgb; - rt->color_srgb = RD::get_singleton()->texture_create_shared(rd_view, rt->color); - if (rt->color_srgb.is_null()) { - _clear_render_target(rt); - ERR_FAIL_COND(rt->color_srgb.is_null()); - } - } Vector<RID> fb_textures; fb_textures.push_back(rt->color); @@ -749,14 +822,55 @@ void RasterizerStorageRD::_update_render_target(RenderTarget *rt) { ERR_FAIL_COND(rt->framebuffer.is_null()); } + { //update texture + + Texture *tex = texture_owner.getornull(rt->texture); + + //free existing textures + if (RD::get_singleton()->texture_is_valid(tex->rd_texture)) { + RD::get_singleton()->free(tex->rd_texture); + } + if (RD::get_singleton()->texture_is_valid(tex->rd_texture_srgb)) { + RD::get_singleton()->free(tex->rd_texture_srgb); + } + + tex->rd_texture = RID(); + tex->rd_texture_srgb = RID(); + + //create shared textures to the color buffer, + //so transparent can be supported + RD::TextureView view; + view.format_override = rt->color_format; + if (!rt->flags[RENDER_TARGET_TRANSPARENT]) { + view.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } + tex->rd_texture = RD::get_singleton()->texture_create_shared(view, rt->color); + if (rt->color_format_srgb != RD::DATA_FORMAT_MAX) { + view.format_override = rt->color_format_srgb; + tex->rd_texture_srgb = RD::get_singleton()->texture_create_shared(view, rt->color); + } + tex->rd_view = view; + tex->width = rt->size.width; + tex->height = rt->size.height; + tex->width_2d = rt->size.width; + tex->height_2d = rt->size.height; + tex->rd_format = rt->color_format; + tex->rd_format_srgb = rt->color_format_srgb; + tex->format = rt->image_format; + + Vector<RID> proxies = tex->proxies; //make a copy, since update may change it + for (int i = 0; i < proxies.size(); i++) { + texture_proxy_update(proxies[i], rt->texture); + } + } rt->dirty = false; } RID RasterizerStorageRD::render_target_create() { RenderTarget render_target; render_target.dirty = true; - render_target.texture_dirty = true; render_target.was_used = false; + render_target.clear_requested = false; for (int i = 0; i < RENDER_TARGET_FLAG_MAX; i++) { render_target.flags[i] = false; @@ -774,48 +888,14 @@ void RasterizerStorageRD::render_target_set_size(RID p_render_target, int p_widt rt->size.x = p_width; rt->size.y = p_height; rt->dirty = true; - rt->texture_dirty = true; } RID RasterizerStorageRD::render_target_get_texture(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); - if (rt->texture_dirty) { - if (rt->dirty) { - _update_render_target(rt); - } - - if (rt->texture.is_null()) { - //kinda hacky, but not terrible - rt->texture = texture_2d_placeholder_create(); - } - - Texture *tex = texture_owner.getornull(rt->texture); - - if (!tex->is_render_target) { - //first allocation, fix it up - RD::get_singleton()->free(tex->rd_texture); - if (tex->rd_texture_srgb.is_null()) { - RD::get_singleton()->free(tex->rd_texture_srgb); - } - tex->is_render_target = true; - } - - if (!rt->color.is_null()) { - //there is a color buffer, update to it - tex->rd_texture = rt->color; - tex->rd_texture_srgb = rt->color_srgb; - tex->width = rt->size.width; - tex->height = rt->size.height; - tex->width_2d = rt->size.width; - tex->height_2d = rt->size.height; - tex->rd_format = rt->color_format; - tex->rd_format_srgb = rt->color_format_srgb; - tex->format = rt->image_format; - } - - rt->texture_dirty = false; + if (rt->dirty) { + _update_render_target(rt); } return rt->texture; @@ -829,7 +909,6 @@ void RasterizerStorageRD::render_target_set_flag(RID p_render_target, RenderTarg ERR_FAIL_COND(!rt); rt->flags[p_flag] = p_value; rt->dirty = true; - rt->texture_dirty = true; } bool RasterizerStorageRD::render_target_was_used(RID p_render_target) { @@ -839,7 +918,7 @@ bool RasterizerStorageRD::render_target_was_used(RID p_render_target) { return rt->was_used; } -void RasterizerStorageRD::render_target_clear_used_flag(RID p_render_target) { +void RasterizerStorageRD::render_target_set_as_unused(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); @@ -864,6 +943,33 @@ RID RasterizerStorageRD::render_target_get_rd_framebuffer(RID p_render_target) { return rt->framebuffer; } +void RasterizerStorageRD::render_target_request_clear(RID p_render_target, const Color &p_clear_color) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + rt->clear_requested = true; + rt->clear_color = p_clear_color; +} + +bool RasterizerStorageRD::render_target_is_clear_requested(RID p_render_target) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, false); + return rt->clear_requested; +} + +Color RasterizerStorageRD::render_target_get_clear_request_color(RID p_render_target) { + + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, Color()); + return rt->clear_color; +} + +void RasterizerStorageRD::render_target_disable_clear_request(RID p_render_target) { + + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + rt->clear_requested = false; +} + bool RasterizerStorageRD::free(RID p_rid) { if (texture_owner.owns(p_rid)) { @@ -871,10 +977,19 @@ bool RasterizerStorageRD::free(RID p_rid) { ERR_FAIL_COND_V(t->is_render_target, false); - RD::get_singleton()->free(t->rd_texture); if (t->rd_texture_srgb.is_valid()) { + //erase this first, as it's a dependency of the one below RD::get_singleton()->free(t->rd_texture_srgb); } + RD::get_singleton()->free(t->rd_texture); + + for (int i = 0; i < t->proxies.size(); i++) { + Texture *p = texture_owner.getornull(t->proxies[i]); + ERR_CONTINUE(!p); + p->proxy_to = RID(); + p->rd_texture = RID(); + p->rd_texture_srgb = RID(); + } texture_owner.free(p_rid); } else if (render_target_owner.owns(p_rid)) { diff --git a/servers/visual/rasterizer/rasterizer_storage_rd.h b/servers/visual/rasterizer/rasterizer_storage_rd.h index caaaced75f..39404347fb 100644 --- a/servers/visual/rasterizer/rasterizer_storage_rd.h +++ b/servers/visual/rasterizer/rasterizer_storage_rd.h @@ -23,6 +23,8 @@ public: RenderingDevice::DataFormat rd_format; RenderingDevice::DataFormat rd_format_srgb; + RD::TextureView rd_view; + Image::Format format; int width; int height; @@ -34,9 +36,13 @@ public: int width_2d; bool is_render_target; + bool is_proxy; Ref<Image> image_cache_2d; String path; + + RID proxy_to; + Vector<RID> proxies; }; struct TextureToRDFormat { @@ -67,7 +73,6 @@ public: Size2i size; RID framebuffer; RID color; - RID color_srgb; //used for retrieving from CPU RD::DataFormat color_format; @@ -79,8 +84,11 @@ public: //texture generated for this owner (nor RD). RID texture; bool dirty; - bool texture_dirty; bool was_used; + + //clear request + bool clear_requested; + Color clear_color; }; RID_Owner<RenderTarget> render_target_owner; @@ -94,12 +102,14 @@ public: virtual RID texture_2d_create(const Ref<Image> &p_image); virtual RID texture_2d_layered_create(const Vector<Ref<Image> > &p_layers, VS::TextureLayeredType p_layered_type); virtual RID texture_3d_create(const Vector<Ref<Image> > &p_slices); //all slices, then all the mipmaps, must be coherent + virtual RID texture_proxy_create(RID p_base); virtual void _texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_immediate); virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0); //mostly used for video and streaming virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0); virtual void texture_3d_update(RID p_texture, const Ref<Image> &p_image, int p_depth, int p_mipmap); + virtual void texture_proxy_update(RID p_texture, RID p_proxy_to); //these two APIs can be used together or in combination with the others. virtual RID texture_2d_placeholder_create(); @@ -125,7 +135,7 @@ public: virtual void texture_set_proxy(RID p_proxy, RID p_base); virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable); - virtual Size2 texture_size_with_proxy(RID p_proxy) const; + virtual Size2 texture_size_with_proxy(RID p_proxy); //internal usage @@ -625,7 +635,12 @@ public: void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id); void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value); bool render_target_was_used(RID p_render_target); - void render_target_clear_used_flag(RID p_render_target); + void render_target_set_as_unused(RID p_render_target); + + virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color); + virtual bool render_target_is_clear_requested(RID p_render_target); + virtual Color render_target_get_clear_request_color(RID p_render_target); + virtual void render_target_disable_clear_request(RID p_render_target); Size2 render_target_get_size(RID p_render_target); RID render_target_get_rd_framebuffer(RID p_render_target); diff --git a/servers/visual/rasterizer/render_pipeline_vertex_format_cache_rd.cpp b/servers/visual/rasterizer/render_pipeline_vertex_format_cache_rd.cpp index 441c70cdcf..be2aa95c34 100644 --- a/servers/visual/rasterizer/render_pipeline_vertex_format_cache_rd.cpp +++ b/servers/visual/rasterizer/render_pipeline_vertex_format_cache_rd.cpp @@ -22,7 +22,10 @@ void RenderPipelineVertexFormatCacheRD::_clear() { for (int v = 0; v < RD::TEXTURE_SAMPLES_MAX; v++) { if (versions[v]) { for (uint32_t i = 0; i < version_count[v]; i++) { - RD::get_singleton()->free(versions[v][i].pipeline); + //shader may be gone, so this may not be valid + if (RD::get_singleton()->render_pipeline_is_valid(versions[v][i].pipeline)) { + RD::get_singleton()->free(versions[v][i].pipeline); + } } version_count[v] = 0; memfree(versions[v]); diff --git a/servers/visual/rasterizer/shaders/canvas.glsl b/servers/visual/rasterizer/shaders/canvas.glsl index f8900326c8..50782f99b0 100644 --- a/servers/visual/rasterizer/shaders/canvas.glsl +++ b/servers/visual/rasterizer/shaders/canvas.glsl @@ -8,13 +8,14 @@ VERSION_DEFINES /* clang-format on */ -#ifdef USE_VERTEX_ARRAYS +#ifdef USE_ATTRIBUTES layout(location = 0) in vec2 vertex_attrib; layout(location = 3) in vec4 color_attrib; layout(location = 4) in vec2 uv_attrib; layout(location = 6) in uvec4 bone_indices_attrib; layout(location = 7) in vec4 bone_weights_attrib; + #endif #include "canvas_uniforms_inc.glsl" @@ -42,12 +43,45 @@ VERTEX_SHADER_GLOBALS void main() { vec4 instance_custom = vec4(0.0); +#ifdef USE_PRIMITIVE + +//weird bug, +//this works + vec2 vertex; + vec2 uv; + vec4 color; + + if (gl_VertexIndex==0) { + vertex = draw_data.points[0]; + uv = draw_data.uvs[0]; + color = vec4(unpackHalf2x16(draw_data.colors[0]),unpackHalf2x16(draw_data.colors[1])); + } else if (gl_VertexIndex==1) { + vertex = draw_data.points[1]; + uv = draw_data.uvs[1]; + color = vec4(unpackHalf2x16(draw_data.colors[2]),unpackHalf2x16(draw_data.colors[3])); + } else if (gl_VertexIndex==2) { + vertex = draw_data.points[2]; + uv = draw_data.uvs[2]; + color = vec4(unpackHalf2x16(draw_data.colors[4]),unpackHalf2x16(draw_data.colors[5])); -#ifdef USE_VERTEX_ARRAYS + } else { + vertex = draw_data.points[3]; + uv = draw_data.uvs[3]; + color = vec4(unpackHalf2x16(draw_data.colors[6]),unpackHalf2x16(draw_data.colors[7])); + } +// this does not +// vec2 vertex = draw_data.points[gl_VertexIndex]; +// vec2 uv = draw_data.uvs[gl_VertexIndex]; +// vec4 color = vec4(unpackHalf2x16(draw_data.colors[gl_VertexIndex*2+0]),unpackHalf2x16(draw_data.colors[gl_VertexIndex*2+1])); + uvec4 bone_indices = uvec4(0,0,0,0); + vec4 bone_weights = vec4(0,0,0,0); + +#elif defined(USE_ATTRIBUTES) vec2 vertex = vertex_attrib; vec4 color = color_attrib; vec2 uv = uv_attrib; + uvec4 bone_indices = bone_indices_attrib; vec4 bone_weights = bone_weights_attrib; #else @@ -55,16 +89,17 @@ void main() { vec2 vertex_base_arr[4] = vec2[](vec2(0.0,0.0),vec2(0.0,1.0),vec2(1.0,1.0),vec2(1.0,0.0)); vec2 vertex_base = vertex_base_arr[gl_VertexIndex]; - vec2 uv = draw_data.src_rect.xy + draw_data.src_rect.zw * ((draw_data.flags&FLAGS_TRANSPOSE_RECT)!=0 ? vertex_base.yx : vertex_base.xy); - vec4 color = vec4(1.0); + vec2 uv = draw_data.src_rect.xy + abs(draw_data.src_rect.zw) * ((draw_data.flags&FLAGS_TRANSPOSE_RECT)!=0 ? vertex_base.yx : vertex_base.xy); + vec4 color = draw_data.modulation; vec2 vertex = draw_data.dst_rect.xy + abs(draw_data.dst_rect.zw) * mix(vertex_base, vec2(1.0, 1.0) - vertex_base, lessThan(draw_data.src_rect.zw, vec2(0.0, 0.0))); uvec4 bone_indices = uvec4(0,0,0,0); vec4 bone_weights = vec4(0,0,0,0); #endif - mat4 world_matrix = transpose(mat4(draw_data.world[0],draw_data.world[1],vec4(0.0,0.0,1.0,0.0),vec4(0.0,0.0,0.0,1.0))); + mat4 world_matrix = mat4(vec4(draw_data.world_x,0.0,0.0),vec4(draw_data.world_y,0.0,0.0),vec4(0.0,0.0,1.0,0.0),vec4(draw_data.world_ofs,0.0,1.0)); #if 0 + if (draw_data.flags&FLAGS_INSTANCING_ENABLED) { uint offset = draw_data.flags&FLAGS_INSTANCING_STRIDE_MASK; @@ -101,10 +136,13 @@ void main() { #endif +#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE) if (bool(draw_data.flags&FLAGS_USING_PARTICLES)) { //scale by texture size vertex /= draw_data.color_texture_pixel_size; } +#endif + #ifdef USE_POINT_SIZE float point_size = 1.0; #endif @@ -134,6 +172,7 @@ VERTEX_SHADER_CODE uv += 1e-5; } +#ifdef USE_ATTRIBUTES #if 0 if (bool(draw_data.flags&FLAGS_USE_SKELETON) && bone_weights != vec4(0.0)) { //must be a valid bone //skeleton transform @@ -174,6 +213,7 @@ VERTEX_SHADER_CODE //outvec = bone_matrix * outvec; } #endif +#endif uv_interp = uv; #if !defined(SKIP_TRANSFORM_USED) @@ -285,7 +325,7 @@ void main() { vec4 color = color_interp; vec2 uv = uv_interp; -#ifndef USE_VERTEX_ARRAYS +#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE) #ifdef USE_NINEPATCH @@ -300,8 +340,7 @@ void main() { uv = uv * draw_data.src_rect.zw + draw_data.src_rect.xy; //apply region if needed -#endif - +#endif if (bool(draw_data.flags&FLAGS_CLIP_RECT_UV)) { uv = clamp(uv, draw_data.src_rect.xy, draw_data.src_rect.xy + abs(draw_data.src_rect.zw)); @@ -362,7 +401,6 @@ FRAGMENT_SHADER_CODE #endif } - color *= draw_data.modulation; #if 0 if (canvas_data.light_count > 0 ) { //do lighting diff --git a/servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl b/servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl index d49b628078..e0f9e202ae 100644 --- a/servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl +++ b/servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl @@ -17,24 +17,28 @@ #define FLAGS_USING_PARTICLES (1 << 13) #define FLAGS_USE_PIXEL_SNAP (1 << 14) -#define FLAGS_USE_SKELETON (1 << 15) #define FLAGS_NINEPATCH_H_MODE_SHIFT 16 #define FLAGS_NINEPATCH_V_MODE_SHIFT 18 -layout(push_constant, binding = 0, std140) uniform DrawData { - mat2x4 world; +layout(push_constant, binding = 0, std430) uniform DrawData { + vec2 world_x; + vec2 world_y; + vec2 world_ofs; + uint flags; + uint specular_shininess; +#ifdef USE_PRIMITIVE + vec2 points[4]; + uint colors[8]; + vec2 uvs[4]; +#else vec4 modulation; vec4 ninepatch_margins; vec4 dst_rect; //for built-in rect and UV vec4 src_rect; - uint flags; - uint specular_shininess; vec2 color_texture_pixel_size; - uint pad0; - uint pad1; - uint pad2; - uint pad3; + uint pad[6]; +#endif } draw_data; @@ -51,16 +55,18 @@ layout(set = 0, binding = 5) uniform textureBuffer instancing_buffer; // -/* SET2: Per Canvas Item Settings */ +/* SET2: Is the skeleton */ + +#ifdef USE_ATTRIBUTES -layout(set = 1, binding = 1) uniform textureBuffer skeleton_buffer; +layout(set = 2, binding = 0) uniform textureBuffer skeleton_buffer; -layout(set = 1, binding = 2, std140) uniform SkeletonData { - mat4 skeleton_transform; +layout(set = 2, binding = 1, std140) uniform SkeletonData { + mat4 skeleton_transform; //in world coordinates mat4 skeleton_transform_inverse; } skeleton_data; -// this set (set 2) is also used for instance specific uniforms +#endif /* SET3: Per Scene settings */ diff --git a/servers/visual/rendering_device.h b/servers/visual/rendering_device.h index d30af9a7cb..493390ba07 100644 --- a/servers/visual/rendering_device.h +++ b/servers/visual/rendering_device.h @@ -354,6 +354,8 @@ public: virtual Error texture_update(RID p_texture, uint32_t p_layer, const PoolVector<uint8_t> &p_data, bool p_sync_with_draw = false) = 0; //this function can be used from any thread and it takes effect at the begining of the frame, unless sync with draw is used, which is used to mix updates with draw calls virtual bool texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const = 0; + virtual bool texture_is_shared(RID p_texture) =0; + virtual bool texture_is_valid(RID p_texture) = 0; /*********************/ /**** FRAMEBUFFER ****/ @@ -811,6 +813,7 @@ public: }; virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0) = 0; + virtual bool render_pipeline_is_valid(RID p_pipeline) =0; /****************/ /**** SCREEN ****/ @@ -850,6 +853,7 @@ public: virtual void draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index) = 0; virtual void draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array) = 0; virtual void draw_list_bind_index_array(DrawListID p_list, RID p_index_array) = 0; + virtual void draw_list_set_line_width(DrawListID p_list, float p_width) = 0; virtual void draw_list_set_push_constant(DrawListID p_list, void *p_data, uint32_t p_data_size) = 0; virtual void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1) = 0; @@ -866,6 +870,7 @@ public: virtual void free(RID p_id) = 0; //methods below not exposed, used by RenderingDeviceRD + virtual void prepare_screen_for_drawing() =0; virtual void finalize_frame() = 0; virtual void advance_frame() = 0; diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index 790dc59496..f44548aded 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -35,7 +35,7 @@ static const int z_range = VS::CANVAS_ITEM_Z_MAX - VS::CANVAS_ITEM_Z_MIN + 1; -void VisualServerCanvas::_render_canvas_item_tree(RID p_to_render_target, bool p_clear, const Color &p_clear_color, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights) { +void VisualServerCanvas::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights) { memset(z_list, 0, z_range * sizeof(RasterizerCanvas::Item *)); memset(z_last_list, 0, z_range * sizeof(RasterizerCanvas::Item *)); @@ -62,7 +62,7 @@ void VisualServerCanvas::_render_canvas_item_tree(RID p_to_render_target, bool p } } - VSG::canvas_render->canvas_render_items(p_to_render_target, p_clear, p_clear_color, list, p_modulate, p_lights, p_transform); + VSG::canvas_render->canvas_render_items(p_to_render_target, list, p_modulate, p_lights, p_transform); } void _collect_ysort_children(VisualServerCanvas::Item *p_canvas_item, Transform2D p_transform, VisualServerCanvas::Item *p_material_owner, const Color p_modulate, VisualServerCanvas::Item **r_items, int &r_index) { @@ -243,7 +243,7 @@ void VisualServerCanvas::_light_mask_canvas_items(int p_z, RasterizerCanvas::Ite } } -void VisualServerCanvas::render_canvas(RID p_render_target, bool p_clear, const Color &p_clear_color, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect) { +void VisualServerCanvas::render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect) { if (p_canvas->children_order_dirty) { @@ -264,30 +264,30 @@ void VisualServerCanvas::render_canvas(RID p_render_target, bool p_clear, const if (!has_mirror) { - _render_canvas_item_tree(p_render_target, p_clear, p_clear_color, ci, l, NULL, p_transform, p_clip_rect, p_canvas->modulate, p_lights); + _render_canvas_item_tree(p_render_target, ci, l, NULL, p_transform, p_clip_rect, p_canvas->modulate, p_lights); } else { //used for parallaxlayer mirroring for (int i = 0; i < l; i++) { const Canvas::ChildItem &ci2 = p_canvas->child_items[i]; - _render_canvas_item_tree(p_render_target, p_clear, p_clear_color, NULL, 0, ci2.item, p_transform, p_clip_rect, p_canvas->modulate, p_lights); + _render_canvas_item_tree(p_render_target, NULL, 0, ci2.item, p_transform, p_clip_rect, p_canvas->modulate, p_lights); //mirroring (useful for scrolling backgrounds) if (ci2.mirror.x != 0) { Transform2D xform2 = p_transform * Transform2D(0, Vector2(ci2.mirror.x, 0)); - _render_canvas_item_tree(p_render_target, false, Color(), NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); + _render_canvas_item_tree(p_render_target, NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); } if (ci2.mirror.y != 0) { Transform2D xform2 = p_transform * Transform2D(0, Vector2(0, ci2.mirror.y)); - _render_canvas_item_tree(p_render_target, false, Color(), NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); + _render_canvas_item_tree(p_render_target, NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); } if (ci2.mirror.y != 0 && ci2.mirror.x != 0) { Transform2D xform2 = p_transform * Transform2D(0, ci2.mirror); - _render_canvas_item_tree(p_render_target, false, Color(), NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); + _render_canvas_item_tree(p_render_target, NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); } } } @@ -487,15 +487,27 @@ void VisualServerCanvas::canvas_item_add_line(RID p_item, const Point2 &p_from, Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); - Item::CommandLine *line = memnew(Item::CommandLine); + Item::CommandPrimitive *line = memnew(Item::CommandPrimitive); ERR_FAIL_COND(!line); - line->color = p_color; - line->from = p_from; - line->to = p_to; - line->width = p_width; - line->antialiased = p_antialiased; - canvas_item->rect_dirty = true; + if (p_width > 1.001) { + + Vector2 t = (p_from - p_to).tangent().normalized(); + line->points[0] = p_from + t * p_width; + line->points[1] = p_from - t * p_width; + line->points[2] = p_to - t * p_width; + line->points[3] = p_to + t * p_width; + line->point_count = 4; + } else { + line->point_count = 2; + line->points[0] = p_from; + line->points[1] = p_to; + } + for (int i = 0; i < line->point_count; i++) { + line->colors[i] = p_color; + } + line->specular_shininess = Color(1, 1, 1, 1); + canvas_item->rect_dirty = true; canvas_item->commands.push_back(line); } @@ -505,21 +517,29 @@ void VisualServerCanvas::canvas_item_add_polyline(RID p_item, const Vector<Point Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); - Item::CommandPolyLine *pline = memnew(Item::CommandPolyLine); + Item::CommandPolygon *pline = memnew(Item::CommandPolygon); ERR_FAIL_COND(!pline); - pline->antialiased = p_antialiased; - pline->multiline = false; - - if (p_width <= 1) { - pline->lines = p_points; - pline->line_colors = p_colors; - if (pline->line_colors.size() == 0) { - pline->line_colors.push_back(Color(1, 1, 1, 1)); - } else if (pline->line_colors.size() > 1 && pline->line_colors.size() != pline->lines.size()) { - pline->line_colors.resize(1); + pline->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, RID(), RID(), RID(), VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED, RID()); + + if (true || p_width <= 1) { +#define TODO make thick lines possible + Vector<int> indices; + int pc = p_points.size(); + indices.resize((pc - 1) * 2); + { + int *iptr = indices.ptrw(); + for (int i = 0; i < (pc - 1); i++) { + iptr[i * 2 + 0] = i; + iptr[i * 2 + 1] = i + 1; + } } + + pline->primitive = VS::PRIMITIVE_LINES; + pline->specular_shininess = Color(1, 1, 1, 1); + pline->polygon.create(indices, p_points, p_colors); } else { +#if 0 //make a trianglestrip for drawing the line... Vector2 prev_t; pline->triangles.resize(p_points.size() * 2); @@ -579,6 +599,7 @@ void VisualServerCanvas::canvas_item_add_polyline(RID p_item, const Vector<Point prev_t = t; } +#endif } canvas_item->rect_dirty = true; canvas_item->commands.push_back(pline); @@ -590,18 +611,18 @@ void VisualServerCanvas::canvas_item_add_multiline(RID p_item, const Vector<Poin Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); - Item::CommandPolyLine *pline = memnew(Item::CommandPolyLine); + Item::CommandPolygon *pline = memnew(Item::CommandPolygon); ERR_FAIL_COND(!pline); - pline->antialiased = false; //todo - pline->multiline = true; + pline->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, RID(), RID(), RID(), VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED, RID()); + + if (true || p_width <= 1) { +#define TODO make thick lines possible - pline->lines = p_points; - pline->line_colors = p_colors; - if (pline->line_colors.size() == 0) { - pline->line_colors.push_back(Color(1, 1, 1, 1)); - } else if (pline->line_colors.size() > 1 && pline->line_colors.size() != pline->lines.size()) { - pline->line_colors.resize(1); + pline->primitive = VS::PRIMITIVE_LINES; + pline->specular_shininess = Color(1, 1, 1, 1); + pline->polygon.create(Vector<int>(), p_points, p_colors); + } else { } canvas_item->rect_dirty = true; @@ -627,12 +648,39 @@ void VisualServerCanvas::canvas_item_add_circle(RID p_item, const Point2 &p_pos, Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); - Item::CommandCircle *circle = memnew(Item::CommandCircle); + Item::CommandPolygon *circle = memnew(Item::CommandPolygon); ERR_FAIL_COND(!circle); - circle->color = p_color; - circle->pos = p_pos; - circle->radius = p_radius; + circle->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, RID(), RID(), RID(), VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED, RID()); + + circle->primitive = VS::PRIMITIVE_TRIANGLES; + circle->specular_shininess = Color(1, 1, 1, 1); + + Vector<int> indices; + Vector<Vector2> points; + + static const int circle_points = 64; + + points.resize(circle_points); + for (int i = 0; i < circle_points; i++) { + float angle = (i / float(circle_points)) * 2 * Math_PI; + points.write[i].x = Math::cos(angle) * p_radius; + points.write[i].y = Math::sin(angle) * p_radius; + points.write[i] += p_pos; + } + indices.resize((circle_points - 2) * 3); + + for (int i = 0; i < circle_points - 2; i++) { + indices.write[i * 3 + 0] = 0; + indices.write[i * 3 + 1] = i + 1; + indices.write[i * 3 + 2] = i + 2; + } + + Vector<Color> color; + color.push_back(p_color); + circle->polygon.create(indices, points, color); + + canvas_item->rect_dirty = true; canvas_item->commands.push_back(circle); } @@ -746,17 +794,33 @@ void VisualServerCanvas::canvas_item_add_nine_patch(RID p_item, const Rect2 &p_r } void VisualServerCanvas::canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat) { + uint32_t pc = p_points.size(); + ERR_FAIL_COND(pc == 0 || pc > 4); + Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); Item::CommandPrimitive *prim = memnew(Item::CommandPrimitive); ERR_FAIL_COND(!prim); + + for (int i = 0; i < p_points.size(); i++) { + prim->points[i] = p_points[i]; + if (i < p_uvs.size()) { + prim->uvs[i] = p_uvs[i]; + } + if (i < p_colors.size()) { + prim->colors[i] = p_colors[i]; + } else if (p_colors.size()) { + prim->colors[i] = p_colors[0]; + } else { + prim->colors[i] = Color(1, 1, 1, 1); + } + } + + prim->point_count = p_points.size(); + prim->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID()); prim->specular_shininess = p_specular_color_shininess; - prim->points = p_points; - prim->uvs = p_uvs; - prim->colors = p_colors; - prim->width = p_width; canvas_item->rect_dirty = true; canvas_item->commands.push_back(prim); @@ -779,14 +843,11 @@ void VisualServerCanvas::canvas_item_add_polygon(RID p_item, const Vector<Point2 Item::CommandPolygon *polygon = memnew(Item::CommandPolygon); ERR_FAIL_COND(!polygon); + polygon->primitive = VS::PRIMITIVE_TRIANGLES; polygon->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID()); polygon->specular_shininess = p_specular_color_shininess; - polygon->points = p_points; - polygon->uvs = p_uvs; - polygon->colors = p_colors; - polygon->indices = indices; - polygon->count = indices.size(); - polygon->antialiased = p_antialiased; + polygon->polygon.create(indices, p_points, p_colors, p_uvs); + canvas_item->rect_dirty = true; canvas_item->commands.push_back(polygon); @@ -806,32 +867,13 @@ void VisualServerCanvas::canvas_item_add_triangle_array(RID p_item, const Vector const Vector<int> &indices = p_indices; - int count = p_count * 3; - - if (indices.empty()) { - - ERR_FAIL_COND(vertex_count % 3 != 0); - if (p_count == -1) - count = vertex_count; - } else { - - ERR_FAIL_COND(indices.size() % 3 != 0); - if (p_count == -1) - count = indices.size(); - } - Item::CommandPolygon *polygon = memnew(Item::CommandPolygon); ERR_FAIL_COND(!polygon); polygon->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID()); polygon->specular_shininess = p_specular_color_shininess; - polygon->points = p_points; - polygon->uvs = p_uvs; - polygon->colors = p_colors; - polygon->bones = p_bones; - polygon->weights = p_weights; - polygon->indices = indices; - polygon->count = count; - polygon->antialiased = p_antialiased; + polygon->polygon.create(indices, p_points, p_colors, p_uvs, p_bones, p_weights); + + polygon->primitive = VS::PRIMITIVE_TRIANGLES; canvas_item->rect_dirty = true; canvas_item->commands.push_back(polygon); diff --git a/servers/visual/visual_server_canvas.h b/servers/visual/visual_server_canvas.h index 4a1bce51f9..d979d202b4 100644 --- a/servers/visual/visual_server_canvas.h +++ b/servers/visual/visual_server_canvas.h @@ -162,7 +162,7 @@ public: bool disable_scale; private: - void _render_canvas_item_tree(RID p_to_render_target, bool p_clear, const Color &p_clear_color, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights); + void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights); void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RasterizerCanvas::Item **z_list, RasterizerCanvas::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner); void _light_mask_canvas_items(int p_z, RasterizerCanvas::Item *p_canvas_item, RasterizerCanvas::Light *p_masked_lights); @@ -170,7 +170,7 @@ private: RasterizerCanvas::Item **z_last_list; public: - void render_canvas(RID p_render_target, bool p_clear, const Color &p_clear_color, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect); + void render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect); RID canvas_create(); void canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 32c14e6f21..ba4eccd0f0 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -150,12 +150,14 @@ public: BIND1R(RID, texture_2d_create, const Ref<Image> &) BIND2R(RID, texture_2d_layered_create, const Vector<Ref<Image> > &, TextureLayeredType) BIND1R(RID, texture_3d_create, const Vector<Ref<Image> > &) + BIND1R(RID, texture_proxy_create, RID) //goes pass-through BIND3(texture_2d_update_immediate, RID, const Ref<Image> &, int) //these go through command queue if they are in another thread BIND3(texture_2d_update, RID, const Ref<Image> &, int) BIND4(texture_3d_update, RID, const Ref<Image> &, int, int) + BIND2(texture_proxy_update, RID, RID) //these also go pass-through BIND0R(RID, texture_2d_placeholder_create) @@ -182,8 +184,6 @@ public: BIND1RC(String, texture_get_path, RID) BIND1(texture_debug_usage, List<TextureInfo> *) - BIND2(texture_set_proxy, RID, RID) - BIND2(texture_set_force_redraw_if_visible, RID, bool) /* SKY API */ diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index ca0caefc77..05db6454dc 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -81,7 +81,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E bool scenario_draw_canvas_bg = false; //draw canvas, or some layer of it, as BG for 3D instead of in front int scenario_canvas_max_layer = 0; - bool cleared = false; + Color bgcolor = clear_color; if (!p_viewport->hide_canvas && !p_viewport->disable_environment && VSG::scene->scenario_owner.owns(p_viewport->scenario)) { @@ -106,9 +106,10 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E } } + VSG::storage->render_target_request_clear(p_viewport->render_target, bgcolor); + if (!scenario_draw_canvas_bg && can_draw_3d) { _draw_3d(p_viewport, p_eye); - cleared = true; //if 3D has drawn, 2D is cleared. } if (!p_viewport->hide_canvas) { @@ -240,8 +241,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E ptr = ptr->filter_next_ptr; } - VSG::canvas->render_canvas(p_viewport->render_target, !cleared, bgcolor, canvas, xform, canvas_lights, lights_with_mask, clip_rect); - cleared = true; + VSG::canvas->render_canvas(p_viewport->render_target, canvas, xform, canvas_lights, lights_with_mask, clip_rect); i++; if (scenario_draw_canvas_bg && E->key().get_layer() >= scenario_canvas_max_layer) { @@ -308,7 +308,7 @@ void VisualServerViewport::draw_viewports() { if (!visible) continue; - VSG::storage->render_target_clear_used_flag(vp->render_target); + VSG::storage->render_target_set_as_unused(vp->render_target); #if 0 if (vp->use_arvr && arvr_interface.is_valid()) { // override our size, make sure it matches our required size @@ -381,6 +381,9 @@ void VisualServerViewport::draw_viewports() { } VSG::scene_render->set_debug_draw_mode(VS::VIEWPORT_DEBUG_DRAW_DISABLED); + //this needs to be called to make screen swapping more efficient + VSG::rasterizer->prepare_for_blitting_render_targets(); + for (Map<int, Vector<Rasterizer::BlitToScreen> >::Element *E = blit_to_screen_list.front(); E; E = E->next()) { VSG::rasterizer->blit_render_targets_to_screen(E->key(), E->get().ptr(), E->get().size()); } diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 6af6c3902e..fb6f42d1a4 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -81,12 +81,14 @@ public: virtual RID texture_2d_create(const Ref<Image> &p_image) { return visual_server->texture_2d_create(p_image); } virtual RID texture_2d_layered_create(const Vector<Ref<Image> > &p_layers, TextureLayeredType p_layered_type) { return visual_server->texture_2d_layered_create(p_layers, p_layered_type); } virtual RID texture_3d_create(const Vector<Ref<Image> > &p_slices) { return visual_server->texture_3d_create(p_slices); } + virtual RID texture_proxy_create(RID p_base) { return visual_server->texture_proxy_create(p_base); } //goes pass-through virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) { visual_server->texture_2d_update_immediate(p_texture, p_image, p_layer); } //these go through command queue if they are in another thread FUNC3(texture_2d_update, RID, const Ref<Image> &, int) FUNC4(texture_3d_update, RID, const Ref<Image> &, int, int) + FUNC2(texture_proxy_update, RID, RID) //these also go pass-through virtual RID texture_2d_placeholder_create() { return visual_server->texture_2d_placeholder_create(); } @@ -113,8 +115,6 @@ public: FUNC1RC(String, texture_get_path, RID) FUNC1S(texture_debug_usage, List<TextureInfo> *) - FUNC2(texture_set_proxy, RID, RID) - FUNC2(texture_set_force_redraw_if_visible, RID, bool) /* SKY API */ |