|
43 | 43 | /**** GENERIC ****/ |
44 | 44 | /*****************/ |
45 | 45 |
|
| 46 | +#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED) |
| 47 | +static const uint32_t BREADCRUMB_BUFFER_ENTRIES = 512u; |
| 48 | +#endif |
| 49 | + |
46 | 50 | static const VkFormat RD_TO_VK_FORMAT[RDD::DATA_FORMAT_MAX] = { |
47 | 51 | VK_FORMAT_R4G4_UNORM_PACK8, |
48 | 52 | VK_FORMAT_R4G4B4A4_UNORM_PACK16, |
@@ -1370,7 +1374,10 @@ Error RenderingDeviceDriverVulkan::initialize(uint32_t p_device_index, uint32_t |
1370 | 1374 | ERR_FAIL_COND_V(err != OK, err); |
1371 | 1375 |
|
1372 | 1376 | max_descriptor_sets_per_pool = GLOBAL_GET("rendering/rendering_device/vulkan/max_descriptors_per_pool"); |
1373 | | - breadcrumb_buffer = buffer_create(sizeof(uint32_t), BufferUsageBits::BUFFER_USAGE_TRANSFER_TO_BIT, MemoryAllocationType::MEMORY_ALLOCATION_TYPE_CPU); |
| 1377 | + |
| 1378 | +#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED) |
| 1379 | + breadcrumb_buffer = buffer_create(2u * sizeof(uint32_t) * BREADCRUMB_BUFFER_ENTRIES, BufferUsageBits::BUFFER_USAGE_TRANSFER_TO_BIT, MemoryAllocationType::MEMORY_ALLOCATION_TYPE_CPU); |
| 1380 | +#endif |
1374 | 1381 |
|
1375 | 1382 | return OK; |
1376 | 1383 | } |
@@ -5004,10 +5011,65 @@ void RenderingDeviceDriverVulkan::command_end_label(CommandBufferID p_cmd_buffer |
5004 | 5011 | /**** DEBUG *****/ |
5005 | 5012 | /****************/ |
5006 | 5013 | void RenderingDeviceDriverVulkan::command_insert_breadcrumb(CommandBufferID p_cmd_buffer, uint32_t p_data) { |
| 5014 | +#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED) |
5007 | 5015 | if (p_data == BreadcrumbMarker::NONE) { |
5008 | 5016 | return; |
5009 | 5017 | } |
5010 | | - vkCmdFillBuffer((VkCommandBuffer)p_cmd_buffer.id, ((BufferInfo *)breadcrumb_buffer.id)->vk_buffer, 0, sizeof(uint32_t), p_data); |
| 5018 | + |
| 5019 | + if (Engine::get_singleton()->is_accurate_breadcrumbs_enabled()) { |
| 5020 | + // Force a full barrier so commands are not executed in parallel. |
| 5021 | + // This will mean that the last breadcrumb to see was actually the |
| 5022 | + // last (group of) command to be executed (hence, the one causing the crash). |
| 5023 | + VkMemoryBarrier memoryBarrier; |
| 5024 | + memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; |
| 5025 | + memoryBarrier.pNext = nullptr; |
| 5026 | + memoryBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT | |
| 5027 | + VK_ACCESS_INDEX_READ_BIT | |
| 5028 | + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | |
| 5029 | + VK_ACCESS_UNIFORM_READ_BIT | |
| 5030 | + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | |
| 5031 | + VK_ACCESS_SHADER_READ_BIT | |
| 5032 | + VK_ACCESS_SHADER_WRITE_BIT | |
| 5033 | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | |
| 5034 | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | |
| 5035 | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | |
| 5036 | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | |
| 5037 | + VK_ACCESS_TRANSFER_READ_BIT | |
| 5038 | + VK_ACCESS_TRANSFER_WRITE_BIT | |
| 5039 | + VK_ACCESS_HOST_READ_BIT | |
| 5040 | + VK_ACCESS_HOST_WRITE_BIT; |
| 5041 | + memoryBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT | |
| 5042 | + VK_ACCESS_INDEX_READ_BIT | |
| 5043 | + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | |
| 5044 | + VK_ACCESS_UNIFORM_READ_BIT | |
| 5045 | + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | |
| 5046 | + VK_ACCESS_SHADER_READ_BIT | |
| 5047 | + VK_ACCESS_SHADER_WRITE_BIT | |
| 5048 | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | |
| 5049 | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | |
| 5050 | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | |
| 5051 | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | |
| 5052 | + VK_ACCESS_TRANSFER_READ_BIT | |
| 5053 | + VK_ACCESS_TRANSFER_WRITE_BIT | |
| 5054 | + VK_ACCESS_HOST_READ_BIT | |
| 5055 | + VK_ACCESS_HOST_WRITE_BIT; |
| 5056 | + |
| 5057 | + vkCmdPipelineBarrier( |
| 5058 | + (VkCommandBuffer)p_cmd_buffer.id, |
| 5059 | + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, |
| 5060 | + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, |
| 5061 | + 0, 1u, &memoryBarrier, 0u, nullptr, 0u, nullptr); |
| 5062 | + } |
| 5063 | + |
| 5064 | + // We write to a circular buffer. If you're getting barrier sync errors here, |
| 5065 | + // increase the value of BREADCRUMB_BUFFER_ENTRIES. |
| 5066 | + vkCmdFillBuffer((VkCommandBuffer)p_cmd_buffer.id, ((BufferInfo *)breadcrumb_buffer.id)->vk_buffer, breadcrumb_offset, sizeof(uint32_t), breadcrumb_id++); |
| 5067 | + vkCmdFillBuffer((VkCommandBuffer)p_cmd_buffer.id, ((BufferInfo *)breadcrumb_buffer.id)->vk_buffer, breadcrumb_offset + sizeof(uint32_t), sizeof(uint32_t), p_data); |
| 5068 | + breadcrumb_offset += sizeof(uint32_t) * 2u; |
| 5069 | + if (breadcrumb_offset >= BREADCRUMB_BUFFER_ENTRIES * sizeof(uint32_t) * 2u) { |
| 5070 | + breadcrumb_offset = 0u; |
| 5071 | + } |
| 5072 | +#endif |
5011 | 5073 | } |
5012 | 5074 |
|
5013 | 5075 | void RenderingDeviceDriverVulkan::on_device_lost() const { |
@@ -5089,64 +5151,121 @@ void RenderingDeviceDriverVulkan::on_device_lost() const { |
5089 | 5151 |
|
5090 | 5152 | void RenderingDeviceDriverVulkan::print_lost_device_info() { |
5091 | 5153 | #if defined(DEBUG_ENABLED) || defined(DEV_ENABLED) |
5092 | | - void *breadcrumb_ptr; |
5093 | | - vmaFlushAllocation(allocator, ((BufferInfo *)breadcrumb_buffer.id)->allocation.handle, 0, sizeof(uint32_t)); |
5094 | | - vmaInvalidateAllocation(allocator, ((BufferInfo *)breadcrumb_buffer.id)->allocation.handle, 0, sizeof(uint32_t)); |
5095 | | - |
5096 | | - vmaMapMemory(allocator, ((BufferInfo *)breadcrumb_buffer.id)->allocation.handle, &breadcrumb_ptr); |
5097 | | - uint32_t last_breadcrumb = *(uint32_t *)breadcrumb_ptr; |
5098 | | - vmaUnmapMemory(allocator, ((BufferInfo *)breadcrumb_buffer.id)->allocation.handle); |
5099 | | - uint32_t phase = last_breadcrumb & uint32_t(~((1 << 16) - 1)); |
5100 | | - uint32_t user_data = last_breadcrumb & ((1 << 16) - 1); |
5101 | | - String error_msg = "Last known breadcrumb: "; |
5102 | | - |
5103 | | - switch (phase) { |
5104 | | - case BreadcrumbMarker::ALPHA_PASS: |
5105 | | - error_msg += "ALPHA_PASS"; |
5106 | | - break; |
5107 | | - case BreadcrumbMarker::BLIT_PASS: |
5108 | | - error_msg += "BLIT_PASS"; |
5109 | | - break; |
5110 | | - case BreadcrumbMarker::DEBUG_PASS: |
5111 | | - error_msg += "DEBUG_PASS"; |
5112 | | - break; |
5113 | | - case BreadcrumbMarker::LIGHTMAPPER_PASS: |
5114 | | - error_msg += "LIGHTMAPPER_PASS"; |
5115 | | - break; |
5116 | | - case BreadcrumbMarker::OPAQUE_PASS: |
5117 | | - error_msg += "OPAQUE_PASS"; |
5118 | | - break; |
5119 | | - case BreadcrumbMarker::POST_PROCESSING_PASS: |
5120 | | - error_msg += "POST_PROCESSING_PASS"; |
5121 | | - break; |
5122 | | - case BreadcrumbMarker::REFLECTION_PROBES: |
5123 | | - error_msg += "REFLECTION_PROBES"; |
5124 | | - break; |
5125 | | - case BreadcrumbMarker::SHADOW_PASS_CUBE: |
5126 | | - error_msg += "SHADOW_PASS_CUBE"; |
5127 | | - break; |
5128 | | - case BreadcrumbMarker::SHADOW_PASS_DIRECTIONAL: |
5129 | | - error_msg += "SHADOW_PASS_DIRECTIONAL"; |
5130 | | - break; |
5131 | | - case BreadcrumbMarker::SKY_PASS: |
5132 | | - error_msg += "SKY_PASS"; |
5133 | | - break; |
5134 | | - case BreadcrumbMarker::TRANSPARENT_PASS: |
5135 | | - error_msg += "TRANSPARENT_PASS"; |
5136 | | - break; |
5137 | | - case BreadcrumbMarker::UI_PASS: |
5138 | | - error_msg += "UI_PASS"; |
5139 | | - break; |
5140 | | - default: |
5141 | | - error_msg += "UNKNOWN_BREADCRUMB(" + itos((uint32_t)phase) + ')'; |
5142 | | - break; |
| 5154 | + { |
| 5155 | + String error_msg = "Printing last known breadcrumbs in reverse order (last executed first)."; |
| 5156 | + if (!Engine::get_singleton()->is_accurate_breadcrumbs_enabled()) { |
| 5157 | + error_msg += "\nSome of them might be inaccurate. Try running with --accurate-breadcrumbs for precise information."; |
| 5158 | + } |
| 5159 | + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, error_msg); |
5143 | 5160 | } |
5144 | 5161 |
|
5145 | | - if (user_data != 0) { |
5146 | | - error_msg += " | User data: " + itos(user_data); |
5147 | | - } |
| 5162 | + uint8_t *breadcrumb_ptr = nullptr; |
| 5163 | + VkResult map_result = VK_SUCCESS; |
| 5164 | + |
| 5165 | + vmaFlushAllocation(allocator, ((BufferInfo *)breadcrumb_buffer.id)->allocation.handle, 0, BREADCRUMB_BUFFER_ENTRIES * sizeof(uint32_t) * 2u); |
| 5166 | + vmaInvalidateAllocation(allocator, ((BufferInfo *)breadcrumb_buffer.id)->allocation.handle, 0, BREADCRUMB_BUFFER_ENTRIES * sizeof(uint32_t) * 2u); |
| 5167 | + { |
| 5168 | + void *ptr = nullptr; |
| 5169 | + map_result = vmaMapMemory(allocator, ((BufferInfo *)breadcrumb_buffer.id)->allocation.handle, &ptr); |
| 5170 | + breadcrumb_ptr = reinterpret_cast<uint8_t *>(ptr); |
| 5171 | + } |
| 5172 | + |
| 5173 | + if (breadcrumb_ptr && map_result == VK_SUCCESS) { |
| 5174 | + uint32_t last_breadcrumb_offset = 0; |
| 5175 | + { |
| 5176 | + _err_print_error_asap("Searching last breadcrumb. We've sent up to ID: " + itos(breadcrumb_id - 1u)); |
| 5177 | + |
| 5178 | + // Scan the whole buffer to find the offset with the highest ID. |
| 5179 | + // That means that was the last one to be written. |
| 5180 | + // |
| 5181 | + // We use "breadcrumb_id - id" to account for wraparound. |
| 5182 | + // e.g. breadcrumb_id = 2 and id = 4294967294; then 2 - 4294967294 = 4. |
| 5183 | + // The one with the smallest difference is the closest to breadcrumb_id, which means it's |
| 5184 | + // the last written command. |
| 5185 | + uint32_t biggest_id = 0u; |
| 5186 | + uint32_t smallest_id_diff = std::numeric_limits<uint32_t>::max(); |
| 5187 | + const uint32_t *breadcrumb_ptr32 = reinterpret_cast<const uint32_t *>(breadcrumb_ptr); |
| 5188 | + for (size_t i = 0u; i < BREADCRUMB_BUFFER_ENTRIES; ++i) { |
| 5189 | + const uint32_t id = breadcrumb_ptr32[i * 2u]; |
| 5190 | + const uint32_t id_diff = breadcrumb_id - id; |
| 5191 | + if (id_diff < smallest_id_diff) { |
| 5192 | + biggest_id = i; |
| 5193 | + smallest_id_diff = id_diff; |
| 5194 | + } |
| 5195 | + } |
| 5196 | + |
| 5197 | + _err_print_error_asap("Last breadcrumb ID found: " + itos(breadcrumb_ptr32[biggest_id * 2u])); |
| 5198 | + |
| 5199 | + last_breadcrumb_offset = biggest_id * sizeof(uint32_t) * 2u; |
| 5200 | + } |
| 5201 | + |
| 5202 | + const size_t entries_to_print = 8u; // Note: The value is arbitrary. |
| 5203 | + for (size_t i = 0u; i < entries_to_print; ++i) { |
| 5204 | + const uint32_t last_breadcrumb = *reinterpret_cast<uint32_t *>(breadcrumb_ptr + last_breadcrumb_offset + sizeof(uint32_t)); |
| 5205 | + const uint32_t phase = last_breadcrumb & uint32_t(~((1 << 16) - 1)); |
| 5206 | + const uint32_t user_data = last_breadcrumb & ((1 << 16) - 1); |
| 5207 | + String error_msg = "Last known breadcrumb: "; |
| 5208 | + |
| 5209 | + switch (phase) { |
| 5210 | + case BreadcrumbMarker::ALPHA_PASS: |
| 5211 | + error_msg += "ALPHA_PASS"; |
| 5212 | + break; |
| 5213 | + case BreadcrumbMarker::BLIT_PASS: |
| 5214 | + error_msg += "BLIT_PASS"; |
| 5215 | + break; |
| 5216 | + case BreadcrumbMarker::DEBUG_PASS: |
| 5217 | + error_msg += "DEBUG_PASS"; |
| 5218 | + break; |
| 5219 | + case BreadcrumbMarker::LIGHTMAPPER_PASS: |
| 5220 | + error_msg += "LIGHTMAPPER_PASS"; |
| 5221 | + break; |
| 5222 | + case BreadcrumbMarker::OPAQUE_PASS: |
| 5223 | + error_msg += "OPAQUE_PASS"; |
| 5224 | + break; |
| 5225 | + case BreadcrumbMarker::POST_PROCESSING_PASS: |
| 5226 | + error_msg += "POST_PROCESSING_PASS"; |
| 5227 | + break; |
| 5228 | + case BreadcrumbMarker::REFLECTION_PROBES: |
| 5229 | + error_msg += "REFLECTION_PROBES"; |
| 5230 | + break; |
| 5231 | + case BreadcrumbMarker::SHADOW_PASS_CUBE: |
| 5232 | + error_msg += "SHADOW_PASS_CUBE"; |
| 5233 | + break; |
| 5234 | + case BreadcrumbMarker::SHADOW_PASS_DIRECTIONAL: |
| 5235 | + error_msg += "SHADOW_PASS_DIRECTIONAL"; |
| 5236 | + break; |
| 5237 | + case BreadcrumbMarker::SKY_PASS: |
| 5238 | + error_msg += "SKY_PASS"; |
| 5239 | + break; |
| 5240 | + case BreadcrumbMarker::TRANSPARENT_PASS: |
| 5241 | + error_msg += "TRANSPARENT_PASS"; |
| 5242 | + break; |
| 5243 | + case BreadcrumbMarker::UI_PASS: |
| 5244 | + error_msg += "UI_PASS"; |
| 5245 | + break; |
| 5246 | + default: |
| 5247 | + error_msg += "UNKNOWN_BREADCRUMB(" + itos((uint32_t)phase) + ')'; |
| 5248 | + break; |
| 5249 | + } |
| 5250 | + |
| 5251 | + if (user_data != 0) { |
| 5252 | + error_msg += " | User data: " + itos(user_data); |
| 5253 | + } |
| 5254 | + |
| 5255 | + _err_print_error_asap(error_msg); |
5148 | 5256 |
|
5149 | | - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, error_msg); |
| 5257 | + if (last_breadcrumb_offset == 0u) { |
| 5258 | + // Decrement last_breadcrumb_idx, wrapping underflow. |
| 5259 | + last_breadcrumb_offset = BREADCRUMB_BUFFER_ENTRIES * sizeof(uint32_t) * 2u; |
| 5260 | + } |
| 5261 | + last_breadcrumb_offset -= sizeof(uint32_t) * 2u; |
| 5262 | + } |
| 5263 | + |
| 5264 | + vmaUnmapMemory(allocator, ((BufferInfo *)breadcrumb_buffer.id)->allocation.handle); |
| 5265 | + breadcrumb_ptr = nullptr; |
| 5266 | + } else { |
| 5267 | + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Couldn't map breadcrumb buffer. VkResult = " + itos(map_result)); |
| 5268 | + } |
5150 | 5269 | #endif |
5151 | 5270 | on_device_lost(); |
5152 | 5271 | } |
@@ -5417,7 +5536,9 @@ RenderingDeviceDriverVulkan::RenderingDeviceDriverVulkan(RenderingContextDriverV |
5417 | 5536 | } |
5418 | 5537 |
|
5419 | 5538 | RenderingDeviceDriverVulkan::~RenderingDeviceDriverVulkan() { |
| 5539 | +#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED) |
5420 | 5540 | buffer_free(breadcrumb_buffer); |
| 5541 | +#endif |
5421 | 5542 |
|
5422 | 5543 | while (small_allocs_pools.size()) { |
5423 | 5544 | HashMap<uint32_t, VmaPool>::Iterator E = small_allocs_pools.begin(); |
|
0 commit comments