Browse Source

Fix viewport sorting being wrong on parent/child relation

MinusKube 3 years ago
parent
commit
be09a87ff9
2 changed files with 49 additions and 18 deletions
  1. 46 6
      servers/rendering/renderer_viewport.cpp
  2. 3 12
      servers/rendering/renderer_viewport.h

+ 46 - 6
servers/rendering/renderer_viewport.cpp

@@ -72,6 +72,41 @@ static Transform2D _canvas_get_transform(RendererViewport::Viewport *p_viewport,
 	return xf;
 }
 
+Vector<RendererViewport::Viewport *> RendererViewport::_sort_active_viewports() {
+	// We need to sort the viewports in a "topological order",
+	// children first and parents last, we use the Kahn's algorithm to achieve that.
+
+	Vector<Viewport *> result;
+	List<Viewport *> nodes;
+
+	for (Viewport *viewport : active_viewports) {
+		if (viewport->parent.is_valid()) {
+			continue;
+		}
+
+		nodes.push_back(viewport);
+	}
+
+	while (!nodes.is_empty()) {
+		Viewport *node = nodes[0];
+		nodes.pop_front();
+
+		result.insert(0, node);
+
+		for (Viewport *child : active_viewports) {
+			if (child->parent != node->self) {
+				continue;
+			}
+
+			if (!nodes.find(child)) {
+				nodes.push_back(child);
+			}
+		}
+	}
+
+	return result;
+}
+
 void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
 	if (p_viewport->render_buffers.is_valid()) {
 		if (p_viewport->size.width == 0 || p_viewport->size.height == 0) {
@@ -544,8 +579,10 @@ void RendererViewport::draw_viewports() {
 		set_default_clear_color(GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
 	}
 
-	//sort viewports
-	active_viewports.sort_custom<ViewportSort>();
+	if (sorted_active_viewports_dirty) {
+		sorted_active_viewports = _sort_active_viewports();
+		sorted_active_viewports_dirty = false;
+	}
 
 	HashMap<DisplayServer::WindowID, Vector<BlitToScreen>> blit_to_screen_list;
 	//draw viewports
@@ -554,9 +591,9 @@ void RendererViewport::draw_viewports() {
 	//determine what is visible
 	draw_viewports_pass++;
 
-	for (int i = active_viewports.size() - 1; i >= 0; i--) { //to compute parent dependency, must go in reverse draw order
+	for (int i = sorted_active_viewports.size() - 1; i >= 0; i--) { //to compute parent dependency, must go in reverse draw order
 
-		Viewport *vp = active_viewports[i];
+		Viewport *vp = sorted_active_viewports[i];
 
 		if (vp->update_mode == RS::VIEWPORT_UPDATE_DISABLED) {
 			continue;
@@ -617,8 +654,8 @@ void RendererViewport::draw_viewports() {
 	int objects_drawn = 0;
 	int draw_calls_used = 0;
 
-	for (int i = 0; i < active_viewports.size(); i++) {
-		Viewport *vp = active_viewports[i];
+	for (int i = 0; i < sorted_active_viewports.size(); i++) {
+		Viewport *vp = sorted_active_viewports[i];
 
 		if (vp->last_pass != draw_viewports_pass) {
 			continue; //should not draw
@@ -810,6 +847,8 @@ void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) {
 	} else {
 		active_viewports.erase(viewport);
 	}
+
+	sorted_active_viewports_dirty = true;
 }
 
 void RendererViewport::viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) {
@@ -1239,6 +1278,7 @@ bool RendererViewport::free(RID p_rid) {
 
 		viewport_set_scenario(p_rid, RID());
 		active_viewports.erase(viewport);
+		sorted_active_viewports_dirty = true;
 
 		if (viewport->use_occlusion_culling) {
 			RendererSceneOcclusionCull::get_singleton()->remove_buffer(p_rid);

+ 3 - 12
servers/rendering/renderer_viewport.h

@@ -184,25 +184,16 @@ public:
 
 	mutable RID_Owner<Viewport, true> viewport_owner;
 
-	struct ViewportSort {
-		_FORCE_INLINE_ bool operator()(const Viewport *p_left, const Viewport *p_right) const {
-			bool left_to_screen = p_left->viewport_to_screen_rect.size != Size2();
-			bool right_to_screen = p_right->viewport_to_screen_rect.size != Size2();
-
-			if (left_to_screen == right_to_screen) {
-				return p_right->parent == p_left->self;
-			}
-			return (right_to_screen ? 0 : 1) < (left_to_screen ? 0 : 1);
-		}
-	};
-
 	Vector<Viewport *> active_viewports;
+	Vector<Viewport *> sorted_active_viewports;
+	bool sorted_active_viewports_dirty = false;
 
 	int total_objects_drawn = 0;
 	int total_vertices_drawn = 0;
 	int total_draw_calls_used = 0;
 
 private:
+	Vector<Viewport *> _sort_active_viewports();
 	void _configure_3d_render_buffers(Viewport *p_viewport);
 	void _draw_3d(Viewport *p_viewport);
 	void _draw_viewport(Viewport *p_viewport);