From 8da695010a2579b5cf18d4553338e0f1c46045dc Mon Sep 17 00:00:00 2001 From: clayjohn Date: Mon, 6 Oct 2025 09:45:21 -0700 Subject: [PATCH 01/44] Add all PowerVR devices to the ban list for disabling the transform feedback shader cache (cherry picked from commit b20466d12f7892a8dbad9e37959da0287365b69b) --- drivers/gles3/storage/config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp index 5c50aed954b7..98d41704301f 100644 --- a/drivers/gles3/storage/config.cpp +++ b/drivers/gles3/storage/config.cpp @@ -232,7 +232,7 @@ Config::Config() { //https://github.com/godotengine/godot/issues/92662#issuecomment-2161199477 //disable_particles_workaround = false; } - } else if (rendering_device_name == "PowerVR Rogue GE8320") { + } else if (rendering_device_name.contains("PowerVR")) { disable_transform_feedback_shader_cache = true; } From 33d385b0bfbc95526a47d13d6576b0a41ab7d98d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Mon, 15 Dec 2025 23:25:16 +0100 Subject: [PATCH 02/44] RenderingDevice: Add null checks when retrieving uniform sets This may mitigate a crash seen in the wild in Rift Riff on Android, most likely trading it for a single-frame rendering bug (which is better than crashing on user devices). It doesn't solve the underlying issue which seems to be a race condition where a uniform set RID gets has been freed while still being reported as owned by the RID_Owner. (cherry picked from commit adb7774a615b714d098985c9574fe02a3b462c7e) --- servers/rendering/rendering_device.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index eb7d27e4a639..44cd7f191f88 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -4779,12 +4779,13 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint if (draw_list.state.sets[i].pipeline_expected_format != draw_list.state.sets[i].uniform_set_format) { if (draw_list.state.sets[i].uniform_set_format == 0) { - ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline."); + ERR_FAIL_MSG(vformat("Uniforms were never supplied for set (%d) at the time of drawing, which are required by the pipeline.", i)); } else if (uniform_set_owner.owns(draw_list.state.sets[i].uniform_set)) { UniformSet *us = uniform_set_owner.get_or_null(draw_list.state.sets[i].uniform_set); - ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(draw_list.state.pipeline_shader)); + const String us_info = us ? vformat("(%d):\n%s\n", i, _shader_uniform_debug(us->shader_id, us->shader_set)) : vformat("(%d, which was just freed) ", i); + ERR_FAIL_MSG(vformat("Uniforms supplied for set %sare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n%s", us_info, _shader_uniform_debug(draw_list.state.pipeline_shader))); } else { - ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(draw_list.state.pipeline_shader)); + ERR_FAIL_MSG(vformat("Uniforms supplied for set (%d, which was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n%s", i, _shader_uniform_debug(draw_list.state.pipeline_shader))); } } } @@ -4836,6 +4837,7 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint } UniformSet *uniform_set = uniform_set_owner.get_or_null(draw_list.state.sets[i].uniform_set); + ERR_FAIL_NULL(uniform_set); _uniform_set_update_shared(uniform_set); draw_graph.add_draw_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage); draw_list.state.sets[i].bound = true; @@ -4946,9 +4948,10 @@ void RenderingDevice::draw_list_draw_indirect(DrawListID p_list, bool p_use_indi ERR_FAIL_MSG(vformat("Uniforms were never supplied for set (%d) at the time of drawing, which are required by the pipeline.", i)); } else if (uniform_set_owner.owns(draw_list.state.sets[i].uniform_set)) { UniformSet *us = uniform_set_owner.get_or_null(draw_list.state.sets[i].uniform_set); - ERR_FAIL_MSG(vformat("Uniforms supplied for set (%d):\n%s\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n%s", i, _shader_uniform_debug(us->shader_id, us->shader_set), _shader_uniform_debug(draw_list.state.pipeline_shader))); + const String us_info = us ? vformat("(%d):\n%s\n", i, _shader_uniform_debug(us->shader_id, us->shader_set)) : vformat("(%d, which was just freed) ", i); + ERR_FAIL_MSG(vformat("Uniforms supplied for set %sare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n%s", us_info, _shader_uniform_debug(draw_list.state.pipeline_shader))); } else { - ERR_FAIL_MSG(vformat("Uniforms supplied for set (%s, which was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n%s", i, _shader_uniform_debug(draw_list.state.pipeline_shader))); + ERR_FAIL_MSG(vformat("Uniforms supplied for set (%d, which was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n%s", i, _shader_uniform_debug(draw_list.state.pipeline_shader))); } } } @@ -4976,6 +4979,7 @@ void RenderingDevice::draw_list_draw_indirect(DrawListID p_list, bool p_use_indi draw_graph.add_draw_list_bind_uniform_set(draw_list.state.pipeline_shader_driver_id, draw_list.state.sets[i].uniform_set_driver_id, i); UniformSet *uniform_set = uniform_set_owner.get_or_null(draw_list.state.sets[i].uniform_set); + ERR_FAIL_NULL(uniform_set); _uniform_set_update_shared(uniform_set); draw_graph.add_draw_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage); From f767a389610771d9168db7b42241675f74ce8faf Mon Sep 17 00:00:00 2001 From: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Mon, 22 Dec 2025 12:42:19 +0300 Subject: [PATCH 03/44] Create new pools when they become fragmented on Vulkan. (cherry picked from commit 3b23931eae53b6ae6198f2c23b1876f8378c3caa) --- .../vulkan/rendering_device_driver_vulkan.cpp | 82 ++++++++++--------- .../vulkan/rendering_device_driver_vulkan.h | 2 +- 2 files changed, 43 insertions(+), 41 deletions(-) diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp index 7cc27c2167c9..a8bbf45d3a0f 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.cpp +++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp @@ -3801,21 +3801,7 @@ void RenderingDeviceDriverVulkan::shader_destroy_modules(ShaderID p_shader) { /*********************/ /**** UNIFORM SET ****/ /*********************/ -VkDescriptorPool RenderingDeviceDriverVulkan::_descriptor_set_pool_find_or_create(const DescriptorSetPoolKey &p_key, DescriptorSetPools::Iterator *r_pool_sets_it, int p_linear_pool_index) { - bool linear_pool = p_linear_pool_index >= 0; - DescriptorSetPools::Iterator pool_sets_it = linear_pool ? linear_descriptor_set_pools[p_linear_pool_index].find(p_key) : descriptor_set_pools.find(p_key); - - if (pool_sets_it) { - for (KeyValue &E : pool_sets_it->value) { - if (E.value < max_descriptor_sets_per_pool) { - *r_pool_sets_it = pool_sets_it; - return E.key; - } - } - } - - // Create a new one. - +VkDescriptorPool RenderingDeviceDriverVulkan::_descriptor_set_pool_create(const DescriptorSetPoolKey &p_key, bool p_linear_pool) { // Here comes more vulkan API strangeness. VkDescriptorPoolSize *vk_sizes = ALLOCA_ARRAY(VkDescriptorPoolSize, UNIFORM_TYPE_MAX); uint32_t vk_sizes_count = 0; @@ -3889,7 +3875,7 @@ VkDescriptorPool RenderingDeviceDriverVulkan::_descriptor_set_pool_find_or_creat VkDescriptorPoolCreateInfo descriptor_set_pool_create_info = {}; descriptor_set_pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - if (linear_descriptor_pools_enabled && linear_pool) { + if (linear_descriptor_pools_enabled && p_linear_pool) { descriptor_set_pool_create_info.flags = 0; } else { descriptor_set_pool_create_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; // Can't think how somebody may NOT need this flag. @@ -3904,18 +3890,6 @@ VkDescriptorPool RenderingDeviceDriverVulkan::_descriptor_set_pool_find_or_creat ERR_FAIL_COND_V_MSG(res, VK_NULL_HANDLE, "vkCreateDescriptorPool failed with error " + itos(res) + "."); } - // Bookkeep. - - if (!pool_sets_it) { - if (linear_pool) { - pool_sets_it = linear_descriptor_set_pools[p_linear_pool_index].insert(p_key, HashMap()); - } else { - pool_sets_it = descriptor_set_pools.insert(p_key, HashMap()); - } - } - HashMap &pool_rcs = pool_sets_it->value; - pool_rcs.insert(vk_pool, 0); - *r_pool_sets_it = pool_sets_it; return vk_pool; } @@ -4115,27 +4089,55 @@ RDD::UniformSetID RenderingDeviceDriverVulkan::uniform_set_create(VectorViewvalue[vk_pool]++; + bool linear_pool = p_linear_pool_index >= 0; + DescriptorSetPools::Iterator pool_sets_it = linear_pool ? linear_descriptor_set_pools[p_linear_pool_index].find(pool_key) : descriptor_set_pools.find(pool_key); + if (!pool_sets_it) { + if (linear_pool) { + pool_sets_it = linear_descriptor_set_pools[p_linear_pool_index].insert(pool_key, HashMap()); + } else { + pool_sets_it = descriptor_set_pools.insert(pool_key, HashMap()); + } + } VkDescriptorSetAllocateInfo descriptor_set_allocate_info = {}; descriptor_set_allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - descriptor_set_allocate_info.descriptorPool = vk_pool; descriptor_set_allocate_info.descriptorSetCount = 1; const ShaderInfo *shader_info = (const ShaderInfo *)p_shader.id; descriptor_set_allocate_info.pSetLayouts = &shader_info->vk_descriptor_set_layouts[p_set_index]; VkDescriptorSet vk_descriptor_set = VK_NULL_HANDLE; + for (KeyValue &E : pool_sets_it->value) { + if (E.value < max_descriptor_sets_per_pool) { + descriptor_set_allocate_info.descriptorPool = E.key; + VkResult res = vkAllocateDescriptorSets(vk_device, &descriptor_set_allocate_info, &vk_descriptor_set); - VkResult res = vkAllocateDescriptorSets(vk_device, &descriptor_set_allocate_info, &vk_descriptor_set); - if (res) { - _descriptor_set_pool_unreference(pool_sets_it, vk_pool, p_linear_pool_index); - ERR_FAIL_V_MSG(UniformSetID(), "Cannot allocate descriptor sets, error " + itos(res) + "."); + // Break early on success. + if (res == VK_SUCCESS) { + break; + } + + // "Fragmented pool" and "out of memory pool" errors are handled by creating more pools. Any other error is unexpected. + if (res != VK_ERROR_FRAGMENTED_POOL && res != VK_ERROR_OUT_OF_POOL_MEMORY) { + ERR_FAIL_V_MSG(UniformSetID(), "Cannot allocate descriptor sets, error " + itos(res) + "."); + } + } } + // Create a new pool when no allocations could be made from the existing pools. + if (vk_descriptor_set == VK_NULL_HANDLE) { + descriptor_set_allocate_info.descriptorPool = _descriptor_set_pool_create(pool_key, linear_pool); + VkResult res = vkAllocateDescriptorSets(vk_device, &descriptor_set_allocate_info, &vk_descriptor_set); + + // All errors are unexpected at this stage. + if (res) { + vkDestroyDescriptorPool(vk_device, descriptor_set_allocate_info.descriptorPool, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_DESCRIPTOR_POOL)); + ERR_FAIL_V_MSG(UniformSetID(), "Cannot allocate descriptor sets, error " + itos(res) + "."); + } + } + + DEV_ASSERT(descriptor_set_allocate_info.descriptorPool != VK_NULL_HANDLE && vk_descriptor_set != VK_NULL_HANDLE); + pool_sets_it->value[descriptor_set_allocate_info.descriptorPool]++; + for (uint32_t i = 0; i < writes_amount; i++) { vk_writes[i].dstSet = vk_descriptor_set; } @@ -4146,9 +4148,9 @@ RDD::UniformSetID RenderingDeviceDriverVulkan::uniform_set_create(VectorView(resources_allocator); usi->vk_descriptor_set = vk_descriptor_set; if (p_linear_pool_index >= 0) { - usi->vk_linear_descriptor_pool = vk_pool; + usi->vk_linear_descriptor_pool = descriptor_set_allocate_info.descriptorPool; } else { - usi->vk_descriptor_pool = vk_pool; + usi->vk_descriptor_pool = descriptor_set_allocate_info.descriptorPool; } usi->pool_sets_it = pool_sets_it; diff --git a/drivers/vulkan/rendering_device_driver_vulkan.h b/drivers/vulkan/rendering_device_driver_vulkan.h index 90868a15781d..331fdc7095c7 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.h +++ b/drivers/vulkan/rendering_device_driver_vulkan.h @@ -460,7 +460,7 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { HashMap linear_descriptor_set_pools; bool linear_descriptor_pools_enabled = true; - VkDescriptorPool _descriptor_set_pool_find_or_create(const DescriptorSetPoolKey &p_key, DescriptorSetPools::Iterator *r_pool_sets_it, int p_linear_pool_index); + VkDescriptorPool _descriptor_set_pool_create(const DescriptorSetPoolKey &p_key, bool p_linear_pool); void _descriptor_set_pool_unreference(DescriptorSetPools::Iterator p_pool_sets_it, VkDescriptorPool p_vk_descriptor_pool, int p_linear_pool_index); // Global flag to toggle usage of immutable sampler when creating pipeline layouts. From 13bbeb865e5731f8f442de05230e2d44ff2ccda6 Mon Sep 17 00:00:00 2001 From: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Mon, 29 Dec 2025 15:14:04 +0300 Subject: [PATCH 04/44] Implement workaround for GPU driver crash on Adreno 5XX. (cherry picked from commit 3ef93dc19f99e3df337525b2194be34f18bc512e) --- .../vulkan/rendering_device_driver_vulkan.cpp | 21 +++++++++++++++++++ .../vulkan/rendering_device_driver_vulkan.h | 2 ++ 2 files changed, 23 insertions(+) diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp index a8bbf45d3a0f..79e6f2fa3fc2 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.cpp +++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp @@ -1535,6 +1535,14 @@ Error RenderingDeviceDriverVulkan::initialize(uint32_t p_device_index, uint32_t const uint32_t reset_descriptor_pool_fixed_driver_begin = VK_MAKE_VERSION(512u, 671u, 0u); linear_descriptor_pools_enabled = physical_device_properties.driverVersion < reset_descriptor_pool_broken_driver_begin || physical_device_properties.driverVersion > reset_descriptor_pool_fixed_driver_begin; } + + // Workaround a driver bug on Adreno 5XX GPUs that causes a crash when + // there are empty descriptor set layouts placed between non-empty ones. + adreno_5xx_empty_descriptor_set_layout_workaround = + physical_device_properties.vendorID == RenderingContextDriver::Vendor::VENDOR_QUALCOMM && + physical_device_properties.deviceID >= 0x5000000 && + physical_device_properties.deviceID < 0x6000000; + frame_count = p_frame_count; // Copy the queue family properties the context already retrieved. @@ -3713,6 +3721,13 @@ RDD::ShaderID RenderingDeviceDriverVulkan::shader_create_from_container(const Re // Descriptor sets. if (error_text.is_empty()) { + // For Adreno 5XX driver bug. + VkDescriptorSetLayoutBinding placeholder_binding = {}; + placeholder_binding.binding = 0; + placeholder_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + placeholder_binding.descriptorCount = 1; + placeholder_binding.stageFlags = VK_SHADER_STAGE_ALL; + for (uint32_t i = 0; i < shader_refl.uniform_sets.size(); i++) { // Empty ones are fine if they were not used according to spec (binding count will be 0). VkDescriptorSetLayoutCreateInfo layout_create_info = {}; @@ -3720,6 +3735,12 @@ RDD::ShaderID RenderingDeviceDriverVulkan::shader_create_from_container(const Re layout_create_info.bindingCount = vk_set_bindings[i].size(); layout_create_info.pBindings = vk_set_bindings[i].ptr(); + // ...not so fine on Adreno 5XX. + if (adreno_5xx_empty_descriptor_set_layout_workaround && layout_create_info.bindingCount == 0) { + layout_create_info.bindingCount = 1; + layout_create_info.pBindings = &placeholder_binding; + } + VkDescriptorSetLayout layout = VK_NULL_HANDLE; res = vkCreateDescriptorSetLayout(vk_device, &layout_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT), &layout); if (res) { diff --git a/drivers/vulkan/rendering_device_driver_vulkan.h b/drivers/vulkan/rendering_device_driver_vulkan.h index 331fdc7095c7..c2638a0b77ce 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.h +++ b/drivers/vulkan/rendering_device_driver_vulkan.h @@ -474,6 +474,8 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { DescriptorSetPools::Iterator pool_sets_it; }; + bool adreno_5xx_empty_descriptor_set_layout_workaround = false; + public: virtual UniformSetID uniform_set_create(VectorView p_uniforms, ShaderID p_shader, uint32_t p_set_index, int p_linear_pool_index) override final; virtual void linear_uniform_set_pools_reset(int p_linear_pool_index) override final; From b362e2e0df065df9ea7bb3b244e0592ea2633bed Mon Sep 17 00:00:00 2001 From: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Wed, 31 Dec 2025 16:46:34 +0300 Subject: [PATCH 05/44] Create separate graphics queue instead of reusing the main queue when transfer queue family is unsupported. (cherry picked from commit 2bc63ddf0839d648ed149f02ce921b625b133f11) --- servers/rendering/rendering_device.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 44cd7f191f88..e0910525f572 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -6757,16 +6757,15 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ ERR_FAIL_COND_V(!main_queue, FAILED); transfer_queue_family = driver->command_queue_family_get(RDD::COMMAND_QUEUE_FAMILY_TRANSFER_BIT); - if (transfer_queue_family) { - // Create the transfer queue. - transfer_queue = driver->command_queue_create(transfer_queue_family); - ERR_FAIL_COND_V(!transfer_queue, FAILED); - } else { - // Use main queue as the transfer queue. - transfer_queue = main_queue; + if (!transfer_queue_family) { + // Use main queue family if transfer queue family is not supported. transfer_queue_family = main_queue_family; } + // Create the transfer queue. + transfer_queue = driver->command_queue_create(transfer_queue_family); + ERR_FAIL_COND_V(!transfer_queue, FAILED); + if (present_queue_family) { // Create the present queue. present_queue = driver->command_queue_create(present_queue_family); From 6c2d9c871139df1d437925df9e720b2e4ab47a37 Mon Sep 17 00:00:00 2001 From: Dario Date: Tue, 6 Jan 2026 16:02:51 -0300 Subject: [PATCH 06/44] Always add Vulkan descriptor count for immutable samplers to descriptor pool. (cherry picked from commit bce41d08fe93092c452ed784cd203e942d54caeb) --- .../vulkan/rendering_device_driver_vulkan.cpp | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp index 79e6f2fa3fc2..231ed930481b 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.cpp +++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp @@ -3944,25 +3944,28 @@ RDD::UniformSetID RenderingDeviceDriverVulkan::uniform_set_create(VectorView= 0; From 97bfe4970929be906711c80fee722d2744d5dba6 Mon Sep 17 00:00:00 2001 From: nikitalita <69168929+nikitalita@users.noreply.github.com> Date: Fri, 26 Dec 2025 12:44:22 -0800 Subject: [PATCH 07/44] Fix setting mesh blend shape properties in dummy mesh storage (cherry picked from commit 84742563f8bcbd525d8accbc2c05b46a6bc5ada0) --- .../rendering/dummy/storage/mesh_storage.h | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/servers/rendering/dummy/storage/mesh_storage.h b/servers/rendering/dummy/storage/mesh_storage.h index a660a5444519..0871c91ade58 100644 --- a/servers/rendering/dummy/storage/mesh_storage.h +++ b/servers/rendering/dummy/storage/mesh_storage.h @@ -69,7 +69,11 @@ class MeshStorage : public RendererMeshStorage { virtual void mesh_initialize(RID p_rid) override; virtual void mesh_free(RID p_rid) override; - virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) override {} + virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) override { + DummyMesh *m = mesh_owner.get_or_null(p_mesh); + ERR_FAIL_NULL(m); + m->blend_shape_count = p_blend_shape_count; + } virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) override { return false; } virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) override { @@ -95,10 +99,23 @@ class MeshStorage : public RendererMeshStorage { m->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MESH); } - virtual int mesh_get_blend_shape_count(RID p_mesh) const override { return 0; } + virtual int mesh_get_blend_shape_count(RID p_mesh) const override { + DummyMesh *m = mesh_owner.get_or_null(p_mesh); + ERR_FAIL_NULL_V(m, 0); + return m->blend_shape_count; + } + + virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) override { + DummyMesh *m = mesh_owner.get_or_null(p_mesh); + ERR_FAIL_NULL(m); + m->blend_shape_mode = p_mode; + } - virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) override {} - virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const override { return RS::BLEND_SHAPE_MODE_NORMALIZED; } + virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const override { + DummyMesh *m = mesh_owner.get_or_null(p_mesh); + ERR_FAIL_NULL_V(m, RS::BLEND_SHAPE_MODE_NORMALIZED); + return m->blend_shape_mode; + } virtual void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector &p_data) override {} virtual void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector &p_data) override {} From 965097ef729ac15c6025f7971c999f86e208ea41 Mon Sep 17 00:00:00 2001 From: Clay John Date: Sun, 19 Oct 2025 19:25:28 -0700 Subject: [PATCH 08/44] Use GL_FRAMEBUFFER instead of GL_DRAW_FRAMEBUFFER when doing final blit to the screen framebuffer to work around OBS bug (cherry picked from commit 7bde47e43317a2be7df6e4688e79e23c827cd5c1) --- drivers/gles3/rasterizer_gles3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 61eeb064e649..bdc78e3873d9 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -410,7 +410,7 @@ void RasterizerGLES3::_blit_render_target_to_screen(DisplayServer::WindowID p_sc } #endif - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); if (p_first) { if (p_blit.dst_rect.position != Vector2() || p_blit.dst_rect.size != rt->size) { From a01d8c288a0a394784282670d8e513616b2c9cd3 Mon Sep 17 00:00:00 2001 From: Dario Date: Tue, 2 Sep 2025 12:09:21 -0300 Subject: [PATCH 09/44] Clamp minimum size of 3D texture view in D3D12. (cherry picked from commit 1ce55b946c73147a104fd6a38cb2cfda20b9a2bd) --- drivers/d3d12/rendering_device_driver_d3d12.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index af3b6d443666..8a89487babd1 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -3055,7 +3055,7 @@ D3D12_UNORDERED_ACCESS_VIEW_DESC RenderingDeviceDriverD3D12::_make_ranged_uav_fo } break; case D3D12_UAV_DIMENSION_TEXTURE3D: { uav_desc.Texture3D.MipSlice = mip; - uav_desc.Texture3D.WSize >>= p_mipmap_offset; + uav_desc.Texture3D.WSize = MAX(uav_desc.Texture3D.WSize >> p_mipmap_offset, 1U); } break; default: break; From 19c3e3908e00db1d970a45d75e9c2ec1823507d0 Mon Sep 17 00:00:00 2001 From: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Mon, 6 Oct 2025 16:29:29 +0300 Subject: [PATCH 10/44] Fix D3D12 not checking for fullscreen clear region correctly. (cherry picked from commit b568b06970fe6d63977d9b6e09a0dfbf5523feba) --- drivers/d3d12/rendering_device_driver_d3d12.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index 8a89487babd1..53ce0f3ddfaa 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -4571,8 +4571,7 @@ void RenderingDeviceDriverD3D12::command_begin_render_pass(CommandBufferID p_cmd p_rect.position.y, p_rect.position.x + p_rect.size.x, p_rect.position.y + p_rect.size.y); - cmd_buf_info->render_pass_state.region_is_all = !( - cmd_buf_info->render_pass_state.region_rect.left == 0 && + cmd_buf_info->render_pass_state.region_is_all = (cmd_buf_info->render_pass_state.region_rect.left == 0 && cmd_buf_info->render_pass_state.region_rect.top == 0 && cmd_buf_info->render_pass_state.region_rect.right == fb_info->size.x && cmd_buf_info->render_pass_state.region_rect.bottom == fb_info->size.y); From 5f687a2de0b2f29b149311ec0a18b91cff45e9d1 Mon Sep 17 00:00:00 2001 From: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Tue, 7 Oct 2025 13:18:38 +0300 Subject: [PATCH 11/44] Fix specialization constant patching on D3D12. (cherry picked from commit 36b7e77f032a6ff44e05fcfc6fd9ae1790272df9) --- .../rendering_shader_container_d3d12.cpp | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/drivers/d3d12/rendering_shader_container_d3d12.cpp b/drivers/d3d12/rendering_shader_container_d3d12.cpp index 1b484e24d718..568ca8101804 100644 --- a/drivers/d3d12/rendering_shader_container_d3d12.cpp +++ b/drivers/d3d12/rendering_shader_container_d3d12.cpp @@ -99,28 +99,26 @@ uint32_t RenderingDXIL::patch_specialization_constant( const uint64_t (&p_stages_bit_offsets)[D3D12_BITCODE_OFFSETS_NUM_STAGES], HashMap> &r_stages_bytecodes, bool p_is_first_patch) { - uint32_t patch_val = 0; + int64_t patch_val = 0; switch (p_type) { case RenderingDeviceCommons::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT: { - uint32_t int_value = *((const int *)p_value); - ERR_FAIL_COND_V(int_value & (1 << 31), 0); - patch_val = int_value; + patch_val = *((const int32_t *)p_value); } break; case RenderingDeviceCommons::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL: { bool bool_value = *((const bool *)p_value); - patch_val = (uint32_t)bool_value; + patch_val = (int32_t)bool_value; } break; case RenderingDeviceCommons::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT: { - uint32_t int_value = *((const int *)p_value); - ERR_FAIL_COND_V(int_value & (1 << 31), 0); - patch_val = (int_value >> 1); + patch_val = *((const int32_t *)p_value); } break; } - // For VBR encoding to encode the number of bits we expect (32), we need to set the MSB unconditionally. - // However, signed VBR moves the MSB to the LSB, so setting the MSB to 1 wouldn't help. Therefore, - // the bit we set to 1 is the one at index 30. - patch_val |= (1 << 30); - patch_val <<= 1; // What signed VBR does. + + // Encode to signed VBR. + if (patch_val >= 0) { + patch_val <<= 1; + } else { + patch_val = ((-patch_val) << 1) | 1; + } auto tamper_bits = [](uint8_t *p_start, uint64_t p_bit_offset, uint64_t p_tb_value) -> uint64_t { uint64_t original = 0; @@ -174,13 +172,13 @@ uint32_t RenderingDXIL::patch_specialization_constant( Vector &bytecode = r_stages_bytecodes[(RenderingDeviceCommons::ShaderStage)stage]; #ifdef DEV_ENABLED - uint64_t orig_patch_val = tamper_bits(bytecode.ptrw(), offset, patch_val); + uint64_t orig_patch_val = tamper_bits(bytecode.ptrw(), offset, (uint64_t)patch_val); // Checking against the value the NIR patch should have set. DEV_ASSERT(!p_is_first_patch || ((orig_patch_val >> 1) & GODOT_NIR_SC_SENTINEL_MAGIC_MASK) == GODOT_NIR_SC_SENTINEL_MAGIC); - uint64_t readback_patch_val = tamper_bits(bytecode.ptrw(), offset, patch_val); - DEV_ASSERT(readback_patch_val == patch_val); + uint64_t readback_patch_val = tamper_bits(bytecode.ptrw(), offset, (uint64_t)patch_val); + DEV_ASSERT(readback_patch_val == (uint64_t)patch_val); #else - tamper_bits(bytecode.ptrw(), offset, patch_val); + tamper_bits(bytecode.ptrw(), offset, (uint64_t)patch_val); #endif stages_patched_mask |= (1 << stage); From d82e24b4905e1a573a9c093d557db77fcb19b4e4 Mon Sep 17 00:00:00 2001 From: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Wed, 22 Oct 2025 12:42:12 +0300 Subject: [PATCH 12/44] Force disable SPIRV debug info on D3D12. (cherry picked from commit a62b194dc2495fa473c4af76ba3fb5bd78b49c48) --- main/main.cpp | 2 +- modules/glslang/register_types.cpp | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/main/main.cpp b/main/main.cpp index 62dafe881d4a..7ab3b8360387 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -633,7 +633,7 @@ void Main::print_help(const char *p_binary) { #ifdef DEBUG_ENABLED print_help_option("--gpu-abort", "Abort on graphics API usage errors (usually validation layer errors). May help see the problem if your system freezes.\n", CLI_OPTION_AVAILABILITY_TEMPLATE_DEBUG); #endif - print_help_option("--generate-spirv-debug-info", "Generate SPIR-V debug information. This allows source-level shader debugging with RenderDoc.\n"); + print_help_option("--generate-spirv-debug-info", "Generate SPIR-V debug information (Vulkan only). This allows source-level shader debugging with RenderDoc.\n"); #if defined(DEBUG_ENABLED) || defined(DEV_ENABLED) print_help_option("--extra-gpu-memory-tracking", "Enables additional memory tracking (see class reference for `RenderingDevice.get_driver_and_device_memory_report()` and linked methods). Currently only implemented for Vulkan. Enabling this feature may cause crashes on some systems due to buggy drivers or bugs in the Vulkan Loader. See https://github.com/godotengine/godot/issues/95967\n"); print_help_option("--accurate-breadcrumbs", "Force barriers between breadcrumbs. Useful for narrowing down a command causing GPU resets. Currently only implemented for Vulkan.\n"); diff --git a/modules/glslang/register_types.cpp b/modules/glslang/register_types.cpp index 764d339bac70..22ef1bb01b03 100644 --- a/modules/glslang/register_types.cpp +++ b/modules/glslang/register_types.cpp @@ -31,6 +31,7 @@ #include "register_types.h" #include "core/config/engine.h" +#include "core/os/os.h" #include "shader_compile.h" #include @@ -67,8 +68,16 @@ Vector compile_glslang_shader(RenderingDeviceCommons::ShaderStage p_sta shader.setPreamble(preamble.c_str()); } + bool generate_spirv_debug_info = Engine::get_singleton()->is_generate_spirv_debug_info_enabled(); +#ifdef D3D12_ENABLED + if (OS::get_singleton()->get_current_rendering_driver_name() == "d3d12") { + // SPIRV to DXIL conversion does not support debug info. + generate_spirv_debug_info = false; + } +#endif + EShMessages messages = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules); - if (Engine::get_singleton()->is_generate_spirv_debug_info_enabled()) { + if (generate_spirv_debug_info) { messages = (EShMessages)(messages | EShMsgDebugInfo); } const int DefaultVersion = 100; @@ -103,7 +112,7 @@ Vector compile_glslang_shader(RenderingDeviceCommons::ShaderStage p_sta spv::SpvBuildLogger logger; glslang::SpvOptions spvOptions; - if (Engine::get_singleton()->is_generate_spirv_debug_info_enabled()) { + if (generate_spirv_debug_info) { spvOptions.generateDebugInfo = true; spvOptions.emitNonSemanticShaderDebugInfo = true; spvOptions.emitNonSemanticShaderDebugSource = true; From 13c1531a3475380152dd8ca09c8c9102370eaf26 Mon Sep 17 00:00:00 2001 From: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Fri, 17 Oct 2025 14:28:31 +0300 Subject: [PATCH 13/44] Greatly reduce shader conversion time & fix spec constant bitmasking on D3D12. (cherry picked from commit 8895dfa56c4a87db3d4b7ebf3f5d6d60ed7f7a18) --- drivers/d3d12/rendering_shader_container_d3d12.cpp | 4 ---- misc/scripts/install_d3d12_sdk_windows.py | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/d3d12/rendering_shader_container_d3d12.cpp b/drivers/d3d12/rendering_shader_container_d3d12.cpp index 568ca8101804..8b0a65a508ca 100644 --- a/drivers/d3d12/rendering_shader_container_d3d12.cpp +++ b/drivers/d3d12/rendering_shader_container_d3d12.cpp @@ -317,10 +317,6 @@ bool RenderingShaderContainerD3D12::_convert_spirv_to_nir(const Vector Date: Thu, 20 Nov 2025 19:26:00 +0300 Subject: [PATCH 14/44] Check for Typed UAV Load Additional Formats capability when creating D3D12 device. (cherry picked from commit 23314701285b9e2011d365428e7f452be9d103bc) --- drivers/d3d12/rendering_device_driver_d3d12.cpp | 8 +++----- drivers/d3d12/rendering_device_driver_d3d12.h | 5 ----- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index 53ce0f3ddfaa..ded33cce14d3 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -5806,7 +5806,7 @@ uint64_t RenderingDeviceDriverD3D12::api_trait_get(ApiTrait p_trait) { bool RenderingDeviceDriverD3D12::has_feature(Features p_feature) { switch (p_feature) { case SUPPORTS_HALF_FLOAT: - return shader_capabilities.native_16bit_ops && storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported; + return shader_capabilities.native_16bit_ops; case SUPPORTS_FRAGMENT_SHADER_WITH_ONLY_SIDE_EFFECTS: return true; case SUPPORTS_BUFFER_DEVICE_ADDRESS: @@ -6036,7 +6036,6 @@ Error RenderingDeviceDriverD3D12::_check_capabilities() { subgroup_capabilities.wave_ops_supported = false; shader_capabilities.shader_model = (D3D_SHADER_MODEL)0; shader_capabilities.native_16bit_ops = false; - storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported = false; format_capabilities.relaxed_casting_supported = false; { @@ -6077,9 +6076,8 @@ Error RenderingDeviceDriverD3D12::_check_capabilities() { D3D12_FEATURE_DATA_D3D12_OPTIONS options = {}; res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)); - if (SUCCEEDED(res)) { - storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported = options.TypedUAVLoadAdditionalFormats; - } + ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_UNAVAILABLE, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + "."); + ERR_FAIL_COND_V_MSG(!options.TypedUAVLoadAdditionalFormats, ERR_UNAVAILABLE, "No support for Typed UAV Load Additional Formats has been found."); D3D12_FEATURE_DATA_D3D12_OPTIONS1 options1 = {}; res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS1, &options1, sizeof(options1)); diff --git a/drivers/d3d12/rendering_device_driver_d3d12.h b/drivers/d3d12/rendering_device_driver_d3d12.h index 602c4d48f235..f75e001011c1 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.h +++ b/drivers/d3d12/rendering_device_driver_d3d12.h @@ -114,10 +114,6 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver { bool native_16bit_ops = false; }; - struct StorageBufferCapabilities { - bool storage_buffer_16_bit_access_is_supported = false; - }; - struct FormatCapabilities { bool relaxed_casting_supported = false; }; @@ -143,7 +139,6 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver { FragmentShadingRateCapabilities fsr_capabilities; FragmentDensityMapCapabilities fdm_capabilities; ShaderCapabilities shader_capabilities; - StorageBufferCapabilities storage_buffer_capabilities; FormatCapabilities format_capabilities; BarrierCapabilities barrier_capabilities; MiscFeaturesSupport misc_features_support; From 7083143e5771b286d5c5162d7d8b25aaa3500308 Mon Sep 17 00:00:00 2001 From: Dario Date: Tue, 22 Jul 2025 11:38:36 -0300 Subject: [PATCH 15/44] Move D3D12's automatic texture clears to RenderingDevice. (cherry picked from commit d17ea061bcbf0ae96e4b71e642834315a9580be0) --- .../d3d12/rendering_device_driver_d3d12.cpp | 24 +--- drivers/d3d12/rendering_device_driver_d3d12.h | 2 - servers/rendering/rendering_device.cpp | 105 +++++++++++++++--- servers/rendering/rendering_device.h | 5 + servers/rendering/rendering_device_driver.cpp | 2 + servers/rendering/rendering_device_driver.h | 1 + 6 files changed, 97 insertions(+), 42 deletions(-) diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index ded33cce14d3..50f86ef05795 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -1573,12 +1573,6 @@ RDD::TextureID RenderingDeviceDriverD3D12::texture_create(const TextureFormat &p tex_info->view_descs.srv = srv_desc; tex_info->view_descs.uav = uav_desc; - if (!barrier_capabilities.enhanced_barriers_supported && (p_format.usage_bits & (TEXTURE_USAGE_STORAGE_BIT | TEXTURE_USAGE_COLOR_ATTACHMENT_BIT))) { - // Fallback to clear resources when they're first used in a uniform set. Not necessary if enhanced barriers - // are supported, as the discard flag will be used instead when transitioning from an undefined layout. - textures_pending_clear.add(&tex_info->pending_clear); - } - return TextureID(tex_info); } @@ -3643,21 +3637,6 @@ void RenderingDeviceDriverD3D12::command_uniform_set_prepare_for_use(CommandBuff return; } - // Perform pending blackouts. - { - SelfList *E = textures_pending_clear.first(); - while (E) { - TextureSubresourceRange subresources; - subresources.layer_count = E->self()->layers; - subresources.mipmap_count = E->self()->mipmaps; - command_clear_color_texture(p_cmd_buffer, TextureID(E->self()), TEXTURE_LAYOUT_UNDEFINED, Color(), subresources); - - SelfList *next = E->next(); - E->remove_from_list(); - E = next; - } - } - CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id; const UniformSetInfo *uniform_set_info = (const UniformSetInfo *)p_uniform_set.id; const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id; @@ -4615,7 +4594,6 @@ void RenderingDeviceDriverD3D12::command_begin_render_pass(CommandBufferID p_cmd if (pass_info->attachments[i].load_op == ATTACHMENT_LOAD_OP_CLEAR) { clear.aspect.set_flag(TEXTURE_ASPECT_COLOR_BIT); clear.color_attachment = i; - tex_info->pending_clear.remove_from_list(); } } else if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) { if (pass_info->attachments[i].load_op == ATTACHMENT_LOAD_OP_CLEAR) { @@ -5798,6 +5776,8 @@ uint64_t RenderingDeviceDriverD3D12::api_trait_get(ApiTrait p_trait) { return true; case API_TRAIT_BUFFERS_REQUIRE_TRANSITIONS: return !barrier_capabilities.enhanced_barriers_supported; + case API_TRAIT_TEXTURE_OUTPUTS_REQUIRE_CLEARS: + return true; default: return RenderingDeviceDriver::api_trait_get(p_trait); } diff --git a/drivers/d3d12/rendering_device_driver_d3d12.h b/drivers/d3d12/rendering_device_driver_d3d12.h index f75e001011c1..e90a3867a5d5 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.h +++ b/drivers/d3d12/rendering_device_driver_d3d12.h @@ -355,12 +355,10 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver { TextureInfo *main_texture = nullptr; UINT mapped_subresource = UINT_MAX; - SelfList pending_clear{ this }; #ifdef DEBUG_ENABLED bool created_from_extension = false; #endif }; - SelfList::List textures_pending_clear; HashMap format_sample_counts_mask_cache; Mutex format_sample_counts_mask_cache_mutex; diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index e0910525f572..0b60bf35a84f 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -1038,6 +1038,11 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture texture.allowed_shared_formats = format.shareable_formats; texture.has_initial_data = !data.is_empty(); + if (driver->api_trait_get(RDD::API_TRAIT_TEXTURE_OUTPUTS_REQUIRE_CLEARS)) { + // Check if a clear for this texture must be performed the first time it's used if the driver requires explicit clears after initialization. + texture.pending_clear = !texture.has_initial_data && (format.usage_bits & (TEXTURE_USAGE_STORAGE_BIT | TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)); + } + if ((format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { texture.read_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT); texture.barrier_aspect_flags.set_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT); @@ -1901,6 +1906,50 @@ uint32_t RenderingDevice::_texture_vrs_method_to_usage_bits() const { } } +void RenderingDevice::_texture_check_pending_clear(RID p_texture_rid, Texture *p_texture) { + DEV_ASSERT(p_texture != nullptr); + + if (!p_texture->pending_clear) { + return; + } + + bool clear = true; + p_texture->pending_clear = false; + + if (p_texture->owner.is_valid()) { + // Check the owner texture instead if it exists. + p_texture_rid = p_texture->owner; + p_texture = texture_owner.get_or_null(p_texture_rid); + clear = p_texture->pending_clear; + } + + if (p_texture != nullptr && clear) { + _texture_clear(p_texture_rid, p_texture, Color(), 0, p_texture->mipmaps, 0, p_texture->layers); + p_texture->pending_clear = false; + } +} + +void RenderingDevice::_texture_clear(RID p_texture_rid, Texture *p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers) { + _check_transfer_worker_texture(p_texture); + + RDD::TextureSubresourceRange range; + range.aspect = p_texture->read_aspect_flags; + range.base_mipmap = p_texture->base_mipmap + p_base_mipmap; + range.mipmap_count = p_mipmaps; + range.base_layer = p_texture->base_layer + p_base_layer; + range.layer_count = p_layers; + + // Indicate the texture will get modified for the shared texture fallback. + _texture_update_shared_fallback(p_texture_rid, p_texture, true); + + if (_texture_make_mutable(p_texture, p_texture_rid)) { + // The texture must be mutable to be used as a clear destination. + draw_graph.add_synchronization(); + } + + draw_graph.add_texture_clear(p_texture->driver_id, p_texture->draw_tracker, p_color, range); +} + Vector RenderingDevice::_texture_get_data(Texture *tex, uint32_t p_layer, bool p_2d) { uint32_t width, height, depth; uint32_t tight_mip_size = get_image_format_required_size(tex->format, tex->width, tex->height, p_2d ? 1 : tex->depth, tex->mipmaps, &width, &height, &depth); @@ -2427,24 +2476,7 @@ Error RenderingDevice::texture_clear(RID p_texture, const Color &p_color, uint32 ERR_FAIL_COND_V(p_base_mipmap + p_mipmaps > src_tex->mipmaps, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_base_layer + p_layers > src_tex->layers, ERR_INVALID_PARAMETER); - _check_transfer_worker_texture(src_tex); - - RDD::TextureSubresourceRange range; - range.aspect = src_tex->read_aspect_flags; - range.base_mipmap = src_tex->base_mipmap + p_base_mipmap; - range.mipmap_count = p_mipmaps; - range.base_layer = src_tex->base_layer + p_base_layer; - range.layer_count = p_layers; - - // Indicate the texture will get modified for the shared texture fallback. - _texture_update_shared_fallback(p_texture, src_tex, true); - - if (_texture_make_mutable(src_tex, p_texture)) { - // The texture must be mutable to be used as a clear destination. - draw_graph.add_synchronization(); - } - - draw_graph.add_texture_clear(src_tex->driver_id, src_tex->draw_tracker, p_color, range); + _texture_clear(p_texture, src_tex, p_color, p_base_mipmap, p_mipmaps, p_base_layer, p_layers); return OK; } @@ -3553,6 +3585,21 @@ void RenderingDevice::_uniform_set_update_shared(UniformSet *p_uniform_set) { } } +void RenderingDevice::_uniform_set_update_clears(UniformSet *p_uniform_set) { + if (p_uniform_set->pending_clear_textures.is_empty()) { + return; + } + + for (RID texture_id : p_uniform_set->pending_clear_textures) { + Texture *texture = texture_owner.get_or_null(texture_id); + if (texture != nullptr) { + _texture_check_pending_clear(texture_id, texture); + } + } + + p_uniform_set->pending_clear_textures.clear(); +} + RID RenderingDevice::uniform_set_create(const VectorView &p_uniforms, RID p_shader, uint32_t p_shader_set, bool p_linear_pool) { _THREAD_SAFE_METHOD_ @@ -3582,6 +3629,7 @@ RID RenderingDevice::uniform_set_create(const VectorView &p_uniform Vector draw_trackers_usage; HashMap untracked_usage; Vector shared_textures_to_update; + LocalVector pending_clear_textures; for (uint32_t i = 0; i < set_uniform_count; i++) { const ShaderUniform &set_uniform = set_uniforms[i]; @@ -3652,6 +3700,10 @@ RID RenderingDevice::uniform_set_create(const VectorView &p_uniform attachable_textures.push_back(attachable_texture); } + if (texture->pending_clear) { + pending_clear_textures.push_back(texture_id); + } + RDD::TextureID driver_id = texture->driver_id; RDG::ResourceTracker *tracker = texture->draw_tracker; if (texture->shared_fallback != nullptr && texture->shared_fallback->texture.id != 0) { @@ -3698,6 +3750,10 @@ RID RenderingDevice::uniform_set_create(const VectorView &p_uniform attachable_textures.push_back(attachable_texture); } + if (texture->pending_clear) { + pending_clear_textures.push_back(texture_id); + } + RDD::TextureID driver_id = texture->driver_id; RDG::ResourceTracker *tracker = texture->draw_tracker; if (texture->shared_fallback != nullptr && texture->shared_fallback->texture.id != 0) { @@ -3742,6 +3798,10 @@ RID RenderingDevice::uniform_set_create(const VectorView &p_uniform shared_textures_to_update.push_back({ true, texture_id }); } + if (texture->pending_clear) { + pending_clear_textures.push_back(texture_id); + } + if (_texture_make_mutable(texture, texture_id)) { // The texture must be mutable as a layout transition will be required. draw_graph.add_synchronization(); @@ -3934,6 +3994,7 @@ RID RenderingDevice::uniform_set_create(const VectorView &p_uniform uniform_set.draw_trackers_usage = draw_trackers_usage; uniform_set.untracked_usage = untracked_usage; uniform_set.shared_textures_to_update = shared_textures_to_update; + uniform_set.pending_clear_textures = pending_clear_textures; uniform_set.shader_set = p_shader_set; uniform_set.shader_id = p_shader; @@ -4450,6 +4511,9 @@ RenderingDevice::DrawListID RenderingDevice::draw_list_begin(RID p_framebuffer, continue; } + // Clear the texture if the driver requires it during its first use. + _texture_check_pending_clear(texture_rid, texture); + // Indicate the texture will get modified for the shared texture fallback. _texture_update_shared_fallback(texture_rid, texture, true); @@ -4839,6 +4903,8 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint UniformSet *uniform_set = uniform_set_owner.get_or_null(draw_list.state.sets[i].uniform_set); ERR_FAIL_NULL(uniform_set); _uniform_set_update_shared(uniform_set); + _uniform_set_update_clears(uniform_set); + draw_graph.add_draw_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage); draw_list.state.sets[i].bound = true; @@ -4981,6 +5047,7 @@ void RenderingDevice::draw_list_draw_indirect(DrawListID p_list, bool p_use_indi UniformSet *uniform_set = uniform_set_owner.get_or_null(draw_list.state.sets[i].uniform_set); ERR_FAIL_NULL(uniform_set); _uniform_set_update_shared(uniform_set); + _uniform_set_update_clears(uniform_set); draw_graph.add_draw_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage); @@ -5375,6 +5442,7 @@ void RenderingDevice::compute_list_dispatch(ComputeListID p_list, uint32_t p_x_g } UniformSet *uniform_set = uniform_set_owner.get_or_null(compute_list.state.sets[i].uniform_set); _uniform_set_update_shared(uniform_set); + _uniform_set_update_clears(uniform_set); draw_graph.add_compute_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage); compute_list.state.sets[i].bound = true; @@ -5511,6 +5579,7 @@ void RenderingDevice::compute_list_dispatch_indirect(ComputeListID p_list, RID p UniformSet *uniform_set = uniform_set_owner.get_or_null(compute_list.state.sets[i].uniform_set); _uniform_set_update_shared(uniform_set); + _uniform_set_update_clears(uniform_set); draw_graph.add_compute_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage); compute_list.state.sets[i].bound = true; diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index b6e589e714da..0bee8d7de825 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -303,6 +303,7 @@ class RenderingDevice : public RenderingDeviceCommons { bool is_resolve_buffer = false; bool is_discardable = false; bool has_initial_data = false; + bool pending_clear = false; BitField read_aspect_flags = {}; BitField barrier_aspect_flags = {}; @@ -356,6 +357,8 @@ class RenderingDevice : public RenderingDeviceCommons { void _texture_free_shared_fallback(Texture *p_texture); void _texture_copy_shared(RID p_src_texture_rid, Texture *p_src_texture, RID p_dst_texture_rid, Texture *p_dst_texture); void _texture_create_reinterpret_buffer(Texture *p_texture); + void _texture_check_pending_clear(RID p_texture_rid, Texture *p_texture); + void _texture_clear(RID p_texture_rid, Texture *p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers); uint32_t _texture_vrs_method_to_usage_bits() const; struct TextureGetDataRequest { @@ -1091,6 +1094,7 @@ class RenderingDevice : public RenderingDeviceCommons { Vector draw_trackers_usage; HashMap untracked_usage; LocalVector shared_textures_to_update; + LocalVector pending_clear_textures; InvalidationCallback invalidated_callback = nullptr; void *invalidated_callback_userdata = nullptr; }; @@ -1098,6 +1102,7 @@ class RenderingDevice : public RenderingDeviceCommons { RID_Owner uniform_set_owner; void _uniform_set_update_shared(UniformSet *p_uniform_set); + void _uniform_set_update_clears(UniformSet *p_uniform_set); public: /** Bake a set of uniforms that can be bound at runtime with the given shader. diff --git a/servers/rendering/rendering_device_driver.cpp b/servers/rendering/rendering_device_driver.cpp index 0c26a5808a1f..abc57e441676 100644 --- a/servers/rendering/rendering_device_driver.cpp +++ b/servers/rendering/rendering_device_driver.cpp @@ -53,6 +53,8 @@ uint64_t RenderingDeviceDriver::api_trait_get(ApiTrait p_trait) { return false; case API_TRAIT_BUFFERS_REQUIRE_TRANSITIONS: return false; + case API_TRAIT_TEXTURE_OUTPUTS_REQUIRE_CLEARS: + return false; default: ERR_FAIL_V(0); } diff --git a/servers/rendering/rendering_device_driver.h b/servers/rendering/rendering_device_driver.h index 7d7d732f0794..a41af12348d6 100644 --- a/servers/rendering/rendering_device_driver.h +++ b/servers/rendering/rendering_device_driver.h @@ -784,6 +784,7 @@ class RenderingDeviceDriver : public RenderingDeviceCommons { API_TRAIT_CLEARS_WITH_COPY_ENGINE, API_TRAIT_USE_GENERAL_IN_COPY_QUEUES, API_TRAIT_BUFFERS_REQUIRE_TRANSITIONS, + API_TRAIT_TEXTURE_OUTPUTS_REQUIRE_CLEARS, }; enum ShaderChangeInvalidation { From b2c02b7a51178155b8c287ad6ce3c69a9b19764d Mon Sep 17 00:00:00 2001 From: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Thu, 27 Nov 2025 17:26:26 +0300 Subject: [PATCH 16/44] Check for pending clears in every RD texture function. (cherry picked from commit bfdf86370f7d3acf32b99bef4b07db56d0dab179) --- servers/rendering/rendering_device.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 0b60bf35a84f..2419a0195b25 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -1600,6 +1600,9 @@ Error RenderingDevice::texture_update(RID p_texture, uint32_t p_layer, const Vec ERR_FAIL_COND_V_MSG(required_size != (uint32_t)p_data.size(), ERR_INVALID_PARAMETER, "Required size for texture update (" + itos(required_size) + ") does not match data supplied size (" + itos(p_data.size()) + ")."); + // Clear the texture if the driver requires it during its first use. + _texture_check_pending_clear(p_texture, texture); + _check_transfer_worker_texture(texture); uint32_t block_w, block_h; @@ -2028,6 +2031,9 @@ Vector RenderingDevice::texture_get_data(RID p_texture, uint32_t p_laye ERR_FAIL_COND_V(p_layer >= tex->layers, Vector()); + // Clear the texture if the driver requires it during its first use. + _texture_check_pending_clear(p_texture, tex); + _check_transfer_worker_texture(tex); if (tex->usage_flags & TEXTURE_USAGE_CPU_READ_BIT) { @@ -2141,6 +2147,9 @@ Error RenderingDevice::texture_get_data_async(RID p_texture, uint32_t p_layer, c ERR_FAIL_COND_V_MSG(!(tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), ERR_INVALID_PARAMETER, "Texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT` to be set to be retrieved."); ERR_FAIL_COND_V(p_layer >= tex->layers, ERR_INVALID_PARAMETER); + // Clear the texture if the driver requires it during its first use. + _texture_check_pending_clear(p_texture, tex); + _check_transfer_worker_texture(tex); thread_local LocalVector mip_layouts; @@ -2350,6 +2359,10 @@ Error RenderingDevice::texture_copy(RID p_from_texture, RID p_to_texture, const ERR_FAIL_COND_V_MSG(src_tex->read_aspect_flags != dst_tex->read_aspect_flags, ERR_INVALID_PARAMETER, "Source and destination texture must be of the same type (color or depth)."); + // Clear the textures if the driver requires it during its first use. + _texture_check_pending_clear(p_from_texture, src_tex); + _texture_check_pending_clear(p_to_texture, dst_tex); + _check_transfer_worker_texture(src_tex); _check_transfer_worker_texture(dst_tex); @@ -2417,6 +2430,10 @@ Error RenderingDevice::texture_resolve_multisample(RID p_from_texture, RID p_to_ // Indicate the texture will get modified for the shared texture fallback. _texture_update_shared_fallback(p_to_texture, dst_tex, true); + // Clear the textures if the driver requires it during its first use. + _texture_check_pending_clear(p_from_texture, src_tex); + _texture_check_pending_clear(p_to_texture, dst_tex); + _check_transfer_worker_texture(src_tex); _check_transfer_worker_texture(dst_tex); @@ -2476,6 +2493,9 @@ Error RenderingDevice::texture_clear(RID p_texture, const Color &p_color, uint32 ERR_FAIL_COND_V(p_base_mipmap + p_mipmaps > src_tex->mipmaps, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_base_layer + p_layers > src_tex->layers, ERR_INVALID_PARAMETER); + // Clear the texture if the driver requires it during its first use. + _texture_check_pending_clear(p_texture, src_tex); + _texture_clear(p_texture, src_tex, p_color, p_base_mipmap, p_mipmaps, p_base_layer, p_layers); return OK; From 967e028d6c3089bcb7658449642726b7ea3ed4d7 Mon Sep 17 00:00:00 2001 From: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Mon, 5 Jan 2026 11:16:20 +0300 Subject: [PATCH 17/44] Remove amplification & mesh shader deny flags on D3D12. (cherry picked from commit e631fce422bd508047c3ab6813ae38d4e53cc412) --- drivers/d3d12/rendering_shader_container_d3d12.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/d3d12/rendering_shader_container_d3d12.cpp b/drivers/d3d12/rendering_shader_container_d3d12.cpp index 8b0a65a508ca..a951393f272b 100644 --- a/drivers/d3d12/rendering_shader_container_d3d12.cpp +++ b/drivers/d3d12/rendering_shader_container_d3d12.cpp @@ -615,9 +615,7 @@ bool RenderingShaderContainerD3D12::_generate_root_signature(BitField Date: Wed, 13 Aug 2025 09:28:06 +0200 Subject: [PATCH 18/44] Fix spotlight's shadow with volumetric fog (cherry picked from commit 199161f02334ba84f071409a8d1a479a95cea458) --- .../renderer_rd/shaders/environment/volumetric_fog_process.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl index d2122e0a3489..47c991292f37 100644 --- a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl @@ -559,7 +559,7 @@ void main() { vec4 v = vec4(view_pos, 1.0); vec4 splane = (spot_lights.data[light_index].shadow_matrix * v); - splane.z -= spot_lights.data[light_index].shadow_bias / (d * spot_lights.data[light_index].inv_radius); + splane.z -= spot_lights.data[light_index].shadow_bias; splane /= splane.w; vec3 pos = vec3(splane.xy * spot_lights.data[light_index].atlas_rect.zw + spot_lights.data[light_index].atlas_rect.xy, splane.z); From 7e50ad1a8e7983f30140550601eb21de5bc85406 Mon Sep 17 00:00:00 2001 From: Alex Threlfo Date: Tue, 2 Sep 2025 09:36:40 +1000 Subject: [PATCH 19/44] Fix rounding error in clustered vertex light culling (cherry picked from commit 60a7bed19cefa2c04af3e3eeaaaa92935a2ef924) --- .../shaders/forward_clustered/scene_forward_clustered.glsl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index 170aa77a430e..6b54067568f4 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl @@ -529,7 +529,9 @@ void vertex_shader(vec3 vertex_input, vec2 clip_pos = clamp((gl_Position.xy / gl_Position.w) * 0.5 + 0.5, 0.0, 1.0); #endif - uvec2 cluster_pos = uvec2(clip_pos / scene_data.screen_pixel_size) >> implementation_data.cluster_shift; + uvec2 screen_size = uvec2(1.0 / scene_data.screen_pixel_size); + uvec2 screen_pixel = clamp(uvec2(clip_pos * vec2(screen_size)), uvec2(0), screen_size - uvec2(1)); + uvec2 cluster_pos = screen_pixel >> implementation_data.cluster_shift; uint cluster_offset = (implementation_data.cluster_width * cluster_pos.y + cluster_pos.x) * (implementation_data.max_cluster_element_count_div_32 + 32); uint cluster_z = uint(clamp((-vertex_interp.z / scene_data.z_far) * 32.0, 0.0, 31.0)); From efdf224f87c35068ae64475397767915370f1916 Mon Sep 17 00:00:00 2001 From: Luo Zhihao Date: Thu, 4 Sep 2025 19:15:16 +0800 Subject: [PATCH 20/44] Fix `CompositorEffect` not setting post-transparent callback on init (cherry picked from commit d9d796618deec066b9624acd1101280419b5018f) --- scene/resources/compositor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scene/resources/compositor.cpp b/scene/resources/compositor.cpp index d9fdb93c5d32..40c7e7626c69 100644 --- a/scene/resources/compositor.cpp +++ b/scene/resources/compositor.cpp @@ -186,7 +186,7 @@ CompositorEffect::CompositorEffect() { RenderingServer *rs = RenderingServer::get_singleton(); if (rs != nullptr) { rid = rs->compositor_effect_create(); - rs->compositor_effect_set_callback(rid, RenderingServer::CompositorEffectCallbackType(effect_callback_type), Callable(this, "_render_callback")); + rs->compositor_effect_set_callback(rid, RenderingServer::CompositorEffectCallbackType(effect_callback_type), callable_mp(this, &CompositorEffect::_call_render_callback)); } } From 1e01637db170e83e1558cbbf4432b318d46332ee Mon Sep 17 00:00:00 2001 From: Bastiaan Olij Date: Thu, 11 Sep 2025 20:53:19 +1000 Subject: [PATCH 21/44] Fix fixed size flag on StandardMaterial3D when rendering in stereo (cherry picked from commit 748f35ccb87f8382c5b49c9189798b339ff4fde8) --- scene/resources/material.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index cd42fd1e0642..a26d604bd789 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -1357,7 +1357,7 @@ void vertex() {)"; if (flags[FLAG_FIXED_SIZE]) { code += R"( // Fixed Size: Enabled - if (PROJECTION_MATRIX[3][3] != 0.0) { + if (PROJECTION_MATRIX[2][3] == 0.0) { // Orthogonal matrix; try to do about the same with viewport size. float h = abs(1.0 / (2.0 * PROJECTION_MATRIX[1][1])); // Consistent with vertical FOV (Keep Height). @@ -1367,7 +1367,7 @@ void vertex() {)"; MODELVIEW_MATRIX[2] *= sc; } else { // Scale by depth. - float sc = -(MODELVIEW_MATRIX)[3].z; + float sc = length((MODELVIEW_MATRIX)[3].xyz); MODELVIEW_MATRIX[0] *= sc; MODELVIEW_MATRIX[1] *= sc; MODELVIEW_MATRIX[2] *= sc; From b1d1a2e76a6b0cd12f3a363bb8c86dce1e5d32ba Mon Sep 17 00:00:00 2001 From: Kaleb Reid <78945904+Kaleb-Reid@users.noreply.github.com> Date: Wed, 24 Sep 2025 22:37:28 -0700 Subject: [PATCH 22/44] Use correct AABB for SpotLight3Ds when spot_angle > 90 (cherry picked from commit 91167c3c23201226df7ab10b5c64225495de1205) --- drivers/gles3/storage/light_storage.cpp | 9 ++++++++- .../rendering/renderer_rd/storage_rd/light_storage.cpp | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp index f58f769b3e46..75dbd8869da7 100644 --- a/drivers/gles3/storage/light_storage.cpp +++ b/drivers/gles3/storage/light_storage.cpp @@ -350,7 +350,14 @@ AABB LightStorage::light_get_aabb(RID p_light) const { switch (light->type) { case RS::LIGHT_SPOT: { float len = light->param[RS::LIGHT_PARAM_RANGE]; - float size = Math::tan(Math::deg_to_rad(light->param[RS::LIGHT_PARAM_SPOT_ANGLE])) * len; + float angle = Math::deg_to_rad(light->param[RS::LIGHT_PARAM_SPOT_ANGLE]); + + if (angle > Math::PI * 0.5) { + // Light casts backwards as well. + return AABB(Vector3(-1, -1, -1) * len, Vector3(2, 2, 2) * len); + } + + float size = Math::sin(angle) * len; return AABB(Vector3(-size, -size, -len), Vector3(size * 2, size * 2, len)); }; case RS::LIGHT_OMNI: { diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp index 8f319d430aa2..8ef316927df8 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp @@ -432,7 +432,14 @@ AABB LightStorage::light_get_aabb(RID p_light) const { switch (light->type) { case RS::LIGHT_SPOT: { float len = light->param[RS::LIGHT_PARAM_RANGE]; - float size = Math::tan(Math::deg_to_rad(light->param[RS::LIGHT_PARAM_SPOT_ANGLE])) * len; + float angle = Math::deg_to_rad(light->param[RS::LIGHT_PARAM_SPOT_ANGLE]); + + if (angle > Math::PI * 0.5) { + // Light casts backwards as well. + return AABB(Vector3(-1, -1, -1) * len, Vector3(2, 2, 2) * len); + } + + float size = Math::sin(angle) * len; return AABB(Vector3(-size, -size, -len), Vector3(size * 2, size * 2, len)); }; case RS::LIGHT_OMNI: { From 1b7d50912756e19002e1038403ffff7fd14dbd77 Mon Sep 17 00:00:00 2001 From: Kaleb Reid <78945904+Kaleb-Reid@users.noreply.github.com> Date: Thu, 25 Sep 2025 16:37:57 -0700 Subject: [PATCH 23/44] Clear intermediate buffers when not in use in Compatibility (cherry picked from commit a88c54a5c7dd80774f18361314f89ebcffa159a7) --- drivers/gles3/storage/render_scene_buffers_gles3.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.cpp b/drivers/gles3/storage/render_scene_buffers_gles3.cpp index 1ad5dc6bcbad..e0a426de9b2b 100644 --- a/drivers/gles3/storage/render_scene_buffers_gles3.cpp +++ b/drivers/gles3/storage/render_scene_buffers_gles3.cpp @@ -200,6 +200,10 @@ void RenderSceneBuffersGLES3::_check_render_buffers() { uint32_t depth_format_size = 4; bool use_multiview = view_count > 1; + if (!use_internal_buffer && internal3d.color != 0) { + _clear_intermediate_buffers(); + } + if ((!use_internal_buffer || internal3d.color != 0) && (msaa3d.mode == RS::VIEWPORT_MSAA_DISABLED || msaa3d.color != 0)) { // already setup! return; From 152fa5b328018c6cd9d831007219b69e8dee06dd Mon Sep 17 00:00:00 2001 From: Kaleb Reid <78945904+Kaleb-Reid@users.noreply.github.com> Date: Wed, 24 Sep 2025 00:40:37 -0700 Subject: [PATCH 24/44] Ensure reflection atlas is valid before rendering (cherry picked from commit f2d0ea6d40cd1c3b1113ddf4f651e458b01cc609) --- drivers/gles3/storage/light_storage.cpp | 3 +++ servers/rendering/renderer_rd/storage_rd/light_storage.cpp | 3 +++ servers/rendering_server.cpp | 6 +++--- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp index 75dbd8869da7..767dd86c3223 100644 --- a/drivers/gles3/storage/light_storage.cpp +++ b/drivers/gles3/storage/light_storage.cpp @@ -814,6 +814,9 @@ bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_ ERR_FAIL_NULL_V(atlas, false); + ERR_FAIL_COND_V_MSG(atlas->size < 4, false, "Attempted to render to a reflection atlas of invalid resolution."); + ERR_FAIL_COND_V_MSG(atlas->count < 1, false, "Attempted to render to a reflection atlas of size < 1."); + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); ERR_FAIL_NULL_V(rpi, false); diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp index 8ef316927df8..39dbe5b870a6 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp @@ -1493,6 +1493,9 @@ bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_ ERR_FAIL_NULL_V(atlas, false); + ERR_FAIL_COND_V_MSG(atlas->size < 2, false, "Attempted to render to a reflection atlas of invalid resolution."); + ERR_FAIL_COND_V_MSG(atlas->count < 1, false, "Attempted to render to a reflection atlas of size < 1."); + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); ERR_FAIL_NULL_V(rpi, false); diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 8202dff8cbe2..cfb7ea71c4c7 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -3648,9 +3648,9 @@ void RenderingServer::init() { GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/reflections/sky_reflections/ggx_samples", PROPERTY_HINT_RANGE, "0,256,1"), 32); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/reflections/sky_reflections/ggx_samples.mobile", PROPERTY_HINT_RANGE, "0,128,1"), 16); GLOBAL_DEF("rendering/reflections/sky_reflections/fast_filter_high_quality", false); - GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/reflections/reflection_atlas/reflection_size", PROPERTY_HINT_RANGE, "0,4096,1"), 256); - GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/reflections/reflection_atlas/reflection_size.mobile", PROPERTY_HINT_RANGE, "0,2048,1"), 128); - GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/reflections/reflection_atlas/reflection_count", PROPERTY_HINT_RANGE, "0,256,1"), 64); + GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/reflections/reflection_atlas/reflection_size", PROPERTY_HINT_RANGE, "4,4096,1"), 256); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/reflections/reflection_atlas/reflection_size.mobile", PROPERTY_HINT_RANGE, "4,2048,1"), 128); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/reflections/reflection_atlas/reflection_count", PROPERTY_HINT_RANGE, "1,256,1"), 64); GLOBAL_DEF_RST("rendering/reflections/specular_occlusion/enabled", true); GLOBAL_DEF("rendering/global_illumination/gi/use_half_resolution", false); From b97b2cca5e8c37595e15ec97ca801a8e10002f06 Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Thu, 9 Oct 2025 10:56:01 +0100 Subject: [PATCH 25/44] FTI - Fix `SceneTreeFTI` depth limit behaviour Fixes off by one bug, and increases the limit slightly. (cherry picked from commit cee37f0234329444271fb5f8371f3de8c8fe7579) --- scene/main/scene_tree_fti.cpp | 2 +- scene/main/scene_tree_fti.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scene/main/scene_tree_fti.cpp b/scene/main/scene_tree_fti.cpp index c7503e1610f6..7ac6266beaf7 100644 --- a/scene/main/scene_tree_fti.cpp +++ b/scene/main/scene_tree_fti.cpp @@ -286,7 +286,7 @@ void SceneTreeFTI::_create_depth_lists() { // This shouldn't happen, but wouldn't be terrible if it did. DEV_ASSERT(depth >= 0); - depth = MIN(depth, (int32_t)data.scene_tree_depth_limit); + depth = MIN(depth, (int32_t)data.scene_tree_depth_limit - 1); LocalVector &dest_list = data.dirty_node_depth_lists[depth]; #ifdef GODOT_SCENE_TREE_FTI_EXTRA_CHECKS diff --git a/scene/main/scene_tree_fti.h b/scene/main/scene_tree_fti.h index cdea9be1b8b6..9997ff8cfc01 100644 --- a/scene/main/scene_tree_fti.h +++ b/scene/main/scene_tree_fti.h @@ -77,7 +77,7 @@ class SceneTreeFTI { }; struct Data { - static const uint32_t scene_tree_depth_limit = 32; + static const uint32_t scene_tree_depth_limit = 48; // Prev / Curr lists of Node3Ds having local xforms pumped. LocalVector tick_xform_list[2]; From 1100fc4516b7c28abb180eb4b0a304cc4029afea Mon Sep 17 00:00:00 2001 From: Kaleb Reid <78945904+Kaleb-Reid@users.noreply.github.com> Date: Tue, 14 Oct 2025 13:44:09 -0700 Subject: [PATCH 26/44] Use correct shadow material in some cases in Mobile (cherry picked from commit 8a8bd02860a3f240dd294ae3a603cf9107519e07) --- .../renderer_rd/forward_mobile/scene_shader_forward_mobile.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h index 98ab09a1629b..cc78121192e3 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h @@ -290,7 +290,8 @@ class SceneShaderForwardMobile { } _FORCE_INLINE_ bool uses_shared_shadow_material() const { - return !uses_particle_trails && !writes_modelview_or_projection && !uses_vertex && !uses_discard && !uses_depth_prepass_alpha && !uses_alpha_clip && !uses_alpha_antialiasing && !uses_world_coordinates && !wireframe && !stencil_enabled; + bool backface_culling = cull_mode == RS::CULL_MODE_BACK; + return !uses_particle_trails && !writes_modelview_or_projection && !uses_vertex && !uses_discard && !uses_depth_prepass_alpha && !uses_alpha_clip && !uses_alpha_antialiasing && !uses_point_size && !uses_world_coordinates && !wireframe && !stencil_enabled && backface_culling; } virtual void set_code(const String &p_Code); From 06acb82e1638f9061db7ae85127f8078e7ddb4a3 Mon Sep 17 00:00:00 2001 From: Ben Botwin Date: Thu, 16 Oct 2025 17:26:48 -0400 Subject: [PATCH 27/44] fixes the lods array returned by mesh_get_surface (cherry picked from commit 761312304802ec4d541ce6bbbb764376d8a29c97) --- servers/rendering_server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index cfb7ea71c4c7..93655d5a45d2 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2034,7 +2034,7 @@ Dictionary RenderingServer::_mesh_get_surface(RID p_mesh, int p_idx) { Dictionary ld; ld["edge_length"] = sd.lods[i].edge_length; ld["index_data"] = sd.lods[i].index_data; - lods.push_back(lods); + lods.push_back(ld); } d["lods"] = lods; } From bde8a7d70536d1179790583a819b4f8aff405c61 Mon Sep 17 00:00:00 2001 From: Kaleb Reid <78945904+Kaleb-Reid@users.noreply.github.com> Date: Wed, 8 Oct 2025 14:48:15 -0700 Subject: [PATCH 28/44] Use correct ndc for proximity fade in Compatibility (cherry picked from commit 43c03e224a4e1175309d1a3df94092269eedde3c) --- scene/resources/material.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index a26d604bd789..cb53dd61eb92 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -1841,7 +1841,8 @@ void fragment() {)"; code += R"( // Proximity Fade: Enabled float proximity_depth_tex = textureLod(depth_texture, SCREEN_UV, 0.0).r; - vec4 proximity_view_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, proximity_depth_tex, 1.0); + vec4 ndc = OUTPUT_IS_SRGB ? vec4(vec3(SCREEN_UV, proximity_depth_tex) * 2.0 - 1.0, 1.0) : vec4(SCREEN_UV * 2.0 - 1.0, proximity_depth_tex, 1.0); + vec4 proximity_view_pos = INV_PROJECTION_MATRIX * ndc; proximity_view_pos.xyz /= proximity_view_pos.w; ALPHA *= clamp(1.0 - smoothstep(proximity_view_pos.z + proximity_fade_distance, proximity_view_pos.z, VERTEX.z), 0.0, 1.0); )"; From 747f69f921bdcf923e3bf36e9f75194da63a13c5 Mon Sep 17 00:00:00 2001 From: Skorpnok <6632336+skorpnok@users.noreply.github.com> Date: Tue, 18 Nov 2025 20:37:25 +0100 Subject: [PATCH 29/44] Fix missing mipmaps for RB_TEX_BACK_COLOR (cherry picked from commit 94f433ccf625bf11ca368f7d91c4c438589e9e82) --- .../rendering/renderer_rd/renderer_scene_render_rd.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index f21815b303a9..a773672de2d1 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -335,9 +335,13 @@ void RendererSceneRenderRD::_render_buffers_ensure_screen_texture(const RenderDa if (reuse_blur_texture) { rb->allocate_blur_textures(); } else { - uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; - usage_bits |= can_use_storage ? RD::TEXTURE_USAGE_STORAGE_BIT : RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; - rb->create_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_COLOR, rb->get_base_data_format(), usage_bits); + if (!rb->has_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_COLOR)) { + uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + usage_bits |= can_use_storage ? RD::TEXTURE_USAGE_STORAGE_BIT : RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + // This needs to have mipmaps if any shader needs textureLod to work on screen_texture + uint32_t mipmaps_required = Image::get_image_required_mipmaps(size.x, size.y, Image::FORMAT_RGBAH); + rb->create_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_COLOR, rb->get_base_data_format(), usage_bits, RenderingDeviceCommons::TEXTURE_SAMPLES_1, { 0, 0 }, 0U, mipmaps_required); + } } } From 3eea4156bce78fc05825e9e9bffeabe313596996 Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Fri, 21 Jun 2024 18:34:26 +0200 Subject: [PATCH 30/44] Use Viewport's 3D Scaling in the 3D editor's Half Resolution option This removes the reliance on Viewport shrinking, which fixes various bugs with mouse input handling in 3D gizmos or the GridMap editor. This also makes Half Resolution make use of the current 3D scaling mode defined in the project setting (bilinear, FSR1 or FSR2). When Half Resolution is checked, the Scaling 3D Scale value in the project settings is halved in the editor. To ensure the 3D view remaisn somewhat readable, the final value can't go below the minimum value allowed in the project settings, which is 0.25. (cherry picked from commit 54a6e6784c982819bf8c585c5a912e3b60553c4a) --- editor/scene/3d/node_3d_editor_plugin.cpp | 28 ++++++++++------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/editor/scene/3d/node_3d_editor_plugin.cpp b/editor/scene/3d/node_3d_editor_plugin.cpp index 7415c9125000..a4bfc291feb1 100644 --- a/editor/scene/3d/node_3d_editor_plugin.cpp +++ b/editor/scene/3d/node_3d_editor_plugin.cpp @@ -703,9 +703,9 @@ void Node3DEditorViewport::cancel_transform() { } void Node3DEditorViewport::_update_shrink() { - bool shrink = view_display_menu->get_popup()->is_item_checked(view_display_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION)); - subviewport_container->set_stretch_shrink(shrink ? 2 : 1); - subviewport_container->set_texture_filter(shrink ? TEXTURE_FILTER_NEAREST : TEXTURE_FILTER_PARENT_NODE); + const float scaling_3d_scale = GLOBAL_GET("rendering/scaling_3d/scale"); + const float shrink_factor = view_display_menu->get_popup()->is_item_checked(view_display_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION)) ? 0.5 : 1.0; + viewport->set_scaling_3d_scale(MAX(0.25, scaling_3d_scale * shrink_factor)); } float Node3DEditorViewport::get_znear() const { @@ -729,11 +729,11 @@ Vector3 Node3DEditorViewport::_get_camera_position() const { } Point2 Node3DEditorViewport::point_to_screen(const Vector3 &p_point) { - return camera->unproject_position(p_point) * subviewport_container->get_stretch_shrink(); + return camera->unproject_position(p_point); } Vector3 Node3DEditorViewport::get_ray_pos(const Vector2 &p_pos) const { - return camera->project_ray_origin(p_pos / subviewport_container->get_stretch_shrink()); + return camera->project_ray_origin(p_pos); } Vector3 Node3DEditorViewport::_get_camera_normal() const { @@ -741,7 +741,7 @@ Vector3 Node3DEditorViewport::_get_camera_normal() const { } Vector3 Node3DEditorViewport::get_ray(const Vector2 &p_pos) const { - return camera->project_ray_normal(p_pos / subviewport_container->get_stretch_shrink()); + return camera->project_ray_normal(p_pos); } void Node3DEditorViewport::_clear_selected() { @@ -826,7 +826,7 @@ void Node3DEditorViewport::_select_clicked(bool p_allow_locked) { ObjectID Node3DEditorViewport::_select_ray(const Point2 &p_pos) const { Vector3 ray = get_ray(p_pos); Vector3 pos = get_ray_pos(p_pos); - Vector2 shrinked_pos = p_pos / subviewport_container->get_stretch_shrink(); + Vector2 shrinked_pos = p_pos; if (viewport->get_debug_draw() == Viewport::DEBUG_DRAW_SDFGI_PROBES) { RS::get_singleton()->sdfgi_set_debug_probe_select(pos, ray); @@ -2985,8 +2985,6 @@ void Node3DEditorViewport::_project_settings_changed() { viewport->set_positional_shadow_atlas_quadrant_subdiv(2, Viewport::PositionalShadowAtlasQuadrantSubdiv(atlas_q2)); viewport->set_positional_shadow_atlas_quadrant_subdiv(3, Viewport::PositionalShadowAtlasQuadrantSubdiv(atlas_q3)); - _update_shrink(); - // Update MSAA, screen-space AA and debanding if changed const int msaa_mode = GLOBAL_GET("rendering/anti_aliasing/quality/msaa_3d"); @@ -3014,8 +3012,7 @@ void Node3DEditorViewport::_project_settings_changed() { const Viewport::Scaling3DMode scaling_3d_mode = Viewport::Scaling3DMode(int(GLOBAL_GET("rendering/scaling_3d/mode"))); viewport->set_scaling_3d_mode(scaling_3d_mode); - const float scaling_3d_scale = GLOBAL_GET("rendering/scaling_3d/scale"); - viewport->set_scaling_3d_scale(scaling_3d_scale); + _update_shrink(); const float fsr_sharpness = GLOBAL_GET("rendering/scaling_3d/fsr_sharpness"); viewport->set_fsr_sharpness(fsr_sharpness); @@ -3259,7 +3256,7 @@ void Node3DEditorViewport::_notification(int p_what) { } if (show_info) { - const String viewport_size = vformat(U"%d × %d", viewport->get_size().x, viewport->get_size().y); + const String viewport_size = vformat(U"%d × %d", viewport->get_size().x * viewport->get_scaling_3d_scale(), viewport->get_size().y * viewport->get_scaling_3d_scale()); String text; text += vformat(TTR("X: %s\n"), rtos(current_camera->get_position().x).pad_decimals(1)); text += vformat(TTR("Y: %s\n"), rtos(current_camera->get_position().y).pad_decimals(1)); @@ -3268,7 +3265,7 @@ void Node3DEditorViewport::_notification(int p_what) { text += vformat( TTR("Size: %s (%.1fMP)\n"), viewport_size, - viewport->get_size().x * viewport->get_size().y * 0.000001); + viewport->get_size().x * viewport->get_size().y * Math::pow(viewport->get_scaling_3d_scale(), 2) * 0.000001); text += "\n"; text += vformat(TTR("Objects: %d\n"), viewport->get_render_info(Viewport::RENDER_INFO_TYPE_VISIBLE, Viewport::RENDER_INFO_OBJECTS_IN_FRAME)); @@ -4279,8 +4276,7 @@ void Node3DEditorViewport::update_transform_gizmo_view() { const int viewport_base_height = 400 * MAX(1, EDSCALE); gizmo_scale = (gizmo_size / Math::abs(dd)) * MAX(1, EDSCALE) * - MIN(viewport_base_height, subviewport_container->get_size().height) / viewport_base_height / - subviewport_container->get_stretch_shrink(); + MIN(viewport_base_height, subviewport_container->get_size().height) / viewport_base_height; Vector3 scale = Vector3(1, 1, 1) * gizmo_scale; // if the determinant is zero, we should disable the gizmo from being rendered @@ -4512,7 +4508,7 @@ Dictionary Node3DEditorViewport::get_state() const { d["grid"] = view_display_menu->get_popup()->is_item_checked(view_display_menu->get_popup()->get_item_index(VIEW_GRID)); d["information"] = view_display_menu->get_popup()->is_item_checked(view_display_menu->get_popup()->get_item_index(VIEW_INFORMATION)); d["frame_time"] = view_display_menu->get_popup()->is_item_checked(view_display_menu->get_popup()->get_item_index(VIEW_FRAME_TIME)); - d["half_res"] = subviewport_container->get_stretch_shrink() > 1; + d["half_res"] = view_display_menu->get_popup()->is_item_checked(view_display_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION)); d["cinematic_preview"] = view_display_menu->get_popup()->is_item_checked(view_display_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW)); if (previewing) { d["previewing"] = EditorNode::get_singleton()->get_edited_scene()->get_path_to(previewing); From bbba6f177042428af7eef1862ddd5ced347aa94b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20D=C3=B6hl?= Date: Tue, 2 Dec 2025 09:04:19 +0100 Subject: [PATCH 31/44] set shader path before compilation (cherry picked from commit 772caa8170121f69302486db12a0a4477abd3d72) --- drivers/gles3/storage/material_storage.cpp | 1 + servers/rendering/rendering_server_default.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp index 565678479387..747c45d84124 100644 --- a/drivers/gles3/storage/material_storage.cpp +++ b/drivers/gles3/storage/material_storage.cpp @@ -2265,6 +2265,7 @@ void MaterialStorage::shader_set_code(RID p_shader, const String &p_code) { } if (shader->data) { + shader->data->set_path_hint(shader->path_hint); shader->data->set_code(p_code); } diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 3c198652b23b..d78cc7b7ff28 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -263,8 +263,8 @@ class RenderingServerDefault : public RenderingServer { } RSG::material_storage->shader_initialize(shader, false); - RSG::material_storage->shader_set_code(shader, p_code); RSG::material_storage->shader_set_path_hint(shader, p_path_hint); + RSG::material_storage->shader_set_code(shader, p_code); } else { command_queue.push(RSG::material_storage, &RendererMaterialStorage::shader_initialize, shader, false); command_queue.push(RSG::material_storage, &RendererMaterialStorage::shader_set_code, shader, p_code); From f25f3e59841f1c1b9b1a65ba7a5ade12332ebcaf Mon Sep 17 00:00:00 2001 From: Thomas ten Cate Date: Wed, 3 Dec 2025 09:08:31 +0100 Subject: [PATCH 32/44] Use AABB center instead of origin for visibility fade Fixes #79471 Fixes #102799 (cherry picked from commit c2bc0afa3554407aeb003708eb1a08fe4bd9f0af) --- .../renderer_rd/forward_clustered/render_forward_clustered.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 3fe0542bd4d5..9be147caa1f0 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -931,7 +931,7 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con float fade_alpha = 1.0; if (inst->fade_near || inst->fade_far) { - float fade_dist = inst->transform.origin.distance_to(p_render_data->scene_data->cam_transform.origin); + float fade_dist = inst->transformed_aabb.get_center().distance_to(p_render_data->scene_data->cam_transform.origin); // Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player. if (inst->fade_far && fade_dist > inst->fade_far_begin) { fade_alpha = Math::smoothstep(0.0f, 1.0f, 1.0f - (fade_dist - inst->fade_far_begin) / (inst->fade_far_end - inst->fade_far_begin)); From f0d07eff4882a23afc3f7e89e7875d48539f0135 Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Tue, 4 Nov 2025 00:25:08 +0100 Subject: [PATCH 33/44] Disable shader baker when exporting as dedicated server Dedicated server exports don't perform any rendering, so there's no point in including baked shaders. Doing so saves a few MBs in PCK size if the shader baker was enabled in the export options. (cherry picked from commit 09f9dc157acd38df2a41a448ae16255d5ff975ce) --- editor/export/editor_export_platform_apple_embedded.cpp | 3 ++- editor/export/editor_export_platform_pc.cpp | 3 ++- platform/android/doc_classes/EditorExportPlatformAndroid.xml | 1 + platform/android/export/export_plugin.cpp | 3 ++- platform/ios/doc_classes/EditorExportPlatformIOS.xml | 1 + platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml | 1 + platform/macos/doc_classes/EditorExportPlatformMacOS.xml | 1 + platform/macos/export/export_plugin.cpp | 3 ++- platform/visionos/doc_classes/EditorExportPlatformVisionOS.xml | 1 + platform/windows/doc_classes/EditorExportPlatformWindows.xml | 1 + 10 files changed, 14 insertions(+), 4 deletions(-) diff --git a/editor/export/editor_export_platform_apple_embedded.cpp b/editor/export/editor_export_platform_apple_embedded.cpp index 02c7f9334407..29de9267c973 100644 --- a/editor/export/editor_export_platform_apple_embedded.cpp +++ b/editor/export/editor_export_platform_apple_embedded.cpp @@ -52,7 +52,8 @@ void EditorExportPlatformAppleEmbedded::get_preset_features(const Refpush_back("etc2"); r_features->push_back("astc"); - if (p_preset->get("shader_baker/enabled")) { + if (!p_preset->is_dedicated_server() && p_preset->get("shader_baker/enabled")) { + // Don't use the shader baker if exporting as a dedicated server, as no rendering is performed. r_features->push_back("shader_baker"); } diff --git a/editor/export/editor_export_platform_pc.cpp b/editor/export/editor_export_platform_pc.cpp index 2a2983d4337e..9ad8acce5657 100644 --- a/editor/export/editor_export_platform_pc.cpp +++ b/editor/export/editor_export_platform_pc.cpp @@ -42,7 +42,8 @@ void EditorExportPlatformPC::get_preset_features(const Ref & r_features->push_back("etc2"); r_features->push_back("astc"); } - if (p_preset->get("shader_baker/enabled")) { + if (!p_preset->is_dedicated_server() && p_preset->get("shader_baker/enabled")) { + // Don't use the shader baker if exporting as a dedicated server, as no rendering is performed. r_features->push_back("shader_baker"); } // PC platforms only have one architecture per export, since diff --git a/platform/android/doc_classes/EditorExportPlatformAndroid.xml b/platform/android/doc_classes/EditorExportPlatformAndroid.xml index a6b392610bfe..5db594d09763 100644 --- a/platform/android/doc_classes/EditorExportPlatformAndroid.xml +++ b/platform/android/doc_classes/EditorExportPlatformAndroid.xml @@ -627,6 +627,7 @@ If [code]true[/code], shaders will be compiled and embedded in the application. This option is only supported when using the Forward+ or Mobile renderers. + [b]Note:[/b] When exporting as a dedicated server, the shader baker is always disabled since no rendering is performed. If [code]true[/code], allows the application to participate in the backup and restore infrastructure. diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 4bb7263db45d..0f8173b0b72d 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -1995,7 +1995,8 @@ void EditorExportPlatformAndroid::get_preset_features(const Refpush_back("etc2"); r_features->push_back("astc"); - if (p_preset->get("shader_baker/enabled")) { + if (!p_preset->is_dedicated_server() && p_preset->get("shader_baker/enabled")) { + // Don't use the shader baker if exporting as a dedicated server, as no rendering is performed. r_features->push_back("shader_baker"); } diff --git a/platform/ios/doc_classes/EditorExportPlatformIOS.xml b/platform/ios/doc_classes/EditorExportPlatformIOS.xml index e22850bc9a77..17388d1c9c9c 100644 --- a/platform/ios/doc_classes/EditorExportPlatformIOS.xml +++ b/platform/ios/doc_classes/EditorExportPlatformIOS.xml @@ -730,6 +730,7 @@ If [code]true[/code], shaders will be compiled and embedded in the application. This option is only supported when using the Forward+ or Mobile renderers. + [b]Note:[/b] When exporting as a dedicated server, the shader baker is always disabled since no rendering is performed. A custom background color of the storyboard launch screen. diff --git a/platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml b/platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml index 7425f49b1b60..3a7f086cb165 100644 --- a/platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml +++ b/platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml @@ -28,6 +28,7 @@ If [code]true[/code], shaders will be compiled and embedded in the application. This option is only supported when using the Forward+ or Mobile renderers. + [b]Note:[/b] When exporting as a dedicated server, the shader baker is always disabled since no rendering is performed. Script code to execute on the remote host when app is finished. diff --git a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml index 5b93a4a3c553..c14dc0dff8a3 100644 --- a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml +++ b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml @@ -699,6 +699,7 @@ If [code]true[/code], shaders will be compiled and embedded in the application. This option is only supported when using the Forward+ or Mobile renderers. + [b]Note:[/b] When exporting as a dedicated server, the shader baker is always disabled since no rendering is performed. Script code to execute on the remote host when app is finished. diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp index 25f3926ae3ac..d6e70244ae78 100644 --- a/platform/macos/export/export_plugin.cpp +++ b/platform/macos/export/export_plugin.cpp @@ -63,7 +63,8 @@ void EditorExportPlatformMacOS::get_preset_features(const Refget("shader_baker/enabled")) { + if (!p_preset->is_dedicated_server() && p_preset->get("shader_baker/enabled")) { + // Don't use the shader baker if exporting as a dedicated server, as no rendering is performed. r_features->push_back("shader_baker"); } diff --git a/platform/visionos/doc_classes/EditorExportPlatformVisionOS.xml b/platform/visionos/doc_classes/EditorExportPlatformVisionOS.xml index 255c46e2858e..36de17b94b3b 100644 --- a/platform/visionos/doc_classes/EditorExportPlatformVisionOS.xml +++ b/platform/visionos/doc_classes/EditorExportPlatformVisionOS.xml @@ -582,6 +582,7 @@ If [code]true[/code], shaders will be compiled and embedded in the application. This option is only supported when using the Forward+ and Mobile renderers. + [b]Note:[/b] When exporting as a dedicated server, the shader baker is always disabled since no rendering is performed. If [code]true[/code], the app "Documents" folder can be accessed via "Files" app. See [url=https://developer.apple.com/documentation/bundleresources/information_property_list/lssupportsopeningdocumentsinplace]LSSupportsOpeningDocumentsInPlace[/url]. diff --git a/platform/windows/doc_classes/EditorExportPlatformWindows.xml b/platform/windows/doc_classes/EditorExportPlatformWindows.xml index 3faf75bf3931..5c263d95a2a0 100644 --- a/platform/windows/doc_classes/EditorExportPlatformWindows.xml +++ b/platform/windows/doc_classes/EditorExportPlatformWindows.xml @@ -100,6 +100,7 @@ If [code]true[/code], shaders will be compiled and embedded in the application. This option is only supported when using the Forward+ and Mobile renderers. + [b]Note:[/b] When exporting as a dedicated server, the shader baker is always disabled since no rendering is performed. Script code to execute on the remote host when app is finished. From 2fd341e98dee258824faf5edc2eecabb4f8920cf Mon Sep 17 00:00:00 2001 From: Kaleb Reid <78945904+Kaleb-Reid@users.noreply.github.com> Date: Sun, 12 Oct 2025 23:21:21 -0700 Subject: [PATCH 34/44] Apply luminance multiplier in copy_cubemap_to_panorama (cherry picked from commit 8173f43770e9d83e67cd3488d506c85330a95c2d) --- servers/rendering/renderer_rd/effects/copy_effects.cpp | 2 ++ servers/rendering/renderer_rd/effects/copy_effects.h | 2 +- servers/rendering/renderer_rd/shaders/effects/copy.glsl | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp index a3a873a2d175..8c6d9f0691a1 100644 --- a/servers/rendering/renderer_rd/effects/copy_effects.cpp +++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp @@ -401,6 +401,8 @@ void CopyEffects::copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panoram copy.push_constant.target[1] = 0; copy.push_constant.camera_z_far = p_lod; + copy.push_constant.luminance_multiplier = prefer_raster_effects ? 2.0 : 1.0; + // setup our uniforms RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); diff --git a/servers/rendering/renderer_rd/effects/copy_effects.h b/servers/rendering/renderer_rd/effects/copy_effects.h index caf0e8466ae5..aaf83b3148e2 100644 --- a/servers/rendering/renderer_rd/effects/copy_effects.h +++ b/servers/rendering/renderer_rd/effects/copy_effects.h @@ -138,7 +138,7 @@ class CopyEffects { int32_t section[4]; int32_t target[2]; uint32_t flags; - uint32_t pad; + float luminance_multiplier; // Glow. float glow_strength; float glow_bloom; diff --git a/servers/rendering/renderer_rd/shaders/effects/copy.glsl b/servers/rendering/renderer_rd/shaders/effects/copy.glsl index debf6b736739..fa8e0590fc9c 100644 --- a/servers/rendering/renderer_rd/shaders/effects/copy.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/copy.glsl @@ -20,7 +20,7 @@ layout(push_constant, std430) uniform Params { ivec4 section; ivec2 target; uint flags; - uint pad; + float luminance_multiplier; // Glow. float glow_strength; float glow_bloom; @@ -276,7 +276,7 @@ void main() { #else vec4 color = textureLod(source_color, vec4(normal, params.camera_z_far), 0.0); //the biggest the lod the least the acne #endif - imageStore(dest_buffer, pos + params.target, color); + imageStore(dest_buffer, pos + params.target, color * params.luminance_multiplier); #endif // defined(MODE_CUBEMAP_TO_PANORAMA) || defined(MODE_CUBEMAP_ARRAY_TO_PANORAMA) #ifdef MODE_SET_COLOR From acb19dbd20100f26a582d9d1491b8043a635d1ae Mon Sep 17 00:00:00 2001 From: Wesley Clements Date: Tue, 16 Sep 2025 00:50:21 -0400 Subject: [PATCH 35/44] fixed tile map tiles displaying incorrectly based on visibility layer (cherry picked from commit 89503e387a0bf3799a91c01673068968f8fcea9e) --- servers/rendering/renderer_canvas_cull.cpp | 84 ++++++++++++---------- servers/rendering/renderer_canvas_cull.h | 2 +- 2 files changed, 48 insertions(+), 38 deletions(-) diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index 3b91bace7e1c..42ba93c0f2e5 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -107,50 +107,57 @@ void RendererCanvasCull::_render_canvas_item_tree(RID p_to_render_target, Canvas } } -void RendererCanvasCull::_collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, RendererCanvasCull::Item *p_material_owner, const Color &p_modulate, RendererCanvasCull::Item **r_items, int &r_index, int p_z) { +void RendererCanvasCull::_collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, RendererCanvasCull::Item *p_material_owner, const Color &p_modulate, RendererCanvasCull::Item **r_items, int &r_index, int &r_ysort_children_count, int p_z, uint32_t p_canvas_cull_mask) { int child_item_count = p_canvas_item->child_items.size(); RendererCanvasCull::Item **child_items = p_canvas_item->child_items.ptrw(); for (int i = 0; i < child_item_count; i++) { if (child_items[i]->visible) { - // To y-sort according to the item's final position, physics interpolation - // and transform snapping need to be applied before y-sorting. - Transform2D child_xform; - if (!_interpolation_data.interpolation_enabled || !child_items[i]->interpolated) { - child_xform = child_items[i]->xform_curr; - } else { - real_t f = Engine::get_singleton()->get_physics_interpolation_fraction(); - TransformInterpolator::interpolate_transform_2d(child_items[i]->xform_prev, child_items[i]->xform_curr, child_xform, f); - } + if (child_items[i]->visibility_layer & p_canvas_cull_mask) { + // To y-sort according to the item's final position, physics interpolation + // and transform snapping need to be applied before y-sorting. + Transform2D child_xform; + if (!_interpolation_data.interpolation_enabled || !child_items[i]->interpolated) { + child_xform = child_items[i]->xform_curr; + } else { + real_t f = Engine::get_singleton()->get_physics_interpolation_fraction(); + TransformInterpolator::interpolate_transform_2d(child_items[i]->xform_prev, child_items[i]->xform_curr, child_xform, f); + } - if (snapping_2d_transforms_to_pixel) { - child_xform.columns[2] = (child_xform.columns[2] + Point2(0.5, 0.5)).floor(); - } + if (snapping_2d_transforms_to_pixel) { + child_xform.columns[2] = (child_xform.columns[2] + Point2(0.5, 0.5)).floor(); + } - r_items[r_index] = child_items[i]; - child_items[i]->ysort_xform = p_canvas_item->ysort_xform * child_xform; - child_items[i]->material_owner = child_items[i]->use_parent_material ? p_material_owner : nullptr; - child_items[i]->ysort_modulate = p_modulate; - child_items[i]->ysort_index = r_index; - child_items[i]->ysort_parent_abs_z_index = p_z; - - if (!child_items[i]->repeat_source) { - child_items[i]->repeat_size = p_canvas_item->repeat_size; - child_items[i]->repeat_times = p_canvas_item->repeat_times; - child_items[i]->repeat_source_item = p_canvas_item->repeat_source_item; - } + r_items[r_index] = child_items[i]; + child_items[i]->ysort_xform = p_canvas_item->ysort_xform * child_xform; + child_items[i]->material_owner = child_items[i]->use_parent_material ? p_material_owner : nullptr; + child_items[i]->ysort_modulate = p_modulate; + child_items[i]->ysort_index = r_index; + child_items[i]->ysort_parent_abs_z_index = p_z; + + if (!child_items[i]->repeat_source) { + child_items[i]->repeat_size = p_canvas_item->repeat_size; + child_items[i]->repeat_times = p_canvas_item->repeat_times; + child_items[i]->repeat_source_item = p_canvas_item->repeat_source_item; + } - // Y sorted canvas items are flattened into r_items. Calculate their absolute z index to use when rendering r_items. - int abs_z = 0; - if (child_items[i]->z_relative) { - abs_z = CLAMP(p_z + child_items[i]->z_index, RS::CANVAS_ITEM_Z_MIN, RS::CANVAS_ITEM_Z_MAX); - } else { - abs_z = child_items[i]->z_index; - } + // Y sorted canvas items are flattened into r_items. Calculate their absolute z index to use when rendering r_items. + int abs_z = 0; + if (child_items[i]->z_relative) { + abs_z = CLAMP(p_z + child_items[i]->z_index, RS::CANVAS_ITEM_Z_MIN, RS::CANVAS_ITEM_Z_MAX); + } else { + abs_z = child_items[i]->z_index; + } - r_index++; + r_index++; - if (child_items[i]->sort_y) { - _collect_ysort_children(child_items[i], child_items[i]->use_parent_material ? p_material_owner : child_items[i], p_modulate * child_items[i]->modulate, r_items, r_index, abs_z); + if (child_items[i]->sort_y) { + _collect_ysort_children(child_items[i], child_items[i]->use_parent_material ? p_material_owner : child_items[i], p_modulate * child_items[i]->modulate, r_items, r_index, r_ysort_children_count, abs_z, p_canvas_cull_mask); + } + } else { + r_ysort_children_count--; + if (child_items[i]->sort_y) { + r_ysort_children_count -= child_items[i]->ysort_children_count; + } } } } @@ -164,7 +171,10 @@ int RendererCanvasCull::_count_ysort_children(RendererCanvasCull::Item *p_canvas if (child_items[i]->visible) { ysort_children_count++; if (child_items[i]->sort_y) { - ysort_children_count += _count_ysort_children(child_items[i]); + if (child_items[i]->ysort_children_count == -1) { + child_items[i]->ysort_children_count = _count_ysort_children(child_items[i]); + } + ysort_children_count += child_items[i]->ysort_children_count; } } } @@ -439,7 +449,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 ci->ysort_parent_abs_z_index = parent_z; child_items[0] = ci; int i = 1; - _collect_ysort_children(ci, p_material_owner, Color(1, 1, 1, 1), child_items, i, p_z); + _collect_ysort_children(ci, p_material_owner, Color(1, 1, 1, 1), child_items, i, child_item_count, p_z, p_canvas_cull_mask); SortArray sorter; sorter.sort(child_items, child_item_count); diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h index 1f01bbce11a2..c83fa1fb66ee 100644 --- a/servers/rendering/renderer_canvas_cull.h +++ b/servers/rendering/renderer_canvas_cull.h @@ -207,7 +207,7 @@ class RendererCanvasCull { void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, uint32_t p_canvas_cull_mask, RenderingMethod::RenderInfo *r_render_info = nullptr); void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_parent_xform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool p_is_already_y_sorted, uint32_t p_canvas_cull_mask, const Point2 &p_repeat_size, int p_repeat_times, RendererCanvasRender::Item *p_repeat_source_item); - void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, RendererCanvasCull::Item *p_material_owner, const Color &p_modulate, RendererCanvasCull::Item **r_items, int &r_index, int p_z); + void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, RendererCanvasCull::Item *p_material_owner, const Color &p_modulate, RendererCanvasCull::Item **r_items, int &r_index, int &r_ysort_children_count, int p_z, uint32_t p_canvas_cull_mask); int _count_ysort_children(RendererCanvasCull::Item *p_canvas_item); void _mark_ysort_dirty(RendererCanvasCull::Item *ysort_owner); From 190b6e198b087729a2ccf0e7a8c4c4917ef2460e Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Thu, 4 Sep 2025 00:33:24 +0200 Subject: [PATCH 36/44] Fix shader compilation errors in Compatibility when using `depth_texture` Globals were defined too early, which means some uniforms were not available at the point they were defined in. (cherry picked from commit dd8bab9f8908ba0c05c181bcde26d463b7c3a131) --- drivers/gles3/shaders/scene.glsl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 2814f41c3767..d99fd5563cc2 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -1022,12 +1022,6 @@ uniform highp mat4 world_transform; uniform highp uint instance_offset; uniform highp uint model_flags; -/* clang-format off */ - -#GLOBALS - -/* clang-format on */ - #define LIGHT_BAKE_DISABLED 0u #define LIGHT_BAKE_STATIC 1u #define LIGHT_BAKE_DYNAMIC 2u @@ -1268,6 +1262,12 @@ layout(location = 0) out vec4 frag_color; #endif // !RENDER_MATERIAL +/* clang-format off */ + +#GLOBALS + +/* clang-format on */ + vec3 F0(float metallic, float specular, vec3 albedo) { float dielectric = 0.16 * specular * specular; // use albedo * metallic as colored specular reflectance at 0 angle for metallic materials; From f3c380a7b62ccb40ccf29744f052fc8d45b4496e Mon Sep 17 00:00:00 2001 From: clayjohn Date: Fri, 14 Nov 2025 23:17:17 -0800 Subject: [PATCH 37/44] Apply PREMUL_ALPHA_FACTOR only in non-split-specular shader variants. This avoids a shader compile error when using SSS and PREMUL_ALPHA_FACTOR in the same shader. This doesn't change any functionaility, since in practive, the split-specular shader variant is only ever used for opaque objects while using premul alpha makes the object non-opaque (cherry picked from commit a7e1a65ca823d7e5f189d508792bcccd61929a08) --- .../forward_clustered/scene_forward_clustered.glsl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index 6b54067568f4..af1c6e7e41bb 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl @@ -2847,6 +2847,10 @@ void fragment_shader(in SceneData scene_data) { frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); #endif //!FOG_DISABLED +#if defined(PREMUL_ALPHA_USED) && !defined(MODE_RENDER_DEPTH) + frag_color.rgb *= premul_alpha; +#endif //PREMUL_ALPHA_USED + #endif //MODE_SEPARATE_SPECULAR #endif //MODE_RENDER_DEPTH @@ -2859,10 +2863,6 @@ void fragment_shader(in SceneData scene_data) { motion_vector = prev_position_uv - position_uv; #endif - -#if defined(PREMUL_ALPHA_USED) && !defined(MODE_RENDER_DEPTH) - frag_color.rgb *= premul_alpha; -#endif //PREMUL_ALPHA_USED } void main() { From 66f2e90629e552ab2fe1dda6745014df982a7fcc Mon Sep 17 00:00:00 2001 From: jitspoe Date: Sat, 15 Nov 2025 02:58:21 -0500 Subject: [PATCH 38/44] Fix shader baker freezing if there are errors in the shader compilation process. `tasks_processed` was not incrementing previously, so the packing was never considered "done". (cherry picked from commit b9d5c3e213f203b519b36ef4638293eb20817dde) --- editor/export/shader_baker_export_plugin.cpp | 38 +++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/editor/export/shader_baker_export_plugin.cpp b/editor/export/shader_baker_export_plugin.cpp index 9dc0f067a2ce..b1f86544e71d 100644 --- a/editor/export/shader_baker_export_plugin.cpp +++ b/editor/export/shader_baker_export_plugin.cpp @@ -426,23 +426,27 @@ void ShaderBakerExportPlugin::_process_work_item(WorkItem p_work_item) { if (!tasks_cancelled) { // Only process the item if the tasks haven't been cancelled by the user yet. Vector spirv_data = ShaderRD::compile_stages(p_work_item.stage_sources); - ERR_FAIL_COND_MSG(spirv_data.is_empty(), "Unable to retrieve SPIR-V data for shader"); - - RD::ShaderReflection shader_refl; - Error err = RenderingDeviceCommons::reflect_spirv(spirv_data, shader_refl); - ERR_FAIL_COND_MSG(err != OK, "Unable to reflect SPIR-V data that was compiled"); - - Ref shader_container = shader_container_format->create_container(); - shader_container->set_from_shader_reflection(p_work_item.shader_name, shader_refl); - - // Compile shader binary from SPIR-V. - bool code_compiled = shader_container->set_code_from_spirv(spirv_data); - ERR_FAIL_COND_MSG(!code_compiled, vformat("Failed to compile code to native for SPIR-V.")); - - PackedByteArray shader_bytes = shader_container->to_bytes(); - { - MutexLock lock(shader_work_results_mutex); - shader_work_results[p_work_item.cache_path].variant_data.ptrw()[p_work_item.variant] = shader_bytes; + if (unlikely(spirv_data.is_empty())) { + ERR_PRINT("Unable to retrieve SPIR-V data for shader."); + } else { + RD::ShaderReflection shader_refl; + Error err = RenderingDeviceCommons::reflect_spirv(spirv_data, shader_refl); + ERR_FAIL_COND_MSG(err != OK, "Unable to reflect SPIR-V data that was compiled"); + + Ref shader_container = shader_container_format->create_container(); + shader_container->set_from_shader_reflection(p_work_item.shader_name, shader_refl); + + // Compile shader binary from SPIR-V. + bool code_compiled = shader_container->set_code_from_spirv(spirv_data); + if (unlikely(!code_compiled)) { + ERR_PRINT("Failed to compile code to native for SPIR-V."); + } else { + PackedByteArray shader_bytes = shader_container->to_bytes(); + { + MutexLock lock(shader_work_results_mutex); + shader_work_results[p_work_item.cache_path].variant_data.ptrw()[p_work_item.variant] = shader_bytes; + } + } } } From 7b74d0da1f4a02a0ff139a13b6690857fa32db04 Mon Sep 17 00:00:00 2001 From: Jiang Yiheng Date: Sun, 29 Sep 2024 23:54:00 +0800 Subject: [PATCH 39/44] Fixed an issue where nodes' relative positions changed when opened in a different display scale. (cherry picked from commit dda1842b185ac4128cbe216feb68e12a94c3497f) --- editor/shader/visual_shader_editor_plugin.cpp | 8 +++++--- editor/shader/visual_shader_editor_plugin.h | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/editor/shader/visual_shader_editor_plugin.cpp b/editor/shader/visual_shader_editor_plugin.cpp index 33b6088a1126..dcc064204cd7 100644 --- a/editor/shader/visual_shader_editor_plugin.cpp +++ b/editor/shader/visual_shader_editor_plugin.cpp @@ -538,7 +538,7 @@ void VisualShaderGraphPlugin::update_frames(VisualShader::Type p_type, int p_nod void VisualShaderGraphPlugin::set_node_position(VisualShader::Type p_type, int p_id, const Vector2 &p_position) { if (editor->get_current_shader_type() == p_type && links.has(p_id)) { - links[p_id].graph_element->set_position_offset(p_position); + links[p_id].graph_element->set_position_offset(p_position * editor->cached_theme_base_scale); } } @@ -735,7 +735,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool expression = expression_node->get_expression(); } - node->set_position_offset(visual_shader->get_node_position(p_type, p_id)); + node->set_position_offset(visual_shader->get_node_position(p_type, p_id) * editor->cached_theme_base_scale); node->connect("dragged", callable_mp(editor, &VisualShaderEditor::_node_dragged).bind(p_id)); @@ -4166,7 +4166,7 @@ void VisualShaderEditor::_update_varyings() { void VisualShaderEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_to, int p_node) { VisualShader::Type type = get_current_shader_type(); - drag_buffer.push_back({ type, p_node, p_from, p_to }); + drag_buffer.push_back({ type, p_node, p_from / cached_theme_base_scale, p_to / cached_theme_base_scale }); if (!drag_dirty) { callable_mp(this, &VisualShaderEditor::_nodes_dragged).call_deferred(); } @@ -5340,6 +5340,8 @@ void VisualShaderEditor::_notification(int p_what) { tools->set_button_icon(get_editor_theme_icon(SNAME("Tools"))); preview_tools->set_button_icon(get_editor_theme_icon(SNAME("Tools"))); + cached_theme_base_scale = get_theme_default_base_scale(); + if (is_visible_in_tree()) { _update_graph(); } diff --git a/editor/shader/visual_shader_editor_plugin.h b/editor/shader/visual_shader_editor_plugin.h index dc3dad38b6a9..28a3589a0ac7 100644 --- a/editor/shader/visual_shader_editor_plugin.h +++ b/editor/shader/visual_shader_editor_plugin.h @@ -289,6 +289,8 @@ class VisualShaderEditor : public ShaderEditor { VBoxContainer *param_vbox = nullptr; VBoxContainer *param_vbox2 = nullptr; + float cached_theme_base_scale = 1.0f; + enum ShaderModeFlags { MODE_FLAGS_SPATIAL_CANVASITEM = 1, MODE_FLAGS_SKY = 2, From 9e1d0be25b5606e50777e1a1b5adc3036ef6889d Mon Sep 17 00:00:00 2001 From: Mattia Zirpoli Date: Sat, 13 Dec 2025 02:41:01 +0100 Subject: [PATCH 40/44] VisualShader: fix new node spawning position with display scaling (cherry picked from commit 2eb41ac549fdf8bd82e1b11ba6bf7a4f524dadee) --- editor/shader/visual_shader_editor_plugin.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/editor/shader/visual_shader_editor_plugin.cpp b/editor/shader/visual_shader_editor_plugin.cpp index dcc064204cd7..bab5d6fa611c 100644 --- a/editor/shader/visual_shader_editor_plugin.cpp +++ b/editor/shader/visual_shader_editor_plugin.cpp @@ -3840,6 +3840,7 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector &p_ops, cons position /= EDSCALE; } position /= graph->get_zoom(); + position /= cached_theme_base_scale; saved_node_pos_dirty = false; int id_to_use = visual_shader->get_valid_node_id(type); From a6531b8c48f00c7f7bd4286cb559f84adbbfcda1 Mon Sep 17 00:00:00 2001 From: Adelynne Brito Date: Fri, 5 Dec 2025 17:32:15 -0500 Subject: [PATCH 41/44] Only check material initialization for CanvasMaterial Prevents the check from causing other materials to error (cherry picked from commit d7792feabad6c20aa7bc25dbdeab5cf62f784236) --- editor/scene/material_editor_plugin.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/editor/scene/material_editor_plugin.cpp b/editor/scene/material_editor_plugin.cpp index f4b2281e154f..6e7c81f86609 100644 --- a/editor/scene/material_editor_plugin.cpp +++ b/editor/scene/material_editor_plugin.cpp @@ -456,7 +456,6 @@ bool StandardMaterial3DConversionPlugin::handles(const Ref &p_resource Ref StandardMaterial3DConversionPlugin::convert(const Ref &p_resource) const { Ref mat = p_resource; ERR_FAIL_COND_V(mat.is_null(), Ref()); - ERR_FAIL_COND_V(!mat->_is_initialized(), Ref()); Ref smat; smat.instantiate(); @@ -503,7 +502,6 @@ bool ORMMaterial3DConversionPlugin::handles(const Ref &p_resource) con Ref ORMMaterial3DConversionPlugin::convert(const Ref &p_resource) const { Ref mat = p_resource; ERR_FAIL_COND_V(mat.is_null(), Ref()); - ERR_FAIL_COND_V(!mat->_is_initialized(), Ref()); Ref smat; smat.instantiate(); @@ -550,7 +548,6 @@ bool ParticleProcessMaterialConversionPlugin::handles(const Ref &p_res Ref ParticleProcessMaterialConversionPlugin::convert(const Ref &p_resource) const { Ref mat = p_resource; ERR_FAIL_COND_V(mat.is_null(), Ref()); - ERR_FAIL_COND_V(!mat->_is_initialized(), Ref()); Ref smat; smat.instantiate(); From fe8d644c92d4dfb563ebe2e6d06eb96669b60881 Mon Sep 17 00:00:00 2001 From: Qbieshay Date: Fri, 7 Nov 2025 17:23:40 +0100 Subject: [PATCH 42/44] Fix CPUParticle3D not randomizing (cherry picked from commit 3a66d88be208948177781f6ec3cdd6b7e32e2f01) --- scene/3d/cpu_particles_3d.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp index 12fd33ffba6b..9ff730b73b0e 100644 --- a/scene/3d/cpu_particles_3d.cpp +++ b/scene/3d/cpu_particles_3d.cpp @@ -827,7 +827,7 @@ void CPUParticles3D::_particles_process(double p_delta) { tex_anim_offset = curve_parameters[PARAM_ANGLE]->sample(tv); } - p.seed = seed + uint32_t(1) + i + cycle; + p.seed = seed + uint32_t(1) + i + cycle * pcount; rng->set_seed(p.seed); p.angle_rand = rng->randf(); p.scale_rand = rng->randf(); From 9cf1ddb6ed2795367db09f32fa6200da32b598f4 Mon Sep 17 00:00:00 2001 From: David Snopek Date: Fri, 19 Sep 2025 14:36:36 -0500 Subject: [PATCH 43/44] Fix XR tracker name changing at runtime (cherry picked from commit bb06ffd944834e1cb5e9c053e21d65a9787138d2) --- scene/3d/xr/xr_body_modifier_3d.cpp | 4 ++++ scene/3d/xr/xr_face_modifier_3d.cpp | 4 ++++ scene/3d/xr/xr_hand_modifier_3d.cpp | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/scene/3d/xr/xr_body_modifier_3d.cpp b/scene/3d/xr/xr_body_modifier_3d.cpp index ca68b5a01157..942af82c7a99 100644 --- a/scene/3d/xr/xr_body_modifier_3d.cpp +++ b/scene/3d/xr/xr_body_modifier_3d.cpp @@ -66,6 +66,10 @@ StringName XRBodyModifier3D::get_body_tracker() const { void XRBodyModifier3D::set_body_update(BitField p_body_update) { body_update = p_body_update; + + if (is_inside_tree()) { + _get_joint_data(); + } } BitField XRBodyModifier3D::get_body_update() const { diff --git a/scene/3d/xr/xr_face_modifier_3d.cpp b/scene/3d/xr/xr_face_modifier_3d.cpp index ff2b9ace858c..6b8580aaecce 100644 --- a/scene/3d/xr/xr_face_modifier_3d.cpp +++ b/scene/3d/xr/xr_face_modifier_3d.cpp @@ -504,6 +504,10 @@ void XRFaceModifier3D::_bind_methods() { void XRFaceModifier3D::set_face_tracker(const StringName &p_tracker_name) { tracker_name = p_tracker_name; + + if (is_inside_tree()) { + _get_blend_data(); + } } StringName XRFaceModifier3D::get_face_tracker() const { diff --git a/scene/3d/xr/xr_hand_modifier_3d.cpp b/scene/3d/xr/xr_hand_modifier_3d.cpp index 872e169fa14f..5b59f3a05191 100644 --- a/scene/3d/xr/xr_hand_modifier_3d.cpp +++ b/scene/3d/xr/xr_hand_modifier_3d.cpp @@ -50,6 +50,10 @@ void XRHandModifier3D::_bind_methods() { void XRHandModifier3D::set_hand_tracker(const StringName &p_tracker_name) { tracker_name = p_tracker_name; + + if (is_inside_tree()) { + _get_joint_data(); + } } StringName XRHandModifier3D::get_hand_tracker() const { From 23e345712c6d769cfa8c215c53b31bb0cc3d53d9 Mon Sep 17 00:00:00 2001 From: Bastiaan Olij Date: Fri, 19 Dec 2025 16:02:34 +1100 Subject: [PATCH 44/44] OpenXR: When visibility mask extension does not return a mask, don't create a mesh (cherry picked from commit 12764858d36ad090ec131979b0bcc19fd9b1f83d) --- .../openxr_visibility_mask_extension.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/modules/openxr/extensions/openxr_visibility_mask_extension.cpp b/modules/openxr/extensions/openxr_visibility_mask_extension.cpp index 3e193d7d500d..71153f7c1d8d 100644 --- a/modules/openxr/extensions/openxr_visibility_mask_extension.cpp +++ b/modules/openxr/extensions/openxr_visibility_mask_extension.cpp @@ -100,9 +100,6 @@ void OpenXRVisibilityMaskExtension::on_session_created(const XrSession p_instanc rendering_server->material_set_shader(material, shader); rendering_server->material_set_render_priority(material, 99); - // Create our mesh. - mesh = rendering_server->mesh_create(); - // Get our initial mesh data. mesh_count = openxr_api->get_view_count(); // We need a mesh for each view. for (uint32_t i = 0; i < mesh_count; i++) { @@ -237,6 +234,16 @@ void OpenXRVisibilityMaskExtension::_update_mesh() { index_count += mesh_data[i].indices.size(); } + if (vertice_count == 0 || index_count == 0) { + // Free our mesh if we have one. + if (mesh.is_valid()) { + rendering_server->free(mesh); + mesh = RID(); + } + + return; + } + vertices.resize(vertice_count); indices.resize(index_count); uint64_t offset = 0; @@ -263,6 +270,11 @@ void OpenXRVisibilityMaskExtension::_update_mesh() { offset += mesh_data[i].vertices.size(); } + // Create our mesh if we don't have one yet. + if (mesh.is_null()) { + mesh = rendering_server->mesh_create(); + } + // Update our mesh. Array arr; arr.resize(RS::ARRAY_MAX);