blob: ffba61dc8bd02304976756ab20b854bef9e18019 [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
Tony-LunarGb5fae462020-03-05 12:43:25 -070045UtilDescriptorSetManager::UtilDescriptorSetManager(VkDevice device, uint32_t numBindingsInSet)
Tony-LunarG1dce2392019-10-23 16:49:29 -060046 : device(device), numBindingsInSet(numBindingsInSet) {}
47
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,
93 pool_count * numBindingsInSet,
94 };
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
142static VKAPI_ATTR void VKAPI_CALL gpuVkGetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
143 VkPhysicalDeviceProperties *pProperties) {
144 DispatchGetPhysicalDeviceProperties(physicalDevice, pProperties);
145}
146static VKAPI_ATTR void VKAPI_CALL gpuVkGetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice,
147 VkPhysicalDeviceMemoryProperties *pMemoryProperties) {
148 DispatchGetPhysicalDeviceMemoryProperties(physicalDevice, pMemoryProperties);
149}
150static VKAPI_ATTR VkResult VKAPI_CALL gpuVkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
151 const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) {
152 return DispatchAllocateMemory(device, pAllocateInfo, pAllocator, pMemory);
153}
154static VKAPI_ATTR void VKAPI_CALL gpuVkFreeMemory(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks *pAllocator) {
155 DispatchFreeMemory(device, memory, pAllocator);
156}
157static VKAPI_ATTR VkResult VKAPI_CALL gpuVkMapMemory(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size,
158 VkMemoryMapFlags flags, void **ppData) {
159 return DispatchMapMemory(device, memory, offset, size, flags, ppData);
160}
161static VKAPI_ATTR void VKAPI_CALL gpuVkUnmapMemory(VkDevice device, VkDeviceMemory memory) { DispatchUnmapMemory(device, memory); }
162static VKAPI_ATTR VkResult VKAPI_CALL gpuVkFlushMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount,
163 const VkMappedMemoryRange *pMemoryRanges) {
164 return DispatchFlushMappedMemoryRanges(device, memoryRangeCount, pMemoryRanges);
165}
166static VKAPI_ATTR VkResult VKAPI_CALL gpuVkInvalidateMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount,
167 const VkMappedMemoryRange *pMemoryRanges) {
168 return DispatchInvalidateMappedMemoryRanges(device, memoryRangeCount, pMemoryRanges);
169}
170static VKAPI_ATTR VkResult VKAPI_CALL gpuVkBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory memory,
171 VkDeviceSize memoryOffset) {
172 return DispatchBindBufferMemory(device, buffer, memory, memoryOffset);
173}
174static VKAPI_ATTR VkResult VKAPI_CALL gpuVkBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory memory,
175 VkDeviceSize memoryOffset) {
176 return DispatchBindImageMemory(device, image, memory, memoryOffset);
177}
178static VKAPI_ATTR void VKAPI_CALL gpuVkGetBufferMemoryRequirements(VkDevice device, VkBuffer buffer,
179 VkMemoryRequirements *pMemoryRequirements) {
180 DispatchGetBufferMemoryRequirements(device, buffer, pMemoryRequirements);
181}
182static VKAPI_ATTR void VKAPI_CALL gpuVkGetImageMemoryRequirements(VkDevice device, VkImage image,
183 VkMemoryRequirements *pMemoryRequirements) {
184 DispatchGetImageMemoryRequirements(device, image, pMemoryRequirements);
185}
186static VKAPI_ATTR VkResult VKAPI_CALL gpuVkCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
187 const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) {
188 return DispatchCreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
189}
190static VKAPI_ATTR void VKAPI_CALL gpuVkDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
191 return DispatchDestroyBuffer(device, buffer, pAllocator);
192}
193static VKAPI_ATTR VkResult VKAPI_CALL gpuVkCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
194 const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
195 return DispatchCreateImage(device, pCreateInfo, pAllocator, pImage);
196}
197static VKAPI_ATTR void VKAPI_CALL gpuVkDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
198 DispatchDestroyImage(device, image, pAllocator);
199}
200static VKAPI_ATTR void VKAPI_CALL gpuVkCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
201 uint32_t regionCount, const VkBufferCopy *pRegions) {
202 DispatchCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions);
203}
204
Tony-LunarGb5fae462020-03-05 12:43:25 -0700205VkResult UtilInitializeVma(VkPhysicalDevice physical_device, VkDevice device, VmaAllocator *pAllocator) {
Tony-LunarG1dce2392019-10-23 16:49:29 -0600206 VmaVulkanFunctions functions;
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700207 VmaAllocatorCreateInfo allocator_info = {};
208 allocator_info.device = device;
209 allocator_info.physicalDevice = physical_device;
Tony-LunarG1dce2392019-10-23 16:49:29 -0600210
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700211 functions.vkGetPhysicalDeviceProperties = static_cast<PFN_vkGetPhysicalDeviceProperties>(gpuVkGetPhysicalDeviceProperties);
212 functions.vkGetPhysicalDeviceMemoryProperties =
213 static_cast<PFN_vkGetPhysicalDeviceMemoryProperties>(gpuVkGetPhysicalDeviceMemoryProperties);
214 functions.vkAllocateMemory = static_cast<PFN_vkAllocateMemory>(gpuVkAllocateMemory);
215 functions.vkFreeMemory = static_cast<PFN_vkFreeMemory>(gpuVkFreeMemory);
216 functions.vkMapMemory = static_cast<PFN_vkMapMemory>(gpuVkMapMemory);
217 functions.vkUnmapMemory = static_cast<PFN_vkUnmapMemory>(gpuVkUnmapMemory);
218 functions.vkFlushMappedMemoryRanges = static_cast<PFN_vkFlushMappedMemoryRanges>(gpuVkFlushMappedMemoryRanges);
219 functions.vkInvalidateMappedMemoryRanges = static_cast<PFN_vkInvalidateMappedMemoryRanges>(gpuVkInvalidateMappedMemoryRanges);
220 functions.vkBindBufferMemory = static_cast<PFN_vkBindBufferMemory>(gpuVkBindBufferMemory);
221 functions.vkBindImageMemory = static_cast<PFN_vkBindImageMemory>(gpuVkBindImageMemory);
222 functions.vkGetBufferMemoryRequirements = static_cast<PFN_vkGetBufferMemoryRequirements>(gpuVkGetBufferMemoryRequirements);
223 functions.vkGetImageMemoryRequirements = static_cast<PFN_vkGetImageMemoryRequirements>(gpuVkGetImageMemoryRequirements);
224 functions.vkCreateBuffer = static_cast<PFN_vkCreateBuffer>(gpuVkCreateBuffer);
225 functions.vkDestroyBuffer = static_cast<PFN_vkDestroyBuffer>(gpuVkDestroyBuffer);
226 functions.vkCreateImage = static_cast<PFN_vkCreateImage>(gpuVkCreateImage);
227 functions.vkDestroyImage = static_cast<PFN_vkDestroyImage>(gpuVkDestroyImage);
228 functions.vkCmdCopyBuffer = static_cast<PFN_vkCmdCopyBuffer>(gpuVkCmdCopyBuffer);
229 allocator_info.pVulkanFunctions = &functions;
Tony-LunarG1dce2392019-10-23 16:49:29 -0600230
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -0700231 return vmaCreateAllocator(&allocator_info, pAllocator);
Tony-LunarG1dce2392019-10-23 16:49:29 -0600232}
233
Jeremy Gebben5ca80b32022-04-11 10:58:39 -0600234gpu_utils_state::CommandBuffer::CommandBuffer(GpuAssistedBase *ga, VkCommandBuffer cb,
235 const VkCommandBufferAllocateInfo *pCreateInfo, const COMMAND_POOL_STATE *pool)
236 : CMD_BUFFER_STATE(ga, cb, pCreateInfo, pool) {}
237
Jeremy Gebben04697b02022-03-23 16:18:12 -0600238ReadLockGuard GpuAssistedBase::ReadLock() {
239 if (fine_grained_locking) {
240 return ReadLockGuard(validation_object_mutex, std::defer_lock);
241 } else {
242 return ReadLockGuard(validation_object_mutex);
243 }
244}
245
246WriteLockGuard GpuAssistedBase::WriteLock() {
247 if (fine_grained_locking) {
248 return WriteLockGuard(validation_object_mutex, std::defer_lock);
249 } else {
250 return WriteLockGuard(validation_object_mutex);
251 }
252}
253
Jeremy Gebben33717862022-03-28 15:53:56 -0600254void GpuAssistedBase::PreCallRecordCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
255 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, void *modified_ci) {
256 ValidationStateTracker::PreCallRecordCreateDevice(gpu, pCreateInfo, pAllocator, pDevice, modified_ci);
Tony-LunarG1dce2392019-10-23 16:49:29 -0600257 VkPhysicalDeviceFeatures *features = nullptr;
Jeremy Gebben33717862022-03-28 15:53:56 -0600258 // Use a local variable to query features since this method runs in the instance validation object.
259 // To avoid confusion and race conditions about which physical device's features are stored in the
260 // 'supported_devices' member variable, it will only be set in the device validation objects.
261 // See CreateDevice() below.
262 VkPhysicalDeviceFeatures gpu_supported_features;
263 DispatchGetPhysicalDeviceFeatures(gpu, &gpu_supported_features);
264 auto modified_create_info = static_cast<VkDeviceCreateInfo *>(modified_ci);
Tony-LunarG1dce2392019-10-23 16:49:29 -0600265 if (modified_create_info->pEnabledFeatures) {
266 // If pEnabledFeatures, VkPhysicalDeviceFeatures2 in pNext chain is not allowed
267 features = const_cast<VkPhysicalDeviceFeatures *>(modified_create_info->pEnabledFeatures);
268 } else {
269 VkPhysicalDeviceFeatures2 *features2 = nullptr;
Mark Lobodzinski1f887d32020-12-30 15:31:33 -0700270 features2 = const_cast<VkPhysicalDeviceFeatures2 *>(LvlFindInChain<VkPhysicalDeviceFeatures2>(modified_create_info->pNext));
Tony-LunarG1dce2392019-10-23 16:49:29 -0600271 if (features2) features = &features2->features;
272 }
Tony-LunarGf0634eb2021-01-05 15:11:12 -0700273 VkPhysicalDeviceFeatures new_features = {};
274 VkBool32 *desired = reinterpret_cast<VkBool32 *>(&desired_features);
275 VkBool32 *feature_ptr;
Tony-LunarG1dce2392019-10-23 16:49:29 -0600276 if (features) {
Tony-LunarGf0634eb2021-01-05 15:11:12 -0700277 feature_ptr = reinterpret_cast<VkBool32 *>(features);
Tony-LunarG1dce2392019-10-23 16:49:29 -0600278 } else {
Tony-LunarGf0634eb2021-01-05 15:11:12 -0700279 feature_ptr = reinterpret_cast<VkBool32 *>(&new_features);
280 }
281 VkBool32 *supported = reinterpret_cast<VkBool32 *>(&supported_features);
282 for (size_t i = 0; i < sizeof(VkPhysicalDeviceFeatures); i += (sizeof(VkBool32))) {
283 if (*supported && *desired) {
284 *feature_ptr = true;
285 }
286 supported++;
287 desired++;
288 feature_ptr++;
289 }
290 if (!features) {
Tony-LunarG1dce2392019-10-23 16:49:29 -0600291 delete modified_create_info->pEnabledFeatures;
292 modified_create_info->pEnabledFeatures = new VkPhysicalDeviceFeatures(new_features);
293 }
294}
295
Jeremy Gebben33717862022-03-28 15:53:56 -0600296void GpuAssistedBase::CreateDevice(const VkDeviceCreateInfo *pCreateInfo) {
297 ValidationStateTracker::CreateDevice(pCreateInfo);
298 // If api version 1.1 or later, SetDeviceLoaderData will be in the loader
299 auto chain_info = get_chain_info(pCreateInfo, VK_LOADER_DATA_CALLBACK);
300 assert(chain_info->u.pfnSetDeviceLoaderData);
301 vkSetDeviceLoaderData = chain_info->u.pfnSetDeviceLoaderData;
302
303 // Some devices have extremely high limits here, so set a reasonable max because we have to pad
304 // the pipeline layout with dummy descriptor set layouts.
305 adjusted_max_desc_sets = phys_dev_props.limits.maxBoundDescriptorSets;
306 adjusted_max_desc_sets = std::min(33U, adjusted_max_desc_sets);
307
308 // We can't do anything if there is only one.
309 // Device probably not a legit Vulkan device, since there should be at least 4. Protect ourselves.
310 if (adjusted_max_desc_sets == 1) {
311 ReportSetupProblem(device, "Device can bind only a single descriptor set.");
312 aborted = true;
313 return;
314 }
315 desc_set_bind_index = adjusted_max_desc_sets - 1;
316
317 VkResult result1 = UtilInitializeVma(physical_device, device, &vmaAllocator);
318 assert(result1 == VK_SUCCESS);
319 desc_set_manager = layer_data::make_unique<UtilDescriptorSetManager>(device, static_cast<uint32_t>(bindings_.size()));
320
321 const VkDescriptorSetLayoutCreateInfo debug_desc_layout_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, NULL, 0,
322 static_cast<uint32_t>(bindings_.size()), bindings_.data()};
323
324 const VkDescriptorSetLayoutCreateInfo dummy_desc_layout_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, NULL, 0, 0,
325 NULL};
326
327 result1 = DispatchCreateDescriptorSetLayout(device, &debug_desc_layout_info, NULL, &debug_desc_layout);
328
329 // This is a layout used to "pad" a pipeline layout to fill in any gaps to the selected bind index.
330 VkResult result2 = DispatchCreateDescriptorSetLayout(device, &dummy_desc_layout_info, NULL, &dummy_desc_layout);
331
332 assert((result1 == VK_SUCCESS) && (result2 == VK_SUCCESS));
333 if ((result1 != VK_SUCCESS) || (result2 != VK_SUCCESS)) {
334 ReportSetupProblem(device, "Unable to create descriptor set layout.");
335 if (result1 == VK_SUCCESS) {
336 DispatchDestroyDescriptorSetLayout(device, debug_desc_layout, NULL);
337 }
338 if (result2 == VK_SUCCESS) {
339 DispatchDestroyDescriptorSetLayout(device, dummy_desc_layout, NULL);
340 }
341 debug_desc_layout = VK_NULL_HANDLE;
342 dummy_desc_layout = VK_NULL_HANDLE;
343 aborted = true;
344 return;
345 }
346}
347
348void GpuAssistedBase::PreCallRecordDestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
Jeremy Gebben33717862022-03-28 15:53:56 -0600349 if (debug_desc_layout) {
350 DispatchDestroyDescriptorSetLayout(device, debug_desc_layout, NULL);
351 debug_desc_layout = VK_NULL_HANDLE;
352 }
353 if (dummy_desc_layout) {
354 DispatchDestroyDescriptorSetLayout(device, dummy_desc_layout, NULL);
355 dummy_desc_layout = VK_NULL_HANDLE;
356 }
357 ValidationStateTracker::PreCallRecordDestroyDevice(device, pAllocator);
358 // State Tracker can end up making vma calls through callbacks - don't destroy allocator until ST is done
359 if (vmaAllocator) {
360 vmaDestroyAllocator(vmaAllocator);
361 }
362 desc_set_manager.reset();
363}
364
Jeremy Gebbenfcfc33c2022-03-28 15:31:29 -0600365gpu_utils_state::Queue::Queue(GpuAssistedBase &state, VkQueue q, uint32_t index, VkDeviceQueueCreateFlags flags)
366 : QUEUE_STATE(q, index, flags), state_(state) {}
367
368gpu_utils_state::Queue::~Queue() {
369 if (barrier_command_buffer_) {
370 DispatchFreeCommandBuffers(state_.device, barrier_command_pool_, 1, &barrier_command_buffer_);
371 barrier_command_buffer_ = VK_NULL_HANDLE;
372 }
373 if (barrier_command_pool_) {
374 DispatchDestroyCommandPool(state_.device, barrier_command_pool_, NULL);
375 barrier_command_pool_ = VK_NULL_HANDLE;
376 }
377}
378
379// Submit a memory barrier on graphics queues.
380// Lazy-create and record the needed command buffer.
381void gpu_utils_state::Queue::SubmitBarrier() {
382 if (barrier_command_pool_ == VK_NULL_HANDLE) {
383 VkResult result = VK_SUCCESS;
384
385 auto pool_create_info = LvlInitStruct<VkCommandPoolCreateInfo>();
386 pool_create_info.queueFamilyIndex = queueFamilyIndex;
387 result = DispatchCreateCommandPool(state_.device, &pool_create_info, nullptr, &barrier_command_pool_);
388 if (result != VK_SUCCESS) {
389 state_.ReportSetupProblem(state_.device, "Unable to create command pool for barrier CB.");
390 barrier_command_pool_ = VK_NULL_HANDLE;
391 return;
392 }
393
394 auto buffer_alloc_info = LvlInitStruct<VkCommandBufferAllocateInfo>();
395 buffer_alloc_info.commandPool = barrier_command_pool_;
396 buffer_alloc_info.commandBufferCount = 1;
397 buffer_alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
398 result = DispatchAllocateCommandBuffers(state_.device, &buffer_alloc_info, &barrier_command_buffer_);
399 if (result != VK_SUCCESS) {
400 state_.ReportSetupProblem(state_.device, "Unable to create barrier command buffer.");
401 DispatchDestroyCommandPool(state_.device, barrier_command_pool_, nullptr);
402 barrier_command_pool_ = VK_NULL_HANDLE;
403 barrier_command_buffer_ = VK_NULL_HANDLE;
404 return;
405 }
406
407 // Hook up command buffer dispatch
408 state_.vkSetDeviceLoaderData(state_.device, barrier_command_buffer_);
409
410 // Record a global memory barrier to force availability of device memory operations to the host domain.
411 auto command_buffer_begin_info = LvlInitStruct<VkCommandBufferBeginInfo>();
412 result = DispatchBeginCommandBuffer(barrier_command_buffer_, &command_buffer_begin_info);
413 if (result == VK_SUCCESS) {
414 auto memory_barrier = LvlInitStruct<VkMemoryBarrier>();
415 memory_barrier.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT;
416 memory_barrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT;
417 DispatchCmdPipelineBarrier(barrier_command_buffer_, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0,
418 1, &memory_barrier, 0, nullptr, 0, nullptr);
419 DispatchEndCommandBuffer(barrier_command_buffer_);
420 }
421 }
422 if (barrier_command_buffer_ != VK_NULL_HANDLE) {
423 auto submit_info = LvlInitStruct<VkSubmitInfo>();
424 submit_info.commandBufferCount = 1;
425 submit_info.pCommandBuffers = &barrier_command_buffer_;
426 DispatchQueueSubmit(QUEUE_STATE::Queue(), 1, &submit_info, VK_NULL_HANDLE);
427 }
428}
429
Jeremy Gebben5ca80b32022-04-11 10:58:39 -0600430bool GpuAssistedBase::CommandBufferNeedsProcessing(VkCommandBuffer command_buffer) const {
Jeremy Gebben04697b02022-03-23 16:18:12 -0600431 auto cb_node = GetRead<gpu_utils_state::CommandBuffer>(command_buffer);
Jeremy Gebben5ca80b32022-04-11 10:58:39 -0600432 if (cb_node->NeedsProcessing()) {
433 return true;
434 }
435 for (const auto *secondary_cb : cb_node->linkedCommandBuffers) {
436 auto secondary_cb_node = static_cast<const gpu_utils_state::CommandBuffer *>(secondary_cb);
Jeremy Gebben04697b02022-03-23 16:18:12 -0600437 auto guard = secondary_cb_node->ReadLock();
Jeremy Gebben5ca80b32022-04-11 10:58:39 -0600438 if (secondary_cb_node->NeedsProcessing()) {
439 return true;
440 }
441 }
442 return false;
443}
444
445void GpuAssistedBase::ProcessCommandBuffer(VkQueue queue, VkCommandBuffer command_buffer) {
Jeremy Gebben04697b02022-03-23 16:18:12 -0600446 auto cb_node = GetWrite<gpu_utils_state::CommandBuffer>(command_buffer);
Jeremy Gebben5ca80b32022-04-11 10:58:39 -0600447
448 cb_node->Process(queue);
449 for (auto *secondary_cmd_base : cb_node->linkedCommandBuffers) {
450 auto *secondary_cb_node = static_cast<gpu_utils_state::CommandBuffer *>(secondary_cmd_base);
Jeremy Gebben04697b02022-03-23 16:18:12 -0600451 auto guard = secondary_cb_node->WriteLock();
Jeremy Gebben5ca80b32022-04-11 10:58:39 -0600452 secondary_cb_node->Process(queue);
453 }
454}
455
Jeremy Gebbenfcfc33c2022-03-28 15:31:29 -0600456// Issue a memory barrier to make GPU-written data available to host.
457// Wait for the queue to complete execution.
458// Check the debug buffers for all the command buffers that were submitted.
459void GpuAssistedBase::PostCallRecordQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence,
460 VkResult result) {
461 ValidationStateTracker::PostCallRecordQueueSubmit(queue, submitCount, pSubmits, fence, result);
462
463 if (aborted || (result != VK_SUCCESS)) return;
464 bool buffers_present = false;
465 // Don't QueueWaitIdle if there's nothing to process
466 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
467 const VkSubmitInfo *submit = &pSubmits[submit_idx];
468 for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
469 buffers_present |= CommandBufferNeedsProcessing(submit->pCommandBuffers[i]);
470 }
471 }
472 if (!buffers_present) return;
473
474 SubmitBarrier(queue);
475
476 DispatchQueueWaitIdle(queue);
477
478 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
479 const VkSubmitInfo *submit = &pSubmits[submit_idx];
480 for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
481 ProcessCommandBuffer(queue, submit->pCommandBuffers[i]);
482 }
483 }
484}
485
486void GpuAssistedBase::RecordQueueSubmit2(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2 *pSubmits, VkFence fence,
487 VkResult result) {
488 if (aborted || (result != VK_SUCCESS)) return;
489 bool buffers_present = false;
490 // Don't QueueWaitIdle if there's nothing to process
491 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
492 const VkSubmitInfo2 *submit = &pSubmits[submit_idx];
493 for (uint32_t i = 0; i < submit->commandBufferInfoCount; i++) {
494 buffers_present |= CommandBufferNeedsProcessing(submit->pCommandBufferInfos[i].commandBuffer);
495 }
496 }
497 if (!buffers_present) return;
498
499 SubmitBarrier(queue);
500
501 DispatchQueueWaitIdle(queue);
502
503 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
504 const VkSubmitInfo2 *submit = &pSubmits[submit_idx];
505 for (uint32_t i = 0; i < submit->commandBufferInfoCount; i++) {
506 ProcessCommandBuffer(queue, submit->pCommandBufferInfos[i].commandBuffer);
507 }
508 }
509}
510
511void GpuAssistedBase::PostCallRecordQueueSubmit2KHR(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2KHR *pSubmits,
512 VkFence fence, VkResult result) {
513 ValidationStateTracker::PostCallRecordQueueSubmit2KHR(queue, submitCount, pSubmits, fence, result);
514 RecordQueueSubmit2(queue, submitCount, pSubmits, fence, result);
515}
516
517void GpuAssistedBase::PostCallRecordQueueSubmit2(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2 *pSubmits, VkFence fence,
518 VkResult result) {
519 ValidationStateTracker::PostCallRecordQueueSubmit2(queue, submitCount, pSubmits, fence, result);
520 RecordQueueSubmit2(queue, submitCount, pSubmits, fence, result);
521}
522
sjfricke9a209802022-08-03 17:57:40 +0900523// Just gives a warning about a possible deadlock.
524bool GpuAssistedBase::ValidateCmdWaitEvents(VkCommandBuffer command_buffer, VkPipelineStageFlags2 src_stage_mask,
525 CMD_TYPE cmd_type) const {
526 if (src_stage_mask & VK_PIPELINE_STAGE_2_HOST_BIT) {
527 std::ostringstream error_msg;
528 error_msg << CommandTypeString(cmd_type)
529 << ": recorded with VK_PIPELINE_STAGE_HOST_BIT set. GPU-Assisted validation waits on queue completion. This wait "
530 "could block the host's signaling of this event, resulting in deadlock.";
531 ReportSetupProblem(command_buffer, error_msg.str().c_str());
532 }
533 return false;
534}
535
536bool GpuAssistedBase::PreCallValidateCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
537 VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
538 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
539 uint32_t bufferMemoryBarrierCount,
540 const VkBufferMemoryBarrier *pBufferMemoryBarriers,
541 uint32_t imageMemoryBarrierCount,
542 const VkImageMemoryBarrier *pImageMemoryBarriers) const {
543 ValidationStateTracker::PreCallValidateCmdWaitEvents(commandBuffer, eventCount, pEvents, srcStageMask, dstStageMask,
544 memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
545 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
546 return ValidateCmdWaitEvents(commandBuffer, static_cast<VkPipelineStageFlags2>(srcStageMask), CMD_WAITEVENTS);
547}
548
549bool GpuAssistedBase::PreCallValidateCmdWaitEvents2KHR(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
550 const VkDependencyInfoKHR *pDependencyInfos) const {
551 VkPipelineStageFlags2 src_stage_mask = 0;
552
553 for (uint32_t i = 0; i < eventCount; i++) {
554 auto stage_masks = sync_utils::GetGlobalStageMasks(pDependencyInfos[i]);
555 src_stage_mask |= stage_masks.src;
556 }
557
558 ValidationStateTracker::PreCallValidateCmdWaitEvents2KHR(commandBuffer, eventCount, pEvents, pDependencyInfos);
559 return ValidateCmdWaitEvents(commandBuffer, src_stage_mask, CMD_WAITEVENTS2KHR);
560}
561
562bool GpuAssistedBase::PreCallValidateCmdWaitEvents2(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
563 const VkDependencyInfo *pDependencyInfos) const {
564 VkPipelineStageFlags2 src_stage_mask = 0;
565
566 for (uint32_t i = 0; i < eventCount; i++) {
567 auto stage_masks = sync_utils::GetGlobalStageMasks(pDependencyInfos[i]);
568 src_stage_mask |= stage_masks.src;
569 }
570
571 ValidationStateTracker::PreCallValidateCmdWaitEvents2(commandBuffer, eventCount, pEvents, pDependencyInfos);
572 return ValidateCmdWaitEvents(commandBuffer, src_stage_mask, CMD_WAITEVENTS2);
573}
574
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600575void GpuAssistedBase::PreCallRecordCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
576 const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout,
577 void *cpl_state_data) {
578 if (aborted) {
579 return;
580 }
581 auto cpl_state = static_cast<create_pipeline_layout_api_state *>(cpl_state_data);
582 if (cpl_state->modified_create_info.setLayoutCount >= adjusted_max_desc_sets) {
583 std::ostringstream strm;
584 strm << "Pipeline Layout conflict with validation's descriptor set at slot " << desc_set_bind_index << ". "
585 << "Application has too many descriptor sets in the pipeline layout to continue with gpu validation. "
586 << "Validation is not modifying the pipeline layout. "
587 << "Instrumented shaders are replaced with non-instrumented shaders.";
588 ReportSetupProblem(device, strm.str().c_str());
589 } else {
590 // Modify the pipeline layout by:
591 // 1. Copying the caller's descriptor set desc_layouts
592 // 2. Fill in dummy descriptor layouts up to the max binding
593 // 3. Fill in with the debug descriptor layout at the max binding slot
594 cpl_state->new_layouts.reserve(adjusted_max_desc_sets);
595 cpl_state->new_layouts.insert(cpl_state->new_layouts.end(), &pCreateInfo->pSetLayouts[0],
596 &pCreateInfo->pSetLayouts[pCreateInfo->setLayoutCount]);
597 for (uint32_t i = pCreateInfo->setLayoutCount; i < adjusted_max_desc_sets - 1; ++i) {
598 cpl_state->new_layouts.push_back(dummy_desc_layout);
599 }
600 cpl_state->new_layouts.push_back(debug_desc_layout);
601 cpl_state->modified_create_info.pSetLayouts = cpl_state->new_layouts.data();
602 cpl_state->modified_create_info.setLayoutCount = adjusted_max_desc_sets;
603 }
604 ValidationStateTracker::PreCallRecordCreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout, cpl_state_data);
605}
606
607void GpuAssistedBase::PostCallRecordCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
608 const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout,
609 VkResult result) {
610 if (result != VK_SUCCESS) {
611 ReportSetupProblem(device, "Unable to create pipeline layout. Device could become unstable.");
612 aborted = true;
613 }
614 ValidationStateTracker::PostCallRecordCreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout, result);
615}
616
617void GpuAssistedBase::PreCallRecordCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
618 const VkGraphicsPipelineCreateInfo *pCreateInfos,
619 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
620 void *cgpl_state_data) {
621 if (aborted) return;
622 std::vector<safe_VkGraphicsPipelineCreateInfo> new_pipeline_create_infos;
623 create_graphics_pipeline_api_state *cgpl_state = reinterpret_cast<create_graphics_pipeline_api_state *>(cgpl_state_data);
624 PreCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, cgpl_state->pipe_state, &new_pipeline_create_infos,
625 VK_PIPELINE_BIND_POINT_GRAPHICS);
Tony-LunarG806cddb2022-05-11 15:32:48 -0600626 cgpl_state->modified_create_infos = new_pipeline_create_infos;
627 cgpl_state->pCreateInfos = reinterpret_cast<VkGraphicsPipelineCreateInfo *>(cgpl_state->modified_create_infos.data());
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600628}
629
630void GpuAssistedBase::PreCallRecordCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
631 const VkComputePipelineCreateInfo *pCreateInfos,
632 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
633 void *ccpl_state_data) {
634 if (aborted) return;
635 std::vector<safe_VkComputePipelineCreateInfo> new_pipeline_create_infos;
636 auto *ccpl_state = reinterpret_cast<create_compute_pipeline_api_state *>(ccpl_state_data);
637 PreCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, ccpl_state->pipe_state, &new_pipeline_create_infos,
638 VK_PIPELINE_BIND_POINT_COMPUTE);
Tony-LunarG806cddb2022-05-11 15:32:48 -0600639 ccpl_state->modified_create_infos = new_pipeline_create_infos;
640 ccpl_state->pCreateInfos = reinterpret_cast<VkComputePipelineCreateInfo *>(ccpl_state->modified_create_infos.data());
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600641}
642
643void GpuAssistedBase::PreCallRecordCreateRayTracingPipelinesNV(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
644 const VkRayTracingPipelineCreateInfoNV *pCreateInfos,
645 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
646 void *crtpl_state_data) {
647 if (aborted) return;
648 std::vector<safe_VkRayTracingPipelineCreateInfoCommon> new_pipeline_create_infos;
649 auto *crtpl_state = reinterpret_cast<create_ray_tracing_pipeline_api_state *>(crtpl_state_data);
650 PreCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, crtpl_state->pipe_state, &new_pipeline_create_infos,
651 VK_PIPELINE_BIND_POINT_RAY_TRACING_NV);
Tony-LunarG806cddb2022-05-11 15:32:48 -0600652 crtpl_state->modified_create_infos = new_pipeline_create_infos;
653 crtpl_state->pCreateInfos = reinterpret_cast<VkRayTracingPipelineCreateInfoNV *>(crtpl_state->modified_create_infos.data());
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600654}
655
656void GpuAssistedBase::PreCallRecordCreateRayTracingPipelinesKHR(VkDevice device, VkDeferredOperationKHR deferredOperation,
657 VkPipelineCache pipelineCache, uint32_t count,
658 const VkRayTracingPipelineCreateInfoKHR *pCreateInfos,
659 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
660 void *crtpl_state_data) {
661 if (aborted) return;
662 std::vector<safe_VkRayTracingPipelineCreateInfoCommon> new_pipeline_create_infos;
663 auto *crtpl_state = reinterpret_cast<create_ray_tracing_pipeline_khr_api_state *>(crtpl_state_data);
664 PreCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, crtpl_state->pipe_state, &new_pipeline_create_infos,
665 VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR);
Tony-LunarG806cddb2022-05-11 15:32:48 -0600666 crtpl_state->modified_create_infos = new_pipeline_create_infos;
667 crtpl_state->pCreateInfos = reinterpret_cast<VkRayTracingPipelineCreateInfoKHR *>(crtpl_state->modified_create_infos.data());
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600668}
669
670template <typename CreateInfos, typename SafeCreateInfos>
671static void UtilCopyCreatePipelineFeedbackData(const uint32_t count, CreateInfos *pCreateInfos, SafeCreateInfos *pSafeCreateInfos) {
672 for (uint32_t i = 0; i < count; i++) {
673 auto src_feedback_struct = LvlFindInChain<VkPipelineCreationFeedbackCreateInfoEXT>(pSafeCreateInfos[i].pNext);
674 if (!src_feedback_struct) return;
675 auto dst_feedback_struct = const_cast<VkPipelineCreationFeedbackCreateInfoEXT *>(
676 LvlFindInChain<VkPipelineCreationFeedbackCreateInfoEXT>(pCreateInfos[i].pNext));
677 *dst_feedback_struct->pPipelineCreationFeedback = *src_feedback_struct->pPipelineCreationFeedback;
678 for (uint32_t j = 0; j < src_feedback_struct->pipelineStageCreationFeedbackCount; j++) {
679 dst_feedback_struct->pPipelineStageCreationFeedbacks[j] = src_feedback_struct->pPipelineStageCreationFeedbacks[j];
680 }
681 }
682}
683
684void GpuAssistedBase::PostCallRecordCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
685 const VkGraphicsPipelineCreateInfo *pCreateInfos,
686 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
687 VkResult result, void *cgpl_state_data) {
688 ValidationStateTracker::PostCallRecordCreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pAllocator,
689 pPipelines, result, cgpl_state_data);
690 if (aborted) return;
691 create_graphics_pipeline_api_state *cgpl_state = reinterpret_cast<create_graphics_pipeline_api_state *>(cgpl_state_data);
Tony-LunarG806cddb2022-05-11 15:32:48 -0600692 UtilCopyCreatePipelineFeedbackData(count, pCreateInfos, cgpl_state->modified_create_infos.data());
Tony-LunarGabe71bd2022-05-11 15:58:16 -0600693 PostCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, VK_PIPELINE_BIND_POINT_GRAPHICS,
694 cgpl_state->modified_create_infos.data());
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600695}
696
697void GpuAssistedBase::PostCallRecordCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
698 const VkComputePipelineCreateInfo *pCreateInfos,
699 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
700 VkResult result, void *ccpl_state_data) {
701 ValidationStateTracker::PostCallRecordCreateComputePipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines,
702 result, ccpl_state_data);
703 if (aborted) return;
704 create_compute_pipeline_api_state *ccpl_state = reinterpret_cast<create_compute_pipeline_api_state *>(ccpl_state_data);
Tony-LunarG806cddb2022-05-11 15:32:48 -0600705 UtilCopyCreatePipelineFeedbackData(count, pCreateInfos, ccpl_state->modified_create_infos.data());
Tony-LunarGabe71bd2022-05-11 15:58:16 -0600706 PostCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, VK_PIPELINE_BIND_POINT_COMPUTE,
707 ccpl_state->modified_create_infos.data());
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600708}
709
710void GpuAssistedBase::PostCallRecordCreateRayTracingPipelinesNV(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
711 const VkRayTracingPipelineCreateInfoNV *pCreateInfos,
712 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
713 VkResult result, void *crtpl_state_data) {
714 auto *crtpl_state = reinterpret_cast<create_ray_tracing_pipeline_khr_api_state *>(crtpl_state_data);
715 ValidationStateTracker::PostCallRecordCreateRayTracingPipelinesNV(device, pipelineCache, count, pCreateInfos, pAllocator,
716 pPipelines, result, crtpl_state_data);
717 if (aborted) return;
Tony-LunarG806cddb2022-05-11 15:32:48 -0600718 UtilCopyCreatePipelineFeedbackData(count, pCreateInfos, crtpl_state->modified_create_infos.data());
Tony-LunarGabe71bd2022-05-11 15:58:16 -0600719 PostCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, VK_PIPELINE_BIND_POINT_RAY_TRACING_NV,
720 crtpl_state->modified_create_infos.data());
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600721}
722
723void GpuAssistedBase::PostCallRecordCreateRayTracingPipelinesKHR(VkDevice device, VkDeferredOperationKHR deferredOperation,
724 VkPipelineCache pipelineCache, uint32_t count,
725 const VkRayTracingPipelineCreateInfoKHR *pCreateInfos,
726 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
727 VkResult result, void *crtpl_state_data) {
728 auto *crtpl_state = reinterpret_cast<create_ray_tracing_pipeline_khr_api_state *>(crtpl_state_data);
729 ValidationStateTracker::PostCallRecordCreateRayTracingPipelinesKHR(
730 device, deferredOperation, pipelineCache, count, pCreateInfos, pAllocator, pPipelines, result, crtpl_state_data);
731 if (aborted) return;
Tony-LunarG806cddb2022-05-11 15:32:48 -0600732 UtilCopyCreatePipelineFeedbackData(count, pCreateInfos, crtpl_state->modified_create_infos.data());
Tony-LunarGabe71bd2022-05-11 15:58:16 -0600733 PostCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR,
734 crtpl_state->modified_create_infos.data());
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600735}
736
737// Remove all the shader trackers associated with this destroyed pipeline.
738void GpuAssistedBase::PreCallRecordDestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) {
Jeremy Gebben58cc9d12022-03-23 17:04:57 -0600739 auto to_erase = shader_map.snapshot([pipeline](const GpuAssistedShaderTracker &entry) { return entry.pipeline == pipeline; });
740 for (const auto &entry : to_erase) {
741 shader_map.erase(entry.first);
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600742 }
743 ValidationStateTracker::PreCallRecordDestroyPipeline(device, pipeline, pAllocator);
744}
745
746template <typename CreateInfo>
747struct CreatePipelineTraits {};
748template <>
749struct CreatePipelineTraits<VkGraphicsPipelineCreateInfo> {
750 using SafeType = safe_VkGraphicsPipelineCreateInfo;
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600751 static uint32_t GetStageCount(const VkGraphicsPipelineCreateInfo &createInfo) { return createInfo.stageCount; }
Tony-LunarG0f647382022-05-12 15:11:59 -0600752 static VkShaderModule GetShaderModule(const VkGraphicsPipelineCreateInfo &createInfo, uint32_t stage) {
753 return createInfo.pStages[stage].module;
754 }
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600755 static void SetShaderModule(SafeType *createInfo, VkShaderModule shader_module, uint32_t stage) {
756 createInfo->pStages[stage].module = shader_module;
757 }
758};
759
760template <>
761struct CreatePipelineTraits<VkComputePipelineCreateInfo> {
762 using SafeType = safe_VkComputePipelineCreateInfo;
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600763 static uint32_t GetStageCount(const VkComputePipelineCreateInfo &createInfo) { return 1; }
Tony-LunarG0f647382022-05-12 15:11:59 -0600764 static VkShaderModule GetShaderModule(const VkComputePipelineCreateInfo &createInfo, uint32_t stage) {
765 return createInfo.stage.module;
766 }
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600767 static void SetShaderModule(SafeType *createInfo, VkShaderModule shader_module, uint32_t stage) {
768 assert(stage == 0);
769 createInfo->stage.module = shader_module;
770 }
771};
772
773template <>
774struct CreatePipelineTraits<VkRayTracingPipelineCreateInfoNV> {
775 using SafeType = safe_VkRayTracingPipelineCreateInfoCommon;
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600776 static uint32_t GetStageCount(const VkRayTracingPipelineCreateInfoNV &createInfo) { return createInfo.stageCount; }
Tony-LunarG0f647382022-05-12 15:11:59 -0600777 static VkShaderModule GetShaderModule(const VkRayTracingPipelineCreateInfoNV &createInfo, uint32_t stage) {
778 return createInfo.pStages[stage].module;
779 }
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600780 static void SetShaderModule(SafeType *createInfo, VkShaderModule shader_module, uint32_t stage) {
781 createInfo->pStages[stage].module = shader_module;
782 }
783};
784
785template <>
786struct CreatePipelineTraits<VkRayTracingPipelineCreateInfoKHR> {
787 using SafeType = safe_VkRayTracingPipelineCreateInfoCommon;
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600788 static uint32_t GetStageCount(const VkRayTracingPipelineCreateInfoKHR &createInfo) { return createInfo.stageCount; }
Tony-LunarG0f647382022-05-12 15:11:59 -0600789 static VkShaderModule GetShaderModule(const VkRayTracingPipelineCreateInfoKHR &createInfo, uint32_t stage) {
790 return createInfo.pStages[stage].module;
791 }
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600792 static void SetShaderModule(SafeType *createInfo, VkShaderModule shader_module, uint32_t stage) {
793 createInfo->pStages[stage].module = shader_module;
794 }
795};
796
797// Examine the pipelines to see if they use the debug descriptor set binding index.
798// If any do, create new non-instrumented shader modules and use them to replace the instrumented
799// shaders in the pipeline. Return the (possibly) modified create infos to the caller.
800template <typename CreateInfo, typename SafeCreateInfo>
801void GpuAssistedBase::PreCallRecordPipelineCreations(uint32_t count, const CreateInfo *pCreateInfos,
802 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
803 std::vector<std::shared_ptr<PIPELINE_STATE>> &pipe_state,
804 std::vector<SafeCreateInfo> *new_pipeline_create_infos,
805 const VkPipelineBindPoint bind_point) {
806 using Accessor = CreatePipelineTraits<CreateInfo>;
807 if (bind_point != VK_PIPELINE_BIND_POINT_GRAPHICS && bind_point != VK_PIPELINE_BIND_POINT_COMPUTE &&
sjfricke62366d32022-08-01 21:04:10 +0900808 bind_point != VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR) {
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600809 return;
810 }
811
812 // Walk through all the pipelines, make a copy of each and flag each pipeline that contains a shader that uses the debug
813 // descriptor set index.
814 for (uint32_t pipeline = 0; pipeline < count; ++pipeline) {
815 uint32_t stageCount = Accessor::GetStageCount(pCreateInfos[pipeline]);
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600816 const auto &pipe = pipe_state[pipeline];
Nathaniel Cesariod4d8fce2022-05-06 15:01:10 -0600817 new_pipeline_create_infos->push_back(pipe->GetCreateInfo<CreateInfo>());
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600818
819 if (!pipe->IsGraphicsLibrary()) {
820 bool replace_shaders = false;
821 if (pipe->active_slots.find(desc_set_bind_index) != pipe->active_slots.end()) {
822 replace_shaders = true;
823 }
824 // If the app requests all available sets, the pipeline layout was not modified at pipeline layout creation and the
825 // already instrumented shaders need to be replaced with uninstrumented shaders
826 const auto pipeline_layout = pipe->PipelineLayoutState();
827 if (pipeline_layout->set_layouts.size() >= adjusted_max_desc_sets) {
828 replace_shaders = true;
829 }
830
831 if (replace_shaders) {
832 for (uint32_t stage = 0; stage < stageCount; ++stage) {
Nathaniel Cesariod4d8fce2022-05-06 15:01:10 -0600833 const auto module_state = Get<SHADER_MODULE_STATE>(pipe->GetShaderModuleByCIIndex<CreateInfo>(stage));
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600834
835 VkShaderModule shader_module;
836 auto create_info = LvlInitStruct<VkShaderModuleCreateInfo>();
837 create_info.pCode = module_state->words.data();
838 create_info.codeSize = module_state->words.size() * sizeof(uint32_t);
839 VkResult result = DispatchCreateShaderModule(device, &create_info, pAllocator, &shader_module);
840 if (result == VK_SUCCESS) {
841 Accessor::SetShaderModule(&(*new_pipeline_create_infos)[pipeline], shader_module, stage);
842 } else {
843 ReportSetupProblem(device,
844 "Unable to replace instrumented shader with non-instrumented one. "
845 "Device could become unstable.");
846 }
847 }
848 }
849 }
850 }
851}
852// For every pipeline:
853// - For every shader in a pipeline:
854// - If the shader had to be replaced in PreCallRecord (because the pipeline is using the debug desc set index):
855// - Destroy it since it has been bound into the pipeline by now. This is our only chance to delete it.
856// - Track the shader in the shader_map
857// - Save the shader binary if it contains debug code
Tony-LunarGabe71bd2022-05-11 15:58:16 -0600858template <typename CreateInfo, typename SafeCreateInfo>
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600859void GpuAssistedBase::PostCallRecordPipelineCreations(const uint32_t count, const CreateInfo *pCreateInfos,
860 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
Tony-LunarG0f647382022-05-12 15:11:59 -0600861 const VkPipelineBindPoint bind_point, const SafeCreateInfo &modified_create_infos) {
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600862 if (bind_point != VK_PIPELINE_BIND_POINT_GRAPHICS && bind_point != VK_PIPELINE_BIND_POINT_COMPUTE &&
sjfricke62366d32022-08-01 21:04:10 +0900863 bind_point != VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR) {
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600864 return;
865 }
866 for (uint32_t pipeline = 0; pipeline < count; ++pipeline) {
867 auto pipeline_state = Get<PIPELINE_STATE>(pPipelines[pipeline]);
868 if (!pipeline_state || pipeline_state->IsGraphicsLibrary()) continue;
869
870 const uint32_t stageCount = static_cast<uint32_t>(pipeline_state->stage_state.size());
871 assert(stageCount > 0);
872
Tony-LunarG0f647382022-05-12 15:11:59 -0600873 const auto pipeline_layout = pipeline_state->PipelineLayoutState();
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600874 for (uint32_t stage = 0; stage < stageCount; ++stage) {
Nathaniel Cesariod4d8fce2022-05-06 15:01:10 -0600875 assert((bind_point != VK_PIPELINE_BIND_POINT_COMPUTE) || (stage == 0));
876 auto shader_module = pipeline_state->GetShaderModuleByCIIndex<CreateInfo>(stage);
877 auto module_state = Get<SHADER_MODULE_STATE>(shader_module);
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600878
Tony-LunarG0f647382022-05-12 15:11:59 -0600879 if (pipeline_state->active_slots.find(desc_set_bind_index) != pipeline_state->active_slots.end() ||
880 (pipeline_layout->set_layouts.size() >= adjusted_max_desc_sets)) {
881 auto *modified_ci = reinterpret_cast<const CreateInfo *>(modified_create_infos[pipeline].ptr());
882 auto uninstrumented_module = CreatePipelineTraits<CreateInfo>::GetShaderModule(*modified_ci, stage);
883 assert(uninstrumented_module != shader_module);
884 DispatchDestroyShaderModule(device, uninstrumented_module, pAllocator);
885 }
886
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600887 std::vector<unsigned int> code;
888 // Save the shader binary
889 // The core_validation ShaderModule tracker saves the binary too, but discards it when the ShaderModule
890 // is destroyed. Applications may destroy ShaderModules after they are placed in a pipeline and before
891 // the pipeline is used, so we have to keep another copy.
892 if (module_state && module_state->has_valid_spirv) code = module_state->words;
893
Jeremy Gebben58cc9d12022-03-23 17:04:57 -0600894 shader_map.insert_or_assign(module_state->gpu_validation_shader_id, pipeline_state->pipeline(), shader_module,
895 std::move(code));
Jeremy Gebbenefd97802022-03-28 16:45:05 -0600896 }
897 }
898}
899
Tony-LunarG1dce2392019-10-23 16:49:29 -0600900// Generate the stage-specific part of the message.
Tony-LunarGb5fae462020-03-05 12:43:25 -0700901void UtilGenerateStageMessage(const uint32_t *debug_record, std::string &msg) {
Tony-LunarG1dce2392019-10-23 16:49:29 -0600902 using namespace spvtools;
903 std::ostringstream strm;
904 switch (debug_record[kInstCommonOutStageIdx]) {
905 case spv::ExecutionModelVertex: {
906 strm << "Stage = Vertex. Vertex Index = " << debug_record[kInstVertOutVertexIndex]
907 << " Instance Index = " << debug_record[kInstVertOutInstanceIndex] << ". ";
908 } break;
909 case spv::ExecutionModelTessellationControl: {
910 strm << "Stage = Tessellation Control. Invocation ID = " << debug_record[kInstTessCtlOutInvocationId]
911 << ", Primitive ID = " << debug_record[kInstTessCtlOutPrimitiveId];
912 } break;
913 case spv::ExecutionModelTessellationEvaluation: {
914 strm << "Stage = Tessellation Eval. Primitive ID = " << debug_record[kInstTessEvalOutPrimitiveId]
915 << ", TessCoord (u, v) = (" << debug_record[kInstTessEvalOutTessCoordU] << ", "
916 << debug_record[kInstTessEvalOutTessCoordV] << "). ";
917 } break;
918 case spv::ExecutionModelGeometry: {
919 strm << "Stage = Geometry. Primitive ID = " << debug_record[kInstGeomOutPrimitiveId]
920 << " Invocation ID = " << debug_record[kInstGeomOutInvocationId] << ". ";
921 } break;
922 case spv::ExecutionModelFragment: {
923 strm << "Stage = Fragment. Fragment coord (x,y) = ("
924 << *reinterpret_cast<const float *>(&debug_record[kInstFragOutFragCoordX]) << ", "
925 << *reinterpret_cast<const float *>(&debug_record[kInstFragOutFragCoordY]) << "). ";
926 } break;
927 case spv::ExecutionModelGLCompute: {
928 strm << "Stage = Compute. Global invocation ID (x, y, z) = (" << debug_record[kInstCompOutGlobalInvocationIdX] << ", "
929 << debug_record[kInstCompOutGlobalInvocationIdY] << ", " << debug_record[kInstCompOutGlobalInvocationIdZ] << " )";
930 } break;
931 case spv::ExecutionModelRayGenerationNV: {
932 strm << "Stage = Ray Generation. Global Launch ID (x,y,z) = (" << debug_record[kInstRayTracingOutLaunchIdX] << ", "
933 << debug_record[kInstRayTracingOutLaunchIdY] << ", " << debug_record[kInstRayTracingOutLaunchIdZ] << "). ";
934 } break;
935 case spv::ExecutionModelIntersectionNV: {
936 strm << "Stage = Intersection. Global Launch ID (x,y,z) = (" << debug_record[kInstRayTracingOutLaunchIdX] << ", "
937 << debug_record[kInstRayTracingOutLaunchIdY] << ", " << debug_record[kInstRayTracingOutLaunchIdZ] << "). ";
938 } break;
939 case spv::ExecutionModelAnyHitNV: {
940 strm << "Stage = Any Hit. Global Launch ID (x,y,z) = (" << debug_record[kInstRayTracingOutLaunchIdX] << ", "
941 << debug_record[kInstRayTracingOutLaunchIdY] << ", " << debug_record[kInstRayTracingOutLaunchIdZ] << "). ";
942 } break;
943 case spv::ExecutionModelClosestHitNV: {
944 strm << "Stage = Closest Hit. Global Launch ID (x,y,z) = (" << debug_record[kInstRayTracingOutLaunchIdX] << ", "
945 << debug_record[kInstRayTracingOutLaunchIdY] << ", " << debug_record[kInstRayTracingOutLaunchIdZ] << "). ";
946 } break;
947 case spv::ExecutionModelMissNV: {
948 strm << "Stage = Miss. Global Launch ID (x,y,z) = (" << debug_record[kInstRayTracingOutLaunchIdX] << ", "
949 << debug_record[kInstRayTracingOutLaunchIdY] << ", " << debug_record[kInstRayTracingOutLaunchIdZ] << "). ";
950 } break;
951 case spv::ExecutionModelCallableNV: {
952 strm << "Stage = Callable. Global Launch ID (x,y,z) = (" << debug_record[kInstRayTracingOutLaunchIdX] << ", "
953 << debug_record[kInstRayTracingOutLaunchIdY] << ", " << debug_record[kInstRayTracingOutLaunchIdZ] << "). ";
954 } break;
Tony-LunarGc7ed2082020-06-11 14:00:04 -0600955 case spv::ExecutionModelTaskNV: {
956 strm << "Stage = Task. Global invocation ID (x, y, z) = (" << debug_record[kInstTaskOutGlobalInvocationIdX] << ", "
957 << debug_record[kInstTaskOutGlobalInvocationIdY] << ", " << debug_record[kInstTaskOutGlobalInvocationIdZ] << " )";
958 } break;
959 case spv::ExecutionModelMeshNV: {
960 strm << "Stage = Mesh.Global invocation ID (x, y, z) = (" << debug_record[kInstMeshOutGlobalInvocationIdX] << ", "
961 << debug_record[kInstMeshOutGlobalInvocationIdY] << ", " << debug_record[kInstMeshOutGlobalInvocationIdZ] << " )";
962 } break;
Tony-LunarG1dce2392019-10-23 16:49:29 -0600963 default: {
964 strm << "Internal Error (unexpected stage = " << debug_record[kInstCommonOutStageIdx] << "). ";
965 assert(false);
966 } break;
967 }
968 msg = strm.str();
969}
970
971std::string LookupDebugUtilsName(const debug_report_data *report_data, const uint64_t object) {
972 auto object_label = report_data->DebugReportGetUtilsObjectName(object);
973 if (object_label != "") {
974 object_label = "(" + object_label + ")";
975 }
976 return object_label;
977}
978
979// Generate message from the common portion of the debug report record.
Tony-LunarGb5fae462020-03-05 12:43:25 -0700980void UtilGenerateCommonMessage(const debug_report_data *report_data, const VkCommandBuffer commandBuffer,
981 const uint32_t *debug_record, const VkShaderModule shader_module_handle,
982 const VkPipeline pipeline_handle, const VkPipelineBindPoint pipeline_bind_point,
983 const uint32_t operation_index, std::string &msg) {
Tony-LunarG1dce2392019-10-23 16:49:29 -0600984 using namespace spvtools;
985 std::ostringstream strm;
986 if (shader_module_handle == VK_NULL_HANDLE) {
987 strm << std::hex << std::showbase << "Internal Error: Unable to locate information for shader used in command buffer "
988 << LookupDebugUtilsName(report_data, HandleToUint64(commandBuffer)) << "(" << HandleToUint64(commandBuffer) << "). ";
989 assert(true);
990 } else {
991 strm << std::hex << std::showbase << "Command buffer " << LookupDebugUtilsName(report_data, HandleToUint64(commandBuffer))
992 << "(" << HandleToUint64(commandBuffer) << "). ";
993 if (pipeline_bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS) {
994 strm << "Draw ";
995 } else if (pipeline_bind_point == VK_PIPELINE_BIND_POINT_COMPUTE) {
sjfricke9a209802022-08-03 17:57:40 +0900996 strm << "Compute Dispatch ";
sjfricke62366d32022-08-01 21:04:10 +0900997 } else if (pipeline_bind_point == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR) {
Tony-LunarG1dce2392019-10-23 16:49:29 -0600998 strm << "Ray Trace ";
999 } else {
1000 assert(false);
1001 strm << "Unknown Pipeline Operation ";
1002 }
1003 strm << "Index " << operation_index << ". "
1004 << "Pipeline " << LookupDebugUtilsName(report_data, HandleToUint64(pipeline_handle)) << "("
1005 << HandleToUint64(pipeline_handle) << "). "
1006 << "Shader Module " << LookupDebugUtilsName(report_data, HandleToUint64(shader_module_handle)) << "("
1007 << HandleToUint64(shader_module_handle) << "). ";
1008 }
1009 strm << std::dec << std::noshowbase;
1010 strm << "Shader Instruction Index = " << debug_record[kInstCommonOutInstructionIdx] << ". ";
1011 msg = strm.str();
1012}
1013
1014// Read the contents of the SPIR-V OpSource instruction and any following continuation instructions.
1015// Split the single string into a vector of strings, one for each line, for easier processing.
sfricke-samsungef15e482022-01-26 11:32:49 -08001016void ReadOpSource(const SHADER_MODULE_STATE &module_state, const uint32_t reported_file_id,
1017 std::vector<std::string> &opsource_lines) {
1018 for (auto insn : module_state) {
Tony-LunarG1dce2392019-10-23 16:49:29 -06001019 if ((insn.opcode() == spv::OpSource) && (insn.len() >= 5) && (insn.word(3) == reported_file_id)) {
1020 std::istringstream in_stream;
1021 std::string cur_line;
1022 in_stream.str((char *)&insn.word(4));
1023 while (std::getline(in_stream, cur_line)) {
1024 opsource_lines.push_back(cur_line);
1025 }
1026 while ((++insn).opcode() == spv::OpSourceContinued) {
1027 in_stream.str((char *)&insn.word(1));
1028 while (std::getline(in_stream, cur_line)) {
1029 opsource_lines.push_back(cur_line);
1030 }
1031 }
1032 break;
1033 }
1034 }
1035}
1036
1037// The task here is to search the OpSource content to find the #line directive with the
1038// line number that is closest to, but still prior to the reported error line number and
1039// still within the reported filename.
1040// From this known position in the OpSource content we can add the difference between
1041// the #line line number and the reported error line number to determine the location
1042// in the OpSource content of the reported error line.
1043//
1044// Considerations:
1045// - Look only at #line directives that specify the reported_filename since
1046// the reported error line number refers to its location in the reported filename.
1047// - If a #line directive does not have a filename, the file is the reported filename, or
1048// the filename found in a prior #line directive. (This is C-preprocessor behavior)
1049// - It is possible (e.g., inlining) for blocks of code to get shuffled out of their
1050// original order and the #line directives are used to keep the numbering correct. This
1051// is why we need to examine the entire contents of the source, instead of leaving early
1052// when finding a #line line number larger than the reported error line number.
1053//
1054
1055// GCC 4.8 has a problem with std::regex that is fixed in GCC 4.9. Provide fallback code for 4.8
1056#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
1057
1058#if defined(__GNUC__) && GCC_VERSION < 40900
1059bool GetLineAndFilename(const std::string string, uint32_t *linenumber, std::string &filename) {
1060 // # line <linenumber> "<filename>" or
1061 // #line <linenumber> "<filename>"
1062 std::vector<std::string> tokens;
1063 std::stringstream stream(string);
1064 std::string temp;
1065 uint32_t line_index = 0;
1066
1067 while (stream >> temp) tokens.push_back(temp);
1068 auto size = tokens.size();
1069 if (size > 1) {
1070 if (tokens[0] == "#" && tokens[1] == "line") {
1071 line_index = 2;
1072 } else if (tokens[0] == "#line") {
1073 line_index = 1;
1074 }
1075 }
1076 if (0 == line_index) return false;
Mark Young0ec6b062020-11-19 15:32:17 -07001077 *linenumber = static_cast<uint32_t>(std::stoul(tokens[line_index]));
Tony-LunarG1dce2392019-10-23 16:49:29 -06001078 uint32_t filename_index = line_index + 1;
1079 // Remove enclosing double quotes around filename
1080 if (size > filename_index) filename = tokens[filename_index].substr(1, tokens[filename_index].size() - 2);
1081 return true;
1082}
1083#else
1084bool GetLineAndFilename(const std::string string, uint32_t *linenumber, std::string &filename) {
1085 static const std::regex line_regex( // matches #line directives
1086 "^" // beginning of line
1087 "\\s*" // optional whitespace
1088 "#" // required text
1089 "\\s*" // optional whitespace
1090 "line" // required text
1091 "\\s+" // required whitespace
1092 "([0-9]+)" // required first capture - line number
1093 "(\\s+)?" // optional second capture - whitespace
1094 "(\".+\")?" // optional third capture - quoted filename with at least one char inside
1095 ".*"); // rest of line (needed when using std::regex_match since the entire line is tested)
1096
1097 std::smatch captures;
1098
1099 bool found_line = std::regex_match(string, captures, line_regex);
1100 if (!found_line) return false;
1101
1102 // filename is optional and considered found only if the whitespace and the filename are captured
1103 if (captures[2].matched && captures[3].matched) {
1104 // Remove enclosing double quotes. The regex guarantees the quotes and at least one char.
1105 filename = captures[3].str().substr(1, captures[3].str().size() - 2);
1106 }
Artem Bolgar82d08362021-06-03 13:11:13 -07001107 *linenumber = (uint32_t)std::stoul(captures[1]);
Tony-LunarG1dce2392019-10-23 16:49:29 -06001108 return true;
1109}
1110#endif // GCC_VERSION
1111
1112// Extract the filename, line number, and column number from the correct OpLine and build a message string from it.
1113// 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 -08001114void UtilGenerateSourceMessages(const std::vector<uint32_t> &pgm, const uint32_t *debug_record, bool from_printf,
Tony-LunarGb5fae462020-03-05 12:43:25 -07001115 std::string &filename_msg, std::string &source_msg) {
Tony-LunarG1dce2392019-10-23 16:49:29 -06001116 using namespace spvtools;
1117 std::ostringstream filename_stream;
1118 std::ostringstream source_stream;
Nathaniel Cesario77cd59b2021-10-11 23:52:24 -06001119 SHADER_MODULE_STATE shader(pgm);
Tony-LunarG1dce2392019-10-23 16:49:29 -06001120 // Find the OpLine just before the failing instruction indicated by the debug info.
1121 // SPIR-V can only be iterated in the forward direction due to its opcode/length encoding.
1122 uint32_t instruction_index = 0;
1123 uint32_t reported_file_id = 0;
1124 uint32_t reported_line_number = 0;
1125 uint32_t reported_column_number = 0;
1126 if (shader.words.size() > 0) {
John Zulauf79f06582021-02-27 18:38:39 -07001127 for (const auto &insn : shader) {
Tony-LunarG1dce2392019-10-23 16:49:29 -06001128 if (insn.opcode() == spv::OpLine) {
1129 reported_file_id = insn.word(1);
1130 reported_line_number = insn.word(2);
1131 reported_column_number = insn.word(3);
1132 }
1133 if (instruction_index == debug_record[kInstCommonOutInstructionIdx]) {
1134 break;
1135 }
1136 instruction_index++;
1137 }
1138 }
1139 // Create message with file information obtained from the OpString pointed to by the discovered OpLine.
1140 std::string reported_filename;
1141 if (reported_file_id == 0) {
1142 filename_stream
1143 << "Unable to find SPIR-V OpLine for source information. Build shader with debug info to get source information.";
1144 } else {
1145 bool found_opstring = false;
1146 std::string prefix;
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07001147 if (from_printf) {
Tony-LunarG1dce2392019-10-23 16:49:29 -06001148 prefix = "Debug shader printf message generated ";
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07001149 } else {
Tony-LunarG1dce2392019-10-23 16:49:29 -06001150 prefix = "Shader validation error occurred ";
Nathaniel Cesarioce9b4812020-12-17 08:55:28 -07001151 }
John Zulauf79f06582021-02-27 18:38:39 -07001152 for (const auto &insn : shader) {
Tony-LunarG1dce2392019-10-23 16:49:29 -06001153 if ((insn.opcode() == spv::OpString) && (insn.len() >= 3) && (insn.word(1) == reported_file_id)) {
1154 found_opstring = true;
1155 reported_filename = (char *)&insn.word(2);
1156 if (reported_filename.empty()) {
1157 filename_stream << prefix << "at line " << reported_line_number;
1158 } else {
1159 filename_stream << prefix << "in file " << reported_filename << " at line " << reported_line_number;
1160 }
1161 if (reported_column_number > 0) {
1162 filename_stream << ", column " << reported_column_number;
1163 }
1164 filename_stream << ".";
1165 break;
1166 }
1167 }
1168 if (!found_opstring) {
Tony-LunarG6d195e12020-10-27 16:54:14 -06001169 filename_stream << "Unable to find SPIR-V OpString for file id " << reported_file_id << " from OpLine instruction."
1170 << std::endl;
1171 filename_stream << "File ID = " << reported_file_id << ", Line Number = " << reported_line_number
1172 << ", Column = " << reported_column_number << std::endl;
Tony-LunarG1dce2392019-10-23 16:49:29 -06001173 }
1174 }
1175 filename_msg = filename_stream.str();
1176
1177 // Create message to display source code line containing error.
1178 if ((reported_file_id != 0)) {
1179 // Read the source code and split it up into separate lines.
1180 std::vector<std::string> opsource_lines;
1181 ReadOpSource(shader, reported_file_id, opsource_lines);
1182 // Find the line in the OpSource content that corresponds to the reported error file and line.
1183 if (!opsource_lines.empty()) {
1184 uint32_t saved_line_number = 0;
1185 std::string current_filename = reported_filename; // current "preprocessor" filename state.
1186 std::vector<std::string>::size_type saved_opsource_offset = 0;
1187 bool found_best_line = false;
1188 for (auto it = opsource_lines.begin(); it != opsource_lines.end(); ++it) {
1189 uint32_t parsed_line_number;
1190 std::string parsed_filename;
1191 bool found_line = GetLineAndFilename(*it, &parsed_line_number, parsed_filename);
1192 if (!found_line) continue;
1193
1194 bool found_filename = parsed_filename.size() > 0;
1195 if (found_filename) {
1196 current_filename = parsed_filename;
1197 }
1198 if ((!found_filename) || (current_filename == reported_filename)) {
1199 // Update the candidate best line directive, if the current one is prior and closer to the reported line
1200 if (reported_line_number >= parsed_line_number) {
1201 if (!found_best_line ||
1202 (reported_line_number - parsed_line_number <= reported_line_number - saved_line_number)) {
1203 saved_line_number = parsed_line_number;
1204 saved_opsource_offset = std::distance(opsource_lines.begin(), it);
1205 found_best_line = true;
1206 }
1207 }
1208 }
1209 }
1210 if (found_best_line) {
1211 assert(reported_line_number >= saved_line_number);
1212 std::vector<std::string>::size_type opsource_index =
1213 (reported_line_number - saved_line_number) + 1 + saved_opsource_offset;
1214 if (opsource_index < opsource_lines.size()) {
1215 source_stream << "\n" << reported_line_number << ": " << opsource_lines[opsource_index].c_str();
1216 } else {
1217 source_stream << "Internal error: calculated source line of " << opsource_index << " for source size of "
1218 << opsource_lines.size() << " lines.";
1219 }
1220 } else {
1221 source_stream << "Unable to find suitable #line directive in SPIR-V OpSource.";
1222 }
1223 } else {
1224 source_stream << "Unable to find SPIR-V OpSource.";
1225 }
1226 }
1227 source_msg = source_stream.str();
1228}