summaryrefslogtreecommitdiff
path: root/servers
diff options
context:
space:
mode:
authorreduz <reduzio@gmail.com>2021-06-15 17:33:24 -0300
committerreduz <reduzio@gmail.com>2021-06-16 10:48:57 -0300
commit38d164c74b24f10215312f304ec1b04175989376 (patch)
treece2c76d08a3bbc7dfe33994ce3d1b17b9ef03819 /servers
parentbadad5343814cb68ec19646067078f241a74071a (diff)
Refactor VisibilityNotifier
* Works from RenderinServer * Accurately tells when on or off-scren, its no longer approximate. * VisibilityEnabler also simplified to use the process mode instead.
Diffstat (limited to 'servers')
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp125
-rw-r--r--servers/rendering/renderer_canvas_cull.h24
-rw-r--r--servers/rendering/rendering_server_default.cpp3
-rw-r--r--servers/rendering/rendering_server_default.h2
-rw-r--r--servers/rendering/rendering_server_globals.cpp2
-rw-r--r--servers/rendering/rendering_server_globals.h2
-rw-r--r--servers/rendering_server.h2
7 files changed, 138 insertions, 22 deletions
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index 6e126ea77e..5703737252 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -104,7 +104,7 @@ void _mark_ysort_dirty(RendererCanvasCull::Item *ysort_owner, RID_PtrOwner<Rende
} while (ysort_owner && ysort_owner->sort_y);
}
-void _attach_canvas_item_for_draw(RendererCanvasCull::Item *ci, RendererCanvasCull::Item *p_canvas_clip, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool use_canvas_group, RendererCanvasRender::Item *canvas_group_from) {
+void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item *ci, RendererCanvasCull::Item *p_canvas_clip, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool use_canvas_group, RendererCanvasRender::Item *canvas_group_from, const Transform2D &p_xform) {
if (ci->copy_back_buffer) {
ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).intersection(p_clip_rect);
}
@@ -173,32 +173,44 @@ void _attach_canvas_item_for_draw(RendererCanvasCull::Item *ci, RendererCanvasCu
}
}
- if (ci->update_when_visible) {
- RenderingServerDefault::redraw_request();
- }
-
- if ((ci->commands != nullptr && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) {
+ if (((ci->commands != nullptr || ci->visibility_notifier) && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) {
//something to draw?
- ci->final_transform = xform;
- ci->final_modulate = Color(modulate.r * ci->self_modulate.r, modulate.g * ci->self_modulate.g, modulate.b * ci->self_modulate.b, modulate.a * ci->self_modulate.a);
- ci->global_rect_cache = global_rect;
- ci->global_rect_cache.position -= p_clip_rect.position;
- ci->light_masked = false;
- int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
+ if (ci->update_when_visible) {
+ RenderingServerDefault::redraw_request();
+ }
- if (z_last_list[zidx]) {
- z_last_list[zidx]->next = ci;
- z_last_list[zidx] = ci;
+ if (ci->commands != nullptr) {
+ ci->final_transform = xform;
+ ci->final_modulate = Color(modulate.r * ci->self_modulate.r, modulate.g * ci->self_modulate.g, modulate.b * ci->self_modulate.b, modulate.a * ci->self_modulate.a);
+ ci->global_rect_cache = global_rect;
+ ci->global_rect_cache.position -= p_clip_rect.position;
+ ci->light_masked = false;
- } else {
- z_list[zidx] = ci;
- z_last_list[zidx] = ci;
+ int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
+
+ if (z_last_list[zidx]) {
+ z_last_list[zidx]->next = ci;
+ z_last_list[zidx] = ci;
+
+ } else {
+ z_list[zidx] = ci;
+ z_last_list[zidx] = ci;
+ }
+
+ ci->z_final = p_z;
+
+ ci->next = nullptr;
}
- ci->z_final = p_z;
+ if (ci->visibility_notifier) {
+ if (!ci->visibility_notifier->visible_element.in_list()) {
+ visibility_notifier_list.add(&ci->visibility_notifier->visible_element);
+ ci->visibility_notifier->just_visible = true;
+ }
- ci->next = nullptr;
+ ci->visibility_notifier->visible_in_frame = RSG::rasterizer->get_frame_number();
+ }
}
}
@@ -215,6 +227,13 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
}
Rect2 rect = ci->get_rect();
+
+ if (ci->visibility_notifier) {
+ if (ci->visibility_notifier->area.size != Vector2()) {
+ rect = rect.merge(ci->visibility_notifier->area);
+ }
+ }
+
Transform2D xform = ci->xform;
if (snapping_2d_transforms_to_pixel) {
xform.elements[2] = xform.elements[2].floor();
@@ -289,7 +308,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
canvas_group_from = z_last_list[zidx];
}
- _attach_canvas_item_for_draw(ci, p_canvas_clip, z_list, z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from);
+ _attach_canvas_item_for_draw(ci, p_canvas_clip, z_list, z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from, xform);
}
} else {
RendererCanvasRender::Item *canvas_group_from = nullptr;
@@ -305,7 +324,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
}
_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, true);
}
- _attach_canvas_item_for_draw(ci, p_canvas_clip, z_list, z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from);
+ _attach_canvas_item_for_draw(ci, p_canvas_clip, z_list, z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from, xform);
for (int i = 0; i < child_item_count; i++) {
if (child_items[i]->behind || use_canvas_group) {
continue;
@@ -1095,6 +1114,26 @@ void RendererCanvasCull::canvas_item_set_use_parent_material(RID p_item, bool p_
canvas_item->use_parent_material = p_enable;
}
+void RendererCanvasCull::canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callable, const Callable &p_exit_callable) {
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ if (p_enable) {
+ if (!canvas_item->visibility_notifier) {
+ canvas_item->visibility_notifier = visibility_notifier_allocator.alloc();
+ }
+ canvas_item->visibility_notifier->area = p_area;
+ canvas_item->visibility_notifier->enter_callable = p_enter_callable;
+ canvas_item->visibility_notifier->exit_callable = p_exit_callable;
+
+ } else {
+ if (canvas_item->visibility_notifier) {
+ visibility_notifier_allocator.free(canvas_item->visibility_notifier);
+ canvas_item->visibility_notifier = nullptr;
+ }
+ }
+}
+
void RendererCanvasCull::canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin, bool p_fit_empty, float p_fit_margin, bool p_blur_mipmaps) {
Item *canvas_item = canvas_item_owner.getornull(p_item);
ERR_FAIL_COND(!canvas_item);
@@ -1477,6 +1516,44 @@ void RendererCanvasCull::canvas_item_set_default_texture_repeat(RID p_item, RS::
ci->texture_repeat = p_repeat;
}
+void RendererCanvasCull::update_visibility_notifiers() {
+ SelfList<Item::VisibilityNotifierData> *E = visibility_notifier_list.first();
+ while (E) {
+ SelfList<Item::VisibilityNotifierData> *N = E->next();
+
+ Item::VisibilityNotifierData *visibility_notifier = E->self();
+ if (visibility_notifier->just_visible) {
+ visibility_notifier->just_visible = false;
+
+ if (!visibility_notifier->enter_callable.is_null()) {
+ if (RSG::threaded) {
+ visibility_notifier->enter_callable.call_deferred(nullptr, 0);
+ } else {
+ Callable::CallError ce;
+ Variant ret;
+ visibility_notifier->enter_callable.call(nullptr, 0, ret, ce);
+ }
+ }
+ } else {
+ if (visibility_notifier->visible_in_frame != RSG::rasterizer->get_frame_number()) {
+ visibility_notifier_list.remove(E);
+
+ if (!visibility_notifier->exit_callable.is_null()) {
+ if (RSG::threaded) {
+ visibility_notifier->exit_callable.call_deferred(nullptr, 0);
+ } else {
+ Callable::CallError ce;
+ Variant ret;
+ visibility_notifier->exit_callable.call(nullptr, 0, ret, ce);
+ }
+ }
+ }
+ }
+
+ E = N;
+ }
+}
+
bool RendererCanvasCull::free(RID p_rid) {
if (canvas_owner.owns(p_rid)) {
Canvas *canvas = canvas_owner.getornull(p_rid);
@@ -1531,6 +1608,10 @@ bool RendererCanvasCull::free(RID p_rid) {
canvas_item->child_items[i]->parent = RID();
}
+ if (canvas_item->visibility_notifier != nullptr) {
+ visibility_notifier_allocator.free(canvas_item->visibility_notifier);
+ }
+
/*
if (canvas_item->material) {
canvas_item->material->owners.erase(canvas_item);
diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h
index 37391d7c0e..661216cad3 100644
--- a/servers/rendering/renderer_canvas_cull.h
+++ b/servers/rendering/renderer_canvas_cull.h
@@ -31,6 +31,7 @@
#ifndef RENDERING_SERVER_CANVAS_CULL_H
#define RENDERING_SERVER_CANVAS_CULL_H
+#include "core/templates/paged_allocator.h"
#include "renderer_compositor.h"
#include "renderer_viewport.h"
@@ -55,6 +56,20 @@ public:
Vector<Item *> child_items;
+ struct VisibilityNotifierData {
+ Rect2 area;
+ Callable enter_callable;
+ Callable exit_callable;
+ bool just_visible = false;
+ uint64_t visible_in_frame = 0;
+ SelfList<VisibilityNotifierData> visible_element;
+ VisibilityNotifierData() :
+ visible_element(this) {
+ }
+ };
+
+ VisibilityNotifierData *visibility_notifier = nullptr;
+
Item() {
children_order_dirty = true;
E = nullptr;
@@ -156,6 +171,11 @@ public:
bool sdf_used = false;
bool snapping_2d_transforms_to_pixel = false;
+ PagedAllocator<Item::VisibilityNotifierData> visibility_notifier_allocator;
+ SelfList<Item::VisibilityNotifierData>::List visibility_notifier_list;
+
+ _FORCE_INLINE_ void _attach_canvas_item_for_draw(Item *ci, Item *p_canvas_clip, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool use_canvas_group, RendererCanvasRender::Item *canvas_group_from, const Transform2D &p_xform);
+
private:
void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel);
void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool allow_y_sort);
@@ -224,6 +244,8 @@ public:
void canvas_item_set_use_parent_material(RID p_item, bool p_enable);
+ void canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callable, const Callable &p_exit_callable);
+
void canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false);
RID canvas_light_allocate();
@@ -283,6 +305,8 @@ public:
void canvas_item_set_default_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter);
void canvas_item_set_default_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat);
+ void update_visibility_notifiers();
+
bool free(RID p_rid);
RendererCanvasCull();
~RendererCanvasCull();
diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp
index cd66cd0716..95aa05f6b3 100644
--- a/servers/rendering/rendering_server_default.cpp
+++ b/servers/rendering/rendering_server_default.cpp
@@ -117,6 +117,8 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
_draw_margins();
RSG::rasterizer->end_frame(p_swap_buffers);
+ RSG::canvas->update_visibility_notifiers();
+
while (frame_drawn_callbacks.front()) {
Object *obj = ObjectDB::get_instance(frame_drawn_callbacks.front()->get().object);
if (obj) {
@@ -396,6 +398,7 @@ RenderingServerDefault::RenderingServerDefault(bool p_create_thread) :
server_thread = 0;
}
+ RSG::threaded = p_create_thread;
RSG::canvas = memnew(RendererCanvasCull);
RSG::viewport = memnew(RendererViewport);
RendererSceneCull *sr = memnew(RendererSceneCull);
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index e4d319ed6c..73373c97bb 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -820,6 +820,8 @@ public:
FUNC2(canvas_item_set_use_parent_material, RID, bool)
+ FUNC5(canvas_item_set_visibility_notifier, RID, bool, const Rect2 &, const Callable &, const Callable &)
+
FUNC6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool)
FUNCRIDSPLIT(canvas_light)
diff --git a/servers/rendering/rendering_server_globals.cpp b/servers/rendering/rendering_server_globals.cpp
index c0d9988e85..2dda506bac 100644
--- a/servers/rendering/rendering_server_globals.cpp
+++ b/servers/rendering/rendering_server_globals.cpp
@@ -30,6 +30,8 @@
#include "rendering_server_globals.h"
+bool RenderingServerGlobals::threaded = false;
+
RendererStorage *RenderingServerGlobals::storage = nullptr;
RendererCanvasRender *RenderingServerGlobals::canvas_render = nullptr;
RendererCompositor *RenderingServerGlobals::rasterizer = nullptr;
diff --git a/servers/rendering/rendering_server_globals.h b/servers/rendering/rendering_server_globals.h
index a28a0f5180..63755e6125 100644
--- a/servers/rendering/rendering_server_globals.h
+++ b/servers/rendering/rendering_server_globals.h
@@ -41,6 +41,8 @@ class RendererScene;
class RenderingServerGlobals {
public:
+ static bool threaded;
+
static RendererStorage *storage;
static RendererCanvasRender *canvas_render;
static RendererCompositor *rasterizer;
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 1806f1da18..0cb765ef56 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -1301,6 +1301,8 @@ public:
virtual void canvas_item_set_use_parent_material(RID p_item, bool p_enable) = 0;
+ virtual void canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callbable, const Callable &p_exit_callable) = 0;
+
enum CanvasGroupMode {
CANVAS_GROUP_MODE_DISABLED,
CANVAS_GROUP_MODE_OPAQUE,