diff options
author | Juan Linietsky <reduzio@gmail.com> | 2019-06-15 23:45:24 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2020-02-11 11:53:27 +0100 |
commit | 9b0dd4f571ff431e23b9097e7f29746f4157be12 (patch) | |
tree | aa18fc6803e8733f8f270666e691153c72b6066d /servers | |
parent | 836c2109a0b1371653e3c82100199dfdabd47da9 (diff) |
A lot of progress with canvas rendering, still far from working.
Diffstat (limited to 'servers')
27 files changed, 3884 insertions, 222 deletions
diff --git a/servers/server_wrap_mt_common.h b/servers/server_wrap_mt_common.h index b4819431b5..f01e0b9578 100644 --- a/servers/server_wrap_mt_common.h +++ b/servers/server_wrap_mt_common.h @@ -820,3 +820,21 @@ server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \ } \ } + +#define FUNC14(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13, m_arg14) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11, m_arg12 p12, m_arg13 p13, m_arg14 p14) { \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \ + } else { \ + server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \ + } \ + } + +#define FUNC15(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13, m_arg14, m_arg15) \ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7, m_arg8 p8, m_arg9 p9, m_arg10 p10, m_arg11 p11, m_arg12 p12, m_arg13 p13, m_arg14 p14, m_arg15 p15) { \ + if (Thread::get_caller_id() != server_thread) { \ + command_queue.push(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \ + } else { \ + server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \ + } \ + } diff --git a/servers/visual/rasterizer/SCsub b/servers/visual/rasterizer/SCsub index 70cd4087bf..cc17feeb05 100644 --- a/servers/visual/rasterizer/SCsub +++ b/servers/visual/rasterizer/SCsub @@ -4,3 +4,4 @@ Import('env') env.add_source_files(env.servers_sources, "*.cpp") +SConscript("shaders/SCsub") diff --git a/servers/visual/rasterizer/rasterizer.cpp b/servers/visual/rasterizer/rasterizer.cpp index 77c716379a..647908c75f 100644 --- a/servers/visual/rasterizer/rasterizer.cpp +++ b/servers/visual/rasterizer/rasterizer.cpp @@ -40,6 +40,8 @@ Rasterizer *Rasterizer::create() { return _create_func(); } +RasterizerCanvas *RasterizerCanvas::singleton = NULL; + RasterizerStorage *RasterizerStorage::base_singleton = NULL; RasterizerStorage::RasterizerStorage() { diff --git a/servers/visual/rasterizer/rasterizer.h b/servers/visual/rasterizer/rasterizer.h index 70b9ab18c6..c70056ea9a 100644 --- a/servers/visual/rasterizer/rasterizer.h +++ b/servers/visual/rasterizer/rasterizer.h @@ -549,12 +549,11 @@ public: virtual RID render_target_create() = 0; virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) = 0; virtual void render_target_set_size(RID p_render_target, int p_width, int p_height) = 0; - virtual RID render_target_get_texture(RID p_render_target) const = 0; + virtual RID render_target_get_texture(RID p_render_target) = 0; 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(RID p_render_target) = 0; - virtual void render_target_set_msaa(RID p_render_target, VS::ViewportMSAA p_msaa) = 0; + virtual void render_target_clear_used_flag(RID p_render_target) = 0; /* CANVAS SHADOW */ @@ -589,6 +588,8 @@ public: class RasterizerCanvas { public: + static RasterizerCanvas *singleton; + enum CanvasRectFlags { CANVAS_RECT_REGION = 1, @@ -669,6 +670,38 @@ public: virtual void light_internal_update(RID p_rid, Light *p_light) = 0; virtual void light_internal_free(RID p_rid) = 0; + typedef uint64_t TextureBindingID; + + virtual TextureBindingID request_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VS::CanvasItemTextureFilter p_filter, VS::CanvasItemTextureRepeat p_repeat, RID p_multimesh) = 0; + virtual void free_texture_binding(TextureBindingID p_binding) = 0; + + //easier wrap to avoid mistakes + + struct Item; + + struct TextureBinding { + + TextureBindingID binding_id; + + _FORCE_INLINE_ void create(VS::CanvasItemTextureFilter p_item_filter, VS::CanvasItemTextureRepeat p_item_repeat, RID p_texture, RID p_normalmap, RID p_specular, VS::CanvasItemTextureFilter p_filter, VS::CanvasItemTextureRepeat p_repeat, RID p_multimesh) { + if (p_filter == VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT) { + p_filter = p_item_filter; + } + if (p_repeat == VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) { + p_repeat = p_item_repeat; + } + if (p_texture != RID() || p_normalmap != RID() || p_specular != RID() || p_filter != VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT || p_repeat != VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT || p_multimesh.is_valid()) { + ERR_FAIL_COND(binding_id != 0); + binding_id = singleton->request_texture_binding(p_texture, p_normalmap, p_specular, p_filter, p_repeat, p_multimesh); + } + } + + _FORCE_INLINE_ TextureBinding() { binding_id = 0; } + _FORCE_INLINE_ ~TextureBinding() { + if (binding_id) singleton->free_texture_binding(binding_id); + } + }; + struct Item { struct Command { @@ -719,11 +752,12 @@ public: struct CommandRect : public Command { Rect2 rect; - RID texture; - RID normal_map; Color modulate; Rect2 source; uint8_t flags; + Color specular_shininess; + + TextureBinding texture_binding; CommandRect() { flags = 0; @@ -735,13 +769,13 @@ public: Rect2 rect; Rect2 source; - RID texture; - RID normal_map; float margin[4]; bool draw_center; Color color; VS::NinePatchAxisMode axis_x; VS::NinePatchAxisMode axis_y; + Color specular_shininess; + TextureBinding texture_binding; CommandNinePatch() { draw_center = true; type = TYPE_NINEPATCH; @@ -753,10 +787,9 @@ public: Vector<Point2> points; Vector<Point2> uvs; Vector<Color> colors; - RID texture; - RID normal_map; float width; - + Color specular_shininess; + TextureBinding texture_binding; CommandPrimitive() { type = TYPE_PRIMITIVE; width = 1; @@ -771,11 +804,11 @@ public: Vector<Color> colors; Vector<int> bones; Vector<float> weights; - RID texture; - RID normal_map; int count; bool antialiased; - bool antialiasing_use_indices; + + Color specular_shininess; + TextureBinding texture_binding; CommandPolygon() { type = TYPE_POLYGON; @@ -786,26 +819,26 @@ public: struct CommandMesh : public Command { RID mesh; - RID texture; - RID normal_map; Transform2D transform; Color modulate; + Color specular_shininess; + TextureBinding texture_binding; CommandMesh() { type = TYPE_MESH; } }; struct CommandMultiMesh : public Command { RID multimesh; - RID texture; - RID normal_map; + Color specular_shininess; + TextureBinding texture_binding; CommandMultiMesh() { type = TYPE_MULTIMESH; } }; struct CommandParticles : public Command { RID particles; - RID texture; - RID normal_map; + Color specular_shininess; + TextureBinding texture_binding; CommandParticles() { type = TYPE_PARTICLES; } }; @@ -1050,10 +1083,7 @@ public: } }; - virtual void canvas_begin() = 0; - virtual void canvas_end() = 0; - - virtual void canvas_render_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform) = 0; + 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_debug_viewport_shadows(Light *p_lights_with_shadow) = 0; struct LightOccluderInstance { @@ -1084,6 +1114,9 @@ public: virtual void draw_window_margins(int *p_margins, RID *p_margin_textures) = 0; + virtual void update() = 0; + + RasterizerCanvas() { singleton = this; } virtual ~RasterizerCanvas() {} }; @@ -1102,11 +1135,15 @@ public: virtual void initialize() = 0; virtual void begin_frame(double frame_step) = 0; - virtual void set_current_render_target(RID p_render_target) = 0; - virtual void restore_render_target(bool p_3d) = 0; - virtual void clear_render_target(const Color &p_color) = 0; - virtual void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0) = 0; - virtual void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) = 0; + + struct BlitToScreen { + RID render_target; + Rect2i rect; + //lens distorted parameters for VR should go here + }; + + 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; virtual void finalize() = 0; diff --git a/servers/visual/rasterizer/rasterizer_canvas_rd.cpp b/servers/visual/rasterizer/rasterizer_canvas_rd.cpp index 585647ba1d..f8822a1dc5 100644 --- a/servers/visual/rasterizer/rasterizer_canvas_rd.cpp +++ b/servers/visual/rasterizer/rasterizer_canvas_rd.cpp @@ -1 +1,1264 @@ #include "rasterizer_canvas_rd.h" + +void RasterizerCanvasRD::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) { + + p_mat4[0] = p_transform.elements[0][0]; + p_mat4[1] = p_transform.elements[0][1]; + p_mat4[2] = 0; + p_mat4[3] = 0; + p_mat4[4] = p_transform.elements[1][0]; + p_mat4[5] = p_transform.elements[1][1]; + p_mat4[6] = 0; + p_mat4[7] = 0; + p_mat4[8] = 0; + p_mat4[9] = 0; + p_mat4[10] = 1; + p_mat4[11] = 0; + p_mat4[12] = p_transform.elements[2][0]; + p_mat4[13] = p_transform.elements[2][1]; + p_mat4[14] = 0; + p_mat4[15] = 1; +} + +void RasterizerCanvasRD::_update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4) { + + p_mat2x4[0] = p_transform.elements[0][0]; + p_mat2x4[1] = p_transform.elements[1][0]; + p_mat2x4[2] = 0; + p_mat2x4[3] = p_transform.elements[2][0]; + + p_mat2x4[4] = p_transform.elements[0][1]; + p_mat2x4[5] = p_transform.elements[1][1]; + p_mat2x4[6] = 0; + p_mat2x4[7] = 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]; + p_mat4[1] = p_transform.basis.elements[1][0]; + p_mat4[2] = p_transform.basis.elements[2][0]; + p_mat4[3] = 0; + p_mat4[4] = p_transform.basis.elements[0][1]; + p_mat4[5] = p_transform.basis.elements[1][1]; + p_mat4[6] = p_transform.basis.elements[2][1]; + p_mat4[7] = 0; + p_mat4[8] = p_transform.basis.elements[0][2]; + p_mat4[9] = p_transform.basis.elements[1][2]; + p_mat4[10] = p_transform.basis.elements[2][2]; + p_mat4[11] = 0; + p_mat4[12] = p_transform.origin.x; + p_mat4[13] = p_transform.origin.y; + p_mat4[14] = p_transform.origin.z; + p_mat4[15] = 1; +} + +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) { + p_filter = default_samplers.default_filter; + } + + if (p_repeat == VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) { + p_repeat = default_samplers.default_repeat; + } + + TextureBindingKey key; + key.texture = p_texture; + key.normalmap = p_normalmap; + key.specular = p_specular; + key.multimesh = p_multimesh; + key.texture_filter = p_filter; + key.texture_repeat = p_repeat; + + TextureBinding *binding; + TextureBindingID id; + { + TextureBindingID *idptr = bindings.texture_key_bindings.getptr(key); + + if (!idptr) { + id = bindings.id_generator++; + bindings.texture_key_bindings[key] = id; + binding = memnew(TextureBinding); + binding->key = key; + binding->id = id; + + bindings.texture_bindings[id] = binding; + + } else { + id = *idptr; + binding = bindings.texture_bindings[id]; + } + } + + binding->reference_count++; + + if (binding->to_dispose.in_list()) { + //was queued for disposal previously, but ended up reused. + bindings.to_dispose_list.remove(&binding->to_dispose); + } + + 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 white 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); + } + + return id; +} + +void RasterizerCanvasRD::free_texture_binding(TextureBindingID p_binding) { + + TextureBinding **binding_ptr = bindings.texture_bindings.getptr(p_binding); + ERR_FAIL_COND(!binding_ptr); + TextureBinding *binding = *binding_ptr; + ERR_FAIL_COND(binding->reference_count == 0); + binding->reference_count--; + if (binding->reference_count == 0) { + bindings.to_dispose_list.add(&binding->to_dispose); + } +} + +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)) { + RD::get_singleton()->free(binding->uniform_set); + } + + bindings.texture_key_bindings.erase(binding->key); + bindings.texture_bindings.erase(binding->id); + bindings.to_dispose_list.remove(&binding->to_dispose); + memdelete(binding); + } +} + +void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RenderTargetFormat p_render_target_format, const Color &p_modulate, const Transform2D &p_canvas_transform_inverse) { + + 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); + for (int i = 0; i < 4; i++) { + push_constant.modulation[i] = 0; + push_constant.ninepatch_margins[i] = 0; + push_constant.src_rect[i] = 0; + push_constant.dst_rect[i] = 0; + } + push_constant.flags = 0; + push_constant.ninepatch_repeat = 0; + push_constant.color_texture_pixel_size[0] = 0; + push_constant.color_texture_pixel_size[1] = 0; + push_constant.specular_shininess = 0xFFFFFFFF; + push_constant.pad[0] = 0; + push_constant.pad[1] = 0; + push_constant.pad[2] = 0; + + PipelineVariants *pipeline_variants = &shader.pipeline_variants; + + 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); + + //bind pipeline + { + RID pipeline = pipeline_variants->variants[p_render_target_format][PIPELINE_VARIANT_QUAD]; + RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline); + } + + //bind textures + + 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; + } + } + } + + Rect2 src_rect; + Rect2 dst_rect; + + if (texpixel_size != Vector2()) { + push_constant.color_texture_pixel_size[0] = texpixel_size.x; + push_constant.color_texture_pixel_size[1] = texpixel_size.y; + + src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * texpixel_size, rect->source.size * texpixel_size) : Rect2(0, 0, 1, 1); + dst_rect = Rect2(rect->rect.position, rect->rect.size); + + if (dst_rect.size.width < 0) { + dst_rect.position.x += dst_rect.size.width; + dst_rect.size.width *= -1; + } + if (dst_rect.size.height < 0) { + dst_rect.position.y += dst_rect.size.height; + dst_rect.size.height *= -1; + } + + if (rect->flags & CANVAS_RECT_FLIP_H) { + src_rect.size.x *= -1; + } + + if (rect->flags & CANVAS_RECT_FLIP_V) { + src_rect.size.y *= -1; + } + + if (rect->flags & CANVAS_RECT_TRANSPOSE) { + dst_rect.size.x *= -1; // Encoding in the dst_rect.z uniform + } + + if (rect->flags & CANVAS_RECT_CLIP_UV) { + push_constant.flags |= FLAGS_CLIP_RECT_UV; + } + + } else { + dst_rect = Rect2(rect->rect.position, rect->rect.size); + + if (dst_rect.size.width < 0) { + dst_rect.position.x += dst_rect.size.width; + dst_rect.size.width *= -1; + } + if (dst_rect.size.height < 0) { + dst_rect.position.y += dst_rect.size.height; + dst_rect.size.height *= -1; + } + + src_rect = Rect2(0, 0, 1, 1); + texpixel_size = Vector2(1, 1); + } + + push_constant.modulation[0] = rect->modulate.r * p_modulate.r; + push_constant.modulation[1] = rect->modulate.g * p_modulate.g; + push_constant.modulation[2] = rect->modulate.b * p_modulate.b; + push_constant.modulation[3] = rect->modulate.a; + + push_constant.src_rect[0] = src_rect.position.x; + push_constant.src_rect[1] = src_rect.position.y; + push_constant.src_rect[2] = src_rect.size.width; + push_constant.src_rect[3] = src_rect.size.height; + + push_constant.dst_rect[0] = dst_rect.position.x; + push_constant.dst_rect[1] = dst_rect.position.y; + push_constant.dst_rect[2] = dst_rect.size.width; + push_constant.dst_rect[3] = dst_rect.size.height; + + 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_index_array(p_draw_list, shader.quad_index_array); + RD::get_singleton()->draw_list_draw(p_draw_list, true); + + } break; + + case Item::Command::TYPE_NINEPATCH: { + + const Item::CommandNinePatch *np = static_cast<const Item::CommandNinePatch *>(c); + + //bind pipeline + { + RID pipeline = pipeline_variants->variants[p_render_target_format][PIPELINE_VARIANT_NINEPATCH]; + RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline); + } + + //bind textures + + 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; + } + } + } + + Rect2 src_rect; + Rect2 dst_rect(np->rect.position.x, np->rect.position.y, np->rect.size.x, np->rect.size.y); + + if (texpixel_size == Size2()) { + + texpixel_size = Size2(1, 1); + src_rect = Rect2(0, 0, 1, 1); + + } else { + + if (np->source != Rect2()) { + src_rect = Rect2(np->source.position.x * texpixel_size.width, np->source.position.y * texpixel_size.height, np->source.size.x * texpixel_size.width, np->source.size.y * texpixel_size.height); + texpixel_size = Size2(1.0 / np->source.size.width, 1.0 / np->source.size.height); + } else { + src_rect = Rect2(0, 0, 1, 1); + } + } + + 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.src_rect[0] = src_rect.position.x; + push_constant.src_rect[1] = src_rect.position.y; + push_constant.src_rect[2] = src_rect.size.width; + push_constant.src_rect[3] = src_rect.size.height; + + push_constant.dst_rect[0] = dst_rect.position.x; + push_constant.dst_rect[1] = dst_rect.position.y; + push_constant.dst_rect[2] = dst_rect.size.width; + push_constant.dst_rect[3] = dst_rect.size.height; + + push_constant.color_texture_pixel_size[0] = texpixel_size.x; + push_constant.color_texture_pixel_size[1] = texpixel_size.y; + + push_constant.ninepatch_repeat = int(np->axis_x) << 16; + push_constant.ninepatch_repeat |= int(np->axis_y); + + if (np->draw_center) { + push_constant.flags |= FLAGS_NINEPACH_DRAW_CENTER; + } + + push_constant.ninepatch_margins[0] = np->margin[MARGIN_LEFT]; + push_constant.ninepatch_margins[1] = np->margin[MARGIN_TOP]; + push_constant.ninepatch_margins[2] = np->margin[MARGIN_RIGHT]; + push_constant.ninepatch_margins[3] = np->margin[MARGIN_BOTTOM]; + + 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, shader.quad_index_array); + RD::get_singleton()->draw_list_draw(p_draw_list, true); + + } break; +#if 0 +case Item::Command::TYPE_PRIMITIVE : { + + Item::CommandPrimitive *primitive = static_cast<Item::CommandPrimitive *>(c); + _set_texture_rect_mode(false); + + ERR_CONTINUE(primitive->points.size() < 1); + + RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(primitive->texture, primitive->normal_map); + + if (texture) { + Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); + state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); + } + 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); + + } else if (primitive->colors.empty()) { + glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); + } + + _draw_gui_primitive(primitive->points.size(), primitive->points.ptr(), primitive->colors.ptr(), primitive->uvs.ptr()); + + } break; + case Item::Command::TYPE_POLYGON: { + + Item::CommandPolygon *polygon = static_cast<Item::CommandPolygon *>(c); + _set_texture_rect_mode(false); + + RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(polygon->texture, polygon->normal_map); + + if (texture) { + Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); + state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); + } + + _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); + } +#endif + + } break; + case Item::Command::TYPE_MESH: { + + Item::CommandMesh *mesh = static_cast<Item::CommandMesh *>(c); + _set_texture_rect_mode(false); + + RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(mesh->texture, mesh->normal_map); + + if (texture) { + Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); + state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); + } + + state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * mesh->transform); + + RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.getornull(mesh->mesh); + if (mesh_data) { + + for (int j = 0; j < mesh_data->surfaces.size(); j++) { + RasterizerStorageGLES3::Surface *s = mesh_data->surfaces[j]; + // materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing + glBindVertexArray(s->array_id); + + glVertexAttrib4f(VS::ARRAY_COLOR, mesh->modulate.r, mesh->modulate.g, mesh->modulate.b, mesh->modulate.a); + + if (s->index_array_len) { + glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0); + } else { + glDrawArrays(gl_primitive[s->primitive], 0, s->array_len); + } + + glBindVertexArray(0); + } + } + state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform); + + } break; + case Item::Command::TYPE_MULTIMESH: { + + Item::CommandMultiMesh *mmesh = static_cast<Item::CommandMultiMesh *>(c); + + RasterizerStorageGLES3::MultiMesh *multi_mesh = storage->multimesh_owner.getornull(mmesh->multimesh); + + if (!multi_mesh) + break; + + RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.getornull(multi_mesh->mesh); + + if (!mesh_data) + break; + + RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(mmesh->texture, mmesh->normal_map); + + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, multi_mesh->custom_data_format != VS::MULTIMESH_CUSTOM_DATA_NONE); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, true); + //reset shader and force rebind + state.using_texture_rect = true; + _set_texture_rect_mode(false); + + if (texture) { + Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); + state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); + } + + int amount = MIN(multi_mesh->size, multi_mesh->visible_instances); + + if (amount == -1) { + amount = multi_mesh->size; + } + + for (int j = 0; j < mesh_data->surfaces.size(); j++) { + RasterizerStorageGLES3::Surface *s = mesh_data->surfaces[j]; + // materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing + glBindVertexArray(s->instancing_array_id); + + glBindBuffer(GL_ARRAY_BUFFER, multi_mesh->buffer); //modify the buffer + + int stride = (multi_mesh->xform_floats + multi_mesh->color_floats + multi_mesh->custom_data_floats) * 4; + glEnableVertexAttribArray(8); + glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(0)); + glVertexAttribDivisor(8, 1); + glEnableVertexAttribArray(9); + glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(4 * 4)); + glVertexAttribDivisor(9, 1); + + int color_ofs; + + if (multi_mesh->transform_format == VS::MULTIMESH_TRANSFORM_3D) { + glEnableVertexAttribArray(10); + glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(8 * 4)); + glVertexAttribDivisor(10, 1); + color_ofs = 12 * 4; + } else { + glDisableVertexAttribArray(10); + glVertexAttrib4f(10, 0, 0, 1, 0); + color_ofs = 8 * 4; + } + + int custom_data_ofs = color_ofs; + + switch (multi_mesh->color_format) { + + case VS::MULTIMESH_COLOR_NONE: { + glDisableVertexAttribArray(11); + glVertexAttrib4f(11, 1, 1, 1, 1); + } break; + case VS::MULTIMESH_COLOR_8BIT: { + glEnableVertexAttribArray(11); + glVertexAttribPointer(11, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs)); + glVertexAttribDivisor(11, 1); + custom_data_ofs += 4; + + } break; + case VS::MULTIMESH_COLOR_FLOAT: { + glEnableVertexAttribArray(11); + glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs)); + glVertexAttribDivisor(11, 1); + custom_data_ofs += 4 * 4; + } break; + } + + switch (multi_mesh->custom_data_format) { + + case VS::MULTIMESH_CUSTOM_DATA_NONE: { + glDisableVertexAttribArray(12); + glVertexAttrib4f(12, 1, 1, 1, 1); + } break; + case VS::MULTIMESH_CUSTOM_DATA_8BIT: { + glEnableVertexAttribArray(12); + glVertexAttribPointer(12, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(custom_data_ofs)); + glVertexAttribDivisor(12, 1); + + } break; + case VS::MULTIMESH_CUSTOM_DATA_FLOAT: { + glEnableVertexAttribArray(12); + glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(custom_data_ofs)); + glVertexAttribDivisor(12, 1); + } break; + } + + if (s->index_array_len) { + glDrawElementsInstanced(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0, amount); + } else { + glDrawArraysInstanced(gl_primitive[s->primitive], 0, s->array_len, amount); + } + + glBindVertexArray(0); + } + + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false); + state.using_texture_rect = true; + _set_texture_rect_mode(false); + + } break; + case Item::Command::TYPE_PARTICLES: { + + Item::CommandParticles *particles_cmd = static_cast<Item::CommandParticles *>(c); + + RasterizerStorageGLES3::Particles *particles = storage->particles_owner.getornull(particles_cmd->particles); + if (!particles) + break; + + if (particles->inactive && !particles->emitting) + break; + + glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); //not used, so keep white + + VisualServerRaster::redraw_request(); + + storage->particles_request_process(particles_cmd->particles); + //enable instancing + + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, true); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, true); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, true); + //reset shader and force rebind + state.using_texture_rect = true; + _set_texture_rect_mode(false); + + RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(particles_cmd->texture, particles_cmd->normal_map); + + if (texture) { + Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); + state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); + } else { + state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, Vector2(1.0, 1.0)); + } + + if (!particles->use_local_coords) { + + Transform2D inv_xf; + inv_xf.set_axis(0, Vector2(particles->emission_transform.basis.get_axis(0).x, particles->emission_transform.basis.get_axis(0).y)); + inv_xf.set_axis(1, Vector2(particles->emission_transform.basis.get_axis(1).x, particles->emission_transform.basis.get_axis(1).y)); + inv_xf.set_origin(Vector2(particles->emission_transform.get_origin().x, particles->emission_transform.get_origin().y)); + inv_xf.affine_invert(); + + state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * inv_xf); + } + + glBindVertexArray(data.particle_quad_array); //use particle quad array + glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); //bind particle buffer + + int stride = sizeof(float) * 4 * 6; + + int amount = particles->amount; + + if (particles->draw_order != VS::PARTICLES_DRAW_ORDER_LIFETIME) { + + glEnableVertexAttribArray(8); //xform x + glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3)); + glVertexAttribDivisor(8, 1); + glEnableVertexAttribArray(9); //xform y + glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 4)); + glVertexAttribDivisor(9, 1); + glEnableVertexAttribArray(10); //xform z + glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 5)); + glVertexAttribDivisor(10, 1); + glEnableVertexAttribArray(11); //color + glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, NULL); + glVertexAttribDivisor(11, 1); + glEnableVertexAttribArray(12); //custom + glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 2)); + glVertexAttribDivisor(12, 1); + + glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, amount); + } else { + //split + int split = int(Math::ceil(particles->phase * particles->amount)); + + if (amount - split > 0) { + glEnableVertexAttribArray(8); //xform x + glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 3)); + glVertexAttribDivisor(8, 1); + glEnableVertexAttribArray(9); //xform y + glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 4)); + glVertexAttribDivisor(9, 1); + glEnableVertexAttribArray(10); //xform z + glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 5)); + glVertexAttribDivisor(10, 1); + glEnableVertexAttribArray(11); //color + glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + 0)); + glVertexAttribDivisor(11, 1); + glEnableVertexAttribArray(12); //custom + glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 2)); + glVertexAttribDivisor(12, 1); + + glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, amount - split); + } + + if (split > 0) { + glEnableVertexAttribArray(8); //xform x + glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3)); + glVertexAttribDivisor(8, 1); + glEnableVertexAttribArray(9); //xform y + glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 4)); + glVertexAttribDivisor(9, 1); + glEnableVertexAttribArray(10); //xform z + glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 5)); + glVertexAttribDivisor(10, 1); + glEnableVertexAttribArray(11); //color + glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, NULL); + glVertexAttribDivisor(11, 1); + glEnableVertexAttribArray(12); //custom + glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 2)); + glVertexAttribDivisor(12, 1); + + glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, split); + } + } + + glBindVertexArray(0); + + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false); + state.using_texture_rect = true; + _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; + 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); + + } break; + case Item::Command::TYPE_CLIP_IGNORE: { + + Item::CommandClipIgnore *ci = static_cast<Item::CommandClipIgnore *>(c); + if (current_clip) { + + if (ci->ignore != reclip) { + if (ci->ignore) { + + glDisable(GL_SCISSOR_TEST); + 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); + + reclip = false; + } + } + } + + } break; +#endif + } + } +} + +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) { + + Item *current_clip = NULL; + + RenderTargetFormat render_target_format = RENDER_TARGET_FORMAT_8_BIT_INT; + Transform2D canvas_transform_inverse = p_transform.affine_inverse(); + + 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); + } + + 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::get_singleton()->draw_list_bind_uniform_set(draw_list, state.canvas_state_uniform_set, 3); + + for (int i = 0; i < p_item_count; i++) { + + Item *ci = items[i]; + + if (current_clip != ci->final_clip_owner) { + + current_clip = ci->final_clip_owner; + + //setup clip + if (current_clip) { + + RD::get_singleton()->draw_list_enable_scissor(draw_list, current_clip->final_clip_rect); + + } else { + + RD::get_singleton()->draw_list_disable_scissor(draw_list); + } + } + + if (true) { //not skeleton + + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, shader.default_material_uniform_set, 1); + } + + _render_item(draw_list, ci, render_target_format, p_modulate, canvas_transform_inverse); + } + + RD::get_singleton()->draw_list_end(); +} + +void RasterizerCanvasRD::_update_canvas_state_uniform_set() { + + if (state.canvas_state_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(state.canvas_state_uniform_set)) { + return; //nothing to update + } + + Vector<RD::Uniform> uniforms; + + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 0; + u.ids.push_back(state.canvas_state_buffer); + uniforms.push_back(u); + + 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) { + + int item_count = 0; + + //setup canvas state uniforms if needed + _update_canvas_state_uniform_set(); + + { + //update canvas state uniform buffer + State::Buffer state_buffer; + + Size2i ssize = storage->render_target_get_size(p_to_render_target); + + Transform screen_transform; + screen_transform.translate(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f); + screen_transform.scale(Vector3(2.0f / ssize.width, 2.0f / ssize.height, 1.0f)); + _update_transform_to_mat4(screen_transform, state_buffer.screen_transform); + _update_transform_2d_to_mat4(p_canvas_transform, state_buffer.canvas_transform); + RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer, true); + } + + //fill the list until rendering is possible. + Item *ci = p_item_list; + while (ci) { + + items[item_count++] = ci; + + 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); + //then reset + item_count = 0; + p_clear = false; + } + + if (ci->copy_back_buffer) { + + if (ci->copy_back_buffer->full) { + + //_copy_texscreen(Rect2()); + } else { + //_copy_texscreen(ci->copy_back_buffer->rect); + } + } + + ci = ci->next; + } +} + +void RasterizerCanvasRD::update() { + _dispose_bindings(); +} + +RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { + storage = p_storage; + + { //create default textures + + RD::TextureFormat tformat; + tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + tformat.width = 4; + tformat.height = 4; + tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; + tformat.type = RD::TEXTURE_TYPE_2D; + + PoolVector<uint8_t> pv; + pv.resize(16 * 4); + for (int i = 0; i < 16; i++) { + pv.set(i * 4 + 0, 255); + pv.set(i * 4 + 1, 255); + pv.set(i * 4 + 2, 255); + pv.set(i * 4 + 3, 255); + } + + { + Vector<PoolVector<uint8_t> > vpv; + vpv.push_back(pv); + default_textures.white_texture = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); + } + + for (int i = 0; i < 16; i++) { + pv.set(i * 4 + 0, 0); + pv.set(i * 4 + 1, 0); + pv.set(i * 4 + 2, 0); + pv.set(i * 4 + 3, 255); + } + + { + Vector<PoolVector<uint8_t> > vpv; + vpv.push_back(pv); + default_textures.black_texture = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); + } + + for (int i = 0; i < 16; i++) { + pv.set(i * 4 + 0, 128); + pv.set(i * 4 + 1, 128); + pv.set(i * 4 + 2, 255); + pv.set(i * 4 + 3, 255); + } + + { + Vector<PoolVector<uint8_t> > vpv; + vpv.push_back(pv); + default_textures.normal_texture = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); + } + + for (int i = 0; i < 16; i++) { + pv.set(i * 4 + 0, 255); + pv.set(i * 4 + 1, 128); + pv.set(i * 4 + 2, 255); + pv.set(i * 4 + 3, 255); + } + + { + Vector<PoolVector<uint8_t> > vpv; + vpv.push_back(pv); + default_textures.aniso_texture = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); + } + + for (int i = 0; i < 16; i++) { + pv.set(i * 4 + 0, 0); + pv.set(i * 4 + 1, 0); + pv.set(i * 4 + 2, 0); + pv.set(i * 4 + 3, 0); + } + + default_textures.default_multimesh_tb = RD::get_singleton()->texture_buffer_create(16, RD::DATA_FORMAT_R8G8B8A8_UNORM, pv); + } + + { //create default 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::SamplerState sampler_state; + switch (i) { + case VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: { + sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST; + sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST; + sampler_state.max_lod = 0; + } break; + case VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR: { + + sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.max_lod = 0; + } break; + case VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: { + sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR; + + } break; + case VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS: { + sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST; + sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR; + } break; + default: { + } + } + switch (j) { + case VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: { + + sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE; + sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE; + + } break; + case VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: { + sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT; + sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_REPEAT; + } break; + case VS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: { + sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + } break; + default: { + } + } + + default_samplers.samplers[i][j] = RD::get_singleton()->sampler_create(sampler_state); + } + } + + default_samplers.default_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR; + default_samplers.default_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; + } + + { //shader variants + 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 + shader.canvas_shader.initialize(variants); + + shader.default_version = shader.canvas_shader.version_create(); + + { + //framebuffer formats + RD::AttachmentFormat af; + af.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + af.samples = RD::TEXTURE_SAMPLES_1; + af.usage_flags = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + Vector<RD::AttachmentFormat> formats; + formats.push_back(af); + shader.framebuffer_formats[RENDER_TARGET_FORMAT_8_BIT_INT] = RD::get_singleton()->framebuffer_format_create(formats); + + formats.clear(); + af.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + formats.push_back(af); + shader.framebuffer_formats[RENDER_TARGET_FORMAT_16_BIT_FLOAT] = RD::get_singleton()->framebuffer_format_create(formats); + } + + 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 }; + + RID shader_variant = shader.canvas_shader.version_get_shader(shader.default_version, shader_variants[j]); + RID pipeline = RD::get_singleton()->render_pipeline_create(shader_variant, fb_format, RD::INVALID_ID, 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] = pipeline; + } + } + + shader.default_version_rd_shader = shader.canvas_shader.version_get_shader(shader.default_version, 0); + } + + { //bindings + bindings.id_generator = 0; + //generate for 0 + bindings.default_empty = request_texture_binding(RID(), RID(), RID(), VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, RID()); + + { //state allocate + state.canvas_state_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(State::Buffer)); + } + } + + { // default index buffer + + PoolVector<uint8_t> pv; + pv.resize(6 * 4); + { + PoolVector<uint8_t>::Write w = pv.write(); + int *p32 = (int *)w.ptr(); + p32[0] = 0; + p32[1] = 1; + p32[2] = 2; + p32[3] = 0; + 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); + } + + { //default skeleton buffer + + shader.default_material_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); + } + + { //default material uniform set + Vector<RD::Uniform> default_material_uniforms; + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 2; + u.ids.push_back(shader.default_material_skeleton_uniform); + default_material_uniforms.push_back(u); + + u.ids.clear(); + u.type = RD::UNIFORM_TYPE_TEXTURE_BUFFER; + u.binding = 1; + 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); + } + + ERR_FAIL_COND(sizeof(PushConstant) != 128); +} diff --git a/servers/visual/rasterizer/rasterizer_canvas_rd.h b/servers/visual/rasterizer/rasterizer_canvas_rd.h index 898fdb238a..1d4faf29ab 100644 --- a/servers/visual/rasterizer/rasterizer_canvas_rd.h +++ b/servers/visual/rasterizer/rasterizer_canvas_rd.h @@ -2,17 +2,218 @@ #define RASTERIZER_CANVAS_RD_H #include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer/rasterizer_storage_rd.h" +#include "servers/visual/rasterizer/shaders/canvas.glsl.gen.h" +#include "servers/visual/rendering_device.h" class RasterizerCanvasRD : public RasterizerCanvas { + + RasterizerStorageRD *storage; + + enum ShaderVariant { + SHADER_VARIANT_QUAD, + SHADER_VARIANT_NINEPATCH, + SHADER_VARIANT_VERTICES, + SHADER_VARIANT_POINTS, + SHADER_VARIANT_MAX + }; + + enum RenderTargetFormat { + RENDER_TARGET_FORMAT_8_BIT_INT, + RENDER_TARGET_FORMAT_16_BIT_FLOAT, + RENDER_TARGET_FORMAT_MAX + }; + + enum { + FLAGS_INSTANCING_STRIDE_MASK = 0xF, + FLAGS_INSTANCING_ENABLED = (1 << 4), + FLAGS_INSTANCING_HAS_COLORS = (1 << 5), + FLAGS_INSTANCING_COLOR_8BIT = (1 << 6), + FLAGS_INSTANCING_HAS_CUSTOM_DATA = (1 << 7), + FLAGS_INSTANCING_CUSTOM_DATA_8_BIT = (1 << 8), + + FLAGS_CLIP_RECT_UV = (1 << 9), + FLAGS_TRANSPOSE_RECT = (1 << 10), + FLAGS_NINEPACH_DRAW_CENTER = (1 << 12), + FLAGS_USING_PARTICLES = (1 << 13), + FLAGS_USE_PIXEL_SNAP = (1 << 14), + + FLAGS_USE_SKELETON = (1 << 16) + }; + + /****************/ + /**** SHADER ****/ + /****************/ + + enum PipelineVariant { + PIPELINE_VARIANT_QUAD, + PIPELINE_VARIANT_NINEPATCH, + PIPELINE_VARIANT_TRIANGLES, + PIPELINE_VARIANT_LINES, + PIPELINE_VARIANT_POINTS, + PIPELINE_VARIANT_TRIANGLES_COMPRESSED, + PIPELINE_VARIANT_LINES_COMPRESSED, + PIPELINE_VARIANT_POINTS_COMPRESSED, + PIPELINE_VARIANT_MAX + }; + struct PipelineVariants { + RID variants[RENDER_TARGET_FORMAT_MAX][PIPELINE_VARIANT_MAX]; + }; + + struct { + CanvasShaderRD canvas_shader; + RD::FramebufferFormatID framebuffer_formats[RENDER_TARGET_FORMAT_MAX]; + RID default_version; + RID default_version_rd_shader; + RID quad_index_array; + PipelineVariants pipeline_variants; + + // default_skeleton uniform set + RID default_material_skeleton_uniform; + RID default_material_uniform_set; + + } shader; + + /**************************/ + /**** TEXTURE BINDINGS ****/ + /**************************/ + + // bindings used to render commands, + // cached for performance. + + struct TextureBindingKey { + RID texture; + RID normalmap; + RID specular; + RID multimesh; + VS::CanvasItemTextureFilter texture_filter; + VS::CanvasItemTextureRepeat texture_repeat; + bool operator==(const TextureBindingKey &p_key) const { + return texture == p_key.texture && normalmap == p_key.normalmap && specular == p_key.specular && multimesh == p_key.specular && texture_filter == p_key.texture_filter && texture_repeat == p_key.texture_repeat; + } + }; + + struct TextureBindingKeyHasher { + static _FORCE_INLINE_ uint32_t hash(const TextureBindingKey &p_key) { + uint32_t hash = hash_djb2_one_64(p_key.texture.get_id()); + hash = hash_djb2_one_64(p_key.normalmap.get_id(), hash); + hash = hash_djb2_one_64(p_key.specular.get_id(), hash); + hash = hash_djb2_one_64(p_key.multimesh.get_id(), hash); + hash = hash_djb2_one_32(uint32_t(p_key.texture_filter) << 16 | uint32_t(p_key.texture_repeat), hash); + return hash; + } + }; + + struct TextureBinding { + TextureBindingID id; + TextureBindingKey key; + SelfList<TextureBinding> to_dispose; + uint32_t reference_count; + RID uniform_set; + TextureBinding() : + to_dispose(this) { + reference_count = 0; + } + }; + + struct { + SelfList<TextureBinding>::List to_dispose_list; + + TextureBindingID id_generator; + HashMap<TextureBindingKey, TextureBindingID, TextureBindingKeyHasher> texture_key_bindings; + HashMap<TextureBindingID, TextureBinding *> texture_bindings; + + TextureBindingID default_empty; + } bindings; + + void _dispose_bindings(); + struct { + RID white_texture; + RID black_texture; + RID normal_texture; + RID aniso_texture; + + RID default_multimesh_tb; + + } default_textures; + + struct { + RID samplers[VS::CANVAS_ITEM_TEXTURE_FILTER_MAX][VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX]; + VS::CanvasItemTextureFilter default_filter; + VS::CanvasItemTextureRepeat default_repeat; + } default_samplers; + + /*******************/ + /**** MATERIALS ****/ + /*******************/ + + /***************/ + /**** STATE ****/ + /***************/ + + //state that does not vary across rendering all items + + struct State { + + //state buffer + struct Buffer { + float canvas_transform[16]; + float screen_transform[16]; + //uint32_t light_count; + //uint32_t pad[3]; + }; + RID canvas_state_buffer; + //light buffer + RID canvas_state_light_buffer; + + //uniform set for all the above + RID canvas_state_uniform_set; + } state; + + struct PushConstant { + float world[8]; + float modulation[4]; + float ninepatch_margins[4]; + float dst_rect[4]; + float src_rect[4]; + uint32_t flags; + uint32_t ninepatch_repeat; + float color_texture_pixel_size[2]; + uint32_t specular_shininess; + uint32_t pad[3]; + }; + + struct SkeletonUniform { + float skeleton_transform[16]; + float skeleton_inverse[16]; + }; + + enum { + MAX_RENDER_ITEMS = 256 * 1024 + }; + + Item *items[MAX_RENDER_ITEMS]; + + void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderTargetFormat p_render_target_format, 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); + + void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4); + + 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); + + void _update_canvas_state_uniform_set(); + 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); + 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_begin(){}; - void canvas_end(){}; + 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(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_transform){}; void canvas_debug_viewport_shadows(Light *p_lights_with_shadow){}; void canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache) {} @@ -21,7 +222,8 @@ public: void draw_window_margins(int *p_margins, RID *p_margin_textures) {} - RasterizerCanvasRD() {} + void update(); + RasterizerCanvasRD(RasterizerStorageRD *p_storage); ~RasterizerCanvasRD() {} }; diff --git a/servers/visual/rasterizer/rasterizer_rd.cpp b/servers/visual/rasterizer/rasterizer_rd.cpp index ecbcc2b251..c740ce61ef 100644 --- a/servers/visual/rasterizer/rasterizer_rd.cpp +++ b/servers/visual/rasterizer/rasterizer_rd.cpp @@ -1,7 +1,127 @@ #include "rasterizer_rd.h" -RasterizerRD::RasterizerRD() { - canvas = memnew(RasterizerCanvasRD); +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); + for (int i = 0; i < p_amount; i++) { + RID texture = storage->render_target_get_texture(p_render_targets[i].render_target); + ERR_CONTINUE(texture.is_null()); + RID rd_texture = storage->texture_get_rd_texture(texture); + ERR_CONTINUE(rd_texture.is_null()); + if (!render_target_descriptors.has(rd_texture) || !RD::get_singleton()->uniform_set_is_valid(render_target_descriptors[rd_texture])) { + Vector<RD::Uniform> uniforms; + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.binding = 0; + u.ids.push_back(copy_viewports_sampler); + u.ids.push_back(rd_texture); + RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, copy_viewports_rd_shader, 0); + + render_target_descriptors[rd_texture] = uniform_set; + } + + Size2 screen_size(RD::get_singleton()->screen_get_width(p_screen), RD::get_singleton()->screen_get_height(p_screen)); + + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_viewports_rd_pipeline); + RD::get_singleton()->draw_list_bind_index_array(draw_list, copy_viewports_rd_array); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_target_descriptors[rd_texture], 0); + + float push_constant[4] = { + p_render_targets[i].rect.position.x / screen_size.width, + p_render_targets[i].rect.position.y / screen_size.height, + p_render_targets[i].rect.size.width / screen_size.width, + p_render_targets[i].rect.size.height / screen_size.height, + }; + RD::get_singleton()->draw_list_set_push_constant(draw_list, push_constant, 4 * sizeof(float)); + RD::get_singleton()->draw_list_draw(draw_list, true); + } +} + +void RasterizerRD::begin_frame(double frame_step) { +} + +void RasterizerRD::end_frame(bool p_swap_buffers) { + RD::get_singleton()->finalize_frame(); +#warning not swapping buffers likely not an option for now, find another way + OS::get_singleton()->swap_buffers(); //probably should pass some bool to avoid display? + RD::get_singleton()->advance_frame(); //advance frame here, so any new call happens on new frame +} + +void RasterizerRD::initialize() { storage = memnew(RasterizerStorageRD); + canvas = memnew(RasterizerCanvasRD(storage)); scene = memnew(RasterizerSceneForwardRD); + + { //create framebuffer copy shader + RenderingDevice::ShaderStageSource vert; + vert.shader_stage = RenderingDevice::SHADER_STAGE_VERTEX; + vert.shader_source = + "#version 450\n" + "layout(push_constant, binding = 0, std140) uniform Pos { vec4 dst_rect; } pos;\n" + "layout(location =0) out vec2 uv;\n" + "void main() { \n" + " vec2 base_arr[4] = float[](vec2(0.0,0.0),vec2(0.0,1.0),vec2(1.0,1.0),vec2(1.0,0.0));\n" + " uv = base_arr[gl_VertexIndex];\n" + " gl_Position = vec4(dst_rect.xy,uv*dst_rect.zw);\n" + "}\n"; + + RenderingDevice::ShaderStageSource frag; + frag.shader_stage = RenderingDevice::SHADER_STAGE_FRAGMENT; + frag.shader_source = + "#version 450\n" + "layout (location = 0) in vec2 uv;\n" + "layout (location = 0) out vec4 color;\n" + "layout (binding = 0) uniform sampler2D src_rt;\n" + "void main() { color=texture(src_rt,uv); }\n"; + + Vector<RenderingDevice::ShaderStageSource> source; + source.push_back(vert); + source.push_back(frag); + String error; + copy_viewports_rd_shader = RD::get_singleton()->shader_create_from_source(source, &error); + if (!copy_viewports_rd_shader.is_valid()) { + print_line("failed compilation: " + error); + } else { + print_line("compilation success"); + } + } + + { //create index array for copy shader + PoolVector<uint8_t> pv; + pv.resize(6 * 4); + { + PoolVector<uint8_t>::Write w = pv.write(); + int *p32 = (int *)w.ptr(); + p32[0] = 0; + p32[1] = 1; + p32[2] = 2; + p32[3] = 0; + p32[4] = 2; + p32[5] = 3; + } + copy_viewports_rd_index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv); + copy_viewports_rd_array = RD::get_singleton()->index_array_create(copy_viewports_rd_index_buffer, 0, 6); + } + + { //pipeline + copy_viewports_rd_pipeline = RD::get_singleton()->render_pipeline_create(copy_viewports_rd_shader, RD::get_singleton()->screen_get_framebuffer_format(), RD::INVALID_ID, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RenderingDevice::PipelineColorBlendState::create_disabled(), 0); + } + { // sampler + copy_viewports_sampler = RD::get_singleton()->sampler_create(RD::SamplerState()); + } +} + +void RasterizerRD::finalize() { + + memdelete(scene); + memdelete(canvas); + memdelete(storage); + + //only need to erase these, the rest are erased by cascade + RD::get_singleton()->free(copy_viewports_rd_index_buffer); + RD::get_singleton()->free(copy_viewports_rd_shader); + RD::get_singleton()->free(copy_viewports_sampler); +} + +RasterizerRD::RasterizerRD() { } diff --git a/servers/visual/rasterizer/rasterizer_rd.h b/servers/visual/rasterizer/rasterizer_rd.h index 17ff29c19b..fb5945fa4d 100644 --- a/servers/visual/rasterizer/rasterizer_rd.h +++ b/servers/visual/rasterizer/rasterizer_rd.h @@ -12,6 +12,14 @@ protected: RasterizerStorageRD *storage; RasterizerSceneForwardRD *scene; + RID copy_viewports_rd_shader; + RID copy_viewports_rd_pipeline; + RID copy_viewports_rd_index_buffer; + RID copy_viewports_rd_array; + RID copy_viewports_sampler; + + Map<RID, RID> render_target_descriptors; + public: RasterizerStorage *get_storage() { return storage; } RasterizerCanvas *get_canvas() { return canvas; } @@ -19,15 +27,12 @@ public: void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) {} - void initialize() {} - void begin_frame(double frame_step) {} - void set_current_render_target(RID p_render_target) {} - void restore_render_target(bool p_3d_was_drawn) {} - void clear_render_target(const Color &p_color) {} - void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0) {} - void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) {} - void end_frame(bool p_swap_buffers) { OS::get_singleton()->swap_buffers(); } - void finalize() {} + void initialize(); + void begin_frame(double frame_step); + void blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount); + + void end_frame(bool p_swap_buffers); + void finalize(); static Error is_viable() { return OK; diff --git a/servers/visual/rasterizer/rasterizer_storage_rd.cpp b/servers/visual/rasterizer/rasterizer_storage_rd.cpp index bdaaba8d10..010bdc88ae 100644 --- a/servers/visual/rasterizer/rasterizer_storage_rd.cpp +++ b/servers/visual/rasterizer/rasterizer_storage_rd.cpp @@ -1,8 +1,539 @@ #include "rasterizer_storage_rd.h" +Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format) { + + Ref<Image> image = p_image->duplicate(); + + switch (p_image->get_format()) { + case Image::FORMAT_L8: { + r_format.format = RD::DATA_FORMAT_R8_UNORM; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; //luminance + case Image::FORMAT_LA8: { + r_format.format = RD::DATA_FORMAT_R8G8_UNORM; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_G; + } break; //luminance-alpha + case Image::FORMAT_R8: { + r_format.format = RD::DATA_FORMAT_R8_UNORM; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case Image::FORMAT_RG8: { + r_format.format = RD::DATA_FORMAT_R8G8_UNORM; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case Image::FORMAT_RGB8: { + //this format is not mandatory for specification, check if supported first + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R8G8B8_UNORM, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT) && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R8G8B8_SRGB, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_R8G8B8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8_SRGB; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + + } break; + case Image::FORMAT_RGBA8: { + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; + case Image::FORMAT_RGBA4444: { + r_format.format = RD::DATA_FORMAT_B4G4R4A4_UNORM_PACK16; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_B; //needs swizzle + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; + case Image::FORMAT_RGBA5551: { + r_format.format = RD::DATA_FORMAT_A1R5G5B5_UNORM_PACK16; +#warning TODO needs something in Texture to convert to this format internally + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; + case Image::FORMAT_RF: { + r_format.format = RD::DATA_FORMAT_R32_SFLOAT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; //float + case Image::FORMAT_RGF: { + r_format.format = RD::DATA_FORMAT_R32G32_SFLOAT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case Image::FORMAT_RGBF: { + //this format is not mandatory for specification, check if supported first + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R32G32B32_SFLOAT, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_R32G32B32_SFLOAT; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + image->convert(Image::FORMAT_RGBAF); + } + + r_format.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case Image::FORMAT_RGBAF: { + r_format.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + + } break; + case Image::FORMAT_RH: { + r_format.format = RD::DATA_FORMAT_R16_SFLOAT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + + } break; //half float + case Image::FORMAT_RGH: { + r_format.format = RD::DATA_FORMAT_R16G16_SFLOAT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + + } break; + case Image::FORMAT_RGBH: { + //this format is not mandatory for specification, check if supported first + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R16G16B16_SFLOAT, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_R16G16B16_SFLOAT; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + image->convert(Image::FORMAT_RGBAH); + } + + r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case Image::FORMAT_RGBAH: { + r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + + } break; + case Image::FORMAT_RGBE9995: { + r_format.format = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32; +#warning TODO need to make a function in Image to swap bits for this + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_IDENTITY; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_IDENTITY; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_IDENTITY; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_IDENTITY; + } break; + case Image::FORMAT_DXT1: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC1_RGB_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_BC1_RGB_UNORM_BLOCK; + r_format.format_srgb = RD::DATA_FORMAT_BC1_RGBA_SRGB_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + + } break; //s3tc bc1 + case Image::FORMAT_DXT3: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC2_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_BC2_UNORM_BLOCK; + r_format.format_srgb = RD::DATA_FORMAT_BC2_SRGB_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + + } break; //bc2 + case Image::FORMAT_DXT5: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC3_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_BC3_UNORM_BLOCK; + r_format.format_srgb = RD::DATA_FORMAT_BC3_SRGB_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; //bc3 + case Image::FORMAT_RGTC_R: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC4_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_BC4_UNORM_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8_UNORM; + image->decompress(); + image->convert(Image::FORMAT_R8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + + } break; + case Image::FORMAT_RGTC_RG: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC5_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_BC5_UNORM_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8_UNORM; + image->decompress(); + image->convert(Image::FORMAT_RG8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + + } break; + case Image::FORMAT_BPTC_RGBA: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC7_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_BC7_UNORM_BLOCK; + r_format.format_srgb = RD::DATA_FORMAT_BC7_SRGB_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + + } break; //btpc bc7 + case Image::FORMAT_BPTC_RGBF: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC6H_SFLOAT_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_BC6H_SFLOAT_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + image->decompress(); + image->convert(Image::FORMAT_RGBAH); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; //float bc6h + case Image::FORMAT_BPTC_RGBFU: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC6H_UFLOAT_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_BC6H_UFLOAT_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + image->decompress(); + image->convert(Image::FORMAT_RGBAH); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; //unsigned float bc6hu + case Image::FORMAT_PVRTC2: { + //this is not properly supported by MoltekVK it seems, so best to use ETC2 + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG; + r_format.format_srgb = RD::DATA_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + + } break; //pvrtc + case Image::FORMAT_PVRTC2A: { + //this is not properly supported by MoltekVK it seems, so best to use ETC2 + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG; + r_format.format_srgb = RD::DATA_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; + case Image::FORMAT_PVRTC4: { + //this is not properly supported by MoltekVK it seems, so best to use ETC2 + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; + r_format.format_srgb = RD::DATA_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case Image::FORMAT_PVRTC4A: { + //this is not properly supported by MoltekVK it seems, so best to use ETC2 + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; + r_format.format_srgb = RD::DATA_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; + case Image::FORMAT_ETC2_R11: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_EAC_R11_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_EAC_R11_UNORM_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8_UNORM; + image->decompress(); + image->convert(Image::FORMAT_R8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + + } break; //etc2 + case Image::FORMAT_ETC2_R11S: { + + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_EAC_R11_SNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_EAC_R11_SNORM_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8_SNORM; + image->decompress(); + image->convert(Image::FORMAT_R8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; //signed: {} break; NOT srgb. + case Image::FORMAT_ETC2_RG11: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_EAC_R11G11_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_EAC_R11G11_UNORM_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8_UNORM; + image->decompress(); + image->convert(Image::FORMAT_RG8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case Image::FORMAT_ETC2_RG11S: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_EAC_R11G11_SNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_EAC_R11G11_SNORM_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8_SNORM; + image->decompress(); + image->convert(Image::FORMAT_RG8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case Image::FORMAT_ETC: + case Image::FORMAT_ETC2_RGB8: { + //ETC2 is backwards compatible with ETC1, and all modern platforms support it + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; + r_format.format_srgb = RD::DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + + } break; + case Image::FORMAT_ETC2_RGBA8: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK; + r_format.format_srgb = RD::DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; + case Image::FORMAT_ETC2_RGB8A1: { + + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK; + r_format.format_srgb = RD::DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; + default: { + } + } + + return image; +} + RID RasterizerStorageRD::texture_2d_create(const Ref<Image> &p_image) { + ERR_FAIL_COND_V(p_image.is_null(), RID()); + ERR_FAIL_COND_V(p_image->empty(), RID()); - return RID(); + TextureToRDFormat ret_format; + Ref<Image> image = _validate_texture_format(p_image, ret_format); + + Texture texture; + + texture.type = Texture::TYPE_2D; + + texture.width = p_image->get_width(); + texture.height = p_image->get_height(); + texture.layers = 1; + texture.mipmaps = p_image->get_mipmap_count(); + texture.depth = 1; + + texture.rd_type = RD::TEXTURE_TYPE_2D; + texture.rd_format = ret_format.format; + texture.rd_format_srgb = ret_format.format_srgb; + + RD::TextureFormat rd_format; + RD::TextureView rd_view; + { //attempt register + rd_format.format = texture.rd_format; + rd_format.width = texture.width; + rd_format.height = texture.height; + rd_format.depth = 1; + rd_format.array_layers = 1; + rd_format.mipmaps = texture.mipmaps; + rd_format.type = texture.rd_type; + rd_format.samples = RD::TEXTURE_SAMPLES_1; + rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; + } + { + rd_view.swizzle_r = ret_format.swizzle_r; + rd_view.swizzle_g = ret_format.swizzle_g; + rd_view.swizzle_b = ret_format.swizzle_b; + rd_view.swizzle_a = ret_format.swizzle_a; + } + PoolVector<uint8_t> data = image->get_data(); //use image data + Vector<PoolVector<uint8_t> > data_slices; + data_slices.push_back(data); + texture.rd_texture = RD::get_singleton()->texture_create(rd_format, rd_view, data_slices); + ERR_FAIL_COND_V(texture.rd_texture.is_null(), RID()); + if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) { + rd_view.format_override = texture.rd_format_srgb; + texture.rd_texture_srgb = RD::get_singleton()->texture_create_shared(rd_view, texture.rd_texture); + if (texture.rd_texture_srgb.is_null()) { + RD::get_singleton()->free(texture.rd_texture); + ERR_FAIL_COND_V(texture.rd_texture_srgb.is_null(), RID()); + } + } + + //used for 2D, overridable + texture.width_2d = texture.width; + texture.height_2d = texture.height; + texture.is_render_target = false; + +#warning TODO this is temporary to get things to work + texture.image_cache_2d = p_image; + +#warning texture owner needs a spinlock to make this really callable from any thread + return texture_owner.make_rid(texture); } RID RasterizerStorageRD::texture_2d_layered_create(const Vector<Ref<Image> > &p_layers, VS::TextureLayeredType p_layered_type) { @@ -14,9 +545,34 @@ RID RasterizerStorageRD::texture_3d_create(const Vector<Ref<Image> > &p_slices) 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()); + + Texture *tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND(!tex); + ERR_FAIL_COND(tex->is_render_target); + ERR_FAIL_COND(p_image->get_width() != tex->width || p_image->get_height() != tex->height); + ERR_FAIL_COND(p_image->get_format() != tex->format); + + if (tex->type == Texture::TYPE_LAYERED) { + ERR_FAIL_INDEX(p_layer, tex->layers); + } + +#warning TODO this is temporary to get things to work + tex->image_cache_2d = p_image; + + TextureToRDFormat f; + Ref<Image> validated = _validate_texture_format(p_image, f); + + RD::get_singleton()->texture_update(tex->rd_texture, p_layer, validated->get_data(), !p_immediate); +} + void RasterizerStorageRD::texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer) { + _texture_2d_update(p_texture, p_image, p_layer, true); } void RasterizerStorageRD::texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer) { + _texture_2d_update(p_texture, p_image, p_layer, false); } void RasterizerStorageRD::texture_3d_update(RID p_texture, const Ref<Image> &p_image, int p_depth, int p_mipmap) { } @@ -24,7 +580,20 @@ void RasterizerStorageRD::texture_3d_update(RID p_texture, const Ref<Image> &p_i //these two APIs can be used together or in combination with the others. RID RasterizerStorageRD::texture_2d_placeholder_create() { - return RID(); + //this could be better optimized to reuse an existing image , done this way + //for now to get it working + Ref<Image> image; + image.instance(); + image->create(4, 4, false, Image::FORMAT_RGBA8); + image->lock(); + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + image->set_pixel(i, j, Color(1, 0, 1, 1)); + } + } + image->unlock(); + + return texture_2d_create(image); } RID RasterizerStorageRD::texture_2d_layered_placeholder_create() { @@ -37,7 +606,11 @@ RID RasterizerStorageRD::texture_3d_placeholder_create() { Ref<Image> RasterizerStorageRD::texture_2d_get(RID p_texture) const { - return Ref<Image>(); + Texture *tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND_V(!tex, Ref<Image>()); + +#warning TODO this is temporary to get things to work + return tex->image_cache_2d; } Ref<Image> RasterizerStorageRD::texture_2d_layer_get(RID p_texture, int p_layer) const { @@ -49,8 +622,31 @@ Ref<Image> RasterizerStorageRD::texture_3d_slice_get(RID p_texture, int p_depth, } void RasterizerStorageRD::texture_replace(RID p_texture, RID p_by_texture) { + + Texture *tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND(!tex); + Texture *by_tex = texture_owner.getornull(p_by_texture); + ERR_FAIL_COND(!by_tex); + + 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); + } + + *tex = *by_tex; + + texture_owner.free(p_by_texture); } void RasterizerStorageRD::texture_set_size_override(RID p_texture, int p_width, int p_height) { + Texture *tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND(!tex); + ERR_FAIL_COND(tex->type != Texture::TYPE_2D); + tex->width_2d = p_width; + tex->height_2d = p_width; } void RasterizerStorageRD::texture_set_path(RID p_texture, const String &p_path) { @@ -76,3 +672,219 @@ void RasterizerStorageRD::texture_set_force_redraw_if_visible(RID p_texture, boo Size2 RasterizerStorageRD::texture_size_with_proxy(RID p_proxy) const { return Size2(); } + +/* RENDER TARGET API */ + +void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) { + + //free in reverse dependency order + 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); + } + + rt->framebuffer = RID(); + rt->color = RID(); + rt->color_srgb = RID(); + + rt->dirty = true; + rt->texture_dirty = true; +} + +void RasterizerStorageRD::_update_render_target(RenderTarget *rt) { + + _clear_render_target(rt); + + //until we implement suport for HDR monitors (and render target is attached to screen), this is enough. + rt->color_format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + rt->color_format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + rt->image_format = rt->flags[RENDER_TARGET_TRANSPARENT] ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8; + + RD::TextureFormat rd_format; + RD::TextureView rd_view; + { //attempt register + rd_format.format = rt->color_format; + rd_format.width = rt->size.width; + rd_format.height = rt->size.height; + rd_format.depth = 1; + rd_format.array_layers = 1; + rd_format.mipmaps = 1; + rd_format.type = RD::TEXTURE_TYPE_2D; + rd_format.samples = RD::TEXTURE_SAMPLES_1; + rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + } + { + rd_view.swizzle_r = RD::TEXTURE_SWIZZLE_R; + rd_view.swizzle_g = RD::TEXTURE_SWIZZLE_R; + rd_view.swizzle_b = RD::TEXTURE_SWIZZLE_R; + rd_view.swizzle_a = rt->flags[RENDER_TARGET_TRANSPARENT] ? RD::TEXTURE_SWIZZLE_A : RD::TEXTURE_SWIZZLE_ONE; + } + + 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); + rt->framebuffer = RD::get_singleton()->framebuffer_create(fb_textures); + if (rt->framebuffer.is_null()) { + _clear_render_target(rt); + ERR_FAIL_COND(rt->framebuffer.is_null()); + } +} + +RID RasterizerStorageRD::render_target_create() { + RenderTarget render_target; + render_target.dirty = true; + render_target.texture_dirty = true; + render_target.was_used = false; + + for (int i = 0; i < RENDER_TARGET_FLAG_MAX; i++) { + render_target.flags[i] = false; + } + return render_target_owner.make_rid(render_target); +} + +void RasterizerStorageRD::render_target_set_position(RID p_render_target, int p_x, int p_y) { + //unused for this render target +} + +void RasterizerStorageRD::render_target_set_size(RID p_render_target, int p_width, int p_height) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + 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; + } + + return rt->texture; +} + +void RasterizerStorageRD::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) { +} + +void RasterizerStorageRD::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + 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) { + + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, false); + return rt->was_used; +} + +void RasterizerStorageRD::render_target_clear_used_flag(RID p_render_target) { + + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + rt->was_used = false; +} + +Size2 RasterizerStorageRD::render_target_get_size(RID p_render_target) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, Size2()); + + return rt->size; +} + +RID RasterizerStorageRD::render_target_get_rd_framebuffer(RID p_render_target) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, RID()); + + if (rt->dirty) { + _update_render_target(rt); + } + + return rt->framebuffer; +} + +bool RasterizerStorageRD::free(RID p_rid) { + + if (texture_owner.owns(p_rid)) { + Texture *t = texture_owner.getornull(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()) { + RD::get_singleton()->free(t->rd_texture_srgb); + } + texture_owner.free(p_rid); + + } else if (render_target_owner.owns(p_rid)) { + RenderTarget *rt = render_target_owner.getornull(p_rid); + + _clear_render_target(rt); + + if (rt->texture.is_valid()) { + //no memory to be freed from here + texture_owner.free(rt->texture); + } + + render_target_owner.free(p_rid); + } else { + return false; + } + + return true; +} diff --git a/servers/visual/rasterizer/rasterizer_storage_rd.h b/servers/visual/rasterizer/rasterizer_storage_rd.h index 9c41f81fd7..caaaced75f 100644 --- a/servers/visual/rasterizer/rasterizer_storage_rd.h +++ b/servers/visual/rasterizer/rasterizer_storage_rd.h @@ -3,44 +3,100 @@ #include "core/rid_owner.h" #include "servers/visual/rasterizer/rasterizer.h" - +#include "servers/visual/rendering_device.h" class RasterizerStorageRD : public RasterizerStorage { public: /* TEXTURE API */ - struct RDTexture { + struct Texture { + + enum Type { + TYPE_2D, + TYPE_LAYERED, + TYPE_3D + }; + + Type type; + + RenderingDevice::TextureType rd_type; + RID rd_texture; + RID rd_texture_srgb; + RenderingDevice::DataFormat rd_format; + RenderingDevice::DataFormat rd_format_srgb; + + Image::Format format; int width; int height; - uint32_t flags; - Image::Format format; - Ref<Image> image; + int depth; + int layers; + int mipmaps; + + int height_2d; + int width_2d; + + bool is_render_target; + + Ref<Image> image_cache_2d; String path; }; - struct RDSurface { - uint32_t format; - VS::PrimitiveType primitive; - PoolVector<uint8_t> array; - int vertex_count; - PoolVector<uint8_t> index_array; - int index_count; - AABB aabb; - Vector<PoolVector<uint8_t> > blend_shapes; - Vector<AABB> bone_aabbs; + struct TextureToRDFormat { + RD::DataFormat format; + RD::DataFormat format_srgb; + RD::TextureSwizzle swizzle_r; + RD::TextureSwizzle swizzle_g; + RD::TextureSwizzle swizzle_b; + RD::TextureSwizzle swizzle_a; + TextureToRDFormat() { + format = RD::DATA_FORMAT_MAX; + format_srgb = RD::DATA_FORMAT_MAX; + swizzle_r = RD::TEXTURE_SWIZZLE_R; + swizzle_g = RD::TEXTURE_SWIZZLE_G; + swizzle_b = RD::TEXTURE_SWIZZLE_B; + swizzle_a = RD::TEXTURE_SWIZZLE_A; + } }; - struct RDMesh { - Vector<RDSurface> surfaces; - int blend_shape_count; - VS::BlendShapeMode blend_shape_mode; + mutable RID_Owner<Texture> texture_owner; + + Ref<Image> _validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format); + + /* RENDER TARGET */ + + struct RenderTarget { + + Size2i size; + RID framebuffer; + RID color; + RID color_srgb; + + //used for retrieving from CPU + RD::DataFormat color_format; + RD::DataFormat color_format_srgb; + Image::Format image_format; + + bool flags[RENDER_TARGET_FLAG_MAX]; + + //texture generated for this owner (nor RD). + RID texture; + bool dirty; + bool texture_dirty; + bool was_used; }; - mutable RID_PtrOwner<RDTexture> texture_owner; - mutable RID_PtrOwner<RDMesh> mesh_owner; + RID_Owner<RenderTarget> render_target_owner; + + void _clear_render_target(RenderTarget *rt); + void _update_render_target(RenderTarget *rt); + +public: + /* TEXTURE API */ 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 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); @@ -71,10 +127,54 @@ public: virtual Size2 texture_size_with_proxy(RID p_proxy) const; + //internal usage + + _FORCE_INLINE_ RID texture_get_rd_texture(RID p_texture, bool p_srgb = false) { + if (p_texture.is_null()) { + return RID(); + } + Texture *tex = texture_owner.getornull(p_texture); + + if (!tex) { + return RID(); + } + return (p_srgb && tex->rd_texture_srgb.is_valid()) ? tex->rd_texture_srgb : tex->rd_texture; + } + + _FORCE_INLINE_ Size2i texture_2d_get_size(RID p_texture) { + if (p_texture.is_null()) { + return Size2i(); + } + Texture *tex = texture_owner.getornull(p_texture); + + if (!tex) { + return Size2i(); + } + return Size2i(tex->width_2d, tex->height_2d); + } + /* SKY API */ + struct RDSurface { + uint32_t format; + VS::PrimitiveType primitive; + PoolVector<uint8_t> array; + int vertex_count; + PoolVector<uint8_t> index_array; + int index_count; + AABB aabb; + Vector<PoolVector<uint8_t> > blend_shapes; + Vector<AABB> bone_aabbs; + }; + + struct RDMesh { + Vector<RDSurface> surfaces; + int blend_shape_count; + VS::BlendShapeMode blend_shape_mode; + }; RID sky_create() { return RID(); } void sky_set_texture(RID p_sky, RID p_cube_map, int p_radiance_size) {} + mutable RID_PtrOwner<RDMesh> mesh_owner; /* SHADER API */ @@ -516,17 +616,19 @@ public: virtual bool particles_is_inactive(RID p_particles) const { return false; } - /* RENDER TARGET */ + /* RENDER TARGET API */ - RID render_target_create() { return RID(); } - void render_target_set_position(RID p_render_target, int p_x, int p_y) {} - void render_target_set_size(RID p_render_target, int p_width, int p_height) {} - RID render_target_get_texture(RID p_render_target) const { return RID(); } - 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) { return false; } - void render_target_clear_used(RID p_render_target) {} - void render_target_set_msaa(RID p_render_target, VS::ViewportMSAA p_msaa) {} + RID render_target_create(); + void render_target_set_position(RID p_render_target, int p_x, int p_y); + void render_target_set_size(RID p_render_target, int p_width, int p_height); + RID render_target_get_texture(RID p_render_target); + 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); + + Size2 render_target_get_size(RID p_render_target); + RID render_target_get_rd_framebuffer(RID p_render_target); /* CANVAS SHADOW */ @@ -545,16 +647,7 @@ public: return VS::INSTANCE_NONE; } - bool free(RID p_rid) { - - if (texture_owner.owns(p_rid)) { - // delete the texture - RDTexture *texture = texture_owner.getornull(p_rid); - texture_owner.free(p_rid); - memdelete(texture); - } - return true; - } + bool free(RID p_rid); bool has_os_feature(const String &p_feature) const { return false; } diff --git a/servers/visual/rasterizer/render_pipeline_cache_rd.cpp b/servers/visual/rasterizer/render_pipeline_cache_rd.cpp new file mode 100644 index 0000000000..24b0de279e --- /dev/null +++ b/servers/visual/rasterizer/render_pipeline_cache_rd.cpp @@ -0,0 +1,51 @@ +#include "render_pipeline_cache_rd.h" +#include "core/os/memory.h" + +RID RenderPipelineCacheRD::_generate_version(RD::VertexFormatID p_format_id) { + RID pipeline = RD::get_singleton()->render_pipeline_create(shader, framebuffer_format, p_format_id, render_primitive, rasterization_state, multisample_state, depth_stencil_state, blend_state, dynamic_state_flags); + ERR_FAIL_COND_V(pipeline.is_null(), RID()); + versions = (Version *)memrealloc(versions, sizeof(Version) * (version_count + 1)); + versions[version_count].format_id = p_format_id; + versions[version_count].pipeline = pipeline; + version_count++; + return pipeline; +} + +void RenderPipelineCacheRD::_clear() { + + if (versions) { + for (uint32_t i = 0; i < version_count; i++) { + RD::get_singleton()->free(versions[i].pipeline); + } + version_count = 0; + memfree(versions); + versions = NULL; + } +} + +void RenderPipelineCacheRD::setup(RID p_shader, RD::FramebufferFormatID p_framebuffer_format, RD::RenderPrimitive p_primitive, const RD::PipelineRasterizationState &p_rasterization_state, RD::PipelineMultisampleState p_multisample, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags) { + ERR_FAIL_COND(p_shader.is_null()); + shader = p_shader; + framebuffer_format = p_framebuffer_format; + render_primitive = p_primitive; + rasterization_state = p_rasterization_state; + multisample_state = p_multisample; + depth_stencil_state = p_depth_stencil_state; + blend_state = p_blend_state; + dynamic_state_flags = p_dynamic_state_flags; +} + +void RenderPipelineCacheRD::update_shader(RID p_shader) { + ERR_FAIL_COND(p_shader.is_null()); + _clear(); + setup(p_shader, framebuffer_format, render_primitive, rasterization_state, multisample_state, depth_stencil_state, blend_state, dynamic_state_flags); +} + +RenderPipelineCacheRD::RenderPipelineCacheRD() { + version_count = 0; + versions = NULL; +} + +RenderPipelineCacheRD::~RenderPipelineCacheRD() { + _clear(); +} diff --git a/servers/visual/rasterizer/render_pipeline_cache_rd.h b/servers/visual/rasterizer/render_pipeline_cache_rd.h new file mode 100644 index 0000000000..a280628c75 --- /dev/null +++ b/servers/visual/rasterizer/render_pipeline_cache_rd.h @@ -0,0 +1,47 @@ +#ifndef RENDER_PIPELINE_CACHE_RD_H +#define RENDER_PIPELINE_CACHE_RD_H + +#include "servers/visual/rendering_device.h" + +class RenderPipelineCacheRD { + + RID shader; + + RD::FramebufferFormatID framebuffer_format; + RD::RenderPrimitive render_primitive; + RD::PipelineRasterizationState rasterization_state; + RD::PipelineMultisampleState multisample_state; + RD::PipelineDepthStencilState depth_stencil_state; + RD::PipelineColorBlendState blend_state; + int dynamic_state_flags; + + struct Version { + RD::VertexFormatID format_id; + RID pipeline; + }; + + Version *versions; + uint32_t version_count; + + RID _generate_version(RD::VertexFormatID p_format_id); + + void _clear(); + +public: + void setup(RID p_shader, RD::FramebufferFormatID p_framebuffer_format, RD::RenderPrimitive p_primitive, const RD::PipelineRasterizationState &p_rasterization_state, RD::PipelineMultisampleState p_multisample, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0); + void update_shader(RID p_shader); + + _FORCE_INLINE_ RID get_render_pipeline(RD::VertexFormatID p_format_id) { + for (uint32_t i = 0; i < version_count; i++) { + if (versions[i].format_id == p_format_id) { + return versions[i].pipeline; + } + } + return _generate_version(p_format_id); + } + + RenderPipelineCacheRD(); + ~RenderPipelineCacheRD(); +}; + +#endif // RENDER_PIPELINE_CACHE_RD_H diff --git a/servers/visual/rasterizer/shader_rd.cpp b/servers/visual/rasterizer/shader_rd.cpp new file mode 100644 index 0000000000..94d42a2823 --- /dev/null +++ b/servers/visual/rasterizer/shader_rd.cpp @@ -0,0 +1,328 @@ +/*************************************************************************/ +/* shader_rd.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "shader_rd.h" +#include "core/string_builder.h" +#include "servers/visual/rendering_device.h" + +void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_name) { + + name = p_name; + //split vertex and shader code (thank you, shader compiler programmers from you know what company). + { + String defines_tag = "\nVERSION_DEFINES"; + String globals_tag = "\nVERTEX_SHADER_GLOBALS"; + String material_tag = "\nMATERIAL_UNIFORMS"; + String code_tag = "\nVERTEX_SHADER_CODE"; + String code = p_vertex_code; + + int cpos = code.find(defines_tag); + if (cpos != -1) { + vertex_codev = code.substr(0, cpos).ascii(); + code = code.substr(cpos + defines_tag.length(), code.length()); + } + + cpos = code.find(material_tag); + + if (cpos == -1) { + vertex_code0 = code.ascii(); + } else { + vertex_code0 = code.substr(0, cpos).ascii(); + code = code.substr(cpos + material_tag.length(), code.length()); + + cpos = code.find(globals_tag); + + if (cpos == -1) { + vertex_code1 = code.ascii(); + } else { + + vertex_code1 = code.substr(0, cpos).ascii(); + String code2 = code.substr(cpos + globals_tag.length(), code.length()); + + cpos = code2.find(code_tag); + if (cpos == -1) { + vertex_code2 = code2.ascii(); + } else { + + vertex_code2 = code2.substr(0, cpos).ascii(); + vertex_code3 = code2.substr(cpos + code_tag.length(), code2.length()).ascii(); + } + } + } + } + + { + String defines_tag = "\nVERSION_DEFINES"; + String globals_tag = "\nFRAGMENT_SHADER_GLOBALS"; + String material_tag = "\nMATERIAL_UNIFORMS"; + String code_tag = "\nFRAGMENT_SHADER_CODE"; + String light_code_tag = "\nLIGHT_SHADER_CODE"; + String code = p_fragment_code; + + int cpos = code.find(defines_tag); + if (cpos != -1) { + fragment_codev = code.substr(0, cpos).ascii(); + code = code.substr(cpos + defines_tag.length(), code.length()); + } + + cpos = code.find(material_tag); + if (cpos == -1) { + fragment_code0 = code.ascii(); + } else { + fragment_code0 = code.substr(0, cpos).ascii(); + //print_line("CODE0:\n"+String(fragment_code0.get_data())); + code = code.substr(cpos + material_tag.length(), code.length()); + cpos = code.find(globals_tag); + + if (cpos == -1) { + fragment_code1 = code.ascii(); + } else { + + fragment_code1 = code.substr(0, cpos).ascii(); + //print_line("CODE1:\n"+String(fragment_code1.get_data())); + + String code2 = code.substr(cpos + globals_tag.length(), code.length()); + cpos = code2.find(light_code_tag); + + if (cpos == -1) { + fragment_code2 = code2.ascii(); + } else { + + fragment_code2 = code2.substr(0, cpos).ascii(); + //print_line("CODE2:\n"+String(fragment_code2.get_data())); + + String code3 = code2.substr(cpos + light_code_tag.length(), code2.length()); + + cpos = code3.find(code_tag); + if (cpos == -1) { + fragment_code3 = code3.ascii(); + } else { + + fragment_code3 = code3.substr(0, cpos).ascii(); + //print_line("CODE3:\n"+String(fragment_code3.get_data())); + fragment_code4 = code3.substr(cpos + code_tag.length(), code3.length()).ascii(); + //print_line("CODE4:\n"+String(fragment_code4.get_data())); + } + } + } + } + } +} + +RID ShaderRD::version_create() { + + //initialize() was never called + ERR_FAIL_COND_V(variant_defines.size() == 0, RID()); + + Version version; + version.dirty = true; + version.valid = false; + version.initialize_needed = true; + version.variants = NULL; + return version_owner.make_rid(version); +} + +void ShaderRD::_clear_version(Version *p_version) { + //clear versions if they exist + if (p_version->variants) { + for (int i = 0; i < variant_defines.size(); i++) { + RD::get_singleton()->free(p_version->variants[i]); + } + + memdelete_arr(p_version->variants); + p_version->variants = NULL; + } +} +void ShaderRD::_compile_version(Version *p_version) { + + _clear_version(p_version); + + p_version->valid = false; + p_version->dirty = false; + + p_version->variants = memnew_arr(RID, variant_defines.size()); + + for (int i = 0; i < variant_defines.size(); i++) { + + Vector<RD::ShaderStageSource> stages; + + { + //vertex stage + + StringBuilder builder; + + builder.append(vertex_codev.get_data()); // version info (if exists) + + builder.append(variant_defines[i].get_data()); + for (int j = 0; j < p_version->custom_defines.size(); j++) { + builder.append(p_version->custom_defines[j].get_data()); + } + + builder.append(vertex_code0.get_data()); //first part of vertex + + builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment) + + builder.append(vertex_code1.get_data()); //second part of vertex + + builder.append(p_version->vertex_globals.get_data()); // vertex globals + + builder.append(vertex_code2.get_data()); //third part of vertex + + builder.append(p_version->vertex_code.get_data()); // code + + builder.append(vertex_code3.get_data()); //fourth of vertex + + RD::ShaderStageSource stage; + stage.shader_source = builder.as_string(); + stage.shader_stage = RD::SHADER_STAGE_VERTEX; + + stages.push_back(stage); + } + + { + //fragment stage + + StringBuilder builder; + + builder.append(fragment_codev.get_data()); // version info (if exists) + + builder.append(variant_defines[i].get_data()); + for (int j = 0; j < p_version->custom_defines.size(); j++) { + builder.append(p_version->custom_defines[j].get_data()); + } + + builder.append(fragment_code0.get_data()); //first part of fragment + + builder.append(p_version->uniforms.get_data()); //uniforms (same for fragment and fragment) + + builder.append(fragment_code1.get_data()); //first part of fragment + + builder.append(p_version->fragment_globals.get_data()); // fragment globals + + builder.append(fragment_code2.get_data()); //third part of fragment + + builder.append(p_version->fragment_light.get_data()); // fragment light + + builder.append(fragment_code3.get_data()); //fourth part of fragment + + builder.append(p_version->fragment_code.get_data()); // fragment code + + builder.append(fragment_code4.get_data()); //fourth part of fragment + + RD::ShaderStageSource stage; + stage.shader_source = builder.as_string(); + stage.shader_stage = RD::SHADER_STAGE_FRAGMENT; + + stages.push_back(stage); + } + + String error; + RD::ShaderStage error_stage; + RID shader = RD::get_singleton()->shader_create_from_source(stages, &error, &error_stage); + + if (shader.is_null() && error != String()) { + ERR_PRINT("Error compiling shader, variant #" + itos(i) + " (" + variant_defines[i].get_data() + ")."); + ERR_PRINT(error); + +#ifdef DEBUG_ENABLED + if (error_stage < RD::SHADER_STAGE_MAX) { + ERR_PRINT("code:\n" + stages[error_stage].shader_source.get_with_code_lines()); + } +#endif + //clear versions if they exist + for (int j = 0; j < i; j++) { + RD::get_singleton()->free(p_version->variants[j]); + } + + memdelete_arr(p_version->variants); + p_version->variants = NULL; + return; + } + + p_version->variants[i] = shader; + } + + p_version->valid = true; +} + +void ShaderRD::version_set_code(RID p_version, const String &p_uniforms, const String &p_vertex_globals, const String &p_vertex_code, const String &p_fragment_globals, const String &p_fragment_light, const String &p_fragment_code, const Vector<String> &p_custom_defines) { + + Version *version = version_owner.getornull(p_version); + ERR_FAIL_COND(!version); + version->vertex_globals = p_vertex_globals.utf8(); + version->vertex_code = p_vertex_code.utf8(); + version->fragment_light = p_fragment_light.utf8(); + version->fragment_globals = p_fragment_globals.utf8(); + version->fragment_code = p_fragment_code.utf8(); + version->custom_defines.clear(); + for (int i = 0; i < p_custom_defines.size(); i++) { + version->custom_defines.push_back(p_custom_defines[i].utf8()); + } + + version->dirty = true; + if (version->initialize_needed) { + _compile_version(version); + version->initialize_needed = false; + } +} + +bool ShaderRD::version_free(RID p_version) { + + if (version_owner.owns(p_version)) { + Version *version = version_owner.getornull(p_version); + _clear_version(version); + version_owner.free(p_version); + } else { + return false; + } + + return true; +} + +void ShaderRD::initialize(const Vector<String> &p_variant_defines) { + ERR_FAIL_COND(variant_defines.size()); + ERR_FAIL_COND(p_variant_defines.size() == 0); + for (int i = 0; i < p_variant_defines.size(); i++) { + + variant_defines.push_back(p_variant_defines[i].utf8()); + } +} + +ShaderRD::~ShaderRD() { + List<RID> remaining; + version_owner.get_owned_list(&remaining); + if (remaining.size()) { + ERR_PRINT(itos(remaining.size()) + " shaders of type " + name + " were never freed"); + while (remaining.size()) { + version_free(remaining.front()->get()); + remaining.pop_front(); + } + } +} diff --git a/servers/visual/rasterizer/shader_rd.h b/servers/visual/rasterizer/shader_rd.h new file mode 100644 index 0000000000..814c87d281 --- /dev/null +++ b/servers/visual/rasterizer/shader_rd.h @@ -0,0 +1,121 @@ +/*************************************************************************/ +/* shader_rd.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef SHADER_RD_H +#define SHADER_RD_H + +#include "core/hash_map.h" +#include "core/map.h" +#include "core/rid_owner.h" +#include "core/variant.h" +#include <stdio.h> + +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ + +class ShaderRD { + + //versions + Vector<CharString> variant_defines; + + int vertex_code_start; + int fragment_code_start; + + struct Version { + + CharString uniforms; + CharString vertex_globals; + CharString vertex_code; + CharString fragment_light; + CharString fragment_globals; + CharString fragment_code; + Vector<CharString> custom_defines; + + RID *variants; //same size as version defines + + bool valid; + bool dirty; + bool initialize_needed; + }; + + void _clear_version(Version *p_version); + void _compile_version(Version *p_version); + + RID_Owner<Version> version_owner; + + CharString fragment_codev; //for version and extensions + CharString fragment_code0; + CharString fragment_code1; + CharString fragment_code2; + CharString fragment_code3; + CharString fragment_code4; + + CharString vertex_codev; //for version and extensions + CharString vertex_code0; + CharString vertex_code1; + CharString vertex_code2; + CharString vertex_code3; + + const char *name; + +protected: + ShaderRD() {} + void setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_name); + +public: + RID version_create(); + + void version_set_code(RID p_version, const String &p_uniforms, const String &p_vertex_globals, const String &p_vertex_code, const String &p_fragment_globals, const String &p_fragment_light, const String &p_fragment_code, const Vector<String> &p_custom_defines); + + _FORCE_INLINE_ RID version_get_shader(RID p_version, int p_variant) { + ERR_FAIL_INDEX_V(p_variant, variant_defines.size(), RID()); + + Version *version = version_owner.getornull(p_version); + ERR_FAIL_COND_V(!version, RID()); + + if (version->dirty) { + _compile_version(version); + } + + if (!version->valid) { + return RID(); + } + + return version->variants[p_variant]; + } + + bool version_free(RID p_version); + + void initialize(const Vector<String> &p_variant_defines); + virtual ~ShaderRD(); +}; + +#endif diff --git a/servers/visual/rasterizer/shaders/SCsub b/servers/visual/rasterizer/shaders/SCsub new file mode 100644 index 0000000000..62a4c2a0ba --- /dev/null +++ b/servers/visual/rasterizer/shaders/SCsub @@ -0,0 +1,6 @@ +#!/usr/bin/env python + +Import('env') + +if 'RD_GLSL' in env['BUILDERS']: + env.RD_GLSL('canvas.glsl'); diff --git a/servers/visual/rasterizer/shaders/canvas.glsl b/servers/visual/rasterizer/shaders/canvas.glsl new file mode 100644 index 0000000000..67d6ab9d78 --- /dev/null +++ b/servers/visual/rasterizer/shaders/canvas.glsl @@ -0,0 +1,372 @@ +/* clang-format off */ +[vertex] +/* clang-format on */ + +#version 450 + +/* clang-format off */ +VERSION_DEFINES +/* clang-format on */ + +#ifdef USE_VERTEX_ARRAYS +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" + + +layout(location=0) out vec2 uv_interp; +layout(location=1) out vec4 color_interp; + +#ifdef USE_NINEPATCH + +layout(location=3) out vec2 pixel_size_interp; + +#endif + +/* clang-format off */ +MATERIAL_UNIFORMS +/* clang-format on */ + + +/* clang-format off */ +VERTEX_SHADER_GLOBALS +/* clang-format on */ + + +void main() { + + vec4 instance_custom = vec4(0.0); + +#ifdef USE_VERTEX_ARRAYS + + 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 + + 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.xy : vertex_base.yx); + vec4 color = vec4(1.0); + 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 = 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)); +#if 0 + if (draw_data.flags&FLAGS_INSTANCING_ENABLED) { + + uint offset = draw_data.flags&FLAGS_INSTANCING_STRIDE_MASK; + offset *= gl_InstanceIndex; + mat4 instance_xform = mat4( + vec4( texelFetch(instancing_buffer,offset+0),texelFetch(instancing_buffer,offset+1),0.0,texelFetch(instancing_buffer,offset+3) ), + vec4( texelFetch(instancing_buffer,offset+4),texelFetch(instancing_buffer,offset+5),0.0,texelFetch(instancing_buffer,offset+7) ), + vec4( 0.0,0.0,1.0,0.0), + vec4( 0.0,0.0,0.0,1.0 ) ); + offset+=8; + if ( draw_data.flags&FLAGS_INSTANCING_HAS_COLORS ) { + vec4 instance_color; + if (draw_data.flags&FLAGS_INSTANCING_COLOR_8_BIT ) { + uint bits = floatBitsToUint(texelFetch(instancing_buffer,offset)); + instance_color = unpackUnorm4x8(bits); + offset+=1; + } else { + instance_color = vec4(texelFetch(instancing_buffer,offset+0),texelFetch(instancing_buffer,offset+1),texelFetch(instancing_buffer,offset+2),texelFetch(instancing_buffer,offset+3)); + offser+=4; + } + + color*=instance_color; + } + if ( draw_data.flags&FLAGS_INSTANCING_HAS_CUSTOM_DATA ) { + if (draw_data.flags&FLAGS_INSTANCING_CUSTOM_DATA_8_BIT ) { + uint bits = floatBitsToUint(texelFetch(instancing_buffer,offset)); + instance_custom = unpackUnorm4x8(bits); + } else { + instance_custom = vec4(texelFetch(instancing_buffer,offset+0),texelFetch(instancing_buffer,offset+1),texelFetch(instancing_buffer,offset+2),texelFetch(instancing_buffer,offset+3)); + } + } + + } + +#endif + + if (bool(draw_data.flags&FLAGS_USING_PARTICLES)) { + //scale by texture size + vertex /= draw_data.color_texture_pixel_size; + } +#ifdef USE_POINT_SIZE + float point_size = 1.0; +#endif + { + /* clang-format off */ +VERTEX_SHADER_CODE + /* clang-format on */ + } + + + +#ifdef USE_NINEPATCH + pixel_size_interp = abs(draw_data.dst_rect.zw) * vertex; +#endif + +#if !defined(SKIP_TRANSFORM_USED) + vertex = (world_matrix * vec4(vertex,0.0,1.0)).xy; +#endif + + color_interp = color; + + if (bool(draw_data.flags&FLAGS_USE_PIXEL_SNAP)) { + + vertex = floor(vertex + 0.5); + // precision issue on some hardware creates artifacts within texture + // offset uv by a small amount to avoid + uv += 1e-5; + } + +#if 0 + if (bool(draw_data.flags&FLAGS_USE_SKELETON) && bone_weights != vec4(0.0)) { //must be a valid bone + //skeleton transform + + ivec4 bone_indicesi = ivec4(bone_indices); + + uvec2 tex_ofs = bone_indicesi.x *2; + + mat2x4 m; + m = mat2x4( + texelFetch(skeleton_buffer, tex_ofs+0), + texelFetch(skeleton_buffer, tex_ofs+1) ) * + bone_weights.x; + + tex_ofs = bone_indicesi.y * 2; + + m += mat2x4( + texelFetch(skeleton_buffer, tex_ofs+0), + texelFetch(skeleton_buffer, tex_ofs+1) ) * + bone_weights.y; + + tex_ofs = bone_indicesi.z * 2; + + m += mat2x4( + texelFetch(skeleton_buffer, tex_ofs+0), + texelFetch(skeleton_buffer, tex_ofs+1) ) * + bone_weights.z; + + tex_ofs = bone_indicesi.w * 2; + + m += mat2x4( + texelFetch(skeleton_buffer, tex_ofs+0), + texelFetch(skeleton_buffer, tex_ofs+1) ) * + bone_weights.w; + + mat4 bone_matrix = skeleton_data.skeleton_transform * transpose(mat4(m[0], m[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))) * skeleton_data.skeleton_transform_inverse; + + //outvec = bone_matrix * outvec; + } +#endif + +#if !defined(SKIP_TRANSFORM_USED) + gl_Position = (canvas_data.screen_transform * canvas_data.canvas_transform) * vec4(vertex,0.0,1.0); +#else + gl_Position = vec4(vertex,0.0,1.0); +#endif + +#ifdef USE_POINT_SIZE + gl_PointSize=point_size; +#endif + +} + +/* clang-format off */ +[fragment] + +#version 450 + +/* clang-format off */ +VERSION_DEFINES +/* clang-format on */ + +#include "canvas_uniforms_inc.glsl" + +layout(location=0) in vec2 uv_interp; +layout(location=1) in vec4 color_interp; + +#ifdef USE_NINEPATCH + +layout(location=3) in vec2 pixel_size_interp; + +#endif + +layout(location = 0) out vec4 frag_color; + +/* clang-format off */ +MATERIAL_UNIFORMS +/* clang-format on */ + + +/* clang-format off */ +FRAGMENT_SHADER_GLOBALS +/* clang-format on */ + + +void light_compute( + inout vec4 light, + inout vec2 light_vec, + inout float light_height, + inout vec4 light_color, + vec2 light_uv, + inout vec4 shadow_color, + vec3 normal, + vec2 uv, + vec2 screen_uv, + vec4 color) { + + /* clang-format off */ +LIGHT_SHADER_CODE + /* clang-format on */ +} + + +#ifdef USE_NINEPATCH + +float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, float margin_begin, float margin_end, int np_repeat, inout int draw_center) { + + float tex_size = 1.0 / tex_pixel_size; + + if (pixel < margin_begin) { + return pixel * tex_pixel_size; + } else if (pixel >= draw_size - margin_end) { + return (tex_size - (draw_size - pixel)) * tex_pixel_size; + } else { + if (!bool(draw_data.flags&FLAGS_NINEPACH_DRAW_CENTER)) { + draw_center--; + } + + if (np_repeat == 0) { //stretch + //convert to ratio + float ratio = (pixel - margin_begin) / (draw_size - margin_begin - margin_end); + //scale to source texture + return (margin_begin + ratio * (tex_size - margin_begin - margin_end)) * tex_pixel_size; + } else if (np_repeat == 1) { //tile + //convert to ratio + float ofs = mod((pixel - margin_begin), tex_size - margin_begin - margin_end); + //scale to source texture + return (margin_begin + ofs) * tex_pixel_size; + } else if (np_repeat == 2) { //tile fit + //convert to ratio + float src_area = draw_size - margin_begin - margin_end; + float dst_area = tex_size - margin_begin - margin_end; + float scale = max(1.0, floor(src_area / max(dst_area, 0.0000001) + 0.5)); + + //convert to ratio + float ratio = (pixel - margin_begin) / src_area; + ratio = mod(ratio * scale, 1.0); + return (margin_begin + ratio * dst_area) * tex_pixel_size; + } + } +} + + +#endif + +void main() { + + vec4 color = color_interp; + vec2 uv = uv_interp; + +#ifdef USE_TEXTURE_RECT + +#ifdef USE_NINEPATCH + + int draw_center = 2; + uv = vec2( + map_ninepatch_axis(pixel_size_interp.x, abs(draw_data.dst_rect.z), draw_data.color_texture_pixel_size.x, draw_data.ninepatch_margins.x, draw_data.ninepatch_margins.z, (draw_data.ninepatch_repeat>>16), draw_center), + map_ninepatch_axis(pixel_size_interp.y, abs(draw_data.dst_rect.w), draw_data.color_texture_pixel_size.y, draw_data.ninepatch_margins.y, draw_data.ninepatch_margins.w, (draw_data.ninepatch_repeat&0xFFFF), draw_center)); + + if (draw_center == 0) { + color.a = 0.0; + } + + uv = uv * draw_data.src_rect.zw + draw_data.src_rect.xy; //apply region if needed +#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)); + } + +#endif + +#if !defined(COLOR_USED) + //default behavior, texture by color + + color *= texture(sampler2D(color_texture,texture_sampler), uv); + +#endif + + + + vec3 normal; + +#if defined(NORMAL_USED) + + bool normal_used = true; +#else + bool normal_used = false; +#endif + +#if 0 + if (false /*normal_used || canvas_data.light_count > 0*/ ) { + normal.xy = texture(sampler2D(normal_texture,texture_sampler ), uv).xy * 2.0 - 1.0; + normal.z = sqrt(1.0 - dot(normal.xy, normal.xy)); + normal_used = true; + } else { +#endif + normal = vec3(0.0, 0.0, 1.0); +#if 0 + } +#endif + +#if defined(SCREEN_UV_USED) + vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; +#endif + + { + float normal_depth = 1.0; + +#if defined(NORMALMAP_USED) + vec3 normal_map = vec3(0.0, 0.0, 1.0); + normal_used = true; +#endif + + /* clang-format off */ + +FRAGMENT_SHADER_CODE + + /* clang-format on */ + +#if defined(NORMALMAP_USED) + normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_depth); +#endif + } + + color *= draw_data.modulation; +#if 0 + if (canvas_data.light_count > 0 ) { + //do lighting + + } +#endif + //color.rgb *= color.a; + frag_color = color; +} diff --git a/servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl b/servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl new file mode 100644 index 0000000000..51769bbdc3 --- /dev/null +++ b/servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl @@ -0,0 +1,84 @@ + +/* SET0: Per draw primitive settings */ + + +#define MAX_LIGHTS 128 + +#define FLAGS_INSTANCING_STRIDE_MASK 0xF +#define FLAGS_INSTANCING_ENABLED (1<<4) +#define FLAGS_INSTANCING_HAS_COLORS (1 << 5) +#define FLAGS_INSTANCING_COLOR_8BIT (1 << 6) +#define FLAGS_INSTANCING_HAS_CUSTOM_DATA (1 << 7) +#define FLAGS_INSTANCING_CUSTOM_DATA_8_BIT (1 << 8) + +#define FLAGS_CLIP_RECT_UV (1 << 9) +#define FLAGS_TRANSPOSE_RECT (1 << 10) +#define FLAGS_NINEPACH_DRAW_CENTER (1 << 12) +#define FLAGS_USING_PARTICLES (1 << 13) +#define FLAGS_USE_PIXEL_SNAP (1 << 14) + +#define FLAGS_USE_SKELETON (1 << 16) + +layout(push_constant, binding = 0, std140) uniform DrawData { + mat2x4 world; + vec4 modulation; + vec4 ninepatch_margins; + vec4 dst_rect; //for built-in rect and UV + vec4 src_rect; + uint flags; + uint ninepatch_repeat; + vec2 color_texture_pixel_size; +} draw_data; + +// The values passed per draw primitives are cached within it + +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; + +/* SET1: Is reserved for the material */ + +// + +/* SET2: Per Canvas Item Settings */ + +layout(set = 1, binding = 1) uniform textureBuffer skeleton_buffer; + +layout(set = 1, binding = 2, std140) uniform SkeletonData { + mat4 skeleton_transform; + mat4 skeleton_transform_inverse; +} skeleton_data; + +// this set (set 2) is also used for instance specific uniforms + +/* SET3: Per Scene settings */ + +layout(set = 3, binding = 0, std140) uniform CanvasData { + mat4 canvas_transform; + mat4 screen_transform; + //uint light_count; +} canvas_data; + +struct Light { + // light matrices + mat4 light_matrix; + mat4 light_local_matrix; + mat4 shadow_matrix; + vec4 light_color; + vec4 light_shadow_color; + vec2 light_pos; + float shadowpixel_size; + float shadow_gradient; + float light_height; + float light_outside_alpha; + float shadow_distance_mult; +}; + +layout(set = 3, binding = 1, std140) uniform LightData { + Light lights[MAX_LIGHTS]; +} light_data; + +layout(set = 3, binding = 2) uniform texture2D light_textures[MAX_LIGHTS]; diff --git a/servers/visual/rendering_device.cpp b/servers/visual/rendering_device.cpp index d17efce690..eaecc76b55 100644 --- a/servers/visual/rendering_device.cpp +++ b/servers/visual/rendering_device.cpp @@ -1,6 +1,13 @@ #include "rendering_device.h" -RenderingDevice::RenderingDevice() -{ +RenderingDevice *RenderingDevice::singleton=NULL; + +RenderingDevice *RenderingDevice::get_singleton() { + return singleton; +} + +RenderingDevice::RenderingDevice() { + + singleton=this; } diff --git a/servers/visual/rendering_device.h b/servers/visual/rendering_device.h index cf31063100..a1143a5f0d 100644 --- a/servers/visual/rendering_device.h +++ b/servers/visual/rendering_device.h @@ -5,6 +5,8 @@ class RenderingDevice : public Object { GDCLASS(RenderingDevice, Object) + + static RenderingDevice *singleton; public: //base numeric ID for all types enum { @@ -352,7 +354,7 @@ public: virtual RID texture_create_shared(const TextureView& p_view, RID p_with_texture) = 0; 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,TextureUsageBits p_usage) const = 0; + virtual bool texture_is_format_supported_for_usage(DataFormat p_format,uint32_t p_usage) const = 0; /*********************/ @@ -505,7 +507,8 @@ public: } }; - virtual RID shader_create_from_source(const Vector<ShaderStageSource> &p_stages,String *r_error=NULL,bool p_allow_cache=true) = 0; + virtual RID shader_create_from_source(const Vector<ShaderStageSource> &p_stages,String *r_error=NULL,ShaderStage *r_error_stage=NULL,bool p_allow_cache=true) = 0; + virtual Vector<int> shader_get_vertex_input_locations_used(RID p_shader) = 0; /******************/ @@ -514,7 +517,7 @@ public: enum UniformType { UNIFORM_TYPE_SAMPLER, //for sampling only (sampler GLSL type) - UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, // for sampling only, but includes a texture, (samplerXX GLSL type) + UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, // for sampling only, but includes a texture, (samplerXX GLSL type), first a sampler then a texture UNIFORM_TYPE_TEXTURE, //only texture, (textureXX GLSL type) UNIFORM_TYPE_IMAGE, // storage image (imageXX GLSL type), for compute mostly UNIFORM_TYPE_TEXTURE_BUFFER, // buffer texture (or TBO, textureBuffer type) @@ -548,6 +551,8 @@ public: }; virtual RID uniform_set_create(const Vector<Uniform>& p_uniforms,RID p_shader,uint32_t p_shader_set) = 0; + virtual bool uniform_set_is_valid(RID p_uniform_set) =0; + virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, void *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 @@ -774,6 +779,22 @@ public: return bs; } + static PipelineColorBlendState create_blend(int p_attachments=1) { + PipelineColorBlendState bs; + for(int i=0;i<p_attachments;i++) { + + Attachment ba; + ba.enable_blend=true; + ba.src_color_blend_factor = BLEND_FACTOR_SRC_ALPHA; + ba.dst_color_blend_factor = BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + ba.src_alpha_blend_factor = BLEND_FACTOR_SRC_ALPHA; + ba.dst_alpha_blend_factor = BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + + bs.attachments.push_back(ba); + } + return bs; + } + Vector<Attachment> attachments; //one per render target texture Color blend_constant; @@ -849,7 +870,17 @@ public: /***************/ virtual void free(RID p_id) =0; + + //methods below not exposed, used by RenderingDeviceRD + virtual void finalize_frame() =0; + virtual void advance_frame() =0; + + static RenderingDevice *get_singleton(); + RenderingDevice(); }; + +typedef RenderingDevice RD; + #endif // RENDERING_DEVICE_H diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index 02213e0d4c..790dc59496 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -35,18 +35,34 @@ static const int z_range = VS::CANVAS_ITEM_Z_MAX - VS::CANVAS_ITEM_Z_MIN + 1; -void VisualServerCanvas::_render_canvas_item_tree(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, 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) { memset(z_list, 0, z_range * sizeof(RasterizerCanvas::Item *)); memset(z_last_list, 0, z_range * sizeof(RasterizerCanvas::Item *)); - _render_canvas_item(p_canvas_item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, NULL, NULL); + for (int i = 0; i < p_child_item_count; i++) { + _cull_canvas_item(p_child_items[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, NULL, NULL); + } + if (p_canvas_item) { + _cull_canvas_item(p_canvas_item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, NULL, NULL); + } + + RasterizerCanvas::Item *list = NULL; + RasterizerCanvas::Item *list_end = NULL; for (int i = 0; i < z_range; i++) { if (!z_list[i]) continue; - VSG::canvas_render->canvas_render_items(z_list[i], VS::CANVAS_ITEM_Z_MIN + i, p_modulate, p_lights, p_transform); + if (!list) { + list = z_list[i]; + list_end = z_last_list[i]; + } else { + list_end->next = z_list[i]; + list_end = z_last_list[i]; + } } + + VSG::canvas_render->canvas_render_items(p_to_render_target, p_clear, p_clear_color, 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) { @@ -81,7 +97,7 @@ void _mark_ysort_dirty(VisualServerCanvas::Item *ysort_owner, RID_PtrOwner<Visua } while (ysort_owner && ysort_owner->sort_y); } -void VisualServerCanvas::_render_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 VisualServerCanvas::_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) { Item *ci = p_canvas_item; @@ -153,9 +169,9 @@ void VisualServerCanvas::_render_canvas_item(Item *p_canvas_item, const Transfor if (!child_items[i]->behind || (ci->sort_y && child_items[i]->sort_y)) continue; if (ci->sort_y) { - _render_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner); + _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner); } else { - _render_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner); + _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner); } } @@ -187,6 +203,8 @@ void VisualServerCanvas::_render_canvas_item(Item *p_canvas_item, const Transfor z_last_list[zidx] = ci; } + ci->z_final = p_z; + ci->next = NULL; } @@ -195,9 +213,9 @@ void VisualServerCanvas::_render_canvas_item(Item *p_canvas_item, const Transfor if (child_items[i]->behind || (ci->sort_y && child_items[i]->sort_y)) continue; if (ci->sort_y) { - _render_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner); + _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner); } else { - _render_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner); + _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner); } } } @@ -225,9 +243,7 @@ void VisualServerCanvas::_light_mask_canvas_items(int p_z, RasterizerCanvas::Ite } } -void VisualServerCanvas::render_canvas(Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect) { - - VSG::canvas_render->canvas_begin(); +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) { if (p_canvas->children_order_dirty) { @@ -248,54 +264,33 @@ void VisualServerCanvas::render_canvas(Canvas *p_canvas, const Transform2D &p_tr if (!has_mirror) { - static const int z_range = VS::CANVAS_ITEM_Z_MAX - VS::CANVAS_ITEM_Z_MIN + 1; - RasterizerCanvas::Item *z_list[z_range]; - RasterizerCanvas::Item *z_last_list[z_range]; - - memset(z_list, 0, z_range * sizeof(RasterizerCanvas::Item *)); - memset(z_last_list, 0, z_range * sizeof(RasterizerCanvas::Item *)); - - for (int i = 0; i < l; i++) { - _render_canvas_item(ci[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, NULL, NULL); - } - - for (int i = 0; i < z_range; i++) { - if (!z_list[i]) - continue; - - if (p_masked_lights) { - _light_mask_canvas_items(VS::CANVAS_ITEM_Z_MIN + i, z_list[i], p_masked_lights); - } + _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); - VSG::canvas_render->canvas_render_items(z_list[i], VS::CANVAS_ITEM_Z_MIN + i, p_canvas->modulate, p_lights, p_transform); - } } 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(ci2.item, p_transform, p_clip_rect, p_canvas->modulate, p_lights); + _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); //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(ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); + _render_canvas_item_tree(p_render_target, false, Color(), 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(ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); + _render_canvas_item_tree(p_render_target, false, Color(), 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(ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); + _render_canvas_item_tree(p_render_target, false, Color(), NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); } } } - - VSG::canvas_render->canvas_end(); } RID VisualServerCanvas::canvas_create() { @@ -473,6 +468,20 @@ void VisualServerCanvas::canvas_item_set_update_when_visible(RID p_item, bool p_ canvas_item->update_when_visible = p_update; } +void VisualServerCanvas::canvas_item_set_default_texture_filter(RID p_item, VS::CanvasItemTextureFilter p_filter) { + + Item *canvas_item = canvas_item_owner.getornull(p_item); + ERR_FAIL_COND(!canvas_item); + canvas_item->texture_filter = p_filter; +} + +void VisualServerCanvas::canvas_item_set_default_texture_repeat(RID p_item, VS::CanvasItemTextureRepeat p_repeat) { + + Item *canvas_item = canvas_item_owner.getornull(p_item); + ERR_FAIL_COND(!canvas_item); + canvas_item->texture_repeat = p_repeat; +} + void VisualServerCanvas::canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width, bool p_antialiased) { Item *canvas_item = canvas_item_owner.getornull(p_item); @@ -627,7 +636,7 @@ void VisualServerCanvas::canvas_item_add_circle(RID p_item, const Point2 &p_pos, canvas_item->commands.push_back(circle); } -void VisualServerCanvas::canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile, const Color &p_modulate, bool p_transpose, RID p_normal_map) { +void VisualServerCanvas::canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile, const Color &p_modulate, bool p_transpose, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -657,13 +666,13 @@ void VisualServerCanvas::canvas_item_add_texture_rect(RID p_item, const Rect2 &p rect->flags |= RasterizerCanvas::CANVAS_RECT_TRANSPOSE; SWAP(rect->rect.size.x, rect->rect.size.y); } - rect->texture = p_texture; - rect->normal_map = p_normal_map; + rect->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID()); + rect->specular_shininess = p_specular_color_shininess; canvas_item->rect_dirty = true; canvas_item->commands.push_back(rect); } -void VisualServerCanvas::canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, RID p_normal_map, bool p_clip_uv) { +void VisualServerCanvas::canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, bool p_clip_uv, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -672,8 +681,8 @@ void VisualServerCanvas::canvas_item_add_texture_rect_region(RID p_item, const R ERR_FAIL_COND(!rect); rect->modulate = p_modulate; rect->rect = p_rect; - rect->texture = p_texture; - rect->normal_map = p_normal_map; + rect->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID()); + rect->specular_shininess = p_specular_color_shininess; rect->source = p_src_rect; rect->flags = RasterizerCanvas::CANVAS_RECT_REGION; @@ -712,15 +721,15 @@ void VisualServerCanvas::canvas_item_add_texture_rect_region(RID p_item, const R canvas_item->commands.push_back(rect); } -void VisualServerCanvas::canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, VS::NinePatchAxisMode p_x_axis_mode, VS::NinePatchAxisMode p_y_axis_mode, bool p_draw_center, const Color &p_modulate, RID p_normal_map) { +void VisualServerCanvas::canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, VS::NinePatchAxisMode p_x_axis_mode, VS::NinePatchAxisMode p_y_axis_mode, bool p_draw_center, const Color &p_modulate, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); Item::CommandNinePatch *style = memnew(Item::CommandNinePatch); ERR_FAIL_COND(!style); - style->texture = p_texture; - style->normal_map = p_normal_map; + style->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID()); + style->specular_shininess = p_specular_color_shininess; style->rect = p_rect; style->source = p_source; style->draw_center = p_draw_center; @@ -735,15 +744,15 @@ void VisualServerCanvas::canvas_item_add_nine_patch(RID p_item, const Rect2 &p_r canvas_item->commands.push_back(style); } -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) { +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) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); Item::CommandPrimitive *prim = memnew(Item::CommandPrimitive); ERR_FAIL_COND(!prim); - prim->texture = p_texture; - prim->normal_map = p_normal_map; + 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; @@ -753,7 +762,7 @@ void VisualServerCanvas::canvas_item_add_primitive(RID p_item, const Vector<Poin canvas_item->commands.push_back(prim); } -void VisualServerCanvas::canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, RID p_normal_map, bool p_antialiased) { +void VisualServerCanvas::canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, bool p_antialiased, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -770,21 +779,20 @@ void VisualServerCanvas::canvas_item_add_polygon(RID p_item, const Vector<Point2 Item::CommandPolygon *polygon = memnew(Item::CommandPolygon); ERR_FAIL_COND(!polygon); - polygon->texture = p_texture; - polygon->normal_map = p_normal_map; + 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->antialiasing_use_indices = false; canvas_item->rect_dirty = true; canvas_item->commands.push_back(polygon); } -void VisualServerCanvas::canvas_item_add_triangle_array(RID p_item, 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, RID p_texture, int p_count, RID p_normal_map, bool p_antialiased, bool p_antialiasing_use_indices) { +void VisualServerCanvas::canvas_item_add_triangle_array(RID p_item, 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, RID p_texture, int p_count, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, bool p_antialiased, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -814,8 +822,8 @@ void VisualServerCanvas::canvas_item_add_triangle_array(RID p_item, const Vector Item::CommandPolygon *polygon = memnew(Item::CommandPolygon); ERR_FAIL_COND(!polygon); - polygon->texture = p_texture; - polygon->normal_map = p_normal_map; + 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; @@ -824,7 +832,6 @@ void VisualServerCanvas::canvas_item_add_triangle_array(RID p_item, const Vector polygon->indices = indices; polygon->count = count; polygon->antialiased = p_antialiased; - polygon->antialiasing_use_indices = p_antialiasing_use_indices; canvas_item->rect_dirty = true; canvas_item->commands.push_back(polygon); @@ -842,7 +849,7 @@ void VisualServerCanvas::canvas_item_add_set_transform(RID p_item, const Transfo canvas_item->commands.push_back(tr); } -void VisualServerCanvas::canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform, const Color &p_modulate, RID p_texture, RID p_normal_map) { +void VisualServerCanvas::canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform, const Color &p_modulate, RID p_texture, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -850,14 +857,14 @@ void VisualServerCanvas::canvas_item_add_mesh(RID p_item, const RID &p_mesh, con Item::CommandMesh *m = memnew(Item::CommandMesh); ERR_FAIL_COND(!m); m->mesh = p_mesh; - m->texture = p_texture; - m->normal_map = p_normal_map; + m->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID()); + m->specular_shininess = p_specular_color_shininess; m->transform = p_transform; m->modulate = p_modulate; canvas_item->commands.push_back(m); } -void VisualServerCanvas::canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal) { +void VisualServerCanvas::canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -865,8 +872,8 @@ void VisualServerCanvas::canvas_item_add_particles(RID p_item, RID p_particles, Item::CommandParticles *part = memnew(Item::CommandParticles); ERR_FAIL_COND(!part); part->particles = p_particles; - part->texture = p_texture; - part->normal_map = p_normal; + part->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID()); + part->specular_shininess = p_specular_color_shininess; //take the chance and request processing for them, at least once until they become visible again VSG::storage->particles_request_process(p_particles); @@ -875,7 +882,7 @@ void VisualServerCanvas::canvas_item_add_particles(RID p_item, RID p_particles, canvas_item->commands.push_back(part); } -void VisualServerCanvas::canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture, RID p_normal_map) { +void VisualServerCanvas::canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -883,8 +890,8 @@ void VisualServerCanvas::canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p Item::CommandMultiMesh *mm = memnew(Item::CommandMultiMesh); ERR_FAIL_COND(!mm); mm->multimesh = p_mesh; - mm->texture = p_texture; - mm->normal_map = p_normal_map; + mm->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, mm->multimesh); + mm->specular_shininess = p_specular_color_shininess; canvas_item->rect_dirty = true; canvas_item->commands.push_back(mm); diff --git a/servers/visual/visual_server_canvas.h b/servers/visual/visual_server_canvas.h index 7b5d2f6cb4..4a1bce51f9 100644 --- a/servers/visual/visual_server_canvas.h +++ b/servers/visual/visual_server_canvas.h @@ -52,6 +52,9 @@ public: Color ysort_modulate; Transform2D ysort_xform; Vector2 ysort_pos; + VS::CanvasItemTextureFilter texture_filter; + VS::CanvasItemTextureRepeat texture_repeat; + int z_final; Vector<Item *> child_items; @@ -68,6 +71,8 @@ public: ysort_children_count = -1; ysort_xform = Transform2D(); ysort_pos = Vector2(); + texture_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT; + texture_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT; } }; @@ -157,15 +162,15 @@ public: bool disable_scale; private: - void _render_canvas_item_tree(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(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 _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 _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); RasterizerCanvas::Item **z_list; RasterizerCanvas::Item **z_last_list; public: - void render_canvas(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, 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); RID canvas_create(); void canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring); @@ -190,20 +195,23 @@ public: void canvas_item_set_update_when_visible(RID p_item, bool p_update); + void canvas_item_set_default_texture_filter(RID p_item, VS::CanvasItemTextureFilter p_filter); + void canvas_item_set_default_texture_repeat(RID p_item, VS::CanvasItemTextureRepeat p_repeat); + void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false); void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false); void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false); void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color); void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color); - void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID()); - void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID(), bool p_clip_uv = false); - void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, VS::NinePatchAxisMode p_x_axis_mode = VS::NINE_PATCH_STRETCH, VS::NinePatchAxisMode p_y_axis_mode = VS::NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1), RID p_normal_map = RID()); - void 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 = 1.0, RID p_normal_map = RID()); - void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), RID p_normal_map = RID(), bool p_antialiased = false); - void canvas_item_add_triangle_array(RID p_item, 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>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID(), bool p_antialiased = false, bool p_antialiasing_use_indices = false); - void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID(), RID p_normal_map = RID()); - void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID()); - void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal); + void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), VS::CanvasItemTextureFilter p_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT); + void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), bool p_clip_uv = false, VS::CanvasItemTextureFilter p_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT); + void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, VS::NinePatchAxisMode p_x_axis_mode = VS::NINE_PATCH_STRETCH, VS::NinePatchAxisMode p_y_axis_mode = VS::NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), VS::CanvasItemTextureFilter p_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT); + void 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 = 1.0, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), VS::CanvasItemTextureFilter p_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT); + void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), bool p_antialiased = false, VS::CanvasItemTextureFilter p_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT); + void canvas_item_add_triangle_array(RID p_item, 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>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), bool p_antialiased = false, VS::CanvasItemTextureFilter p_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT); + void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID(), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), VS::CanvasItemTextureFilter p_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT); + void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), VS::CanvasItemTextureFilter p_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT); + void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map, RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), VS::CanvasItemTextureFilter p_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT); void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform); void canvas_item_add_clip_ignore(RID p_item, bool p_ignore); void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable); diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index 74a4265462..1b9f5b58b2 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -107,6 +107,8 @@ void VisualServerRaster::draw(bool p_swap_buffers, double frame_step) { VSG::viewport->draw_viewports(); VSG::scene->render_probes(); + VSG::canvas_render->update(); + _draw_margins(); VSG::rasterizer->end_frame(p_swap_buffers); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index ff2a4b01c4..32c14e6f21 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -136,6 +136,10 @@ public: void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11, m_type12 arg12) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); } #define BIND13(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11, m_type12, m_type13) \ void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11, m_type12 arg12, m_type13 arg13) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); } +#define BIND14(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11, m_type12, m_type13, m_type14) \ + void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11, m_type12 arg12, m_type13 arg13, m_type14 arg14) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); } +#define BIND15(m_name, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6, m_type7, m_type8, m_type9, m_type10, m_type11, m_type12, m_type13, m_type14, m_type15) \ + void m_name(m_type1 arg1, m_type2 arg2, m_type3 arg3, m_type4 arg4, m_type5 arg5, m_type6 arg6, m_type7 arg7, m_type8 arg8, m_type9 arg9, m_type10 arg10, m_type11 arg11, m_type12 arg12, m_type13 arg13, m_type14 arg14, m_type15 arg15) { DISPLAY_CHANGED BINDBASE->m_name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); } //from now on, calls forwarded to this singleton #define BINDBASE VSG::storage @@ -603,20 +607,23 @@ public: BIND2(canvas_item_set_draw_behind_parent, RID, bool) + BIND2(canvas_item_set_default_texture_filter, RID, CanvasItemTextureFilter) + BIND2(canvas_item_set_default_texture_repeat, RID, CanvasItemTextureRepeat) + BIND6(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float, bool) BIND5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool) BIND5(canvas_item_add_multiline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool) BIND3(canvas_item_add_rect, RID, const Rect2 &, const Color &) BIND4(canvas_item_add_circle, RID, const Point2 &, float, const Color &) - BIND7(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool, RID) - BIND8(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, RID, bool) - BIND11(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &, RID) - BIND7(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float, RID) - BIND7(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, RID, bool) - BIND12(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int, RID, bool, bool) - BIND6(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID, RID) - BIND4(canvas_item_add_multimesh, RID, RID, RID, RID) - BIND4(canvas_item_add_particles, RID, RID, RID, RID) + BIND11(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat) + BIND12(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, RID, RID, const Color &, bool, CanvasItemTextureFilter, CanvasItemTextureRepeat) + BIND15(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat) + BIND11(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat) + BIND11(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, RID, RID, const Color &, bool, CanvasItemTextureFilter, CanvasItemTextureRepeat) + BIND15(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int, RID, RID, const Color &, bool, CanvasItemTextureFilter, CanvasItemTextureRepeat) + BIND10(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat) + BIND8(canvas_item_add_multimesh, RID, RID, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat) + BIND8(canvas_item_add_particles, RID, RID, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat) BIND2(canvas_item_add_set_transform, RID, const Transform2D &) BIND2(canvas_item_add_clip_ignore, RID, bool) BIND2(canvas_item_set_sort_children_by_y, RID, bool) diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index e05eb4d523..ca0caefc77 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -81,6 +81,8 @@ 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)) { @@ -96,7 +98,9 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E bool can_draw_3d = !p_viewport->disable_3d && !p_viewport->disable_3d_by_usage && VSG::scene->camera_owner.owns(p_viewport->camera); if (p_viewport->clear_mode != VS::VIEWPORT_CLEAR_NEVER) { - VSG::rasterizer->clear_render_target(p_viewport->transparent_bg ? Color(0, 0, 0, 0) : clear_color); + if (p_viewport->transparent_bg) { + bgcolor = Color(0, 0, 0, 0); + } if (p_viewport->clear_mode == VS::VIEWPORT_CLEAR_ONLY_NEXT_FRAME) { p_viewport->clear_mode = VS::VIEWPORT_CLEAR_NEVER; } @@ -104,6 +108,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E 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) { @@ -209,8 +214,6 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E //VSG::canvas_render->reset_canvas(); } - VSG::rasterizer->restore_render_target(!scenario_draw_canvas_bg && can_draw_3d); - if (scenario_draw_canvas_bg && canvas_map.front() && canvas_map.front()->key().get_layer() > scenario_canvas_max_layer) { if (!can_draw_3d) { VSG::scene->render_empty_scene(p_viewport->scenario, p_viewport->shadow_atlas); @@ -237,7 +240,8 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E ptr = ptr->filter_next_ptr; } - VSG::canvas->render_canvas(canvas, xform, canvas_lights, lights_with_mask, clip_rect); + VSG::canvas->render_canvas(p_viewport->render_target, !cleared, bgcolor, canvas, xform, canvas_lights, lights_with_mask, clip_rect); + cleared = true; i++; if (scenario_draw_canvas_bg && E->key().get_layer() >= scenario_canvas_max_layer) { @@ -265,6 +269,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E void VisualServerViewport::draw_viewports() { +#if 0 // get our arvr interface in case we need it Ref<ARVRInterface> arvr_interface; @@ -274,6 +279,7 @@ void VisualServerViewport::draw_viewports() { // process all our active interfaces ARVRServer::get_singleton()->_process(); } +#endif if (Engine::get_singleton()->is_editor_hint()) { clear_color = GLOBAL_GET("rendering/environment/default_clear_color"); @@ -282,6 +288,7 @@ void VisualServerViewport::draw_viewports() { //sort viewports active_viewports.sort_custom<ViewportSort>(); + Map<int, Vector<Rasterizer::BlitToScreen> > blit_to_screen_list; //draw viewports for (int i = 0; i < active_viewports.size(); i++) { @@ -301,8 +308,8 @@ void VisualServerViewport::draw_viewports() { if (!visible) continue; - VSG::storage->render_target_clear_used(vp->render_target); - + VSG::storage->render_target_clear_used_flag(vp->render_target); +#if 0 if (vp->use_arvr && arvr_interface.is_valid()) { // override our size, make sure it matches our required size vp->size = arvr_interface->get_render_targetsize(); @@ -336,8 +343,9 @@ void VisualServerViewport::draw_viewports() { // and for our frame timing, mark when we've finished committing our eyes ARVRServer::get_singleton()->_mark_commit(); } else { +#endif + { VSG::storage->render_target_set_external_texture(vp->render_target, 0); - VSG::rasterizer->set_current_render_target(vp->render_target); VSG::scene_render->set_debug_draw_mode(vp->debug_draw); VSG::storage->render_info_begin_capture(); @@ -355,15 +363,26 @@ void VisualServerViewport::draw_viewports() { if (vp->viewport_to_screen_rect != Rect2() && (!vp->viewport_render_direct_to_screen || !VSG::rasterizer->is_low_end())) { //copy to screen if set as such - VSG::rasterizer->set_current_render_target(RID()); - VSG::rasterizer->blit_render_target_to_screen(vp->render_target, vp->viewport_to_screen_rect, vp->viewport_to_screen); + Rasterizer::BlitToScreen blit; + blit.render_target = vp->render_target; + blit.rect = vp->viewport_to_screen_rect; + + if (!blit_to_screen_list.has(vp->viewport_to_screen)) { + blit_to_screen_list[vp->viewport_to_screen] = Vector<Rasterizer::BlitToScreen>(); + } + + blit_to_screen_list[vp->viewport_to_screen].push_back(blit); } } if (vp->update_mode == VS::VIEWPORT_UPDATE_ONCE) { vp->update_mode = VS::VIEWPORT_UPDATE_DISABLED; } - VSG::scene_render->set_debug_draw_mode(VS::VIEWPORT_DEBUG_DRAW_DISABLED); + } + VSG::scene_render->set_debug_draw_mode(VS::VIEWPORT_DEBUG_DRAW_DISABLED); + + 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()); } } @@ -650,7 +669,8 @@ void VisualServerViewport::viewport_set_msaa(RID p_viewport, VS::ViewportMSAA p_ Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); - VSG::storage->render_target_set_msaa(viewport->render_target, p_msaa); +#warning this will no longer go in the render target, but in the 3D view + //VSG::storage->render_target_set_msaa(viewport->render_target, p_msaa); } void VisualServerViewport::viewport_set_hdr(RID p_viewport, bool p_enabled) { diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 9b999a33f6..6af6c3902e 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -520,20 +520,23 @@ public: FUNC2(canvas_item_set_draw_behind_parent, RID, bool) + FUNC2(canvas_item_set_default_texture_filter, RID, CanvasItemTextureFilter) + FUNC2(canvas_item_set_default_texture_repeat, RID, CanvasItemTextureRepeat) + FUNC6(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float, bool) FUNC5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool) FUNC5(canvas_item_add_multiline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool) FUNC3(canvas_item_add_rect, RID, const Rect2 &, const Color &) FUNC4(canvas_item_add_circle, RID, const Point2 &, float, const Color &) - FUNC7(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool, RID) - FUNC8(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, RID, bool) - FUNC11(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &, RID) - FUNC7(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float, RID) - FUNC7(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, RID, bool) - FUNC12(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int, RID, bool, bool) - FUNC6(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID, RID) - FUNC4(canvas_item_add_multimesh, RID, RID, RID, RID) - FUNC4(canvas_item_add_particles, RID, RID, RID, RID) + FUNC11(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat) + FUNC12(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, RID, RID, const Color &, bool, CanvasItemTextureFilter, CanvasItemTextureRepeat) + FUNC15(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat) + FUNC11(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat) + FUNC11(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, RID, RID, const Color &, bool, CanvasItemTextureFilter, CanvasItemTextureRepeat) + FUNC15(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int, RID, RID, const Color &, bool, CanvasItemTextureFilter, CanvasItemTextureRepeat) + FUNC10(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat) + FUNC8(canvas_item_add_multimesh, RID, RID, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat) + FUNC8(canvas_item_add_particles, RID, RID, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat) FUNC2(canvas_item_add_set_transform, RID, const Transform2D &) FUNC2(canvas_item_add_clip_ignore, RID, bool) FUNC2(canvas_item_set_sort_children_by_y, RID, bool) diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index ba200fe94a..077a85f151 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -1940,7 +1940,7 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("canvas_item_add_nine_patch", "item", "rect", "source", "texture", "topleft", "bottomright", "x_axis_mode", "y_axis_mode", "draw_center", "modulate", "normal_map"), &VisualServer::canvas_item_add_nine_patch, DEFVAL(NINE_PATCH_STRETCH), DEFVAL(NINE_PATCH_STRETCH), DEFVAL(true), DEFVAL(Color(1, 1, 1)), DEFVAL(RID())); ClassDB::bind_method(D_METHOD("canvas_item_add_primitive", "item", "points", "colors", "uvs", "texture", "width", "normal_map"), &VisualServer::canvas_item_add_primitive, DEFVAL(1.0), DEFVAL(RID())); ClassDB::bind_method(D_METHOD("canvas_item_add_polygon", "item", "points", "colors", "uvs", "texture", "normal_map", "antialiased"), &VisualServer::canvas_item_add_polygon, DEFVAL(Vector<Point2>()), DEFVAL(RID()), DEFVAL(RID()), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("canvas_item_add_triangle_array", "item", "indices", "points", "colors", "uvs", "bones", "weights", "texture", "count", "normal_map", "antialiased", "antialiasing_use_indices"), &VisualServer::canvas_item_add_triangle_array, DEFVAL(Vector<Point2>()), DEFVAL(Vector<int>()), DEFVAL(Vector<float>()), DEFVAL(RID()), DEFVAL(-1), DEFVAL(RID()), DEFVAL(false), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("canvas_item_add_triangle_array", "item", "indices", "points", "colors", "uvs", "bones", "weights", "texture", "count", "normal_map", "antialiased"), &VisualServer::canvas_item_add_triangle_array, DEFVAL(Vector<Point2>()), DEFVAL(Vector<int>()), DEFVAL(Vector<float>()), DEFVAL(RID()), DEFVAL(-1), DEFVAL(RID()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("canvas_item_add_mesh", "item", "mesh", "transform", "modulate", "texture", "normal_map"), &VisualServer::canvas_item_add_mesh, DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1)), DEFVAL(RID()), DEFVAL(RID())); ClassDB::bind_method(D_METHOD("canvas_item_add_multimesh", "item", "mesh", "texture", "normal_map"), &VisualServer::canvas_item_add_multimesh, DEFVAL(RID())); ClassDB::bind_method(D_METHOD("canvas_item_add_particles", "item", "particles", "texture", "normal_map"), &VisualServer::canvas_item_add_particles); @@ -2075,11 +2075,7 @@ void VisualServer::_bind_methods() { BIND_ENUM_CONSTANT(PRIMITIVE_POINTS); BIND_ENUM_CONSTANT(PRIMITIVE_LINES); - BIND_ENUM_CONSTANT(PRIMITIVE_LINE_STRIP); - BIND_ENUM_CONSTANT(PRIMITIVE_LINE_LOOP); BIND_ENUM_CONSTANT(PRIMITIVE_TRIANGLES); - BIND_ENUM_CONSTANT(PRIMITIVE_TRIANGLE_STRIP); - BIND_ENUM_CONSTANT(PRIMITIVE_TRIANGLE_FAN); BIND_ENUM_CONSTANT(PRIMITIVE_MAX); BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_NORMALIZED); diff --git a/servers/visual_server.h b/servers/visual_server.h index 4299870de0..d96f7cbf10 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -249,14 +249,10 @@ public: }; enum PrimitiveType { - PRIMITIVE_POINTS = 0, - PRIMITIVE_LINES = 1, - PRIMITIVE_LINE_STRIP = 2, - PRIMITIVE_LINE_LOOP = 3, - PRIMITIVE_TRIANGLES = 4, - PRIMITIVE_TRIANGLE_STRIP = 5, - PRIMITIVE_TRIANGLE_FAN = 6, - PRIMITIVE_MAX = 7, + PRIMITIVE_POINTS, + PRIMITIVE_LINES, + PRIMITIVE_TRIANGLES, + PRIMITIVE_MAX, }; virtual RID mesh_create() = 0; @@ -884,20 +880,41 @@ public: NINE_PATCH_TILE_FIT, }; + enum CanvasItemTextureFilter { + CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, //uses canvas item setting for draw command, uses global setting for canvas item + CANVAS_ITEM_TEXTURE_FILTER_NEAREST, + CANVAS_ITEM_TEXTURE_FILTER_LINEAR, + CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, + CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS, + CANVAS_ITEM_TEXTURE_FILTER_MAX + }; + + enum CanvasItemTextureRepeat { + CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, //uses canvas item setting for draw command, uses global setting for canvas item + CANVAS_ITEM_TEXTURE_REPEAT_DISABLED, + CANVAS_ITEM_TEXTURE_REPEAT_ENABLED, + CANVAS_ITEM_TEXTURE_REPEAT_MIRROR, + CANVAS_ITEM_TEXTURE_REPEAT_MAX, + }; + + //takes effect only for new draw commands + virtual void canvas_item_set_default_texture_filter(RID p_item, CanvasItemTextureFilter p_filter) = 0; + virtual void canvas_item_set_default_texture_repeat(RID p_item, CanvasItemTextureRepeat p_repeat) = 0; + virtual void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false) = 0; virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false) = 0; virtual void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false) = 0; virtual void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) = 0; virtual void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) = 0; - virtual void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID()) = 0; - virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID(), bool p_clip_uv = false) = 0; - virtual void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, NinePatchAxisMode p_x_axis_mode = NINE_PATCH_STRETCH, NinePatchAxisMode p_y_axis_mode = NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1), RID p_normal_map = RID()) = 0; - virtual void 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 = 1.0, RID p_normal_map = RID()) = 0; - virtual void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), RID p_normal_map = RID(), bool p_antialiased = false) = 0; - virtual void canvas_item_add_triangle_array(RID p_item, 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>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID(), bool p_antialiased = false, bool p_antialiasing_use_indices = false) = 0; - virtual void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID(), RID p_normal_map = RID()) = 0; - virtual void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID()) = 0; - virtual void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map) = 0; + virtual void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0; + virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), bool p_clip_uv = false, CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0; + virtual void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, NinePatchAxisMode p_x_axis_mode = NINE_PATCH_STRETCH, NinePatchAxisMode p_y_axis_mode = NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0; + virtual void 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 = 1.0, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0; + virtual void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), bool p_antialiased = false, CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0; + virtual void canvas_item_add_triangle_array(RID p_item, 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>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), bool p_antialiased = false, CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0; + virtual void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID(), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0; + virtual void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0; + virtual void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map, RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0; virtual void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) = 0; virtual void canvas_item_add_clip_ignore(RID p_item, bool p_ignore) = 0; virtual void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) = 0; @@ -1088,6 +1105,8 @@ VARIANT_ENUM_CAST(VisualServer::EnvironmentSSAOQuality); VARIANT_ENUM_CAST(VisualServer::EnvironmentSSAOBlur); VARIANT_ENUM_CAST(VisualServer::InstanceFlags); VARIANT_ENUM_CAST(VisualServer::ShadowCastingSetting); +VARIANT_ENUM_CAST(VisualServer::CanvasItemTextureFilter); +VARIANT_ENUM_CAST(VisualServer::CanvasItemTextureRepeat); //typedef VisualServer VS; // makes it easier to use #define VS VisualServer |