diff options
| -rw-r--r-- | core/math/dynamic_bvh.cpp | 25 | ||||
| -rw-r--r-- | core/math/dynamic_bvh.h | 125 | ||||
| -rw-r--r-- | core/templates/paged_allocator.h | 129 | ||||
| -rw-r--r-- | core/templates/paged_array.h | 2 | ||||
| -rw-r--r-- | core/templates/rid_owner.h | 13 | ||||
| -rw-r--r-- | servers/rendering/renderer_rd/renderer_scene_render_forward.cpp | 62 | ||||
| -rw-r--r-- | servers/rendering/renderer_rd/renderer_scene_render_forward.h | 18 | ||||
| -rw-r--r-- | servers/rendering/renderer_rd/renderer_scene_render_rd.cpp | 123 | ||||
| -rw-r--r-- | servers/rendering/renderer_rd/renderer_scene_render_rd.h | 43 | ||||
| -rw-r--r-- | servers/rendering/renderer_scene_cull.cpp | 819 | ||||
| -rw-r--r-- | servers/rendering/renderer_scene_cull.h | 205 | ||||
| -rw-r--r-- | servers/rendering/renderer_scene_render.h | 17 | ||||
| -rw-r--r-- | servers/rendering_server.cpp | 3 | 
13 files changed, 1027 insertions, 557 deletions
diff --git a/core/math/dynamic_bvh.cpp b/core/math/dynamic_bvh.cpp index 8486415c81..5f87f75b61 100644 --- a/core/math/dynamic_bvh.cpp +++ b/core/math/dynamic_bvh.cpp @@ -49,7 +49,6 @@ DynamicBVH::Node *DynamicBVH::_create_node(Node *p_parent, void *p_data) {  	Node *node = memnew(Node);  	node->parent = p_parent;  	node->data = p_data; -	node->childs[1] = 0;  	return (node);  } @@ -335,6 +334,7 @@ DynamicBVH::ID DynamicBVH::insert(const AABB &p_box, void *p_userdata) {  	ID id;  	id.node = leaf; +  	return id;  } @@ -389,12 +389,35 @@ void DynamicBVH::_extract_leaves(Node *p_node, List<ID> *r_elements) {  	}  } +void DynamicBVH::set_index(uint32_t p_index) { +	ERR_FAIL_COND(bvh_root != nullptr); +	index = p_index; +} + +uint32_t DynamicBVH::get_index() const { +	return index; +} +  void DynamicBVH::get_elements(List<ID> *r_elements) {  	if (bvh_root) {  		_extract_leaves(bvh_root, r_elements);  	}  } +int DynamicBVH::get_leaf_count() const { +	return total_leaves; +} +int DynamicBVH::get_max_depth() const { +	if (bvh_root) { +		int depth = 1; +		int max_depth = 0; +		bvh_root->get_max_depth(depth, max_depth); +		return max_depth; +	} else { +		return 0; +	} +} +  DynamicBVH::~DynamicBVH() {  	clear();  } diff --git a/core/math/dynamic_bvh.h b/core/math/dynamic_bvh.h index 81d70d7469..cdea51c674 100644 --- a/core/math/dynamic_bvh.h +++ b/core/math/dynamic_bvh.h @@ -61,13 +61,10 @@ class DynamicBVH {  public:  	struct ID { -		Node *node; +		Node *node = nullptr;  	public:  		_FORCE_INLINE_ bool is_valid() const { return node != nullptr; } -		_FORCE_INLINE_ ID() { -			node = nullptr; -		}  	};  private: @@ -134,6 +131,48 @@ private:  					(min.z <= b.max.z) &&  					(max.z >= b.min.z));  		} + +		_FORCE_INLINE_ bool intersects_convex(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const { +			Vector3 half_extents = (max - min) * 0.5; +			Vector3 ofs = min + half_extents; + +			for (int i = 0; i < p_plane_count; i++) { +				const Plane &p = p_planes[i]; +				Vector3 point( +						(p.normal.x > 0) ? -half_extents.x : half_extents.x, +						(p.normal.y > 0) ? -half_extents.y : half_extents.y, +						(p.normal.z > 0) ? -half_extents.z : half_extents.z); +				point += ofs; +				if (p.is_point_over(point)) { +					return false; +				} +			} + +			// Make sure all points in the shape aren't fully separated from the AABB on +			// each axis. +			int bad_point_counts_positive[3] = { 0 }; +			int bad_point_counts_negative[3] = { 0 }; + +			for (int k = 0; k < 3; k++) { +				for (int i = 0; i < p_point_count; i++) { +					if (p_points[i].coord[k] > ofs.coord[k] + half_extents.coord[k]) { +						bad_point_counts_positive[k]++; +					} +					if (p_points[i].coord[k] < ofs.coord[k] - half_extents.coord[k]) { +						bad_point_counts_negative[k]++; +					} +				} + +				if (bad_point_counts_negative[k] == p_point_count) { +					return false; +				} +				if (bad_point_counts_positive[k] == p_point_count) { +					return false; +				} +			} + +			return true; +		}  	};  	struct Node { @@ -144,14 +183,14 @@ private:  			void *data;  		}; -		_FORCE_INLINE_ bool is_leaf() const { return data != nullptr; } +		_FORCE_INLINE_ bool is_leaf() const { return childs[1] == nullptr; }  		_FORCE_INLINE_ bool is_internal() const { return (!is_leaf()); }  		_FORCE_INLINE_ int get_index_in_parent() const {  			ERR_FAIL_COND_V(!parent, 0);  			return (parent->childs[1] == this) ? 1 : 0;  		} -		_FORCE_INLINE_ void get_max_depth(int depth, int &maxdepth) { +		void get_max_depth(int depth, int &maxdepth) {  			if (is_internal()) {  				childs[0]->get_max_depth(depth + 1, maxdepth);  				childs[1]->get_max_depth(depth + 1, maxdepth); @@ -183,6 +222,7 @@ private:  	int lkhd = -1;  	int total_leaves = 0;  	uint32_t opath = 0; +	uint32_t index = 0;  	enum {  		ALLOCA_STACK_SIZE = 128 @@ -245,6 +285,9 @@ public:  	void remove(const ID &p_id);  	void get_elements(List<ID> *r_elements); +	int get_leaf_count() const; +	int get_max_depth() const; +  	/* Discouraged, but works as a reference on how it must be used */  	struct DefaultQueryResult {  		virtual bool operator()(void *p_data) = 0; //return true whether you want to continue the query @@ -254,9 +297,13 @@ public:  	template <class QueryResult>  	_FORCE_INLINE_ void aabb_query(const AABB &p_aabb, QueryResult &r_result);  	template <class QueryResult> +	_FORCE_INLINE_ void convex_query(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, QueryResult &r_result); +	template <class QueryResult>  	_FORCE_INLINE_ void ray_query(const Vector3 &p_from, const Vector3 &p_to, QueryResult &r_result); -	DynamicBVH(); +	void set_index(uint32_t p_index); +	uint32_t get_index() const; +  	~DynamicBVH();  }; @@ -278,8 +325,8 @@ void DynamicBVH::aabb_query(const AABB &p_box, QueryResult &r_result) {  	LocalVector<const Node *> aux_stack; //only used in rare occasions when you run out of alloca memory because tree is too unbalanced. Should correct itself over time.  	do { -		const Node *n = stack[depth - 1];  		depth--; +		const Node *n = stack[depth];  		if (n->volume.intersects(volume)) {  			if (n->is_internal()) {  				if (depth > threshold) { @@ -304,7 +351,66 @@ void DynamicBVH::aabb_query(const AABB &p_box, QueryResult &r_result) {  }  template <class QueryResult> +void DynamicBVH::convex_query(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, QueryResult &r_result) { +	if (!bvh_root) { +		return; +	} + +	//generate a volume anyway to improve pre-testing +	Volume volume; +	for (int i = 0; i < p_point_count; i++) { +		if (i == 0) { +			volume.min = p_points[0]; +			volume.max = p_points[0]; +		} else { +			volume.min.x = MIN(volume.min.x, p_points[i].x); +			volume.min.y = MIN(volume.min.y, p_points[i].y); +			volume.min.z = MIN(volume.min.z, p_points[i].z); + +			volume.max.x = MAX(volume.max.x, p_points[i].x); +			volume.max.y = MAX(volume.max.y, p_points[i].y); +			volume.max.z = MAX(volume.max.z, p_points[i].z); +		} +	} + +	const Node **stack = (const Node **)alloca(ALLOCA_STACK_SIZE * sizeof(const Node *)); +	stack[0] = bvh_root; +	int32_t depth = 1; +	int32_t threshold = ALLOCA_STACK_SIZE - 2; + +	LocalVector<const Node *> aux_stack; //only used in rare occasions when you run out of alloca memory because tree is too unbalanced. Should correct itself over time. + +	do { +		depth--; +		const Node *n = stack[depth]; +		if (n->volume.intersects(volume) && n->volume.intersects_convex(p_planes, p_plane_count, p_points, p_point_count)) { +			if (n->is_internal()) { +				if (depth > threshold) { +					if (aux_stack.empty()) { +						aux_stack.resize(ALLOCA_STACK_SIZE * 2); +						copymem(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *)); +					} else { +						aux_stack.resize(aux_stack.size() * 2); +					} +					stack = aux_stack.ptr(); +					threshold = aux_stack.size() - 2; +				} +				stack[depth++] = n->childs[0]; +				stack[depth++] = n->childs[1]; +			} else { +				if (r_result(n->data)) { +					return; +				} +			} +		} +	} while (depth > 0); +} +template <class QueryResult>  void DynamicBVH::ray_query(const Vector3 &p_from, const Vector3 &p_to, QueryResult &r_result) { +	if (!bvh_root) { +		return; +	} +  	Vector3 ray_dir = (p_to - p_from);  	ray_dir.normalize(); @@ -327,7 +433,8 @@ void DynamicBVH::ray_query(const Vector3 &p_from, const Vector3 &p_to, QueryResu  	LocalVector<const Node *> aux_stack; //only used in rare occasions when you run out of alloca memory because tree is too unbalanced. Should correct itself over time.  	do { -		const Node *node = stack[--depth]; +		depth--; +		const Node *node = stack[depth];  		bounds[0] = node->volume.min;  		bounds[1] = node->volume.max;  		real_t tmin = 1.f, lambda_min = 0.f; diff --git a/core/templates/paged_allocator.h b/core/templates/paged_allocator.h new file mode 100644 index 0000000000..8bd1eecdeb --- /dev/null +++ b/core/templates/paged_allocator.h @@ -0,0 +1,129 @@ +/*************************************************************************/ +/*  paged_allocator.h                                                    */ +/*************************************************************************/ +/*                       This file is part of:                           */ +/*                           GODOT ENGINE                                */ +/*                      https://godotengine.org                          */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2020 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 PAGED_ALLOCATOR_H +#define PAGED_ALLOCATOR_H + +#include "core/os/memory.h" +#include "core/os/spin_lock.h" +#include "core/typedefs.h" + +template <class T, bool thread_safe = false> +class PagedAllocator { +	T **page_pool = nullptr; +	T ***available_pool = nullptr; +	uint32_t pages_allocated = 0; +	uint32_t allocs_available = 0; + +	uint32_t page_shift = 0; +	uint32_t page_mask = 0; +	uint32_t page_size = 0; +	SpinLock spin_lock; + +public: +	T *alloc() { +		if (thread_safe) { +			spin_lock.lock(); +		} +		if (unlikely(allocs_available == 0)) { +			uint32_t pages_used = pages_allocated; + +			pages_allocated++; +			page_pool = (T **)memrealloc(page_pool, sizeof(T *) * pages_allocated); +			available_pool = (T ***)memrealloc(available_pool, sizeof(T **) * pages_allocated); + +			page_pool[pages_used] = (T *)memalloc(sizeof(T) * page_size); +			available_pool[pages_used] = (T **)memalloc(sizeof(T *) * page_size); + +			for (uint32_t i = 0; i < page_size; i++) { +				available_pool[0][i] = &page_pool[pages_used][i]; +			} +			allocs_available += page_size; +		} + +		allocs_available--; +		T *alloc = available_pool[allocs_available >> page_shift][allocs_available & page_mask]; +		if (thread_safe) { +			spin_lock.unlock(); +		} +		memnew_placement(alloc, T); +		return alloc; +	} + +	void free(T *p_mem) { +		if (thread_safe) { +			spin_lock.lock(); +		} +		p_mem->~T(); +		available_pool[allocs_available >> page_shift][allocs_available & page_mask] = p_mem; +		if (thread_safe) { +			spin_lock.unlock(); +		} +		allocs_available++; +	} + +	void reset() { +		ERR_FAIL_COND(allocs_available < pages_allocated * page_size); +		if (pages_allocated) { +			for (uint32_t i = 0; i < pages_allocated; i++) { +				memfree(page_pool[i]); +				memfree(available_pool[i]); +			} +			memfree(page_pool); +			memfree(available_pool); +			page_pool = nullptr; +			available_pool = nullptr; +			pages_allocated = 0; +			allocs_available = 0; +		} +	} +	bool is_configured() const { +		return page_size > 0; +	} + +	void configure(uint32_t p_page_size, bool p_thread_safe) { +		ERR_FAIL_COND(page_pool != nullptr); //sanity check +		ERR_FAIL_COND(p_page_size == 0); +		page_size = nearest_power_of_2_templated(p_page_size); +		page_mask = page_size - 1; +		page_shift = get_shift_from_power_of_2(page_size); +	} + +	PagedAllocator(uint32_t p_page_size = 4096, bool p_thread_safe = false) { // power of 2 recommended because of alignment with OS page sizes. Even if element is bigger, its still a multiple and get rounded amount of pages +		configure(p_page_size, false); +	} + +	~PagedAllocator() { +		ERR_FAIL_COND_MSG(allocs_available < pages_allocated * page_size, "Pages in use exist at exit in PagedAllocator"); +		reset(); +	} +}; + +#endif // PAGED_ALLOCATOR_H diff --git a/core/templates/paged_array.h b/core/templates/paged_array.h index 71183c4ad8..aaf3893715 100644 --- a/core/templates/paged_array.h +++ b/core/templates/paged_array.h @@ -329,7 +329,7 @@ public:  		}  	} -	uint64_t size() const { +	_FORCE_INLINE_ uint64_t size() const {  		return count;  	} diff --git a/core/templates/rid_owner.h b/core/templates/rid_owner.h index d1bcb92010..7de4e43648 100644 --- a/core/templates/rid_owner.h +++ b/core/templates/rid_owner.h @@ -346,6 +346,18 @@ public:  		alloc.free(p_rid);  	} +	_FORCE_INLINE_ uint32_t get_rid_count() const { +		return alloc.get_rid_count(); +	} + +	_FORCE_INLINE_ RID get_rid_by_index(uint32_t p_index) { +		return alloc.get_rid_by_index(p_index); +	} + +	_FORCE_INLINE_ T *get_ptr_by_index(uint32_t p_index) { +		return *alloc.get_ptr_by_index(p_index); +	} +  	_FORCE_INLINE_ void get_owned_list(List<RID> *p_owned) {  		return alloc.get_owned_list(p_owned);  	} @@ -353,6 +365,7 @@ public:  	void set_description(const char *p_descrption) {  		alloc.set_description(p_descrption);  	} +  	RID_PtrOwner(uint32_t p_target_chunk_byte_size = 4096) :  			alloc(p_target_chunk_byte_size) {}  }; diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp b/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp index 01dd2965c4..c6b2fa6dc0 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp @@ -1532,7 +1532,7 @@ void RendererSceneRenderForward::_add_geometry_with_material(InstanceBase *p_ins  	}  } -void RendererSceneRenderForward::_fill_render_list(InstanceBase **p_cull_result, int p_cull_count, PassMode p_pass_mode, bool p_using_sdfgi) { +void RendererSceneRenderForward::_fill_render_list(const PagedArray<InstanceBase *> &p_instances, PassMode p_pass_mode, bool p_using_sdfgi) {  	scene_state.current_shader_index = 0;  	scene_state.current_material_index = 0;  	scene_state.used_sss = false; @@ -1544,8 +1544,8 @@ void RendererSceneRenderForward::_fill_render_list(InstanceBase **p_cull_result,  	//fill list -	for (int i = 0; i < p_cull_count; i++) { -		InstanceBase *inst = p_cull_result[i]; +	for (int i = 0; i < (int)p_instances.size(); i++) { +		InstanceBase *inst = p_instances[i];  		//add geometry for drawing  		switch (inst->base_type) { @@ -1635,14 +1635,14 @@ void RendererSceneRenderForward::_fill_render_list(InstanceBase **p_cull_result,  	}  } -void RendererSceneRenderForward::_setup_lightmaps(InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, const Transform &p_cam_transform) { +void RendererSceneRenderForward::_setup_lightmaps(const PagedArray<InstanceBase *> &p_lightmaps, const Transform &p_cam_transform) {  	uint32_t lightmaps_used = 0; -	for (int i = 0; i < p_lightmap_cull_count; i++) { +	for (int i = 0; i < (int)p_lightmaps.size(); i++) {  		if (i >= (int)scene_state.max_lightmaps) {  			break;  		} -		InstanceBase *lm = p_lightmap_cull_result[i]; +		InstanceBase *lm = p_lightmaps[i];  		Basis to_lm = lm->transform.basis.inverse() * p_cam_transform.basis;  		to_lm = to_lm.inverse().transposed(); //will transform normals  		RendererStorageRD::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform); @@ -1654,7 +1654,7 @@ void RendererSceneRenderForward::_setup_lightmaps(InstanceBase **p_lightmap_cull  	}  } -void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_screen_lod_threshold) { +void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<InstanceBase *> &p_instances, int p_directional_light_count, const PagedArray<RID> &p_gi_probes, const PagedArray<InstanceBase *> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_screen_lod_threshold) {  	RenderBufferDataForward *render_buffer = nullptr;  	if (p_render_buffer.is_valid()) {  		render_buffer = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffer); @@ -1709,7 +1709,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf  		opaque_framebuffer = render_buffer->color_fb; -		if (!low_end && p_gi_probe_cull_count > 0) { +		if (!low_end && p_gi_probes.size() > 0) {  			using_giprobe = true;  			render_buffer->ensure_gi();  		} @@ -1776,13 +1776,13 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf  		ERR_FAIL(); //bug?  	} -	_setup_lightmaps(p_lightmap_cull_result, p_lightmap_cull_count, p_cam_transform); +	_setup_lightmaps(p_lightmaps, p_cam_transform);  	_setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), false);  	_update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example)  	render_list.clear(); -	_fill_render_list(p_cull_result, p_cull_count, PASS_MODE_COLOR, using_sdfgi); +	_fill_render_list(p_instances, PASS_MODE_COLOR, using_sdfgi);  	bool using_sss = !low_end && render_buffer && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED; @@ -1864,7 +1864,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf  		clear_color = p_default_bg_color;  	} -	RID rp_uniform_set = _setup_render_pass_uniform_set(p_render_buffer, radiance_texture, p_shadow_atlas, p_reflection_atlas, p_gi_probe_cull_result, p_gi_probe_cull_count); +	RID rp_uniform_set = _setup_render_pass_uniform_set(p_render_buffer, radiance_texture, p_shadow_atlas, p_reflection_atlas, p_gi_probes);  	render_list.sort_by_key(false); @@ -1903,7 +1903,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf  	}  	if (using_sdfgi || using_giprobe) { -		_process_gi(p_render_buffer, render_buffer->normal_roughness_buffer, render_buffer->ambient_buffer, render_buffer->reflection_buffer, render_buffer->giprobe_buffer, p_environment, p_cam_projection, p_cam_transform, p_gi_probe_cull_result, p_gi_probe_cull_count); +		_process_gi(p_render_buffer, render_buffer->normal_roughness_buffer, render_buffer->ambient_buffer, render_buffer->reflection_buffer, render_buffer->giprobe_buffer, p_environment, p_cam_projection, p_cam_transform, p_gi_probes);  	}  	_setup_environment(p_environment, p_render_buffer, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_size, p_shadow_atlas, !p_reflection_probe.is_valid(), p_default_bg_color, p_cam_projection.get_z_near(), p_cam_projection.get_z_far(), p_render_buffer.is_valid()); @@ -1949,8 +1949,8 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf  		dc.set_depth_correction(true);  		CameraMatrix cm = (dc * p_cam_projection) * CameraMatrix(p_cam_transform.affine_inverse());  		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); -		for (int i = 0; i < p_gi_probe_cull_count; i++) { -			_debug_giprobe(p_gi_probe_cull_result[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION, 1.0); +		for (int i = 0; i < (int)p_gi_probes.size(); i++) { +			_debug_giprobe(p_gi_probes[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION, 1.0);  		}  		RD::get_singleton()->draw_list_end();  	} @@ -2027,7 +2027,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf  	}  } -void RendererSceneRenderForward::_render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold) { +void RendererSceneRenderForward::_render_shadow(RID p_framebuffer, const PagedArray<InstanceBase *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold) {  	RENDER_TIMESTAMP("Setup Rendering Shadow");  	_update_render_base_uniform_set(); @@ -2046,9 +2046,9 @@ void RendererSceneRenderForward::_render_shadow(RID p_framebuffer, InstanceBase  	PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW; -	_fill_render_list(p_cull_result, p_cull_count, pass_mode); +	_fill_render_list(p_instances, pass_mode); -	RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), nullptr, 0); +	RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), PagedArray<RID>());  	RENDER_TIMESTAMP("Render Shadow"); @@ -2064,7 +2064,7 @@ void RendererSceneRenderForward::_render_shadow(RID p_framebuffer, InstanceBase  	}  } -void RendererSceneRenderForward::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, InstanceBase **p_cull_result, int p_cull_count) { +void RendererSceneRenderForward::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<InstanceBase *> &p_instances) {  	RENDER_TIMESTAMP("Setup Render Collider Heightfield");  	_update_render_base_uniform_set(); @@ -2079,9 +2079,9 @@ void RendererSceneRenderForward::_render_particle_collider_heightfield(RID p_fb,  	PassMode pass_mode = PASS_MODE_SHADOW; -	_fill_render_list(p_cull_result, p_cull_count, pass_mode); +	_fill_render_list(p_instances, pass_mode); -	RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), nullptr, 0); +	RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), PagedArray<RID>());  	RENDER_TIMESTAMP("Render Collider Heightield"); @@ -2097,7 +2097,7 @@ void RendererSceneRenderForward::_render_particle_collider_heightfield(RID p_fb,  	}  } -void RendererSceneRenderForward::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) { +void RendererSceneRenderForward::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<InstanceBase *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {  	RENDER_TIMESTAMP("Setup Rendering Material");  	_update_render_base_uniform_set(); @@ -2112,9 +2112,9 @@ void RendererSceneRenderForward::_render_material(const Transform &p_cam_transfo  	render_list.clear();  	PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; -	_fill_render_list(p_cull_result, p_cull_count, pass_mode); +	_fill_render_list(p_instances, pass_mode); -	RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), nullptr, 0); +	RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), PagedArray<RID>());  	RENDER_TIMESTAMP("Render Material"); @@ -2136,7 +2136,7 @@ void RendererSceneRenderForward::_render_material(const Transform &p_cam_transfo  	}  } -void RendererSceneRenderForward::_render_uv2(InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) { +void RendererSceneRenderForward::_render_uv2(const PagedArray<InstanceBase *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {  	RENDER_TIMESTAMP("Setup Rendering UV2");  	_update_render_base_uniform_set(); @@ -2151,9 +2151,9 @@ void RendererSceneRenderForward::_render_uv2(InstanceBase **p_cull_result, int p  	render_list.clear();  	PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; -	_fill_render_list(p_cull_result, p_cull_count, pass_mode); +	_fill_render_list(p_instances, pass_mode); -	RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), nullptr, 0); +	RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), PagedArray<RID>());  	RENDER_TIMESTAMP("Render Material"); @@ -2197,7 +2197,7 @@ void RendererSceneRenderForward::_render_uv2(InstanceBase **p_cull_result, int p  	}  } -void RendererSceneRenderForward::_render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, InstanceBase **p_cull_result, int p_cull_count, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) { +void RendererSceneRenderForward::_render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<InstanceBase *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) {  	RENDER_TIMESTAMP("Render SDFGI");  	_update_render_base_uniform_set(); @@ -2209,7 +2209,7 @@ void RendererSceneRenderForward::_render_sdfgi(RID p_render_buffers, const Vecto  	render_list.clear();  	PassMode pass_mode = PASS_MODE_SDF; -	_fill_render_list(p_cull_result, p_cull_count, pass_mode); +	_fill_render_list(p_instances, pass_mode);  	render_list.sort_by_key(false);  	_fill_instances(render_list.elements, render_list.element_count, true); @@ -2453,7 +2453,7 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() {  	}  } -RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count) { +RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, const PagedArray<RID> &p_gi_probes) {  	if (render_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_pass_uniform_set)) {  		RD::get_singleton()->free(render_pass_uniform_set);  	} @@ -2516,8 +2516,8 @@ RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RID p_render_buff  		u.ids.resize(MAX_GI_PROBES);  		RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);  		for (int i = 0; i < MAX_GI_PROBES; i++) { -			if (i < p_gi_probe_cull_count) { -				RID tex = gi_probe_instance_get_texture(p_gi_probe_cull_result[i]); +			if (i < (int)p_gi_probes.size()) { +				RID tex = gi_probe_instance_get_texture(p_gi_probes[i]);  				if (!tex.is_valid()) {  					tex = default_tex;  				} diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward.h b/servers/rendering/renderer_rd/renderer_scene_render_forward.h index da4cb579c1..5d77c13b43 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_forward.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_forward.h @@ -266,7 +266,7 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {  	void _update_render_base_uniform_set();  	RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture); -	RID _setup_render_pass_uniform_set(RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count); +	RID _setup_render_pass_uniform_set(RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, const PagedArray<RID> &p_gi_probes);  	struct LightmapData {  		float normal_xform[12]; @@ -567,26 +567,26 @@ class RendererSceneRenderForward : public RendererSceneRenderRD {  	};  	void _setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_size, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false); -	void _setup_lightmaps(InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, const Transform &p_cam_transform); +	void _setup_lightmaps(const PagedArray<InstanceBase *> &p_lightmaps, const Transform &p_cam_transform);  	void _fill_instances(RenderList::Element **p_elements, int p_element_count, bool p_for_depth, bool p_has_sdfgi = false, bool p_has_opaque_gi = false);  	void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0);  	_FORCE_INLINE_ void _add_geometry(InstanceBase *p_instance, uint32_t p_surface, RID p_material, PassMode p_pass_mode, uint32_t p_geometry_index, bool p_using_sdfgi = false);  	_FORCE_INLINE_ void _add_geometry_with_material(InstanceBase *p_instance, uint32_t p_surface, MaterialData *p_material, RID p_material_rid, PassMode p_pass_mode, uint32_t p_geometry_index, bool p_using_sdfgi = false); -	void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, PassMode p_pass_mode, bool p_using_sdfgi = false); +	void _fill_render_list(const PagedArray<InstanceBase *> &p_instances, PassMode p_pass_mode, bool p_using_sdfgi = false);  	Map<Size2i, RID> sdfgi_framebuffer_size_cache;  	bool low_end = false;  protected: -	virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_lod_threshold); -	virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0); -	virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region); -	virtual void _render_uv2(InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region); -	virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, InstanceBase **p_cull_result, int p_cull_count, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture); -	virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, InstanceBase **p_cull_result, int p_cull_count); +	virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<InstanceBase *> &p_instances, int p_directional_light_count, const PagedArray<RID> &p_gi_probes, const PagedArray<InstanceBase *> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_lod_threshold); +	virtual void _render_shadow(RID p_framebuffer, const PagedArray<InstanceBase *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0); +	virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<InstanceBase *> &p_instances, RID p_framebuffer, const Rect2i &p_region); +	virtual void _render_uv2(const PagedArray<InstanceBase *> &p_instances, RID p_framebuffer, const Rect2i &p_region); +	virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<InstanceBase *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture); +	virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<InstanceBase *> &p_instances);  public:  	virtual void set_time(double p_time, double p_step); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 1d9983a28c..02ec399f58 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -1153,7 +1153,7 @@ void RendererSceneRenderRD::_sdfgi_update_cascades(RID p_render_buffers) {  	RD::get_singleton()->buffer_update(rb->sdfgi->cascades_ubo, 0, sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES, cascade_data, true);  } -void RendererSceneRenderRD::sdfgi_update_probes(RID p_render_buffers, RID p_environment, const RID *p_directional_light_instances, uint32_t p_directional_light_count, const RID *p_positional_light_instances, uint32_t p_positional_light_count) { +void RendererSceneRenderRD::sdfgi_update_probes(RID p_render_buffers, RID p_environment, const PagedArray<RID> &p_directional_light_instances, const RID *p_positional_light_instances, uint32_t p_positional_light_count) {  	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);  	ERR_FAIL_COND(rb == nullptr);  	if (rb->sdfgi == nullptr) { @@ -1179,7 +1179,7 @@ void RendererSceneRenderRD::sdfgi_update_probes(RID p_render_buffers, RID p_envi  			SDGIShader::Light lights[SDFGI::MAX_DYNAMIC_LIGHTS];  			uint32_t idx = 0; -			for (uint32_t j = 0; j < p_directional_light_count; j++) { +			for (uint32_t j = 0; j < (uint32_t)p_directional_light_instances.size(); j++) {  				if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) {  					break;  				} @@ -1402,7 +1402,7 @@ void RendererSceneRenderRD::sdfgi_update_probes(RID p_render_buffers, RID p_envi  	RENDER_TIMESTAMP("<SDFGI Update Probes");  } -void RendererSceneRenderRD::_setup_giprobes(RID p_render_buffers, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, uint32_t &r_gi_probes_used) { +void RendererSceneRenderRD::_setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used) {  	r_gi_probes_used = 0;  	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);  	ERR_FAIL_COND(rb == nullptr); @@ -1417,8 +1417,8 @@ void RendererSceneRenderRD::_setup_giprobes(RID p_render_buffers, const Transfor  	for (int i = 0; i < RenderBuffers::MAX_GIPROBES; i++) {  		RID texture; -		if (i < p_gi_probe_cull_count) { -			GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_gi_probe_cull_result[i]); +		if (i < (int)p_gi_probes.size()) { +			GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_gi_probes[i]);  			if (gipi) {  				texture = gipi->texture; @@ -1489,12 +1489,12 @@ void RendererSceneRenderRD::_setup_giprobes(RID p_render_buffers, const Transfor  		}  	} -	if (p_gi_probe_cull_count > 0) { -		RD::get_singleton()->buffer_update(gi_probe_buffer, 0, sizeof(GI::GIProbeData) * MIN(RenderBuffers::MAX_GIPROBES, p_gi_probe_cull_count), gi_probe_data, true); +	if (p_gi_probes.size() > 0) { +		RD::get_singleton()->buffer_update(gi_probe_buffer, 0, sizeof(GI::GIProbeData) * MIN((uint64_t)RenderBuffers::MAX_GIPROBES, p_gi_probes.size()), gi_probe_data, true);  	}  } -void RendererSceneRenderRD::_process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_ambient_buffer, RID p_reflection_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count) { +void RendererSceneRenderRD::_process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_ambient_buffer, RID p_reflection_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes) {  	RENDER_TIMESTAMP("Render GI");  	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); @@ -1512,7 +1512,7 @@ void RendererSceneRenderRD::_process_gi(RID p_render_buffers, RID p_normal_rough  	push_constant.proj_info[1] = -2.0f / (rb->height * p_projection.matrix[1][1]);  	push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0];  	push_constant.proj_info[3] = (1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1]; -	push_constant.max_giprobes = MIN(RenderBuffers::MAX_GIPROBES, p_gi_probe_cull_count); +	push_constant.max_giprobes = MIN((uint64_t)RenderBuffers::MAX_GIPROBES, p_gi_probes.size());  	push_constant.high_quality_vct = gi_probe_quality == RS::GI_PROBE_QUALITY_HIGH;  	push_constant.use_sdfgi = rb->sdfgi != nullptr; @@ -4061,7 +4061,7 @@ bool RendererSceneRenderRD::gi_probe_needs_update(RID p_probe) const {  	return gi_probe->last_probe_version != storage->gi_probe_get_version(gi_probe->probe);  } -void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects) { +void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<InstanceBase *> &p_dynamic_objects) {  	GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);  	ERR_FAIL_COND(!gi_probe); @@ -4420,7 +4420,7 @@ void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_ins  	uint32_t light_count = 0; -	if (p_update_light_instances || p_dynamic_object_count > 0) { +	if (p_update_light_instances || p_dynamic_objects.size() > 0) {  		light_count = MIN(gi_probe_max_lights, (uint32_t)p_light_instances.size());  		{ @@ -4470,7 +4470,7 @@ void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_ins  		}  	} -	if (gi_probe->has_dynamic_object_data || p_update_light_instances || p_dynamic_object_count) { +	if (gi_probe->has_dynamic_object_data || p_update_light_instances || p_dynamic_objects.size()) {  		// PROCESS MIPMAPS  		if (gi_probe->mipmaps.size()) {  			//can update mipmaps @@ -4563,7 +4563,7 @@ void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_ins  	gi_probe->has_dynamic_object_data = false; //clear until dynamic object data is used again -	if (p_dynamic_object_count && gi_probe->dynamic_maps.size()) { +	if (p_dynamic_objects.size() && gi_probe->dynamic_maps.size()) {  		Vector3i octree_size = storage->gi_probe_get_octree_size(gi_probe->probe);  		int multiplier = gi_probe->dynamic_maps[0].size / MAX(MAX(octree_size.x, octree_size.y), octree_size.z); @@ -4577,7 +4577,7 @@ void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_ins  		AABB probe_aabb(Vector3(), octree_size);  		//this could probably be better parallelized in compute.. -		for (int i = 0; i < p_dynamic_object_count; i++) { +		for (int i = 0; i < (int)p_dynamic_objects.size(); i++) {  			InstanceBase *instance = p_dynamic_objects[i];  			//not used, so clear  			instance->depth_layer = 0; @@ -4648,7 +4648,12 @@ void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_ins  				CameraMatrix cm;  				cm.set_orthogonal(-rect.size.width / 2, rect.size.width / 2, -rect.size.height / 2, rect.size.height / 2, 0.0001, aabb.size[z_axis]); -				_render_material(to_world_xform * xform, cm, true, &instance, 1, gi_probe->dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size)); +				if (cull_argument.size() == 0) { +					cull_argument.push_back(nullptr); +				} +				cull_argument[0] = instance; + +				_render_material(to_world_xform * xform, cm, true, cull_argument, gi_probe->dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size));  				GIProbeDynamicPushConstant push_constant;  				zeromem(&push_constant, sizeof(GIProbeDynamicPushConstant)); @@ -6001,11 +6006,11 @@ RendererSceneRenderRD::RenderBufferData *RendererSceneRenderRD::render_buffers_g  	return rb->data;  } -void RendererSceneRenderRD::_setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment) { -	for (int i = 0; i < p_reflection_probe_cull_count; i++) { -		RID rpi = p_reflection_probe_cull_result[i]; +void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflections, const Transform &p_camera_inverse_transform, RID p_environment) { +	for (uint32_t i = 0; i < (uint32_t)p_reflections.size(); i++) { +		RID rpi = p_reflections[i]; -		if (i >= (int)cluster.max_reflections) { +		if (i >= cluster.max_reflections) {  			reflection_probe_instance_set_render_index(rpi, 0); //invalid, but something needs to be set  			continue;  		} @@ -6056,19 +6061,19 @@ void RendererSceneRenderRD::_setup_reflections(RID *p_reflection_probe_cull_resu  		reflection_probe_instance_set_render_pass(rpi, RSG::rasterizer->get_frame_number());  	} -	if (p_reflection_probe_cull_count) { -		RD::get_singleton()->buffer_update(cluster.reflection_buffer, 0, MIN(cluster.max_reflections, (unsigned int)p_reflection_probe_cull_count) * sizeof(ReflectionData), cluster.reflections, true); +	if (p_reflections.size()) { +		RD::get_singleton()->buffer_update(cluster.reflection_buffer, 0, MIN(cluster.max_reflections, (unsigned int)p_reflections.size()) * sizeof(ReflectionData), cluster.reflections, true);  	}  } -void RendererSceneRenderRD::_setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count) { +void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count) {  	uint32_t light_count = 0;  	r_directional_light_count = 0;  	r_positional_light_count = 0;  	sky_scene_state.ubo.directional_light_count = 0; -	for (int i = 0; i < p_light_cull_count; i++) { -		RID li = p_light_cull_result[i]; +	for (int i = 0; i < (int)p_lights.size(); i++) { +		RID li = p_lights[i];  		RID base = light_instance_get_base_light(li);  		ERR_CONTINUE(base.is_null()); @@ -6421,15 +6426,15 @@ void RendererSceneRenderRD::_setup_lights(RID *p_light_cull_result, int p_light_  	}  } -void RendererSceneRenderRD::_setup_decals(const RID *p_decal_instances, int p_decal_count, const Transform &p_camera_inverse_xform) { +void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const Transform &p_camera_inverse_xform) {  	Transform uv_xform;  	uv_xform.basis.scale(Vector3(2.0, 1.0, 2.0));  	uv_xform.origin = Vector3(-1.0, 0.0, -1.0); -	p_decal_count = MIN((uint32_t)p_decal_count, cluster.max_decals); +	uint32_t decal_count = MIN((uint32_t)p_decals.size(), cluster.max_decals);  	int idx = 0; -	for (int i = 0; i < p_decal_count; i++) { -		RID di = p_decal_instances[i]; +	for (uint32_t i = 0; i < decal_count; i++) { +		RID di = p_decals[i];  		RID decal = decal_instance_get_base(di);  		Transform xform = decal_instance_get_transform(di); @@ -7097,7 +7102,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e  	RD::get_singleton()->compute_list_end();  } -void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold) { +void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<InstanceBase *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<InstanceBase *> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold) {  	Color clear_color;  	if (p_render_buffers.is_valid()) {  		RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); @@ -7108,17 +7113,23 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &  	}  	//assign render indices to giprobes -	for (int i = 0; i < p_gi_probe_cull_count; i++) { -		GIProbeInstance *giprobe_inst = gi_probe_instance_owner.getornull(p_gi_probe_cull_result[i]); +	for (uint32_t i = 0; i < (uint32_t)p_gi_probes.size(); i++) { +		GIProbeInstance *giprobe_inst = gi_probe_instance_owner.getornull(p_gi_probes[i]);  		if (giprobe_inst) {  			giprobe_inst->render_index = i;  		}  	} +	const PagedArray<RID> *lights = &p_lights; +	const PagedArray<RID> *reflections = &p_reflection_probes; +	const PagedArray<RID> *gi_probes = &p_gi_probes; + +	PagedArray<RID> empty; +  	if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) { -		p_light_cull_count = 0; -		p_reflection_probe_cull_count = 0; -		p_gi_probe_cull_count = 0; +		lights = ∅ +		reflections = ∅ +		gi_probes = ∅  	}  	cluster.builder.begin(p_cam_transform.affine_inverse(), p_cam_projection); //prepare cluster @@ -7131,17 +7142,17 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &  		}  	} else {  		//do not render reflections when rendering a reflection probe -		_setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_environment); +		_setup_reflections(*reflections, p_cam_transform.affine_inverse(), p_environment);  	}  	uint32_t directional_light_count = 0;  	uint32_t positional_light_count = 0; -	_setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas, using_shadows, directional_light_count, positional_light_count); -	_setup_decals(p_decal_cull_result, p_decal_cull_count, p_cam_transform.affine_inverse()); +	_setup_lights(*lights, p_cam_transform.affine_inverse(), p_shadow_atlas, using_shadows, directional_light_count, positional_light_count); +	_setup_decals(p_decals, p_cam_transform.affine_inverse());  	cluster.builder.bake_cluster(); //bake to cluster  	uint32_t gi_probe_count = 0; -	_setup_giprobes(p_render_buffers, p_cam_transform, p_gi_probe_cull_result, p_gi_probe_cull_count, gi_probe_count); +	_setup_giprobes(p_render_buffers, p_cam_transform, *gi_probes, gi_probe_count);  	if (p_render_buffers.is_valid()) {  		bool directional_shadows = false; @@ -7154,7 +7165,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &  		_update_volumetric_fog(p_render_buffers, p_environment, p_cam_projection, p_cam_transform, p_shadow_atlas, directional_light_count, directional_shadows, positional_light_count, gi_probe_count);  	} -	_render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, directional_light_count, p_gi_probe_cull_result, p_gi_probe_cull_count, p_lightmap_cull_result, p_lightmap_cull_count, p_environment, p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color, p_screen_lod_threshold); +	_render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_instances, directional_light_count, *gi_probes, p_lightmaps, p_environment, p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color, p_screen_lod_threshold);  	if (p_render_buffers.is_valid()) {  		RENDER_TIMESTAMP("Tonemap"); @@ -7167,7 +7178,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &  	}  } -void RendererSceneRenderRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold) { +void RendererSceneRenderRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<InstanceBase *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold) {  	LightInstance *light_instance = light_instance_owner.getornull(p_light);  	ERR_FAIL_COND(!light_instance); @@ -7318,7 +7329,7 @@ void RendererSceneRenderRD::render_shadow(RID p_light, RID p_shadow_atlas, int p  	if (render_cubemap) {  		//rendering to cubemap -		_render_shadow(render_fb, p_cull_result, p_cull_count, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold); +		_render_shadow(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold);  		if (finalize_cubemap) {  			//reblit  			atlas_rect.size.height /= 2; @@ -7329,7 +7340,7 @@ void RendererSceneRenderRD::render_shadow(RID p_light, RID p_shadow_atlas, int p  	} else {  		//render shadow -		_render_shadow(render_fb, p_cull_result, p_cull_count, light_projection, light_transform, zfar, bias, normal_bias, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold); +		_render_shadow(render_fb, p_instances, light_projection, light_transform, zfar, bias, normal_bias, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold);  		//copy to atlas  		if (use_linear_depth) { @@ -7343,11 +7354,11 @@ void RendererSceneRenderRD::render_shadow(RID p_light, RID p_shadow_atlas, int p  	}  } -void RendererSceneRenderRD::render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) { -	_render_material(p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_framebuffer, p_region); +void RendererSceneRenderRD::render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<InstanceBase *> &p_instances, RID p_framebuffer, const Rect2i &p_region) { +	_render_material(p_cam_transform, p_cam_projection, p_cam_ortogonal, p_instances, p_framebuffer, p_region);  } -void RendererSceneRenderRD::render_sdfgi(RID p_render_buffers, int p_region, InstanceBase **p_cull_result, int p_cull_count) { +void RendererSceneRenderRD::render_sdfgi(RID p_render_buffers, int p_region, const PagedArray<InstanceBase *> &p_instances) {  	//print_line("rendering region " + itos(p_region));  	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);  	ERR_FAIL_COND(!rb); @@ -7370,7 +7381,7 @@ void RendererSceneRenderRD::render_sdfgi(RID p_render_buffers, int p_region, Ins  	}  	//print_line("rendering cascade " + itos(p_region) + " objects: " + itos(p_cull_count) + " bounds: " + bounds + " from: " + from + " size: " + size + " cell size: " + rtos(rb->sdfgi->cascades[cascade].cell_size)); -	_render_sdfgi(p_render_buffers, from, size, bounds, p_cull_result, p_cull_count, rb->sdfgi->render_albedo, rb->sdfgi->render_emission, rb->sdfgi->render_emission_aniso, rb->sdfgi->render_geom_facing); +	_render_sdfgi(p_render_buffers, from, size, bounds, p_instances, rb->sdfgi->render_albedo, rb->sdfgi->render_emission, rb->sdfgi->render_emission_aniso, rb->sdfgi->render_geom_facing);  	if (cascade_next != cascade) {  		RENDER_TIMESTAMP(">SDFGI Update SDF"); @@ -7684,7 +7695,7 @@ void RendererSceneRenderRD::render_sdfgi(RID p_render_buffers, int p_region, Ins  	}  } -void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, InstanceBase **p_cull_result, int p_cull_count) { +void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<InstanceBase *> &p_instances) {  	ERR_FAIL_COND(!storage->particles_collision_is_heightfield(p_collider));  	Vector3 extents = storage->particles_collision_get_extents(p_collider) * p_transform.basis.get_scale();  	CameraMatrix cm; @@ -7698,16 +7709,14 @@ void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider,  	RID fb = storage->particles_collision_get_heightfield_framebuffer(p_collider); -	_render_particle_collider_heightfield(fb, cam_xform, cm, p_cull_result, p_cull_count); +	_render_particle_collider_heightfield(fb, cam_xform, cm, p_instances);  } -void RendererSceneRenderRD::render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const RID **p_positional_light_cull_result, const uint32_t *p_positional_light_cull_count) { +void RendererSceneRenderRD::render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result) {  	RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);  	ERR_FAIL_COND(!rb);  	ERR_FAIL_COND(!rb->sdfgi); -	ERR_FAIL_COND(p_positional_light_cull_count == 0); -  	_sdfgi_update_cascades(p_render_buffers); //need cascades updated for this  	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); @@ -7743,7 +7752,7 @@ void RendererSceneRenderRD::render_sdfgi_static_lights(RID p_render_buffers, uin  			int idx = 0; -			for (uint32_t j = 0; j < p_positional_light_cull_count[i]; j++) { +			for (uint32_t j = 0; j < (uint32_t)p_positional_light_cull_result[i].size(); j++) {  				if (idx == SDFGI::MAX_STATIC_LIGHTS) {  					break;  				} @@ -7982,8 +7991,11 @@ TypedArray<Image> RendererSceneRenderRD::bake_render_uv2(RID p_base, const Vecto  		}  	} -	InstanceBase *cull = &ins; -	_render_uv2(&cull, 1, fb, Rect2i(0, 0, p_image_size.width, p_image_size.height)); +	if (cull_argument.size() == 0) { +		cull_argument.push_back(nullptr); +	} +	cull_argument[0] = &ins; +	_render_uv2(cull_argument, fb, Rect2i(0, 0, p_image_size.width, p_image_size.height));  	TypedArray<Image> ret; @@ -8534,6 +8546,8 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {  	environment_set_volumetric_fog_filter_active(GLOBAL_GET("rendering/volumetric_fog/use_filter"));  	environment_set_volumetric_fog_directional_shadow_shrink_size(GLOBAL_GET("rendering/volumetric_fog/directional_shadow_shrink"));  	environment_set_volumetric_fog_positional_shadow_shrink_size(GLOBAL_GET("rendering/volumetric_fog/positional_shadow_shrink")); + +	cull_argument.set_page_pool(&cull_argument_pool);  }  RendererSceneRenderRD::~RendererSceneRenderRD() { @@ -8598,4 +8612,5 @@ RendererSceneRenderRD::~RendererSceneRenderRD() {  	RD::get_singleton()->free(shadow_sampler);  	directional_shadow_atlas_set_size(0); +	cull_argument.reset(); //avoid exit error  } diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 1b0ae61042..ded6d99e47 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -104,17 +104,17 @@ protected:  	};  	virtual RenderBufferData *_create_render_buffer_data() = 0; -	void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count); -	void _setup_decals(const RID *p_decal_instances, int p_decal_count, const Transform &p_camera_inverse_xform); -	void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment); -	void _setup_giprobes(RID p_render_buffers, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, uint32_t &r_gi_probes_used); - -	virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, int p_directional_light_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_color, float p_screen_lod_threshold) = 0; -	virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0) = 0; -	virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0; -	virtual void _render_uv2(InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0; -	virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, InstanceBase **p_cull_result, int p_cull_count, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) = 0; -	virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, InstanceBase **p_cull_result, int p_cull_count) = 0; +	void _setup_lights(const PagedArray<RID> &p_lights, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count); +	void _setup_decals(const PagedArray<RID> &p_decals, const Transform &p_camera_inverse_xform); +	void _setup_reflections(const PagedArray<RID> &p_reflections, const Transform &p_camera_inverse_transform, RID p_environment); +	void _setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used); + +	virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<InstanceBase *> &p_instances, int p_directional_light_count, const PagedArray<RID> &p_gi_probes, const PagedArray<InstanceBase *> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_color, float p_screen_lod_threshold) = 0; +	virtual void _render_shadow(RID p_framebuffer, const PagedArray<InstanceBase *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0) = 0; +	virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<InstanceBase *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; +	virtual void _render_uv2(const PagedArray<InstanceBase *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; +	virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<InstanceBase *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) = 0; +	virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<InstanceBase *> &p_instances) = 0;  	virtual void _debug_giprobe(RID p_gi_probe, RenderingDevice::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);  	void _debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform); @@ -134,8 +134,11 @@ protected:  	void _setup_sky(RID p_environment, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size);  	void _update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform);  	void _draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform); -	void _process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_ambient_buffer, RID p_reflection_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count); +	void _process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_ambient_buffer, RID p_reflection_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes); +	// needed for a single argument calls (material and uv2) +	PagedArrayPool<InstanceBase *> cull_argument_pool; +	PagedArray<InstanceBase *> cull_argument; //need this to exist  private:  	RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED;  	double time_step = 0; @@ -1513,7 +1516,7 @@ public:  	virtual int sdfgi_get_pending_region_count(RID p_render_buffers) const;  	virtual AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const;  	virtual uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const; -	virtual void sdfgi_update_probes(RID p_render_buffers, RID p_environment, const RID *p_directional_light_instances, uint32_t p_directional_light_count, const RID *p_positional_light_instances, uint32_t p_positional_light_count); +	virtual void sdfgi_update_probes(RID p_render_buffers, RID p_environment, const PagedArray<RID> &p_directional_light_instances, const RID *p_positional_light_instances, uint32_t p_positional_light_count);  	RID sdfgi_get_ubo() const { return gi.sdfgi_ubo; }  	/* SKY API */ @@ -1822,7 +1825,7 @@ public:  	RID gi_probe_instance_create(RID p_base);  	void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform);  	bool gi_probe_needs_update(RID p_probe) const; -	void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects); +	void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::InstanceBase *> &p_dynamic_objects);  	void gi_probe_set_quality(RS::GIProbeQuality p_quality) { gi_probe_quality = p_quality; } @@ -1897,16 +1900,16 @@ public:  	float render_buffers_get_volumetric_fog_end(RID p_render_buffers);  	float render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers); -	void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_shadow_atlas, RID p_camera_effects, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold); +	void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<InstanceBase *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<InstanceBase *> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold); -	void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0); +	void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<InstanceBase *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0); -	void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region); +	void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<InstanceBase *> &p_instances, RID p_framebuffer, const Rect2i &p_region); -	void render_sdfgi(RID p_render_buffers, int p_region, InstanceBase **p_cull_result, int p_cull_count); -	void render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const RID **p_positional_light_cull_result, const uint32_t *p_positional_light_cull_count); +	void render_sdfgi(RID p_render_buffers, int p_region, const PagedArray<InstanceBase *> &p_instances); +	void render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result); -	void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, InstanceBase **p_cull_result, int p_cull_count); +	void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<InstanceBase *> &p_instances);  	virtual void set_scene_pass(uint64_t p_pass) {  		scene_pass = p_pass; diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 88a0859a28..1db678a441 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -30,6 +30,7 @@  #include "renderer_scene_cull.h" +#include "core/config/project_settings.h"  #include "core/os/os.h"  #include "rendering_server_default.h"  #include "rendering_server_globals.h" @@ -108,8 +109,8 @@ bool RendererSceneCull::is_camera(RID p_camera) const {  /* SCENARIO API */ -void *RendererSceneCull::_instance_pair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int) { -	//RendererSceneCull *self = (RendererSceneCull*)p_self; +void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) { +	RendererSceneCull *self = (RendererSceneCull *)singleton;  	Instance *A = p_A;  	Instance *B = p_B; @@ -122,90 +123,66 @@ void *RendererSceneCull::_instance_pair(void *p_self, OctreeElementID, Instance  		InstanceLightData *light = static_cast<InstanceLightData *>(B->base_data);  		InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); -		InstanceLightData::PairInfo pinfo; -		pinfo.geometry = A; -		pinfo.L = geom->lighting.push_back(B); - -		List<InstanceLightData::PairInfo>::Element *E = light->geometries.push_back(pinfo); +		geom->lights.insert(B); +		light->geometries.insert(A);  		if (geom->can_cast_shadows) {  			light->shadow_dirty = true;  		}  		geom->lighting_dirty = true; -		return E; //this element should make freeing faster -	} else if (B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { +	} else if (self->pair_volumes_to_mesh && B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {  		InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(B->base_data);  		InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); -		InstanceReflectionProbeData::PairInfo pinfo; -		pinfo.geometry = A; -		pinfo.L = geom->reflection_probes.push_back(B); - -		List<InstanceReflectionProbeData::PairInfo>::Element *E = reflection_probe->geometries.push_back(pinfo); +		geom->reflection_probes.insert(B); +		reflection_probe->geometries.insert(A);  		geom->reflection_dirty = true; -		return E; //this element should make freeing faster -	} else if (B->base_type == RS::INSTANCE_DECAL && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { +	} else if (self->pair_volumes_to_mesh && B->base_type == RS::INSTANCE_DECAL && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {  		InstanceDecalData *decal = static_cast<InstanceDecalData *>(B->base_data);  		InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); -		InstanceDecalData::PairInfo pinfo; -		pinfo.geometry = A; -		pinfo.L = geom->decals.push_back(B); - -		List<InstanceDecalData::PairInfo>::Element *E = decal->geometries.push_back(pinfo); +		geom->decals.insert(B); +		decal->geometries.insert(A);  		geom->decal_dirty = true; -		return E; //this element should make freeing faster  	} else if (B->base_type == RS::INSTANCE_LIGHTMAP && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {  		InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(B->base_data);  		InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);  		if (A->dynamic_gi) { -			InstanceLightmapData::PairInfo pinfo; -			pinfo.geometry = A; -			pinfo.L = geom->lightmap_captures.push_back(B); -			List<InstanceLightmapData::PairInfo>::Element *E = lightmap_data->geometries.push_back(pinfo); -			((RendererSceneCull *)p_self)->_instance_queue_update(A, false, false); //need to update capture -			return E; //this element should make freeing faster -		} else { -			return nullptr; +			geom->lightmap_captures.insert(A); +			lightmap_data->geometries.insert(B); +			((RendererSceneCull *)self)->_instance_queue_update(A, false, false); //need to update capture  		}  	} else if (B->base_type == RS::INSTANCE_GI_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {  		InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data);  		InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); -		InstanceGIProbeData::PairInfo pinfo; -		pinfo.geometry = A; -		pinfo.L = geom->gi_probes.push_back(B); +		geom->gi_probes.insert(B); -		List<InstanceGIProbeData::PairInfo>::Element *E;  		if (A->dynamic_gi) { -			E = gi_probe->dynamic_geometries.push_back(pinfo); +			gi_probe->dynamic_geometries.insert(A);  		} else { -			E = gi_probe->geometries.push_back(pinfo); +			gi_probe->geometries.insert(A);  		}  		geom->gi_probes_dirty = true; -		return E; //this element should make freeing faster -  	} else if (B->base_type == RS::INSTANCE_GI_PROBE && A->base_type == RS::INSTANCE_LIGHT) {  		InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); -		return gi_probe->lights.insert(A); +		gi_probe->lights.insert(A);  	} else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) {  		RSG::storage->particles_add_collision(A->base, B);  	} - -	return nullptr;  } -void RendererSceneCull::_instance_unpair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int, void *udata) { -	//RendererSceneCull *self = (RendererSceneCull*)p_self; +void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) { +	RendererSceneCull *self = (RendererSceneCull *)singleton;  	Instance *A = p_A;  	Instance *B = p_B; @@ -218,68 +195,55 @@ void RendererSceneCull::_instance_unpair(void *p_self, OctreeElementID, Instance  		InstanceLightData *light = static_cast<InstanceLightData *>(B->base_data);  		InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); -		List<InstanceLightData::PairInfo>::Element *E = reinterpret_cast<List<InstanceLightData::PairInfo>::Element *>(udata); - -		geom->lighting.erase(E->get().L); -		light->geometries.erase(E); +		geom->lights.erase(B); +		light->geometries.erase(A);  		if (geom->can_cast_shadows) {  			light->shadow_dirty = true;  		}  		geom->lighting_dirty = true; -	} else if (B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { +	} else if (self->pair_volumes_to_mesh && B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {  		InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(B->base_data);  		InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); -		List<InstanceReflectionProbeData::PairInfo>::Element *E = reinterpret_cast<List<InstanceReflectionProbeData::PairInfo>::Element *>(udata); - -		geom->reflection_probes.erase(E->get().L); -		reflection_probe->geometries.erase(E); - +		geom->reflection_probes.erase(B); +		reflection_probe->geometries.erase(A);  		geom->reflection_dirty = true; -	} else if (B->base_type == RS::INSTANCE_DECAL && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + +	} else if (self->pair_volumes_to_mesh && B->base_type == RS::INSTANCE_DECAL && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {  		InstanceDecalData *decal = static_cast<InstanceDecalData *>(B->base_data);  		InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); -		List<InstanceDecalData::PairInfo>::Element *E = reinterpret_cast<List<InstanceDecalData::PairInfo>::Element *>(udata); - -		geom->decals.erase(E->get().L); -		decal->geometries.erase(E); +		geom->decals.erase(B); +		decal->geometries.erase(A);  		geom->decal_dirty = true;  	} else if (B->base_type == RS::INSTANCE_LIGHTMAP && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { -		if (udata) { //only for dynamic geometries -			InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(B->base_data); -			InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - -			List<InstanceLightmapData::PairInfo>::Element *E = reinterpret_cast<List<InstanceLightmapData::PairInfo>::Element *>(udata); - -			geom->lightmap_captures.erase(E->get().L); -			lightmap_data->geometries.erase(E); -			((RendererSceneCull *)p_self)->_instance_queue_update(A, false, false); //need to update capture +		InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(B->base_data); +		InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); +		if (A->dynamic_gi) { +			geom->lightmap_captures.erase(B); +			lightmap_data->geometries.erase(A); +			((RendererSceneCull *)self)->_instance_queue_update(A, false, false); //need to update capture  		}  	} else if (B->base_type == RS::INSTANCE_GI_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {  		InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data);  		InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); -		List<InstanceGIProbeData::PairInfo>::Element *E = reinterpret_cast<List<InstanceGIProbeData::PairInfo>::Element *>(udata); - -		geom->gi_probes.erase(E->get().L); +		geom->gi_probes.erase(B);  		if (A->dynamic_gi) { -			gi_probe->dynamic_geometries.erase(E); +			gi_probe->dynamic_geometries.erase(A);  		} else { -			gi_probe->geometries.erase(E); +			gi_probe->geometries.erase(A);  		}  		geom->gi_probes_dirty = true;  	} else if (B->base_type == RS::INSTANCE_GI_PROBE && A->base_type == RS::INSTANCE_LIGHT) {  		InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); -		Set<Instance *>::Element *E = reinterpret_cast<Set<Instance *>::Element *>(udata); - -		gi_probe->lights.erase(E); +		gi_probe->lights.erase(A);  	} else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) {  		RSG::storage->particles_remove_collision(A->base, B);  	} @@ -291,8 +255,6 @@ RID RendererSceneCull::scenario_create() {  	RID scenario_rid = scenario_owner.make_rid(scenario);  	scenario->self = scenario_rid; -	scenario->octree.set_pair_callback(_instance_pair, this); -	scenario->octree.set_unpair_callback(_instance_unpair, this);  	scenario->reflection_probe_shadow_atlas = scene_render->shadow_atlas_create();  	scene_render->shadow_atlas_set_size(scenario->reflection_probe_shadow_atlas, 1024); //make enough shadows for close distance, don't bother with rest  	scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 0, 4); @@ -395,9 +357,8 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {  	if (instance->base_type != RS::INSTANCE_NONE) {  		//free anything related to that base -		if (scenario && instance->octree_id) { -			scenario->octree.erase(instance->octree_id); //make dependencies generated by the octree go away -			instance->octree_id = 0; +		if (scenario && instance->indexer_id.is_valid()) { +			_unpair_instance(instance);  		}  		if (instance->mesh_instance.is_valid()) { @@ -556,9 +517,8 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) {  	if (instance->scenario) {  		instance->scenario->instances.remove(&instance->scenario_item); -		if (instance->octree_id) { -			instance->scenario->octree.erase(instance->octree_id); //make dependencies generated by the octree go away -			instance->octree_id = 0; +		if (instance->indexer_id.is_valid()) { +			_unpair_instance(instance);  		}  		switch (instance->base_type) { @@ -715,45 +675,12 @@ void RendererSceneCull::instance_set_visible(RID p_instance, bool p_visible) {  	instance->visible = p_visible; -	switch (instance->base_type) { -		case RS::INSTANCE_LIGHT: { -			if (RSG::storage->light_get_type(instance->base) != RS::LIGHT_DIRECTIONAL && instance->octree_id && instance->scenario) { -				instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_LIGHT, p_visible ? RS::INSTANCE_GEOMETRY_MASK : 0); -			} - -		} break; -		case RS::INSTANCE_REFLECTION_PROBE: { -			if (instance->octree_id && instance->scenario) { -				instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_REFLECTION_PROBE, p_visible ? RS::INSTANCE_GEOMETRY_MASK : 0); -			} - -		} break; -		case RS::INSTANCE_DECAL: { -			if (instance->octree_id && instance->scenario) { -				instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_DECAL, p_visible ? RS::INSTANCE_GEOMETRY_MASK : 0); -			} - -		} break; -		case RS::INSTANCE_LIGHTMAP: { -			if (instance->octree_id && instance->scenario) { -				instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_LIGHTMAP, p_visible ? RS::INSTANCE_GEOMETRY_MASK : 0); -			} - -		} break; -		case RS::INSTANCE_GI_PROBE: { -			if (instance->octree_id && instance->scenario) { -				instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_GI_PROBE, p_visible ? (RS::INSTANCE_GEOMETRY_MASK | (1 << RS::INSTANCE_LIGHT)) : 0); -			} - -		} break; -		case RS::INSTANCE_PARTICLES_COLLISION: { -			if (instance->octree_id && instance->scenario) { -				instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_PARTICLES_COLLISION, p_visible ? (1 << RS::INSTANCE_PARTICLES) : 0); -			} - -		} break; -		default: { +	if (p_visible) { +		if (instance->scenario != nullptr) { +			_instance_queue_update(instance, true, false);  		} +	} else if (instance->indexer_id.is_valid()) { +		_unpair_instance(instance);  	}  } @@ -824,21 +751,21 @@ Vector<ObjectID> RendererSceneCull::instances_cull_aabb(const AABB &p_aabb, RID  	const_cast<RendererSceneCull *>(this)->update_dirty_instances(); // check dirty instances before culling -	int culled = 0; -	Instance *cull[1024]; -	culled = scenario->octree.cull_aabb(p_aabb, cull, 1024); - -	for (int i = 0; i < culled; i++) { -		Instance *instance = cull[i]; -		ERR_CONTINUE(!instance); -		if (instance->object_id.is_null()) { -			continue; +	struct CullAABB { +		Vector<ObjectID> instances; +		_FORCE_INLINE_ bool operator()(void *p_data) { +			Instance *p_instance = (Instance *)p_data; +			if (!p_instance->object_id.is_null()) { +				instances.push_back(p_instance->object_id); +			} +			return false;  		} +	}; -		instances.push_back(instance->object_id); -	} - -	return instances; +	CullAABB cull_aabb; +	scenario->indexers[Scenario::INDEXER_GEOMETRY].aabb_query(p_aabb, cull_aabb); +	scenario->indexers[Scenario::INDEXER_VOLUMES].aabb_query(p_aabb, cull_aabb); +	return cull_aabb.instances;  }  Vector<ObjectID> RendererSceneCull::instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario) const { @@ -847,21 +774,21 @@ Vector<ObjectID> RendererSceneCull::instances_cull_ray(const Vector3 &p_from, co  	ERR_FAIL_COND_V(!scenario, instances);  	const_cast<RendererSceneCull *>(this)->update_dirty_instances(); // check dirty instances before culling -	int culled = 0; -	Instance *cull[1024]; -	culled = scenario->octree.cull_segment(p_from, p_from + p_to * 10000, cull, 1024); - -	for (int i = 0; i < culled; i++) { -		Instance *instance = cull[i]; -		ERR_CONTINUE(!instance); -		if (instance->object_id.is_null()) { -			continue; +	struct CullRay { +		Vector<ObjectID> instances; +		_FORCE_INLINE_ bool operator()(void *p_data) { +			Instance *p_instance = (Instance *)p_data; +			if (!p_instance->object_id.is_null()) { +				instances.push_back(p_instance->object_id); +			} +			return false;  		} +	}; -		instances.push_back(instance->object_id); -	} - -	return instances; +	CullRay cull_ray; +	scenario->indexers[Scenario::INDEXER_GEOMETRY].ray_query(p_from, p_to, cull_ray); +	scenario->indexers[Scenario::INDEXER_VOLUMES].ray_query(p_from, p_to, cull_ray); +	return cull_ray.instances;  }  Vector<ObjectID> RendererSceneCull::instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario) const { @@ -870,22 +797,23 @@ Vector<ObjectID> RendererSceneCull::instances_cull_convex(const Vector<Plane> &p  	ERR_FAIL_COND_V(!scenario, instances);  	const_cast<RendererSceneCull *>(this)->update_dirty_instances(); // check dirty instances before culling -	int culled = 0; -	Instance *cull[1024]; - -	culled = scenario->octree.cull_convex(p_convex, cull, 1024); +	Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&p_convex[0], p_convex.size()); -	for (int i = 0; i < culled; i++) { -		Instance *instance = cull[i]; -		ERR_CONTINUE(!instance); -		if (instance->object_id.is_null()) { -			continue; +	struct CullConvex { +		Vector<ObjectID> instances; +		_FORCE_INLINE_ bool operator()(void *p_data) { +			Instance *p_instance = (Instance *)p_data; +			if (!p_instance->object_id.is_null()) { +				instances.push_back(p_instance->object_id); +			} +			return false;  		} +	}; -		instances.push_back(instance->object_id); -	} - -	return instances; +	CullConvex cull_convex; +	scenario->indexers[Scenario::INDEXER_GEOMETRY].convex_query(p_convex.ptr(), p_convex.size(), points.ptr(), points.size(), cull_convex); +	scenario->indexers[Scenario::INDEXER_VOLUMES].convex_query(p_convex.ptr(), p_convex.size(), points.ptr(), points.size(), cull_convex); +	return cull_convex.instances;  }  void RendererSceneCull::instance_geometry_set_flag(RID p_instance, RS::InstanceFlags p_flags, bool p_enabled) { @@ -905,10 +833,8 @@ void RendererSceneCull::instance_geometry_set_flag(RID p_instance, RS::InstanceF  				return;  			} -			if (instance->octree_id != 0) { -				//remove from octree, it needs to be re-paired -				instance->scenario->octree.erase(instance->octree_id); -				instance->octree_id = 0; +			if (instance->indexer_id.is_valid()) { +				_unpair_instance(instance);  				_instance_queue_update(instance, true, true);  			} @@ -1102,7 +1028,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {  		//make sure lights are updated if it casts shadow  		if (geom->can_cast_shadows) { -			for (List<Instance *>::Element *E = geom->lighting.front(); E; E = E->next()) { +			for (Set<Instance *>::Element *E = geom->lights.front(); E; E = E->next()) {  				InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data);  				light->shadow_dirty = true;  			} @@ -1124,8 +1050,8 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {  		InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(p_instance->base_data);  		//erase dependencies, since no longer a lightmap -		for (List<InstanceLightmapData::PairInfo>::Element *E = lightmap_data->geometries.front(); E; E = E->next()) { -			Instance *geom = E->get().geometry; +		for (Set<Instance *>::Element *E = lightmap_data->geometries.front(); E; E = E->next()) { +			Instance *geom = E->get();  			_instance_queue_update(geom, true, false);  		}  	} @@ -1138,42 +1064,81 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {  	p_instance->transformed_aabb = new_aabb; -	if (!p_instance->scenario) { +	if (p_instance->scenario == nullptr || !p_instance->visible || Math::is_zero_approx(p_instance->transform.basis.determinant())) {  		return;  	} -	if (p_instance->octree_id == 0) { -		uint32_t base_type = 1 << p_instance->base_type; -		uint32_t pairable_mask = 0; -		bool pairable = false; - -		if (p_instance->base_type == RS::INSTANCE_LIGHT || p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE || p_instance->base_type == RS::INSTANCE_DECAL || p_instance->base_type == RS::INSTANCE_LIGHTMAP) { -			pairable_mask = p_instance->visible ? RS::INSTANCE_GEOMETRY_MASK : 0; -			pairable = true; +	if (!p_instance->indexer_id.is_valid()) { +		if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { +			p_instance->indexer_id = p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY].insert(p_instance->aabb, p_instance); +		} else { +			p_instance->indexer_id = p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES].insert(p_instance->aabb, p_instance);  		} +	} -		if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { -			pairable_mask = p_instance->visible ? (1 << RS::INSTANCE_PARTICLES) : 0; -			pairable = true; -		} +	//move instance and repair +	pair_pass++; + +	PairInstances pair; + +	pair.instance = p_instance; +	pair.pair_allocator = &pair_allocator; +	pair.pair_pass = pair_pass; +	pair.pair_mask = 0; + +	if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { +		pair.pair_mask |= 1 << RS::INSTANCE_LIGHT; +		pair.pair_mask |= 1 << RS::INSTANCE_GI_PROBE; +		pair.pair_mask |= 1 << RS::INSTANCE_LIGHTMAP; -		if (p_instance->base_type == RS::INSTANCE_GI_PROBE) { -			//lights and geometries -			pairable_mask = p_instance->visible ? RS::INSTANCE_GEOMETRY_MASK | (1 << RS::INSTANCE_LIGHT) : 0; -			pairable = true; +		if (pair_volumes_to_mesh) { +			pair.pair_mask |= 1 << RS::INSTANCE_DECAL; +			pair.pair_mask |= 1 << RS::INSTANCE_REFLECTION_PROBE; +		} +		pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES]; +	} else if (p_instance->base_type == RS::INSTANCE_LIGHT) { +		pair.pair_mask |= RS::INSTANCE_GEOMETRY_MASK; +		pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; + +		if (RSG::storage->light_get_bake_mode(p_instance->base) == RS::LIGHT_BAKE_DYNAMIC) { +			pair.pair_mask |= (1 << RS::INSTANCE_GI_PROBE); +			pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES];  		} +	} else if (pair_volumes_to_mesh && (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE || p_instance->base_type == RS::INSTANCE_DECAL)) { +		pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK; +		pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; +	} else if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { +		pair.pair_mask = (1 << RS::INSTANCE_PARTICLES); +		pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; +	} else if (p_instance->base_type == RS::INSTANCE_GI_PROBE) { +		//lights and geometries +		pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK | (1 << RS::INSTANCE_LIGHT); +		pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; +		pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES]; +	} -		// not inside octree -		p_instance->octree_id = p_instance->scenario->octree.create(p_instance, new_aabb, 0, pairable, base_type, pairable_mask); +	pair.pair(); +} -	} else { -		/* -		if (new_aabb==p_instance->data.transformed_aabb) -			return; -		*/ +void RendererSceneCull::_unpair_instance(Instance *p_instance) { +	if (!p_instance->indexer_id.is_valid()) { +		return; //nothing to do +	} + +	while (p_instance->pairs.first()) { +		InstancePair *pair = p_instance->pairs.first()->self(); +		Instance *other_instance = p_instance == pair->a ? pair->b : pair->a; +		_instance_unpair(p_instance, other_instance); +		pair_allocator.free(pair); +	} -		p_instance->scenario->octree.move(p_instance->octree_id, new_aabb); +	if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { +		p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY].remove(p_instance->indexer_id); +	} else { +		p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES].remove(p_instance->indexer_id);  	} + +	p_instance->indexer_id = DynamicBVH::ID();  }  void RendererSceneCull::_update_instance_aabb(Instance *p_instance) { @@ -1264,7 +1229,7 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance)  	float accum_blend = 0.0;  	InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); -	for (List<Instance *>::Element *E = geom->lightmap_captures.front(); E; E = E->next()) { +	for (Set<Instance *>::Element *E = geom->lightmap_captures.front(); E; E = E->next()) {  		Instance *lightmap = E->get();  		bool interior = RSG::storage->lightmap_is_interior(lightmap->base); @@ -1358,8 +1323,26 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons  			if (depth_range_mode == RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED) {  				//optimize min/max +  				Vector<Plane> planes = p_cam_projection.get_projection_planes(p_cam_transform); -				int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, RS::INSTANCE_GEOMETRY_MASK); +				Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&planes[0], planes.size()); + +				geometry_instances_to_shadow_render.clear(); + +				struct CullConvex { +					PagedArray<RendererSceneRender::InstanceBase *> *result; +					_FORCE_INLINE_ bool operator()(void *p_data) { +						Instance *p_instance = (Instance *)p_data; +						result->push_back(p_instance); +						return false; +					} +				}; + +				CullConvex cull_convex; +				cull_convex.result = &geometry_instances_to_shadow_render; + +				p_scenario->indexers[Scenario::INDEXER_GEOMETRY].convex_query(planes.ptr(), planes.size(), points.ptr(), points.size(), cull_convex); +  				Plane base(p_cam_transform.origin, -p_cam_transform.basis.get_axis(2));  				//check distance max and min @@ -1367,7 +1350,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons  				real_t z_max = -1e20;  				real_t z_min = 1e20; -				for (int i = 0; i < cull_count; i++) { +				for (int i = 0; i < (int)instance_shadow_cull_result.size(); i++) {  					Instance *instance = instance_shadow_cull_result[i];  					if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) {  						continue; @@ -1583,20 +1566,34 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons  				light_frustum_planes.write[4] = Plane(z_vec, z_max + 1e6);  				light_frustum_planes.write[5] = Plane(-z_vec, -z_min); // z_min is ok, since casters further than far-light plane are not needed -				int cull_count = p_scenario->octree.cull_convex(light_frustum_planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, RS::INSTANCE_GEOMETRY_MASK); +				geometry_instances_to_shadow_render.clear(); +				instance_shadow_cull_result.clear(); + +				Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&light_frustum_planes[0], light_frustum_planes.size()); + +				struct CullConvex { +					PagedArray<Instance *> *result; +					_FORCE_INLINE_ bool operator()(void *p_data) { +						Instance *p_instance = (Instance *)p_data; +						result->push_back(p_instance); +						return false; +					} +				}; + +				CullConvex cull_convex; +				cull_convex.result = &instance_shadow_cull_result; + +				p_scenario->indexers[Scenario::INDEXER_GEOMETRY].convex_query(light_frustum_planes.ptr(), light_frustum_planes.size(), points.ptr(), points.size(), cull_convex);  				// a pre pass will need to be needed to determine the actual z-near to be used  				Plane near_plane(light_transform.origin, -light_transform.basis.get_axis(2));  				real_t cull_max = 0; -				for (int j = 0; j < cull_count; j++) { +				for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) {  					real_t min, max;  					Instance *instance = instance_shadow_cull_result[j];  					if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { -						cull_count--; -						SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]); -						j--;  						continue;  					} @@ -1610,6 +1607,8 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons  					if (instance->mesh_instance.is_valid()) {  						RSG::storage->mesh_instance_check_for_update(instance->mesh_instance);  					} + +					geometry_instances_to_shadow_render.push_back(instance);  				}  				if (cull_max > z_max) { @@ -1712,7 +1711,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons  				RSG::storage->update_mesh_instances(); -				scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RendererSceneRender::InstanceBase **)instance_shadow_cull_result, cull_count, camera_plane, p_cam_projection.get_lod_multiplier(), p_screen_lod_threshold); +				scene_render->render_shadow(light->instance, p_shadow_atlas, i, geometry_instances_to_shadow_render, camera_plane, p_cam_projection.get_lod_multiplier(), p_screen_lod_threshold);  			}  		} break; @@ -1736,15 +1735,31 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons  					planes.write[4] = light_transform.xform(Plane(Vector3(0, -1, z).normalized(), radius));  					planes.write[5] = light_transform.xform(Plane(Vector3(0, 0, -z), 0)); -					int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, RS::INSTANCE_GEOMETRY_MASK); +					geometry_instances_to_shadow_render.clear(); +					instance_shadow_cull_result.clear(); + +					Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&planes[0], planes.size()); + +					struct CullConvex { +						PagedArray<Instance *> *result; +						_FORCE_INLINE_ bool operator()(void *p_data) { +							Instance *p_instance = (Instance *)p_data; +							result->push_back(p_instance); +							return false; +						} +					}; + +					CullConvex cull_convex; +					cull_convex.result = &instance_shadow_cull_result; + +					p_scenario->indexers[Scenario::INDEXER_GEOMETRY].convex_query(planes.ptr(), planes.size(), points.ptr(), points.size(), cull_convex); +  					Plane near_plane(light_transform.origin, light_transform.basis.get_axis(2) * z); -					for (int j = 0; j < cull_count; j++) { +					for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) {  						Instance *instance = instance_shadow_cull_result[j];  						if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { -							cull_count--; -							SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]); -							j--; +							continue;  						} else {  							if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) {  								animated_material_found = true; @@ -1757,12 +1772,14 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons  								RSG::storage->mesh_instance_check_for_update(instance->mesh_instance);  							}  						} + +						geometry_instances_to_shadow_render.push_back(instance);  					}  					RSG::storage->update_mesh_instances();  					scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, i, 0); -					scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RendererSceneRender::InstanceBase **)instance_shadow_cull_result, cull_count); +					scene_render->render_shadow(light->instance, p_shadow_atlas, i, geometry_instances_to_shadow_render);  				}  			} else { //shadow cube @@ -1795,15 +1812,31 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons  					Vector<Plane> planes = cm.get_projection_planes(xform); -					int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, RS::INSTANCE_GEOMETRY_MASK); +					geometry_instances_to_shadow_render.clear(); +					instance_shadow_cull_result.clear(); + +					Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&planes[0], planes.size()); + +					struct CullConvex { +						PagedArray<Instance *> *result; +						_FORCE_INLINE_ bool operator()(void *p_data) { +							Instance *p_instance = (Instance *)p_data; +							result->push_back(p_instance); +							return false; +						} +					}; + +					CullConvex cull_convex; +					cull_convex.result = &instance_shadow_cull_result; + +					p_scenario->indexers[Scenario::INDEXER_GEOMETRY].convex_query(planes.ptr(), planes.size(), points.ptr(), points.size(), cull_convex);  					Plane near_plane(xform.origin, -xform.basis.get_axis(2)); -					for (int j = 0; j < cull_count; j++) { + +					for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) {  						Instance *instance = instance_shadow_cull_result[j];  						if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { -							cull_count--; -							SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]); -							j--; +							continue;  						} else {  							if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) {  								animated_material_found = true; @@ -1814,11 +1847,13 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons  								RSG::storage->mesh_instance_check_for_update(instance->mesh_instance);  							}  						} + +						geometry_instances_to_shadow_render.push_back(instance);  					}  					RSG::storage->update_mesh_instances();  					scene_render->light_instance_set_shadow_transform(light->instance, cm, xform, radius, 0, i, 0); -					scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RendererSceneRender::InstanceBase **)instance_shadow_cull_result, cull_count); +					scene_render->render_shadow(light->instance, p_shadow_atlas, i, geometry_instances_to_shadow_render);  				}  				//restore the regular DP matrix @@ -1836,15 +1871,32 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons  			cm.set_perspective(angle * 2.0, 1.0, 0.01, radius);  			Vector<Plane> planes = cm.get_projection_planes(light_transform); -			int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, RS::INSTANCE_GEOMETRY_MASK); + +			geometry_instances_to_shadow_render.clear(); +			instance_shadow_cull_result.clear(); + +			Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&planes[0], planes.size()); + +			struct CullConvex { +				PagedArray<Instance *> *result; +				_FORCE_INLINE_ bool operator()(void *p_data) { +					Instance *p_instance = (Instance *)p_data; +					result->push_back(p_instance); +					return false; +				} +			}; + +			CullConvex cull_convex; +			cull_convex.result = &instance_shadow_cull_result; + +			p_scenario->indexers[Scenario::INDEXER_GEOMETRY].convex_query(planes.ptr(), planes.size(), points.ptr(), points.size(), cull_convex);  			Plane near_plane(light_transform.origin, -light_transform.basis.get_axis(2)); -			for (int j = 0; j < cull_count; j++) { + +			for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) {  				Instance *instance = instance_shadow_cull_result[j];  				if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { -					cull_count--; -					SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]); -					j--; +					continue;  				} else {  					if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) {  						animated_material_found = true; @@ -1856,12 +1908,13 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons  						RSG::storage->mesh_instance_check_for_update(instance->mesh_instance);  					}  				} +				geometry_instances_to_shadow_render.push_back(instance);  			}  			RSG::storage->update_mesh_instances();  			scene_render->light_instance_set_shadow_transform(light->instance, cm, light_transform, radius, 0, 0, 0); -			scene_render->render_shadow(light->instance, p_shadow_atlas, 0, (RendererSceneRender::InstanceBase **)instance_shadow_cull_result, cull_count); +			scene_render->render_shadow(light->instance, p_shadow_atlas, 0, geometry_instances_to_shadow_render);  		} break;  	} @@ -2028,14 +2081,17 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca  	Plane near_plane(p_cam_transform.origin, -p_cam_transform.basis.get_axis(2).normalized());  	float z_far = p_cam_projection.get_z_far(); +	instance_cull_result.clear();  	/* STEP 2 - CULL */ -	instance_cull_count = scenario->octree.cull_convex(planes, instance_cull_result, MAX_INSTANCE_CULL); -	light_cull_count = 0; +	{ +		CullResult cull_result; +		cull_result.result = &instance_cull_result; + +		Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&planes[0], planes.size()); -	reflection_probe_cull_count = 0; -	decal_cull_count = 0; -	gi_probe_cull_count = 0; -	lightmap_cull_count = 0; +		scenario->indexers[Scenario::INDEXER_GEOMETRY].convex_query(planes.ptr(), planes.size(), points.ptr(), points.size(), cull_result); +		scenario->indexers[Scenario::INDEXER_VOLUMES].convex_query(planes.ptr(), planes.size(), points.ptr(), points.size(), cull_result); +	}  	//light_samplers_culled=0; @@ -2053,83 +2109,65 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca  	uint64_t frame_number = RSG::rasterizer->get_frame_number();  	float lightmap_probe_update_speed = RSG::storage->lightmap_get_probe_capture_update_speed() * RSG::rasterizer->get_frame_delta_time(); -	for (int i = 0; i < instance_cull_count; i++) { -		Instance *ins = instance_cull_result[i]; +	geometry_instances_to_render.clear(); +	light_cull_result.clear(); +	lightmap_cull_result.clear(); +	reflection_probe_instance_cull_result.clear(); +	light_instance_cull_result.clear(); +	gi_probe_instance_cull_result.clear(); +	lightmap_cull_result.clear(); +	decal_instance_cull_result.clear(); -		bool keep = false; +	for (uint32_t i = 0; i < (uint32_t)instance_cull_result.size(); i++) { +		Instance *ins = instance_cull_result[i];  		if ((camera_layer_mask & ins->layer_mask) == 0) {  			//failure -		} else if (ins->base_type == RS::INSTANCE_LIGHT && ins->visible) { -			if (light_cull_count < MAX_LIGHTS_CULLED) { -				InstanceLightData *light = static_cast<InstanceLightData *>(ins->base_data); - -				if (!light->geometries.empty()) { -					//do not add this light if no geometry is affected by it.. -					light_cull_result[light_cull_count] = ins; -					light_instance_cull_result[light_cull_count] = light->instance; -					if (p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(ins->base)) { -						scene_render->light_instance_mark_visible(light->instance); //mark it visible for shadow allocation later -					} +		} else if (ins->base_type == RS::INSTANCE_LIGHT) { +			InstanceLightData *light = static_cast<InstanceLightData *>(ins->base_data); -					light_cull_count++; -				} +			light_cull_result.push_back(ins); +			light_instance_cull_result.push_back(light->instance); +			if (p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(ins->base)) { +				scene_render->light_instance_mark_visible(light->instance); //mark it visible for shadow allocation later  			} -		} else if (ins->base_type == RS::INSTANCE_REFLECTION_PROBE && ins->visible) { -			if (reflection_probe_cull_count < MAX_REFLECTION_PROBES_CULLED) { -				InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(ins->base_data); - -				if (p_reflection_probe != reflection_probe->instance) { -					//avoid entering The Matrix - -					if (!reflection_probe->geometries.empty()) { -						//do not add this light if no geometry is affected by it.. -						if (reflection_probe->reflection_dirty || scene_render->reflection_probe_instance_needs_redraw(reflection_probe->instance)) { -							if (!reflection_probe->update_list.in_list()) { -								reflection_probe->render_step = 0; -								reflection_probe_render_list.add_last(&reflection_probe->update_list); -							} +		} else if (ins->base_type == RS::INSTANCE_REFLECTION_PROBE) { +			InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(ins->base_data); -							reflection_probe->reflection_dirty = false; -						} +			if (p_reflection_probe != reflection_probe->instance) { +				//avoid entering The Matrix -						if (scene_render->reflection_probe_instance_has_reflection(reflection_probe->instance)) { -							reflection_probe_instance_cull_result[reflection_probe_cull_count] = reflection_probe->instance; -							reflection_probe_cull_count++; -						} +				if (reflection_probe->reflection_dirty || scene_render->reflection_probe_instance_needs_redraw(reflection_probe->instance)) { +					if (!reflection_probe->update_list.in_list()) { +						reflection_probe->render_step = 0; +						reflection_probe_render_list.add_last(&reflection_probe->update_list);  					} + +					reflection_probe->reflection_dirty = false;  				} -			} -		} else if (ins->base_type == RS::INSTANCE_DECAL && ins->visible) { -			if (decal_cull_count < MAX_DECALS_CULLED) { -				InstanceDecalData *decal = static_cast<InstanceDecalData *>(ins->base_data); - -				if (!decal->geometries.empty()) { -					//do not add this decal if no geometry is affected by it.. -					decal_instance_cull_result[decal_cull_count] = decal->instance; -					decal_cull_count++; + +				if (scene_render->reflection_probe_instance_has_reflection(reflection_probe->instance)) { +					reflection_probe_instance_cull_result.push_back(reflection_probe->instance);  				}  			} +		} else if (ins->base_type == RS::INSTANCE_DECAL) { +			InstanceDecalData *decal = static_cast<InstanceDecalData *>(ins->base_data); + +			decal_instance_cull_result.push_back(decal->instance); -		} else if (ins->base_type == RS::INSTANCE_GI_PROBE && ins->visible) { +		} else if (ins->base_type == RS::INSTANCE_GI_PROBE) {  			InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(ins->base_data);  			if (!gi_probe->update_element.in_list()) {  				gi_probe_update_list.add(&gi_probe->update_element);  			} -			if (gi_probe_cull_count < MAX_GI_PROBES_CULLED) { -				gi_probe_instance_cull_result[gi_probe_cull_count] = gi_probe->probe_instance; -				gi_probe_cull_count++; -			} -		} else if (ins->base_type == RS::INSTANCE_LIGHTMAP && ins->visible) { -			if (lightmap_cull_count < MAX_LIGHTMAPS_CULLED) { -				lightmap_cull_result[lightmap_cull_count] = ins; -				lightmap_cull_count++; -			} +			gi_probe_instance_cull_result.push_back(gi_probe->probe_instance); -		} else if (((1 << ins->base_type) & RS::INSTANCE_GEOMETRY_MASK) && ins->visible && ins->cast_shadows != RS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) { -			keep = true; +		} else if (ins->base_type == RS::INSTANCE_LIGHTMAP) { +			lightmap_cull_result.push_back(ins); +		} else if (((1 << ins->base_type) & RS::INSTANCE_GEOMETRY_MASK) && ins->cast_shadows != RS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) { +			bool keep = true;  			InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(ins->base_data); @@ -2150,12 +2188,12 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca  				}  			} -			if (geom->lighting_dirty) { +			if (pair_volumes_to_mesh && geom->lighting_dirty) {  				int l = 0;  				//only called when lights AABB enter/exit this geometry -				ins->light_instances.resize(geom->lighting.size()); +				ins->light_instances.resize(geom->lights.size()); -				for (List<Instance *>::Element *E = geom->lighting.front(); E; E = E->next()) { +				for (Set<Instance *>::Element *E = geom->lights.front(); E; E = E->next()) {  					InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data);  					ins->light_instances.write[l++] = light->instance; @@ -2164,12 +2202,12 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca  				geom->lighting_dirty = false;  			} -			if (geom->reflection_dirty) { +			if (pair_volumes_to_mesh && geom->reflection_dirty) {  				int l = 0;  				//only called when reflection probe AABB enter/exit this geometry  				ins->reflection_probe_instances.resize(geom->reflection_probes.size()); -				for (List<Instance *>::Element *E = geom->reflection_probes.front(); E; E = E->next()) { +				for (Set<Instance *>::Element *E = geom->reflection_probes.front(); E; E = E->next()) {  					InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data);  					ins->reflection_probe_instances.write[l++] = reflection_probe->instance; @@ -2183,7 +2221,7 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca  				//only called when reflection probe AABB enter/exit this geometry  				ins->gi_probe_instances.resize(geom->gi_probes.size()); -				for (List<Instance *>::Element *E = geom->gi_probes.front(); E; E = E->next()) { +				for (Set<Instance *>::Element *E = geom->gi_probes.front(); E; E = E->next()) {  					InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(E->get()->base_data);  					ins->gi_probe_instances.write[l++] = gi_probe->probe_instance; @@ -2206,17 +2244,15 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca  			ins->depth = near_plane.distance_to(ins->transform.origin);  			ins->depth_layer = CLAMP(int(ins->depth * 16 / z_far), 0, 15); -		} -		if (!keep) { -			// remove, no reason to keep -			instance_cull_count--; -			SWAP(instance_cull_result[i], instance_cull_result[instance_cull_count]); -			i--; -			ins->last_render_pass = 0; // make invalid -		} else { -			ins->last_render_pass = render_pass; +			if (keep) { +				geometry_instances_to_render.push_back(ins); +				ins->last_render_pass = render_pass; +			} else { +				ins->last_render_pass = 0; // make invalid +			}  		} +  		ins->last_frame_pass = frame_number;  	} @@ -2224,19 +2260,13 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca  	/* STEP 5 - PROCESS LIGHTS */ -	RID *directional_light_ptr = &light_instance_cull_result[light_cull_count]; -	directional_light_count = 0; +	directional_light_cull_result.clear();  	// directional lights  	{ -		Instance **lights_with_shadow = (Instance **)alloca(sizeof(Instance *) * scenario->directional_lights.size()); -		int directional_shadow_count = 0; +		directional_shadow_cull_result.clear();  		for (List<Instance *>::Element *E = scenario->directional_lights.front(); E; E = E->next()) { -			if (light_cull_count + directional_light_count >= MAX_LIGHTS_CULLED) { -				break; -			} -  			if (!E->get()->visible) {  				continue;  			} @@ -2247,19 +2277,21 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca  			if (light) {  				if (p_using_shadows && p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(E->get()->base) && !(RSG::storage->light_get_type(E->get()->base) == RS::LIGHT_DIRECTIONAL && RSG::storage->light_directional_is_sky_only(E->get()->base))) { -					lights_with_shadow[directional_shadow_count++] = E->get(); +					directional_shadow_cull_result.push_back(E->get());  				}  				//add to list -				directional_light_ptr[directional_light_count++] = light->instance; +				directional_light_cull_result.push_back(light->instance);  			} + +			light_instance_cull_result.push_back(light->instance);  		} -		scene_render->set_directional_shadow_count(directional_shadow_count); +		scene_render->set_directional_shadow_count(directional_shadow_cull_result.size()); -		for (int i = 0; i < directional_shadow_count; i++) { +		for (uint32_t i = 0; i < (uint32_t)directional_shadow_cull_result.size(); i++) {  			RENDER_TIMESTAMP(">Rendering Directional Light " + itos(i)); -			_light_instance_update_shadow(lights_with_shadow[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario, p_screen_lod_threshold); +			_light_instance_update_shadow(directional_shadow_cull_result[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario, p_screen_lod_threshold);  			RENDER_TIMESTAMP("<Rendering Directional Light " + itos(i));  		} @@ -2269,7 +2301,7 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca  		//SortArray<Instance*,_InstanceLightsort> sorter;  		//sorter.sort(light_cull_result,light_cull_count); -		for (int i = 0; i < light_cull_count; i++) { +		for (uint32_t i = 0; i < (uint32_t)light_cull_result.size(); i++) {  			Instance *ins = light_cull_result[i];  			if (!p_shadow_atlas.is_valid() || !RSG::storage->light_has_shadow(ins->base)) { @@ -2368,8 +2400,9 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca  	if (p_render_buffers.is_valid()) {  		uint32_t cascade_index[8]; -		uint32_t cascade_sizes[8]; -		const RID *cascade_ptrs[8]; +		for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { +			sdfgi_cascade_lights[i].clear(); +		}  		uint32_t cascade_count = 0;  		uint32_t sdfgi_light_cull_count = 0; @@ -2379,30 +2412,36 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca  			uint32_t region_cascade = scene_render->sdfgi_get_pending_region_cascade(p_render_buffers, i);  			if (region_cascade != prev_cascade) { -				cascade_sizes[cascade_count] = 0;  				cascade_index[cascade_count] = region_cascade; -				cascade_ptrs[cascade_count] = &sdfgi_light_cull_result[sdfgi_light_cull_count];  				cascade_count++;  				sdfgi_light_cull_pass++;  				prev_cascade = region_cascade;  			} -			uint32_t sdfgi_cull_count = scenario->octree.cull_aabb(region, instance_shadow_cull_result, MAX_INSTANCE_CULL); +			instance_sdfgi_cull_result.clear(); +			{ +				CullResult cull_result; +				cull_result.result = &instance_sdfgi_cull_result; + +				scenario->indexers[Scenario::INDEXER_GEOMETRY].aabb_query(region, cull_result); +				scenario->indexers[Scenario::INDEXER_VOLUMES].aabb_query(region, cull_result); +			} -			for (uint32_t j = 0; j < sdfgi_cull_count; j++) { -				Instance *ins = instance_shadow_cull_result[j]; +			geometry_instances_to_sdfgi_render.clear(); + +			for (uint32_t j = 0; j < (uint32_t)instance_sdfgi_cull_result.size(); j++) { +				Instance *ins = instance_sdfgi_cull_result[j];  				bool keep = false; -				if (ins->base_type == RS::INSTANCE_LIGHT && ins->visible) { +				if (ins->base_type == RS::INSTANCE_LIGHT) {  					InstanceLightData *instance_light = (InstanceLightData *)ins->base_data;  					if (instance_light->bake_mode != RS::LIGHT_BAKE_STATIC || region_cascade > instance_light->max_sdfgi_cascade) {  						continue;  					} -					if (sdfgi_light_cull_pass != instance_light->sdfgi_cascade_light_pass && sdfgi_light_cull_count < MAX_LIGHTS_CULLED) { +					if (sdfgi_light_cull_pass != instance_light->sdfgi_cascade_light_pass) {  						instance_light->sdfgi_cascade_light_pass = sdfgi_light_cull_pass; -						sdfgi_light_cull_result[sdfgi_light_cull_count++] = instance_light->instance; -						cascade_sizes[cascade_count - 1]++; +						sdfgi_cascade_lights[cascade_count - 1].push_back(instance_light->instance);  					}  				} else if ((1 << ins->base_type) & RS::INSTANCE_GEOMETRY_MASK) {  					if (ins->baked_light) { @@ -2413,25 +2452,22 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca  					}  				} -				if (!keep) { -					// remove, no reason to keep -					sdfgi_cull_count--; -					SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[sdfgi_cull_count]); -					j--; +				if (keep) { +					geometry_instances_to_sdfgi_render.push_back(ins);  				}  			}  			RSG::storage->update_mesh_instances(); -			scene_render->render_sdfgi(p_render_buffers, i, (RendererSceneRender::InstanceBase **)instance_shadow_cull_result, sdfgi_cull_count); +			scene_render->render_sdfgi(p_render_buffers, i, geometry_instances_to_sdfgi_render);  			//have to save updated cascades, then update static lights.  		}  		if (sdfgi_light_cull_count) { -			scene_render->render_sdfgi_static_lights(p_render_buffers, cascade_count, cascade_index, cascade_ptrs, cascade_sizes); +			scene_render->render_sdfgi_static_lights(p_render_buffers, cascade_count, cascade_index, sdfgi_cascade_lights);  		} -		scene_render->sdfgi_update_probes(p_render_buffers, p_environment, directional_light_ptr, directional_light_count, scenario->dynamic_lights.ptr(), scenario->dynamic_lights.size()); +		scene_render->sdfgi_update_probes(p_render_buffers, p_environment, directional_light_cull_result, scenario->dynamic_lights.ptr(), scenario->dynamic_lights.size());  	}  } @@ -2468,7 +2504,7 @@ void RendererSceneCull::_render_scene(RID p_render_buffers, const Transform p_ca  	/* PROCESS GEOMETRY AND DRAW SCENE */  	RENDER_TIMESTAMP("Render Scene "); -	scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, (RendererSceneRender::InstanceBase **)instance_cull_result, instance_cull_count, light_instance_cull_result, light_cull_count + directional_light_count, reflection_probe_instance_cull_result, reflection_probe_cull_count, gi_probe_instance_cull_result, gi_probe_cull_count, decal_instance_cull_result, decal_cull_count, (RendererSceneRender::InstanceBase **)lightmap_cull_result, lightmap_cull_count, p_environment, camera_effects, p_shadow_atlas, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_lod_threshold); +	scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, geometry_instances_to_render, light_instance_cull_result, reflection_probe_instance_cull_result, gi_probe_instance_cull_result, decal_instance_cull_result, lightmap_cull_result, p_environment, camera_effects, p_shadow_atlas, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_lod_threshold);  }  void RendererSceneCull::render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) { @@ -2483,7 +2519,7 @@ void RendererSceneCull::render_empty_scene(RID p_render_buffers, RID p_scenario,  		environment = scenario->fallback_environment;  	}  	RENDER_TIMESTAMP("Render Empty Scene "); -	scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0, environment, RID(), p_shadow_atlas, scenario->reflection_atlas, RID(), 0, 0); +	scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, PagedArray<RendererSceneRender::InstanceBase *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RendererSceneRender::InstanceBase *>(), RID(), RID(), p_shadow_atlas, scenario->reflection_atlas, RID(), 0, 0);  #endif  } @@ -2758,35 +2794,34 @@ void RendererSceneCull::render_probes() {  			update_lights = true;  		} -		instance_cull_count = 0; -		for (List<InstanceGIProbeData::PairInfo>::Element *E = probe->dynamic_geometries.front(); E; E = E->next()) { -			if (instance_cull_count < MAX_INSTANCE_CULL) { -				Instance *ins = E->get().geometry; -				if (!ins->visible) { -					continue; -				} -				InstanceGeometryData *geom = (InstanceGeometryData *)ins->base_data; +		geometry_instances_to_render.clear(); -				if (geom->gi_probes_dirty) { -					//giprobes may be dirty, so update -					int l = 0; -					//only called when reflection probe AABB enter/exit this geometry -					ins->gi_probe_instances.resize(geom->gi_probes.size()); +		for (Set<Instance *>::Element *E = probe->dynamic_geometries.front(); E; E = E->next()) { +			Instance *ins = E->get(); +			if (!ins->visible) { +				continue; +			} +			InstanceGeometryData *geom = (InstanceGeometryData *)ins->base_data; -					for (List<Instance *>::Element *F = geom->gi_probes.front(); F; F = F->next()) { -						InstanceGIProbeData *gi_probe2 = static_cast<InstanceGIProbeData *>(F->get()->base_data); +			if (geom->gi_probes_dirty) { +				//giprobes may be dirty, so update +				int l = 0; +				//only called when reflection probe AABB enter/exit this geometry +				ins->gi_probe_instances.resize(geom->gi_probes.size()); -						ins->gi_probe_instances.write[l++] = gi_probe2->probe_instance; -					} +				for (Set<Instance *>::Element *F = geom->gi_probes.front(); F; F = F->next()) { +					InstanceGIProbeData *gi_probe2 = static_cast<InstanceGIProbeData *>(F->get()->base_data); -					geom->gi_probes_dirty = false; +					ins->gi_probe_instances.write[l++] = gi_probe2->probe_instance;  				} -				instance_cull_result[instance_cull_count++] = E->get().geometry; +				geom->gi_probes_dirty = false;  			} + +			geometry_instances_to_render.push_back(E->get());  		} -		scene_render->gi_probe_update(probe->probe_instance, update_lights, probe->light_instances, instance_cull_count, (RendererSceneRender::InstanceBase **)instance_cull_result); +		scene_render->gi_probe_update(probe->probe_instance, update_lights, probe->light_instances, geometry_instances_to_render);  		gi_probe_update_list.remove(gi_probe); @@ -2800,16 +2835,32 @@ void RendererSceneCull::render_particle_colliders() {  		if (hfpc->scenario && hfpc->base_type == RS::INSTANCE_PARTICLES_COLLISION && RSG::storage->particles_collision_is_heightfield(hfpc->base)) {  			//update heightfield -			int cull_count = hfpc->scenario->octree.cull_aabb(hfpc->transformed_aabb, instance_cull_result, MAX_INSTANCE_CULL); //@TODO: cull mask missing -			for (int i = 0; i < cull_count; i++) { +			instance_cull_result.clear(); +			geometry_instances_to_render.clear(); + +			struct CullAABB { +				PagedArray<Instance *> *result; +				_FORCE_INLINE_ bool operator()(void *p_data) { +					Instance *p_instance = (Instance *)p_data; +					result->push_back(p_instance); +					return false; +				} +			}; + +			CullAABB cull_aabb; +			cull_aabb.result = &instance_cull_result; +			hfpc->scenario->indexers[Scenario::INDEXER_GEOMETRY].aabb_query(hfpc->transformed_aabb, cull_aabb); +			hfpc->scenario->indexers[Scenario::INDEXER_VOLUMES].aabb_query(hfpc->transformed_aabb, cull_aabb); + +			for (int i = 0; i < (int)instance_cull_result.size(); i++) {  				Instance *instance = instance_cull_result[i]; -				if (!instance->visible || !((1 << instance->base_type) & (RS::INSTANCE_GEOMETRY_MASK & (~(1 << RS::INSTANCE_PARTICLES))))) { //all but particles to avoid self collision -					cull_count--; -					SWAP(instance_cull_result[i], instance_cull_result[cull_count]); +				if (!instance || !((1 << instance->base_type) & (RS::INSTANCE_GEOMETRY_MASK & (~(1 << RS::INSTANCE_PARTICLES))))) { //all but particles to avoid self collision +					continue;  				} +				geometry_instances_to_render.push_back(instance);  			} -			scene_render->render_particle_collider_heightfield(hfpc->base, hfpc->transform, (RendererSceneRender::InstanceBase **)instance_cull_result, cull_count); +			scene_render->render_particle_collider_heightfield(hfpc->base, hfpc->transform, geometry_instances_to_render);  		}  		heightfield_particle_colliders_update_list.erase(heightfield_particle_colliders_update_list.front());  	} @@ -3009,7 +3060,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {  			if (can_cast_shadows != geom->can_cast_shadows) {  				//ability to cast shadows change, let lights now -				for (List<Instance *>::Element *E = geom->lighting.front(); E; E = E->next()) { +				for (Set<Instance *>::Element *E = geom->lights.front(); E; E = E->next()) {  					InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data);  					light->shadow_dirty = true;  				} @@ -3060,6 +3111,12 @@ void RendererSceneCull::update_dirty_instances() {  }  void RendererSceneCull::update() { +	//optimize bvhs +	for (uint32_t i = 0; i < scenario_owner.get_rid_count(); i++) { +		Scenario *s = scenario_owner.get_ptr_by_index(i); +		s->indexers[Scenario::INDEXER_GEOMETRY].optimize_incremental(indexer_update_iterations); +		s->indexers[Scenario::INDEXER_VOLUMES].optimize_incremental(indexer_update_iterations); +	}  	scene_render->update();  	update_dirty_instances();  	render_particle_colliders(); @@ -3130,7 +3187,51 @@ RendererSceneCull *RendererSceneCull::singleton = nullptr;  RendererSceneCull::RendererSceneCull() {  	render_pass = 1;  	singleton = this; +	pair_volumes_to_mesh = false; + +	instance_cull_result.set_page_pool(&instance_cull_page_pool); +	instance_shadow_cull_result.set_page_pool(&instance_cull_page_pool); +	instance_sdfgi_cull_result.set_page_pool(&instance_cull_page_pool); +	light_cull_result.set_page_pool(&instance_cull_page_pool); +	directional_shadow_cull_result.set_page_pool(&instance_cull_page_pool); + +	geometry_instances_to_render.set_page_pool(&base_instance_cull_page_pool); +	geometry_instances_to_shadow_render.set_page_pool(&base_instance_cull_page_pool); +	geometry_instances_to_sdfgi_render.set_page_pool(&base_instance_cull_page_pool); +	lightmap_cull_result.set_page_pool(&base_instance_cull_page_pool); + +	reflection_probe_instance_cull_result.set_page_pool(&rid_cull_page_pool); +	light_instance_cull_result.set_page_pool(&rid_cull_page_pool); +	directional_light_cull_result.set_page_pool(&rid_cull_page_pool); +	gi_probe_instance_cull_result.set_page_pool(&rid_cull_page_pool); +	decal_instance_cull_result.set_page_pool(&rid_cull_page_pool); + +	for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { +		sdfgi_cascade_lights[i].set_page_pool(&rid_cull_page_pool); +	} + +	indexer_update_iterations = GLOBAL_GET("rendering/spatial_indexer/update_iterations_per_frame");  }  RendererSceneCull::~RendererSceneCull() { +	instance_cull_result.reset(); +	instance_shadow_cull_result.reset(); +	instance_sdfgi_cull_result.reset(); +	light_cull_result.reset(); +	directional_shadow_cull_result.reset(); + +	geometry_instances_to_render.reset(); +	geometry_instances_to_shadow_render.reset(); +	geometry_instances_to_sdfgi_render.reset(); +	lightmap_cull_result.reset(); + +	reflection_probe_instance_cull_result.reset(); +	light_instance_cull_result.reset(); +	directional_light_cull_result.reset(); +	gi_probe_instance_cull_result.reset(); +	decal_instance_cull_result.reset(); + +	for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { +		sdfgi_cascade_lights[i].reset(); +	}  } diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 051919314e..8bf262d7c0 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -34,30 +34,25 @@  #include "core/templates/pass_func.h"  #include "servers/rendering/renderer_compositor.h" +#include "core/math/dynamic_bvh.h"  #include "core/math/geometry_3d.h"  #include "core/math/octree.h"  #include "core/os/semaphore.h"  #include "core/os/thread.h"  #include "core/templates/local_vector.h" +#include "core/templates/paged_allocator.h" +#include "core/templates/paged_array.h"  #include "core/templates/rid_owner.h"  #include "core/templates/self_list.h"  #include "servers/rendering/renderer_scene.h"  #include "servers/rendering/renderer_scene_render.h"  #include "servers/xr/xr_interface.h" -  class RendererSceneCull : public RendererScene {  public:  	RendererSceneRender *scene_render;  	enum { -		MAX_INSTANCE_CULL = 65536, -		MAX_LIGHTS_CULLED = 4096, -		MAX_REFLECTION_PROBES_CULLED = 4096, -		MAX_DECALS_CULLED = 4096, -		MAX_GI_PROBES_CULLED = 4096, -		MAX_ROOM_CULL = 32, -		MAX_LIGHTMAPS_CULLED = 4096, -		MAX_EXTERIOR_PORTALS = 128, +		SDFGI_MAX_CASCADES = 8  	};  	uint64_t render_pass; @@ -114,11 +109,17 @@ public:  	struct Instance;  	struct Scenario { +		enum IndexerType { +			INDEXER_GEOMETRY, //for geometry +			INDEXER_VOLUMES, //for everything else +			INDEXER_MAX +		}; + +		DynamicBVH indexers[INDEXER_MAX]; +  		RS::ScenarioDebugMode debug;  		RID self; -		Octree<Instance, true> octree; -  		List<Instance *> directional_lights;  		RID environment;  		RID fallback_environment; @@ -130,13 +131,19 @@ public:  		LocalVector<RID> dynamic_lights; -		Scenario() { debug = RS::SCENARIO_DEBUG_DISABLED; } +		Scenario() { +			indexers[INDEXER_GEOMETRY].set_index(INDEXER_GEOMETRY); +			indexers[INDEXER_VOLUMES].set_index(INDEXER_VOLUMES); +			debug = RS::SCENARIO_DEBUG_DISABLED; +		}  	}; +	int indexer_update_iterations = 0; +  	mutable RID_PtrOwner<Scenario> scenario_owner; -	static void *_instance_pair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int); -	static void _instance_unpair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int, void *); +	static void _instance_pair(Instance *p_A, Instance *p_B); +	static void _instance_unpair(Instance *p_A, Instance *p_B);  	static void _instance_update_mesh_instance(Instance *p_instance); @@ -152,6 +159,17 @@ public:  	/* INSTANCING API */ +	struct InstancePair { +		Instance *a; +		Instance *b; +		SelfList<InstancePair> list_a; +		SelfList<InstancePair> list_b; +		InstancePair() : +				list_a(this), list_b(this) {} +	}; + +	PagedAllocator<InstancePair> pair_allocator; +  	struct InstanceBaseData {  		virtual ~InstanceBaseData() {}  	}; @@ -159,7 +177,7 @@ public:  	struct Instance : RendererSceneRender::InstanceBase {  		RID self;  		//scenario stuff -		OctreeElementID octree_id; +		DynamicBVH::ID indexer_id;  		Scenario *scenario;  		SelfList<Instance> scenario_item; @@ -188,6 +206,9 @@ public:  		InstanceBaseData *base_data; +		SelfList<InstancePair>::List pairs; +		uint64_t pair_check; +  		virtual void dependency_deleted(RID p_dependency) {  			if (p_dependency == base) {  				singleton->instance_set_base(self, RID()); @@ -205,7 +226,6 @@ public:  		Instance() :  				scenario_item(this),  				update_item(this) { -			octree_id = 0;  			scenario = nullptr;  			update_aabb = false; @@ -226,6 +246,8 @@ public:  			base_data = nullptr;  			custom_aabb = nullptr; + +			pair_check = 0;  		}  		~Instance() { @@ -242,21 +264,21 @@ public:  	void _instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies = false);  	struct InstanceGeometryData : public InstanceBaseData { -		List<Instance *> lighting; +		Set<Instance *> lights;  		bool lighting_dirty;  		bool can_cast_shadows;  		bool material_is_animated; -		List<Instance *> decals; +		Set<Instance *> decals;  		bool decal_dirty; -		List<Instance *> reflection_probes; +		Set<Instance *> reflection_probes;  		bool reflection_dirty; -		List<Instance *> gi_probes; +		Set<Instance *> gi_probes;  		bool gi_probes_dirty; -		List<Instance *> lightmap_captures; +		Set<Instance *> lightmap_captures;  		InstanceGeometryData() {  			lighting_dirty = false; @@ -271,11 +293,7 @@ public:  	struct InstanceReflectionProbeData : public InstanceBaseData {  		Instance *owner; -		struct PairInfo { -			List<Instance *>::Element *L; //reflection iterator in geometry -			Instance *geometry; -		}; -		List<PairInfo> geometries; +		Set<Instance *> geometries;  		RID instance;  		bool reflection_dirty; @@ -294,11 +312,7 @@ public:  		Instance *owner;  		RID instance; -		struct PairInfo { -			List<Instance *>::Element *L; //reflection iterator in geometry -			Instance *geometry; -		}; -		List<PairInfo> geometries; +		Set<Instance *> geometries;  		InstanceDecalData() {  		} @@ -307,18 +321,13 @@ public:  	SelfList<InstanceReflectionProbeData>::List reflection_probe_render_list;  	struct InstanceLightData : public InstanceBaseData { -		struct PairInfo { -			List<Instance *>::Element *L; //light iterator in geometry -			Instance *geometry; -		}; -  		RID instance;  		uint64_t last_version;  		List<Instance *>::Element *D; // directional light in scenario  		bool shadow_dirty; -		List<PairInfo> geometries; +		Set<Instance *> geometries;  		Instance *baked_light; @@ -339,13 +348,8 @@ public:  	struct InstanceGIProbeData : public InstanceBaseData {  		Instance *owner; -		struct PairInfo { -			List<Instance *>::Element *L; //gi probe iterator in geometry -			Instance *geometry; -		}; - -		List<PairInfo> geometries; -		List<PairInfo> dynamic_geometries; +		Set<Instance *> geometries; +		Set<Instance *> dynamic_geometries;  		Set<Instance *> lights; @@ -383,40 +387,110 @@ public:  	SelfList<InstanceGIProbeData>::List gi_probe_update_list;  	struct InstanceLightmapData : public InstanceBaseData { -		struct PairInfo { -			List<Instance *>::Element *L; //iterator in geometry -			Instance *geometry; -		}; -		List<PairInfo> geometries; - +		Set<Instance *> geometries;  		Set<Instance *> users;  		InstanceLightmapData() {  		}  	}; +	uint64_t pair_pass = 1; + +	struct PairInstances { +		Instance *instance = nullptr; +		PagedAllocator<InstancePair> *pair_allocator = nullptr; +		SelfList<InstancePair>::List pairs_found; +		DynamicBVH *bvh = nullptr; +		DynamicBVH *bvh2 = nullptr; //some may need to cull in two +		uint32_t pair_mask; +		uint64_t pair_pass; + +		_FORCE_INLINE_ bool operator()(void *p_data) { +			Instance *p_instance = (Instance *)p_data; +			if (instance != p_instance && instance->transformed_aabb.intersects(p_instance->transformed_aabb) && (pair_mask & (1 << p_instance->base_type))) { +				//test is more coarse in indexer +				p_instance->pair_check = pair_pass; +				InstancePair *pair = pair_allocator->alloc(); +				pair->a = instance; +				pair->b = p_instance; +				pairs_found.add(&pair->list_a); +			} +			return false; +		} + +		void pair() { +			if (bvh) { +				bvh->aabb_query(instance->transformed_aabb, *this); +			} +			if (bvh2) { +				bvh2->aabb_query(instance->transformed_aabb, *this); +			} +			while (instance->pairs.first()) { +				InstancePair *pair = instance->pairs.first()->self(); +				Instance *other_instance = instance == pair->a ? pair->b : pair->a; +				if (other_instance->pair_check != pair_pass) { +					//unpaired +					_instance_unpair(instance, other_instance); +				} else { +					//kept +					other_instance->pair_check = 0; // if kept, then put pair check to zero, so we can distinguish with the newly added ones +				} + +				pair_allocator->free(pair); +			} +			while (pairs_found.first()) { +				InstancePair *pair = pairs_found.first()->self(); +				pairs_found.remove(pairs_found.first()); + +				if (pair->b->pair_check == pair_pass) { +					//paired +					_instance_pair(instance, pair->b); +				} +				pair->a->pairs.add(&pair->list_a); +				pair->b->pairs.add(&pair->list_b); +			} +		} +	}; + +	struct CullResult { +		PagedArray<Instance *> *result; +		_FORCE_INLINE_ bool operator()(void *p_data) { +			Instance *p_instance = (Instance *)p_data; +			result->push_back(p_instance); +			return false; +		} +	}; +  	Set<Instance *> heightfield_particle_colliders_update_list; -	int instance_cull_count; -	Instance *instance_cull_result[MAX_INSTANCE_CULL]; -	Instance *instance_shadow_cull_result[MAX_INSTANCE_CULL]; //used for generating shadowmaps -	Instance *light_cull_result[MAX_LIGHTS_CULLED]; -	RID sdfgi_light_cull_result[MAX_LIGHTS_CULLED]; -	RID light_instance_cull_result[MAX_LIGHTS_CULLED]; +	PagedArrayPool<Instance *> instance_cull_page_pool; +	PagedArrayPool<RendererSceneRender::InstanceBase *> base_instance_cull_page_pool; +	PagedArrayPool<RID> rid_cull_page_pool; + +	PagedArray<Instance *> instance_cull_result; +	PagedArray<RendererSceneRender::InstanceBase *> geometry_instances_to_render; +	PagedArray<Instance *> instance_shadow_cull_result; +	PagedArray<RendererSceneRender::InstanceBase *> geometry_instances_to_shadow_render; +	PagedArray<Instance *> instance_sdfgi_cull_result; +	PagedArray<RendererSceneRender::InstanceBase *> geometry_instances_to_sdfgi_render; +	PagedArray<Instance *> light_cull_result; +	PagedArray<RendererSceneRender::InstanceBase *> lightmap_cull_result; +	PagedArray<Instance *> directional_shadow_cull_result; +	PagedArray<RID> reflection_probe_instance_cull_result; +	PagedArray<RID> light_instance_cull_result; +	PagedArray<RID> directional_light_cull_result; +	PagedArray<RID> gi_probe_instance_cull_result; +	PagedArray<RID> decal_instance_cull_result; + +	PagedArray<RID> sdfgi_cascade_lights[SDFGI_MAX_CASCADES]; +  	uint64_t sdfgi_light_cull_pass = 0; -	int light_cull_count;  	int directional_light_count; -	RID reflection_probe_instance_cull_result[MAX_REFLECTION_PROBES_CULLED]; -	RID decal_instance_cull_result[MAX_DECALS_CULLED]; -	int reflection_probe_cull_count; -	int decal_cull_count; -	RID gi_probe_instance_cull_result[MAX_GI_PROBES_CULLED]; -	int gi_probe_cull_count; -	Instance *lightmap_cull_result[MAX_LIGHTS_CULLED]; -	int lightmap_cull_count;  	RID_PtrOwner<Instance> instance_owner; +	bool pair_volumes_to_mesh; // used in traditional forward, unnecesary on clustered +  	virtual RID instance_create();  	virtual void instance_set_base(RID p_instance, RID p_base); @@ -460,6 +534,7 @@ public:  	_FORCE_INLINE_ void _update_instance_aabb(Instance *p_instance);  	_FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance);  	_FORCE_INLINE_ void _update_instance_lightmap_captures(Instance *p_instance); +	void _unpair_instance(Instance *p_instance);  	_FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, float p_scren_lod_threshold); diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h index b6bdcab88f..f8b70e3ad4 100644 --- a/servers/rendering/renderer_scene_render.h +++ b/servers/rendering/renderer_scene_render.h @@ -32,6 +32,7 @@  #define RENDERINGSERVERSCENERENDER_H  #include "core/math/camera_matrix.h" +#include "core/templates/paged_array.h"  #include "servers/rendering/renderer_storage.h"  class RendererSceneRender { @@ -55,7 +56,7 @@ public:  	virtual int sdfgi_get_pending_region_count(RID p_render_buffers) const = 0;  	virtual AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const = 0;  	virtual uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const = 0; -	virtual void sdfgi_update_probes(RID p_render_buffers, RID p_environment, const RID *p_directional_light_instances, uint32_t p_directional_light_count, const RID *p_positional_light_instances, uint32_t p_positional_light_count) = 0; +	virtual void sdfgi_update_probes(RID p_render_buffers, RID p_environment, const PagedArray<RID> &p_directionals, const RID *p_positional_light_instances, uint32_t p_positional_light_count) = 0;  	/* SKY API */ @@ -231,17 +232,17 @@ public:  	virtual RID gi_probe_instance_create(RID p_gi_probe) = 0;  	virtual void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) = 0;  	virtual bool gi_probe_needs_update(RID p_probe) const = 0; -	virtual void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects) = 0; +	virtual void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::InstanceBase *> &p_dynamic_objects) = 0;  	virtual void gi_probe_set_quality(RS::GIProbeQuality) = 0; -	virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, InstanceBase **p_lightmap_cull_result, int p_lightmap_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold) = 0; +	virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<InstanceBase *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<InstanceBase *> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold) = 0; -	virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0) = 0; -	virtual void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0; -	virtual void render_sdfgi(RID p_render_buffers, int p_region, InstanceBase **p_cull_result, int p_cull_count) = 0; -	virtual void render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const RID **p_positional_light_cull_result, const uint32_t *p_positional_light_cull_count) = 0; -	virtual void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, InstanceBase **p_cull_result, int p_cull_count) = 0; +	virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<InstanceBase *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0) = 0; +	virtual void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<InstanceBase *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; +	virtual void render_sdfgi(RID p_render_buffers, int p_region, const PagedArray<InstanceBase *> &p_instances) = 0; +	virtual void render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_lights) = 0; +	virtual void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<InstanceBase *> &p_instances) = 0;  	virtual void set_scene_pass(uint64_t p_pass) = 0;  	virtual void set_time(double p_time, double p_step) = 0; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 3eff92d916..0a3e82ea22 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2359,6 +2359,9 @@ RenderingServer::RenderingServer() {  	ProjectSettings::get_singleton()->set_custom_property_info("rendering/volumetric_fog/directional_shadow_shrink", PropertyInfo(Variant::INT, "rendering/volumetric_fog/directional_shadow_shrink", PROPERTY_HINT_RANGE, "32,2048,1"));  	GLOBAL_DEF("rendering/volumetric_fog/positional_shadow_shrink", 512);  	ProjectSettings::get_singleton()->set_custom_property_info("rendering/volumetric_fog/positional_shadow_shrink", PropertyInfo(Variant::INT, "rendering/volumetric_fog/positional_shadow_shrink", PROPERTY_HINT_RANGE, "32,2048,1")); + +	GLOBAL_DEF("rendering/spatial_indexer/update_iterations_per_frame", 10); +	ProjectSettings::get_singleton()->set_custom_property_info("rendering/spatial_indexer/update_iterations_per_frame", PropertyInfo(Variant::INT, "rendering/spatial_indexer/update_iterations_per_frame", PROPERTY_HINT_RANGE, "0,1024,1"));  }  RenderingServer::~RenderingServer() {  |