From 83058597cf02255d7c0359a96f125010f63deff7 Mon Sep 17 00:00:00 2001 From: reduz Date: Wed, 23 Dec 2020 13:52:58 -0300 Subject: [PATCH] Replace Octree by DynamicBVH in cull code -Much greater pairing/unpairing performance -For now, using it for culling too, but this will change in a couple of days. -Added a paged allocator, to efficiently alloc/free some types of objects. --- core/math/dynamic_bvh.cpp | 25 +- core/math/dynamic_bvh.h | 125 ++- core/templates/paged_allocator.h | 129 +++ core/templates/paged_array.h | 2 +- core/templates/rid_owner.h | 13 + .../renderer_scene_render_forward.cpp | 62 +- .../renderer_scene_render_forward.h | 18 +- .../renderer_rd/renderer_scene_render_rd.cpp | 123 +-- .../renderer_rd/renderer_scene_render_rd.h | 41 +- servers/rendering/renderer_scene_cull.cpp | 849 ++++++++++-------- servers/rendering/renderer_scene_cull.h | 205 +++-- servers/rendering/renderer_scene_render.h | 17 +- servers/rendering_server.cpp | 3 + 13 files changed, 1041 insertions(+), 571 deletions(-) create mode 100644 core/templates/paged_allocator.h diff --git a/core/math/dynamic_bvh.cpp b/core/math/dynamic_bvh.cpp index 8486415c812..5f87f75b61e 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 *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 *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 81d70d7469d..cdea51c674a 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 *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 _FORCE_INLINE_ void aabb_query(const AABB &p_aabb, QueryResult &r_result); template + _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 _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 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) { @@ -303,8 +350,67 @@ void DynamicBVH::aabb_query(const AABB &p_box, QueryResult &r_result) { } while (depth > 0); } +template +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 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 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 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 00000000000..8bd1eecdebd --- /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 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 71183c4ad81..aaf38937150 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 d1bcb92010d..7de4e43648f 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 *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 01dd2965c48..c6b2fa6dc06 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 &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 &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 &p_instances, int p_directional_light_count, const PagedArray &p_gi_probes, const PagedArray &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 &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()); 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 &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()); 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 &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()); 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 &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()); 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 &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 &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 da4cb579c1f..5d77c13b434 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 &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 &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 &p_instances, PassMode p_pass_mode, bool p_using_sdfgi = false); Map 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 &p_instances, int p_directional_light_count, const PagedArray &p_gi_probes, const PagedArray &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 &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 &p_instances, RID p_framebuffer, const Rect2i &p_region); + virtual void _render_uv2(const PagedArray &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 &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 &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 1d9983a28c0..02ec399f58d 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 &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(" &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 &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 &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 &p_light_instances, const PagedArray &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 &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 &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 &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 &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_gi_probes, const PagedArray &p_decals, const PagedArray &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 *lights = &p_lights; + const PagedArray *reflections = &p_reflection_probes; + const PagedArray *gi_probes = &p_gi_probes; + + PagedArray 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 &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 &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 &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 &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 *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 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 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 1b0ae61042c..ded6d99e479 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); + void _setup_lights(const PagedArray &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 &p_decals, const Transform &p_camera_inverse_xform); + void _setup_reflections(const PagedArray &p_reflections, const Transform &p_camera_inverse_transform, RID p_environment); + void _setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray &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, 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; + virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray &p_instances, int p_directional_light_count, const PagedArray &p_gi_probes, const PagedArray &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 &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 &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; + virtual void _render_uv2(const PagedArray &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 &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 &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 &p_gi_probes); + // needed for a single argument calls (material and uv2) + PagedArrayPool cull_argument_pool; + PagedArray 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 &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 &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 &p_light_instances, const PagedArray &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 &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_gi_probes, const PagedArray &p_decals, const PagedArray &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 &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 &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 &p_instances); + void render_sdfgi_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray *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 &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 88a0859a280..1db678a441f 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(B->base_data); InstanceGeometryData *geom = static_cast(A->base_data); - InstanceLightData::PairInfo pinfo; - pinfo.geometry = A; - pinfo.L = geom->lighting.push_back(B); - - List::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(B->base_data); InstanceGeometryData *geom = static_cast(A->base_data); - InstanceReflectionProbeData::PairInfo pinfo; - pinfo.geometry = A; - pinfo.L = geom->reflection_probes.push_back(B); - - List::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(B->base_data); InstanceGeometryData *geom = static_cast(A->base_data); - InstanceDecalData::PairInfo pinfo; - pinfo.geometry = A; - pinfo.L = geom->decals.push_back(B); - - List::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(B->base_data); InstanceGeometryData *geom = static_cast(A->base_data); if (A->dynamic_gi) { - InstanceLightmapData::PairInfo pinfo; - pinfo.geometry = A; - pinfo.L = geom->lightmap_captures.push_back(B); - List::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(B->base_data); InstanceGeometryData *geom = static_cast(A->base_data); - InstanceGIProbeData::PairInfo pinfo; - pinfo.geometry = A; - pinfo.L = geom->gi_probes.push_back(B); + geom->gi_probes.insert(B); - List::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(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(B->base_data); InstanceGeometryData *geom = static_cast(A->base_data); - List::Element *E = reinterpret_cast::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(B->base_data); InstanceGeometryData *geom = static_cast(A->base_data); - List::Element *E = reinterpret_cast::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(B->base_data); InstanceGeometryData *geom = static_cast(A->base_data); - List::Element *E = reinterpret_cast::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(B->base_data); - InstanceGeometryData *geom = static_cast(A->base_data); - - List::Element *E = reinterpret_cast::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(B->base_data); + InstanceGeometryData *geom = static_cast(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(B->base_data); InstanceGeometryData *geom = static_cast(A->base_data); - List::Element *E = reinterpret_cast::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(B->base_data); - Set::Element *E = reinterpret_cast::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 RendererSceneCull::instances_cull_aabb(const AABB &p_aabb, RID const_cast(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 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 RendererSceneCull::instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario) const { @@ -847,21 +774,21 @@ Vector RendererSceneCull::instances_cull_ray(const Vector3 &p_from, co ERR_FAIL_COND_V(!scenario, instances); const_cast(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 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 RendererSceneCull::instances_cull_convex(const Vector &p_convex, RID p_scenario) const { @@ -870,22 +797,23 @@ Vector RendererSceneCull::instances_cull_convex(const Vector &p ERR_FAIL_COND_V(!scenario, instances); const_cast(this)->update_dirty_instances(); // check dirty instances before culling - int culled = 0; - Instance *cull[1024]; + Vector points = Geometry3D::compute_convex_mesh_points(&p_convex[0], p_convex.size()); - culled = scenario->octree.cull_convex(p_convex, cull, 1024); - - for (int i = 0; i < culled; i++) { - Instance *instance = cull[i]; - ERR_CONTINUE(!instance); - if (instance->object_id.is_null()) { - continue; + struct CullConvex { + Vector 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::Element *E = geom->lighting.front(); E; E = E->next()) { + for (Set::Element *E = geom->lights.front(); E; E = E->next()) { InstanceLightData *light = static_cast(E->get()->base_data); light->shadow_dirty = true; } @@ -1124,8 +1050,8 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { InstanceLightmapData *lightmap_data = static_cast(p_instance->base_data); //erase dependencies, since no longer a lightmap - for (List::Element *E = lightmap_data->geometries.front(); E; E = E->next()) { - Instance *geom = E->get().geometry; + for (Set::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; - } - - 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; - } - - // not inside octree - p_instance->octree_id = p_instance->scenario->octree.create(p_instance, new_aabb, 0, pairable, base_type, pairable_mask); - - } else { - /* - if (new_aabb==p_instance->data.transformed_aabb) - return; - */ - - p_instance->scenario->octree.move(p_instance->octree_id, new_aabb); } + + //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 (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]; + } + + pair.pair(); +} + +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); + } + + 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(p_instance->base_data); - for (List::Element *E = geom->lightmap_captures.front(); E; E = E->next()) { + for (Set::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 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 points = Geometry3D::compute_convex_mesh_points(&planes[0], planes.size()); + + geometry_instances_to_shadow_render.clear(); + + struct CullConvex { + PagedArray *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(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 points = Geometry3D::compute_convex_mesh_points(&light_frustum_planes[0], light_frustum_planes.size()); + + struct CullConvex { + PagedArray *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(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 points = Geometry3D::compute_convex_mesh_points(&planes[0], planes.size()); + + struct CullConvex { + PagedArray *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(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(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 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 points = Geometry3D::compute_convex_mesh_points(&planes[0], planes.size()); + + struct CullConvex { + PagedArray *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(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(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 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 points = Geometry3D::compute_convex_mesh_points(&planes[0], planes.size()); + + struct CullConvex { + PagedArray *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(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(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; - reflection_probe_cull_count = 0; - decal_cull_count = 0; - gi_probe_cull_count = 0; - lightmap_cull_count = 0; + Vector points = Geometry3D::compute_convex_mesh_points(&planes[0], planes.size()); + + 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(ins->base_data); + } else if (ins->base_type == RS::INSTANCE_LIGHT) { + InstanceLightData *light = static_cast(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 + 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) { + InstanceReflectionProbeData *reflection_probe = static_cast(ins->base_data); + + if (p_reflection_probe != reflection_probe->instance) { + //avoid entering The Matrix + + 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); } - light_cull_count++; + reflection_probe->reflection_dirty = false; + } + + 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_REFLECTION_PROBE && ins->visible) { - if (reflection_probe_cull_count < MAX_REFLECTION_PROBES_CULLED) { - InstanceReflectionProbeData *reflection_probe = static_cast(ins->base_data); + } else if (ins->base_type == RS::INSTANCE_DECAL) { + InstanceDecalData *decal = static_cast(ins->base_data); - if (p_reflection_probe != reflection_probe->instance) { - //avoid entering The Matrix + decal_instance_cull_result.push_back(decal->instance); - 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); - } - - reflection_probe->reflection_dirty = false; - } - - 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++; - } - } - } - } - } else if (ins->base_type == RS::INSTANCE_DECAL && ins->visible) { - if (decal_cull_count < MAX_DECALS_CULLED) { - InstanceDecalData *decal = static_cast(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++; - } - } - - } 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(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(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::Element *E = geom->lighting.front(); E; E = E->next()) { + for (Set::Element *E = geom->lights.front(); E; E = E->next()) { InstanceLightData *light = static_cast(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::Element *E = geom->reflection_probes.front(); E; E = E->next()) { + for (Set::Element *E = geom->reflection_probes.front(); E; E = E->next()) { InstanceReflectionProbeData *reflection_probe = static_cast(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::Element *E = geom->gi_probes.front(); E; E = E->next()) { + for (Set::Element *E = geom->gi_probes.front(); E; E = E->next()) { InstanceGIProbeData *gi_probe = static_cast(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) { + geometry_instances_to_render.push_back(ins); + ins->last_render_pass = render_pass; + } else { + ins->last_render_pass = 0; // make invalid + } } - 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; - } 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::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(" 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; - for (uint32_t j = 0; j < sdfgi_cull_count; j++) { - Instance *ins = instance_shadow_cull_result[j]; + scenario->indexers[Scenario::INDEXER_GEOMETRY].aabb_query(region, cull_result); + scenario->indexers[Scenario::INDEXER_VOLUMES].aabb_query(region, cull_result); + } + + 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(), PagedArray(), PagedArray(), PagedArray(), PagedArray(), PagedArray(), 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::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 (List::Element *F = geom->gi_probes.front(); F; F = F->next()) { - InstanceGIProbeData *gi_probe2 = static_cast(F->get()->base_data); - - ins->gi_probe_instances.write[l++] = gi_probe2->probe_instance; - } - - geom->gi_probes_dirty = false; - } - - instance_cull_result[instance_cull_count++] = E->get().geometry; + for (Set::Element *E = probe->dynamic_geometries.front(); E; E = E->next()) { + Instance *ins = E->get(); + if (!ins->visible) { + continue; } + InstanceGeometryData *geom = (InstanceGeometryData *)ins->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()); + + for (Set::Element *F = geom->gi_probes.front(); F; F = F->next()) { + InstanceGIProbeData *gi_probe2 = static_cast(F->get()->base_data); + + ins->gi_probe_instances.write[l++] = gi_probe2->probe_instance; + } + + 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 *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]); + instance_cull_result.clear(); + geometry_instances_to_render.clear(); + + struct CullAABB { + PagedArray *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 || !((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::Element *E = geom->lighting.front(); E; E = E->next()) { + for (Set::Element *E = geom->lights.front(); E; E = E->next()) { InstanceLightData *light = static_cast(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 051919314e5..8bf262d7c0a 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 octree; - List directional_lights; RID environment; RID fallback_environment; @@ -130,13 +131,19 @@ public: LocalVector 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_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 list_a; + SelfList list_b; + InstancePair() : + list_a(this), list_b(this) {} + }; + + PagedAllocator 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 scenario_item; @@ -188,6 +206,9 @@ public: InstanceBaseData *base_data; + SelfList::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 lighting; + Set lights; bool lighting_dirty; bool can_cast_shadows; bool material_is_animated; - List decals; + Set decals; bool decal_dirty; - List reflection_probes; + Set reflection_probes; bool reflection_dirty; - List gi_probes; + Set gi_probes; bool gi_probes_dirty; - List lightmap_captures; + Set lightmap_captures; InstanceGeometryData() { lighting_dirty = false; @@ -271,11 +293,7 @@ public: struct InstanceReflectionProbeData : public InstanceBaseData { Instance *owner; - struct PairInfo { - List::Element *L; //reflection iterator in geometry - Instance *geometry; - }; - List geometries; + Set geometries; RID instance; bool reflection_dirty; @@ -294,11 +312,7 @@ public: Instance *owner; RID instance; - struct PairInfo { - List::Element *L; //reflection iterator in geometry - Instance *geometry; - }; - List geometries; + Set geometries; InstanceDecalData() { } @@ -307,18 +321,13 @@ public: SelfList::List reflection_probe_render_list; struct InstanceLightData : public InstanceBaseData { - struct PairInfo { - List::Element *L; //light iterator in geometry - Instance *geometry; - }; - RID instance; uint64_t last_version; List::Element *D; // directional light in scenario bool shadow_dirty; - List geometries; + Set geometries; Instance *baked_light; @@ -339,13 +348,8 @@ public: struct InstanceGIProbeData : public InstanceBaseData { Instance *owner; - struct PairInfo { - List::Element *L; //gi probe iterator in geometry - Instance *geometry; - }; - - List geometries; - List dynamic_geometries; + Set geometries; + Set dynamic_geometries; Set lights; @@ -383,40 +387,110 @@ public: SelfList::List gi_probe_update_list; struct InstanceLightmapData : public InstanceBaseData { - struct PairInfo { - List::Element *L; //iterator in geometry - Instance *geometry; - }; - List geometries; - + Set geometries; Set users; InstanceLightmapData() { } }; + uint64_t pair_pass = 1; + + struct PairInstances { + Instance *instance = nullptr; + PagedAllocator *pair_allocator = nullptr; + SelfList::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 *result; + _FORCE_INLINE_ bool operator()(void *p_data) { + Instance *p_instance = (Instance *)p_data; + result->push_back(p_instance); + return false; + } + }; + Set 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_cull_page_pool; + PagedArrayPool base_instance_cull_page_pool; + PagedArrayPool rid_cull_page_pool; + + PagedArray instance_cull_result; + PagedArray geometry_instances_to_render; + PagedArray instance_shadow_cull_result; + PagedArray geometry_instances_to_shadow_render; + PagedArray instance_sdfgi_cull_result; + PagedArray geometry_instances_to_sdfgi_render; + PagedArray light_cull_result; + PagedArray lightmap_cull_result; + PagedArray directional_shadow_cull_result; + PagedArray reflection_probe_instance_cull_result; + PagedArray light_instance_cull_result; + PagedArray directional_light_cull_result; + PagedArray gi_probe_instance_cull_result; + PagedArray decal_instance_cull_result; + + PagedArray 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_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 b6bdcab88f2..f8b70e3ad40 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 &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 &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 &p_light_instances, const PagedArray &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 &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_gi_probes, const PagedArray &p_decals, const PagedArray &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 &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 &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; + virtual void render_sdfgi(RID p_render_buffers, int p_region, const PagedArray &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 *p_positional_lights) = 0; + virtual void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray &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 3eff92d916b..0a3e82ea22f 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() {