From 823e2db6b1ffaf76deb3aaf4b2111e8906a3d3d2 Mon Sep 17 00:00:00 2001 From: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Wed, 17 Jun 2026 13:49:34 +0300 Subject: [PATCH] Add workaround for Vulkan pipeline compilation errors on Adreno 660. --- drivers/vulkan/rendering_device_driver_vulkan.cpp | 13 +++++++++++++ .../forward_mobile/render_forward_mobile.cpp | 13 ++++++++++--- .../forward_mobile/scene_shader_forward_mobile.cpp | 6 ++++++ servers/rendering/rendering_device.cpp | 6 ++++++ servers/rendering/rendering_device_commons.h | 1 + 5 files changed, 36 insertions(+), 3 deletions(-) diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp index 9f48519b88..46c5a4b677 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.cpp +++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp @@ -717,6 +717,13 @@ void RenderingDeviceDriverVulkan::_check_driver_workarounds(const VkPhysicalDevi p_device_properties.driverVersion < VK_MAKE_VERSION(512, 503, 0) && strstr(p_device_properties.deviceName, "Turnip") == nullptr; + // Don't print pipeline compilation errors on Adreno 660, as they are expected to happen on this device with ubershaders. + // Unhandled error cases will still pop up elsewhere in RD. (eg. when attempting to bind an invalid pipeline.) + driver_workarounds.dont_print_on_render_pipeline_creation_failure = + p_device_properties.vendorID == RenderingContextDriver::Vendor::VENDOR_QUALCOMM && + p_device_properties.deviceID == 0x6060001 && // Adreno 660 + strstr(p_device_properties.deviceName, "Turnip") == nullptr; + // Workaround a driver bug on Adreno 730 GPUs that keeps leaking memory on each call to vkResetDescriptorPool. // Which eventually run out of memory. In such case we should not be using linear allocated pools // Bug introduced in driver 512.597.0 and fixed in 512.671.0. @@ -6216,6 +6223,12 @@ RDD::PipelineID RenderingDeviceDriverVulkan::render_pipeline_create( VkPipeline vk_pipeline = VK_NULL_HANDLE; VkResult err = vkCreateGraphicsPipelines(vk_device, pipelines_cache.vk_cache, 1, &pipeline_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_PIPELINE), &vk_pipeline); + + // Don't print error for VK_ERROR_UNKNOWN on Adreno 660. + if (unlikely(err == VK_ERROR_UNKNOWN && driver_workarounds.dont_print_on_render_pipeline_creation_failure)) { + return PipelineID(); + } + ERR_FAIL_COND_V_MSG(err, PipelineID(), vformat("Couldn't create Vulkan graphics pipelines (VkResult error %d).", err)); #if RECORD_PIPELINE_STATISTICS diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index fedc74ed2e..18367d9a57 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -2564,7 +2564,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr RID pipeline_rd; RID vertex_array_rd; RID index_array_rd; - const uint32_t ubershader_iterations = (disable_ubershaders ? 1 : 2); + uint32_t ubershader_iterations = (disable_ubershaders ? 1 : 2); bool pipeline_valid = false; while (pipeline_key.ubershader < ubershader_iterations) { // Skeleton and blend shape. @@ -2589,7 +2589,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr if (shader != prev_shader || pipeline_hash != prev_pipeline_hash) { RSE::PipelineSource pipeline_source = pipeline_key.ubershader ? RSE::PIPELINE_SOURCE_DRAW : RSE::PIPELINE_SOURCE_SPECIALIZATION; - pipeline_rd = shader->pipeline_hash_map.get_pipeline(pipeline_key, pipeline_hash, pipeline_key.ubershader || disable_ubershaders, pipeline_source); + pipeline_rd = shader->pipeline_hash_map.get_pipeline(pipeline_key, pipeline_hash, pipeline_key.ubershader == (ubershader_iterations - 1), pipeline_source); if (pipeline_rd.is_valid()) { pipeline_valid = true; @@ -2597,7 +2597,14 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr prev_pipeline_hash = pipeline_hash; break; } else { - pipeline_key.ubershader++; + if (pipeline_key.ubershader == 1) { + // If ubershader failed to compile, retry specialized shader and wait for it to finish compilation. + // This prevents pop-in at the cost of shader compilation stutters. + pipeline_key.ubershader = 0; + ubershader_iterations = 1; + } else { + pipeline_key.ubershader++; + } } } else { // The same pipeline is bound already. diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index 95347aaec8..90d8690077 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -448,6 +448,12 @@ void SceneShaderForwardMobile::ShaderData::_create_pipeline(PipelineKey p_pipeli ERR_FAIL_COND(shader_rid.is_null()); RID pipeline = RD::get_singleton()->render_pipeline_create(shader_rid, p_pipeline_key.framebuffer_format_id, p_pipeline_key.vertex_format_id, primitive_rd, raster_state, multisample_state, depth_stencil_state, blend_state, 0, p_pipeline_key.render_pass, specialization_constants); + + // Don't print error when it's expected. + if (unlikely(pipeline.is_null() && RD::get_singleton()->get_driver_workarounds().dont_print_on_render_pipeline_creation_failure)) { + return; + } + ERR_FAIL_COND(pipeline.is_null()); pipeline_hash_map.add_compiled_pipeline(p_pipeline_key.hash(), pipeline); diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index f97b6fc0ca..7574038788 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -4951,6 +4951,12 @@ RID RenderingDevice::render_pipeline_create(RID p_shader, FramebufferFormatID p_ fb_format.render_pass, p_for_render_pass, p_specialization_constants); + + // Don't print error when it's expected. + if (unlikely(!pipeline.driver_id && driver->get_driver_workarounds().dont_print_on_render_pipeline_creation_failure)) { + return RID(); + } + ERR_FAIL_COND_V(!pipeline.driver_id, RID()); if (pipeline_cache_enabled) { diff --git a/servers/rendering/rendering_device_commons.h b/servers/rendering/rendering_device_commons.h index 07e97a301f..fd7b65b246 100644 --- a/servers/rendering/rendering_device_commons.h +++ b/servers/rendering/rendering_device_commons.h @@ -1052,6 +1052,7 @@ public: // Driver workarounds that require higher level code and cannot be solely implemented in RenderingDeviceDriver. struct DriverWorkarounds { bool avoid_compute_after_draw = false; + bool dont_print_on_render_pipeline_creation_failure = false; bool disable_ubershaders = false; };