From 5d2a1d78929764b66a0d6ac7d6cc866ea1c91aed Mon Sep 17 00:00:00 2001 From: reduz Date: Mon, 4 Jan 2021 09:33:25 -0300 Subject: [PATCH] Rewrite render code to be more cache and thread friendly. --- core/templates/rid.h | 2 + .../renderer_scene_render_forward.cpp | 1197 +++++++++-------- .../renderer_scene_render_forward.h | 428 +++--- .../renderer_rd/renderer_scene_render_rd.h | 4 + .../renderer_rd/renderer_storage_rd.cpp | 136 +- .../renderer_rd/renderer_storage_rd.h | 38 +- .../renderer_rd/shaders/scene_forward.glsl | 76 +- .../shaders/scene_forward_inc.glsl | 25 +- servers/rendering/renderer_scene_cull.cpp | 24 +- servers/rendering/renderer_scene_cull.h | 50 +- servers/rendering/renderer_storage.cpp | 23 +- servers/rendering/renderer_storage.h | 83 +- 12 files changed, 1167 insertions(+), 919 deletions(-) diff --git a/core/templates/rid.h b/core/templates/rid.h index b9829bd533..4c7119b4ea 100644 --- a/core/templates/rid.h +++ b/core/templates/rid.h @@ -61,6 +61,8 @@ public: _ALWAYS_INLINE_ bool is_valid() const { return _id != 0; } _ALWAYS_INLINE_ bool is_null() const { return _id == 0; } + _ALWAYS_INLINE_ uint32_t get_local_index() const { return _id & 0xFFFFFFFF; } + static _ALWAYS_INLINE_ RID from_uint64(uint64_t p_id) { RID _rid; _rid._id = p_id; diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp b/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp index 6c54fc6953..b32fff6f01 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_forward.cpp @@ -806,160 +806,10 @@ 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->shader_parameters_offset >= 0 ? e->instance->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_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] == e->instance->lightmap_instance) { - lightmap_cull_index = j; - break; - } - } - if (lightmap_cull_index >= 0) { - id.gi_offset = 0; - id.gi_offset |= e->instance->lightmap_slice_index << 12; - id.gi_offset |= 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 (scene_state.lightmap_has_sh[lightmap_cull_index]) { - id.flags |= INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP; - } - } else { - id.gi_offset = 0xFFFFFFFF; - } - } else if (e->instance->lightmap_sh) { - if (lightmap_captures_used < scene_state.max_lightmap_captures) { - const Color *src_capture = e->instance->lightmap_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; - } - 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_instance_count > 0) { - uint32_t written = 0; - for (uint32_t j = 0; j < e->instance->gi_probe_instance_count; 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->use_baked_light || e->instance->use_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, GeometryInstanceSurfaceDataCache **p_elements, int p_element_count, bool p_reverse_cull, 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) { RD::DrawListID draw_list = p_draw_list; RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format; @@ -968,96 +818,77 @@ void RendererSceneRenderForward::_render_list(RenderingDevice::DrawListID p_draw 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, 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_pass_mode == PASS_MODE_SHADOW) || (p_pass_mode == PASS_MODE_SHADOW_DP); + + float old_offset[2]; for (int i = 0; i < p_element_count; i++) { - const RenderList::Element *e = p_elements[i]; + const GeometryInstanceSurfaceDataCache *surf = p_elements[i]; - MaterialData *material = e->material; - ShaderData *shader = material->shader_data; - RID xforms_uniform_set; + 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_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_uv_offset.x; + surf->owner->push_constant.lightmap_uv_scale[1] = p_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_double_sided_shaodows)) { + 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) && surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS)) { cull_variant = ShaderData::CULL_VARIANT_DOUBLE_SIDED; } else { - bool mirror = e->instance->mirror; + bool mirror = surf->owner->mirror; if (p_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) { 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; @@ -1092,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_screen_lod_threshold > 0.0 && storage->mesh_surface_has_lod(mesh_surface)) { + //lod + Vector3 support_min = surf->owner->transformed_aabb.get_support(-p_lod_plane.normal); + Vector3 support_max = surf->owner->transformed_aabb.get_support(p_lod_plane.normal); + + 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; } - 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_lod_distance_multiplier, p_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) { @@ -1154,39 +982,62 @@ 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_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, 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, const Vector2 &p_uv_offset, const Plane &p_lod_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold) { + //use template for faster performance (pass mode comparisons are inlined) + switch (p_pass_mode) { + case PASS_MODE_COLOR: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_elements, p_element_count, p_reverse_cull, p_no_gi, p_render_pass_uniform_set, p_force_wireframe, p_uv_offset, p_lod_plane, p_lod_distance_multiplier, p_screen_lod_threshold); + } break; + case PASS_MODE_COLOR_SPECULAR: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_elements, p_element_count, p_reverse_cull, p_no_gi, p_render_pass_uniform_set, p_force_wireframe, p_uv_offset, p_lod_plane, p_lod_distance_multiplier, p_screen_lod_threshold); + } break; + case PASS_MODE_COLOR_TRANSPARENT: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_elements, p_element_count, p_reverse_cull, p_no_gi, p_render_pass_uniform_set, p_force_wireframe, p_uv_offset, p_lod_plane, p_lod_distance_multiplier, p_screen_lod_threshold); + } break; + case PASS_MODE_SHADOW: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_elements, p_element_count, p_reverse_cull, p_no_gi, p_render_pass_uniform_set, p_force_wireframe, p_uv_offset, p_lod_plane, p_lod_distance_multiplier, p_screen_lod_threshold); + } break; + case PASS_MODE_SHADOW_DP: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_elements, p_element_count, p_reverse_cull, p_no_gi, p_render_pass_uniform_set, p_force_wireframe, p_uv_offset, p_lod_plane, p_lod_distance_multiplier, p_screen_lod_threshold); + } break; + case PASS_MODE_DEPTH: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_elements, p_element_count, p_reverse_cull, p_no_gi, p_render_pass_uniform_set, p_force_wireframe, p_uv_offset, p_lod_plane, p_lod_distance_multiplier, p_screen_lod_threshold); + } break; + case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_elements, p_element_count, p_reverse_cull, p_no_gi, p_render_pass_uniform_set, p_force_wireframe, p_uv_offset, p_lod_plane, p_lod_distance_multiplier, p_screen_lod_threshold); + } break; + case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_elements, p_element_count, p_reverse_cull, p_no_gi, p_render_pass_uniform_set, p_force_wireframe, p_uv_offset, p_lod_plane, p_lod_distance_multiplier, p_screen_lod_threshold); + } break; + case PASS_MODE_DEPTH_MATERIAL: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_elements, p_element_count, p_reverse_cull, p_no_gi, p_render_pass_uniform_set, p_force_wireframe, p_uv_offset, p_lod_plane, p_lod_distance_multiplier, p_screen_lod_threshold); + } break; + case PASS_MODE_SDF: { + _render_list_template(p_draw_list, p_framebuffer_Format, p_elements, p_element_count, p_reverse_cull, p_no_gi, p_render_pass_uniform_set, p_force_wireframe, p_uv_offset, p_lod_plane, p_lod_distance_multiplier, p_screen_lod_threshold); + } break; + } +} + 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 @@ -1419,128 +1270,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(GeometryInstanceForward *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(GeometryInstanceForward *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) { - //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_instance.is_valid() || e->instance->lightmap_sh != nullptr; - e->uses_forward_gi = has_alpha && (e->instance->gi_probe_instance_count > 0 || 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; @@ -1549,102 +1279,158 @@ 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->surface_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_giprobes(const PagedArray &p_giprobes) { + scene_state.giprobes_used = MIN(p_giprobes.size(), MAX_GI_PROBES); + for (uint32_t i = 0; i < scene_state.giprobes_used; i++) { + scene_state.giprobe_ids[i] = p_giprobes[i]; } } @@ -1793,12 +1579,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; @@ -1882,8 +1668,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; @@ -1894,7 +1678,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf if (depth_pre_pass) { //depth pre pass RENDER_TIMESTAMP("Render Depth Pre-Pass"); - _setup_render_pass_uniform_set(RID(), RID(), RID(), RID(), PagedArray(), 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); @@ -1926,7 +1710,7 @@ void RendererSceneRenderForward::_render_scene(RID p_render_buffer, const Transf RENDER_TIMESTAMP("Render Opaque Pass"); - _setup_render_pass_uniform_set(p_render_buffer, radiance_texture, p_shadow_atlas, p_reflection_atlas, p_gi_probes, p_lightmaps); + 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; @@ -2032,8 +1816,6 @@ 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); @@ -2060,8 +1842,6 @@ 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); @@ -2072,8 +1852,6 @@ void RendererSceneRenderForward::_render_shadow(RID p_framebuffer, const PagedAr 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); @@ -2093,8 +1871,6 @@ 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); @@ -2105,8 +1881,6 @@ void RendererSceneRenderForward::_render_particle_collider_heightfield(RID p_fb, 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); @@ -2127,8 +1901,6 @@ 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); @@ -2138,8 +1910,6 @@ void RendererSceneRenderForward::_render_material(const Transform &p_cam_transfo render_list.sort_by_key(false); - _fill_instances(render_list.elements, render_list.element_count, true); - { //regular forward for now Vector clear; @@ -2166,8 +1936,6 @@ void RendererSceneRenderForward::_render_uv2(const PagedArray clear; @@ -2224,12 +1990,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); @@ -2349,13 +2113,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; @@ -2799,44 +2556,417 @@ 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->base = p_base; - ginstance->base_type = type; + 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->skeleton = p_skeleton; + 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->material_override = p_override; + 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->surface_materials = p_materials; + 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); - ginstance->transform = p_transform; + RendererStorageRD::store_transform(p_transform, ginstance->push_constant.transform); + ginstance->data->transform = p_transform; ginstance->mirror = p_transform.basis.determinant() < 0; - ginstance->aabb = p_aabb; + 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); @@ -2846,60 +2976,74 @@ void RendererSceneRenderForward::geometry_instance_set_lod_bias(GeometryInstance 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->use_baked_light = p_enable; + 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->use_dynamic_gi = p_enable; + 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->lightmap_uv_scale = p_lightmap_uv_scale; - ginstance->lightmap_slice_index = p_lightmap_slice_index; + 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 = (Color *)memalloc(sizeof(Color) * 9); + ginstance->lightmap_sh = geometry_instance_lightmap_sh.alloc(); } - copymem(ginstance->lightmap_sh, p_sh9, sizeof(Color) * 9); + copymem(ginstance->lightmap_sh->sh, p_sh9, sizeof(Color) * 9); } else { if (ginstance->lightmap_sh != nullptr) { - memfree(ginstance->lightmap_sh); + 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->shader_parameters_offset = p_offset; + 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->cast_double_sided_shaodows = p_enable; + 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->layer_mask = p_layer_mask; + 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) { - memfree(ginstance->lightmap_sh); + 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); } @@ -2916,20 +3060,27 @@ void RendererSceneRenderForward::geometry_instance_pair_decal_instances(Geometry Transform RendererSceneRenderForward::geometry_instance_get_transform(GeometryInstance *p_instance) { GeometryInstanceForward *ginstance = static_cast(p_instance); ERR_FAIL_COND_V(!ginstance, Transform()); - return 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->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); - ginstance->gi_probe_instance_count = MIN(p_gi_probe_instance_count, MAX_GI_PROBES); - for (uint32_t i = 0; i < ginstance->gi_probe_instance_count; i++) { - ginstance->gi_probe_instances[i] = p_gi_probe_instances[i]; + 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(); } } @@ -3182,12 +3333,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)); { @@ -3262,10 +3407,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.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 1826cfa938..b90717ce22 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_forward.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_forward.h @@ -48,7 +48,8 @@ class RendererSceneRenderForward : public RendererSceneRenderRD { enum { SDFGI_MAX_CASCADES = 8, MAX_GI_PROBES = 8, - MAX_LIGHTMAPS = 8 + MAX_LIGHTMAPS = 8, + MAX_GI_PROBES_PER_INSTANCE = 2, }; /* Scene Shader */ @@ -199,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 { @@ -294,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]; @@ -398,153 +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 GeometryInstanceForward; - - struct RenderList { - int max_elements; - - struct Element { - GeometryInstanceForward *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; @@ -574,54 +420,250 @@ 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_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(GeometryInstanceForward *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(GeometryInstanceForward *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); + template + _FORCE_INLINE_ void _render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, GeometryInstanceSurfaceDataCache **p_elements, int p_element_count, bool p_reverse_cull, 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); + + void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, 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); + + 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 GeometryInstanceForward : public GeometryInstance { - RID base; - RS::InstanceType base_type; + struct GeometryInstanceData; + struct GeometryInstanceForward; - RID skeleton; - RID mesh_instance; - - uint32_t layer_mask = 1; - - float depth = 0; - int depth_layer = 0; - - RID gi_probe_instances[MAX_GI_PROBES]; - uint32_t gi_probe_instance_count = 0; - - Vector surface_materials; - RID material_override; - Transform transform; - AABB aabb; - AABB transformed_aabb; - float lod_bias = 0.0; - 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; - RID lightmap_instance; - Rect2 lightmap_uv_scale; - uint32_t lightmap_slice_index = 0; - Color *lightmap_sh = nullptr; + 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); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 3cea7fd01d..f81a35f025 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -1836,6 +1836,10 @@ public: 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; diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index c6e93e93bc..bf7237cad0 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) { @@ -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) { @@ -5165,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 { @@ -5285,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; @@ -5347,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: { } @@ -5362,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) { @@ -5404,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) { @@ -5414,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) { @@ -5424,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) { @@ -5434,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) { @@ -5444,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) { @@ -5460,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) { @@ -5469,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 { @@ -5568,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) { @@ -5605,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) { @@ -5616,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) { @@ -5624,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) { @@ -5632,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) { @@ -5647,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) { @@ -5655,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) { @@ -5672,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 { @@ -5790,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) { @@ -5814,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) { @@ -5839,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) { @@ -5996,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 { @@ -7074,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 { @@ -8133,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"); } @@ -8155,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); @@ -8174,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); @@ -8205,7 +8215,7 @@ 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); diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index 76779c4f7d..bd27936e38 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; @@ -761,7 +762,7 @@ private: clear(true) { } - RendererStorage::InstanceDependency instance_dependency; + Dependency dependency; ParticlesFrameParams frame_params; }; @@ -889,7 +890,7 @@ private: RS::ParticlesCollisionHeightfieldResolution heightfield_resolution = RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_1024; - RendererStorage::InstanceDependency instance_dependency; + Dependency dependency; }; mutable RID_Owner particles_collision_owner; @@ -919,7 +920,7 @@ private: uint64_t version = 1; - RendererStorage::InstanceDependency instance_dependency; + Dependency dependency; }; mutable RID_Owner skeleton_owner; @@ -951,7 +952,7 @@ private: bool directional_sky_only = false; uint64_t version = 0; - RendererStorage::InstanceDependency instance_dependency; + Dependency dependency; }; mutable RID_Owner light_owner; @@ -974,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; @@ -995,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; @@ -1033,7 +1034,7 @@ private: uint32_t version = 1; uint32_t data_version = 1; - RendererStorage::InstanceDependency instance_dependency; + Dependency dependency; }; GiprobeSdfShaderRD giprobe_sdf_shader; @@ -1062,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 @@ -1355,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) { @@ -1672,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()); @@ -1835,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 */ diff --git a/servers/rendering/renderer_rd/shaders/scene_forward.glsl b/servers/rendering/renderer_rd/shaders/scene_forward.glsl index 1c12a8a4c7..5d041babf1 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 629bd24b26..87ce74ba88 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[]; diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index f2e10ee73f..f32d010d1f 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -596,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); @@ -830,7 +830,7 @@ 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_queue_update(instance, true, true); @@ -3152,14 +3152,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) { @@ -3211,7 +3211,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); } } @@ -3242,7 +3242,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); } } @@ -3250,7 +3250,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); @@ -3268,7 +3268,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) { @@ -3299,7 +3299,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); } } } @@ -3343,10 +3343,10 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { } 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); diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index c0c4a707b3..6399f145a3 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -329,7 +329,7 @@ public: virtual ~InstanceBaseData() {} }; - struct Instance : public RendererStorage::InstanceBaseDependency { + struct Instance { RS::InstanceType base_type; RID base; @@ -412,18 +412,43 @@ 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() : @@ -434,7 +459,6 @@ public: receive_shadows = true; visible = true; layer_mask = 1; - instance_version = 0; baked_light = false; dynamic_gi = false; redraw_if_visible = false; @@ -465,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() { diff --git a/servers/rendering/renderer_storage.cpp b/servers/rendering/renderer_storage.cpp index 2edf62df56..a402ecc668 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 a8317a5a80..6f79e8f911 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 class 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 */