blob: 760e88953b749034ed408f0250755b453cf16749 [file] [log] [blame]
sfricke-samsungef15e482022-01-26 11:32:49 -08001/* Copyright (c) 2020-2022 The Khronos Group Inc.
2 * Copyright (c) 2020-2022 Valve Corporation
3 * Copyright (c) 2020-2022 LunarG, Inc.
Tony-LunarG1dce2392019-10-23 16:49:29 -06004 *
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
Jeremy Gebben5160e032022-03-28 14:57:43 -060020#include "gpu_utils.h"
Jeremy Gebben159b3cc2021-06-03 09:09:03 -060021#include "descriptor_sets.h"
sjfricke9a209802022-08-03 17:57:40 +090022#include "sync_utils.h"
Tony-LunarG1dce2392019-10-23 16:49:29 -060023#include "spirv-tools/libspirv.h"
24#include "spirv-tools/optimizer.hpp"
25#include "spirv-tools/instrument.hpp"
Mark Lobodzinski102687e2020-04-28 11:03:28 -060026#include <spirv/unified1/spirv.hpp>
Tony-LunarG1dce2392019-10-23 16:49:29 -060027#include <algorithm>
28#include <regex>
29
John Zulauf088a54d2022-06-09 10:12:07 -060030#ifdef _MSC_VER
31#pragma warning(push)
32#pragma warning(disable : 4189)
33#endif
34
Tony-LunarG1dce2392019-10-23 16:49:29 -060035#define VMA_IMPLEMENTATION
36// This define indicates that we will supply Vulkan function pointers at initialization
37#define VMA_STATIC_VULKAN_FUNCTIONS 0
38#include "vk_mem_alloc.h"
39
John Zulauf088a54d2022-06-09 10:12:07 -060040#ifdef _MSC_VER
41#pragma warning(pop)
42#endif
43
Tony-LunarG1dce2392019-10-23 16:49:29 -060044// Implementation for Descriptor Set Manager class
sjfricke43b340c2022-08-04 22:18:38 +090045UtilDescriptorSetManager::UtilDescriptorSetManager(VkDevice device, uint32_t num_bindings_in_set)
46 : device(device), num_bindings_in_set(num_bindings_in_set) {}
Tony-LunarG1dce2392019-10-23 16:49:29 -060047
Tony-LunarGb5fae462020-03-05 12:43:25 -070048UtilDescriptorSetManager::~UtilDescriptorSetManager() {
Tony-LunarG1dce2392019-10-23 16:49:29 -060049 for (auto &pool : desc_pool_map_) {
50 DispatchDestroyDescriptorPool(device, pool.first, NULL);
51 }
52 desc_pool_map_.clear();
53}
54
Tony-LunarGb5fae462020-03-05 12:43:25 -070055VkResult UtilDescriptorSetManager::GetDescriptorSet(VkDescriptorPool *desc_pool, VkDescriptorSetLayout ds_layout,
56 VkDescriptorSet *desc_set) {
Tony-LunarG1dce2392019-10-23 16:49:29 -060057 std::vector<VkDescriptorSet> desc_sets;
58 VkResult result = GetDescriptorSets(1, desc_pool, ds_layout, &desc_sets);
Jeremy Gebbenefd97802022-03-28 16:45:05 -060059 assert(result == VK_SUCCESS);
Tony-LunarG1dce2392019-10-23 16:49:29 -060060 if (result == VK_SUCCESS) {
61 *desc_set = desc_sets[0];
62 }
63 return result;
64}
65
Tony-LunarGb5fae462020-03-05 12:43:25 -070066VkResult UtilDescriptorSetManager::GetDescriptorSets(uint32_t count, VkDescriptorPool *pool, VkDescriptorSetLayout ds_layout,
67 std::vector<VkDescriptorSet> *desc_sets) {
Jeremy Gebbenfcfc33c2022-03-28 15:31:29 -060068 auto guard = Lock();
Tony-LunarG1dce2392019-10-23 16:49:29 -060069 const uint32_t default_pool_size = kItemsPerChunk;
70 VkResult result = VK_SUCCESS;
71 VkDescriptorPool pool_to_use = VK_NULL_HANDLE;
72
Jeremy Gebbenefd97802022-03-28 16:45:05 -060073 assert(count > 0);
Tony-LunarG1dce2392019-10-23 16:49:29 -060074 if (0 == count) {
75 return result;
76 }
77 desc_sets->clear();
78 desc_sets->resize(count);
79
80 for (auto &pool : desc_pool_map_) {
81 if (pool.second.used + count < pool.second.size) {
82 pool_to_use = pool.first;
83 break;
84 }
85 }
86 if (VK_NULL_HANDLE == pool_to_use) {
87 uint32_t pool_count = default_pool_size;
88 if (count > default_pool_size) {
89 pool_count = count;
90 }
91 const VkDescriptorPoolSize size_counts = {
92 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
sjfricke43b340c2022-08-04 22:18:38 +090093 pool_count * num_bindings_in_set,
Tony-LunarG1dce2392019-10-23 16:49:29 -060094 };
Nathaniel Cesariofc6291e2021-04-06 00:22:15 -060095 auto desc_pool_info = LvlInitStruct<VkDescriptorPoolCreateInfo>();
Tony-LunarG1dce2392019-10-23 16:49:29 -060096 desc_pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
97 desc_pool_info.maxSets = pool_count;
98 desc_pool_info.poolSizeCount = 1;
99 desc_pool_info.pPoolSizes = &size_counts;
100 result = DispatchCreateDescriptorPool(device, &desc_pool_info, NULL, &pool_to_use);
101 assert(result == VK_SUCCESS);
102 if (result != VK_SUCCESS) {
103 return result;
104 }
105 desc_pool_map_[pool_to_use].size = desc_pool_info.maxSets;
106 desc_pool_map_[pool_to_use].used = 0;
107 }
108 std::vector<VkDescriptorSetLayout> desc_layouts(count, ds_layout);
109
110 VkDescriptorSetAllocateInfo alloc_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, NULL, pool_to_use, count,
111 desc_layouts.data()};
112
113 result = DispatchAllocateDescriptorSets(device, &alloc_info, desc_sets->data());
114 assert(result == VK_SUCCESS);
115 if (result != VK_SUCCESS) {
116 return result;
117 }
118 *pool = pool_to_use;
119 desc_pool_map_[pool_to_use].used += count;
120 return result;
121}
122
Tony-LunarGb5fae462020-03-05 12:43:25 -0700123void UtilDescriptorSetManager::PutBackDescriptorSet(VkDescriptorPool desc_pool, VkDescriptorSet desc_set) {
Jeremy Gebbenfcfc33c2022-03-28 15:31:29 -0600124 auto guard = Lock();
Tony-LunarG1dce2392019-10-23 16:49:29 -0600125 auto iter = desc_pool_map_.find(desc_pool);
126 if (iter != desc_pool_map_.end()) {
127 VkResult result = DispatchFreeDescriptorSets(device, desc_pool, 1, &desc_set);
128 assert(result == VK_SUCCESS);
129 if (result != VK_SUCCESS) {
130 return;
131 }
132 desc_pool_map_[desc_pool].used--;
133 if (0 == desc_pool_map_[desc_pool].used) {
134 DispatchDestroyDescriptorPool(device, desc_pool, NULL);
135 desc_pool_map_.erase(desc_pool);
136 }
137 }
138 return;
139}
140
141// Trampolines to make VMA call Dispatch for Vulkan calls
Tony-LunarG21624bd2022-08-17 12:26:50 -0600142static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL gpuVkGetInstanceProcAddr(VkInstance inst, const char *name) {
143 return DispatchGetInstanceProcAddr(inst, name);
144}
145static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL gpuVkGetDeviceProcAddr(VkDevice dev, const char *name) {
146 return DispatchGetDeviceProcAddr(dev, name);
147}
Tony-LunarG1dce2392019-10-23 16:49:29 -0600148static VKAPI_ATTR void VKAPI_CALL gpuVkGetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
149 VkPhysicalDeviceProperties *pProperties) {
150 DispatchGetPhysicalDeviceProperties(physicalDevice, pProperties);
151}
152static VKAPI_ATTR void VKAPI_CALL gpuVkGetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice,
153 VkPhysicalDeviceMemoryProperties *pMemoryProperties) {
154 DispatchGetPhysicalDeviceMemoryProperties(physicalDevice, pMemoryProperties);
155}
156static VKAPI_ATTR VkResult VKAPI_CALL gpuVkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
157 const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) {
158 return DispatchAllocateMemory(device, pAllocateInfo, pAllocator, pMemory);
159}
160static VKAPI_ATTR void VKAPI_CALL gpuVkFreeMemory(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks *pAllocator) {
161 DispatchFreeMemory(device, memory, pAllocator);
162}
163static VKAPI_ATTR VkResult VKAPI_CALL gpuVkMapMemory(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size,
164 VkMemoryMapFlags flags, void **ppData) {
165 return DispatchMapMemory(device, memory, offset, size, flags, ppData);
166}
167static VKAPI_ATTR void VKAPI_CALL gpuVkUnmapMemory(VkDevice device, VkDeviceMemory memory) { DispatchUnmapMemory(device, memory); }
168static VKAPI_ATTR VkResult VKAPI_CALL gpuVkFlushMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount,
169 const VkMappedMemoryRange *pMemoryRanges) {
170 return DispatchFlushMappedMemoryRanges(device, memoryRangeCount, pMemoryRanges);
171}
172static VKAPI_ATTR VkResult VKAPI_CALL gpuVkInvalidateMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount,
173 const VkMappedMemoryRange *pMemoryRanges) {
174 return DispatchInvalidateMappedMemoryRanges(device, memoryRangeCount, pMemoryRanges);
175}
176static VKAPI_ATTR VkResult VKAPI_CALL gpuVkBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory memory,
177 VkDeviceSize memoryOffset) {
178 return DispatchBindBufferMemory(device, buffer, memory, memoryOffset);
179}
180static VKAPI_ATTR VkResult VKAPI_CALL gpuVkBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory memory,
181 VkDeviceSize memoryOffset) {
182 return DispatchBindImageMemory(device, image, memory, memoryOffset);
183}
184static VKAPI_ATTR void VKAPI_CALL gpuVkGetBufferMemoryRequirements(VkDevice device, VkBuffer buffer,
185 VkMemoryRequirements *pMemoryRequirements) {
186 DispatchGetBufferMemoryRequirements(device, buffer, pMemoryRequirements);
187}
188static VKAPI_ATTR void VKAPI_CALL gpuVkGetImageMemoryRequirements(VkDevice device, VkImage image,
189 VkMemoryRequirements *pMemoryRequirements) {
190 DispatchGetImageMemoryRequirements(device, image, pMemoryRequirements);
191}
192static VKAPI_ATTR VkResult VKAPI_CALL gpuVkCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
193 const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) {
194 return DispatchCreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
195}
196static VKAPI_ATTR void VKAPI_CALL gpuVkDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
197 return DispatchDestroyBuffer(device, buffer, pAllocator);
198}
199static VKAPI_ATTR VkResult VKAPI_CALL gpuVkCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
200 const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
201 return DispatchCreateImage(device, pCreateInfo, pAllocator, pImage);
202}
203static VKAPI_ATTR void VKAPI_CALL gpuVkDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
204 DispatchDestroyImage(device, image, pAllocator);
205}
206static VKAPI_ATTR void VKAPI_CALL gpuVkCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
207 uint32_t regionCount, const VkBufferCopy *pRegions) {
208 DispatchCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions);
209}
210
Tony-LunarGca5cd032022-07-25 16:03:21 -0600211VkResult UtilInitializeVma(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, VmaAllocator *pAllocator) {
Tony-LunarG1dce2392019-10-23 16:49:29 -0600212 VmaVulkanFunctions functions;
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700213 VmaAllocatorCreateInfo allocator_info = {};
Tony-LunarGca5cd032022-07-25 16:03:21 -0600214 allocator_info.instance = instance;
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700215 allocator_info.device = device;
216 allocator_info.physicalDevice = physical_device;
Tony-LunarG1dce2392019-10-23 16:49:29 -0600217
Tony-LunarG21624bd2022-08-17 12:26:50 -0600218 functions.vkGetInstanceProcAddr = static_cast<PFN_vkGetInstanceProcAddr>(gpuVkGetInstanceProcAddr);
219 functions.vkGetDeviceProcAddr = static_cast<PFN_vkGetDeviceProcAddr>(gpuVkGetDeviceProcAddr);
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700220 functions.vkGetPhysicalDeviceProperties = static_cast<PFN_vkGetPhysicalDeviceProperties>(gpuVkGetPhysicalDeviceProperties);
221 functions.vkGetPhysicalDeviceMemoryProperties =
222 static_cast<PFN_vkGetPhysicalDeviceMemoryProperties>(gpuVkGetPhysicalDeviceMemoryProperties);
223 functions.vkAllocateMemory = static_cast<PFN_vkAllocateMemory>(gpuVkAllocateMemory);
224 functions.vkFreeMemory = static_cast<PFN_vkFreeMemory>(gpuVkFreeMemory);
225 functions.vkMapMemory = static_cast<PFN_vkMapMemory>(gpuVkMapMemory);
226 functions.vkUnmapMemory = static_cast<PFN_vkUnmapMemory>(gpuVkUnmapMemory);
227 functions.vkFlushMappedMemoryRanges = static_cast<PFN_vkFlushMappedMemoryRanges>(gpuVkFlushMappedMemoryRanges);
228 functions.vkInvalidateMappedMemoryRanges = static_cast<PFN_vkInvalidateMappedMemoryRanges>(gpuVkInvalidateMappedMemoryRanges);
229 functions.vkBindBufferMemory = static_cast<PFN_vkBindBufferMemory>(gpuVkBindBufferMemory);
230 functions.vkBindImageMemory = static_cast<PFN_vkBindImageMemory>(gpuVkBindImageMemory);
231 functions.vkGetBufferMemoryRequirements = static_cast<PFN_vkGetBufferMemoryRequirements>(gpuVkGetBufferMemoryRequirements);
232 functions.vkGetImageMemoryRequirements = static_cast<PFN_vkGetImageMemoryRequirements>(gpuVkGetImageMemoryRequirements);
233 functions.vkCreateBuffer = static_cast<PFN_vkCreateBuffer>(gpuVkCreateBuffer);
234 functions.vkDestroyBuffer = static_cast<PFN_vkDestroyBuffer>(gpuVkDestroyBuffer);
235 functions.vkCreateImage = static_cast<PFN_vkCreateImage>(gpuVkCreateImage);
236 functions.vkDestroyImage = static_cast<PFN_vkDestroyImage>(gpuVkDestroyImage);
237 functions.vkCmdCopyBuffer = static_cast<PFN_vkCmdCopyBuffer>(gpuVkCmdCopyBuffer);
238 allocator_info.pVulkanFunctions = &functions;
Tony-LunarG1dce2392019-10-23 16:49:29 -0600239
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700240 return vmaCreateAllocator(&allocator_info, pAllocator);
Tony-LunarG1dce2392019-10-23 16:49:29 -0600241}
242
Jeremy Gebben5ca80b32022-04-11 10:58:39 -0600243gpu_utils_state::CommandBuffer::CommandBuffer(GpuAssistedBase *ga, VkCommandBuffer cb,
244 const VkCommandBufferAllocateInfo *pCreateInfo, const COMMAND_POOL_STATE *pool)
245 : CMD_BUFFER_STATE(ga, cb, pCreateInfo, pool) {}
246
Jeremy Gebben04697b02022-03-23 16:18:12 -0600247ReadLockGuard GpuAssistedBase::ReadLock() {
248 if (fine_grained_locking) {
249 return ReadLockGuard(validation_object_mutex, std::defer_lock);
250 } else {
251 return ReadLockGuard(validation_object_mutex);
252 }
253}
254
255WriteLockGuard GpuAssistedBase::WriteLock() {
256 if (fine_grained_locking) {
257 return WriteLockGuard(validation_object_mutex, std::defer_lock);
258 } else {
259 return WriteLockGuard(validation_object_mutex);
260 }
261}
262
Jeremy Gebben33717862022-03-28 15:53:56 -0600263void GpuAssistedBase::PreCallRecordCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
264 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, void *modified_ci) {
265 ValidationStateTracker::PreCallRecordCreateDevice(gpu, pCreateInfo, pAllocator, pDevice, modified_ci);
Tony-LunarG1dce2392019-10-23 16:49:29 -0600266 VkPhysicalDeviceFeatures *features = nullptr;
Jeremy Gebben33717862022-03-28 15:53:56 -0600267 // Use a local variable to query features since this method runs in the instance validation object.
268 // To avoid confusion and race conditions about which physical device's features are stored in the
269 // 'supported_devices' member variable, it will only be set in the device validation objects.
270 // See CreateDevice() below.
271 VkPhysicalDeviceFeatures gpu_supported_features;
272 DispatchGetPhysicalDeviceFeatures(gpu, &gpu_supported_features);
273 auto modified_create_info = static_cast<VkDeviceCreateInfo *>(modified_ci);
Tony-LunarG1dce2392019-10-23 16:49:29 -0600274 if (modified_create_info->pEnabledFeatures) {
275 // If pEnabledFeatures, VkPhysicalDeviceFeatures2 in pNext chain is not allowed
276 features = const_cast<VkPhysicalDeviceFeatures *>(modified_create_info->pEnabledFeatures);
277 } else {
278 VkPhysicalDeviceFeatures2 *features2 = nullptr;
Mark Lobodzinski1f887d32020-12-30 15:31:33 -0700279 features2 = const_cast<VkPhysicalDeviceFeatures2 *>(LvlFindInChain<VkPhysicalDeviceFeatures2>(modified_create_info->pNext));
Tony-LunarG1dce2392019-10-23 16:49:29 -0600280 if (features2) features = &features2->features;
281 }
Tony-LunarGf0634eb2021-01-05 15:11:12 -0700282 VkPhysicalDeviceFeatures new_features = {};
283 VkBool32 *desired = reinterpret_cast<VkBool32 *>(&desired_features);
284 VkBool32 *feature_ptr;
Tony-LunarG1dce2392019-10-23 16:49:29 -0600285 if (features) {
Tony-LunarGf0634eb2021-01-05 15:11:12 -0700286 feature_ptr = reinterpret_cast<VkBool32 *>(features);
Tony-LunarG1dce2392019-10-23 16:49:29 -0600287 } else {
Tony-LunarGf0634eb2021-01-05 15:11:12 -0700288 feature_ptr = reinterpret_cast<VkBool32 *>(&new_features);
289 }
290 VkBool32 *supported = reinterpret_cast<VkBool32 *>(&supported_features);
291 for (size_t i = 0; i < sizeof(VkPhysicalDeviceFeatures); i += (sizeof(VkBool32))) {
292 if (*supported && *desired) {
293 *feature_ptr = true;
294 }
295 supported++;
296 desired++;
297 feature_ptr++;
298 }
299 if (!features) {
Tony-LunarG1dce2392019-10-23 16:49:29 -0600300 delete modified_create_info->pEnabledFeatures;
301 modified_create_info->pEnabledFeatures = new VkPhysicalDeviceFeatures(new_features);
302 }
303}
304
Jeremy Gebben33717862022-03-28 15:53:56 -0600305void GpuAssistedBase::CreateDevice(const VkDeviceCreateInfo *pCreateInfo) {
306 ValidationStateTracker::CreateDevice(pCreateInfo);
307 // If api version 1.1 or later, SetDeviceLoaderData will be in the loader
308 auto chain_info = get_chain_info(pCreateInfo, VK_LOADER_DATA_CALLBACK);
309 assert(chain_info->u.pfnSetDeviceLoaderData);
310 vkSetDeviceLoaderData = chain_info->u.pfnSetDeviceLoaderData;
311
312 // Some devices have extremely high limits here, so set a reasonable max because we have to pad
313 // the pipeline layout with dummy descriptor set layouts.
314 adjusted_max_desc_sets = phys_dev_props.limits.maxBoundDescriptorSets;
315 adjusted_max_desc_sets = std::min(33U, adjusted_max_desc_sets);
316
317 // We can't do anything if there is only one.
318 // Device probably not a legit Vulkan device, since there should be at least 4. Protect ourselves.
319 if (adjusted_max_desc_sets == 1) {
320 ReportSetupProblem(device, "Device can bind only a single descriptor set.");
321 aborted = true;
322 return;
323 }
324 desc_set_bind_index = adjusted_max_desc_sets - 1;
325
Tony-LunarGca5cd032022-07-25 16:03:21 -0600326 VkResult result1 = UtilInitializeVma(instance, physical_device, device, &vmaAllocator);
Jeremy Gebben33717862022-03-28 15:53:56 -0600327 assert(result1 == VK_SUCCESS);
328 desc_set_manager = layer_data::make_unique<UtilDescriptorSetManager>(device, static_cast<uint32_t>(bindings_.size()));
329
330 const VkDescriptorSetLayoutCreateInfo debug_desc_layout_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, NULL, 0,
331 static_cast<uint32_t>(bindings_.size()), bindings_.data()};
332
333 const VkDescriptorSetLayoutCreateInfo dummy_desc_layout_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, NULL, 0, 0,
334 NULL};
335
336 result1 = DispatchCreateDescriptorSetLayout(device, &debug_desc_layout_info, NULL, &debug_desc_layout);
337
338 // This is a layout used to "pad" a pipeline layout to fill in any gaps to the selected bind index.
339 VkResult result2 = DispatchCreateDescriptorSetLayout(device, &dummy_desc_layout_info, NULL, &dummy_desc_layout);
340
341 assert((result1 == VK_SUCCESS) && (result2 == VK_SUCCESS));
342 if ((result1 != VK_SUCCESS) || (result2 != VK_SUCCESS)) {
343 ReportSetupProblem(device, "Unable to create descriptor set layout.");
344 if (result1 == VK_SUCCESS) {
345 DispatchDestroyDescriptorSetLayout(device, debug_desc_layout, NULL);
346 }
347 if (result2 == VK_SUCCESS) {
348 DispatchDestroyDescriptorSetLayout(device, dummy_desc_layout, NULL);
349 }
350 debug_desc_layout = VK_NULL_HANDLE;
351 dummy_desc_layout = VK_NULL_HANDLE;
352 aborted = true;
353 return;
354 }
355}
356
357void GpuAssistedBase::PreCallRecordDestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
Jeremy Gebben33717862022-03-28 15:53:56 -0600358 if (debug_desc_layout) {
359 DispatchDestroyDescriptorSetLayout(device, debug_desc_layout, NULL);
360 debug_desc_layout = VK_NULL_HANDLE;
361 }
362 if (dummy_desc_layout) {
363 DispatchDestroyDescriptorSetLayout(device, dummy_desc_layout, NULL);
364 dummy_desc_layout = VK_NULL_HANDLE;
365 }
366 ValidationStateTracker::PreCallRecordDestroyDevice(device, pAllocator);
367 // State Tracker can end up making vma calls through callbacks - don't destroy allocator until ST is done
368 if (vmaAllocator) {
369 vmaDestroyAllocator(vmaAllocator);
370 }
371 desc_set_manager.reset();
372}
373
Rodrigo Locatti7ab778d2022-03-09 18:57:15 -0300374gpu_utils_state::Queue::Queue(GpuAssistedBase &state, VkQueue q, uint32_t index, VkDeviceQueueCreateFlags flags, const VkQueueFamilyProperties &queueFamilyProperties)
375 : QUEUE_STATE(q, index, flags, queueFamilyProperties), state_(state) {}
Jeremy Gebbenfcfc33c2022-03-28 15:31:29 -0600376
377gpu_utils_state::Queue::~Queue() {
378 if (barrier_command_buffer_) {
379 DispatchFreeCommandBuffers(state_.device, barrier_command_pool_, 1, &barrier_command_buffer_);
380 barrier_command_buffer_ = VK_NULL_HANDLE;
381 }
382 if (barrier_command_pool_) {
383 DispatchDestroyCommandPool(state_.device, barrier_command_pool_, NULL);
384 barrier_command_pool_ = VK_NULL_HANDLE;
385 }
386}
387
388// Submit a memory barrier on graphics queues.
389// Lazy-create and record the needed command buffer.
390void gpu_utils_state::Queue::SubmitBarrier() {
391 if (barrier_command_pool_ == VK_NULL_HANDLE) {
392 VkResult result = VK_SUCCESS;
393
394 auto pool_create_info = LvlInitStruct<VkCommandPoolCreateInfo>();
395 pool_create_info.queueFamilyIndex = queueFamilyIndex;
396 result = DispatchCreateCommandPool(state_.device, &pool_create_info, nullptr, &barrier_command_pool_);
397 if (result != VK_SUCCESS) {
398 state_.ReportSetupProblem(state_.device, "Unable to create command pool for barrier CB.");
399 barrier_command_pool_ = VK_NULL_HANDLE;
400 return;
401 }
402
403 auto buffer_alloc_info = LvlInitStruct<VkCommandBufferAllocateInfo>();
404 buffer_alloc_info.commandPool = barrier_command_pool_;
405 buffer_alloc_info.commandBufferCount = 1;
406 buffer_alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
407 result = DispatchAllocateCommandBuffers(state_.device, &buffer_alloc_info, &barrier_command_buffer_);
408 if (result != VK_SUCCESS) {
409 state_.ReportSetupProblem(state_.device, "Unable to create barrier command buffer.");
410 DispatchDestroyCommandPool(state_.device, barrier_command_pool_, nullptr);
411 barrier_command_pool_ = VK_NULL_HANDLE;
412 barrier_command_buffer_ = VK_NULL_HANDLE;
413 return;
414 }
415
416 // Hook up command buffer dispatch
417 state_.vkSetDeviceLoaderData(state_.device, barrier_command_buffer_);
418
419 // Record a global memory barrier to force availability of device memory operations to the host domain.
420 auto command_buffer_begin_info = LvlInitStruct<VkCommandBufferBeginInfo>();
421 result = DispatchBeginCommandBuffer(barrier_command_buffer_, &command_buffer_begin_info);
422 if (result == VK_SUCCESS) {
423 auto memory_barrier = LvlInitStruct<VkMemoryBarrier>();
424 memory_barrier.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT;
425 memory_barrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT;
426 DispatchCmdPipelineBarrier(barrier_command_buffer_, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0,
427 1, &memory_barrier, 0, nullptr, 0, nullptr);
428 DispatchEndCommandBuffer(barrier_command_buffer_);
429 }
430 }
431 if (barrier_command_buffer_ != VK_NULL_HANDLE) {
432 auto submit_info = LvlInitStruct<VkSubmitInfo>();
433 submit_info.commandBufferCount = 1;
434 submit_info.pCommandBuffers = &barrier_command_buffer_;
435 DispatchQueueSubmit(QUEUE_STATE::Queue(), 1, &submit_info, VK_NULL_HANDLE);
436 }
437}
438
Jeremy Gebben5ca80b32022-04-11 10:58:39 -0600439bool GpuAssistedBase::CommandBufferNeedsProcessing(VkCommandBuffer command_buffer) const {
Jeremy Gebben04697b02022-03-23 16:18:12 -0600440 auto cb_node = GetRead<gpu_utils_state::CommandBuffer>(command_buffer);
Jeremy Gebben5ca80b32022-04-11 10:58:39 -0600441 if (cb_node->NeedsProcessing()) {
442 return true;
443 }
444 for (const auto *secondary_cb : cb_node->linkedCommandBuffers) {
445 auto secondary_cb_node = static_cast<const gpu_utils_state::CommandBuffer *>(secondary_cb);
Jeremy Gebben04697b02022-03-23 16:18:12 -0600446 auto guard = secondary_cb_node->ReadLock();
Jeremy Gebben5ca80b32022-04-11 10:58:39 -0600447 if (secondary_cb_node->NeedsProcessing()) {
448 return true;
449 }
450 }
451 return false;
452}
453
454void GpuAssistedBase::ProcessCommandBuffer(VkQueue queue, VkCommandBuffer command_buffer) {
Jeremy Gebben04697b02022-03-23 16:18:12 -0600455 auto cb_node = GetWrite<gpu_utils_state::CommandBuffer>(command_buffer);
Jeremy Gebben5ca80b32022-04-11 10:58:39 -0600456
457 cb_node->Process(queue);
458 for (auto *secondary_cmd_base : cb_node->linkedCommandBuffers) {
459 auto *secondary_cb_node = static_cast<gpu_utils_state::CommandBuffer *>(secondary_cmd_base);
Jeremy Gebben04697b02022-03-23 16:18:12 -0600460 auto guard = secondary_cb_node->WriteLock();
Jeremy Gebben5ca80b32022-04-11 10:58:39 -0600461 secondary_cb_node->Process(queue);
462 }
463}
464
Jeremy Gebbenfcfc33c2022-03-28 15:31:29 -0600465// Issue a memory barrier to make GPU-written data available to host.
466// Wait for the queue to complete execution.
467// Check the debug buffers for all the command buffers that were submitted.
468void GpuAssistedBase::PostCallRecordQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence,
469 VkResult result) {
470 ValidationStateTracker::PostCallRecordQueueSubmit(queue, submitCount, pSubmits, fence, result);
471
472 if (aborted || (result != VK_SUCCESS)) return;
473 bool buffers_present = false;
474 // Don't QueueWaitIdle if there's nothing to process
475 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
476 const VkSubmitInfo *submit = &pSubmits[submit_idx];
477 for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
478 buffers_present |= CommandBufferNeedsProcessing(submit->pCommandBuffers[i]);
479 }
480 }
481 if (!buffers_present) return;
482
483 SubmitBarrier(queue);
484
485 DispatchQueueWaitIdle(queue);
486
487 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
488 const VkSubmitInfo *submit = &pSubmits[submit_idx];
489 for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
490 ProcessCommandBuffer(queue, submit->pCommandBuffers[i]);
491 }
492 }
493}
494
495void GpuAssistedBase::RecordQueueSubmit2(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2 *pSubmits, VkFence fence,
496 VkResult result) {
497 if (aborted || (result != VK_SUCCESS)) return;
498 bool buffers_present = false;
499 // Don't QueueWaitIdle if there's nothing to process
500 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
501 const VkSubmitInfo2 *submit = &pSubmits[submit_idx];
502 for (uint32_t i = 0; i < submit->commandBufferInfoCount; i++) {
503 buffers_present |= CommandBufferNeedsProcessing(submit->pCommandBufferInfos[i].commandBuffer);
504 }
505 }
506 if (!buffers_present) return;
507
508 SubmitBarrier(queue);
509
510 DispatchQueueWaitIdle(queue);
511
512 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
513 const VkSubmitInfo2 *submit = &pSubmits[submit_idx];
514 for (uint32_t i = 0; i < submit->commandBufferInfoCount; i++) {
515 ProcessCommandBuffer(queue, submit->pCommandBufferInfos[i].commandBuffer);
516 }
517 }
518}
519
520void GpuAssistedBase::PostCallRecordQueueSubmit2KHR(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2KHR *pSubmits,
521 VkFence fence, VkResult result) {
522 ValidationStateTracker::PostCallRecordQueueSubmit2KHR(queue, submitCount, pSubmits, fence, result);
523 RecordQueueSubmit2(queue, submitCount, pSubmits, fence, result);
524}
525
526void GpuAssistedBase::PostCallRecordQueueSubmit2(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2 *pSubmits, VkFence fence,
527 VkResult result) {
528 ValidationStateTracker::PostCallRecordQueueSubmit2(queue, submitCount, pSubmits, fence, result);
529 RecordQueueSubmit2(queue, submitCount, pSubmits, fence, result);
530}
531
sjfricke9a209802022-08-03 17:57:40 +0900532// Just gives a warning about a possible deadlock.
533bool GpuAssistedBase::ValidateCmdWaitEvents(VkCommandBuffer command_buffer, VkPipelineStageFlags2 src_stage_mask,
534 CMD_TYPE cmd_type) const {
535 if (src_stage_mask & VK_PIPELINE_STAGE_2_HOST_BIT) {
536 std::ostringstream error_msg;
537 error_msg << CommandTypeString(cmd_type)
538 << ": recorded with VK_PIPELINE_STAGE_HOST_BIT set. GPU-Assisted validation waits on queue completion. This wait "
539 "could block the host's signaling of this event, resulting in deadlock.";
540 ReportSetupProblem(command_buffer, error_msg.str().c_str());
541 }
542 return false;
543}
544
545bool GpuAssistedBase::PreCallValidateCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
546 VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
547 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
548 uint32_t bufferMemoryBarrierCount,
549 const VkBufferMemoryBarrier *pBufferMemoryBarriers,
550 uint32_t imageMemoryBarrierCount,
551 const VkImageMemoryBarrier *pImageMemoryBarriers) const {
552 ValidationStateTracker::PreCallValidateCmdWaitEvents(commandBuffer, eventCount, pEvents, srcStageMask, dstStageMask,
553 memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
554 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
555 return ValidateCmdWaitEvents(commandBuffer, static_cast<VkPipelineStageFlags2>(srcStageMask), CMD_WAITEVENTS);
556}
557
558bool GpuAssistedBase::PreCallValidateCmdWaitEvents2KHR(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
559 const VkDependencyInfoKHR *pDependencyInfos) const {
560 VkPipelineStageFlags2 src_stage_mask = 0;
561
562 for (uint32_t i = 0; i < eventCount; i++) {
563 auto stage_masks = sync_utils::GetGlobalStageMasks(pDependencyInfos[i]);
564 src_stage_mask |= stage_masks.src;
565 }
566
567 ValidationStateTracker::PreCallValidateCmdWaitEvents2KHR(commandBuffer, eventCount, pEvents, pDependencyInfos);
568 return ValidateCmdWaitEvents(commandBuffer, src_stage_mask, CMD_WAITEVENTS2KHR);
569}
570
571bool GpuAssistedBase::PreCallValidateCmdWaitEvents2(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
572 const VkDependencyInfo *pDependencyInfos) const {
573 VkPipelineStageFlags2 src_stage_mask = 0;
574
575 for (uint32_t i = 0; i < eventCount; i++) {
576 auto stage_masks = sync_utils::GetGlobalStageMasks(pDependencyInfos[i]);
577 src_stage_mask |= stage_masks.src;
578 }
579
580 ValidationStateTracker::PreCallValidateCmdWaitEvents2(commandBuffer, eventCount, pEvents, pDependencyInfos);
581 return ValidateCmdWaitEvents(commandBuffer, src_stage_mask, CMD_WAITEVENTS2);
582}
583
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600584void GpuAssistedBase::PreCallRecordCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
585 const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout,
586 void *cpl_state_data) {
587 if (aborted) {
588 return;
589 }
590 auto cpl_state = static_cast<create_pipeline_layout_api_state *>(cpl_state_data);
591 if (cpl_state->modified_create_info.setLayoutCount >= adjusted_max_desc_sets) {
592 std::ostringstream strm;
593 strm << "Pipeline Layout conflict with validation's descriptor set at slot " << desc_set_bind_index << ". "
594 << "Application has too many descriptor sets in the pipeline layout to continue with gpu validation. "
595 << "Validation is not modifying the pipeline layout. "
596 << "Instrumented shaders are replaced with non-instrumented shaders.";
597 ReportSetupProblem(device, strm.str().c_str());
598 } else {
599 // Modify the pipeline layout by:
600 // 1. Copying the caller's descriptor set desc_layouts
601 // 2. Fill in dummy descriptor layouts up to the max binding
602 // 3. Fill in with the debug descriptor layout at the max binding slot
603 cpl_state->new_layouts.reserve(adjusted_max_desc_sets);
604 cpl_state->new_layouts.insert(cpl_state->new_layouts.end(), &pCreateInfo->pSetLayouts[0],
605 &pCreateInfo->pSetLayouts[pCreateInfo->setLayoutCount]);
606 for (uint32_t i = pCreateInfo->setLayoutCount; i < adjusted_max_desc_sets - 1; ++i) {
607 cpl_state->new_layouts.push_back(dummy_desc_layout);
608 }
609 cpl_state->new_layouts.push_back(debug_desc_layout);
610 cpl_state->modified_create_info.pSetLayouts = cpl_state->new_layouts.data();
611 cpl_state->modified_create_info.setLayoutCount = adjusted_max_desc_sets;
612 }
613 ValidationStateTracker::PreCallRecordCreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout, cpl_state_data);
614}
615
616void GpuAssistedBase::PostCallRecordCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
617 const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout,
618 VkResult result) {
619 if (result != VK_SUCCESS) {
620 ReportSetupProblem(device, "Unable to create pipeline layout. Device could become unstable.");
621 aborted = true;
622 }
623 ValidationStateTracker::PostCallRecordCreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout, result);
624}
625
626void GpuAssistedBase::PreCallRecordCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
627 const VkGraphicsPipelineCreateInfo *pCreateInfos,
628 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
629 void *cgpl_state_data) {
630 if (aborted) return;
631 std::vector<safe_VkGraphicsPipelineCreateInfo> new_pipeline_create_infos;
632 create_graphics_pipeline_api_state *cgpl_state = reinterpret_cast<create_graphics_pipeline_api_state *>(cgpl_state_data);
633 PreCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, cgpl_state->pipe_state, &new_pipeline_create_infos,
634 VK_PIPELINE_BIND_POINT_GRAPHICS);
Tony-LunarG806cddb2022-05-11 15:32:48 -0600635 cgpl_state->modified_create_infos = new_pipeline_create_infos;
636 cgpl_state->pCreateInfos = reinterpret_cast<VkGraphicsPipelineCreateInfo *>(cgpl_state->modified_create_infos.data());
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600637}
638
639void GpuAssistedBase::PreCallRecordCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
640 const VkComputePipelineCreateInfo *pCreateInfos,
641 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
642 void *ccpl_state_data) {
643 if (aborted) return;
644 std::vector<safe_VkComputePipelineCreateInfo> new_pipeline_create_infos;
645 auto *ccpl_state = reinterpret_cast<create_compute_pipeline_api_state *>(ccpl_state_data);
646 PreCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, ccpl_state->pipe_state, &new_pipeline_create_infos,
647 VK_PIPELINE_BIND_POINT_COMPUTE);
Tony-LunarG806cddb2022-05-11 15:32:48 -0600648 ccpl_state->modified_create_infos = new_pipeline_create_infos;
649 ccpl_state->pCreateInfos = reinterpret_cast<VkComputePipelineCreateInfo *>(ccpl_state->modified_create_infos.data());
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600650}
651
652void GpuAssistedBase::PreCallRecordCreateRayTracingPipelinesNV(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
653 const VkRayTracingPipelineCreateInfoNV *pCreateInfos,
654 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
655 void *crtpl_state_data) {
656 if (aborted) return;
657 std::vector<safe_VkRayTracingPipelineCreateInfoCommon> new_pipeline_create_infos;
658 auto *crtpl_state = reinterpret_cast<create_ray_tracing_pipeline_api_state *>(crtpl_state_data);
659 PreCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, crtpl_state->pipe_state, &new_pipeline_create_infos,
660 VK_PIPELINE_BIND_POINT_RAY_TRACING_NV);
Tony-LunarG806cddb2022-05-11 15:32:48 -0600661 crtpl_state->modified_create_infos = new_pipeline_create_infos;
662 crtpl_state->pCreateInfos = reinterpret_cast<VkRayTracingPipelineCreateInfoNV *>(crtpl_state->modified_create_infos.data());
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600663}
664
665void GpuAssistedBase::PreCallRecordCreateRayTracingPipelinesKHR(VkDevice device, VkDeferredOperationKHR deferredOperation,
666 VkPipelineCache pipelineCache, uint32_t count,
667 const VkRayTracingPipelineCreateInfoKHR *pCreateInfos,
668 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
669 void *crtpl_state_data) {
670 if (aborted) return;
671 std::vector<safe_VkRayTracingPipelineCreateInfoCommon> new_pipeline_create_infos;
672 auto *crtpl_state = reinterpret_cast<create_ray_tracing_pipeline_khr_api_state *>(crtpl_state_data);
673 PreCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, crtpl_state->pipe_state, &new_pipeline_create_infos,
674 VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR);
Tony-LunarG806cddb2022-05-11 15:32:48 -0600675 crtpl_state->modified_create_infos = new_pipeline_create_infos;
676 crtpl_state->pCreateInfos = reinterpret_cast<VkRayTracingPipelineCreateInfoKHR *>(crtpl_state->modified_create_infos.data());
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600677}
678
679template <typename CreateInfos, typename SafeCreateInfos>
680static void UtilCopyCreatePipelineFeedbackData(const uint32_t count, CreateInfos *pCreateInfos, SafeCreateInfos *pSafeCreateInfos) {
681 for (uint32_t i = 0; i < count; i++) {
682 auto src_feedback_struct = LvlFindInChain<VkPipelineCreationFeedbackCreateInfoEXT>(pSafeCreateInfos[i].pNext);
683 if (!src_feedback_struct) return;
684 auto dst_feedback_struct = const_cast<VkPipelineCreationFeedbackCreateInfoEXT *>(
685 LvlFindInChain<VkPipelineCreationFeedbackCreateInfoEXT>(pCreateInfos[i].pNext));
686 *dst_feedback_struct->pPipelineCreationFeedback = *src_feedback_struct->pPipelineCreationFeedback;
687 for (uint32_t j = 0; j < src_feedback_struct->pipelineStageCreationFeedbackCount; j++) {
688 dst_feedback_struct->pPipelineStageCreationFeedbacks[j] = src_feedback_struct->pPipelineStageCreationFeedbacks[j];
689 }
690 }
691}
692
693void GpuAssistedBase::PostCallRecordCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
694 const VkGraphicsPipelineCreateInfo *pCreateInfos,
695 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
696 VkResult result, void *cgpl_state_data) {
697 ValidationStateTracker::PostCallRecordCreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pAllocator,
698 pPipelines, result, cgpl_state_data);
699 if (aborted) return;
700 create_graphics_pipeline_api_state *cgpl_state = reinterpret_cast<create_graphics_pipeline_api_state *>(cgpl_state_data);
Tony-LunarG806cddb2022-05-11 15:32:48 -0600701 UtilCopyCreatePipelineFeedbackData(count, pCreateInfos, cgpl_state->modified_create_infos.data());
Tony-LunarGabe71bd2022-05-11 15:58:16 -0600702 PostCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, VK_PIPELINE_BIND_POINT_GRAPHICS,
703 cgpl_state->modified_create_infos.data());
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600704}
705
706void GpuAssistedBase::PostCallRecordCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
707 const VkComputePipelineCreateInfo *pCreateInfos,
708 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
709 VkResult result, void *ccpl_state_data) {
710 ValidationStateTracker::PostCallRecordCreateComputePipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines,
711 result, ccpl_state_data);
712 if (aborted) return;
713 create_compute_pipeline_api_state *ccpl_state = reinterpret_cast<create_compute_pipeline_api_state *>(ccpl_state_data);
Tony-LunarG806cddb2022-05-11 15:32:48 -0600714 UtilCopyCreatePipelineFeedbackData(count, pCreateInfos, ccpl_state->modified_create_infos.data());
Tony-LunarGabe71bd2022-05-11 15:58:16 -0600715 PostCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, VK_PIPELINE_BIND_POINT_COMPUTE,
716 ccpl_state->modified_create_infos.data());
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600717}
718
719void GpuAssistedBase::PostCallRecordCreateRayTracingPipelinesNV(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
720 const VkRayTracingPipelineCreateInfoNV *pCreateInfos,
721 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
722 VkResult result, void *crtpl_state_data) {
723 auto *crtpl_state = reinterpret_cast<create_ray_tracing_pipeline_khr_api_state *>(crtpl_state_data);
724 ValidationStateTracker::PostCallRecordCreateRayTracingPipelinesNV(device, pipelineCache, count, pCreateInfos, pAllocator,
725 pPipelines, result, crtpl_state_data);
726 if (aborted) return;
Tony-LunarG806cddb2022-05-11 15:32:48 -0600727 UtilCopyCreatePipelineFeedbackData(count, pCreateInfos, crtpl_state->modified_create_infos.data());
Tony-LunarGabe71bd2022-05-11 15:58:16 -0600728 PostCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, VK_PIPELINE_BIND_POINT_RAY_TRACING_NV,
729 crtpl_state->modified_create_infos.data());
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600730}
731
732void GpuAssistedBase::PostCallRecordCreateRayTracingPipelinesKHR(VkDevice device, VkDeferredOperationKHR deferredOperation,
733 VkPipelineCache pipelineCache, uint32_t count,
734 const VkRayTracingPipelineCreateInfoKHR *pCreateInfos,
735 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
736 VkResult result, void *crtpl_state_data) {
737 auto *crtpl_state = reinterpret_cast<create_ray_tracing_pipeline_khr_api_state *>(crtpl_state_data);
738 ValidationStateTracker::PostCallRecordCreateRayTracingPipelinesKHR(
739 device, deferredOperation, pipelineCache, count, pCreateInfos, pAllocator, pPipelines, result, crtpl_state_data);
740 if (aborted) return;
Tony-LunarG806cddb2022-05-11 15:32:48 -0600741 UtilCopyCreatePipelineFeedbackData(count, pCreateInfos, crtpl_state->modified_create_infos.data());
Tony-LunarGabe71bd2022-05-11 15:58:16 -0600742 PostCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR,
743 crtpl_state->modified_create_infos.data());
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600744}
745
746// Remove all the shader trackers associated with this destroyed pipeline.
747void GpuAssistedBase::PreCallRecordDestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) {
Jeremy Gebben58cc9d12022-03-23 17:04:57 -0600748 auto to_erase = shader_map.snapshot([pipeline](const GpuAssistedShaderTracker &entry) { return entry.pipeline == pipeline; });
749 for (const auto &entry : to_erase) {
750 shader_map.erase(entry.first);
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600751 }
752 ValidationStateTracker::PreCallRecordDestroyPipeline(device, pipeline, pAllocator);
753}
754
755template <typename CreateInfo>
756struct CreatePipelineTraits {};
757template <>
758struct CreatePipelineTraits<VkGraphicsPipelineCreateInfo> {
759 using SafeType = safe_VkGraphicsPipelineCreateInfo;
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600760 static uint32_t GetStageCount(const VkGraphicsPipelineCreateInfo &createInfo) { return createInfo.stageCount; }
Tony-LunarG0f647382022-05-12 15:11:59 -0600761 static VkShaderModule GetShaderModule(const VkGraphicsPipelineCreateInfo &createInfo, uint32_t stage) {
762 return createInfo.pStages[stage].module;
763 }
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600764 static void SetShaderModule(SafeType *createInfo, VkShaderModule shader_module, uint32_t stage) {
765 createInfo->pStages[stage].module = shader_module;
766 }
767};
768
769template <>
770struct CreatePipelineTraits<VkComputePipelineCreateInfo> {
771 using SafeType = safe_VkComputePipelineCreateInfo;
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600772 static uint32_t GetStageCount(const VkComputePipelineCreateInfo &createInfo) { return 1; }
Tony-LunarG0f647382022-05-12 15:11:59 -0600773 static VkShaderModule GetShaderModule(const VkComputePipelineCreateInfo &createInfo, uint32_t stage) {
774 return createInfo.stage.module;
775 }
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600776 static void SetShaderModule(SafeType *createInfo, VkShaderModule shader_module, uint32_t stage) {
777 assert(stage == 0);
778 createInfo->stage.module = shader_module;
779 }
780};
781
782template <>
783struct CreatePipelineTraits<VkRayTracingPipelineCreateInfoNV> {
784 using SafeType = safe_VkRayTracingPipelineCreateInfoCommon;
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600785 static uint32_t GetStageCount(const VkRayTracingPipelineCreateInfoNV &createInfo) { return createInfo.stageCount; }
Tony-LunarG0f647382022-05-12 15:11:59 -0600786 static VkShaderModule GetShaderModule(const VkRayTracingPipelineCreateInfoNV &createInfo, uint32_t stage) {
787 return createInfo.pStages[stage].module;
788 }
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600789 static void SetShaderModule(SafeType *createInfo, VkShaderModule shader_module, uint32_t stage) {
790 createInfo->pStages[stage].module = shader_module;
791 }
792};
793
794template <>
795struct CreatePipelineTraits<VkRayTracingPipelineCreateInfoKHR> {
796 using SafeType = safe_VkRayTracingPipelineCreateInfoCommon;
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600797 static uint32_t GetStageCount(const VkRayTracingPipelineCreateInfoKHR &createInfo) { return createInfo.stageCount; }
Tony-LunarG0f647382022-05-12 15:11:59 -0600798 static VkShaderModule GetShaderModule(const VkRayTracingPipelineCreateInfoKHR &createInfo, uint32_t stage) {
799 return createInfo.pStages[stage].module;
800 }
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600801 static void SetShaderModule(SafeType *createInfo, VkShaderModule shader_module, uint32_t stage) {
802 createInfo->pStages[stage].module = shader_module;
803 }
804};
805
806// Examine the pipelines to see if they use the debug descriptor set binding index.
807// If any do, create new non-instrumented shader modules and use them to replace the instrumented
808// shaders in the pipeline. Return the (possibly) modified create infos to the caller.
809template <typename CreateInfo, typename SafeCreateInfo>
810void GpuAssistedBase::PreCallRecordPipelineCreations(uint32_t count, const CreateInfo *pCreateInfos,
811 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
812 std::vector<std::shared_ptr<PIPELINE_STATE>> &pipe_state,
813 std::vector<SafeCreateInfo> *new_pipeline_create_infos,
814 const VkPipelineBindPoint bind_point) {
815 using Accessor = CreatePipelineTraits<CreateInfo>;
816 if (bind_point != VK_PIPELINE_BIND_POINT_GRAPHICS && bind_point != VK_PIPELINE_BIND_POINT_COMPUTE &&
sjfricke62366d32022-08-01 21:04:10 +0900817 bind_point != VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR) {
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600818 return;
819 }
820
821 // Walk through all the pipelines, make a copy of each and flag each pipeline that contains a shader that uses the debug
822 // descriptor set index.
823 for (uint32_t pipeline = 0; pipeline < count; ++pipeline) {
824 uint32_t stageCount = Accessor::GetStageCount(pCreateInfos[pipeline]);
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600825 const auto &pipe = pipe_state[pipeline];
Nathaniel Cesariod4d8fce2022-05-06 15:01:10 -0600826 new_pipeline_create_infos->push_back(pipe->GetCreateInfo<CreateInfo>());
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600827
828 if (!pipe->IsGraphicsLibrary()) {
829 bool replace_shaders = false;
830 if (pipe->active_slots.find(desc_set_bind_index) != pipe->active_slots.end()) {
831 replace_shaders = true;
832 }
833 // If the app requests all available sets, the pipeline layout was not modified at pipeline layout creation and the
834 // already instrumented shaders need to be replaced with uninstrumented shaders
835 const auto pipeline_layout = pipe->PipelineLayoutState();
836 if (pipeline_layout->set_layouts.size() >= adjusted_max_desc_sets) {
837 replace_shaders = true;
838 }
839
840 if (replace_shaders) {
841 for (uint32_t stage = 0; stage < stageCount; ++stage) {
Nathaniel Cesariod4d8fce2022-05-06 15:01:10 -0600842 const auto module_state = Get<SHADER_MODULE_STATE>(pipe->GetShaderModuleByCIIndex<CreateInfo>(stage));
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600843
844 VkShaderModule shader_module;
845 auto create_info = LvlInitStruct<VkShaderModuleCreateInfo>();
846 create_info.pCode = module_state->words.data();
847 create_info.codeSize = module_state->words.size() * sizeof(uint32_t);
848 VkResult result = DispatchCreateShaderModule(device, &create_info, pAllocator, &shader_module);
849 if (result == VK_SUCCESS) {
850 Accessor::SetShaderModule(&(*new_pipeline_create_infos)[pipeline], shader_module, stage);
851 } else {
852 ReportSetupProblem(device,
853 "Unable to replace instrumented shader with non-instrumented one. "
854 "Device could become unstable.");
855 }
856 }
857 }
858 }
859 }
860}
861// For every pipeline:
862// - For every shader in a pipeline:
863// - If the shader had to be replaced in PreCallRecord (because the pipeline is using the debug desc set index):
864// - Destroy it since it has been bound into the pipeline by now. This is our only chance to delete it.
865// - Track the shader in the shader_map
866// - Save the shader binary if it contains debug code
Tony-LunarGabe71bd2022-05-11 15:58:16 -0600867template <typename CreateInfo, typename SafeCreateInfo>
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600868void GpuAssistedBase::PostCallRecordPipelineCreations(const uint32_t count, const CreateInfo *pCreateInfos,
869 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
Tony-LunarG0f647382022-05-12 15:11:59 -0600870 const VkPipelineBindPoint bind_point, const SafeCreateInfo &modified_create_infos) {
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600871 if (bind_point != VK_PIPELINE_BIND_POINT_GRAPHICS && bind_point != VK_PIPELINE_BIND_POINT_COMPUTE &&
sjfricke62366d32022-08-01 21:04:10 +0900872 bind_point != VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR) {
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600873 return;
874 }
875 for (uint32_t pipeline = 0; pipeline < count; ++pipeline) {
876 auto pipeline_state = Get<PIPELINE_STATE>(pPipelines[pipeline]);
877 if (!pipeline_state || pipeline_state->IsGraphicsLibrary()) continue;
878
879 const uint32_t stageCount = static_cast<uint32_t>(pipeline_state->stage_state.size());
880 assert(stageCount > 0);
881
Tony-LunarG0f647382022-05-12 15:11:59 -0600882 const auto pipeline_layout = pipeline_state->PipelineLayoutState();
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600883 for (uint32_t stage = 0; stage < stageCount; ++stage) {
Nathaniel Cesariod4d8fce2022-05-06 15:01:10 -0600884 assert((bind_point != VK_PIPELINE_BIND_POINT_COMPUTE) || (stage == 0));
885 auto shader_module = pipeline_state->GetShaderModuleByCIIndex<CreateInfo>(stage);
886 auto module_state = Get<SHADER_MODULE_STATE>(shader_module);
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600887
Tony-LunarG0f647382022-05-12 15:11:59 -0600888 if (pipeline_state->active_slots.find(desc_set_bind_index) != pipeline_state->active_slots.end() ||
889 (pipeline_layout->set_layouts.size() >= adjusted_max_desc_sets)) {
890 auto *modified_ci = reinterpret_cast<const CreateInfo *>(modified_create_infos[pipeline].ptr());
891 auto uninstrumented_module = CreatePipelineTraits<CreateInfo>::GetShaderModule(*modified_ci, stage);
892 assert(uninstrumented_module != shader_module);
893 DispatchDestroyShaderModule(device, uninstrumented_module, pAllocator);
894 }
895
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600896 std::vector<unsigned int> code;
897 // Save the shader binary
898 // The core_validation ShaderModule tracker saves the binary too, but discards it when the ShaderModule
899 // is destroyed. Applications may destroy ShaderModules after they are placed in a pipeline and before
900 // the pipeline is used, so we have to keep another copy.
901 if (module_state && module_state->has_valid_spirv) code = module_state->words;
902
Jeremy Gebben58cc9d12022-03-23 17:04:57 -0600903 shader_map.insert_or_assign(module_state->gpu_validation_shader_id, pipeline_state->pipeline(), shader_module,
904 std::move(code));
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600905 }
906 }
907}
908
Tony-LunarG1dce2392019-10-23 16:49:29 -0600909// Generate the stage-specific part of the message.
Tony-LunarGb5fae462020-03-05 12:43:25 -0700910void UtilGenerateStageMessage(const uint32_t *debug_record, std::string &msg) {
Tony-LunarG1dce2392019-10-23 16:49:29 -0600911 using namespace spvtools;
912 std::ostringstream strm;
913 switch (debug_record[kInstCommonOutStageIdx]) {
914 case spv::ExecutionModelVertex: {
915 strm << "Stage = Vertex. Vertex Index = " << debug_record[kInstVertOutVertexIndex]
916 << " Instance Index = " << debug_record[kInstVertOutInstanceIndex] << ". ";
917 } break;
918 case spv::ExecutionModelTessellationControl: {
919 strm << "Stage = Tessellation Control. Invocation ID = " << debug_record[kInstTessCtlOutInvocationId]
920 << ", Primitive ID = " << debug_record[kInstTessCtlOutPrimitiveId];
921 } break;
922 case spv::ExecutionModelTessellationEvaluation: {
923 strm << "Stage = Tessellation Eval. Primitive ID = " << debug_record[kInstTessEvalOutPrimitiveId]
924 << ", TessCoord (u, v) = (" << debug_record[kInstTessEvalOutTessCoordU] << ", "
925 << debug_record[kInstTessEvalOutTessCoordV] << "). ";
926 } break;
927 case spv::ExecutionModelGeometry: {
928 strm << "Stage = Geometry. Primitive ID = " << debug_record[kInstGeomOutPrimitiveId]
929 << " Invocation ID = " << debug_record[kInstGeomOutInvocationId] << ". ";
930 } break;
931 case spv::ExecutionModelFragment: {
932 strm << "Stage = Fragment. Fragment coord (x,y) = ("
933 << *reinterpret_cast<const float *>(&debug_record[kInstFragOutFragCoordX]) << ", "
934 << *reinterpret_cast<const float *>(&debug_record[kInstFragOutFragCoordY]) << "). ";
935 } break;
936 case spv::ExecutionModelGLCompute: {
937 strm << "Stage = Compute. Global invocation ID (x, y, z) = (" << debug_record[kInstCompOutGlobalInvocationIdX] << ", "
938 << debug_record[kInstCompOutGlobalInvocationIdY] << ", " << debug_record[kInstCompOutGlobalInvocationIdZ] << " )";
939 } break;
940 case spv::ExecutionModelRayGenerationNV: {
941 strm << "Stage = Ray Generation. Global Launch ID (x,y,z) = (" << debug_record[kInstRayTracingOutLaunchIdX] << ", "
942 << debug_record[kInstRayTracingOutLaunchIdY] << ", " << debug_record[kInstRayTracingOutLaunchIdZ] << "). ";
943 } break;
944 case spv::ExecutionModelIntersectionNV: {
945 strm << "Stage = Intersection. Global Launch ID (x,y,z) = (" << debug_record[kInstRayTracingOutLaunchIdX] << ", "
946 << debug_record[kInstRayTracingOutLaunchIdY] << ", " << debug_record[kInstRayTracingOutLaunchIdZ] << "). ";
947 } break;
948 case spv::ExecutionModelAnyHitNV: {
949 strm << "Stage = Any Hit. Global Launch ID (x,y,z) = (" << debug_record[kInstRayTracingOutLaunchIdX] << ", "
950 << debug_record[kInstRayTracingOutLaunchIdY] << ", " << debug_record[kInstRayTracingOutLaunchIdZ] << "). ";
951 } break;
952 case spv::ExecutionModelClosestHitNV: {
953 strm << "Stage = Closest Hit. Global Launch ID (x,y,z) = (" << debug_record[kInstRayTracingOutLaunchIdX] << ", "
954 << debug_record[kInstRayTracingOutLaunchIdY] << ", " << debug_record[kInstRayTracingOutLaunchIdZ] << "). ";
955 } break;
956 case spv::ExecutionModelMissNV: {
957 strm << "Stage = Miss. Global Launch ID (x,y,z) = (" << debug_record[kInstRayTracingOutLaunchIdX] << ", "
958 << debug_record[kInstRayTracingOutLaunchIdY] << ", " << debug_record[kInstRayTracingOutLaunchIdZ] << "). ";
959 } break;
960 case spv::ExecutionModelCallableNV: {
961 strm << "Stage = Callable. Global Launch ID (x,y,z) = (" << debug_record[kInstRayTracingOutLaunchIdX] << ", "
962 << debug_record[kInstRayTracingOutLaunchIdY] << ", " << debug_record[kInstRayTracingOutLaunchIdZ] << "). ";
963 } break;
Tony-LunarGc7ed2082020-06-11 14:00:04 -0600964 case spv::ExecutionModelTaskNV: {
965 strm << "Stage = Task. Global invocation ID (x, y, z) = (" << debug_record[kInstTaskOutGlobalInvocationIdX] << ", "
966 << debug_record[kInstTaskOutGlobalInvocationIdY] << ", " << debug_record[kInstTaskOutGlobalInvocationIdZ] << " )";
967 } break;
968 case spv::ExecutionModelMeshNV: {
969 strm << "Stage = Mesh.Global invocation ID (x, y, z) = (" << debug_record[kInstMeshOutGlobalInvocationIdX] << ", "
970 << debug_record[kInstMeshOutGlobalInvocationIdY] << ", " << debug_record[kInstMeshOutGlobalInvocationIdZ] << " )";
971 } break;
Tony-LunarG1dce2392019-10-23 16:49:29 -0600972 default: {
973 strm << "Internal Error (unexpected stage = " << debug_record[kInstCommonOutStageIdx] << "). ";
974 assert(false);
975 } break;
976 }
977 msg = strm.str();
978}
979
980std::string LookupDebugUtilsName(const debug_report_data *report_data, const uint64_t object) {
981 auto object_label = report_data->DebugReportGetUtilsObjectName(object);
982 if (object_label != "") {
983 object_label = "(" + object_label + ")";
984 }
985 return object_label;
986}
987
988// Generate message from the common portion of the debug report record.
Tony-LunarGb5fae462020-03-05 12:43:25 -0700989void UtilGenerateCommonMessage(const debug_report_data *report_data, const VkCommandBuffer commandBuffer,
990 const uint32_t *debug_record, const VkShaderModule shader_module_handle,
991 const VkPipeline pipeline_handle, const VkPipelineBindPoint pipeline_bind_point,
992 const uint32_t operation_index, std::string &msg) {
Tony-LunarG1dce2392019-10-23 16:49:29 -0600993 using namespace spvtools;
994 std::ostringstream strm;
995 if (shader_module_handle == VK_NULL_HANDLE) {
996 strm << std::hex << std::showbase << "Internal Error: Unable to locate information for shader used in command buffer "
997 << LookupDebugUtilsName(report_data, HandleToUint64(commandBuffer)) << "(" << HandleToUint64(commandBuffer) << "). ";
998 assert(true);
999 } else {
1000 strm << std::hex << std::showbase << "Command buffer " << LookupDebugUtilsName(report_data, HandleToUint64(commandBuffer))
1001 << "(" << HandleToUint64(commandBuffer) << "). ";
1002 if (pipeline_bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS) {
1003 strm << "Draw ";
1004 } else if (pipeline_bind_point == VK_PIPELINE_BIND_POINT_COMPUTE) {
sjfricke9a209802022-08-03 17:57:40 +09001005 strm << "Compute Dispatch ";
sjfricke62366d32022-08-01 21:04:10 +09001006 } else if (pipeline_bind_point == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR) {
Tony-LunarG1dce2392019-10-23 16:49:29 -06001007 strm << "Ray Trace ";
1008 } else {
1009 assert(false);
1010 strm << "Unknown Pipeline Operation ";
1011 }
1012 strm << "Index " << operation_index << ". "
1013 << "Pipeline " << LookupDebugUtilsName(report_data, HandleToUint64(pipeline_handle)) << "("
1014 << HandleToUint64(pipeline_handle) << "). "
1015 << "Shader Module " << LookupDebugUtilsName(report_data, HandleToUint64(shader_module_handle)) << "("
1016 << HandleToUint64(shader_module_handle) << "). ";
1017 }
1018 strm << std::dec << std::noshowbase;
1019 strm << "Shader Instruction Index = " << debug_record[kInstCommonOutInstructionIdx] << ". ";
1020 msg = strm.str();
1021}
1022
1023// Read the contents of the SPIR-V OpSource instruction and any following continuation instructions.
1024// Split the single string into a vector of strings, one for each line, for easier processing.
sfricke-samsungef15e482022-01-26 11:32:49 -08001025void ReadOpSource(const SHADER_MODULE_STATE &module_state, const uint32_t reported_file_id,
1026 std::vector<std::string> &opsource_lines) {
1027 for (auto insn : module_state) {
Tony-LunarG1dce2392019-10-23 16:49:29 -06001028 if ((insn.opcode() == spv::OpSource) && (insn.len() >= 5) && (insn.word(3) == reported_file_id)) {
1029 std::istringstream in_stream;
1030 std::string cur_line;
1031 in_stream.str((char *)&insn.word(4));
1032 while (std::getline(in_stream, cur_line)) {
1033 opsource_lines.push_back(cur_line);
1034 }
1035 while ((++insn).opcode() == spv::OpSourceContinued) {
1036 in_stream.str((char *)&insn.word(1));
1037 while (std::getline(in_stream, cur_line)) {
1038 opsource_lines.push_back(cur_line);
1039 }
1040 }
1041 break;
1042 }
1043 }
1044}
1045
1046// The task here is to search the OpSource content to find the #line directive with the
1047// line number that is closest to, but still prior to the reported error line number and
1048// still within the reported filename.
1049// From this known position in the OpSource content we can add the difference between
1050// the #line line number and the reported error line number to determine the location
1051// in the OpSource content of the reported error line.
1052//
1053// Considerations:
1054// - Look only at #line directives that specify the reported_filename since
1055// the reported error line number refers to its location in the reported filename.
1056// - If a #line directive does not have a filename, the file is the reported filename, or
1057// the filename found in a prior #line directive. (This is C-preprocessor behavior)
1058// - It is possible (e.g., inlining) for blocks of code to get shuffled out of their
1059// original order and the #line directives are used to keep the numbering correct. This
1060// is why we need to examine the entire contents of the source, instead of leaving early
1061// when finding a #line line number larger than the reported error line number.
1062//
1063
1064// GCC 4.8 has a problem with std::regex that is fixed in GCC 4.9. Provide fallback code for 4.8
1065#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
1066
1067#if defined(__GNUC__) && GCC_VERSION < 40900
1068bool GetLineAndFilename(const std::string string, uint32_t *linenumber, std::string &filename) {
1069 // # line <linenumber> "<filename>" or
1070 // #line <linenumber> "<filename>"
1071 std::vector<std::string> tokens;
1072 std::stringstream stream(string);
1073 std::string temp;
1074 uint32_t line_index = 0;
1075
1076 while (stream >> temp) tokens.push_back(temp);
1077 auto size = tokens.size();
1078 if (size > 1) {
1079 if (tokens[0] == "#" && tokens[1] == "line") {
1080 line_index = 2;
1081 } else if (tokens[0] == "#line") {
1082 line_index = 1;
1083 }
1084 }
1085 if (0 == line_index) return false;
Mark Young0ec6b062020-11-19 15:32:17 -07001086 *linenumber = static_cast<uint32_t>(std::stoul(tokens[line_index]));
Tony-LunarG1dce2392019-10-23 16:49:29 -06001087 uint32_t filename_index = line_index + 1;
1088 // Remove enclosing double quotes around filename
1089 if (size > filename_index) filename = tokens[filename_index].substr(1, tokens[filename_index].size() - 2);
1090 return true;
1091}
1092#else
1093bool GetLineAndFilename(const std::string string, uint32_t *linenumber, std::string &filename) {
1094 static const std::regex line_regex( // matches #line directives
1095 "^" // beginning of line
1096 "\\s*" // optional whitespace
1097 "#" // required text
1098 "\\s*" // optional whitespace
1099 "line" // required text
1100 "\\s+" // required whitespace
1101 "([0-9]+)" // required first capture - line number
1102 "(\\s+)?" // optional second capture - whitespace
1103 "(\".+\")?" // optional third capture - quoted filename with at least one char inside
1104 ".*"); // rest of line (needed when using std::regex_match since the entire line is tested)
1105
1106 std::smatch captures;
1107
1108 bool found_line = std::regex_match(string, captures, line_regex);
1109 if (!found_line) return false;
1110
1111 // filename is optional and considered found only if the whitespace and the filename are captured
1112 if (captures[2].matched && captures[3].matched) {
1113 // Remove enclosing double quotes. The regex guarantees the quotes and at least one char.
1114 filename = captures[3].str().substr(1, captures[3].str().size() - 2);
1115 }
Artem Bolgar82d08362021-06-03 13:11:13 -07001116 *linenumber = (uint32_t)std::stoul(captures[1]);
Tony-LunarG1dce2392019-10-23 16:49:29 -06001117 return true;
1118}
1119#endif // GCC_VERSION
1120
1121// Extract the filename, line number, and column number from the correct OpLine and build a message string from it.
1122// Scan the source (from OpSource) to find the line of source at the reported line number and place it in another message string.
sfricke-samsung7fac88a2022-01-26 11:44:22 -08001123void UtilGenerateSourceMessages(const std::vector<uint32_t> &pgm, const uint32_t *debug_record, bool from_printf,
Tony-LunarGb5fae462020-03-05 12:43:25 -07001124 std::string &filename_msg, std::string &source_msg) {
Tony-LunarG1dce2392019-10-23 16:49:29 -06001125 using namespace spvtools;
1126 std::ostringstream filename_stream;
1127 std::ostringstream source_stream;
Nathaniel Cesario77cd59b2021-10-11 23:52:24 -06001128 SHADER_MODULE_STATE shader(pgm);
Tony-LunarG1dce2392019-10-23 16:49:29 -06001129 // Find the OpLine just before the failing instruction indicated by the debug info.
1130 // SPIR-V can only be iterated in the forward direction due to its opcode/length encoding.
1131 uint32_t instruction_index = 0;
1132 uint32_t reported_file_id = 0;
1133 uint32_t reported_line_number = 0;
1134 uint32_t reported_column_number = 0;
1135 if (shader.words.size() > 0) {
John Zulauf79f06582021-02-27 18:38:39 -07001136 for (const auto &insn : shader) {
Tony-LunarG1dce2392019-10-23 16:49:29 -06001137 if (insn.opcode() == spv::OpLine) {
1138 reported_file_id = insn.word(1);
1139 reported_line_number = insn.word(2);
1140 reported_column_number = insn.word(3);
1141 }
1142 if (instruction_index == debug_record[kInstCommonOutInstructionIdx]) {
1143 break;
1144 }
1145 instruction_index++;
1146 }
1147 }
1148 // Create message with file information obtained from the OpString pointed to by the discovered OpLine.
1149 std::string reported_filename;
1150 if (reported_file_id == 0) {
1151 filename_stream
1152 << "Unable to find SPIR-V OpLine for source information. Build shader with debug info to get source information.";
1153 } else {
1154 bool found_opstring = false;
1155 std::string prefix;
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07001156 if (from_printf) {
Tony-LunarG1dce2392019-10-23 16:49:29 -06001157 prefix = "Debug shader printf message generated ";
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07001158 } else {
Tony-LunarG1dce2392019-10-23 16:49:29 -06001159 prefix = "Shader validation error occurred ";
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07001160 }
John Zulauf79f06582021-02-27 18:38:39 -07001161 for (const auto &insn : shader) {
Tony-LunarG1dce2392019-10-23 16:49:29 -06001162 if ((insn.opcode() == spv::OpString) && (insn.len() >= 3) && (insn.word(1) == reported_file_id)) {
1163 found_opstring = true;
1164 reported_filename = (char *)&insn.word(2);
1165 if (reported_filename.empty()) {
1166 filename_stream << prefix << "at line " << reported_line_number;
1167 } else {
1168 filename_stream << prefix << "in file " << reported_filename << " at line " << reported_line_number;
1169 }
1170 if (reported_column_number > 0) {
1171 filename_stream << ", column " << reported_column_number;
1172 }
1173 filename_stream << ".";
1174 break;
1175 }
1176 }
1177 if (!found_opstring) {
Tony-LunarG6d195e12020-10-27 16:54:14 -06001178 filename_stream << "Unable to find SPIR-V OpString for file id " << reported_file_id << " from OpLine instruction."
1179 << std::endl;
1180 filename_stream << "File ID = " << reported_file_id << ", Line Number = " << reported_line_number
1181 << ", Column = " << reported_column_number << std::endl;
Tony-LunarG1dce2392019-10-23 16:49:29 -06001182 }
1183 }
1184 filename_msg = filename_stream.str();
1185
1186 // Create message to display source code line containing error.
1187 if ((reported_file_id != 0)) {
1188 // Read the source code and split it up into separate lines.
1189 std::vector<std::string> opsource_lines;
1190 ReadOpSource(shader, reported_file_id, opsource_lines);
1191 // Find the line in the OpSource content that corresponds to the reported error file and line.
1192 if (!opsource_lines.empty()) {
1193 uint32_t saved_line_number = 0;
1194 std::string current_filename = reported_filename; // current "preprocessor" filename state.
1195 std::vector<std::string>::size_type saved_opsource_offset = 0;
1196 bool found_best_line = false;
1197 for (auto it = opsource_lines.begin(); it != opsource_lines.end(); ++it) {
1198 uint32_t parsed_line_number;
1199 std::string parsed_filename;
1200 bool found_line = GetLineAndFilename(*it, &parsed_line_number, parsed_filename);
1201 if (!found_line) continue;
1202
1203 bool found_filename = parsed_filename.size() > 0;
1204 if (found_filename) {
1205 current_filename = parsed_filename;
1206 }
1207 if ((!found_filename) || (current_filename == reported_filename)) {
1208 // Update the candidate best line directive, if the current one is prior and closer to the reported line
1209 if (reported_line_number >= parsed_line_number) {
1210 if (!found_best_line ||
1211 (reported_line_number - parsed_line_number <= reported_line_number - saved_line_number)) {
1212 saved_line_number = parsed_line_number;
1213 saved_opsource_offset = std::distance(opsource_lines.begin(), it);
1214 found_best_line = true;
1215 }
1216 }
1217 }
1218 }
1219 if (found_best_line) {
1220 assert(reported_line_number >= saved_line_number);
1221 std::vector<std::string>::size_type opsource_index =
1222 (reported_line_number - saved_line_number) + 1 + saved_opsource_offset;
1223 if (opsource_index < opsource_lines.size()) {
1224 source_stream << "\n" << reported_line_number << ": " << opsource_lines[opsource_index].c_str();
1225 } else {
1226 source_stream << "Internal error: calculated source line of " << opsource_index << " for source size of "
1227 << opsource_lines.size() << " lines.";
1228 }
1229 } else {
1230 source_stream << "Unable to find suitable #line directive in SPIR-V OpSource.";
1231 }
1232 } else {
1233 source_stream << "Unable to find SPIR-V OpSource.";
1234 }
1235 }
1236 source_msg = source_stream.str();
1237}