Tony-LunarG | 7de10e8 | 2020-11-24 11:31:55 -0700 | [diff] [blame] | 1 | /* Copyright (c) 2020-2021 The Khronos Group Inc. |
| 2 | * Copyright (c) 2020-2021 Valve Corporation |
| 3 | * Copyright (c) 2020-2021 LunarG, Inc. |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 4 | * |
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | * you may not use this file except in compliance with the License. |
| 7 | * You may obtain a copy of the License at |
| 8 | * |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | * |
| 11 | * Unless required by applicable law or agreed to in writing, software |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | * See the License for the specific language governing permissions and |
| 15 | * limitations under the License. |
| 16 | * |
| 17 | * Author: Tony Barbour <tony@lunarg.com> |
| 18 | */ |
| 19 | #pragma once |
| 20 | #include "chassis.h" |
| 21 | #include "shader_validation.h" |
Jeremy Gebben | 159b3cc | 2021-06-03 09:09:03 -0600 | [diff] [blame] | 22 | #include "cmd_buffer_state.h" |
Jeremy Gebben | d177d92 | 2021-10-28 13:42:10 -0600 | [diff] [blame^] | 23 | class QUEUE_STATE; |
Jeremy Gebben | 159b3cc | 2021-06-03 09:09:03 -0600 | [diff] [blame] | 24 | |
Tony-LunarG | b5fae46 | 2020-03-05 12:43:25 -0700 | [diff] [blame] | 25 | class UtilDescriptorSetManager { |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 26 | public: |
Tony-LunarG | b5fae46 | 2020-03-05 12:43:25 -0700 | [diff] [blame] | 27 | UtilDescriptorSetManager(VkDevice device, uint32_t numBindingsInSet); |
| 28 | ~UtilDescriptorSetManager(); |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 29 | |
| 30 | VkResult GetDescriptorSet(VkDescriptorPool *desc_pool, VkDescriptorSetLayout ds_layout, VkDescriptorSet *desc_sets); |
| 31 | VkResult GetDescriptorSets(uint32_t count, VkDescriptorPool *pool, VkDescriptorSetLayout ds_layout, |
| 32 | std::vector<VkDescriptorSet> *desc_sets); |
| 33 | void PutBackDescriptorSet(VkDescriptorPool desc_pool, VkDescriptorSet desc_set); |
| 34 | |
| 35 | private: |
| 36 | static const uint32_t kItemsPerChunk = 512; |
| 37 | struct PoolTracker { |
| 38 | uint32_t size; |
| 39 | uint32_t used; |
| 40 | }; |
| 41 | VkDevice device; |
| 42 | uint32_t numBindingsInSet; |
Jeremy Gebben | cbf2286 | 2021-03-03 12:01:22 -0700 | [diff] [blame] | 43 | layer_data::unordered_map<VkDescriptorPool, struct PoolTracker> desc_pool_map_; |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 44 | }; |
Tony-LunarG | b5fae46 | 2020-03-05 12:43:25 -0700 | [diff] [blame] | 45 | struct UtilQueueBarrierCommandInfo { |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 46 | VkCommandPool barrier_command_pool = VK_NULL_HANDLE; |
| 47 | VkCommandBuffer barrier_command_buffer = VK_NULL_HANDLE; |
| 48 | }; |
Tony-LunarG | b5fae46 | 2020-03-05 12:43:25 -0700 | [diff] [blame] | 49 | VkResult UtilInitializeVma(VkPhysicalDevice physical_device, VkDevice device, VmaAllocator *pAllocator); |
| 50 | void UtilPreCallRecordCreateDevice(VkPhysicalDevice gpu, safe_VkDeviceCreateInfo *modified_create_info, |
| 51 | VkPhysicalDeviceFeatures supported_features, VkPhysicalDeviceFeatures desired_features); |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 52 | template <typename ObjectType> |
Tony-LunarG | b5fae46 | 2020-03-05 12:43:25 -0700 | [diff] [blame] | 53 | void UtilPostCallRecordCreateDevice(const VkDeviceCreateInfo *pCreateInfo, std::vector<VkDescriptorSetLayoutBinding> bindings, |
| 54 | ObjectType *object_ptr, VkPhysicalDeviceProperties physical_device_properties) { |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 55 | // If api version 1.1 or later, SetDeviceLoaderData will be in the loader |
| 56 | auto chain_info = get_chain_info(pCreateInfo, VK_LOADER_DATA_CALLBACK); |
| 57 | assert(chain_info->u.pfnSetDeviceLoaderData); |
| 58 | object_ptr->vkSetDeviceLoaderData = chain_info->u.pfnSetDeviceLoaderData; |
| 59 | |
| 60 | // Some devices have extremely high limits here, so set a reasonable max because we have to pad |
| 61 | // the pipeline layout with dummy descriptor set layouts. |
| 62 | object_ptr->adjusted_max_desc_sets = physical_device_properties.limits.maxBoundDescriptorSets; |
| 63 | object_ptr->adjusted_max_desc_sets = std::min(33U, object_ptr->adjusted_max_desc_sets); |
| 64 | |
| 65 | // We can't do anything if there is only one. |
| 66 | // Device probably not a legit Vulkan device, since there should be at least 4. Protect ourselves. |
| 67 | if (object_ptr->adjusted_max_desc_sets == 1) { |
| 68 | object_ptr->ReportSetupProblem(object_ptr->device, "Device can bind only a single descriptor set."); |
| 69 | object_ptr->aborted = true; |
| 70 | return; |
| 71 | } |
| 72 | object_ptr->desc_set_bind_index = object_ptr->adjusted_max_desc_sets - 1; |
| 73 | |
Tony-LunarG | b5fae46 | 2020-03-05 12:43:25 -0700 | [diff] [blame] | 74 | VkResult result1 = UtilInitializeVma(object_ptr->physicalDevice, object_ptr->device, &object_ptr->vmaAllocator); |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 75 | assert(result1 == VK_SUCCESS); |
Tony-LunarG | b5fae46 | 2020-03-05 12:43:25 -0700 | [diff] [blame] | 76 | std::unique_ptr<UtilDescriptorSetManager> desc_set_manager( |
| 77 | new UtilDescriptorSetManager(object_ptr->device, static_cast<uint32_t>(bindings.size()))); |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 78 | |
| 79 | const VkDescriptorSetLayoutCreateInfo debug_desc_layout_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, NULL, 0, |
| 80 | static_cast<uint32_t>(bindings.size()), bindings.data()}; |
| 81 | |
| 82 | const VkDescriptorSetLayoutCreateInfo dummy_desc_layout_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, NULL, 0, 0, |
| 83 | NULL}; |
| 84 | |
| 85 | result1 = DispatchCreateDescriptorSetLayout(object_ptr->device, &debug_desc_layout_info, NULL, &object_ptr->debug_desc_layout); |
| 86 | |
| 87 | // This is a layout used to "pad" a pipeline layout to fill in any gaps to the selected bind index. |
| 88 | VkResult result2 = |
| 89 | DispatchCreateDescriptorSetLayout(object_ptr->device, &dummy_desc_layout_info, NULL, &object_ptr->dummy_desc_layout); |
| 90 | |
| 91 | assert((result1 == VK_SUCCESS) && (result2 == VK_SUCCESS)); |
| 92 | if ((result1 != VK_SUCCESS) || (result2 != VK_SUCCESS)) { |
| 93 | object_ptr->ReportSetupProblem(object_ptr->device, "Unable to create descriptor set layout."); |
| 94 | if (result1 == VK_SUCCESS) { |
| 95 | DispatchDestroyDescriptorSetLayout(object_ptr->device, object_ptr->debug_desc_layout, NULL); |
| 96 | } |
| 97 | if (result2 == VK_SUCCESS) { |
| 98 | DispatchDestroyDescriptorSetLayout(object_ptr->device, object_ptr->dummy_desc_layout, NULL); |
| 99 | } |
| 100 | object_ptr->debug_desc_layout = VK_NULL_HANDLE; |
| 101 | object_ptr->dummy_desc_layout = VK_NULL_HANDLE; |
| 102 | object_ptr->aborted = true; |
| 103 | return; |
| 104 | } |
| 105 | object_ptr->desc_set_manager = std::move(desc_set_manager); |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 106 | } |
| 107 | template <typename ObjectType> |
Tony-LunarG | b5fae46 | 2020-03-05 12:43:25 -0700 | [diff] [blame] | 108 | void UtilPreCallRecordDestroyDevice(ObjectType *object_ptr) { |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 109 | for (auto &queue_barrier_command_info_kv : object_ptr->queue_barrier_command_infos) { |
Tony-LunarG | b5fae46 | 2020-03-05 12:43:25 -0700 | [diff] [blame] | 110 | UtilQueueBarrierCommandInfo &queue_barrier_command_info = queue_barrier_command_info_kv.second; |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 111 | |
| 112 | DispatchFreeCommandBuffers(object_ptr->device, queue_barrier_command_info.barrier_command_pool, 1, |
| 113 | &queue_barrier_command_info.barrier_command_buffer); |
| 114 | queue_barrier_command_info.barrier_command_buffer = VK_NULL_HANDLE; |
| 115 | |
| 116 | DispatchDestroyCommandPool(object_ptr->device, queue_barrier_command_info.barrier_command_pool, NULL); |
| 117 | queue_barrier_command_info.barrier_command_pool = VK_NULL_HANDLE; |
| 118 | } |
| 119 | object_ptr->queue_barrier_command_infos.clear(); |
| 120 | if (object_ptr->debug_desc_layout) { |
| 121 | DispatchDestroyDescriptorSetLayout(object_ptr->device, object_ptr->debug_desc_layout, NULL); |
| 122 | object_ptr->debug_desc_layout = VK_NULL_HANDLE; |
| 123 | } |
| 124 | if (object_ptr->dummy_desc_layout) { |
| 125 | DispatchDestroyDescriptorSetLayout(object_ptr->device, object_ptr->dummy_desc_layout, NULL); |
| 126 | object_ptr->dummy_desc_layout = VK_NULL_HANDLE; |
| 127 | } |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 128 | } |
| 129 | |
| 130 | template <typename ObjectType> |
Tony-LunarG | b5fae46 | 2020-03-05 12:43:25 -0700 | [diff] [blame] | 131 | void UtilPreCallRecordCreatePipelineLayout(create_pipeline_layout_api_state *cpl_state, ObjectType *object_ptr, |
| 132 | const VkPipelineLayoutCreateInfo *pCreateInfo) { |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 133 | // Modify the pipeline layout by: |
| 134 | // 1. Copying the caller's descriptor set desc_layouts |
| 135 | // 2. Fill in dummy descriptor layouts up to the max binding |
| 136 | // 3. Fill in with the debug descriptor layout at the max binding slot |
| 137 | cpl_state->new_layouts.reserve(object_ptr->adjusted_max_desc_sets); |
| 138 | cpl_state->new_layouts.insert(cpl_state->new_layouts.end(), &pCreateInfo->pSetLayouts[0], |
| 139 | &pCreateInfo->pSetLayouts[pCreateInfo->setLayoutCount]); |
| 140 | for (uint32_t i = pCreateInfo->setLayoutCount; i < object_ptr->adjusted_max_desc_sets - 1; ++i) { |
| 141 | cpl_state->new_layouts.push_back(object_ptr->dummy_desc_layout); |
| 142 | } |
| 143 | cpl_state->new_layouts.push_back(object_ptr->debug_desc_layout); |
| 144 | cpl_state->modified_create_info.pSetLayouts = cpl_state->new_layouts.data(); |
| 145 | cpl_state->modified_create_info.setLayoutCount = object_ptr->adjusted_max_desc_sets; |
| 146 | } |
| 147 | |
| 148 | template <typename CreateInfo> |
| 149 | struct CreatePipelineTraits {}; |
| 150 | template <> |
| 151 | struct CreatePipelineTraits<VkGraphicsPipelineCreateInfo> { |
| 152 | using SafeType = safe_VkGraphicsPipelineCreateInfo; |
Jeremy Gebben | 11af979 | 2021-08-20 10:20:09 -0600 | [diff] [blame] | 153 | static const SafeType &GetPipelineCI(const PIPELINE_STATE *pipeline_state) { return pipeline_state->create_info.graphics; } |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 154 | static uint32_t GetStageCount(const VkGraphicsPipelineCreateInfo &createInfo) { return createInfo.stageCount; } |
| 155 | static VkShaderModule GetShaderModule(const VkGraphicsPipelineCreateInfo &createInfo, uint32_t stage) { |
| 156 | return createInfo.pStages[stage].module; |
| 157 | } |
| 158 | static void SetShaderModule(SafeType *createInfo, VkShaderModule shader_module, uint32_t stage) { |
| 159 | createInfo->pStages[stage].module = shader_module; |
| 160 | } |
| 161 | }; |
| 162 | |
| 163 | template <> |
| 164 | struct CreatePipelineTraits<VkComputePipelineCreateInfo> { |
| 165 | using SafeType = safe_VkComputePipelineCreateInfo; |
Jeremy Gebben | 11af979 | 2021-08-20 10:20:09 -0600 | [diff] [blame] | 166 | static const SafeType &GetPipelineCI(const PIPELINE_STATE *pipeline_state) { return pipeline_state->create_info.compute; } |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 167 | static uint32_t GetStageCount(const VkComputePipelineCreateInfo &createInfo) { return 1; } |
| 168 | static VkShaderModule GetShaderModule(const VkComputePipelineCreateInfo &createInfo, uint32_t stage) { |
| 169 | return createInfo.stage.module; |
| 170 | } |
| 171 | static void SetShaderModule(SafeType *createInfo, VkShaderModule shader_module, uint32_t stage) { |
| 172 | assert(stage == 0); |
| 173 | createInfo->stage.module = shader_module; |
| 174 | } |
| 175 | }; |
| 176 | |
| 177 | template <> |
| 178 | struct CreatePipelineTraits<VkRayTracingPipelineCreateInfoNV> { |
| 179 | using SafeType = safe_VkRayTracingPipelineCreateInfoCommon; |
Jeremy Gebben | 11af979 | 2021-08-20 10:20:09 -0600 | [diff] [blame] | 180 | static const SafeType &GetPipelineCI(const PIPELINE_STATE *pipeline_state) { return pipeline_state->create_info.raytracing; } |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 181 | static uint32_t GetStageCount(const VkRayTracingPipelineCreateInfoNV &createInfo) { return createInfo.stageCount; } |
| 182 | static VkShaderModule GetShaderModule(const VkRayTracingPipelineCreateInfoNV &createInfo, uint32_t stage) { |
| 183 | return createInfo.pStages[stage].module; |
| 184 | } |
| 185 | static void SetShaderModule(SafeType *createInfo, VkShaderModule shader_module, uint32_t stage) { |
| 186 | createInfo->pStages[stage].module = shader_module; |
| 187 | } |
| 188 | }; |
| 189 | |
| 190 | template <> |
| 191 | struct CreatePipelineTraits<VkRayTracingPipelineCreateInfoKHR> { |
| 192 | using SafeType = safe_VkRayTracingPipelineCreateInfoCommon; |
Jeremy Gebben | 11af979 | 2021-08-20 10:20:09 -0600 | [diff] [blame] | 193 | static const SafeType &GetPipelineCI(const PIPELINE_STATE *pipeline_state) { return pipeline_state->create_info.raytracing; } |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 194 | static uint32_t GetStageCount(const VkRayTracingPipelineCreateInfoKHR &createInfo) { return createInfo.stageCount; } |
| 195 | static VkShaderModule GetShaderModule(const VkRayTracingPipelineCreateInfoKHR &createInfo, uint32_t stage) { |
| 196 | return createInfo.pStages[stage].module; |
| 197 | } |
| 198 | static void SetShaderModule(SafeType *createInfo, VkShaderModule shader_module, uint32_t stage) { |
| 199 | createInfo->pStages[stage].module = shader_module; |
| 200 | } |
| 201 | }; |
| 202 | |
| 203 | // Examine the pipelines to see if they use the debug descriptor set binding index. |
| 204 | // If any do, create new non-instrumented shader modules and use them to replace the instrumented |
| 205 | // shaders in the pipeline. Return the (possibly) modified create infos to the caller. |
| 206 | template <typename CreateInfo, typename SafeCreateInfo, typename ObjectType> |
Tony-LunarG | b5fae46 | 2020-03-05 12:43:25 -0700 | [diff] [blame] | 207 | void UtilPreCallRecordPipelineCreations(uint32_t count, const CreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, |
| 208 | VkPipeline *pPipelines, std::vector<std::shared_ptr<PIPELINE_STATE>> &pipe_state, |
| 209 | std::vector<SafeCreateInfo> *new_pipeline_create_infos, |
| 210 | const VkPipelineBindPoint bind_point, ObjectType *object_ptr) { |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 211 | using Accessor = CreatePipelineTraits<CreateInfo>; |
| 212 | if (bind_point != VK_PIPELINE_BIND_POINT_GRAPHICS && bind_point != VK_PIPELINE_BIND_POINT_COMPUTE && |
| 213 | bind_point != VK_PIPELINE_BIND_POINT_RAY_TRACING_NV) { |
| 214 | return; |
| 215 | } |
| 216 | |
| 217 | // Walk through all the pipelines, make a copy of each and flag each pipeline that contains a shader that uses the debug |
| 218 | // descriptor set index. |
| 219 | for (uint32_t pipeline = 0; pipeline < count; ++pipeline) { |
| 220 | uint32_t stageCount = Accessor::GetStageCount(pCreateInfos[pipeline]); |
| 221 | new_pipeline_create_infos->push_back(Accessor::GetPipelineCI(pipe_state[pipeline].get())); |
| 222 | |
| 223 | bool replace_shaders = false; |
| 224 | if (pipe_state[pipeline]->active_slots.find(object_ptr->desc_set_bind_index) != pipe_state[pipeline]->active_slots.end()) { |
| 225 | replace_shaders = true; |
| 226 | } |
| 227 | // If the app requests all available sets, the pipeline layout was not modified at pipeline layout creation and the already |
| 228 | // instrumented shaders need to be replaced with uninstrumented shaders |
| 229 | if (pipe_state[pipeline]->pipeline_layout->set_layouts.size() >= object_ptr->adjusted_max_desc_sets) { |
| 230 | replace_shaders = true; |
| 231 | } |
| 232 | |
| 233 | if (replace_shaders) { |
| 234 | for (uint32_t stage = 0; stage < stageCount; ++stage) { |
| 235 | const SHADER_MODULE_STATE *shader = |
| 236 | object_ptr->GetShaderModuleState(Accessor::GetShaderModule(pCreateInfos[pipeline], stage)); |
| 237 | |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 238 | VkShaderModule shader_module; |
Nathaniel Cesario | fc6291e | 2021-04-06 00:22:15 -0600 | [diff] [blame] | 239 | auto create_info = LvlInitStruct<VkShaderModuleCreateInfo>(); |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 240 | create_info.pCode = shader->words.data(); |
| 241 | create_info.codeSize = shader->words.size() * sizeof(uint32_t); |
| 242 | VkResult result = DispatchCreateShaderModule(object_ptr->device, &create_info, pAllocator, &shader_module); |
| 243 | if (result == VK_SUCCESS) { |
| 244 | Accessor::SetShaderModule(&(*new_pipeline_create_infos)[pipeline], shader_module, stage); |
| 245 | } else { |
| 246 | object_ptr->ReportSetupProblem(object_ptr->device, |
| 247 | "Unable to replace instrumented shader with non-instrumented one. " |
| 248 | "Device could become unstable."); |
| 249 | } |
| 250 | } |
| 251 | } |
| 252 | } |
| 253 | } |
| 254 | // For every pipeline: |
| 255 | // - For every shader in a pipeline: |
| 256 | // - If the shader had to be replaced in PreCallRecord (because the pipeline is using the debug desc set index): |
| 257 | // - Destroy it since it has been bound into the pipeline by now. This is our only chance to delete it. |
| 258 | // - Track the shader in the shader_map |
| 259 | // - Save the shader binary if it contains debug code |
| 260 | template <typename CreateInfo, typename ObjectType> |
Tony-LunarG | b5fae46 | 2020-03-05 12:43:25 -0700 | [diff] [blame] | 261 | void UtilPostCallRecordPipelineCreations(const uint32_t count, const CreateInfo *pCreateInfos, |
| 262 | const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines, |
| 263 | const VkPipelineBindPoint bind_point, ObjectType *object_ptr) { |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 264 | using Accessor = CreatePipelineTraits<CreateInfo>; |
| 265 | if (bind_point != VK_PIPELINE_BIND_POINT_GRAPHICS && bind_point != VK_PIPELINE_BIND_POINT_COMPUTE && |
| 266 | bind_point != VK_PIPELINE_BIND_POINT_RAY_TRACING_NV) { |
| 267 | return; |
| 268 | } |
| 269 | for (uint32_t pipeline = 0; pipeline < count; ++pipeline) { |
| 270 | auto pipeline_state = object_ptr->ValidationStateTracker::GetPipelineState(pPipelines[pipeline]); |
| 271 | if (nullptr == pipeline_state) continue; |
| 272 | |
| 273 | uint32_t stageCount = 0; |
| 274 | if (bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS) { |
Jeremy Gebben | 11af979 | 2021-08-20 10:20:09 -0600 | [diff] [blame] | 275 | stageCount = pipeline_state->create_info.graphics.stageCount; |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 276 | } else if (bind_point == VK_PIPELINE_BIND_POINT_COMPUTE) { |
| 277 | stageCount = 1; |
| 278 | } else if (bind_point == VK_PIPELINE_BIND_POINT_RAY_TRACING_NV) { |
Jeremy Gebben | 11af979 | 2021-08-20 10:20:09 -0600 | [diff] [blame] | 279 | stageCount = pipeline_state->create_info.raytracing.stageCount; |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 280 | } else { |
| 281 | assert(false); |
| 282 | } |
| 283 | |
| 284 | for (uint32_t stage = 0; stage < stageCount; ++stage) { |
| 285 | if (pipeline_state->active_slots.find(object_ptr->desc_set_bind_index) != pipeline_state->active_slots.end()) { |
| 286 | DispatchDestroyShaderModule(object_ptr->device, Accessor::GetShaderModule(pCreateInfos[pipeline], stage), |
| 287 | pAllocator); |
| 288 | } |
| 289 | |
| 290 | const SHADER_MODULE_STATE *shader_state = nullptr; |
| 291 | if (bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS) { |
Jeremy Gebben | 11af979 | 2021-08-20 10:20:09 -0600 | [diff] [blame] | 292 | shader_state = object_ptr->GetShaderModuleState(pipeline_state->create_info.graphics.pStages[stage].module); |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 293 | } else if (bind_point == VK_PIPELINE_BIND_POINT_COMPUTE) { |
| 294 | assert(stage == 0); |
Jeremy Gebben | 11af979 | 2021-08-20 10:20:09 -0600 | [diff] [blame] | 295 | shader_state = object_ptr->GetShaderModuleState(pipeline_state->create_info.compute.stage.module); |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 296 | } else if (bind_point == VK_PIPELINE_BIND_POINT_RAY_TRACING_NV) { |
Jeremy Gebben | 11af979 | 2021-08-20 10:20:09 -0600 | [diff] [blame] | 297 | shader_state = object_ptr->GetShaderModuleState(pipeline_state->create_info.raytracing.pStages[stage].module); |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 298 | } else { |
| 299 | assert(false); |
| 300 | } |
| 301 | |
| 302 | std::vector<unsigned int> code; |
| 303 | // Save the shader binary |
| 304 | // The core_validation ShaderModule tracker saves the binary too, but discards it when the ShaderModule |
| 305 | // is destroyed. Applications may destroy ShaderModules after they are placed in a pipeline and before |
| 306 | // the pipeline is used, so we have to keep another copy. |
| 307 | if (shader_state && shader_state->has_valid_spirv) code = shader_state->words; |
| 308 | |
Jeremy Gebben | 14b0d1a | 2021-05-15 20:15:41 -0600 | [diff] [blame] | 309 | object_ptr->shader_map[shader_state->gpu_validation_shader_id].pipeline = pipeline_state->pipeline(); |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 310 | // Be careful to use the originally bound (instrumented) shader here, even if PreCallRecord had to back it |
| 311 | // out with a non-instrumented shader. The non-instrumented shader (found in pCreateInfo) was destroyed above. |
| 312 | VkShaderModule shader_module = VK_NULL_HANDLE; |
| 313 | if (bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS) { |
Jeremy Gebben | 11af979 | 2021-08-20 10:20:09 -0600 | [diff] [blame] | 314 | shader_module = pipeline_state->create_info.graphics.pStages[stage].module; |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 315 | } else if (bind_point == VK_PIPELINE_BIND_POINT_COMPUTE) { |
| 316 | assert(stage == 0); |
Jeremy Gebben | 11af979 | 2021-08-20 10:20:09 -0600 | [diff] [blame] | 317 | shader_module = pipeline_state->create_info.compute.stage.module; |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 318 | } else if (bind_point == VK_PIPELINE_BIND_POINT_RAY_TRACING_NV) { |
Jeremy Gebben | 11af979 | 2021-08-20 10:20:09 -0600 | [diff] [blame] | 319 | shader_module = pipeline_state->create_info.raytracing.pStages[stage].module; |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 320 | } else { |
| 321 | assert(false); |
| 322 | } |
| 323 | object_ptr->shader_map[shader_state->gpu_validation_shader_id].shader_module = shader_module; |
| 324 | object_ptr->shader_map[shader_state->gpu_validation_shader_id].pgm = std::move(code); |
| 325 | } |
| 326 | } |
| 327 | } |
Tony-LunarG | c876c6e | 2020-09-09 15:19:43 -0600 | [diff] [blame] | 328 | template <typename CreateInfos, typename SafeCreateInfos> |
| 329 | void UtilCopyCreatePipelineFeedbackData(const uint32_t count, CreateInfos *pCreateInfos, SafeCreateInfos *pSafeCreateInfos) { |
| 330 | for (uint32_t i = 0; i < count; i++) { |
Mark Lobodzinski | 1f887d3 | 2020-12-30 15:31:33 -0700 | [diff] [blame] | 331 | auto src_feedback_struct = LvlFindInChain<VkPipelineCreationFeedbackCreateInfoEXT>(pSafeCreateInfos[i].pNext); |
Tony-LunarG | c876c6e | 2020-09-09 15:19:43 -0600 | [diff] [blame] | 332 | if (!src_feedback_struct) return; |
| 333 | auto dst_feedback_struct = const_cast<VkPipelineCreationFeedbackCreateInfoEXT *>( |
Mark Lobodzinski | 1f887d3 | 2020-12-30 15:31:33 -0700 | [diff] [blame] | 334 | LvlFindInChain<VkPipelineCreationFeedbackCreateInfoEXT>(pCreateInfos[i].pNext)); |
Tony-LunarG | c876c6e | 2020-09-09 15:19:43 -0600 | [diff] [blame] | 335 | *dst_feedback_struct->pPipelineCreationFeedback = *src_feedback_struct->pPipelineCreationFeedback; |
| 336 | for (uint32_t j = 0; j < src_feedback_struct->pipelineStageCreationFeedbackCount; j++) { |
| 337 | dst_feedback_struct->pPipelineStageCreationFeedbacks[j] = src_feedback_struct->pPipelineStageCreationFeedbacks[j]; |
| 338 | } |
| 339 | } |
| 340 | } |
| 341 | |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 342 | template <typename ObjectType> |
| 343 | // For the given command buffer, map its debug data buffers and read their contents for analysis. |
Tony-LunarG | b5fae46 | 2020-03-05 12:43:25 -0700 | [diff] [blame] | 344 | void UtilProcessInstrumentationBuffer(VkQueue queue, CMD_BUFFER_STATE *cb_node, ObjectType *object_ptr) { |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 345 | if (cb_node && (cb_node->hasDrawCmd || cb_node->hasTraceRaysCmd || cb_node->hasDispatchCmd)) { |
Jeremy Gebben | f6bb4bb | 2021-08-11 15:41:09 -0600 | [diff] [blame] | 346 | auto gpu_buffer_list = object_ptr->GetBufferInfo(cb_node); |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 347 | uint32_t draw_index = 0; |
| 348 | uint32_t compute_index = 0; |
| 349 | uint32_t ray_trace_index = 0; |
| 350 | |
| 351 | for (auto &buffer_info : gpu_buffer_list) { |
| 352 | char *pData; |
| 353 | |
| 354 | uint32_t operation_index = 0; |
| 355 | if (buffer_info.pipeline_bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS) { |
| 356 | operation_index = draw_index; |
| 357 | } else if (buffer_info.pipeline_bind_point == VK_PIPELINE_BIND_POINT_COMPUTE) { |
| 358 | operation_index = compute_index; |
| 359 | } else if (buffer_info.pipeline_bind_point == VK_PIPELINE_BIND_POINT_RAY_TRACING_NV) { |
| 360 | operation_index = ray_trace_index; |
| 361 | } else { |
| 362 | assert(false); |
| 363 | } |
| 364 | |
| 365 | VkResult result = vmaMapMemory(object_ptr->vmaAllocator, buffer_info.output_mem_block.allocation, (void **)&pData); |
| 366 | if (result == VK_SUCCESS) { |
Jeremy Gebben | 14b0d1a | 2021-05-15 20:15:41 -0600 | [diff] [blame] | 367 | object_ptr->AnalyzeAndGenerateMessages(cb_node->commandBuffer(), queue, buffer_info, |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 368 | operation_index, (uint32_t *)pData); |
| 369 | vmaUnmapMemory(object_ptr->vmaAllocator, buffer_info.output_mem_block.allocation); |
| 370 | } |
| 371 | |
| 372 | if (buffer_info.pipeline_bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS) { |
| 373 | draw_index++; |
| 374 | } else if (buffer_info.pipeline_bind_point == VK_PIPELINE_BIND_POINT_COMPUTE) { |
| 375 | compute_index++; |
| 376 | } else if (buffer_info.pipeline_bind_point == VK_PIPELINE_BIND_POINT_RAY_TRACING_NV) { |
| 377 | ray_trace_index++; |
| 378 | } else { |
| 379 | assert(false); |
| 380 | } |
| 381 | } |
| 382 | } |
| 383 | } |
| 384 | template <typename ObjectType> |
| 385 | // Submit a memory barrier on graphics queues. |
| 386 | // Lazy-create and record the needed command buffer. |
Tony-LunarG | b5fae46 | 2020-03-05 12:43:25 -0700 | [diff] [blame] | 387 | void UtilSubmitBarrier(VkQueue queue, ObjectType *object_ptr) { |
| 388 | auto queue_barrier_command_info_it = object_ptr->queue_barrier_command_infos.emplace(queue, UtilQueueBarrierCommandInfo{}); |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 389 | if (queue_barrier_command_info_it.second) { |
Tony-LunarG | b5fae46 | 2020-03-05 12:43:25 -0700 | [diff] [blame] | 390 | UtilQueueBarrierCommandInfo &queue_barrier_command_info = queue_barrier_command_info_it.first->second; |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 391 | |
| 392 | uint32_t queue_family_index = 0; |
| 393 | |
Jeremy Gebben | d177d92 | 2021-10-28 13:42:10 -0600 | [diff] [blame^] | 394 | auto queue_state = object_ptr->template Get<QUEUE_STATE>(queue); |
| 395 | if (queue_state) { |
| 396 | queue_family_index = queue_state->queueFamilyIndex; |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 397 | } |
| 398 | |
| 399 | VkResult result = VK_SUCCESS; |
| 400 | |
Nathaniel Cesario | fc6291e | 2021-04-06 00:22:15 -0600 | [diff] [blame] | 401 | auto pool_create_info = LvlInitStruct<VkCommandPoolCreateInfo>(); |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 402 | pool_create_info.queueFamilyIndex = queue_family_index; |
| 403 | result = DispatchCreateCommandPool(object_ptr->device, &pool_create_info, nullptr, |
| 404 | &queue_barrier_command_info.barrier_command_pool); |
| 405 | if (result != VK_SUCCESS) { |
| 406 | object_ptr->ReportSetupProblem(object_ptr->device, "Unable to create command pool for barrier CB."); |
| 407 | queue_barrier_command_info.barrier_command_pool = VK_NULL_HANDLE; |
| 408 | return; |
| 409 | } |
| 410 | |
Nathaniel Cesario | fc6291e | 2021-04-06 00:22:15 -0600 | [diff] [blame] | 411 | auto buffer_alloc_info = LvlInitStruct<VkCommandBufferAllocateInfo>(); |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 412 | buffer_alloc_info.commandPool = queue_barrier_command_info.barrier_command_pool; |
| 413 | buffer_alloc_info.commandBufferCount = 1; |
| 414 | buffer_alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; |
| 415 | result = DispatchAllocateCommandBuffers(object_ptr->device, &buffer_alloc_info, |
| 416 | &queue_barrier_command_info.barrier_command_buffer); |
| 417 | if (result != VK_SUCCESS) { |
| 418 | object_ptr->ReportSetupProblem(object_ptr->device, "Unable to create barrier command buffer."); |
| 419 | DispatchDestroyCommandPool(object_ptr->device, queue_barrier_command_info.barrier_command_pool, nullptr); |
| 420 | queue_barrier_command_info.barrier_command_pool = VK_NULL_HANDLE; |
| 421 | queue_barrier_command_info.barrier_command_buffer = VK_NULL_HANDLE; |
| 422 | return; |
| 423 | } |
| 424 | |
| 425 | // Hook up command buffer dispatch |
| 426 | object_ptr->vkSetDeviceLoaderData(object_ptr->device, queue_barrier_command_info.barrier_command_buffer); |
| 427 | |
| 428 | // Record a global memory barrier to force availability of device memory operations to the host domain. |
Nathaniel Cesario | fc6291e | 2021-04-06 00:22:15 -0600 | [diff] [blame] | 429 | auto command_buffer_begin_info = LvlInitStruct<VkCommandBufferBeginInfo>(); |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 430 | result = DispatchBeginCommandBuffer(queue_barrier_command_info.barrier_command_buffer, &command_buffer_begin_info); |
| 431 | if (result == VK_SUCCESS) { |
Nathaniel Cesario | fc6291e | 2021-04-06 00:22:15 -0600 | [diff] [blame] | 432 | auto memory_barrier = LvlInitStruct<VkMemoryBarrier>(); |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 433 | memory_barrier.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT; |
| 434 | memory_barrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT; |
| 435 | |
| 436 | DispatchCmdPipelineBarrier(queue_barrier_command_info.barrier_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, |
| 437 | VK_PIPELINE_STAGE_HOST_BIT, 0, 1, &memory_barrier, 0, nullptr, 0, nullptr); |
| 438 | DispatchEndCommandBuffer(queue_barrier_command_info.barrier_command_buffer); |
| 439 | } |
| 440 | } |
| 441 | |
Tony-LunarG | b5fae46 | 2020-03-05 12:43:25 -0700 | [diff] [blame] | 442 | UtilQueueBarrierCommandInfo &queue_barrier_command_info = queue_barrier_command_info_it.first->second; |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 443 | if (queue_barrier_command_info.barrier_command_buffer != VK_NULL_HANDLE) { |
Nathaniel Cesario | fc6291e | 2021-04-06 00:22:15 -0600 | [diff] [blame] | 444 | auto submit_info = LvlInitStruct<VkSubmitInfo>(); |
Tony-LunarG | 1dce239 | 2019-10-23 16:49:29 -0600 | [diff] [blame] | 445 | submit_info.commandBufferCount = 1; |
| 446 | submit_info.pCommandBuffers = &queue_barrier_command_info.barrier_command_buffer; |
| 447 | DispatchQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); |
| 448 | } |
| 449 | } |
Tony-LunarG | b5fae46 | 2020-03-05 12:43:25 -0700 | [diff] [blame] | 450 | void UtilGenerateStageMessage(const uint32_t *debug_record, std::string &msg); |
| 451 | void UtilGenerateCommonMessage(const debug_report_data *report_data, const VkCommandBuffer commandBuffer, |
| 452 | const uint32_t *debug_record, const VkShaderModule shader_module_handle, |
| 453 | const VkPipeline pipeline_handle, const VkPipelineBindPoint pipeline_bind_point, |
| 454 | const uint32_t operation_index, std::string &msg); |
| 455 | void UtilGenerateSourceMessages(const std::vector<unsigned int> &pgm, const uint32_t *debug_record, bool from_printf, |
| 456 | std::string &filename_msg, std::string &source_msg); |