diff --git a/core/templates/rid.h b/core/templates/rid.h index 7fe6dbe4735..4c7119b4ea0 100644 --- a/core/templates/rid.h +++ b/core/templates/rid.h @@ -40,30 +40,37 @@ class RID { uint64_t _id = 0; public: - _FORCE_INLINE_ bool operator==(const RID &p_rid) const { + _ALWAYS_INLINE_ bool operator==(const RID &p_rid) const { return _id == p_rid._id; } - _FORCE_INLINE_ bool operator<(const RID &p_rid) const { + _ALWAYS_INLINE_ bool operator<(const RID &p_rid) const { return _id < p_rid._id; } - _FORCE_INLINE_ bool operator<=(const RID &p_rid) const { + _ALWAYS_INLINE_ bool operator<=(const RID &p_rid) const { return _id <= p_rid._id; } - _FORCE_INLINE_ bool operator>(const RID &p_rid) const { + _ALWAYS_INLINE_ bool operator>(const RID &p_rid) const { return _id > p_rid._id; } - _FORCE_INLINE_ bool operator>=(const RID &p_rid) const { + _ALWAYS_INLINE_ bool operator>=(const RID &p_rid) const { return _id >= p_rid._id; } - _FORCE_INLINE_ bool operator!=(const RID &p_rid) const { + _ALWAYS_INLINE_ bool operator!=(const RID &p_rid) const { return _id != p_rid._id; } - _FORCE_INLINE_ bool is_valid() const { return _id != 0; } - _FORCE_INLINE_ bool is_null() const { return _id == 0; } + _ALWAYS_INLINE_ bool is_valid() const { return _id != 0; } + _ALWAYS_INLINE_ bool is_null() const { return _id == 0; } - _FORCE_INLINE_ uint64_t get_id() const { return _id; } + _ALWAYS_INLINE_ uint32_t get_local_index() const { return _id & 0xFFFFFFFF; } - _FORCE_INLINE_ RID() {} + static _ALWAYS_INLINE_ RID from_uint64(uint64_t p_id) { + RID _rid; + _rid._id = p_id; + return _rid; + } + _ALWAYS_INLINE_ uint64_t get_id() const { return _id; } + + _ALWAYS_INLINE_ RID() {} }; #endif // RID_H diff --git a/core/templates/thread_work_pool.h b/core/templates/thread_work_pool.h index 02d941d0f47..7c3508814fc 100644 --- a/core/templates/thread_work_pool.h +++ b/core/templates/thread_work_pool.h @@ -125,6 +125,7 @@ public: end_work(); } + _FORCE_INLINE_ int get_thread_count() const { return thread_count; } void init(int p_thread_count = -1); void finish(); ~ThreadWorkPool(); diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 52e090e4edd..6eadec4cce6 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -5638,7 +5638,7 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(Di vkCmdSetScissor(command_buffer, 0, 1, &scissor); - return ID_TYPE_DRAW_LIST; + return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT; } Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass) { @@ -5905,7 +5905,7 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu vkCmdSetScissor(command_buffer, 0, 1, &scissor); draw_list->viewport = Rect2i(viewport_offset, viewport_size); - return ID_TYPE_DRAW_LIST; + return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT; } Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector &p_storage_textures) { @@ -6002,7 +6002,7 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p for (uint32_t i = 0; i < p_splits; i++) { //take a command buffer and initialize it - VkCommandBuffer command_buffer = split_draw_list_allocators[p_splits].command_buffers[frame]; + VkCommandBuffer command_buffer = split_draw_list_allocators[i].command_buffers[frame]; VkCommandBufferInheritanceInfo inheritance_info; inheritance_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; @@ -6060,7 +6060,7 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p scissor.extent.height = viewport_size.height; vkCmdSetScissor(command_buffer, 0, 1, &scissor); - r_split_ids[i] = (DrawListID(1) << DrawListID(ID_TYPE_SPLIT_DRAW_LIST)) + i; + r_split_ids[i] = (int64_t(ID_TYPE_SPLIT_DRAW_LIST) << ID_BASE_SHIFT) + i; draw_list[i].viewport = Rect2i(viewport_offset, viewport_size); } @@ -6075,7 +6075,7 @@ RenderingDeviceVulkan::DrawList *RenderingDeviceVulkan::_get_draw_list_ptr(DrawL if (!draw_list) { return nullptr; - } else if (p_id == ID_TYPE_DRAW_LIST) { + } else if (p_id == (int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT)) { if (draw_list_split) { return nullptr; } @@ -6442,8 +6442,8 @@ void RenderingDeviceVulkan::draw_list_end() { //send all command buffers VkCommandBuffer *command_buffers = (VkCommandBuffer *)alloca(sizeof(VkCommandBuffer) * draw_list_count); for (uint32_t i = 0; i < draw_list_count; i++) { - vkEndCommandBuffer(draw_list->command_buffer); - command_buffers[i] = draw_list->command_buffer; + vkEndCommandBuffer(draw_list[i].command_buffer); + command_buffers[i] = draw_list[i].command_buffer; } vkCmdExecuteCommands(frames[frame].draw_command_buffer, draw_list_count, command_buffers); diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index fb9c114ade7..be2552bd326 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -154,12 +154,9 @@ void RendererCompositorRD::initialize() { } } -ThreadWorkPool RendererCompositorRD::thread_work_pool; uint64_t RendererCompositorRD::frame = 1; void RendererCompositorRD::finalize() { - thread_work_pool.finish(); - memdelete(scene); memdelete(canvas); memdelete(storage); @@ -174,7 +171,6 @@ RendererCompositorRD *RendererCompositorRD::singleton = nullptr; RendererCompositorRD::RendererCompositorRD() { singleton = this; - thread_work_pool.init(); time = 0; storage = memnew(RendererStorageRD); diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h index e1995872af1..cb85fc79e0e 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.h +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h @@ -90,8 +90,6 @@ public: virtual bool is_low_end() const { return false; } - static ThreadWorkPool thread_work_pool; - static RendererCompositorRD *singleton; RendererCompositorRD(); ~RendererCompositorRD() {} diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp b/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp index 6881d7913f5..c0939f23eff 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp @@ -806,252 +806,89 @@ bool RendererSceneRenderForward::free(RID p_rid) { return false; } -void RendererSceneRenderForward::_fill_instances(RenderList::Element **p_elements, int p_element_count, bool p_for_depth, bool p_has_sdfgi, bool p_has_opaque_gi) { - uint32_t lightmap_captures_used = 0; - - for (int i = 0; i < p_element_count; i++) { - const RenderList::Element *e = p_elements[i]; - InstanceData &id = scene_state.instances[i]; - bool store_transform = true; - id.flags = 0; - id.mask = e->instance->layer_mask; - id.instance_uniforms_ofs = e->instance->instance_allocated_shader_parameters_offset >= 0 ? e->instance->instance_allocated_shader_parameters_offset : 0; - - if (e->instance->base_type == RS::INSTANCE_MULTIMESH) { - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH; - uint32_t stride; - if (storage->multimesh_get_transform_format(e->instance->base) == RS::MULTIMESH_TRANSFORM_2D) { - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; - stride = 2; - } else { - stride = 3; - } - if (storage->multimesh_uses_colors(e->instance->base)) { - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; - stride += 1; - } - if (storage->multimesh_uses_custom_data(e->instance->base)) { - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; - stride += 1; - } - - id.flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); - } else if (e->instance->base_type == RS::INSTANCE_PARTICLES) { - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH; - uint32_t stride; - if (false) { // 2D particles - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; - stride = 2; - } else { - stride = 3; - } - - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; - stride += 1; - - id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; - stride += 1; - - id.flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); - - if (!storage->particles_is_using_local_coords(e->instance->base)) { - store_transform = false; - } - - } else if (e->instance->base_type == RS::INSTANCE_MESH) { - if (e->instance->skeleton.is_valid()) { - id.flags |= INSTANCE_DATA_FLAG_SKELETON; - } - } - - if (store_transform) { - RendererStorageRD::store_transform(e->instance->transform, id.transform); - RendererStorageRD::store_transform(Transform(e->instance->transform.basis.inverse().transposed()), id.normal_transform); - } else { - RendererStorageRD::store_transform(Transform(), id.transform); - RendererStorageRD::store_transform(Transform(), id.normal_transform); - } - - if (p_for_depth) { - id.gi_offset = 0xFFFFFFFF; - continue; - } - - if (e->instance->lightmap) { - int32_t lightmap_index = storage->lightmap_get_array_index(e->instance->lightmap->base); - if (lightmap_index >= 0) { - id.gi_offset = lightmap_index; - id.gi_offset |= e->instance->lightmap_slice_index << 12; - id.gi_offset |= e->instance->lightmap_cull_index << 20; - id.lightmap_uv_scale[0] = e->instance->lightmap_uv_scale.position.x; - id.lightmap_uv_scale[1] = e->instance->lightmap_uv_scale.position.y; - id.lightmap_uv_scale[2] = e->instance->lightmap_uv_scale.size.width; - id.lightmap_uv_scale[3] = e->instance->lightmap_uv_scale.size.height; - id.flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP; - if (storage->lightmap_uses_spherical_harmonics(e->instance->lightmap->base)) { - id.flags |= INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP; - } - } else { - id.gi_offset = 0xFFFFFFFF; - } - } else if (!e->instance->lightmap_sh.is_empty()) { - if (lightmap_captures_used < scene_state.max_lightmap_captures) { - const Color *src_capture = e->instance->lightmap_sh.ptr(); - LightmapCaptureData &lcd = scene_state.lightmap_captures[lightmap_captures_used]; - for (int j = 0; j < 9; j++) { - lcd.sh[j * 4 + 0] = src_capture[j].r; - lcd.sh[j * 4 + 1] = src_capture[j].g; - lcd.sh[j * 4 + 2] = src_capture[j].b; - lcd.sh[j * 4 + 3] = src_capture[j].a; - } - id.flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE; - id.gi_offset = lightmap_captures_used; - lightmap_captures_used++; - } - - } else { - if (p_has_opaque_gi) { - id.flags |= INSTANCE_DATA_FLAG_USE_GI_BUFFERS; - } - - if (!low_end && !e->instance->gi_probe_instances.is_empty()) { - uint32_t written = 0; - for (int j = 0; j < e->instance->gi_probe_instances.size(); j++) { - RID probe = e->instance->gi_probe_instances[j]; - - uint32_t index = gi_probe_instance_get_render_index(probe); - - if (written == 0) { - id.gi_offset = index; - id.flags |= INSTANCE_DATA_FLAG_USE_GIPROBE; - written = 1; - } else { - id.gi_offset = index << 16; - written = 2; - break; - } - } - if (written == 0) { - id.gi_offset = 0xFFFFFFFF; - } else if (written == 1) { - id.gi_offset |= 0xFFFF0000; - } - } else { - if (p_has_sdfgi && (e->instance->baked_light || e->instance->dynamic_gi)) { - id.flags |= INSTANCE_DATA_FLAG_USE_SDFGI; - } - id.gi_offset = 0xFFFFFFFF; - } - } - } - - RD::get_singleton()->buffer_update(scene_state.instance_buffer, 0, sizeof(InstanceData) * p_element_count, scene_state.instances, true); - if (lightmap_captures_used) { - RD::get_singleton()->buffer_update(scene_state.lightmap_capture_buffer, 0, sizeof(LightmapCaptureData) * lightmap_captures_used, scene_state.lightmap_captures, true); - } -} - /// RENDERING /// -void RendererSceneRenderForward::_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, const Vector2 &p_uv_offset, const Plane &p_lod_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold) { +template +void RendererSceneRenderForward::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) { RD::DrawListID draw_list = p_draw_list; RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format; //global scope bindings RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_base_uniform_set, SCENE_UNIFORM_SET); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_render_pass_uniform_set, RENDER_PASS_UNIFORM_SET); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_params->render_pass_uniform_set, RENDER_PASS_UNIFORM_SET); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_vec4_xform_uniform_set, TRANSFORMS_UNIFORM_SET); - MaterialData *prev_material = nullptr; + RID prev_material_uniform_set; RID prev_vertex_array_rd; RID prev_index_array_rd; RID prev_pipeline_rd; RID prev_xforms_uniform_set; - PushConstant push_constant; - zeromem(&push_constant, sizeof(PushConstant)); - push_constant.bake_uv2_offset[0] = p_uv_offset.x; - push_constant.bake_uv2_offset[1] = p_uv_offset.y; + bool shadow_pass = (p_params->pass_mode == PASS_MODE_SHADOW) || (p_params->pass_mode == PASS_MODE_SHADOW_DP); - for (int i = 0; i < p_element_count; i++) { - const RenderList::Element *e = p_elements[i]; + float old_offset[2] = { 0, 0 }; - MaterialData *material = e->material; - ShaderData *shader = material->shader_data; - RID xforms_uniform_set; + for (uint32_t i = p_from_element; i < p_to_element; i++) { + const GeometryInstanceSurfaceDataCache *surf = p_params->elements[i]; + + RID material_uniform_set; + ShaderData *shader; + void *mesh_surface; + + if (shadow_pass) { + material_uniform_set = surf->material_uniform_set_shadow; + shader = surf->shader_shadow; + mesh_surface = surf->surface_shadow; + + } else { + material_uniform_set = surf->material_uniform_set; + shader = surf->shader; + mesh_surface = surf->surface; + } + + if (!mesh_surface) { + continue; + } + + if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL) { + old_offset[0] = surf->owner->push_constant.lightmap_uv_scale[0]; + old_offset[1] = surf->owner->push_constant.lightmap_uv_scale[1]; + surf->owner->push_constant.lightmap_uv_scale[0] = p_params->uv_offset.x; + surf->owner->push_constant.lightmap_uv_scale[1] = p_params->uv_offset.y; + } //find cull variant ShaderData::CullVariant cull_variant; - if (p_pass_mode == PASS_MODE_DEPTH_MATERIAL || p_pass_mode == PASS_MODE_SDF || ((p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) && e->instance->cast_shadows == RS::SHADOW_CASTING_SETTING_DOUBLE_SIDED)) { + if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL || p_params->pass_mode == PASS_MODE_SDF || ((p_params->pass_mode == PASS_MODE_SHADOW || p_params->pass_mode == PASS_MODE_SHADOW_DP) && surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS)) { cull_variant = ShaderData::CULL_VARIANT_DOUBLE_SIDED; } else { - bool mirror = e->instance->mirror; - if (p_reverse_cull) { + bool mirror = surf->owner->mirror; + if (p_params->reverse_cull) { mirror = !mirror; } cull_variant = mirror ? ShaderData::CULL_VARIANT_REVERSED : ShaderData::CULL_VARIANT_NORMAL; } - //find primitive and vertex format - RS::PrimitiveType primitive; - void *mesh_surface = nullptr; - - switch (e->instance->base_type) { - case RS::INSTANCE_MESH: { - mesh_surface = storage->mesh_get_surface(e->instance->base, e->surface_index); - - primitive = storage->mesh_surface_get_primitive(mesh_surface); - if (e->instance->skeleton.is_valid()) { - xforms_uniform_set = storage->skeleton_get_3d_uniform_set(e->instance->skeleton, default_shader_rd, TRANSFORMS_UNIFORM_SET); - } - } break; - case RS::INSTANCE_MULTIMESH: { - RID mesh = storage->multimesh_get_mesh(e->instance->base); - ERR_CONTINUE(!mesh.is_valid()); //should be a bug - - mesh_surface = storage->mesh_get_surface(e->instance->base, e->surface_index); - - primitive = storage->mesh_surface_get_primitive(mesh_surface); - - xforms_uniform_set = storage->multimesh_get_3d_uniform_set(e->instance->base, default_shader_rd, TRANSFORMS_UNIFORM_SET); - - } break; - case RS::INSTANCE_IMMEDIATE: { - ERR_CONTINUE(true); //should be a bug - } break; - case RS::INSTANCE_PARTICLES: { - RID mesh = storage->particles_get_draw_pass_mesh(e->instance->base, e->surface_index >> 16); - ERR_CONTINUE(!mesh.is_valid()); //should be a bug - - mesh_surface = storage->mesh_get_surface(e->instance->base, e->surface_index & 0xFFFF); - - primitive = storage->mesh_surface_get_primitive(mesh_surface); - - xforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(e->instance->base, default_shader_rd, TRANSFORMS_UNIFORM_SET); - - } break; - default: { - ERR_CONTINUE(true); //should be a bug - } - } + RS::PrimitiveType primitive = surf->primitive; + RID xforms_uniform_set = surf->owner->transforms_uniform_set; ShaderVersion shader_version = SHADER_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized. - switch (p_pass_mode) { + switch (p_params->pass_mode) { case PASS_MODE_COLOR: case PASS_MODE_COLOR_TRANSPARENT: { - if (e->uses_lightmap) { + if (surf->sort.uses_lightmap) { shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS; - } else if (e->uses_forward_gi) { + } else if (surf->sort.uses_forward_gi) { shader_version = SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI; } else { shader_version = SHADER_VERSION_COLOR_PASS; } } break; case PASS_MODE_COLOR_SPECULAR: { - if (e->uses_lightmap) { + if (surf->sort.uses_lightmap) { shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR; } else { shader_version = SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR; @@ -1086,40 +923,37 @@ void RendererSceneRenderForward::_render_list(RenderingDevice::DrawListID p_draw RID vertex_array_rd; RID index_array_rd; - if (mesh_surface) { - if (e->instance->mesh_instance.is_valid()) { //skeleton and blend shape - storage->mesh_instance_surface_get_vertex_arrays_and_format(e->instance->mesh_instance, e->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format); - } else { - storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format); + //skeleton and blend shape + if (surf->owner->mesh_instance.is_valid()) { + storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format); + } else { + storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format); + } + + if (p_params->screen_lod_threshold > 0.0 && storage->mesh_surface_has_lod(mesh_surface)) { + //lod + Vector3 support_min = surf->owner->transformed_aabb.get_support(-p_params->lod_plane.normal); + Vector3 support_max = surf->owner->transformed_aabb.get_support(p_params->lod_plane.normal); + + float distance_min = p_params->lod_plane.distance_to(support_min); + float distance_max = p_params->lod_plane.distance_to(support_max); + + float distance = 0.0; + + if (distance_min * distance_max < 0.0) { + //crossing plane + distance = 0.0; + } else if (distance_min >= 0.0) { + distance = distance_min; + } else if (distance_max <= 0.0) { + distance = -distance_max; } - if (p_screen_lod_threshold > 0.0 && storage->mesh_surface_has_lod(mesh_surface)) { - Vector3 support_min = e->instance->transformed_aabb.get_support(-p_lod_plane.normal); - Vector3 support_max = e->instance->transformed_aabb.get_support(p_lod_plane.normal); + index_array_rd = storage->mesh_surface_get_index_array_with_lod(mesh_surface, surf->owner->lod_model_scale * surf->owner->lod_bias, distance * p_params->lod_distance_multiplier, p_params->screen_lod_threshold); - float distance_min = p_lod_plane.distance_to(support_min); - float distance_max = p_lod_plane.distance_to(support_max); - - float distance = 0.0; - - if (distance_min * distance_max < 0.0) { - //crossing plane - distance = 0.0; - } else if (distance_min >= 0.0) { - distance = distance_min; - } else if (distance_max <= 0.0) { - distance = -distance_max; - } - - Vector3 model_scale_vec = e->instance->transform.basis.get_scale_abs(); - - float model_scale = MAX(model_scale_vec.x, MAX(model_scale_vec.y, model_scale_vec.z)); - - index_array_rd = storage->mesh_surface_get_index_array_with_lod(mesh_surface, model_scale * e->instance->lod_bias, distance * p_lod_distance_multiplier, p_screen_lod_threshold); - - } else { - index_array_rd = storage->mesh_surface_get_index_array(mesh_surface); - } + } else { + //no lod + index_array_rd = storage->mesh_surface_get_index_array(mesh_surface); } if (prev_vertex_array_rd != vertex_array_rd) { @@ -1134,7 +968,7 @@ void RendererSceneRenderForward::_render_list(RenderingDevice::DrawListID p_draw prev_index_array_rd = index_array_rd; } - RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_force_wireframe); + RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe); if (pipeline_rd != prev_pipeline_rd) { // checking with prev shader does not make so much sense, as @@ -1148,39 +982,89 @@ void RendererSceneRenderForward::_render_list(RenderingDevice::DrawListID p_draw prev_xforms_uniform_set = xforms_uniform_set; } - if (material != prev_material) { + if (material_uniform_set != prev_material_uniform_set) { //update uniform set - if (material->uniform_set.is_valid()) { - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material->uniform_set, MATERIAL_UNIFORM_SET); + if (material_uniform_set.is_valid()) { + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_uniform_set, MATERIAL_UNIFORM_SET); } - prev_material = material; + prev_material_uniform_set = material_uniform_set; } - push_constant.index = i; - RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(PushConstant)); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &surf->owner->push_constant, sizeof(GeometryInstanceForward::PushConstant)); - switch (e->instance->base_type) { - case RS::INSTANCE_MESH: { - RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid()); - } break; - case RS::INSTANCE_MULTIMESH: { - uint32_t instances = storage->multimesh_get_instances_to_draw(e->instance->base); - RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instances); - } break; - case RS::INSTANCE_IMMEDIATE: { - } break; - case RS::INSTANCE_PARTICLES: { - uint32_t instances = storage->particles_get_amount(e->instance->base); - RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instances); - } break; - default: { - ERR_CONTINUE(true); //should be a bug - } + RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), surf->owner->instance_count); + + if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL) { + surf->owner->push_constant.lightmap_uv_scale[0] = old_offset[0]; + surf->owner->push_constant.lightmap_uv_scale[1] = old_offset[1]; } } } +void RendererSceneRenderForward::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) { + //use template for faster performance (pass mode comparisons are inlined) + + switch (p_params->pass_mode) { + case PASS_MODE_COLOR: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_COLOR_SPECULAR: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_COLOR_TRANSPARENT: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_SHADOW: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_SHADOW_DP: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_DEPTH: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_DEPTH_MATERIAL: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + case PASS_MODE_SDF: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + } break; + } +} + +void RendererSceneRenderForward::_render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params) { + uint32_t render_total = p_params->element_count; + uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count(); + uint32_t render_from = p_thread * render_total / total_threads; + uint32_t render_to = (p_thread + 1 == total_threads) ? render_total : ((p_thread + 1) * render_total / total_threads); + _render_list(thread_draw_lists[p_thread], p_params->framebuffer_format, p_params, render_from, render_to); +} + +void RendererSceneRenderForward::_render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector &p_storage_textures) { + RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_framebuffer); + p_params->framebuffer_format = fb_format; + + if ((uint32_t)p_params->element_count > render_list_thread_threshold && false) { // secondary command buffers need more testing at this time + //multi threaded + thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count()); + RD::get_singleton()->draw_list_begin_split(p_framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures); + RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RendererSceneRenderForward::_render_list_thread_function, p_params); + RD::get_singleton()->draw_list_end(); + } else { + //single threaded + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures); + _render_list(draw_list, fb_format, p_params, 0, p_params->element_count); + RD::get_singleton()->draw_list_end(); + } +} + void RendererSceneRenderForward::_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, bool p_pancake_shadows) { //CameraMatrix projection = p_cam_projection; //projection.flip_y(); // Vulkan and modern APIs use Y-Down @@ -1413,128 +1297,7 @@ void RendererSceneRenderForward::_setup_environment(RID p_environment, RID p_ren RD::get_singleton()->buffer_update(scene_state.uniform_buffer, 0, sizeof(SceneState::UBO), &scene_state.ubo, true); } -void RendererSceneRenderForward::_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) { - RID m_src; - - m_src = p_instance->material_override.is_valid() ? p_instance->material_override : p_material; - - if (unlikely(get_debug_draw_mode() != RS::VIEWPORT_DEBUG_DRAW_DISABLED)) { - if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) { - m_src = overdraw_material; - } else if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING) { - m_src = default_material; - } - } - - MaterialData *material = nullptr; - - if (m_src.is_valid()) { - material = (MaterialData *)storage->material_get_data(m_src, RendererStorageRD::SHADER_TYPE_3D); - if (!material || !material->shader_data->valid) { - material = nullptr; - } - } - - if (!material) { - material = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); - m_src = default_material; - } - - ERR_FAIL_COND(!material); - - _add_geometry_with_material(p_instance, p_surface, material, m_src, p_pass_mode, p_geometry_index, p_using_sdfgi); - - while (material->next_pass.is_valid()) { - material = (MaterialData *)storage->material_get_data(material->next_pass, RendererStorageRD::SHADER_TYPE_3D); - if (!material || !material->shader_data->valid) { - break; - } - _add_geometry_with_material(p_instance, p_surface, material, material->next_pass, p_pass_mode, p_geometry_index, p_using_sdfgi); - } -} - -void RendererSceneRenderForward::_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) { - bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture; - bool has_base_alpha = (p_material->shader_data->uses_alpha || has_read_screen_alpha); - bool has_blend_alpha = p_material->shader_data->uses_blend_alpha; - bool has_alpha = has_base_alpha || has_blend_alpha; - - if (p_material->shader_data->uses_sss) { - scene_state.used_sss = true; - } - - if (p_material->shader_data->uses_screen_texture) { - scene_state.used_screen_texture = true; - } - - if (p_material->shader_data->uses_depth_texture) { - scene_state.used_depth_texture = true; - } - - if (p_material->shader_data->uses_normal_texture) { - scene_state.used_normal_texture = true; - } - - if (p_pass_mode != PASS_MODE_COLOR && p_pass_mode != PASS_MODE_COLOR_SPECULAR) { - if (has_blend_alpha || has_read_screen_alpha || (has_base_alpha && !p_material->shader_data->uses_depth_pre_pass) || p_material->shader_data->depth_draw == ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED || p_instance->cast_shadows == RS::SHADOW_CASTING_SETTING_OFF) { - //conditions in which no depth pass should be processed - return; - } - - if ((p_pass_mode != PASS_MODE_DEPTH_MATERIAL && p_pass_mode != PASS_MODE_SDF) && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) { - //shader does not use discard and does not write a vertex position, use generic material - if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_DEPTH) { - p_material = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); - } else if ((p_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || p_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE) && !p_material->shader_data->uses_normal && !p_material->shader_data->uses_roughness) { - p_material = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); - } - } - - has_alpha = false; - } - - has_alpha = has_alpha || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED; - - RenderList::Element *e = has_alpha ? render_list.add_alpha_element() : render_list.add_element(); - - if (!e) { - return; - } - - e->instance = p_instance; - e->material = p_material; - e->surface_index = p_surface; - e->sort_key = 0; - - if (e->material->last_pass != render_pass) { - if (!RD::get_singleton()->uniform_set_is_valid(e->material->uniform_set)) { - //uniform set no longer valid, probably a texture changed - storage->material_force_update_textures(p_material_rid, RendererStorageRD::SHADER_TYPE_3D); - } - e->material->last_pass = render_pass; - e->material->index = scene_state.current_material_index++; - if (e->material->shader_data->last_pass != render_pass) { - e->material->shader_data->last_pass = scene_state.current_material_index++; - e->material->shader_data->index = scene_state.current_shader_index++; - } - } - e->geometry_index = p_geometry_index; - e->material_index = e->material->index; - e->uses_instancing = e->instance->base_type == RS::INSTANCE_MULTIMESH; - e->uses_lightmap = e->instance->lightmap != nullptr || !e->instance->lightmap_sh.is_empty(); - e->uses_forward_gi = has_alpha && (e->instance->gi_probe_instances.size() || p_using_sdfgi); - e->shader_index = e->shader_index; - e->depth_layer = e->instance->depth_layer; - e->priority = p_material->priority; - - if (p_material->shader_data->uses_time) { - RenderingServerDefault::redraw_request(); - } -} - -void RendererSceneRenderForward::_fill_render_list(const PagedArray &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_using_sdfgi) { - scene_state.current_shader_index = 0; - scene_state.current_material_index = 0; +void RendererSceneRenderForward::_fill_render_list(const PagedArray &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_using_sdfgi, bool p_using_opaque_gi) { scene_state.used_sss = false; scene_state.used_screen_texture = false; scene_state.used_normal_texture = false; @@ -1543,125 +1306,184 @@ void RendererSceneRenderForward::_fill_render_list(const PagedArray(p_instances[i]); - inst->depth = near_plane.distance_to(inst->transform.origin); - inst->depth_layer = CLAMP(int(inst->depth * 16 / z_max), 0, 15); + Vector3 support_min = inst->transformed_aabb.get_support(-near_plane.normal); + inst->depth = near_plane.distance_to(support_min); + uint32_t depth_layer = CLAMP(int(inst->depth * 16 / z_max), 0, 15); - //add geometry for drawing - switch (inst->base_type) { - case RS::INSTANCE_MESH: { - const RID *materials = nullptr; - uint32_t surface_count; + uint32_t flags = inst->base_flags; //fill flags if appropriate - materials = storage->mesh_get_surface_count_and_materials(inst->base, surface_count); - if (!materials) { - continue; //nothing to do - } + bool uses_lightmap = false; + bool uses_gi = false; - const RID *inst_materials = inst->materials.ptr(); + if (p_pass_mode == PASS_MODE_COLOR) { + //setup GI - for (uint32_t j = 0; j < surface_count; j++) { - RID material = inst_materials[j].is_valid() ? inst_materials[j] : materials[j]; - - uint32_t surface_index = storage->mesh_surface_get_render_pass_index(inst->base, j, render_pass, &geometry_index); - _add_geometry(inst, j, material, p_pass_mode, surface_index, p_using_sdfgi); - } - - //mesh->last_pass=frame; - - } break; - - case RS::INSTANCE_MULTIMESH: { - if (storage->multimesh_get_instances_to_draw(inst->base) == 0) { - //not visible, 0 instances - continue; - } - - RID mesh = storage->multimesh_get_mesh(inst->base); - if (!mesh.is_valid()) { - continue; - } - - const RID *materials = nullptr; - uint32_t surface_count; - - materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); - if (!materials) { - continue; //nothing to do - } - - for (uint32_t j = 0; j < surface_count; j++) { - uint32_t surface_index = storage->mesh_surface_get_multimesh_render_pass_index(mesh, j, render_pass, &geometry_index); - _add_geometry(inst, j, materials[j], p_pass_mode, surface_index, p_using_sdfgi); - } - - } break; -#if 0 - case RS::INSTANCE_IMMEDIATE: { - RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getornull(inst->base); - ERR_CONTINUE(!immediate); - - _add_geometry(immediate, inst, nullptr, -1, p_depth_pass, p_shadow_pass); - - } break; -#endif - case RS::INSTANCE_PARTICLES: { - int draw_passes = storage->particles_get_draw_passes(inst->base); - - for (int j = 0; j < draw_passes; j++) { - RID mesh = storage->particles_get_draw_pass_mesh(inst->base, j); - if (!mesh.is_valid()) - continue; - - const RID *materials = nullptr; - uint32_t surface_count; - - materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); - if (!materials) { - continue; //nothing to do - } - - for (uint32_t k = 0; k < surface_count; k++) { - uint32_t surface_index = storage->mesh_surface_get_particles_render_pass_index(mesh, j, render_pass, &geometry_index); - _add_geometry(inst, (j << 16) | k, materials[j], p_pass_mode, surface_index, p_using_sdfgi); + if (inst->lightmap_instance.is_valid()) { + int32_t lightmap_cull_index = -1; + for (uint32_t j = 0; j < scene_state.lightmaps_used; j++) { + if (scene_state.lightmap_ids[j] == inst->lightmap_instance) { + lightmap_cull_index = j; + break; } } + if (lightmap_cull_index >= 0) { + inst->push_constant.gi_offset &= 0xFFFF; + inst->push_constant.gi_offset |= lightmap_cull_index; + flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP; + if (scene_state.lightmap_has_sh[lightmap_cull_index]) { + flags |= INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP; + } + uses_lightmap = true; + } else { + inst->push_constant.gi_offset = 0xFFFFFFFF; + } - } break; + } else if (inst->lightmap_sh) { + if (lightmap_captures_used < scene_state.max_lightmap_captures) { + const Color *src_capture = inst->lightmap_sh->sh; + LightmapCaptureData &lcd = scene_state.lightmap_captures[lightmap_captures_used]; + for (int j = 0; j < 9; j++) { + lcd.sh[j * 4 + 0] = src_capture[j].r; + lcd.sh[j * 4 + 1] = src_capture[j].g; + lcd.sh[j * 4 + 2] = src_capture[j].b; + lcd.sh[j * 4 + 3] = src_capture[j].a; + } + flags |= INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE; + inst->push_constant.gi_offset = lightmap_captures_used; + lightmap_captures_used++; + uses_lightmap = true; + } - default: { + } else if (!low_end) { + if (p_using_opaque_gi) { + flags |= INSTANCE_DATA_FLAG_USE_GI_BUFFERS; + } + + if (inst->gi_probes[0].is_valid()) { + uint32_t probe0_index = 0xFFFF; + uint32_t probe1_index = 0xFFFF; + + for (uint32_t j = 0; j < scene_state.giprobes_used; j++) { + if (scene_state.giprobe_ids[j] == inst->gi_probes[0]) { + probe0_index = j; + } else if (scene_state.giprobe_ids[j] == inst->gi_probes[1]) { + probe1_index = j; + } + } + + if (probe0_index == 0xFFFF && probe1_index != 0xFFFF) { + //0 must always exist if a probe exists + SWAP(probe0_index, probe1_index); + } + + inst->push_constant.gi_offset = probe0_index | (probe1_index << 16); + uses_gi = true; + } else { + if (p_using_sdfgi && inst->can_sdfgi) { + flags |= INSTANCE_DATA_FLAG_USE_SDFGI; + uses_gi = true; + } + inst->push_constant.gi_offset = 0xFFFFFFFF; + } } } + inst->push_constant.flags = flags; + + GeometryInstanceSurfaceDataCache *surf = inst->surface_caches; + + while (surf) { + surf->sort.uses_forward_gi = 0; + surf->sort.uses_lightmap = 0; + + if (p_pass_mode == PASS_MODE_COLOR) { + if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) { + render_list.add_element(surf); + } + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA) { + render_list.add_alpha_element(surf); + if (uses_gi) { + surf->sort.uses_forward_gi = 1; + } + } + + if (uses_lightmap) { + surf->sort.uses_lightmap = 1; + } + + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING) { + scene_state.used_sss = true; + } + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE) { + scene_state.used_screen_texture = true; + } + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE) { + scene_state.used_normal_texture = true; + } + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE) { + scene_state.used_depth_texture = true; + } + + } else if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) { + if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW) { + render_list.add_element(surf); + } + } else { + if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) { + render_list.add_element(surf); + } + } + + surf->sort.depth_layer = depth_layer; + + surf = surf->next; + } + } + + if (lightmap_captures_used) { + RD::get_singleton()->buffer_update(scene_state.lightmap_capture_buffer, 0, sizeof(LightmapCaptureData) * lightmap_captures_used, scene_state.lightmap_captures, true); } } -void RendererSceneRenderForward::_setup_lightmaps(const PagedArray &p_lightmaps, const Transform &p_cam_transform) { - uint32_t lightmaps_used = 0; +void RendererSceneRenderForward::_setup_giprobes(const PagedArray &p_giprobes) { + scene_state.giprobes_used = MIN(p_giprobes.size(), uint32_t(MAX_GI_PROBES)); + for (uint32_t i = 0; i < scene_state.giprobes_used; i++) { + scene_state.giprobe_ids[i] = p_giprobes[i]; + } +} + +void RendererSceneRenderForward::_setup_lightmaps(const PagedArray &p_lightmaps, const Transform &p_cam_transform) { + scene_state.lightmaps_used = 0; for (int i = 0; i < (int)p_lightmaps.size(); i++) { if (i >= (int)scene_state.max_lightmaps) { break; } - InstanceBase *lm = p_lightmaps[i]; - Basis to_lm = lm->transform.basis.inverse() * p_cam_transform.basis; + RID lightmap = lightmap_instance_get_lightmap(p_lightmaps[i]); + + Basis to_lm = lightmap_instance_get_transform(p_lightmaps[i]).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); - lm->lightmap_cull_index = i; - lightmaps_used++; + scene_state.lightmap_ids[i] = p_lightmaps[i]; + scene_state.lightmap_has_sh[i] = storage->lightmap_uses_spherical_harmonics(lightmap); + + scene_state.lightmaps_used++; } - if (lightmaps_used > 0) { - RD::get_singleton()->buffer_update(scene_state.lightmap_buffer, 0, sizeof(LightmapData) * lightmaps_used, scene_state.lightmaps, true); + if (scene_state.lightmaps_used > 0) { + RD::get_singleton()->buffer_update(scene_state.lightmap_buffer, 0, sizeof(LightmapData) * scene_state.lightmaps_used, scene_state.lightmaps, true); } } -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) { +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); @@ -1784,12 +1606,12 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf } _setup_lightmaps(p_lightmaps, p_cam_transform); + _setup_giprobes(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(), 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_instances, PASS_MODE_COLOR, p_cam_projection, p_cam_transform, using_sdfgi); + _fill_render_list(p_instances, PASS_MODE_COLOR, p_cam_projection, p_cam_transform, using_sdfgi, using_sdfgi || using_giprobe); bool using_sss = !low_end && render_buffer && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED; @@ -1873,8 +1695,6 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf render_list.sort_by_key(false); - _fill_instances(render_list.elements, render_list.element_count, false, false, using_sdfgi || using_giprobe); - bool debug_giprobes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION; bool debug_sdfgi_probes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SDFGI_PROBES; @@ -1885,12 +1705,11 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf if (depth_pre_pass) { //depth pre pass RENDER_TIMESTAMP("Render Depth Pre-Pass"); - RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), PagedArray()); + RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), PagedArray(), PagedArray()); bool finish_depth = using_ssao || using_sdfgi || using_giprobe; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, depth_pass_clear); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(depth_framebuffer), render_list.elements, render_list.element_count, false, depth_pass_mode, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); - RD::get_singleton()->draw_list_end(); + RenderListParameters render_list_params(render_list.elements, render_list.element_count, false, depth_pass_mode, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); + _render_list_with_threads(&render_list_params, depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, depth_pass_clear); if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { RENDER_TIMESTAMP("Resolve Depth Pre-Pass"); @@ -1917,7 +1736,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf RENDER_TIMESTAMP("Render Opaque Pass"); - RID rp_uniform_set = _setup_render_pass_uniform_set(p_render_buffer, radiance_texture, p_shadow_atlas, p_reflection_atlas, p_gi_probes); + RID rp_uniform_set = _setup_render_pass_uniform_set(p_render_buffer, radiance_texture, p_shadow_atlas, p_reflection_atlas, p_gi_probes, p_lightmaps); bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss; bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss; @@ -1938,13 +1757,13 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf } RID framebuffer = using_separate_specular ? opaque_specular_framebuffer : opaque_framebuffer; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CONTINUE) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(framebuffer), render_list.elements, render_list.element_count, false, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); - RD::get_singleton()->draw_list_end(); + RenderListParameters render_list_params(render_list.elements, render_list.element_count, false, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); + + _render_list_with_threads(&render_list_params, framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CONTINUE) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0); if (will_continue_color && using_separate_specular) { // close the specular framebuffer, as it's no longer used - draw_list = RD::get_singleton()->draw_list_begin(render_buffer->specular_only_fb, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_CONTINUE); + RD::get_singleton()->draw_list_begin(render_buffer->specular_only_fb, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_CONTINUE); RD::get_singleton()->draw_list_end(); } } @@ -2023,12 +1842,9 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf render_list.sort_by_reverse_depth_and_priority(true); - _fill_instances(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false, using_sdfgi); - { - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(alpha_framebuffer), &render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false, PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); - RD::get_singleton()->draw_list_end(); + RenderListParameters render_list_params(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false, PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold); + _render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); } if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { @@ -2036,7 +1852,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf } } -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) { +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(); @@ -2051,29 +1867,24 @@ void RendererSceneRenderForward::_render_shadow(RID p_framebuffer, const PagedAr p_screen_lod_threshold = 0.0; } - render_list.clear(); - PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW; _fill_render_list(p_instances, pass_mode, p_projection, p_transform); - RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), PagedArray()); + RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), PagedArray(), PagedArray()); RENDER_TIMESTAMP("Render Shadow"); render_list.sort_by_key(false); - _fill_instances(render_list.elements, render_list.element_count, true); - { //regular forward for now - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, p_use_dp_flip, pass_mode, true, rp_uniform_set, false, Vector2(), p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold); - RD::get_singleton()->draw_list_end(); + RenderListParameters render_list_params(render_list.elements, render_list.element_count, p_use_dp_flip, pass_mode, true, rp_uniform_set, false, Vector2(), p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold); + _render_list_with_threads(&render_list_params, p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ); } } -void RendererSceneRenderForward::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray &p_instances) { +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(); @@ -2084,29 +1895,24 @@ void RendererSceneRenderForward::_render_particle_collider_heightfield(RID p_fb, _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), RID(), true, Color(), 0, p_cam_projection.get_z_far(), false, false); - render_list.clear(); - PassMode pass_mode = PASS_MODE_SHADOW; _fill_render_list(p_instances, pass_mode, p_cam_projection, p_cam_transform); - RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), PagedArray()); + RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), PagedArray(), PagedArray()); RENDER_TIMESTAMP("Render Collider Heightield"); render_list.sort_by_key(false); - _fill_instances(render_list.elements, render_list.element_count, true); - { //regular forward for now - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_fb), render_list.elements, render_list.element_count, false, pass_mode, true, rp_uniform_set); - RD::get_singleton()->draw_list_end(); + RenderListParameters render_list_params(render_list.elements, render_list.element_count, false, pass_mode, true, rp_uniform_set); + _render_list_with_threads(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ); } } -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) { +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(); @@ -2118,20 +1924,17 @@ void RendererSceneRenderForward::_render_material(const Transform &p_cam_transfo _setup_environment(RID(), RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), RID(), false, Color(), 0, 0); - render_list.clear(); - PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; _fill_render_list(p_instances, pass_mode, p_cam_projection, p_cam_transform); - RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), PagedArray()); + RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), PagedArray(), PagedArray()); RENDER_TIMESTAMP("Render Material"); render_list.sort_by_key(false); - _fill_instances(render_list.elements, render_list.element_count, true); - { + RenderListParameters render_list_params(render_list.elements, render_list.element_count, true, pass_mode, true, rp_uniform_set); //regular forward for now Vector clear; clear.push_back(Color(0, 0, 0, 0)); @@ -2140,12 +1943,12 @@ void RendererSceneRenderForward::_render_material(const Transform &p_cam_transfo clear.push_back(Color(0, 0, 0, 0)); clear.push_back(Color(0, 0, 0, 0)); RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, clear, 1.0, 0, p_region); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, true, pass_mode, true, rp_uniform_set); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); RD::get_singleton()->draw_list_end(); } } -void RendererSceneRenderForward::_render_uv2(const PagedArray &p_instances, 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(); @@ -2157,20 +1960,17 @@ void RendererSceneRenderForward::_render_uv2(const PagedArray &p _setup_environment(RID(), RID(), CameraMatrix(), Transform(), RID(), true, Vector2(1, 1), RID(), false, Color(), 0, 0); - render_list.clear(); - PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; _fill_render_list(p_instances, pass_mode, CameraMatrix(), Transform()); - RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), PagedArray()); + RID rp_uniform_set = _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), PagedArray(), PagedArray()); RENDER_TIMESTAMP("Render Material"); render_list.sort_by_key(false); - _fill_instances(render_list.elements, render_list.element_count, true); - { + RenderListParameters render_list_params(render_list.elements, render_list.element_count, true, pass_mode, true, rp_uniform_set, true); //regular forward for now Vector clear; clear.push_back(Color(0, 0, 0, 0)); @@ -2198,15 +1998,17 @@ void RendererSceneRenderForward::_render_uv2(const PagedArray &p Vector2 ofs = uv_offsets[i]; ofs.x /= p_region.size.width; ofs.y /= p_region.size.height; - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, true, pass_mode, true, rp_uniform_set, true, ofs); //first wireframe, for pseudo conservative + render_list_params.uv_offset = ofs; + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //first wireframe, for pseudo conservative } - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, true, pass_mode, true, rp_uniform_set, false); //second regular triangles + render_list_params.uv_offset = Vector2(); + _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //second regular triangles RD::get_singleton()->draw_list_end(); } } -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) { +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(); @@ -2215,12 +2017,10 @@ void RendererSceneRenderForward::_render_sdfgi(RID p_render_buffers, const Vecto ERR_FAIL_COND(!render_buffer); render_pass++; - render_list.clear(); PassMode pass_mode = PASS_MODE_SDF; _fill_render_list(p_instances, pass_mode, CameraMatrix(), Transform()); render_list.sort_by_key(false); - _fill_instances(render_list.elements, render_list.element_count, true); RID rp_uniform_set = _setup_sdfgi_render_pass_uniform_set(p_albedo_texture, p_emission_texture, p_emission_aniso_texture, p_geom_facing_texture); @@ -2281,9 +2081,8 @@ void RendererSceneRenderForward::_render_sdfgi(RID p_render_buffers, const Vecto E = sdfgi_framebuffer_size_cache.insert(fb_size, fb); } - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(E->get(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, Vector(), 1.0, 0, Rect2(), sbs); - _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(E->get()), render_list.elements, render_list.element_count, true, pass_mode, true, rp_uniform_set, false); //second regular triangles - RD::get_singleton()->draw_list_end(); + RenderListParameters render_list_params(render_list.elements, render_list.element_count, true, pass_mode, true, rp_uniform_set, false); + _render_list_with_threads(&render_list_params, E->get(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, Vector(), 1.0, 0, Rect2(), sbs); } } @@ -2340,13 +2139,6 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() { u.ids.push_back(scene_state.uniform_buffer); uniforms.push_back(u); } - { - RD::Uniform u; - u.binding = 4; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.ids.push_back(scene_state.instance_buffer); - uniforms.push_back(u); - } { RD::Uniform u; @@ -2380,20 +2172,13 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() { { RD::Uniform u; u.binding = 11; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.ids = storage->lightmap_array_get_textures(); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.binding = 12; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(scene_state.lightmap_capture_buffer); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 13; + u.binding = 12; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID decal_atlas = storage->decal_atlas_get_texture(); u.ids.push_back(decal_atlas); @@ -2401,7 +2186,7 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() { } { RD::Uniform u; - u.binding = 14; + u.binding = 13; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID decal_atlas = storage->decal_atlas_get_texture_srgb(); u.ids.push_back(decal_atlas); @@ -2409,7 +2194,7 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() { } { RD::Uniform u; - u.binding = 15; + u.binding = 14; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(get_decal_buffer()); uniforms.push_back(u); @@ -2417,14 +2202,14 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() { { RD::Uniform u; - u.binding = 16; + u.binding = 15; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.ids.push_back(get_cluster_builder_texture()); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 17; + u.binding = 16; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.ids.push_back(get_cluster_builder_indices_buffer()); uniforms.push_back(u); @@ -2432,7 +2217,7 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() { { RD::Uniform u; - u.binding = 18; + u.binding = 17; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; if (directional_shadow_get_texture().is_valid()) { u.ids.push_back(directional_shadow_get_texture()); @@ -2445,7 +2230,7 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() { { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.binding = 19; + u.binding = 18; u.ids.push_back(storage->global_variables_get_storage_buffer()); uniforms.push_back(u); } @@ -2453,7 +2238,7 @@ void RendererSceneRenderForward::_update_render_base_uniform_set() { if (!low_end) { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.binding = 20; + u.binding = 19; u.ids.push_back(sdfgi_get_ubo()); uniforms.push_back(u); } @@ -2462,7 +2247,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, const PagedArray &p_gi_probes) { +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, const PagedArray &p_lightmaps) { 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); } @@ -2517,11 +2302,29 @@ RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RID p_render_buff u.ids.push_back(texture); uniforms.push_back(u); } - { RD::Uniform u; u.binding = 3; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.resize(scene_state.max_lightmaps); + RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); + for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) { + if (i < p_lightmaps.size()) { + RID base = lightmap_instance_get_lightmap(p_lightmaps[i]); + RID texture = storage->lightmap_get_texture(base); + RID rd_texture = storage->texture_get_rd_texture(texture); + u.ids.write[i] = rd_texture; + } else { + u.ids.write[i] = default_tex; + } + } + + uniforms.push_back(u); + } + { + RD::Uniform u; + u.binding = 4; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; 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++) { @@ -2541,7 +2344,7 @@ RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RID p_render_buff { RD::Uniform u; - u.binding = 4; + u.binding = 5; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID texture = (false && rb && rb->depth.is_valid()) ? rb->depth : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); u.ids.push_back(texture); @@ -2549,7 +2352,7 @@ RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RID p_render_buff } { RD::Uniform u; - u.binding = 5; + u.binding = 6; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID bbt = rb ? render_buffers_get_back_buffer_texture(p_render_buffers) : RID(); RID texture = bbt.is_valid() ? bbt : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); @@ -2559,7 +2362,7 @@ RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RID p_render_buff if (!low_end) { { RD::Uniform u; - u.binding = 6; + u.binding = 7; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID texture = rb && rb->normal_roughness_buffer.is_valid() ? rb->normal_roughness_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_NORMAL); u.ids.push_back(texture); @@ -2568,7 +2371,7 @@ RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RID p_render_buff { RD::Uniform u; - u.binding = 7; + u.binding = 8; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID aot = rb ? render_buffers_get_ao_texture(p_render_buffers) : RID(); RID texture = aot.is_valid() ? aot : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); @@ -2578,7 +2381,7 @@ RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RID p_render_buff { RD::Uniform u; - u.binding = 8; + u.binding = 9; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID texture = rb && rb->ambient_buffer.is_valid() ? rb->ambient_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); u.ids.push_back(texture); @@ -2587,7 +2390,7 @@ RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RID p_render_buff { RD::Uniform u; - u.binding = 9; + u.binding = 10; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID texture = rb && rb->reflection_buffer.is_valid() ? rb->reflection_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); u.ids.push_back(texture); @@ -2595,7 +2398,7 @@ RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RID p_render_buff } { RD::Uniform u; - u.binding = 10; + u.binding = 11; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID t; if (rb && render_buffers_is_sdfgi_enabled(p_render_buffers)) { @@ -2608,7 +2411,7 @@ RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RID p_render_buff } { RD::Uniform u; - u.binding = 11; + u.binding = 12; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; if (rb && render_buffers_is_sdfgi_enabled(p_render_buffers)) { u.ids.push_back(render_buffers_get_sdfgi_occlusion_texture(p_render_buffers)); @@ -2619,14 +2422,14 @@ RID RendererSceneRenderForward::_setup_render_pass_uniform_set(RID p_render_buff } { RD::Uniform u; - u.binding = 12; + u.binding = 13; u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.ids.push_back(rb ? render_buffers_get_gi_probe_buffer(p_render_buffers) : render_buffers_get_default_gi_probe_buffer()); uniforms.push_back(u); } { RD::Uniform u; - u.binding = 13; + u.binding = 14; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID vfog = RID(); if (rb && render_buffers_has_volumetric_fog(p_render_buffers)) { @@ -2684,10 +2487,24 @@ RID RendererSceneRenderForward::_setup_sdfgi_render_pass_uniform_set(RID p_albed } { - // No GIProbes + // No Lightmaps RD::Uniform u; u.binding = 3; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.ids.resize(scene_state.max_lightmaps); + RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); + for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) { + u.ids.write[i] = default_tex; + } + + uniforms.push_back(u); + } + + { + // No GIProbes + RD::Uniform u; + u.binding = 4; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; 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++) { @@ -2701,28 +2518,28 @@ RID RendererSceneRenderForward::_setup_sdfgi_render_pass_uniform_set(RID p_albed { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 4; + u.binding = 5; u.ids.push_back(p_albedo_texture); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 5; + u.binding = 6; u.ids.push_back(p_emission_texture); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 6; + u.binding = 7; u.ids.push_back(p_emission_aniso_texture); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 7; + u.binding = 8; u.ids.push_back(p_geom_facing_texture); uniforms.push_back(u); } @@ -2765,6 +2582,534 @@ void RendererSceneRenderForward::set_time(double p_time, double p_step) { RendererSceneRenderRD::set_time(p_time, p_step); } +void RendererSceneRenderForward::_geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + if (ginstance->dirty_list_element.in_list()) { + return; + } + + //clear surface caches + GeometryInstanceSurfaceDataCache *surf = ginstance->surface_caches; + + while (surf) { + GeometryInstanceSurfaceDataCache *next = surf->next; + geometry_instance_surface_alloc.free(surf); + surf = next; + } + + ginstance->surface_caches = nullptr; + + geometry_instance_dirty_list.add(&ginstance->dirty_list_element); +} + +void RendererSceneRenderForward::_geometry_instance_add_surface_with_material(GeometryInstanceForward *ginstance, uint32_t p_surface, MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) { + bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture; + bool has_base_alpha = (p_material->shader_data->uses_alpha || has_read_screen_alpha); + bool has_blend_alpha = p_material->shader_data->uses_blend_alpha; + bool has_alpha = has_base_alpha || has_blend_alpha; + + uint32_t flags = 0; + + if (p_material->shader_data->uses_sss) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING; + } + + if (p_material->shader_data->uses_screen_texture) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SCREEN_TEXTURE; + } + + if (p_material->shader_data->uses_depth_texture) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DEPTH_TEXTURE; + } + + if (p_material->shader_data->uses_normal_texture) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_NORMAL_TEXTURE; + } + + if (ginstance->data->cast_double_sided_shaodows) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS; + } + + if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED) { + //material is only meant for alpha pass + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA; + if (p_material->shader_data->uses_depth_pre_pass && !(p_material->shader_data->depth_draw == ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED)) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH; + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW; + } + } else { + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE; + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH; + flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW; + } + + MaterialData *material_shadow = nullptr; + //void *surface_shadow = nullptr; + if (!p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) { + flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL; + material_shadow = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); + } else { + material_shadow = p_material; + } + + GeometryInstanceSurfaceDataCache *sdcache = geometry_instance_surface_alloc.alloc(); + + sdcache->flags = flags; + + sdcache->shader = p_material->shader_data; + sdcache->material_uniform_set = p_material->uniform_set; + sdcache->surface = storage->mesh_get_surface(p_mesh, p_surface); + sdcache->primitive = storage->mesh_surface_get_primitive(sdcache->surface); + sdcache->surface_index = p_surface; + + if (ginstance->data->dirty_dependencies) { + storage->base_update_dependency(p_mesh, &ginstance->data->dependency_tracker); + } + + //shadow + sdcache->shader_shadow = material_shadow->shader_data; + sdcache->material_uniform_set_shadow = material_shadow->uniform_set; + sdcache->surface_shadow = sdcache->surface; //when adding special shadow meshes, will use this + + sdcache->owner = ginstance; + + sdcache->next = ginstance->surface_caches; + ginstance->surface_caches = sdcache; + + //sortkey + + sdcache->sort.sort_key1 = 0; + sdcache->sort.sort_key2 = 0; + + sdcache->sort.surface_type = ginstance->data->base_type; + sdcache->sort.material_id = p_material_id; + sdcache->sort.shader_id = p_shader_id; + sdcache->sort.geometry_id = p_mesh.get_local_index(); + sdcache->sort.uses_forward_gi = ginstance->can_sdfgi; + sdcache->sort.priority = p_material->priority; +} + +void RendererSceneRenderForward::_geometry_instance_add_surface(GeometryInstanceForward *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) { + RID m_src; + + m_src = ginstance->data->material_override.is_valid() ? ginstance->data->material_override : p_material; + + MaterialData *material = nullptr; + + if (m_src.is_valid()) { + material = (MaterialData *)storage->material_get_data(m_src, RendererStorageRD::SHADER_TYPE_3D); + if (!material || !material->shader_data->valid) { + material = nullptr; + } + } + + if (material) { + if (ginstance->data->dirty_dependencies) { + storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker); + } + } else { + material = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); + m_src = default_material; + } + + ERR_FAIL_COND(!material); + + _geometry_instance_add_surface_with_material(ginstance, p_surface, material, m_src.get_local_index(), storage->material_get_shader_id(m_src), p_mesh); + + while (material->next_pass.is_valid()) { + RID next_pass = material->next_pass; + material = (MaterialData *)storage->material_get_data(next_pass, RendererStorageRD::SHADER_TYPE_3D); + if (!material || !material->shader_data->valid) { + break; + } + if (ginstance->data->dirty_dependencies) { + storage->material_update_dependency(next_pass, &ginstance->data->dependency_tracker); + } + _geometry_instance_add_surface_with_material(ginstance, p_surface, material, next_pass.get_local_index(), storage->material_get_shader_id(next_pass), p_mesh); + } +} + +void RendererSceneRenderForward::_geometry_instance_update(GeometryInstance *p_geometry_instance) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + + if (ginstance->data->dirty_dependencies) { + ginstance->data->dependency_tracker.update_begin(); + } + + //add geometry for drawing + switch (ginstance->data->base_type) { + case RS::INSTANCE_MESH: { + const RID *materials = nullptr; + uint32_t surface_count; + RID mesh = ginstance->data->base; + + materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); + if (materials) { + //if no materials, no surfaces. + const RID *inst_materials = ginstance->data->surface_materials.ptr(); + uint32_t surf_mat_count = ginstance->data->surface_materials.size(); + + for (uint32_t j = 0; j < surface_count; j++) { + RID material = (j < surf_mat_count && inst_materials[j].is_valid()) ? inst_materials[j] : materials[j]; + _geometry_instance_add_surface(ginstance, j, material, mesh); + } + } + + ginstance->instance_count = 1; + + } break; + + case RS::INSTANCE_MULTIMESH: { + RID mesh = storage->multimesh_get_mesh(ginstance->data->base); + if (mesh.is_valid()) { + const RID *materials = nullptr; + uint32_t surface_count; + + materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); + if (materials) { + for (uint32_t j = 0; j < surface_count; j++) { + _geometry_instance_add_surface(ginstance, j, materials[j], mesh); + } + } + + ginstance->instance_count = storage->multimesh_get_instances_to_draw(ginstance->data->base); + } + + } break; +#if 0 + case RS::INSTANCE_IMMEDIATE: { + RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getornull(inst->base); + ERR_CONTINUE(!immediate); + + _add_geometry(immediate, inst, nullptr, -1, p_depth_pass, p_shadow_pass); + + } break; +#endif + case RS::INSTANCE_PARTICLES: { + int draw_passes = storage->particles_get_draw_passes(ginstance->data->base); + + for (int j = 0; j < draw_passes; j++) { + RID mesh = storage->particles_get_draw_pass_mesh(ginstance->data->base, j); + if (!mesh.is_valid()) + continue; + + const RID *materials = nullptr; + uint32_t surface_count; + + materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); + if (materials) { + for (uint32_t k = 0; k < surface_count; k++) { + _geometry_instance_add_surface(ginstance, k, materials[k], mesh); + } + } + } + + ginstance->instance_count = storage->particles_get_amount(ginstance->data->base); + + } break; + + default: { + } + } + + //Fill push constant + + ginstance->push_constant.instance_uniforms_ofs = ginstance->data->shader_parameters_offset >= 0 ? ginstance->data->shader_parameters_offset : 0; + ginstance->push_constant.layer_mask = ginstance->data->layer_mask; + ginstance->push_constant.flags = 0; + ginstance->push_constant.gi_offset = 0xFFFFFFFF; //disabled + + bool store_transform = true; + + if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH; + uint32_t stride; + if (storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; + stride = 2; + } else { + stride = 3; + } + if (storage->multimesh_uses_colors(ginstance->data->base)) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; + stride += 1; + } + if (storage->multimesh_uses_custom_data(ginstance->data->base)) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; + stride += 1; + } + + ginstance->base_flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); + ginstance->transforms_uniform_set = storage->multimesh_get_3d_uniform_set(ginstance->data->base, default_shader_rd, TRANSFORMS_UNIFORM_SET); + + } else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH; + uint32_t stride; + if (false) { // 2D particles + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; + stride = 2; + } else { + stride = 3; + } + + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; + stride += 1; + + ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; + stride += 1; + + ginstance->base_flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); + + if (!storage->particles_is_using_local_coords(ginstance->data->base)) { + store_transform = false; + } + ginstance->transforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, default_shader_rd, TRANSFORMS_UNIFORM_SET); + + } else if (ginstance->data->base_type == RS::INSTANCE_MESH) { + if (storage->skeleton_is_valid(ginstance->data->skeleton)) { + ginstance->base_flags |= INSTANCE_DATA_FLAG_SKELETON; + ginstance->transforms_uniform_set = storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, default_shader_rd, TRANSFORMS_UNIFORM_SET); + if (ginstance->data->dirty_dependencies) { + storage->skeleton_update_dependency(ginstance->data->skeleton, &ginstance->data->dependency_tracker); + } + } + } + + if (store_transform) { + RendererStorageRD::store_transform(ginstance->data->transform, ginstance->push_constant.transform); + } else { + RendererStorageRD::store_transform(Transform(), ginstance->push_constant.transform); + } + + ginstance->can_sdfgi = false; + + if (lightmap_instance_is_valid(ginstance->lightmap_instance)) { + ginstance->push_constant.gi_offset = ginstance->data->lightmap_slice_index << 16; + ginstance->push_constant.lightmap_uv_scale[0] = ginstance->data->lightmap_uv_scale.position.x; + ginstance->push_constant.lightmap_uv_scale[1] = ginstance->data->lightmap_uv_scale.position.y; + ginstance->push_constant.lightmap_uv_scale[2] = ginstance->data->lightmap_uv_scale.size.width; + ginstance->push_constant.lightmap_uv_scale[3] = ginstance->data->lightmap_uv_scale.size.height; + } else if (!low_end) { + if (ginstance->gi_probes[0].is_null() && (ginstance->data->use_baked_light || ginstance->data->use_dynamic_gi)) { + ginstance->can_sdfgi = true; + } + } + + if (ginstance->data->dirty_dependencies) { + ginstance->data->dependency_tracker.update_end(); + ginstance->data->dirty_dependencies = false; + } + + ginstance->dirty_list_element.remove_from_list(); +} + +void RendererSceneRenderForward::_update_dirty_geometry_instances() { + while (geometry_instance_dirty_list.first()) { + _geometry_instance_update(geometry_instance_dirty_list.first()->self()); + } +} + +void RendererSceneRenderForward::_geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker) { + switch (p_notification) { + case RendererStorage::DEPENDENCY_CHANGED_MATERIAL: + case RendererStorage::DEPENDENCY_CHANGED_MESH: + case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH: + case RendererStorage::DEPENDENCY_CHANGED_SKELETON_DATA: { + static_cast(singleton)->_geometry_instance_mark_dirty(static_cast(p_tracker->userdata)); + } break; + case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: { + GeometryInstanceForward *ginstance = static_cast(p_tracker->userdata); + if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) { + ginstance->instance_count = static_cast(singleton)->storage->multimesh_get_instances_to_draw(ginstance->data->base); + } + } break; + default: { + //rest of notifications of no interest + } break; + } +} +void RendererSceneRenderForward::_geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker) { + static_cast(singleton)->_geometry_instance_mark_dirty(static_cast(p_tracker->userdata)); +} + +RendererSceneRender::GeometryInstance *RendererSceneRenderForward::geometry_instance_create(RID p_base) { + RS::InstanceType type = storage->get_base_type(p_base); + ERR_FAIL_COND_V(!((1 << type) & RS::INSTANCE_GEOMETRY_MASK), nullptr); + + GeometryInstanceForward *ginstance = geometry_instance_alloc.alloc(); + ginstance->data = memnew(GeometryInstanceForward::Data); + + ginstance->data->base = p_base; + ginstance->data->base_type = type; + ginstance->data->dependency_tracker.userdata = ginstance; + ginstance->data->dependency_tracker.changed_callback = _geometry_instance_dependency_changed; + ginstance->data->dependency_tracker.deleted_callback = _geometry_instance_dependency_deleted; + + _geometry_instance_mark_dirty(ginstance); + + return ginstance; +} +void RendererSceneRenderForward::geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->skeleton = p_skeleton; + _geometry_instance_mark_dirty(ginstance); + ginstance->data->dirty_dependencies = true; +} +void RendererSceneRenderForward::geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->material_override = p_override; + _geometry_instance_mark_dirty(ginstance); + ginstance->data->dirty_dependencies = true; +} +void RendererSceneRenderForward::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector &p_materials) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->surface_materials = p_materials; + _geometry_instance_mark_dirty(ginstance); + ginstance->data->dirty_dependencies = true; +} +void RendererSceneRenderForward::geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->mesh_instance = p_mesh_instance; + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForward::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + RendererStorageRD::store_transform(p_transform, ginstance->push_constant.transform); + ginstance->data->transform = p_transform; + ginstance->mirror = p_transform.basis.determinant() < 0; + ginstance->data->aabb = p_aabb; + ginstance->transformed_aabb = p_transformed_aabb; + + Vector3 model_scale_vec = p_transform.basis.get_scale_abs(); + // handle non uniform scale here + + float max_scale = MAX(model_scale_vec.x, MAX(model_scale_vec.y, model_scale_vec.z)); + float min_scale = MIN(model_scale_vec.x, MIN(model_scale_vec.y, model_scale_vec.z)); + ginstance->non_uniform_scale = max_scale >= 0.0 && (min_scale / max_scale) < 0.9; + + ginstance->lod_model_scale = max_scale; +} +void RendererSceneRenderForward::geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->lod_bias = p_lod_bias; +} +void RendererSceneRenderForward::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->use_baked_light = p_enable; + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForward::geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->use_dynamic_gi = p_enable; + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForward::geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->lightmap_instance = p_lightmap_instance; + ginstance->data->lightmap_uv_scale = p_lightmap_uv_scale; + ginstance->data->lightmap_slice_index = p_lightmap_slice_index; + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForward::geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + if (p_sh9) { + if (ginstance->lightmap_sh == nullptr) { + ginstance->lightmap_sh = geometry_instance_lightmap_sh.alloc(); + } + + copymem(ginstance->lightmap_sh->sh, p_sh9, sizeof(Color) * 9); + } else { + if (ginstance->lightmap_sh != nullptr) { + geometry_instance_lightmap_sh.free(ginstance->lightmap_sh); + ginstance->lightmap_sh = nullptr; + } + } + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForward::geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->shader_parameters_offset = p_offset; + _geometry_instance_mark_dirty(ginstance); +} +void RendererSceneRenderForward::geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + + ginstance->data->cast_double_sided_shaodows = p_enable; + _geometry_instance_mark_dirty(ginstance); +} + +void RendererSceneRenderForward::geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->data->layer_mask = p_layer_mask; + ginstance->push_constant.layer_mask = p_layer_mask; +} + +void RendererSceneRenderForward::geometry_instance_free(GeometryInstance *p_geometry_instance) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + if (ginstance->lightmap_sh != nullptr) { + geometry_instance_lightmap_sh.free(ginstance->lightmap_sh); + } + GeometryInstanceSurfaceDataCache *surf = ginstance->surface_caches; + while (surf) { + GeometryInstanceSurfaceDataCache *next = surf->next; + geometry_instance_surface_alloc.free(surf); + surf = next; + } + memdelete(ginstance->data); + geometry_instance_alloc.free(ginstance); +} + +uint32_t RendererSceneRenderForward::geometry_instance_get_pair_mask() { + return (1 << RS::INSTANCE_GI_PROBE); +} +void RendererSceneRenderForward::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) { +} +void RendererSceneRenderForward::geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) { +} +void RendererSceneRenderForward::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) { +} + +Transform RendererSceneRenderForward::geometry_instance_get_transform(GeometryInstance *p_instance) { + GeometryInstanceForward *ginstance = static_cast(p_instance); + ERR_FAIL_COND_V(!ginstance, Transform()); + return ginstance->data->transform; +} +AABB RendererSceneRenderForward::geometry_instance_get_aabb(GeometryInstance *p_instance) { + GeometryInstanceForward *ginstance = static_cast(p_instance); + ERR_FAIL_COND_V(!ginstance, AABB()); + return ginstance->data->aabb; +} + +void RendererSceneRenderForward::geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) { + GeometryInstanceForward *ginstance = static_cast(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + if (p_gi_probe_instance_count > 0) { + ginstance->gi_probes[0] = p_gi_probe_instances[0]; + } else { + ginstance->gi_probes[0] = RID(); + } + + if (p_gi_probe_instance_count > 1) { + ginstance->gi_probes[1] = p_gi_probe_instances[1]; + } else { + ginstance->gi_probes[1] = RID(); + } +} + RendererSceneRenderForward::RendererSceneRenderForward(RendererStorageRD *p_storage) : RendererSceneRenderRD(p_storage) { singleton = this; @@ -2788,11 +3133,10 @@ RendererSceneRenderForward::RendererSceneRenderForward(RendererStorageRD *p_stor { //lightmaps - scene_state.max_lightmaps = storage->lightmap_array_get_size(); + scene_state.max_lightmaps = low_end ? 2 : MAX_LIGHTMAPS; defines += "\n#define MAX_LIGHTMAP_TEXTURES " + itos(scene_state.max_lightmaps) + "\n"; defines += "\n#define MAX_LIGHTMAPS " + itos(scene_state.max_lightmaps) + "\n"; - scene_state.lightmaps = memnew_arr(LightmapData, scene_state.max_lightmaps); scene_state.lightmap_buffer = RD::get_singleton()->storage_buffer_create(sizeof(LightmapData) * scene_state.max_lightmaps); } { @@ -3015,12 +3359,6 @@ RendererSceneRenderForward::RendererSceneRenderForward(RendererStorageRD *p_stor render_list.init(); render_pass = 0; - { - scene_state.max_instances = render_list.max_elements; - scene_state.instances = memnew_arr(InstanceData, scene_state.max_instances); - scene_state.instance_buffer = RD::get_singleton()->storage_buffer_create(sizeof(InstanceData) * scene_state.max_instances); - } - scene_state.uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO)); { @@ -3068,6 +3406,8 @@ RendererSceneRenderForward::RendererSceneRenderForward(RendererStorageRD *p_stor sampler.compare_op = RD::COMPARE_OP_LESS; shadow_sampler = RD::get_singleton()->sampler_create(sampler); } + + render_list_thread_threshold = GLOBAL_GET("rendering/forward_renderer/threaded_render_minimum_instances"); } RendererSceneRenderForward::~RendererSceneRenderForward() { @@ -3095,11 +3435,8 @@ RendererSceneRenderForward::~RendererSceneRenderForward() { { RD::get_singleton()->free(scene_state.uniform_buffer); - RD::get_singleton()->free(scene_state.instance_buffer); RD::get_singleton()->free(scene_state.lightmap_buffer); RD::get_singleton()->free(scene_state.lightmap_capture_buffer); - memdelete_arr(scene_state.instances); - memdelete_arr(scene_state.lightmaps); memdelete_arr(scene_state.lightmap_captures); } diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward.h b/servers/rendering/renderer_rd/renderer_scene_render_forward.h index 4b37f4a391f..8a6f268c467 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_forward.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_forward.h @@ -31,6 +31,7 @@ #ifndef RENDERING_SERVER_SCENE_RENDER_FORWARD_H #define RENDERING_SERVER_SCENE_RENDER_FORWARD_H +#include "core/templates/paged_allocator.h" #include "servers/rendering/renderer_rd/pipeline_cache_rd.h" #include "servers/rendering/renderer_rd/renderer_scene_render_rd.h" #include "servers/rendering/renderer_rd/renderer_storage_rd.h" @@ -46,7 +47,9 @@ class RendererSceneRenderForward : public RendererSceneRenderRD { enum { SDFGI_MAX_CASCADES = 8, - MAX_GI_PROBES = 8 + MAX_GI_PROBES = 8, + MAX_LIGHTMAPS = 8, + MAX_GI_PROBES_PER_INSTANCE = 2, }; /* Scene Shader */ @@ -197,14 +200,6 @@ class RendererSceneRenderForward : public RendererSceneRenderRD { return static_cast(singleton)->_create_material_func(static_cast(p_shader)); } - /* Push Constant */ - - struct PushConstant { - uint32_t index; - uint32_t pad; - float bake_uv2_offset[2]; - }; - /* Framebuffer */ struct RenderBufferDataForward : public RenderBufferData { @@ -266,7 +261,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, const PagedArray &p_gi_probes); + 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, const PagedArray &p_lightmaps); struct LightmapData { float normal_xform[12]; @@ -292,16 +287,6 @@ class RendererSceneRenderForward : public RendererSceneRenderRD { INSTANCE_DATA_FLAG_SKELETON = 1 << 19, }; - struct InstanceData { - float transform[16]; - float normal_transform[16]; - uint32_t flags; - uint32_t instance_uniforms_ofs; //instance_offset in instancing/skeleton buffer - uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap) - uint32_t mask; - float lightmap_uv_scale[4]; - }; - struct SceneState { struct UBO { float projection_matrix[16]; @@ -385,7 +370,10 @@ class RendererSceneRenderForward : public RendererSceneRenderRD { RID uniform_buffer; - LightmapData *lightmaps; + LightmapData lightmaps[MAX_LIGHTMAPS]; + RID lightmap_ids[MAX_LIGHTMAPS]; + bool lightmap_has_sh[MAX_LIGHTMAPS]; + uint32_t lightmaps_used = 0; uint32_t max_lightmaps; RID lightmap_buffer; @@ -393,151 +381,16 @@ class RendererSceneRenderForward : public RendererSceneRenderRD { uint32_t max_lightmap_captures; RID lightmap_capture_buffer; - RID instance_buffer; - InstanceData *instances; - uint32_t max_instances; + RID giprobe_ids[MAX_GI_PROBES]; + uint32_t giprobes_used = 0; bool used_screen_texture = false; bool used_normal_texture = false; bool used_depth_texture = false; bool used_sss = false; - uint32_t current_shader_index = 0; - uint32_t current_material_index = 0; } scene_state; - /* Render List */ - - struct RenderList { - int max_elements; - - struct Element { - RendererSceneRender::InstanceBase *instance; - MaterialData *material; - union { - struct { - //from least significant to most significant in sort, TODO: should be endian swapped on big endian - uint64_t geometry_index : 20; - uint64_t material_index : 15; - uint64_t shader_index : 12; - uint64_t uses_instancing : 1; - uint64_t uses_forward_gi : 1; - uint64_t uses_lightmap : 1; - uint64_t depth_layer : 4; - uint64_t priority : 8; - }; - - uint64_t sort_key; - }; - uint32_t surface_index; - }; - - Element *base_elements; - Element **elements; - - int element_count; - int alpha_element_count; - - void clear() { - element_count = 0; - alpha_element_count = 0; - } - - //should eventually be replaced by radix - - struct SortByKey { - _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { - return A->sort_key < B->sort_key; - } - }; - - void sort_by_key(bool p_alpha) { - SortArray sorter; - if (p_alpha) { - sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); - } else { - sorter.sort(elements, element_count); - } - } - - struct SortByDepth { - _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { - return A->instance->depth < B->instance->depth; - } - }; - - void sort_by_depth(bool p_alpha) { //used for shadows - - SortArray sorter; - if (p_alpha) { - sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); - } else { - sorter.sort(elements, element_count); - } - } - - struct SortByReverseDepthAndPriority { - _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { - uint32_t layer_A = uint32_t(A->priority); - uint32_t layer_B = uint32_t(B->priority); - if (layer_A == layer_B) { - return A->instance->depth > B->instance->depth; - } else { - return layer_A < layer_B; - } - } - }; - - void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha - - SortArray sorter; - if (p_alpha) { - sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); - } else { - sorter.sort(elements, element_count); - } - } - - _FORCE_INLINE_ Element *add_element() { - if (element_count + alpha_element_count >= max_elements) { - return nullptr; - } - elements[element_count] = &base_elements[element_count]; - return elements[element_count++]; - } - - _FORCE_INLINE_ Element *add_alpha_element() { - if (element_count + alpha_element_count >= max_elements) { - return nullptr; - } - int idx = max_elements - alpha_element_count - 1; - elements[idx] = &base_elements[idx]; - alpha_element_count++; - return elements[idx]; - } - - void init() { - element_count = 0; - alpha_element_count = 0; - elements = memnew_arr(Element *, max_elements); - base_elements = memnew_arr(Element, max_elements); - for (int i = 0; i < max_elements; i++) { - elements[i] = &base_elements[i]; // assign elements - } - } - - RenderList() { - max_elements = 0; - } - - ~RenderList() { - memdelete_arr(elements); - memdelete_arr(base_elements); - } - }; - - RenderList render_list; - static RendererSceneRenderForward *singleton; uint64_t render_pass; double time; @@ -567,28 +420,319 @@ 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(const PagedArray &p_lightmaps, const Transform &p_cam_transform); + void _setup_giprobes(const PagedArray &p_giprobes); + 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); + struct GeometryInstanceSurfaceDataCache; - void _fill_render_list(const PagedArray &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_using_sdfgi = false); + struct RenderListParameters { + GeometryInstanceSurfaceDataCache **elements = nullptr; + int element_count = 0; + bool reverse_cull = false; + PassMode pass_mode = PASS_MODE_COLOR; + bool no_gi = false; + RID render_pass_uniform_set; + bool force_wireframe = false; + Vector2 uv_offset; + Plane lod_plane; + float lod_distance_multiplier = 0.0; + float screen_lod_threshold = 0.0; + RD::FramebufferFormatID framebuffer_format = 0; + RenderListParameters(GeometryInstanceSurfaceDataCache **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) { + elements = p_elements; + element_count = p_element_count; + reverse_cull = p_reverse_cull; + pass_mode = p_pass_mode; + no_gi = p_no_gi; + render_pass_uniform_set = p_render_pass_uniform_set; + force_wireframe = p_force_wireframe; + uv_offset = p_uv_offset; + lod_plane = p_lod_plane; + lod_distance_multiplier = p_lod_distance_multiplier; + screen_lod_threshold = p_screen_lod_threshold; + } + }; + + template + _FORCE_INLINE_ void _render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); + + void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); + + LocalVector thread_draw_lists; + void _render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params); + void _render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector &p_clear_color_values = Vector(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector &p_storage_textures = Vector()); + + uint32_t render_list_thread_threshold = 500; + + void _fill_render_list(const PagedArray &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_using_sdfgi = false, bool p_using_opaque_gi = false); Map sdfgi_framebuffer_size_cache; + struct GeometryInstanceData; + struct GeometryInstanceForward; + + struct GeometryInstanceLightmapSH { + Color sh[9]; + }; + + // Cached data for drawing surfaces + struct GeometryInstanceSurfaceDataCache { + enum { + FLAG_PASS_DEPTH = 1, + FLAG_PASS_OPAQUE = 2, + FLAG_PASS_ALPHA = 4, + FLAG_PASS_SHADOW = 8, + FLAG_USES_SHARED_SHADOW_MATERIAL = 128, + FLAG_USES_SUBSURFACE_SCATTERING = 2048, + FLAG_USES_SCREEN_TEXTURE = 4096, + FLAG_USES_DEPTH_TEXTURE = 8192, + FLAG_USES_NORMAL_TEXTURE = 16384, + FLAG_USES_DOUBLE_SIDED_SHADOWS = 32768, + }; + + union { + struct { + uint32_t geometry_id; + uint32_t material_id; + uint32_t shader_id; + uint32_t surface_type : 4; + uint32_t uses_forward_gi : 1; //set during addition + uint32_t uses_lightmap : 1; //set during addition + uint32_t depth_layer : 4; //set during addition + uint32_t priority : 8; + }; + struct { + uint64_t sort_key1; + uint64_t sort_key2; + }; + } sort; + + RS::PrimitiveType primitive = RS::PRIMITIVE_MAX; + uint32_t flags = 0; + uint32_t surface_index = 0; + + void *surface = nullptr; + RID material_uniform_set; + ShaderData *shader = nullptr; + + void *surface_shadow = nullptr; + RID material_uniform_set_shadow; + ShaderData *shader_shadow = nullptr; + + GeometryInstanceSurfaceDataCache *next = nullptr; + GeometryInstanceForward *owner = nullptr; + }; + + struct GeometryInstanceForward : public GeometryInstance { + //used during rendering + bool mirror = false; + bool non_uniform_scale = false; + float lod_bias = 0.0; + float lod_model_scale = 1.0; + AABB transformed_aabb; //needed for LOD + float depth = 0; + struct PushConstant { + float transform[16]; + uint32_t flags; + uint32_t instance_uniforms_ofs; //base offset in global buffer for instance variables + uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap index) + uint32_t layer_mask; + float lightmap_uv_scale[4]; + } push_constant; + RID transforms_uniform_set; + uint32_t instance_count = 0; + RID mesh_instance; + bool can_sdfgi = false; + //used during setup + uint32_t base_flags = 0; + RID gi_probes[MAX_GI_PROBES_PER_INSTANCE]; + RID lightmap_instance; + GeometryInstanceLightmapSH *lightmap_sh = nullptr; + GeometryInstanceSurfaceDataCache *surface_caches = nullptr; + SelfList dirty_list_element; + + struct Data { + //data used less often goes into regular heap + RID base; + RS::InstanceType base_type; + + RID skeleton; + + uint32_t layer_mask = 1; + + Vector surface_materials; + RID material_override; + Transform transform; + AABB aabb; + int32_t shader_parameters_offset = -1; + + bool use_dynamic_gi = false; + bool use_baked_light = false; + bool cast_double_sided_shaodows = false; + bool mirror = false; + Rect2 lightmap_uv_scale; + uint32_t lightmap_slice_index = 0; + bool dirty_dependencies = false; + + RendererStorage::DependencyTracker dependency_tracker; + }; + + Data *data = nullptr; + + GeometryInstanceForward() : + dirty_list_element(this) {} + }; + + static void _geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker); + static void _geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker); + + SelfList::List geometry_instance_dirty_list; + + PagedAllocator geometry_instance_alloc; + PagedAllocator geometry_instance_surface_alloc; + PagedAllocator geometry_instance_lightmap_sh; + + void _geometry_instance_add_surface_with_material(GeometryInstanceForward *ginstance, uint32_t p_surface, MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh); + void _geometry_instance_add_surface(GeometryInstanceForward *ginstance, uint32_t p_surface, RID p_material, RID p_mesh); + void _geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance); + void _geometry_instance_update(GeometryInstance *p_geometry_instance); + void _update_dirty_geometry_instances(); + bool low_end = false; + /* Render List */ + + struct RenderList { + int max_elements; + + GeometryInstanceSurfaceDataCache **elements = nullptr; + + int element_count; + int alpha_element_count; + + void clear() { + element_count = 0; + alpha_element_count = 0; + } + + //should eventually be replaced by radix + + struct SortByKey { + _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const { + return (A->sort.sort_key2 == B->sort.sort_key2) ? (A->sort.sort_key1 < B->sort.sort_key1) : (A->sort.sort_key2 < B->sort.sort_key2); + } + }; + + void sort_by_key(bool p_alpha) { + SortArray sorter; + if (p_alpha) { + sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); + } else { + sorter.sort(elements, element_count); + } + } + + struct SortByDepth { + _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const { + return (A->owner->depth < B->owner->depth); + } + }; + + void sort_by_depth(bool p_alpha) { //used for shadows + + SortArray sorter; + if (p_alpha) { + sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); + } else { + sorter.sort(elements, element_count); + } + } + + struct SortByReverseDepthAndPriority { + _FORCE_INLINE_ bool operator()(const GeometryInstanceSurfaceDataCache *A, const GeometryInstanceSurfaceDataCache *B) const { + return (A->sort.priority == B->sort.priority) ? (A->owner->depth > B->owner->depth) : (A->sort.priority < B->sort.priority); + } + }; + + void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha + + SortArray sorter; + if (p_alpha) { + sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); + } else { + sorter.sort(elements, element_count); + } + } + + _FORCE_INLINE_ void add_element(GeometryInstanceSurfaceDataCache *p_element) { + if (element_count + alpha_element_count >= max_elements) { + return; + } + elements[element_count] = p_element; + element_count++; + } + + _FORCE_INLINE_ void add_alpha_element(GeometryInstanceSurfaceDataCache *p_element) { + if (element_count + alpha_element_count >= max_elements) { + return; + } + int idx = max_elements - alpha_element_count - 1; + elements[idx] = p_element; + alpha_element_count++; + } + + void init() { + element_count = 0; + alpha_element_count = 0; + elements = memnew_arr(GeometryInstanceSurfaceDataCache *, max_elements); + } + + RenderList() { + max_elements = 0; + } + + ~RenderList() { + memdelete_arr(elements); + } + }; + + RenderList render_list; + protected: - 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); + 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 GeometryInstance *geometry_instance_create(RID p_base); + virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton); + virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override); + virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector &p_materials); + virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance); + virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb); + virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask); + virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias); + virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable); + virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable); + virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index); + virtual void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9); + virtual void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset); + virtual void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable); + + virtual Transform geometry_instance_get_transform(GeometryInstance *p_instance); + virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance); + + virtual void geometry_instance_free(GeometryInstance *p_geometry_instance); + + virtual uint32_t geometry_instance_get_pair_mask(); + virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count); + virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count); + virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count); + virtual void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count); + virtual void set_time(double p_time, double p_step); virtual bool free(RID p_rid); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 1edabed287c..dad08179e71 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -4035,6 +4035,19 @@ void RendererSceneRenderRD::decal_instance_set_transform(RID p_decal, const Tran ///////////////////////////////// +RID RendererSceneRenderRD::lightmap_instance_create(RID p_lightmap) { + LightmapInstance li; + li.lightmap = p_lightmap; + return lightmap_instance_owner.make_rid(li); +} +void RendererSceneRenderRD::lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform) { + LightmapInstance *li = lightmap_instance_owner.getornull(p_lightmap); + ERR_FAIL_COND(!li); + li->transform = p_transform; +} + +///////////////////////////////// + RID RendererSceneRenderRD::gi_probe_instance_create(RID p_base) { GIProbeInstance gi_probe; gi_probe.probe = p_base; @@ -4061,7 +4074,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, const PagedArray &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); @@ -4578,13 +4591,10 @@ void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_ins //this could probably be better parallelized in compute.. 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; - instance->depth = 0; + GeometryInstance *instance = p_dynamic_objects[i]; //transform aabb to giprobe - AABB aabb = (to_probe_xform * instance->transform).xform(instance->aabb); + AABB aabb = (to_probe_xform * geometry_instance_get_transform(instance)).xform(geometry_instance_get_aabb(instance)); //this needs to wrap to grid resolution to avoid jitter //also extend margin a bit just in case @@ -7101,7 +7111,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, 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 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); @@ -7177,7 +7187,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, const PagedArray &p_instances, 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); @@ -7353,11 +7363,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, const PagedArray &p_instances, RID p_framebuffer, const Rect2i &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, const PagedArray &p_instances) { +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); @@ -7694,7 +7704,7 @@ void RendererSceneRenderRD::render_sdfgi(RID p_render_buffers, int p_region, con } } -void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray &p_instances) { +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; @@ -7844,6 +7854,8 @@ bool RendererSceneRenderRD::free(RID p_rid) { reflection_probe_instance_owner.free(p_rid); } else if (decal_instance_owner.owns(p_rid)) { decal_instance_owner.free(p_rid); + } else if (lightmap_instance_owner.owns(p_rid)) { + lightmap_instance_owner.free(p_rid); } else if (gi_probe_instance_owner.owns(p_rid)) { GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_rid); if (gi_probe->texture.is_valid()) { @@ -7979,23 +7991,28 @@ TypedArray RendererSceneRenderRD::bake_render_uv2(RID p_base, const Vecto //RID sampled_light; - InstanceBase ins; + GeometryInstance *gi = geometry_instance_create(p_base); - ins.base_type = RSG::storage->get_base_type(p_base); - ins.base = p_base; - ins.materials.resize(RSG::storage->mesh_get_surface_count(p_base)); - for (int i = 0; i < ins.materials.size(); i++) { - if (i < p_material_overrides.size()) { - ins.materials.write[i] = p_material_overrides[i]; + uint32_t sc = RSG::storage->mesh_get_surface_count(p_base); + Vector materials; + materials.resize(sc); + + for (uint32_t i = 0; i < sc; i++) { + if (i < (uint32_t)p_material_overrides.size()) { + materials.write[i] = p_material_overrides[i]; } } + geometry_instance_set_surface_materials(gi, materials); + if (cull_argument.size() == 0) { cull_argument.push_back(nullptr); } - cull_argument[0] = &ins; + cull_argument[0] = gi; _render_uv2(cull_argument, fb, Rect2i(0, 0, p_image_size.width, p_image_size.height)); + geometry_instance_free(gi); + TypedArray ret; { diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index af35e1b3b47..f81a35f0257 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -109,12 +109,12 @@ protected: 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, 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 _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); @@ -137,8 +137,8 @@ protected: 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 + 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; @@ -374,6 +374,15 @@ private: mutable RID_Owner decal_instance_owner; + /* LIGHTMAP INSTANCE */ + + struct LightmapInstance { + RID lightmap; + Transform transform; + }; + + mutable RID_Owner lightmap_instance_owner; + /* GIPROBE INSTANCE */ struct GIProbeLight { @@ -1473,6 +1482,9 @@ private: bool low_end = false; public: + virtual Transform geometry_instance_get_transform(GeometryInstance *p_instance) = 0; + virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance) = 0; + /* SHADOW ATLAS API */ RID shadow_atlas_create(); @@ -1822,10 +1834,25 @@ public: return decal->transform; } + virtual RID lightmap_instance_create(RID p_lightmap); + virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform); + _FORCE_INLINE_ bool lightmap_instance_is_valid(RID p_lightmap_instance) { + return lightmap_instance_owner.getornull(p_lightmap_instance) != nullptr; + } + + _FORCE_INLINE_ RID lightmap_instance_get_lightmap(RID p_lightmap_instance) { + LightmapInstance *li = lightmap_instance_owner.getornull(p_lightmap_instance); + return li->lightmap; + } + _FORCE_INLINE_ Transform lightmap_instance_get_transform(RID p_lightmap_instance) { + LightmapInstance *li = lightmap_instance_owner.getornull(p_lightmap_instance); + return li->transform; + } + 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, const PagedArray &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; } @@ -1900,16 +1927,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, 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_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, 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_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, const PagedArray &p_instances, 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, const PagedArray &p_instances); + 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, const PagedArray &p_instances); + 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_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index 68983da4084..bf7237cad02 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -1438,7 +1438,7 @@ void RendererStorageRD::shader_set_code(RID p_shader, const String &p_code) { for (Set::Element *E = shader->owners.front(); E; E = E->next()) { Material *material = E->get(); - material->instance_dependency.instance_notify_changed(false, true); + material->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL); _material_queue_update(material, true, true); } } @@ -1547,7 +1547,8 @@ void RendererStorageRD::material_set_shader(RID p_material, RID p_shader) { } if (p_shader.is_null()) { - material->instance_dependency.instance_notify_changed(false, true); + material->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL); + material->shader_id = 0; return; } @@ -1555,6 +1556,7 @@ void RendererStorageRD::material_set_shader(RID p_material, RID p_shader) { ERR_FAIL_COND(!shader); material->shader = shader; material->shader_type = shader->type; + material->shader_id = p_shader.get_local_index(); shader->owners.insert(material); if (shader->type == SHADER_TYPE_MAX) { @@ -1568,7 +1570,7 @@ void RendererStorageRD::material_set_shader(RID p_material, RID p_shader) { material->data->set_next_pass(material->next_pass); material->data->set_render_priority(material->priority); //updating happens later - material->instance_dependency.instance_notify_changed(false, true); + material->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL); _material_queue_update(material, true, true); } @@ -1613,7 +1615,7 @@ void RendererStorageRD::material_set_next_pass(RID p_material, RID p_next_materi material->data->set_next_pass(p_next_material); } - material->instance_dependency.instance_notify_changed(false, true); + material->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL); } void RendererStorageRD::material_set_render_priority(RID p_material, int priority) { @@ -1663,10 +1665,10 @@ void RendererStorageRD::material_get_instance_shader_parameters(RID p_material, } } -void RendererStorageRD::material_update_dependency(RID p_material, InstanceBaseDependency *p_instance) { +void RendererStorageRD::material_update_dependency(RID p_material, DependencyTracker *p_instance) { Material *material = material_owner.getornull(p_material); ERR_FAIL_COND(!material); - p_instance->update_dependency(&material->instance_dependency); + p_instance->update_dependency(&material->dependency); if (material->next_pass.is_valid()) { material_update_dependency(material->next_pass, p_instance); } @@ -2596,7 +2598,7 @@ void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_su _mesh_instance_add_surface(mi, mesh, mesh->surface_count - 1); } - mesh->instance_dependency.instance_notify_changed(true, true); + mesh->dependency.changed_notify(DEPENDENCY_CHANGED_MESH); mesh->material_cache.clear(); } @@ -2638,7 +2640,7 @@ void RendererStorageRD::mesh_surface_set_material(RID p_mesh, int p_surface, RID ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count); mesh->surfaces[p_surface]->material = p_material; - mesh->instance_dependency.instance_notify_changed(false, true); + mesh->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL); mesh->material_cache.clear(); } @@ -2858,8 +2860,8 @@ void RendererStorageRD::mesh_clear(RID p_mesh) { MeshInstance *mi = E->get(); _mesh_instance_clear(mi); } - mesh->instance_dependency.instance_notify_changed(true, true); mesh->has_bone_weights = false; + mesh->dependency.changed_notify(DEPENDENCY_CHANGED_MESH); } bool RendererStorageRD::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) { @@ -3298,6 +3300,8 @@ void RendererStorageRD::multimesh_allocate(RID p_multimesh, int p_instances, RS: if (multimesh->instances) { multimesh->buffer = RD::get_singleton()->storage_buffer_create(multimesh->instances * multimesh->stride_cache * 4); } + + multimesh->dependency.changed_notify(DEPENDENCY_CHANGED_MULTIMESH); } int RendererStorageRD::multimesh_get_instance_count(RID p_multimesh) const { @@ -3331,7 +3335,7 @@ void RendererStorageRD::multimesh_set_mesh(RID p_multimesh, RID p_mesh) { } } - multimesh->instance_dependency.instance_notify_changed(true, true); + multimesh->dependency.changed_notify(DEPENDENCY_CHANGED_MESH); } #define MULTIMESH_DIRTY_REGION_SIZE 512 @@ -3690,7 +3694,7 @@ void RendererStorageRD::multimesh_set_buffer(RID p_multimesh, const Vectorinstances); - multimesh->instance_dependency.instance_notify_changed(true, false); + multimesh->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } } @@ -3731,6 +3735,8 @@ void RendererStorageRD::multimesh_set_visible_instances(RID p_multimesh, int p_v } multimesh->visible_instances = p_visible; + + multimesh->dependency.changed_notify(DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES); } int RendererStorageRD::multimesh_get_visible_instances(RID p_multimesh) const { @@ -3788,7 +3794,7 @@ void RendererStorageRD::_update_dirty_multimeshes() { //aabb is dirty.. _multimesh_re_create_aabb(multimesh, data, visible_instances); multimesh->aabb_dirty = false; - multimesh->instance_dependency.instance_notify_changed(true, false); + multimesh->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } } @@ -3926,7 +3932,7 @@ void RendererStorageRD::particles_set_custom_aabb(RID p_particles, const AABB &p Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->custom_aabb = p_aabb; - particles->instance_dependency.instance_notify_changed(true, false); + particles->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } void RendererStorageRD::particles_set_speed_scale(RID p_particles, float p_scale) { @@ -4155,24 +4161,18 @@ RID RendererStorageRD::particles_get_draw_pass_mesh(RID p_particles, int p_pass) return particles->draw_passes[p_pass]; } -void RendererStorageRD::particles_add_collision(RID p_particles, InstanceBaseDependency *p_instance) { - RendererSceneRender::InstanceBase *instance = static_cast(p_instance); - +void RendererStorageRD::particles_add_collision(RID p_particles, RID p_particles_collision_instance) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); - ERR_FAIL_COND(instance->base_type != RS::INSTANCE_PARTICLES_COLLISION); - - particles->collisions.insert(instance); + particles->collisions.insert(p_particles_collision_instance); } -void RendererStorageRD::particles_remove_collision(RID p_particles, InstanceBaseDependency *p_instance) { - RendererSceneRender::InstanceBase *instance = static_cast(p_instance); - +void RendererStorageRD::particles_remove_collision(RID p_particles, RID p_particles_collision_instance) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); - particles->collisions.erase(instance); + particles->collisions.erase(p_particles_collision_instance); } void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta) { @@ -4272,9 +4272,15 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta to_particles = p_particles->emission_transform.affine_inverse(); } uint32_t collision_3d_textures_used = 0; - for (const Set::Element *E = p_particles->collisions.front(); E; E = E->next()) { - ParticlesCollision *pc = particles_collision_owner.getornull(E->get()->base); - Transform to_collider = E->get()->transform; + for (const Set::Element *E = p_particles->collisions.front(); E; E = E->next()) { + ParticlesCollisionInstance *pci = particles_collision_instance_owner.getornull(E->get()); + if (!pci || !pci->active) { + continue; + } + ParticlesCollision *pc = particles_collision_owner.getornull(pci->collision); + ERR_CONTINUE(!pc); + + Transform to_collider = pci->transform; if (p_particles->use_local_coords) { to_collider = to_particles * to_collider; } @@ -4687,7 +4693,7 @@ void RendererStorageRD::update_particles() { RD::get_singleton()->compute_list_end(); } - particles->instance_dependency.instance_notify_changed(true, false); //make sure shadows are updated + particles->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } } @@ -4986,7 +4992,7 @@ void RendererStorageRD::particles_collision_set_collision_type(RID p_particles_c particles_collision->heightfield_texture = RID(); } particles_collision->type = p_type; - particles_collision->instance_dependency.instance_notify_changed(true, false); + particles_collision->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } void RendererStorageRD::particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) { @@ -5000,7 +5006,7 @@ void RendererStorageRD::particles_collision_set_sphere_radius(RID p_particles_co ERR_FAIL_COND(!particles_collision); particles_collision->radius = p_radius; - particles_collision->instance_dependency.instance_notify_changed(true, false); + particles_collision->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } void RendererStorageRD::particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) { @@ -5008,7 +5014,7 @@ void RendererStorageRD::particles_collision_set_box_extents(RID p_particles_coll ERR_FAIL_COND(!particles_collision); particles_collision->extents = p_extents; - particles_collision->instance_dependency.instance_notify_changed(true, false); + particles_collision->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } void RendererStorageRD::particles_collision_set_attractor_strength(RID p_particles_collision, float p_strength) { @@ -5042,7 +5048,7 @@ void RendererStorageRD::particles_collision_set_field_texture(RID p_particles_co void RendererStorageRD::particles_collision_height_field_update(RID p_particles_collision) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); ERR_FAIL_COND(!particles_collision); - particles_collision->instance_dependency.instance_notify_changed(true, false); + particles_collision->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } void RendererStorageRD::particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) { @@ -5096,6 +5102,22 @@ bool RendererStorageRD::particles_collision_is_heightfield(RID p_particles_colli return particles_collision->type == RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE; } +RID RendererStorageRD::particles_collision_instance_create(RID p_collision) { + ParticlesCollisionInstance pci; + pci.collision = p_collision; + return particles_collision_instance_owner.make_rid(pci); +} +void RendererStorageRD::particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform) { + ParticlesCollisionInstance *pci = particles_collision_instance_owner.getornull(p_collision_instance); + ERR_FAIL_COND(!pci); + pci->transform = p_transform; +} +void RendererStorageRD::particles_collision_instance_set_active(RID p_collision_instance, bool p_active) { + ParticlesCollisionInstance *pci = particles_collision_instance_owner.getornull(p_collision_instance); + ERR_FAIL_COND(!pci); + pci->active = p_active; +} + /* SKELETON API */ RID RendererStorageRD::skeleton_create() { @@ -5149,6 +5171,8 @@ void RendererStorageRD::skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d skeleton->uniform_set_mi = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_SKELETON); } } + + skeleton->dependency.changed_notify(DEPENDENCY_CHANGED_SKELETON_DATA); } int RendererStorageRD::skeleton_get_bone_count(RID p_skeleton) const { @@ -5269,7 +5293,8 @@ void RendererStorageRD::_update_dirty_skeletons() { skeleton_dirty_list = skeleton->dirty_list; - skeleton->instance_dependency.instance_notify_changed(true, false); + skeleton->dependency.changed_notify(DEPENDENCY_CHANGED_SKELETON_BONES); + skeleton->version++; skeleton->dirty = false; @@ -5290,17 +5315,20 @@ RID RendererStorageRD::light_create(RS::LightType p_type) { light.param[RS::LIGHT_PARAM_SPECULAR] = 0.5; light.param[RS::LIGHT_PARAM_RANGE] = 1.0; light.param[RS::LIGHT_PARAM_SIZE] = 0.0; + light.param[RS::LIGHT_PARAM_ATTENUATION] = 1.0; light.param[RS::LIGHT_PARAM_SPOT_ANGLE] = 45; + light.param[RS::LIGHT_PARAM_SPOT_ATTENUATION] = 1.0; light.param[RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE] = 0; light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET] = 0.1; light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET] = 0.3; light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET] = 0.6; light.param[RS::LIGHT_PARAM_SHADOW_FADE_START] = 0.8; - light.param[RS::LIGHT_PARAM_SHADOW_BIAS] = 0.02; light.param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 1.0; + light.param[RS::LIGHT_PARAM_SHADOW_BIAS] = 0.02; + light.param[RS::LIGHT_PARAM_SHADOW_BLUR] = 0; light.param[RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE] = 20.0; - light.param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS] = 0.05; light.param[RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE] = 1.0; + light.param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS] = 0.05; return light_owner.make_rid(light); } @@ -5328,7 +5356,7 @@ void RendererStorageRD::light_set_param(RID p_light, RS::LightParam p_param, flo case RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE: case RS::LIGHT_PARAM_SHADOW_BIAS: { light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } break; default: { } @@ -5343,7 +5371,7 @@ void RendererStorageRD::light_set_shadow(RID p_light, bool p_enabled) { light->shadow = p_enabled; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } void RendererStorageRD::light_set_shadow_color(RID p_light, const Color &p_color) { @@ -5385,7 +5413,7 @@ void RendererStorageRD::light_set_cull_mask(RID p_light, uint32_t p_mask) { light->cull_mask = p_mask; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } void RendererStorageRD::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) { @@ -5395,7 +5423,7 @@ void RendererStorageRD::light_set_reverse_cull_face_mode(RID p_light, bool p_ena light->reverse_cull = p_enabled; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } void RendererStorageRD::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) { @@ -5405,7 +5433,7 @@ void RendererStorageRD::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bak light->bake_mode = p_bake_mode; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } void RendererStorageRD::light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) { @@ -5415,7 +5443,7 @@ void RendererStorageRD::light_set_max_sdfgi_cascade(RID p_light, uint32_t p_casc light->max_sdfgi_cascade = p_cascade; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } void RendererStorageRD::light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) { @@ -5425,7 +5453,7 @@ void RendererStorageRD::light_omni_set_shadow_mode(RID p_light, RS::LightOmniSha light->omni_shadow_mode = p_mode; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } RS::LightOmniShadowMode RendererStorageRD::light_omni_get_shadow_mode(RID p_light) { @@ -5441,7 +5469,7 @@ void RendererStorageRD::light_directional_set_shadow_mode(RID p_light, RS::Light light->directional_shadow_mode = p_mode; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } void RendererStorageRD::light_directional_set_blend_splits(RID p_light, bool p_enable) { @@ -5450,7 +5478,7 @@ void RendererStorageRD::light_directional_set_blend_splits(RID p_light, bool p_e light->directional_blend_splits = p_enable; light->version++; - light->instance_dependency.instance_notify_changed(true, false); + light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT); } bool RendererStorageRD::light_directional_get_blend_splits(RID p_light) const { @@ -5549,7 +5577,7 @@ void RendererStorageRD::reflection_probe_set_update_mode(RID p_probe, RS::Reflec ERR_FAIL_COND(!reflection_probe); reflection_probe->update_mode = p_mode; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } void RendererStorageRD::reflection_probe_set_intensity(RID p_probe, float p_intensity) { @@ -5586,7 +5614,7 @@ void RendererStorageRD::reflection_probe_set_max_distance(RID p_probe, float p_d reflection_probe->max_distance = p_distance; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } void RendererStorageRD::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) { @@ -5597,7 +5625,7 @@ void RendererStorageRD::reflection_probe_set_extents(RID p_probe, const Vector3 return; } reflection_probe->extents = p_extents; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } void RendererStorageRD::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) { @@ -5605,7 +5633,7 @@ void RendererStorageRD::reflection_probe_set_origin_offset(RID p_probe, const Ve ERR_FAIL_COND(!reflection_probe); reflection_probe->origin_offset = p_offset; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } void RendererStorageRD::reflection_probe_set_as_interior(RID p_probe, bool p_enable) { @@ -5613,7 +5641,7 @@ void RendererStorageRD::reflection_probe_set_as_interior(RID p_probe, bool p_ena ERR_FAIL_COND(!reflection_probe); reflection_probe->interior = p_enable; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } void RendererStorageRD::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) { @@ -5628,7 +5656,7 @@ void RendererStorageRD::reflection_probe_set_enable_shadows(RID p_probe, bool p_ ERR_FAIL_COND(!reflection_probe); reflection_probe->enable_shadows = p_enable; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } void RendererStorageRD::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) { @@ -5636,7 +5664,7 @@ void RendererStorageRD::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_l ERR_FAIL_COND(!reflection_probe); reflection_probe->cull_mask = p_layers; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } void RendererStorageRD::reflection_probe_set_resolution(RID p_probe, int p_resolution) { @@ -5653,7 +5681,7 @@ void RendererStorageRD::reflection_probe_set_lod_threshold(RID p_probe, float p_ reflection_probe->lod_threshold = p_ratio; - reflection_probe->instance_dependency.instance_notify_changed(true, false); + reflection_probe->dependency.changed_notify(DEPENDENCY_CHANGED_REFLECTION_PROBE); } AABB RendererStorageRD::reflection_probe_get_aabb(RID p_probe) const { @@ -5771,7 +5799,7 @@ void RendererStorageRD::decal_set_extents(RID p_decal, const Vector3 &p_extents) Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND(!decal); decal->extents = p_extents; - decal->instance_dependency.instance_notify_changed(true, false); + decal->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } void RendererStorageRD::decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) { @@ -5795,7 +5823,7 @@ void RendererStorageRD::decal_set_texture(RID p_decal, RS::DecalTexture p_type, texture_add_to_decal_atlas(decal->textures[p_type]); } - decal->instance_dependency.instance_notify_changed(false, true); + decal->dependency.changed_notify(DEPENDENCY_CHANGED_DECAL); } void RendererStorageRD::decal_set_emission_energy(RID p_decal, float p_energy) { @@ -5820,7 +5848,7 @@ void RendererStorageRD::decal_set_cull_mask(RID p_decal, uint32_t p_layers) { Decal *decal = decal_owner.getornull(p_decal); ERR_FAIL_COND(!decal); decal->cull_mask = p_layers; - decal->instance_dependency.instance_notify_changed(true, false); + decal->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } void RendererStorageRD::decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) { @@ -5977,7 +6005,7 @@ void RendererStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_to_ gi_probe->version++; gi_probe->data_version++; - gi_probe->instance_dependency.instance_notify_changed(true, false); + gi_probe->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } AABB RendererStorageRD::gi_probe_get_bounds(RID p_gi_probe) const { @@ -7055,45 +7083,45 @@ void RendererStorageRD::render_target_set_backbuffer_uniform_set(RID p_render_ta rt->backbuffer_uniform_set = p_uniform_set; } -void RendererStorageRD::base_update_dependency(RID p_base, InstanceBaseDependency *p_instance) { +void RendererStorageRD::base_update_dependency(RID p_base, DependencyTracker *p_instance) { if (mesh_owner.owns(p_base)) { Mesh *mesh = mesh_owner.getornull(p_base); - p_instance->update_dependency(&mesh->instance_dependency); + p_instance->update_dependency(&mesh->dependency); } else if (multimesh_owner.owns(p_base)) { MultiMesh *multimesh = multimesh_owner.getornull(p_base); - p_instance->update_dependency(&multimesh->instance_dependency); + p_instance->update_dependency(&multimesh->dependency); if (multimesh->mesh.is_valid()) { base_update_dependency(multimesh->mesh, p_instance); } } else if (reflection_probe_owner.owns(p_base)) { ReflectionProbe *rp = reflection_probe_owner.getornull(p_base); - p_instance->update_dependency(&rp->instance_dependency); + p_instance->update_dependency(&rp->dependency); } else if (decal_owner.owns(p_base)) { Decal *decal = decal_owner.getornull(p_base); - p_instance->update_dependency(&decal->instance_dependency); + p_instance->update_dependency(&decal->dependency); } else if (gi_probe_owner.owns(p_base)) { GIProbe *gip = gi_probe_owner.getornull(p_base); - p_instance->update_dependency(&gip->instance_dependency); + p_instance->update_dependency(&gip->dependency); } else if (lightmap_owner.owns(p_base)) { Lightmap *lm = lightmap_owner.getornull(p_base); - p_instance->update_dependency(&lm->instance_dependency); + p_instance->update_dependency(&lm->dependency); } else if (light_owner.owns(p_base)) { Light *l = light_owner.getornull(p_base); - p_instance->update_dependency(&l->instance_dependency); + p_instance->update_dependency(&l->dependency); } else if (particles_owner.owns(p_base)) { Particles *p = particles_owner.getornull(p_base); - p_instance->update_dependency(&p->instance_dependency); + p_instance->update_dependency(&p->dependency); } else if (particles_collision_owner.owns(p_base)) { ParticlesCollision *pc = particles_collision_owner.getornull(p_base); - p_instance->update_dependency(&pc->instance_dependency); + p_instance->update_dependency(&pc->dependency); } } -void RendererStorageRD::skeleton_update_dependency(RID p_skeleton, InstanceBaseDependency *p_instance) { +void RendererStorageRD::skeleton_update_dependency(RID p_skeleton, DependencyTracker *p_instance) { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); ERR_FAIL_COND(!skeleton); - p_instance->update_dependency(&skeleton->instance_dependency); + p_instance->update_dependency(&skeleton->dependency); } RS::InstanceType RendererStorageRD::get_base_type(RID p_rid) const { @@ -8114,12 +8142,13 @@ bool RendererStorageRD::free(RID p_rid) { _update_queued_materials(); } material_set_shader(p_rid, RID()); //clean up shader - material->instance_dependency.instance_notify_deleted(p_rid); + material->dependency.deleted_notify(p_rid); + material_owner.free(p_rid); } else if (mesh_owner.owns(p_rid)) { mesh_clear(p_rid); Mesh *mesh = mesh_owner.getornull(p_rid); - mesh->instance_dependency.instance_notify_deleted(p_rid); + mesh->dependency.deleted_notify(p_rid); if (mesh->instances.size()) { ERR_PRINT("deleting mesh with active instances"); } @@ -8136,17 +8165,17 @@ bool RendererStorageRD::free(RID p_rid) { _update_dirty_multimeshes(); multimesh_allocate(p_rid, 0, RS::MULTIMESH_TRANSFORM_2D); MultiMesh *multimesh = multimesh_owner.getornull(p_rid); - multimesh->instance_dependency.instance_notify_deleted(p_rid); + multimesh->dependency.deleted_notify(p_rid); multimesh_owner.free(p_rid); } else if (skeleton_owner.owns(p_rid)) { _update_dirty_skeletons(); skeleton_allocate(p_rid, 0); Skeleton *skeleton = skeleton_owner.getornull(p_rid); - skeleton->instance_dependency.instance_notify_deleted(p_rid); + skeleton->dependency.deleted_notify(p_rid); skeleton_owner.free(p_rid); } else if (reflection_probe_owner.owns(p_rid)) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_rid); - reflection_probe->instance_dependency.instance_notify_deleted(p_rid); + reflection_probe->dependency.deleted_notify(p_rid); reflection_probe_owner.free(p_rid); } else if (decal_owner.owns(p_rid)) { Decal *decal = decal_owner.getornull(p_rid); @@ -8155,30 +8184,30 @@ bool RendererStorageRD::free(RID p_rid) { texture_remove_from_decal_atlas(decal->textures[i]); } } - decal->instance_dependency.instance_notify_deleted(p_rid); + decal->dependency.deleted_notify(p_rid); decal_owner.free(p_rid); } else if (gi_probe_owner.owns(p_rid)) { gi_probe_allocate(p_rid, Transform(), AABB(), Vector3i(), Vector(), Vector(), Vector(), Vector()); //deallocate GIProbe *gi_probe = gi_probe_owner.getornull(p_rid); - gi_probe->instance_dependency.instance_notify_deleted(p_rid); + gi_probe->dependency.deleted_notify(p_rid); gi_probe_owner.free(p_rid); } else if (lightmap_owner.owns(p_rid)) { lightmap_set_textures(p_rid, RID(), false); Lightmap *lightmap = lightmap_owner.getornull(p_rid); - lightmap->instance_dependency.instance_notify_deleted(p_rid); + lightmap->dependency.deleted_notify(p_rid); lightmap_owner.free(p_rid); } else if (light_owner.owns(p_rid)) { light_set_projector(p_rid, RID()); //clear projector // delete the texture Light *light = light_owner.getornull(p_rid); - light->instance_dependency.instance_notify_deleted(p_rid); + light->dependency.deleted_notify(p_rid); light_owner.free(p_rid); } else if (particles_owner.owns(p_rid)) { Particles *particles = particles_owner.getornull(p_rid); _particles_free_data(particles); - particles->instance_dependency.instance_notify_deleted(p_rid); + particles->dependency.deleted_notify(p_rid); particles_owner.free(p_rid); } else if (particles_collision_owner.owns(p_rid)) { ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_rid); @@ -8186,8 +8215,10 @@ bool RendererStorageRD::free(RID p_rid) { if (particles_collision->heightfield_texture.is_valid()) { RD::get_singleton()->free(particles_collision->heightfield_texture); } - particles_collision->instance_dependency.instance_notify_deleted(p_rid); + particles_collision->dependency.deleted_notify(p_rid); particles_collision_owner.free(p_rid); + } else if (particles_collision_instance_owner.owns(p_rid)) { + particles_collision_instance_owner.free(p_rid); } else if (render_target_owner.owns(p_rid)) { RenderTarget *rt = render_target_owner.getornull(p_rid); diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index 6d1587185e2..bd27936e38c 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -360,6 +360,7 @@ private: Shader *shader; //shortcut to shader data and type ShaderType shader_type; + uint32_t shader_id = 0; bool update_requested; bool uniform_dirty; bool texture_dirty; @@ -367,7 +368,7 @@ private: Map params; int32_t priority; RID next_pass; - RendererStorage::InstanceDependency instance_dependency; + Dependency dependency; }; MaterialDataRequestFunction material_data_request_func[SHADER_TYPE_MAX]; @@ -460,7 +461,7 @@ private: List instances; - RendererStorage::InstanceDependency instance_dependency; + Dependency dependency; }; mutable RID_Owner mesh_owner; @@ -563,7 +564,7 @@ private: bool dirty = false; MultiMesh *dirty_list = nullptr; - RendererStorage::InstanceDependency instance_dependency; + Dependency dependency; }; mutable RID_Owner multimesh_owner; @@ -734,7 +735,7 @@ private: ParticleEmissionBuffer *emission_buffer = nullptr; RID emission_storage_buffer; - Set collisions; + Set collisions; Particles() : inactive(true), @@ -761,7 +762,7 @@ private: clear(true) { } - RendererStorage::InstanceDependency instance_dependency; + Dependency dependency; ParticlesFrameParams frame_params; }; @@ -889,11 +890,19 @@ private: RS::ParticlesCollisionHeightfieldResolution heightfield_resolution = RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_1024; - RendererStorage::InstanceDependency instance_dependency; + Dependency dependency; }; mutable RID_Owner particles_collision_owner; + struct ParticlesCollisionInstance { + RID collision; + Transform transform; + bool active = false; + }; + + mutable RID_Owner particles_collision_instance_owner; + /* Skeleton */ struct Skeleton { @@ -911,7 +920,7 @@ private: uint64_t version = 1; - RendererStorage::InstanceDependency instance_dependency; + Dependency dependency; }; mutable RID_Owner skeleton_owner; @@ -943,7 +952,7 @@ private: bool directional_sky_only = false; uint64_t version = 0; - RendererStorage::InstanceDependency instance_dependency; + Dependency dependency; }; mutable RID_Owner light_owner; @@ -966,7 +975,7 @@ private: uint32_t cull_mask = (1 << 20) - 1; float lod_threshold = 0.01; - RendererStorage::InstanceDependency instance_dependency; + Dependency dependency; }; mutable RID_Owner reflection_probe_owner; @@ -987,7 +996,7 @@ private: float distance_fade_length = 1; float normal_fade = 0.0; - RendererStorage::InstanceDependency instance_dependency; + Dependency dependency; }; mutable RID_Owner decal_owner; @@ -1025,7 +1034,7 @@ private: uint32_t version = 1; uint32_t data_version = 1; - RendererStorage::InstanceDependency instance_dependency; + Dependency dependency; }; GiprobeSdfShaderRD giprobe_sdf_shader; @@ -1054,7 +1063,7 @@ private: int32_t over = EMPTY_LEAF, under = EMPTY_LEAF; }; - RendererStorage::InstanceDependency instance_dependency; + Dependency dependency; }; bool using_lightmap_array; //high end uses this @@ -1347,11 +1356,16 @@ public: void material_get_instance_shader_parameters(RID p_material, List *r_parameters); - void material_update_dependency(RID p_material, InstanceBaseDependency *p_instance); + void material_update_dependency(RID p_material, DependencyTracker *p_instance); void material_force_update_textures(RID p_material, ShaderType p_shader_type); void material_set_data_request_function(ShaderType p_shader_type, MaterialDataRequestFunction p_function); + _FORCE_INLINE_ uint32_t material_get_shader_id(RID p_material) { + Material *material = material_owner.getornull(p_material); + return material->shader_id; + } + _FORCE_INLINE_ MaterialData *material_get_data(RID p_material, ShaderType p_shader_type) { Material *material = material_owner.getornull(p_material); if (!material || material->shader_type != p_shader_type) { @@ -1664,6 +1678,10 @@ public: void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform); Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const; + _FORCE_INLINE_ bool skeleton_is_valid(RID p_skeleton) { + return skeleton_owner.getornull(p_skeleton) != nullptr; + } + _FORCE_INLINE_ RID skeleton_get_3d_uniform_set(RID p_skeleton, RID p_shader, uint32_t p_set) const { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); ERR_FAIL_COND_V(!skeleton, RID()); @@ -1827,8 +1845,8 @@ public: Color reflection_probe_get_ambient_color(RID p_probe) const; float reflection_probe_get_ambient_color_energy(RID p_probe) const; - void base_update_dependency(RID p_base, InstanceBaseDependency *p_instance); - void skeleton_update_dependency(RID p_skeleton, InstanceBaseDependency *p_instance); + void base_update_dependency(RID p_base, DependencyTracker *p_instance); + void skeleton_update_dependency(RID p_skeleton, DependencyTracker *p_instance); /* DECAL API */ @@ -1977,7 +1995,11 @@ public: _FORCE_INLINE_ float lightmap_get_probe_capture_update_speed() const { return lightmap_probe_capture_update_speed; } - + _FORCE_INLINE_ RID lightmap_get_texture(RID p_lightmap) const { + const Lightmap *lm = lightmap_owner.getornull(p_lightmap); + ERR_FAIL_COND_V(!lm, RID()); + return lm->light_texture; + } _FORCE_INLINE_ int32_t lightmap_get_array_index(RID p_lightmap) const { ERR_FAIL_COND_V(!using_lightmap_array, -1); //only for arrays const Lightmap *lm = lightmap_owner.getornull(p_lightmap); @@ -2078,8 +2100,8 @@ public: return particles->particles_transforms_buffer_uniform_set; } - virtual void particles_add_collision(RID p_particles, InstanceBaseDependency *p_instance); - virtual void particles_remove_collision(RID p_particles, InstanceBaseDependency *p_instance); + virtual void particles_add_collision(RID p_particles, RID p_particles_collision_instance); + virtual void particles_remove_collision(RID p_particles, RID p_particles_collision_instance); /* PARTICLES COLLISION */ @@ -2099,6 +2121,11 @@ public: virtual bool particles_collision_is_heightfield(RID p_particles_collision) const; RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const; + //used from 2D and 3D + virtual RID particles_collision_instance_create(RID p_collision); + virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform); + virtual void particles_collision_instance_set_active(RID p_collision_instance, bool p_active); + /* GLOBAL VARIABLES API */ virtual void global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value); diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index d1f07a354f9..e955cead05c 100644 --- a/servers/rendering/renderer_rd/shader_rd.cpp +++ b/servers/rendering/renderer_rd/shader_rd.cpp @@ -360,7 +360,7 @@ void ShaderRD::_compile_version(Version *p_version) { p_version->variants = memnew_arr(RID, variant_defines.size()); #if 1 - RendererCompositorRD::thread_work_pool.do_work(variant_defines.size(), this, &ShaderRD::_compile_variant, p_version); + RendererThreadPool::singleton->thread_work_pool.do_work(variant_defines.size(), this, &ShaderRD::_compile_variant, p_version); #else for (int i = 0; i < variant_defines.size(); i++) { _compile_variant(i, p_version); diff --git a/servers/rendering/renderer_rd/shaders/scene_forward.glsl b/servers/rendering/renderer_rd/shaders/scene_forward.glsl index 1c12a8a4c72..5d041babf1a 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward.glsl @@ -97,8 +97,6 @@ VERTEX_SHADER_GLOBALS invariant gl_Position; -layout(location = 7) flat out uint instance_index; - #ifdef MODE_DUAL_PARABOLOID layout(location = 8) out float dp_clip; @@ -106,22 +104,27 @@ layout(location = 8) out float dp_clip; #endif void main() { - instance_index = draw_call.instance_index; vec4 instance_custom = vec4(0.0); #if defined(COLOR_USED) color_interp = color_attrib; #endif - mat4 world_matrix = instances.data[instance_index].transform; - mat3 world_normal_matrix = mat3(instances.data[instance_index].normal_transform); + mat4 world_matrix = draw_call.transform; - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH)) { + mat3 world_normal_matrix; + if (bool(draw_call.flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) { + world_normal_matrix = inverse(mat3(world_matrix)); + } else { + world_normal_matrix = mat3(world_matrix); + } + + if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH)) { //multimesh, instances are for it - uint offset = (instances.data[instance_index].flags >> INSTANCE_FLAGS_MULTIMESH_STRIDE_SHIFT) & INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK; + uint offset = (draw_call.flags >> INSTANCE_FLAGS_MULTIMESH_STRIDE_SHIFT) & INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK; offset *= gl_InstanceIndex; mat4 matrix; - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) { + if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) { matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); offset += 2; } else { @@ -129,14 +132,14 @@ void main() { offset += 3; } - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) { + if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) { #ifdef COLOR_USED color_interp *= transforms.data[offset]; #endif offset += 1; } - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) { + if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) { instance_custom = transforms.data[offset]; } @@ -144,10 +147,6 @@ void main() { matrix = transpose(matrix); world_matrix = world_matrix * matrix; world_normal_matrix = world_normal_matrix * mat3(matrix); - - } else { - //not a multimesh, instances are for multiple draw calls - instance_index += gl_InstanceIndex; } vec3 vertex = vertex_attrib; @@ -162,7 +161,7 @@ void main() { #endif #if 0 - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_SKELETON)) { + if (bool(draw_call.flags & INSTANCE_FLAGS_SKELETON)) { //multimesh, instances are for it uvec2 bones_01 = uvec2(bone_attrib.x & 0xFFFF, bone_attrib.x >> 16) * 3; @@ -305,7 +304,7 @@ VERTEX_SHADER_CODE #endif #ifdef MODE_RENDER_MATERIAL if (scene_data.material_uv2_mode) { - gl_Position.xy = (uv2_attrib.xy + draw_call.bake_uv2_offset) * 2.0 - 1.0; + gl_Position.xy = (uv2_attrib.xy + draw_call.lightmap_uv_scale.xy) * 2.0 - 1.0; gl_Position.z = 0.00001; gl_Position.w = 1.0; } @@ -345,8 +344,6 @@ layout(location = 5) in vec3 tangent_interp; layout(location = 6) in vec3 binormal_interp; #endif -layout(location = 7) flat in uint instance_index; - #ifdef MODE_DUAL_PARABOLOID layout(location = 8) in float dp_clip; @@ -355,8 +352,7 @@ layout(location = 8) in float dp_clip; //defines to keep compatibility with vertex -#define world_matrix instances.data[instance_index].transform -#define world_normal_matrix instances.data[instance_index].normal_transform +#define world_matrix draw_call.transform #define projection_matrix scene_data.projection_matrix #if defined(ENABLE_SSS) && defined(ENABLE_TRANSMITTANCE) @@ -1971,7 +1967,7 @@ FRAGMENT_SHADER_CODE for (uint i = 0; i < decal_count; i++) { uint decal_index = cluster_data.indices[decal_pointer + i]; - if (!bool(decals.data[decal_index].mask & instances.data[instance_index].layer_mask)) { + if (!bool(decals.data[decal_index].mask & draw_call.layer_mask)) { continue; //not masked } @@ -2102,8 +2098,8 @@ FRAGMENT_SHADER_CODE #ifdef USE_LIGHTMAP //lightmap - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE)) { //has lightmap capture - uint index = instances.data[instance_index].gi_offset; + if (bool(draw_call.flags & INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE)) { //has lightmap capture + uint index = draw_call.gi_offset; vec3 wnormal = mat3(scene_data.camera_matrix) * normal; const float c1 = 0.429043; @@ -2122,12 +2118,12 @@ FRAGMENT_SHADER_CODE 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y + 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z); - } else if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap - bool uses_sh = bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP); - uint ofs = instances.data[instance_index].gi_offset & 0xFFF; + } else if (bool(draw_call.flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap + bool uses_sh = bool(draw_call.flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP); + uint ofs = draw_call.gi_offset & 0xFFFF; vec3 uvw; - uvw.xy = uv2 * instances.data[instance_index].lightmap_uv_scale.zw + instances.data[instance_index].lightmap_uv_scale.xy; - uvw.z = float((instances.data[instance_index].gi_offset >> 12) & 0xFF); + uvw.xy = uv2 * draw_call.lightmap_uv_scale.zw + draw_call.lightmap_uv_scale.xy; + uvw.z = float((draw_call.gi_offset >> 16) & 0xFFFF); if (uses_sh) { uvw.z *= 4.0; //SH textures use 4 times more data @@ -2136,7 +2132,7 @@ FRAGMENT_SHADER_CODE vec3 lm_light_l1_0 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb; vec3 lm_light_l1p1 = textureLod(sampler2DArray(lightmap_textures[ofs], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb; - uint idx = instances.data[instance_index].gi_offset >> 20; + uint idx = draw_call.gi_offset >> 20; vec3 n = normalize(lightmaps.data[idx].normal_xform * normal); ambient_light += lm_light_l0 * 0.282095f; @@ -2156,7 +2152,7 @@ FRAGMENT_SHADER_CODE } #elif defined(USE_FORWARD_GI) - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SDFGI)) { //has lightmap capture + if (bool(draw_call.flags & INSTANCE_FLAGS_USE_SDFGI)) { //has lightmap capture //make vertex orientation the world one, but still align to camera vec3 cam_pos = mat3(scene_data.camera_matrix) * vertex; @@ -2228,9 +2224,9 @@ FRAGMENT_SHADER_CODE } } - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes + if (bool(draw_call.flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes - uint index1 = instances.data[instance_index].gi_offset & 0xFFFF; + uint index1 = draw_call.gi_offset & 0xFFFF; vec3 ref_vec = normalize(reflect(normalize(vertex), normal)); //find arbitrary tangent and bitangent, then build a matrix vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); @@ -2242,7 +2238,7 @@ FRAGMENT_SHADER_CODE vec4 spec_accum = vec4(0.0); gi_probe_compute(index1, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum); - uint index2 = instances.data[instance_index].gi_offset >> 16; + uint index2 = draw_call.gi_offset >> 16; if (index2 != 0xFFFF) { gi_probe_compute(index2, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum); @@ -2261,7 +2257,7 @@ FRAGMENT_SHADER_CODE } #elif !defined(LOW_END_MODE) - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GI_BUFFERS)) { //use GI buffers + if (bool(draw_call.flags & INSTANCE_FLAGS_USE_GI_BUFFERS)) { //use GI buffers ivec2 coord; @@ -2343,7 +2339,7 @@ FRAGMENT_SHADER_CODE { //directional light for (uint i = 0; i < scene_data.directional_light_count; i++) { - if (!bool(directional_lights.data[i].mask & instances.data[instance_index].layer_mask)) { + if (!bool(directional_lights.data[i].mask & draw_call.layer_mask)) { continue; //not masked } @@ -2613,7 +2609,7 @@ FRAGMENT_SHADER_CODE for (uint i = 0; i < omni_light_count; i++) { uint light_index = cluster_data.indices[omni_light_pointer + i]; - if (!bool(lights.data[light_index].mask & instances.data[instance_index].layer_mask)) { + if (!bool(lights.data[light_index].mask & draw_call.layer_mask)) { continue; //not masked } @@ -2651,7 +2647,7 @@ FRAGMENT_SHADER_CODE for (uint i = 0; i < spot_light_count; i++) { uint light_index = cluster_data.indices[spot_light_pointer + i]; - if (!bool(lights.data[light_index].mask & instances.data[instance_index].layer_mask)) { + if (!bool(lights.data[light_index].mask & draw_call.layer_mask)) { continue; //not masked } @@ -2822,9 +2818,9 @@ FRAGMENT_SHADER_CODE normal_roughness_output_buffer = vec4(normal * 0.5 + 0.5, roughness); #ifdef MODE_RENDER_GIPROBE - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes - uint index1 = instances.data[instance_index].gi_offset & 0xFFFF; - uint index2 = instances.data[instance_index].gi_offset >> 16; + if (bool(draw_call.flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes + uint index1 = draw_call.gi_offset & 0xFFFF; + uint index2 = draw_call.gi_offset >> 16; giprobe_buffer.x = index1 & 0xFF; giprobe_buffer.y = index2 & 0xFF; } else { diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl index 17ed22f58a5..87ce74ba888 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_inc.glsl @@ -12,9 +12,12 @@ #endif layout(push_constant, binding = 0, std430) uniform DrawCall { - uint instance_index; - uint pad; //16 bits minimum size - vec2 bake_uv2_offset; //used for bake to uv2, ignored otherwise + mat4 transform; + uint flags; + uint instance_uniforms_ofs; //base offset in global buffer for instance variables + uint gi_offset; //GI information when using lightmapping (VCT or lightmap index) + uint layer_mask; + vec4 lightmap_uv_scale; } draw_call; @@ -134,21 +137,7 @@ scene_data; #define INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK 0x7 #define INSTANCE_FLAGS_SKELETON (1 << 19) - -struct InstanceData { - mat4 transform; - mat4 normal_transform; - uint flags; - uint instance_uniforms_ofs; //base offset in global buffer for instance variables - uint gi_offset; //GI information when using lightmapping (VCT or lightmap index) - uint layer_mask; - vec4 lightmap_uv_scale; -}; - -layout(set = 0, binding = 4, std430) restrict readonly buffer Instances { - InstanceData data[]; -} -instances; +#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 20) layout(set = 0, binding = 5, std430) restrict readonly buffer Lights { LightData data[]; @@ -177,35 +166,33 @@ layout(set = 0, binding = 10, std140) restrict readonly buffer Lightmaps { } lightmaps; -layout(set = 0, binding = 11) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES]; - struct LightmapCapture { vec4 sh[9]; }; -layout(set = 0, binding = 12, std140) restrict readonly buffer LightmapCaptures { +layout(set = 0, binding = 11, std140) restrict readonly buffer LightmapCaptures { LightmapCapture data[]; } lightmap_captures; -layout(set = 0, binding = 13) uniform texture2D decal_atlas; -layout(set = 0, binding = 14) uniform texture2D decal_atlas_srgb; +layout(set = 0, binding = 12) uniform texture2D decal_atlas; +layout(set = 0, binding = 13) uniform texture2D decal_atlas_srgb; -layout(set = 0, binding = 15, std430) restrict readonly buffer Decals { +layout(set = 0, binding = 14, std430) restrict readonly buffer Decals { DecalData data[]; } decals; -layout(set = 0, binding = 16) uniform utexture3D cluster_texture; +layout(set = 0, binding = 15) uniform utexture3D cluster_texture; -layout(set = 0, binding = 17, std430) restrict readonly buffer ClusterData { +layout(set = 0, binding = 16, std430) restrict readonly buffer ClusterData { uint indices[]; } cluster_data; -layout(set = 0, binding = 18) uniform texture2D directional_shadow_atlas; +layout(set = 0, binding = 17) uniform texture2D directional_shadow_atlas; -layout(set = 0, binding = 19, std430) restrict readonly buffer GlobalVariableData { +layout(set = 0, binding = 18, std430) restrict readonly buffer GlobalVariableData { vec4 data[]; } global_variables; @@ -219,7 +206,7 @@ struct SDFGIProbeCascadeData { float to_cell; // 1/bounds * grid_size }; -layout(set = 0, binding = 20, std140) uniform SDFGI { +layout(set = 0, binding = 19, std140) uniform SDFGI { vec3 grid_size; uint max_cascades; @@ -269,18 +256,20 @@ layout(set = 1, binding = 1) uniform textureCubeArray reflection_atlas; layout(set = 1, binding = 2) uniform texture2D shadow_atlas; +layout(set = 1, binding = 3) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES]; + #ifndef LOW_END_MODE -layout(set = 1, binding = 3) uniform texture3D gi_probe_textures[MAX_GI_PROBES]; +layout(set = 1, binding = 4) uniform texture3D gi_probe_textures[MAX_GI_PROBES]; #endif /* Set 3, Render Buffers */ #ifdef MODE_RENDER_SDF -layout(r16ui, set = 1, binding = 4) uniform restrict writeonly uimage3D albedo_volume_grid; -layout(r32ui, set = 1, binding = 5) uniform restrict writeonly uimage3D emission_grid; -layout(r32ui, set = 1, binding = 6) uniform restrict writeonly uimage3D emission_aniso_grid; -layout(r32ui, set = 1, binding = 7) uniform restrict uimage3D geom_facing_grid; +layout(r16ui, set = 1, binding = 5) uniform restrict writeonly uimage3D albedo_volume_grid; +layout(r32ui, set = 1, binding = 6) uniform restrict writeonly uimage3D emission_grid; +layout(r32ui, set = 1, binding = 7) uniform restrict writeonly uimage3D emission_aniso_grid; +layout(r32ui, set = 1, binding = 8) uniform restrict uimage3D geom_facing_grid; //still need to be present for shaders that use it, so remap them to something #define depth_buffer shadow_atlas @@ -289,17 +278,17 @@ layout(r32ui, set = 1, binding = 7) uniform restrict uimage3D geom_facing_grid; #else -layout(set = 1, binding = 4) uniform texture2D depth_buffer; -layout(set = 1, binding = 5) uniform texture2D color_buffer; +layout(set = 1, binding = 5) uniform texture2D depth_buffer; +layout(set = 1, binding = 6) uniform texture2D color_buffer; #ifndef LOW_END_MODE -layout(set = 1, binding = 6) uniform texture2D normal_roughness_buffer; -layout(set = 1, binding = 7) uniform texture2D ao_buffer; -layout(set = 1, binding = 8) uniform texture2D ambient_buffer; -layout(set = 1, binding = 9) uniform texture2D reflection_buffer; -layout(set = 1, binding = 10) uniform texture2DArray sdfgi_lightprobe_texture; -layout(set = 1, binding = 11) uniform texture3D sdfgi_occlusion_cascades; +layout(set = 1, binding = 7) uniform texture2D normal_roughness_buffer; +layout(set = 1, binding = 8) uniform texture2D ao_buffer; +layout(set = 1, binding = 9) uniform texture2D ambient_buffer; +layout(set = 1, binding = 10) uniform texture2D reflection_buffer; +layout(set = 1, binding = 11) uniform texture2DArray sdfgi_lightprobe_texture; +layout(set = 1, binding = 12) uniform texture3D sdfgi_occlusion_cascades; struct GIProbeData { mat4 xform; @@ -317,12 +306,12 @@ struct GIProbeData { uint mipmaps; }; -layout(set = 1, binding = 12, std140) uniform GIProbes { +layout(set = 1, binding = 13, std140) uniform GIProbes { GIProbeData data[MAX_GI_PROBES]; } gi_probes; -layout(set = 1, binding = 13) uniform texture3D volumetric_fog_texture; +layout(set = 1, binding = 14) uniform texture3D volumetric_fog_texture; #endif // LOW_END_MODE diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 2e32c69cba3..d3979521b1c 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -135,7 +135,7 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) { idata.flags |= InstanceData::FLAG_GEOM_LIGHTING_DIRTY; } - } else if (self->pair_volumes_to_mesh && B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && 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); @@ -147,7 +147,7 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) { idata.flags |= InstanceData::FLAG_GEOM_REFLECTION_DIRTY; } - } else if (self->pair_volumes_to_mesh && B->base_type == RS::INSTANCE_DECAL && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && 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); @@ -174,7 +174,7 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_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)) { + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_GI_PROBE) && 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); @@ -195,7 +195,8 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) { InstanceGIProbeData *gi_probe = static_cast(B->base_data); 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); + InstanceParticlesCollisionData *collision = static_cast(B->base_data); + RSG::storage->particles_add_collision(A->base, collision->instance); } } @@ -225,7 +226,7 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) { idata.flags |= InstanceData::FLAG_GEOM_LIGHTING_DIRTY; } - } else if (self->pair_volumes_to_mesh && B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && 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); @@ -237,7 +238,7 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) { idata.flags |= InstanceData::FLAG_GEOM_REFLECTION_DIRTY; } - } else if (self->pair_volumes_to_mesh && B->base_type == RS::INSTANCE_DECAL && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && 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); @@ -264,7 +265,7 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_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)) { + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_GI_PROBE) && 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); @@ -284,7 +285,8 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) { InstanceGIProbeData *gi_probe = static_cast(B->base_data); 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); + InstanceParticlesCollisionData *collision = static_cast(B->base_data); + RSG::storage->particles_remove_collision(A->base, collision->instance); } } @@ -386,6 +388,9 @@ void RendererSceneCull::_instance_update_mesh_instance(Instance *p_instance) { p_instance->mesh_instance = RID(); } + InstanceGeometryData *geom = static_cast(p_instance->base_data); + scene_render->geometry_instance_set_mesh_instance(geom->geometry_instance, p_instance->mesh_instance); + if (p_instance->scenario && p_instance->array_index >= 0) { InstanceData &idata = p_instance->scenario->instance_data[p_instance->array_index]; if (p_instance->mesh_instance.is_valid()) { @@ -421,6 +426,13 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { } switch (instance->base_type) { + case RS::INSTANCE_MESH: + case RS::INSTANCE_MULTIMESH: + case RS::INSTANCE_IMMEDIATE: + case RS::INSTANCE_PARTICLES: { + InstanceGeometryData *geom = static_cast(instance->base_data); + scene_render->geometry_instance_free(geom->geometry_instance); + } break; case RS::INSTANCE_LIGHT: { InstanceLightData *light = static_cast(instance->base_data); @@ -439,6 +451,10 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { } scene_render->free(light->instance); } break; + case RS::INSTANCE_PARTICLES_COLLISION: { + InstanceParticlesCollisionData *collision = static_cast(instance->base_data); + RSG::storage->free(collision->instance); + } break; case RS::INSTANCE_REFLECTION_PROBE: { InstanceReflectionProbeData *reflection_probe = static_cast(instance->base_data); scene_render->free(reflection_probe->instance); @@ -457,6 +473,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { while (lightmap_data->users.front()) { instance_geometry_set_lightmap(lightmap_data->users.front()->get()->self, RID(), Rect2(), 0); } + scene_render->free(lightmap_data->instance); } break; case RS::INSTANCE_GI_PROBE: { InstanceGIProbeData *gi_probe = static_cast(instance->base_data); @@ -514,7 +531,28 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { case RS::INSTANCE_PARTICLES: { InstanceGeometryData *geom = memnew(InstanceGeometryData); instance->base_data = geom; + geom->geometry_instance = scene_render->geometry_instance_create(p_base); + scene_render->geometry_instance_set_skeleton(geom->geometry_instance, instance->skeleton); + scene_render->geometry_instance_set_material_override(geom->geometry_instance, instance->material_override); + scene_render->geometry_instance_set_surface_materials(geom->geometry_instance, instance->materials); + scene_render->geometry_instance_set_transform(geom->geometry_instance, instance->transform, instance->aabb, instance->transformed_aabb); + scene_render->geometry_instance_set_layer_mask(geom->geometry_instance, instance->layer_mask); + scene_render->geometry_instance_set_lod_bias(geom->geometry_instance, instance->lod_bias); + scene_render->geometry_instance_set_use_baked_light(geom->geometry_instance, instance->baked_light); + scene_render->geometry_instance_set_use_dynamic_gi(geom->geometry_instance, instance->dynamic_gi); + scene_render->geometry_instance_set_cast_double_sided_shadows(geom->geometry_instance, instance->cast_shadows == RS::SHADOW_CASTING_SETTING_DOUBLE_SIDED); + scene_render->geometry_instance_set_use_lightmap(geom->geometry_instance, RID(), instance->lightmap_uv_scale, instance->lightmap_slice_index); + if (instance->lightmap_sh.size() == 9) { + scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, instance->lightmap_sh.ptr()); + } + + } break; + case RS::INSTANCE_PARTICLES_COLLISION: { + InstanceParticlesCollisionData *collision = memnew(InstanceParticlesCollisionData); + collision->instance = RSG::storage->particles_collision_instance_create(p_base); + RSG::storage->particles_collision_instance_set_active(collision->instance, instance->visible); + instance->base_data = collision; } break; case RS::INSTANCE_REFLECTION_PROBE: { InstanceReflectionProbeData *reflection_probe = memnew(InstanceReflectionProbeData); @@ -533,7 +571,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { case RS::INSTANCE_LIGHTMAP: { InstanceLightmapData *lightmap_data = memnew(InstanceLightmapData); instance->base_data = lightmap_data; - //lightmap_data->instance = scene_render->lightmap_data_instance_create(p_base); + lightmap_data->instance = scene_render->lightmap_instance_create(p_base); } break; case RS::INSTANCE_GI_PROBE: { InstanceGIProbeData *gi_probe = memnew(InstanceGIProbeData); @@ -558,7 +596,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { } //forcefully update the dependency now, so if for some reason it gets removed, we can immediately clear it - RSG::storage->base_update_dependency(p_base, instance); + RSG::storage->base_update_dependency(p_base, &instance->dependency_tracker); } _instance_queue_update(instance, true, true); @@ -659,6 +697,11 @@ void RendererSceneCull::instance_set_layer_mask(RID p_instance, uint32_t p_mask) if (instance->scenario && instance->array_index >= 0) { instance->scenario->instance_data[instance->array_index].layer_mask = p_mask; } + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast(instance->base_data); + scene_render->geometry_instance_set_layer_mask(geom->geometry_instance, p_mask); + } } void RendererSceneCull::instance_set_transform(RID p_instance, const Transform &p_transform) { @@ -739,6 +782,11 @@ void RendererSceneCull::instance_set_visible(RID p_instance, bool p_visible) { } else if (instance->indexer_id.is_valid()) { _unpair_instance(instance); } + + if (instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { + InstanceParticlesCollisionData *collision = static_cast(instance->base_data); + RSG::storage->particles_collision_instance_set_active(collision->instance, p_visible); + } } inline bool is_geometry_instance(RenderingServer::InstanceType p_type) { @@ -782,12 +830,17 @@ void RendererSceneCull::instance_attach_skeleton(RID p_instance, RID p_skeleton) if (p_skeleton.is_valid()) { //update the dependency now, so if cleared, we remove it - RSG::storage->skeleton_update_dependency(p_skeleton, instance); + RSG::storage->skeleton_update_dependency(p_skeleton, &instance->dependency_tracker); } - _instance_update_mesh_instance(instance); - _instance_queue_update(instance, true, true); + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + _instance_update_mesh_instance(instance); + + InstanceGeometryData *geom = static_cast(instance->base_data); + scene_render->geometry_instance_set_skeleton(geom->geometry_instance, p_skeleton); + } } void RendererSceneCull::instance_set_exterior(RID p_instance, bool p_enabled) { @@ -892,6 +945,11 @@ void RendererSceneCull::instance_geometry_set_flag(RID p_instance, RS::InstanceF } } + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast(instance->base_data); + scene_render->geometry_instance_set_use_baked_light(geom->geometry_instance, p_enabled); + } + } break; case RS::INSTANCE_FLAG_USE_DYNAMIC_GI: { if (p_enabled == instance->dynamic_gi) { @@ -907,6 +965,11 @@ void RendererSceneCull::instance_geometry_set_flag(RID p_instance, RS::InstanceF //once out of octree, can be changed instance->dynamic_gi = p_enabled; + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast(instance->base_data); + scene_render->geometry_instance_set_use_dynamic_gi(geom->geometry_instance, p_enabled); + } + } break; case RS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE: { instance->redraw_if_visible = p_enabled; @@ -948,6 +1011,11 @@ void RendererSceneCull::instance_geometry_set_cast_shadows_setting(RID p_instanc } } + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast(instance->base_data); + scene_render->geometry_instance_set_cast_double_sided_shadows(geom->geometry_instance, instance->cast_shadows == RS::SHADOW_CASTING_SETTING_DOUBLE_SIDED); + } + _instance_queue_update(instance, false, true); } @@ -957,6 +1025,11 @@ void RendererSceneCull::instance_geometry_set_material_override(RID p_instance, instance->material_override = p_material; _instance_queue_update(instance, false, true); + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast(instance->base_data); + scene_render->geometry_instance_set_material_override(geom->geometry_instance, p_material); + } } void RendererSceneCull::instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) { @@ -981,9 +1054,17 @@ void RendererSceneCull::instance_geometry_set_lightmap(RID p_instance, RID p_lig instance->lightmap_uv_scale = p_lightmap_uv_scale; instance->lightmap_slice_index = p_slice_index; + RID lightmap_instance_rid; + if (lightmap_instance) { InstanceLightmapData *lightmap_data = static_cast(lightmap_instance->base_data); lightmap_data->users.insert(instance); + lightmap_instance_rid = lightmap_data->instance; + } + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast(instance->base_data); + scene_render->geometry_instance_set_use_lightmap(geom->geometry_instance, lightmap_instance_rid, p_lightmap_uv_scale, p_slice_index); } } @@ -992,16 +1073,21 @@ void RendererSceneCull::instance_geometry_set_lod_bias(RID p_instance, float p_l ERR_FAIL_COND(!instance); instance->lod_bias = p_lod_bias; + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast(instance->base_data); + scene_render->geometry_instance_set_lod_bias(geom->geometry_instance, p_lod_bias); + } } void RendererSceneCull::instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value) { Instance *instance = instance_owner.getornull(p_instance); ERR_FAIL_COND(!instance); - Map::Element *E = instance->instance_shader_parameters.find(p_parameter); + Map::Element *E = instance->instance_shader_parameters.find(p_parameter); if (!E) { - RendererSceneRender::InstanceBase::InstanceShaderParameter isp; + Instance::InstanceShaderParameter isp; isp.index = -1; isp.info = PropertyInfo(); isp.value = p_value; @@ -1042,7 +1128,7 @@ void RendererSceneCull::instance_geometry_get_shader_parameter_list(RID p_instan const_cast(this)->update_dirty_instances(); Vector names; - for (Map::Element *E = instance->instance_shader_parameters.front(); E; E = E->next()) { + for (Map::Element *E = instance->instance_shader_parameters.front(); E; E = E->next()) { names.push_back(E->key()); } names.sort_custom(); @@ -1079,9 +1165,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { if (light->max_sdfgi_cascade != max_sdfgi_cascade) { light->max_sdfgi_cascade = max_sdfgi_cascade; //should most likely make sdfgi dirty in scenario } - } - - if (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE) { + } else if (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE) { InstanceReflectionProbeData *reflection_probe = static_cast(p_instance->base_data); scene_render->reflection_probe_instance_set_transform(reflection_probe->instance, p_instance->transform); @@ -1090,35 +1174,49 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { InstanceData &idata = p_instance->scenario->instance_data[p_instance->array_index]; idata.flags |= InstanceData::FLAG_REFLECTION_PROBE_DIRTY; } - } - - if (p_instance->base_type == RS::INSTANCE_DECAL) { + } else if (p_instance->base_type == RS::INSTANCE_DECAL) { InstanceDecalData *decal = static_cast(p_instance->base_data); scene_render->decal_instance_set_transform(decal->instance, p_instance->transform); - } + } else if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) { + InstanceLightmapData *lightmap = static_cast(p_instance->base_data); - if (p_instance->base_type == RS::INSTANCE_GI_PROBE) { + scene_render->lightmap_instance_set_transform(lightmap->instance, p_instance->transform); + } else if (p_instance->base_type == RS::INSTANCE_GI_PROBE) { InstanceGIProbeData *gi_probe = static_cast(p_instance->base_data); scene_render->gi_probe_instance_set_transform_to_data(gi_probe->probe_instance, p_instance->transform); - } - - if (p_instance->base_type == RS::INSTANCE_PARTICLES) { + } else if (p_instance->base_type == RS::INSTANCE_PARTICLES) { RSG::storage->particles_set_emission_transform(p_instance->base, p_instance->transform); - } + } else if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { + InstanceParticlesCollisionData *collision = static_cast(p_instance->base_data); - if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { //remove materials no longer used and un-own them if (RSG::storage->particles_collision_is_heightfield(p_instance->base)) { heightfield_particle_colliders_update_list.insert(p_instance); } + RSG::storage->particles_collision_instance_set_transform(collision->instance, p_instance->transform); } if (p_instance->aabb.has_no_surface()) { return; } + if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) { + //if this moved, update the captured objects + InstanceLightmapData *lightmap_data = static_cast(p_instance->base_data); + //erase dependencies, since no longer a lightmap + + for (Set::Element *E = lightmap_data->geometries.front(); E; E = E->next()) { + Instance *geom = E->get(); + _instance_queue_update(geom, true, false); + } + } + + AABB new_aabb; + new_aabb = p_instance->transform.xform(p_instance->aabb); + p_instance->transformed_aabb = new_aabb; + if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { InstanceGeometryData *geom = static_cast(p_instance->base_data); //make sure lights are updated if it casts shadow @@ -1137,29 +1235,13 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { if (!p_instance->lightmap_sh.is_empty()) { p_instance->lightmap_sh.clear(); //don't need SH p_instance->lightmap_target_sh.clear(); //don't need SH + scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, nullptr); } } + + scene_render->geometry_instance_set_transform(geom->geometry_instance, p_instance->transform, p_instance->aabb, p_instance->transformed_aabb); } - if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) { - //if this moved, update the captured objects - InstanceLightmapData *lightmap_data = static_cast(p_instance->base_data); - //erase dependencies, since no longer a lightmap - - for (Set::Element *E = lightmap_data->geometries.front(); E; E = E->next()) { - Instance *geom = E->get(); - _instance_queue_update(geom, true, false); - } - } - - p_instance->mirror = p_instance->transform.basis.determinant() < 0.0; - - AABB new_aabb; - - new_aabb = p_instance->transform.xform(p_instance->aabb); - - p_instance->transformed_aabb = new_aabb; - if (p_instance->scenario == nullptr || !p_instance->visible || Math::is_zero_approx(p_instance->transform.basis.determinant())) { p_instance->prev_transformed_aabb = p_instance->transformed_aabb; return; @@ -1195,17 +1277,26 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { idata.flags = p_instance->base_type; //changing it means de-indexing, so this never needs to be changed later idata.base_rid = p_instance->base; switch (p_instance->base_type) { + case RS::INSTANCE_MESH: + case RS::INSTANCE_MULTIMESH: + case RS::INSTANCE_IMMEDIATE: + case RS::INSTANCE_PARTICLES: { + idata.instance_geometry = static_cast(p_instance->base_data)->geometry_instance; + } break; case RS::INSTANCE_LIGHT: { - idata.instance_data_rid = static_cast(p_instance->base_data)->instance; + idata.instance_data_rid = static_cast(p_instance->base_data)->instance.get_id(); } break; case RS::INSTANCE_REFLECTION_PROBE: { - idata.instance_data_rid = static_cast(p_instance->base_data)->instance; + idata.instance_data_rid = static_cast(p_instance->base_data)->instance.get_id(); } break; case RS::INSTANCE_DECAL: { - idata.instance_data_rid = static_cast(p_instance->base_data)->instance; + idata.instance_data_rid = static_cast(p_instance->base_data)->instance.get_id(); + } break; + case RS::INSTANCE_LIGHTMAP: { + idata.instance_data_rid = static_cast(p_instance->base_data)->instance.get_id(); } break; case RS::INSTANCE_GI_PROBE: { - idata.instance_data_rid = static_cast(p_instance->base_data)->probe_instance; + idata.instance_data_rid = static_cast(p_instance->base_data)->probe_instance.get_id(); } break; default: { } @@ -1258,10 +1349,8 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { 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.pair_mask |= geometry_instance_pair_mask; + 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; @@ -1271,7 +1360,10 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { 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)) { + } else if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE)) { + pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK; + pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; + } else if (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && (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) { @@ -1325,10 +1417,12 @@ void RendererSceneCull::_unpair_instance(Instance *p_instance) { p_instance->array_index = -1; if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { // Clear these now because the InstanceData containing the dirty flags is gone - p_instance->light_instances.clear(); - p_instance->reflection_probe_instances.clear(); - //p_instance->decal_instances.clear(); will implement later - p_instance->gi_probe_instances.clear(); + InstanceGeometryData *geom = static_cast(p_instance->base_data); + + scene_render->geometry_instance_pair_light_instances(geom->geometry_instance, nullptr, 0); + scene_render->geometry_instance_pair_reflection_probe_instances(geom->geometry_instance, nullptr, 0); + scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, nullptr, 0); + scene_render->geometry_instance_pair_gi_probe_instances(geom->geometry_instance, nullptr, 0); } } @@ -1486,6 +1580,8 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance) } } } + + scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, p_instance->lightmap_sh.ptr()); } void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_index, Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect) { @@ -1849,7 +1945,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons } } - geometry_instances_to_shadow_render.push_back(instance); + geometry_instances_to_shadow_render.push_back(static_cast(instance->base_data)->geometry_instance); } RSG::storage->update_mesh_instances(); @@ -1922,7 +2018,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons } } - geometry_instances_to_shadow_render.push_back(instance); + geometry_instances_to_shadow_render.push_back(static_cast(instance->base_data)->geometry_instance); } RSG::storage->update_mesh_instances(); @@ -1980,7 +2076,7 @@ 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); + geometry_instances_to_shadow_render.push_back(static_cast(instance->base_data)->geometry_instance); } RSG::storage->update_mesh_instances(); @@ -2128,6 +2224,222 @@ void RendererSceneCull::render_camera(RID p_render_buffers, Ref &p_ _render_scene(p_render_buffers, cam_transform, camera_matrix, false, environment, camera->effects, p_scenario, p_shadow_atlas, RID(), -1, p_screen_lod_threshold); }; +void RendererSceneCull::_frustum_cull_threaded(uint32_t p_thread, FrustumCullData *cull_data) { + uint32_t cull_total = cull_data->scenario->instance_data.size(); + uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count(); + uint32_t cull_from = p_thread * cull_total / total_threads; + uint32_t cull_to = (p_thread + 1 == total_threads) ? cull_total : ((p_thread + 1) * cull_total / total_threads); + + _frustum_cull(*cull_data, frustum_cull_result_threads[p_thread], cull_from, cull_to); +} + +void RendererSceneCull::_frustum_cull(FrustumCullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to) { + 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(); + + uint32_t sdfgi_last_light_index = 0xFFFFFFFF; + uint32_t sdfgi_last_light_cascade = 0xFFFFFFFF; + + RID instance_pair_buffer[MAX_INSTANCE_PAIRS]; + + for (uint64_t i = p_from; i < p_to; i++) { + bool mesh_visible = false; + + if (cull_data.scenario->instance_aabbs[i].in_frustum(cull_data.cull->frustum)) { + InstanceData &idata = cull_data.scenario->instance_data[i]; + uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; + + if ((cull_data.visible_layers & idata.layer_mask) == 0) { + //failure + } else if (base_type == RS::INSTANCE_LIGHT) { + cull_result.lights.push_back(idata.instance); + cull_result.light_instances.push_back(RID::from_uint64(idata.instance_data_rid)); + if (cull_data.shadow_atlas.is_valid() && RSG::storage->light_has_shadow(idata.base_rid)) { + scene_render->light_instance_mark_visible(RID::from_uint64(idata.instance_data_rid)); //mark it visible for shadow allocation later + } + + } else if (base_type == RS::INSTANCE_REFLECTION_PROBE) { + if (cull_data.render_reflection_probe != idata.instance) { + //avoid entering The Matrix + + if ((idata.flags & InstanceData::FLAG_REFLECTION_PROBE_DIRTY) || scene_render->reflection_probe_instance_needs_redraw(RID::from_uint64(idata.instance_data_rid))) { + InstanceReflectionProbeData *reflection_probe = static_cast(idata.instance->base_data); + cull_data.cull->lock.lock(); + if (!reflection_probe->update_list.in_list()) { + reflection_probe->render_step = 0; + reflection_probe_render_list.add_last(&reflection_probe->update_list); + } + cull_data.cull->lock.unlock(); + + idata.flags &= ~uint32_t(InstanceData::FLAG_REFLECTION_PROBE_DIRTY); + } + + if (scene_render->reflection_probe_instance_has_reflection(RID::from_uint64(idata.instance_data_rid))) { + cull_result.reflections.push_back(RID::from_uint64(idata.instance_data_rid)); + } + } + } else if (base_type == RS::INSTANCE_DECAL) { + cull_result.decals.push_back(RID::from_uint64(idata.instance_data_rid)); + + } else if (base_type == RS::INSTANCE_GI_PROBE) { + InstanceGIProbeData *gi_probe = static_cast(idata.instance->base_data); + cull_data.cull->lock.lock(); + if (!gi_probe->update_element.in_list()) { + gi_probe_update_list.add(&gi_probe->update_element); + } + cull_data.cull->lock.unlock(); + cull_result.gi_probes.push_back(RID::from_uint64(idata.instance_data_rid)); + + } else if (base_type == RS::INSTANCE_LIGHTMAP) { + cull_result.gi_probes.push_back(RID::from_uint64(idata.instance_data_rid)); + } else if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && !(idata.flags & InstanceData::FLAG_CAST_SHADOWS_ONLY)) { + bool keep = true; + + if (idata.flags & InstanceData::FLAG_REDRAW_IF_VISIBLE) { + RenderingServerDefault::redraw_request(); + } + + if (base_type == RS::INSTANCE_MESH) { + mesh_visible = true; + } else if (base_type == RS::INSTANCE_PARTICLES) { + //particles visible? process them + if (RSG::storage->particles_is_inactive(idata.base_rid)) { + //but if nothing is going on, don't do it. + keep = false; + } else { + cull_data.cull->lock.lock(); + RSG::storage->particles_request_process(idata.base_rid); + cull_data.cull->lock.unlock(); + RSG::storage->particles_set_view_axis(idata.base_rid, -cull_data.cam_transform.basis.get_axis(2).normalized()); + //particles visible? request redraw + RenderingServerDefault::redraw_request(); + } + } + + if (geometry_instance_pair_mask & (1 << RS::INSTANCE_LIGHT) && (idata.flags & InstanceData::FLAG_GEOM_LIGHTING_DIRTY)) { + InstanceGeometryData *geom = static_cast(idata.instance->base_data); + uint32_t idx = 0; + + for (Set::Element *E = geom->lights.front(); E; E = E->next()) { + InstanceLightData *light = static_cast(E->get()->base_data); + instance_pair_buffer[idx++] = light->instance; + if (idx == MAX_INSTANCE_PAIRS) { + break; + } + } + + scene_render->geometry_instance_pair_light_instances(geom->geometry_instance, instance_pair_buffer, idx); + idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_LIGHTING_DIRTY); + } + + if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (idata.flags & InstanceData::FLAG_GEOM_REFLECTION_DIRTY)) { + InstanceGeometryData *geom = static_cast(idata.instance->base_data); + uint32_t idx = 0; + + for (Set::Element *E = geom->reflection_probes.front(); E; E = E->next()) { + InstanceReflectionProbeData *reflection_probe = static_cast(E->get()->base_data); + + instance_pair_buffer[idx++] = reflection_probe->instance; + if (idx == MAX_INSTANCE_PAIRS) { + break; + } + } + + scene_render->geometry_instance_pair_reflection_probe_instances(geom->geometry_instance, instance_pair_buffer, idx); + idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_REFLECTION_DIRTY); + } + + if (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && (idata.flags & InstanceData::FLAG_GEOM_DECAL_DIRTY)) { + //InstanceGeometryData *geom = static_cast(idata.instance->base_data); + //todo for GLES3 + idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_DECAL_DIRTY); + /*for (Set::Element *E = geom->dec.front(); E; E = E->next()) { + InstanceReflectionProbeData *reflection_probe = static_cast(E->get()->base_data); + + instance_pair_buffer[idx++] = reflection_probe->instance; + if (idx==MAX_INSTANCE_PAIRS) { + break; + } + }*/ + //scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, light_instances, idx); + } + + if (idata.flags & InstanceData::FLAG_GEOM_GI_PROBE_DIRTY) { + InstanceGeometryData *geom = static_cast(idata.instance->base_data); + uint32_t idx = 0; + for (Set::Element *E = geom->gi_probes.front(); E; E = E->next()) { + InstanceGIProbeData *gi_probe = static_cast(E->get()->base_data); + + instance_pair_buffer[idx++] = gi_probe->probe_instance; + if (idx == MAX_INSTANCE_PAIRS) { + break; + } + } + + scene_render->geometry_instance_pair_gi_probe_instances(geom->geometry_instance, instance_pair_buffer, idx); + idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_GI_PROBE_DIRTY); + } + + if ((idata.flags & InstanceData::FLAG_LIGHTMAP_CAPTURE) && idata.instance->last_frame_pass != frame_number && !idata.instance->lightmap_target_sh.is_empty() && !idata.instance->lightmap_sh.is_empty()) { + InstanceGeometryData *geom = static_cast(idata.instance->base_data); + Color *sh = idata.instance->lightmap_sh.ptrw(); + const Color *target_sh = idata.instance->lightmap_target_sh.ptr(); + for (uint32_t j = 0; j < 9; j++) { + sh[j] = sh[j].lerp(target_sh[j], MIN(1.0, lightmap_probe_update_speed)); + } + scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, sh); + idata.instance->last_frame_pass = frame_number; + } + + if (keep) { + cull_result.geometry_instances.push_back(idata.instance_geometry); + } + } + } + + for (uint32_t j = 0; j < cull_data.cull->shadow_count; j++) { + for (uint32_t k = 0; k < cull_data.cull->shadows[j].cascade_count; k++) { + if (cull_data.scenario->instance_aabbs[i].in_frustum(cull_data.cull->shadows[j].cascades[k].frustum)) { + InstanceData &idata = cull_data.scenario->instance_data[i]; + uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; + + if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && idata.flags & InstanceData::FLAG_CAST_SHADOWS) { + cull_result.directional_shadows[j].cascade_geometry_instances[k].push_back(idata.instance_geometry); + mesh_visible = true; + } + } + } + } + + for (uint32_t j = 0; j < cull_data.cull->sdfgi.region_count; j++) { + if (cull_data.scenario->instance_aabbs[i].in_aabb(cull_data.cull->sdfgi.region_aabb[j])) { + InstanceData &idata = cull_data.scenario->instance_data[i]; + uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; + + if (base_type == RS::INSTANCE_LIGHT) { + InstanceLightData *instance_light = (InstanceLightData *)idata.instance->base_data; + if (instance_light->bake_mode == RS::LIGHT_BAKE_STATIC && cull_data.cull->sdfgi.region_cascade[j] <= instance_light->max_sdfgi_cascade) { + if (sdfgi_last_light_index != i || sdfgi_last_light_cascade != cull_data.cull->sdfgi.region_cascade[j]) { + sdfgi_last_light_index = i; + sdfgi_last_light_cascade = cull_data.cull->sdfgi.region_cascade[j]; + cull_result.sdfgi_cascade_lights[sdfgi_last_light_cascade].push_back(instance_light->instance); + } + } + } else if ((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) { + if (idata.flags & InstanceData::FLAG_USES_BAKED_LIGHT) { + cull_result.sdfgi_region_geometry_instances[j].push_back(idata.instance_geometry); + mesh_visible = true; + } + } + } + } + + if (mesh_visible && cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_USES_MESH_INSTANCE) { + cull_result.mesh_instances.push_back(cull_data.scenario->instance_data[i].instance->mesh_instance); + } + } +} + void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, float p_screen_lod_threshold, bool p_using_shadows) { // Note, in stereo rendering: // - p_cam_transform will be a transform in the middle of our two eyes @@ -2153,9 +2465,6 @@ 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()); - 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(); - /* STEP 2 - CULL */ cull.frustum = Frustum(planes); @@ -2163,13 +2472,6 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca Vector directional_lights; // directional lights { - //reset shadows - for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { - for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { - cull.shadows[i].cascades[j].cull_result.clear(); - } - } - cull.shadow_count = 0; Vector lights_with_shadow; @@ -2206,18 +2508,7 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca { //sdfgi cull.sdfgi.region_count = 0; - for (int i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { - cull.sdfgi.region_cull_result[i].clear(); - } - - for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { - cull.sdfgi.cascade_lights[i].clear(); - } - if (p_render_buffers.is_valid()) { - for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { - cull.sdfgi.cascade_lights[i].clear(); - } cull.sdfgi.cascade_light_count = 0; uint32_t prev_cascade = 0xFFFFFFFF; @@ -2239,209 +2530,53 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca } } - { - //pre-clear results - 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(); - mesh_instance_cull_result.clear(); - } + frustum_cull_result.clear(); { - uint64_t cull_count = scenario->instance_data.size(); - uint32_t sdfgi_last_light_index = 0xFFFFFFFF; - uint32_t sdfgi_last_light_cascade = 0xFFFFFFFF; + uint64_t cull_from = 0; + uint64_t cull_to = scenario->instance_data.size(); - for (uint64_t i = 0; i < cull_count; i++) { - bool mesh_visible = false; + FrustumCullData cull_data; - if (scenario->instance_aabbs[i].in_frustum(cull.frustum)) { - InstanceData &idata = scenario->instance_data[i]; - uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; - - if ((p_visible_layers & idata.layer_mask) == 0) { - //failure - } else if (base_type == RS::INSTANCE_LIGHT) { - light_cull_result.push_back(idata.instance); - light_instance_cull_result.push_back(idata.instance_data_rid); - if (p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(idata.base_rid)) { - scene_render->light_instance_mark_visible(idata.instance_data_rid); //mark it visible for shadow allocation later - } - - } else if (base_type == RS::INSTANCE_REFLECTION_PROBE) { - if (render_reflection_probe != idata.instance) { - //avoid entering The Matrix - - if ((idata.flags & InstanceData::FLAG_REFLECTION_PROBE_DIRTY) || scene_render->reflection_probe_instance_needs_redraw(idata.instance_data_rid)) { - InstanceReflectionProbeData *reflection_probe = static_cast(idata.instance->base_data); - cull.lock.lock(); - if (!reflection_probe->update_list.in_list()) { - reflection_probe->render_step = 0; - reflection_probe_render_list.add_last(&reflection_probe->update_list); - } - cull.lock.unlock(); - - idata.flags &= ~uint32_t(InstanceData::FLAG_REFLECTION_PROBE_DIRTY); - } - - if (scene_render->reflection_probe_instance_has_reflection(idata.instance_data_rid)) { - reflection_probe_instance_cull_result.push_back(idata.instance_data_rid); - } - } - } else if (base_type == RS::INSTANCE_DECAL) { - decal_instance_cull_result.push_back(idata.instance_data_rid); - - } else if (base_type == RS::INSTANCE_GI_PROBE) { - InstanceGIProbeData *gi_probe = static_cast(idata.instance->base_data); - cull.lock.lock(); - if (!gi_probe->update_element.in_list()) { - gi_probe_update_list.add(&gi_probe->update_element); - } - cull.lock.unlock(); - gi_probe_instance_cull_result.push_back(idata.instance_data_rid); - - } else if (base_type == RS::INSTANCE_LIGHTMAP) { - lightmap_cull_result.push_back(idata.instance); - } else if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && !(idata.flags & InstanceData::FLAG_CAST_SHADOWS_ONLY)) { - bool keep = true; - - if (idata.flags & InstanceData::FLAG_REDRAW_IF_VISIBLE) { - RenderingServerDefault::redraw_request(); - } - - if (base_type == RS::INSTANCE_MESH) { - mesh_visible = true; - } else if (base_type == RS::INSTANCE_PARTICLES) { - //particles visible? process them - if (RSG::storage->particles_is_inactive(idata.base_rid)) { - //but if nothing is going on, don't do it. - keep = false; - } else { - cull.lock.lock(); - RSG::storage->particles_request_process(idata.base_rid); - cull.lock.unlock(); - RSG::storage->particles_set_view_axis(idata.base_rid, -p_cam_transform.basis.get_axis(2).normalized()); - //particles visible? request redraw - RenderingServerDefault::redraw_request(); - } - } - - if (pair_volumes_to_mesh && (idata.flags & InstanceData::FLAG_GEOM_LIGHTING_DIRTY)) { - InstanceGeometryData *geom = static_cast(idata.instance->base_data); - int l = 0; - //only called when lights AABB enter/exit this geometry - idata.instance->light_instances.resize(geom->lights.size()); - - for (Set::Element *E = geom->lights.front(); E; E = E->next()) { - InstanceLightData *light = static_cast(E->get()->base_data); - - idata.instance->light_instances.write[l++] = light->instance; - } - - idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_LIGHTING_DIRTY); - } - - if (pair_volumes_to_mesh && (idata.flags & InstanceData::FLAG_GEOM_REFLECTION_DIRTY)) { - InstanceGeometryData *geom = static_cast(idata.instance->base_data); - int l = 0; - //only called when reflection probe AABB enter/exit this geometry - idata.instance->reflection_probe_instances.resize(geom->reflection_probes.size()); - - for (Set::Element *E = geom->reflection_probes.front(); E; E = E->next()) { - InstanceReflectionProbeData *reflection_probe = static_cast(E->get()->base_data); - - idata.instance->reflection_probe_instances.write[l++] = reflection_probe->instance; - } - - idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_REFLECTION_DIRTY); - } - - if (pair_volumes_to_mesh && (idata.flags & InstanceData::FLAG_GEOM_DECAL_DIRTY)) { - //InstanceGeometryData *geom = static_cast(idata.instance->base_data); - //todo for GLES3 - idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_DECAL_DIRTY); - } - - if (idata.flags & InstanceData::FLAG_GEOM_GI_PROBE_DIRTY) { - InstanceGeometryData *geom = static_cast(idata.instance->base_data); - int l = 0; - //only called when reflection probe AABB enter/exit this geometry - idata.instance->gi_probe_instances.resize(geom->gi_probes.size()); - - for (Set::Element *E = geom->gi_probes.front(); E; E = E->next()) { - InstanceGIProbeData *gi_probe = static_cast(E->get()->base_data); - - idata.instance->gi_probe_instances.write[l++] = gi_probe->probe_instance; - } - - idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_GI_PROBE_DIRTY); - } - - if ((idata.flags & InstanceData::FLAG_LIGHTMAP_CAPTURE) && idata.instance->last_frame_pass != frame_number && !idata.instance->lightmap_target_sh.is_empty() && !idata.instance->lightmap_sh.is_empty()) { - Color *sh = idata.instance->lightmap_sh.ptrw(); - const Color *target_sh = idata.instance->lightmap_target_sh.ptr(); - for (uint32_t j = 0; j < 9; j++) { - sh[j] = sh[j].lerp(target_sh[j], MIN(1.0, lightmap_probe_update_speed)); - } - idata.instance->last_frame_pass = frame_number; - } - - if (keep) { - geometry_instances_to_render.push_back(idata.instance); - } - } + //prepare for eventual thread usage + cull_data.cull = &cull; + cull_data.scenario = scenario; + cull_data.shadow_atlas = p_shadow_atlas; + cull_data.cam_transform = p_cam_transform; + cull_data.visible_layers = p_visible_layers; + cull_data.render_reflection_probe = render_reflection_probe; +//#define DEBUG_CULL_TIME +#ifdef DEBUG_CULL_TIME + uint64_t time_from = OS::get_singleton()->get_ticks_usec(); +#endif + if (cull_to > thread_cull_threshold) { + //multiple threads + for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) { + frustum_cull_result_threads[i].clear(); } - for (uint32_t j = 0; j < cull.shadow_count; j++) { - for (uint32_t k = 0; k < cull.shadows[j].cascade_count; k++) { - if (scenario->instance_aabbs[i].in_frustum(cull.shadows[j].cascades[k].frustum)) { - InstanceData &idata = scenario->instance_data[i]; - uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; + RendererThreadPool::singleton->thread_work_pool.do_work(frustum_cull_result_threads.size(), this, &RendererSceneCull::_frustum_cull_threaded, &cull_data); - if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && idata.flags & InstanceData::FLAG_CAST_SHADOWS) { - cull.shadows[j].cascades[k].cull_result.push_back(idata.instance); - mesh_visible = true; - } - } - } + for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) { + frustum_cull_result.append_from(frustum_cull_result_threads[i]); } - for (uint32_t j = 0; j < cull.sdfgi.region_count; j++) { - if (scenario->instance_aabbs[i].in_aabb(cull.sdfgi.region_aabb[j])) { - InstanceData &idata = scenario->instance_data[i]; - uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; - - if (base_type == RS::INSTANCE_LIGHT) { - InstanceLightData *instance_light = (InstanceLightData *)idata.instance->base_data; - if (instance_light->bake_mode == RS::LIGHT_BAKE_STATIC && cull.sdfgi.region_cascade[j] <= instance_light->max_sdfgi_cascade) { - if (sdfgi_last_light_index != i || sdfgi_last_light_cascade != cull.sdfgi.region_cascade[j]) { - sdfgi_last_light_index = i; - sdfgi_last_light_cascade = cull.sdfgi.region_cascade[j]; - cull.sdfgi.cascade_lights[sdfgi_last_light_cascade].push_back(instance_light->instance); - } - } - } else if ((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) { - if (idata.flags & InstanceData::FLAG_USES_BAKED_LIGHT) { - cull.sdfgi.region_cull_result[j].push_back(idata.instance); - mesh_visible = true; - } - } - } - } - - if (mesh_visible && scenario->instance_data[i].flags & InstanceData::FLAG_USES_MESH_INSTANCE) { - mesh_instance_cull_result.push_back(scenario->instance_data[i].instance->mesh_instance); - } + } else { + //single threaded + _frustum_cull(cull_data, frustum_cull_result, cull_from, cull_to); } - if (mesh_instance_cull_result.size()) { - for (uint64_t i = 0; i < mesh_instance_cull_result.size(); i++) { - RSG::storage->mesh_instance_check_for_update(mesh_instance_cull_result[i]); +#ifdef DEBUG_CULL_TIME + static float time_avg = 0; + static uint32_t time_count = 0; + time_avg += double(OS::get_singleton()->get_ticks_usec() - time_from) / 1000.0; + time_count++; + print_line("time taken: " + rtos(time_avg / time_count)); +#endif + + if (frustum_cull_result.mesh_instances.size()) { + for (uint64_t i = 0; i < frustum_cull_result.mesh_instances.size(); i++) { + RSG::storage->mesh_instance_check_for_update(frustum_cull_result.mesh_instances[i]); } RSG::storage->update_mesh_instances(); } @@ -2454,7 +2589,7 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca const Cull::Shadow::Cascade &c = cull.shadows[i].cascades[j]; // print_line("shadow " + itos(i) + " cascade " + itos(j) + " elements: " + itos(c.cull_result.size())); scene_render->light_instance_set_shadow_transform(cull.shadows[i].light_instance, c.projection, c.transform, c.zfar, c.split, j, c.shadow_texel_size, c.bias_scale, c.range_begin, c.uv_scale); - scene_render->render_shadow(cull.shadows[i].light_instance, p_shadow_atlas, j, c.cull_result, near_plane, p_cam_projection.get_lod_multiplier(), p_screen_lod_threshold); + scene_render->render_shadow(cull.shadows[i].light_instance, p_shadow_atlas, j, frustum_cull_result.directional_shadows[i].cascade_geometry_instances[j], near_plane, p_cam_projection.get_lod_multiplier(), p_screen_lod_threshold); } } @@ -2464,19 +2599,19 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca if (cull.sdfgi.region_count > 0) { //update regions for (uint32_t i = 0; i < cull.sdfgi.region_count; i++) { - scene_render->render_sdfgi(p_render_buffers, i, cull.sdfgi.region_cull_result[i]); + scene_render->render_sdfgi(p_render_buffers, i, frustum_cull_result.sdfgi_region_geometry_instances[i]); } //check if static lights were culled bool static_lights_culled = false; for (uint32_t i = 0; i < cull.sdfgi.cascade_light_count; i++) { - if (cull.sdfgi.cascade_lights[i].size()) { + if (frustum_cull_result.sdfgi_cascade_lights[i].size()) { static_lights_culled = true; break; } } if (static_lights_culled) { - scene_render->render_sdfgi_static_lights(p_render_buffers, cull.sdfgi.cascade_light_count, cull.sdfgi.cascade_light_index, cull.sdfgi.cascade_lights); + scene_render->render_sdfgi_static_lights(p_render_buffers, cull.sdfgi.cascade_light_count, cull.sdfgi.cascade_light_index, frustum_cull_result.sdfgi_cascade_lights); } } @@ -2505,8 +2640,8 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca //SortArray sorter; //sorter.sort(light_cull_result,light_cull_count); - for (uint32_t i = 0; i < (uint32_t)light_cull_result.size(); i++) { - Instance *ins = light_cull_result[i]; + for (uint32_t i = 0; i < (uint32_t)frustum_cull_result.lights.size(); i++) { + Instance *ins = frustum_cull_result.lights[i]; if (!p_shadow_atlas.is_valid() || !RSG::storage->light_has_shadow(ins->base)) { continue; @@ -2602,7 +2737,7 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca //append the directional lights to the lights culled for (int i = 0; i < directional_lights.size(); i++) { - light_instance_cull_result.push_back(directional_lights[i]); + frustum_cull_result.light_instances.push_back(directional_lights[i]); } } @@ -2639,7 +2774,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, 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); + scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, frustum_cull_result.geometry_instances, frustum_cull_result.light_instances, frustum_cull_result.reflections, frustum_cull_result.gi_probes, frustum_cull_result.decals, frustum_cull_result.lightmaps, 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) { @@ -2654,7 +2789,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, PagedArray(), PagedArray(), PagedArray(), PagedArray(), PagedArray(), PagedArray(), RID(), 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 } @@ -2929,7 +3064,9 @@ void RendererSceneCull::render_probes() { update_lights = true; } - geometry_instances_to_render.clear(); + frustum_cull_result.geometry_instances.clear(); + + RID instance_pair_buffer[MAX_INSTANCE_PAIRS]; for (Set::Element *E = probe->dynamic_geometries.front(); E; E = E->next()) { Instance *ins = E->get(); @@ -2939,24 +3076,25 @@ void RendererSceneCull::render_probes() { InstanceGeometryData *geom = (InstanceGeometryData *)ins->base_data; if (ins->scenario && ins->array_index >= 0 && (ins->scenario->instance_data[ins->array_index].flags & InstanceData::FLAG_GEOM_GI_PROBE_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()); - + uint32_t idx = 0; 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; + instance_pair_buffer[idx++] = gi_probe2->probe_instance; + if (idx == MAX_INSTANCE_PAIRS) { + break; + } } + scene_render->geometry_instance_pair_gi_probe_instances(geom->geometry_instance, instance_pair_buffer, idx); + ins->scenario->instance_data[ins->array_index].flags &= ~uint32_t(InstanceData::FLAG_GEOM_GI_PROBE_DIRTY); } - geometry_instances_to_render.push_back(E->get()); + frustum_cull_result.geometry_instances.push_back(geom->geometry_instance); } - scene_render->gi_probe_update(probe->probe_instance, update_lights, probe->light_instances, geometry_instances_to_render); + scene_render->gi_probe_update(probe->probe_instance, update_lights, probe->light_instances, frustum_cull_result.geometry_instances); gi_probe_update_list.remove(gi_probe); @@ -2971,7 +3109,7 @@ 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 instance_cull_result.clear(); - geometry_instances_to_render.clear(); + frustum_cull_result.geometry_instances.clear(); struct CullAABB { PagedArray *result; @@ -2992,16 +3130,17 @@ void RendererSceneCull::render_particle_colliders() { 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); + InstanceGeometryData *geom = static_cast(instance->base_data); + frustum_cull_result.geometry_instances.push_back(geom->geometry_instance); } - scene_render->render_particle_collider_heightfield(hfpc->base, hfpc->transform, geometry_instances_to_render); + scene_render->render_particle_collider_heightfield(hfpc->base, hfpc->transform, frustum_cull_result.geometry_instances); } heightfield_particle_colliders_update_list.erase(heightfield_particle_colliders_update_list.front()); } } -void RendererSceneCull::_update_instance_shader_parameters_from_material(Map &isparams, const Map &existing_isparams, RID p_material) { +void RendererSceneCull::_update_instance_shader_parameters_from_material(Map &isparams, const Map &existing_isparams, RID p_material) { List plist; RSG::storage->material_get_instance_shader_parameters(p_material, &plist); for (List::Element *E = plist.front(); E; E = E->next()) { @@ -3016,7 +3155,7 @@ void RendererSceneCull::_update_instance_shader_parameters_from_material(Mapget().index; isp.info = E->get().info; isp.default_value = E->get().default_value; @@ -3035,14 +3174,14 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { } if (p_instance->update_dependencies) { - p_instance->instance_increase_version(); + p_instance->dependency_tracker.update_begin(); if (p_instance->base.is_valid()) { - RSG::storage->base_update_dependency(p_instance->base, p_instance); + RSG::storage->base_update_dependency(p_instance->base, &p_instance->dependency_tracker); } if (p_instance->material_override.is_valid()) { - RSG::storage->material_update_dependency(p_instance->material_override, p_instance); + RSG::storage->material_update_dependency(p_instance->material_override, &p_instance->dependency_tracker); } if (p_instance->base_type == RS::INSTANCE_MESH) { @@ -3059,7 +3198,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { bool can_cast_shadows = true; bool is_animated = false; - Map isparams; + Map isparams; if (p_instance->cast_shadows == RS::SHADOW_CASTING_SETTING_OFF) { can_cast_shadows = false; @@ -3094,7 +3233,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); - RSG::storage->material_update_dependency(mat, p_instance); + RSG::storage->material_update_dependency(mat, &p_instance->dependency_tracker); } } @@ -3125,7 +3264,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); - RSG::storage->material_update_dependency(mat, p_instance); + RSG::storage->material_update_dependency(mat, &p_instance->dependency_tracker); } } @@ -3133,7 +3272,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { can_cast_shadows = false; } - RSG::storage->base_update_dependency(mesh, p_instance); + RSG::storage->base_update_dependency(mesh, &p_instance->dependency_tracker); } } else if (p_instance->base_type == RS::INSTANCE_IMMEDIATE) { RID mat = RSG::storage->immediate_get_material(p_instance->base); @@ -3151,7 +3290,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { } if (mat.is_valid()) { - RSG::storage->material_update_dependency(mat, p_instance); + RSG::storage->material_update_dependency(mat, &p_instance->dependency_tracker); } } else if (p_instance->base_type == RS::INSTANCE_PARTICLES) { @@ -3182,7 +3321,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); - RSG::storage->material_update_dependency(mat, p_instance); + RSG::storage->material_update_dependency(mat, &p_instance->dependency_tracker); } } } @@ -3210,7 +3349,9 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { p_instance->instance_allocated_shader_parameters = (p_instance->instance_shader_parameters.size() > 0); if (p_instance->instance_allocated_shader_parameters) { p_instance->instance_allocated_shader_parameters_offset = RSG::storage->global_variables_instance_allocate(p_instance->self); - for (Map::Element *E = p_instance->instance_shader_parameters.front(); E; E = E->next()) { + scene_render->geometry_instance_set_instance_shader_parameters_offset(geom->geometry_instance, p_instance->instance_allocated_shader_parameters_offset); + + for (Map::Element *E = p_instance->instance_shader_parameters.front(); E; E = E->next()) { if (E->get().value.get_type() != Variant::NIL) { RSG::storage->global_variables_instance_update(p_instance->self, E->get().index, E->get().value); } @@ -3218,15 +3359,21 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { } else { RSG::storage->global_variables_instance_free(p_instance->self); p_instance->instance_allocated_shader_parameters_offset = -1; + scene_render->geometry_instance_set_instance_shader_parameters_offset(geom->geometry_instance, -1); } } } if (p_instance->skeleton.is_valid()) { - RSG::storage->skeleton_update_dependency(p_instance->skeleton, p_instance); + RSG::storage->skeleton_update_dependency(p_instance->skeleton, &p_instance->dependency_tracker); } - p_instance->clean_up_dependencies(); + p_instance->dependency_tracker.update_end(); + + if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { + InstanceGeometryData *geom = static_cast(p_instance->base_data); + scene_render->geometry_instance_set_surface_materials(geom->geometry_instance, p_instance->materials); + } } _instance_update_list.remove(&p_instance->update_item); @@ -3322,70 +3469,40 @@ TypedArray RendererSceneCull::bake_render_uv2(RID p_base, const Vectorgeometry_instance_get_pair_mask(); +} + RendererSceneCull::RendererSceneCull() { render_pass = 1; singleton = this; - pair_volumes_to_mesh = false; instance_cull_result.set_page_pool(&instance_cull_page_pool); - mesh_instance_cull_result.set_page_pool(&rid_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); - 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); - lightmap_cull_result.set_page_pool(&base_instance_cull_page_pool); + geometry_instances_to_shadow_render.set_page_pool(&geometry_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); - 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 < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { - for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { - cull.shadows[i].cascades[j].cull_result.set_page_pool(&base_instance_cull_page_pool); - } - } - - for (int i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { - cull.sdfgi.region_cull_result[i].set_page_pool(&base_instance_cull_page_pool); - } - - for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { - cull.sdfgi.cascade_lights[i].set_page_pool(&rid_cull_page_pool); + frustum_cull_result.init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool); + frustum_cull_result_threads.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count()); + for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) { + frustum_cull_result_threads[i].init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool); } indexer_update_iterations = GLOBAL_GET("rendering/spatial_indexer/update_iterations_per_frame"); + thread_cull_threshold = GLOBAL_GET("rendering/spatial_indexer/threaded_cull_minimum_instances"); + thread_cull_threshold = MAX(thread_cull_threshold, (uint32_t)RendererThreadPool::singleton->thread_work_pool.get_thread_count()); //make sure there is at least one thread per CPU } RendererSceneCull::~RendererSceneCull() { instance_cull_result.reset(); - mesh_instance_cull_result.reset(); instance_shadow_cull_result.reset(); - instance_sdfgi_cull_result.reset(); - light_cull_result.reset(); - geometry_instances_to_render.reset(); geometry_instances_to_shadow_render.reset(); - lightmap_cull_result.reset(); - reflection_probe_instance_cull_result.reset(); - light_instance_cull_result.reset(); - gi_probe_instance_cull_result.reset(); - decal_instance_cull_result.reset(); - - for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { - for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { - cull.shadows[i].cascades[j].cull_result.reset(); - } - } - - for (int i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { - cull.sdfgi.region_cull_result[i].reset(); - } - - for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { - cull.sdfgi.cascade_lights[i].reset(); + frustum_cull_result.reset(); + for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) { + frustum_cull_result_threads[i].reset(); } + frustum_cull_result_threads.clear(); } diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 85b4c53c599..796fb147437 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -53,7 +53,8 @@ public: enum { SDFGI_MAX_CASCADES = 8, - SDFGI_MAX_REGIONS_PER_CASCADE = 3 + SDFGI_MAX_REGIONS_PER_CASCADE = 3, + MAX_INSTANCE_PAIRS = 32 }; uint64_t render_pass; @@ -249,7 +250,10 @@ public: uint32_t flags = 0; uint32_t layer_mask = 0; //for fast layer-mask discard RID base_rid; - RID instance_data_rid; + union { + uint64_t instance_data_rid; + RendererSceneRender::GeometryInstance *instance_geometry; + }; Instance *instance = nullptr; }; @@ -296,7 +300,7 @@ public: 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); + void _instance_update_mesh_instance(Instance *p_instance); virtual RID scenario_create(); @@ -325,7 +329,55 @@ public: virtual ~InstanceBaseData() {} }; - struct Instance : RendererSceneRender::InstanceBase { + struct Instance { + RS::InstanceType base_type; + RID base; + + RID skeleton; + RID material_override; + + RID mesh_instance; //only used for meshes and when skeleton/blendshapes exist + + Transform transform; + + float lod_bias; + + Vector materials; + + RS::ShadowCastingSetting cast_shadows; + + uint32_t layer_mask; + //fit in 32 bits + bool mirror : 8; + bool receive_shadows : 8; + bool visible : 8; + bool baked_light : 2; //this flag is only to know if it actually did use baked light + bool dynamic_gi : 2; //same above for dynamic objects + bool redraw_if_visible : 4; + + Instance *lightmap; + Rect2 lightmap_uv_scale; + int lightmap_slice_index; + uint32_t lightmap_cull_index; + Vector lightmap_sh; //spherical harmonic + + AABB aabb; + AABB transformed_aabb; + AABB prev_transformed_aabb; + + struct InstanceShaderParameter { + int32_t index = -1; + Variant value; + Variant default_value; + PropertyInfo info; + }; + + Map instance_shader_parameters; + bool instance_allocated_shader_parameters = false; + int32_t instance_allocated_shader_parameters_offset = -1; + + // + RID self; //scenario stuff DynamicBVH::ID indexer_id; @@ -360,23 +412,61 @@ public: SelfList::List pairs; uint64_t pair_check; - virtual void dependency_deleted(RID p_dependency) { - if (p_dependency == base) { - singleton->instance_set_base(self, RID()); - } else if (p_dependency == skeleton) { - singleton->instance_attach_skeleton(self, RID()); - } else { - singleton->_instance_queue_update(this, false, true); + RendererStorage::DependencyTracker dependency_tracker; + + static void dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *tracker) { + Instance *instance = (Instance *)tracker->userdata; + switch (p_notification) { + case RendererStorage::DEPENDENCY_CHANGED_SKELETON_DATA: + case RendererStorage::DEPENDENCY_CHANGED_AABB: { + singleton->_instance_queue_update(instance, true, false); + + } break; + case RendererStorage::DEPENDENCY_CHANGED_MATERIAL: { + singleton->_instance_queue_update(instance, false, true); + } break; + case RendererStorage::DEPENDENCY_CHANGED_MESH: + case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH: + case RendererStorage::DEPENDENCY_CHANGED_DECAL: + case RendererStorage::DEPENDENCY_CHANGED_LIGHT: + case RendererStorage::DEPENDENCY_CHANGED_REFLECTION_PROBE: { + singleton->_instance_queue_update(instance, true, true); + } break; + case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: + case RendererStorage::DEPENDENCY_CHANGED_SKELETON_BONES: { + //ignored + } break; } } - virtual void dependency_changed(bool p_aabb, bool p_dependencies) { - singleton->_instance_queue_update(this, p_aabb, p_dependencies); + static void dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *tracker) { + Instance *instance = (Instance *)tracker->userdata; + + if (p_dependency == instance->base) { + singleton->instance_set_base(instance->self, RID()); + } else if (p_dependency == instance->skeleton) { + singleton->instance_attach_skeleton(instance->self, RID()); + } else { + singleton->_instance_queue_update(instance, false, true); + } } Instance() : scenario_item(this), update_item(this) { + base_type = RS::INSTANCE_NONE; + cast_shadows = RS::SHADOW_CASTING_SETTING_ON; + receive_shadows = true; + visible = true; + layer_mask = 1; + baked_light = false; + dynamic_gi = false; + redraw_if_visible = false; + lightmap_slice_index = 0; + lightmap = nullptr; + lightmap_cull_index = 0; + lod_bias = 1.0; + scenario = nullptr; update_aabb = false; @@ -399,6 +489,10 @@ public: pair_check = 0; array_index = -1; + + dependency_tracker.userdata = this; + dependency_tracker.changed_callback = dependency_changed; + dependency_tracker.deleted_callback = dependency_deleted; } ~Instance() { @@ -415,6 +509,7 @@ public: void _instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies = false); struct InstanceGeometryData : public InstanceBaseData { + RendererSceneRender::GeometryInstance *geometry_instance = nullptr; Set lights; bool can_cast_shadows; bool material_is_animated; @@ -458,6 +553,10 @@ public: SelfList::List reflection_probe_render_list; + struct InstanceParticlesCollisionData : public InstanceBaseData { + RID instance; + }; + struct InstanceLightData : public InstanceBaseData { RID instance; uint64_t last_version; @@ -523,6 +622,7 @@ public: SelfList::List gi_probe_update_list; struct InstanceLightmapData : public InstanceBaseData { + RID instance; Set geometries; Set users; @@ -588,38 +688,138 @@ public: } }; - 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; PagedArrayPool instance_cull_page_pool; - PagedArrayPool base_instance_cull_page_pool; + PagedArrayPool geometry_instance_cull_page_pool; PagedArrayPool rid_cull_page_pool; PagedArray instance_cull_result; - PagedArray mesh_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 light_cull_result; - PagedArray lightmap_cull_result; - PagedArray reflection_probe_instance_cull_result; - PagedArray light_instance_cull_result; + PagedArray geometry_instances_to_shadow_render; - PagedArray gi_probe_instance_cull_result; - PagedArray decal_instance_cull_result; + struct FrustumCullResult { + PagedArray geometry_instances; + PagedArray lights; + PagedArray light_instances; + PagedArray lightmaps; + PagedArray reflections; + PagedArray decals; + PagedArray gi_probes; + PagedArray mesh_instances; + + struct DirectionalShadow { + PagedArray cascade_geometry_instances[RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES]; + } directional_shadows[RendererSceneRender::MAX_DIRECTIONAL_LIGHTS]; + + PagedArray sdfgi_region_geometry_instances[SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE]; + PagedArray sdfgi_cascade_lights[SDFGI_MAX_CASCADES]; + + void clear() { + geometry_instances.clear(); + lights.clear(); + light_instances.clear(); + lightmaps.clear(); + reflections.clear(); + decals.clear(); + gi_probes.clear(); + mesh_instances.clear(); + for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { + for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { + directional_shadows[i].cascade_geometry_instances[j].clear(); + } + } + + for (int i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { + sdfgi_region_geometry_instances[i].clear(); + } + + for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { + sdfgi_cascade_lights[i].clear(); + } + } + + void reset() { + geometry_instances.reset(); + lights.reset(); + light_instances.reset(); + lightmaps.reset(); + reflections.reset(); + decals.reset(); + gi_probes.reset(); + mesh_instances.reset(); + for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { + for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { + directional_shadows[i].cascade_geometry_instances[j].reset(); + } + } + + for (int i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { + sdfgi_region_geometry_instances[i].reset(); + } + + for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { + sdfgi_cascade_lights[i].reset(); + } + } + + void append_from(FrustumCullResult &p_cull_result) { + geometry_instances.merge_unordered(p_cull_result.geometry_instances); + lights.merge_unordered(p_cull_result.lights); + light_instances.merge_unordered(p_cull_result.light_instances); + lightmaps.merge_unordered(p_cull_result.lightmaps); + reflections.merge_unordered(p_cull_result.reflections); + decals.merge_unordered(p_cull_result.decals); + gi_probes.merge_unordered(p_cull_result.gi_probes); + mesh_instances.merge_unordered(p_cull_result.mesh_instances); + + for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { + for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { + directional_shadows[i].cascade_geometry_instances[j].merge_unordered(p_cull_result.directional_shadows[i].cascade_geometry_instances[j]); + } + } + + for (int i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { + sdfgi_region_geometry_instances[i].merge_unordered(p_cull_result.sdfgi_region_geometry_instances[i]); + } + + for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { + sdfgi_cascade_lights[i].merge_unordered(p_cull_result.sdfgi_cascade_lights[i]); + } + } + + void init(PagedArrayPool *p_rid_pool, PagedArrayPool *p_geometry_instance_pool, PagedArrayPool *p_instance_pool) { + geometry_instances.set_page_pool(p_geometry_instance_pool); + light_instances.set_page_pool(p_rid_pool); + lights.set_page_pool(p_instance_pool); + lightmaps.set_page_pool(p_rid_pool); + reflections.set_page_pool(p_rid_pool); + decals.set_page_pool(p_rid_pool); + mesh_instances.set_page_pool(p_rid_pool); + for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { + for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { + directional_shadows[i].cascade_geometry_instances[j].set_page_pool(p_geometry_instance_pool); + } + } + + for (int i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { + sdfgi_region_geometry_instances[i].set_page_pool(p_geometry_instance_pool); + } + + for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { + sdfgi_cascade_lights[i].set_page_pool(p_rid_pool); + } + } + }; + + FrustumCullResult frustum_cull_result; + LocalVector frustum_cull_result_threads; + + uint32_t thread_cull_threshold = 200; RID_PtrOwner instance_owner; - bool pair_volumes_to_mesh; // used in traditional forward, unnecesary on clustered + uint32_t geometry_instance_pair_mask; // used in traditional forward, unnecesary on clustered virtual RID instance_create(); @@ -653,7 +853,7 @@ public: virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index); virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias); - void _update_instance_shader_parameters_from_material(Map &isparams, const Map &existing_isparams, RID p_material); + void _update_instance_shader_parameters_from_material(Map &isparams, const Map &existing_isparams, RID p_material); virtual void instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value); virtual void instance_geometry_get_shader_parameter_list(RID p_instance, List *p_parameters) const; @@ -687,8 +887,6 @@ public: real_t range_begin; Vector2 uv_scale; - PagedArray cull_result; - } cascades[RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES]; //max 4 cascades uint32_t cascade_count; @@ -698,12 +896,10 @@ public: struct SDFGI { //have arrays here because SDFGI functions expects this, plus regions can have areas - PagedArray region_cull_result[SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE]; AABB region_aabb[SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE]; //max 3 regions per cascade uint32_t region_cascade[SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE]; //max 3 regions per cascade uint32_t region_count = 0; - PagedArray cascade_lights[SDFGI_MAX_CASCADES]; uint32_t cascade_light_index[SDFGI_MAX_CASCADES]; uint32_t cascade_light_count = 0; @@ -714,6 +910,18 @@ public: Frustum frustum; } cull; + struct FrustumCullData { + Cull *cull; + Scenario *scenario; + RID shadow_atlas; + Transform cam_transform; + uint32_t visible_layers; + Instance *render_reflection_probe; + }; + + void _frustum_cull_threaded(uint32_t p_thread, FrustumCullData *cull_data); + void _frustum_cull(FrustumCullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to); + bool _render_reflection_probe_step(Instance *p_instance, int p_step); void _prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, float p_screen_lod_threshold, bool p_using_shadows = true); void _render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_environment, RID p_force_camera_effects, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold); @@ -828,6 +1036,8 @@ public: bool free(RID p_rid); + void set_scene_render(RendererSceneRender *p_scene_render); + RendererSceneCull(); virtual ~RendererSceneCull(); }; diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h index 805d3dcfce2..85353c400d8 100644 --- a/servers/rendering/renderer_scene_render.h +++ b/servers/rendering/renderer_scene_render.h @@ -41,6 +41,34 @@ public: MAX_DIRECTIONAL_LIGHTS = 8, MAX_DIRECTIONAL_LIGHT_CASCADES = 4 }; + + struct GeometryInstance { + virtual ~GeometryInstance() {} + }; + + virtual GeometryInstance *geometry_instance_create(RID p_base) = 0; + virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) = 0; + virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) = 0; + virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector &p_material) = 0; + virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) = 0; + virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) = 0; + virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) = 0; + virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) = 0; + virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) = 0; + virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) = 0; + virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) = 0; + virtual void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) = 0; + virtual void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) = 0; + virtual void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) = 0; + + virtual uint32_t geometry_instance_get_pair_mask() = 0; + virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) = 0; + virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) = 0; + virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) = 0; + virtual void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) = 0; + + virtual void geometry_instance_free(GeometryInstance *p_geometry_instance) = 0; + /* SHADOW ATLAS API */ virtual RID @@ -55,8 +83,6 @@ public: /* SDFGI UPDATE */ - struct InstanceBase; - virtual void sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) = 0; 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; @@ -134,83 +160,6 @@ public: virtual void shadows_quality_set(RS::ShadowQuality p_quality) = 0; virtual void directional_shadow_quality_set(RS::ShadowQuality p_quality) = 0; - struct InstanceBase : public RendererStorage::InstanceBaseDependency { - RS::InstanceType base_type; - RID base; - - RID skeleton; - RID material_override; - - RID mesh_instance; //only used for meshes and when skeleton/blendshapes exist - - Transform transform; - - float lod_bias; - - int depth_layer; - uint32_t layer_mask; - - //RID sampled_light; - - Vector materials; - Vector light_instances; - Vector reflection_probe_instances; - Vector gi_probe_instances; - - RS::ShadowCastingSetting cast_shadows; - - //fit in 32 bits - bool mirror : 8; - bool receive_shadows : 8; - bool visible : 8; - bool baked_light : 2; //this flag is only to know if it actually did use baked light - bool dynamic_gi : 2; //this flag is only to know if it actually did use baked light - bool redraw_if_visible : 4; - - float depth; //used for sorting - - InstanceBase *lightmap; - Rect2 lightmap_uv_scale; - int lightmap_slice_index; - uint32_t lightmap_cull_index; - Vector lightmap_sh; //spherical harmonic - - AABB aabb; - AABB transformed_aabb; - AABB prev_transformed_aabb; - - struct InstanceShaderParameter { - int32_t index = -1; - Variant value; - Variant default_value; - PropertyInfo info; - }; - - Map instance_shader_parameters; - bool instance_allocated_shader_parameters = false; - int32_t instance_allocated_shader_parameters_offset = -1; - - InstanceBase() { - base_type = RS::INSTANCE_NONE; - cast_shadows = RS::SHADOW_CASTING_SETTING_ON; - receive_shadows = true; - visible = true; - depth_layer = 0; - layer_mask = 1; - instance_version = 0; - baked_light = false; - dynamic_gi = false; - redraw_if_visible = false; - lightmap_slice_index = 0; - lightmap = nullptr; - lightmap_cull_index = 0; - lod_bias = 1.0; - } - - virtual ~InstanceBase() { - } - }; - virtual RID light_instance_create(RID p_light) = 0; virtual void light_instance_set_transform(RID p_light_instance, const Transform &p_transform) = 0; virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) = 0; @@ -235,20 +184,23 @@ public: virtual RID decal_instance_create(RID p_decal) = 0; virtual void decal_instance_set_transform(RID p_decal, const Transform &p_transform) = 0; + virtual RID lightmap_instance_create(RID p_lightmap) = 0; + virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform) = 0; + 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, const PagedArray &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, 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_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, 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_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 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/renderer_storage.cpp b/servers/rendering/renderer_storage.cpp index 2edf62df565..a402ecc6684 100644 --- a/servers/rendering/renderer_storage.cpp +++ b/servers/rendering/renderer_storage.cpp @@ -32,28 +32,31 @@ RendererStorage *RendererStorage::base_singleton = nullptr; -void RendererStorage::InstanceDependency::instance_notify_changed(bool p_aabb, bool p_dependencies) { - for (Map::Element *E = instances.front(); E; E = E->next()) { - E->key()->dependency_changed(p_aabb, p_dependencies); +void RendererStorage::Dependency::changed_notify(DependencyChangedNotification p_notification) { + for (Map::Element *E = instances.front(); E; E = E->next()) { + if (E->key()->changed_callback) { + E->key()->changed_callback(p_notification, E->key()); + } } } -void RendererStorage::InstanceDependency::instance_notify_deleted(RID p_deleted) { - for (Map::Element *E = instances.front(); E; E = E->next()) { - E->key()->dependency_deleted(p_deleted); +void RendererStorage::Dependency::deleted_notify(const RID &p_rid) { + for (Map::Element *E = instances.front(); E; E = E->next()) { + if (E->key()->deleted_callback) { + E->key()->deleted_callback(p_rid, E->key()); + } } - for (Map::Element *E = instances.front(); E; E = E->next()) { + for (Map::Element *E = instances.front(); E; E = E->next()) { E->key()->dependencies.erase(this); } - instances.clear(); } -RendererStorage::InstanceDependency::~InstanceDependency() { +RendererStorage::Dependency::~Dependency() { #ifdef DEBUG_ENABLED if (instances.size()) { WARN_PRINT("Leaked instance dependency: Bug - did not call instance_notify_deleted when freeing."); - for (Map::Element *E = instances.front(); E; E = E->next()) { + for (Map::Element *E = instances.front(); E; E = E->next()) { E->key()->dependencies.erase(this); } } diff --git a/servers/rendering/renderer_storage.h b/servers/rendering/renderer_storage.h index 835bf328630..3e53f7130a0 100644 --- a/servers/rendering/renderer_storage.h +++ b/servers/rendering/renderer_storage.h @@ -37,43 +37,59 @@ class RendererStorage { Color default_clear_color; public: - struct InstanceBaseDependency; - - struct InstanceDependency { - void instance_notify_changed(bool p_aabb, bool p_dependencies); - void instance_notify_deleted(RID p_deleted); - - ~InstanceDependency(); - - private: - friend struct InstanceBaseDependency; - Map instances; + enum DependencyChangedNotification { + DEPENDENCY_CHANGED_AABB, + DEPENDENCY_CHANGED_MATERIAL, + DEPENDENCY_CHANGED_MESH, + DEPENDENCY_CHANGED_MULTIMESH, + DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES, + DEPENDENCY_CHANGED_DECAL, + DEPENDENCY_CHANGED_SKELETON_DATA, + DEPENDENCY_CHANGED_SKELETON_BONES, + DEPENDENCY_CHANGED_LIGHT, + DEPENDENCY_CHANGED_REFLECTION_PROBE, }; - struct InstanceBaseDependency { - uint32_t instance_version; - Set dependencies; + struct DependencyTracker; - virtual void dependency_deleted(RID p_dependency) {} - virtual void dependency_changed(bool p_aabb, bool p_dependencies) {} +protected: + struct Dependency { + void changed_notify(DependencyChangedNotification p_notification); + void deleted_notify(const RID &p_rid); - void instance_increase_version() { + ~Dependency(); + + private: + friend struct DependencyTracker; + Map instances; + }; + +public: + struct DependencyTracker { + void *userdata = nullptr; + typedef void (*ChangedCallback)(DependencyChangedNotification, DependencyTracker *); + typedef void (*DeletedCallback)(const RID &, DependencyTracker *); + + ChangedCallback changed_callback = nullptr; + DeletedCallback deleted_callback = nullptr; + + void update_begin() { // call before updating dependencies instance_version++; } - void update_dependency(InstanceDependency *p_dependency) { + void update_dependency(Dependency *p_dependency) { //called internally, can't be used directly, use update functions in Storage dependencies.insert(p_dependency); p_dependency->instances[this] = instance_version; } - void clean_up_dependencies() { - List::Element *>> to_clean_up; - for (Set::Element *E = dependencies.front(); E; E = E->next()) { - InstanceDependency *dep = E->get(); - Map::Element *F = dep->instances.find(this); + void update_end() { //call after updating dependencies + List::Element *>> to_clean_up; + for (Set::Element *E = dependencies.front(); E; E = E->next()) { + Dependency *dep = E->get(); + Map::Element *F = dep->instances.find(this); ERR_CONTINUE(!F); if (F->get() != instance_version) { - Pair::Element *> p; + Pair::Element *> p; p.first = dep; p.second = F; to_clean_up.push_back(p); @@ -86,15 +102,20 @@ public: } } - void clear_dependencies() { - for (Set::Element *E = dependencies.front(); E; E = E->next()) { - InstanceDependency *dep = E->get(); + void clear() { // clear all dependencies + for (Set::Element *E = dependencies.front(); E; E = E->next()) { + Dependency *dep = E->get(); dep->instances.erase(this); } dependencies.clear(); } - virtual ~InstanceBaseDependency() { clear_dependencies(); } + ~DependencyTracker() { clear(); } + + private: + friend struct Dependency; + uint32_t instance_version = 0; + Set dependencies; }; /* TEXTURE API */ @@ -181,7 +202,7 @@ public: virtual void material_get_instance_shader_parameters(RID p_material, List *r_parameters) = 0; - virtual void material_update_dependency(RID p_material, InstanceBaseDependency *p_instance) = 0; + virtual void material_update_dependency(RID p_material, DependencyTracker *p_instance) = 0; /* MESH API */ @@ -349,8 +370,8 @@ public: virtual bool reflection_probe_renders_shadows(RID p_probe) const = 0; virtual float reflection_probe_get_lod_threshold(RID p_probe) const = 0; - virtual void base_update_dependency(RID p_base, InstanceBaseDependency *p_instance) = 0; - virtual void skeleton_update_dependency(RID p_base, InstanceBaseDependency *p_instance) = 0; + virtual void base_update_dependency(RID p_base, DependencyTracker *p_instance) = 0; + virtual void skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) = 0; /* DECAL API */ @@ -474,8 +495,8 @@ public: virtual void particles_set_view_axis(RID p_particles, const Vector3 &p_axis) = 0; - virtual void particles_add_collision(RID p_particles, InstanceBaseDependency *p_instance) = 0; - virtual void particles_remove_collision(RID p_particles, InstanceBaseDependency *p_instance) = 0; + virtual void particles_add_collision(RID p_particles, RID p_particles_collision_instance) = 0; + virtual void particles_remove_collision(RID p_particles, RID p_particles_collision_instance) = 0; virtual void update_particles() = 0; @@ -496,6 +517,11 @@ public: virtual bool particles_collision_is_heightfield(RID p_particles_collision) const = 0; virtual RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const = 0; + //used from 2D and 3D + virtual RID particles_collision_instance_create(RID p_collision) = 0; + virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform) = 0; + virtual void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) = 0; + /* GLOBAL VARIABLES */ virtual void global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value) = 0; diff --git a/servers/rendering/renderer_thread_pool.cpp b/servers/rendering/renderer_thread_pool.cpp new file mode 100644 index 00000000000..98050dd5080 --- /dev/null +++ b/servers/rendering/renderer_thread_pool.cpp @@ -0,0 +1,42 @@ +/*************************************************************************/ +/* renderer_thread_pool.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "renderer_thread_pool.h" + +RendererThreadPool *RendererThreadPool::singleton = nullptr; + +RendererThreadPool::RendererThreadPool() { + singleton = this; + thread_work_pool.init(); +} + +RendererThreadPool::~RendererThreadPool() { + thread_work_pool.finish(); +} diff --git a/servers/rendering/renderer_thread_pool.h b/servers/rendering/renderer_thread_pool.h new file mode 100644 index 00000000000..ae25415a0dd --- /dev/null +++ b/servers/rendering/renderer_thread_pool.h @@ -0,0 +1,45 @@ +/*************************************************************************/ +/* renderer_thread_pool.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 RENDERERTHREADPOOL_H +#define RENDERERTHREADPOOL_H + +#include "core/templates/thread_work_pool.h" + +class RendererThreadPool { +public: + ThreadWorkPool thread_work_pool; + + static RendererThreadPool *singleton; + RendererThreadPool(); + ~RendererThreadPool(); +}; + +#endif // RENDERERTHREADPOOL_H diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp index fb5db8de601..8c6e97a0afb 100644 --- a/servers/rendering/rendering_server_default.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -267,7 +267,7 @@ RenderingServerDefault::RenderingServerDefault() { RSG::rasterizer = RendererCompositor::create(); RSG::storage = RSG::rasterizer->get_storage(); RSG::canvas_render = RSG::rasterizer->get_canvas(); - sr->scene_render = RSG::rasterizer->get_scene(); + sr->set_scene_render(RSG::rasterizer->get_scene()); frame_profile_frame = 0; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 758a9a34cd3..b87171dc5ec 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2253,6 +2253,8 @@ void RenderingServer::set_render_loop_enabled(bool p_enabled) { RenderingServer::RenderingServer() { //ERR_FAIL_COND(singleton); + + thread_pool = memnew(RendererThreadPool); singleton = this; GLOBAL_DEF_RST("rendering/vram_compression/import_bptc", false); @@ -2383,8 +2385,13 @@ RenderingServer::RenderingServer() { 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")); + GLOBAL_DEF("rendering/spatial_indexer/threaded_cull_minimum_instances", 1000); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/spatial_indexer/threaded_cull_minimum_instances", PropertyInfo(Variant::INT, "rendering/spatial_indexer/threaded_cull_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1")); + GLOBAL_DEF("rendering/forward_renderer/threaded_render_minimum_instances", 500); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/forward_renderer/threaded_render_minimum_instances", PropertyInfo(Variant::INT, "rendering/forward_renderer/threaded_render_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1")); } RenderingServer::~RenderingServer() { + memdelete(thread_pool); singleton = nullptr; } diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 7db2924612d..5481079694c 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -39,6 +39,7 @@ #include "core/variant/typed_array.h" #include "core/variant/variant.h" #include "servers/display_server.h" +#include "servers/rendering/renderer_thread_pool.h" #include "servers/rendering/rendering_device.h" #include "servers/rendering/shader_language.h" @@ -52,6 +53,8 @@ class RenderingServer : public Object { Array _get_array_from_surface(uint32_t p_format, Vector p_vertex_data, Vector p_attrib_data, Vector p_skin_data, int p_vertex_len, Vector p_index_data, int p_index_len) const; + RendererThreadPool *thread_pool = nullptr; + protected: RID _make_test_cube(); void _free_internal_rids();