blob: 398d18954d2ff42f51ef47d52083fa6ece307d94 [file] [log] [blame]
Tony-LunarGb5fae462020-03-05 12:43:25 -07001/* Copyright (c) 2020 The Khronos Group Inc.
2 * Copyright (c) 2020 Valve Corporation
3 * Copyright (c) 2020 LunarG, Inc.
Tony-LunarG04717522019-10-17 10:41:17 -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
Tony-LunarGb5fae462020-03-05 12:43:25 -070020#include "debug_printf.h"
Tony-LunarG04717522019-10-17 10:41:17 -060021#include "spirv-tools/optimizer.hpp"
22#include "spirv-tools/instrument.hpp"
23#include <iostream>
Tony-LunarG04717522019-10-17 10:41:17 -060024#include "layer_chassis_dispatch.h"
25
Tony-LunarG04717522019-10-17 10:41:17 -060026static const VkShaderStageFlags kShaderStageAllRayTracing =
27 VK_SHADER_STAGE_ANY_HIT_BIT_NV | VK_SHADER_STAGE_CALLABLE_BIT_NV | VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV |
28 VK_SHADER_STAGE_INTERSECTION_BIT_NV | VK_SHADER_STAGE_MISS_BIT_NV | VK_SHADER_STAGE_RAYGEN_BIT_NV;
29
Tony-LunarG5af54eb2020-03-27 15:32:51 -060030// Convenience function for reporting problems with setting up Debug Printf.
Tony-LunarG1dce2392019-10-23 16:49:29 -060031template <typename T>
Tony-LunarGb5fae462020-03-05 12:43:25 -070032void DebugPrintf::ReportSetupProblem(T object, const char *const specific_message) const {
Tony-LunarG5af54eb2020-03-27 15:32:51 -060033 LogError(object, "UNASSIGNED-DEBUG-PRINTF ", "Detail: (%s)", specific_message);
Tony-LunarG04717522019-10-17 10:41:17 -060034}
35
36// Turn on necessary device features.
Tony-LunarGb5fae462020-03-05 12:43:25 -070037void DebugPrintf::PreCallRecordCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *create_info,
38 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice,
39 safe_VkDeviceCreateInfo *modified_create_info) {
Tony-LunarG04717522019-10-17 10:41:17 -060040 DispatchGetPhysicalDeviceFeatures(gpu, &supported_features);
Tony-LunarG1dce2392019-10-23 16:49:29 -060041 VkPhysicalDeviceFeatures features = {};
42 features.vertexPipelineStoresAndAtomics = true;
43 features.fragmentStoresAndAtomics = true;
Tony-LunarGb5fae462020-03-05 12:43:25 -070044 UtilPreCallRecordCreateDevice(gpu, modified_create_info, supported_features, features);
Tony-LunarG04717522019-10-17 10:41:17 -060045}
Tony-LunarG1dce2392019-10-23 16:49:29 -060046
Tony-LunarG04717522019-10-17 10:41:17 -060047// Perform initializations that can be done at Create Device time.
Tony-LunarGb5fae462020-03-05 12:43:25 -070048void DebugPrintf::PostCallRecordCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
49 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, VkResult result) {
Tony-LunarG04717522019-10-17 10:41:17 -060050 ValidationStateTracker::PostCallRecordCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice, result);
51
52 ValidationObject *device_object = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
53 ValidationObject *validation_data = GetValidationObject(device_object->object_dispatch, this->container_type);
Tony-LunarGb5fae462020-03-05 12:43:25 -070054 DebugPrintf *device_debug_printf = static_cast<DebugPrintf *>(validation_data);
55 device_debug_printf->physicalDevice = physicalDevice;
56 device_debug_printf->device = *pDevice;
Tony-LunarG43416b42019-10-31 16:47:24 -060057
58 const char *size_string = getLayerOption("khronos_validation.printf_buffer_size");
Tony-LunarGb5fae462020-03-05 12:43:25 -070059 device_debug_printf->output_buffer_size = *size_string ? atoi(size_string) : 1024;
Tony-LunarG43416b42019-10-31 16:47:24 -060060 const char *verbose_string = getLayerOption("khronos_validation.printf_verbose");
Tony-LunarGb5fae462020-03-05 12:43:25 -070061 device_debug_printf->verbose = *verbose_string ? !strcmp(verbose_string, "true") : false;
Tony-LunarG43416b42019-10-31 16:47:24 -060062 const char *stdout_string = getLayerOption("khronos_validation.printf_to_stdout");
Tony-LunarGb5fae462020-03-05 12:43:25 -070063 device_debug_printf->use_stdout = *stdout_string ? !strcmp(stdout_string, "true") : false;
64 if (getenv("DEBUG_PRINTF_TO_STDOUT")) device_debug_printf->use_stdout = true;
Tony-LunarG04717522019-10-17 10:41:17 -060065
Tony-LunarGb5fae462020-03-05 12:43:25 -070066 if (device_debug_printf->phys_dev_props.apiVersion < VK_API_VERSION_1_1) {
Tony-LunarGbbbed672020-03-04 10:51:11 -070067 ReportSetupProblem(device, "Debug Printf requires Vulkan 1.1 or later. Debug Printf disabled.");
Tony-LunarGb5fae462020-03-05 12:43:25 -070068 device_debug_printf->aborted = true;
Tony-LunarG04717522019-10-17 10:41:17 -060069 return;
70 }
71
72 if (!supported_features.fragmentStoresAndAtomics || !supported_features.vertexPipelineStoresAndAtomics) {
Tony-LunarG1dce2392019-10-23 16:49:29 -060073 ReportSetupProblem(device,
Tony-LunarGbbbed672020-03-04 10:51:11 -070074 "Debug Printf requires fragmentStoresAndAtomics and vertexPipelineStoresAndAtomics. "
75 "Debug Printf disabled.");
Tony-LunarGb5fae462020-03-05 12:43:25 -070076 device_debug_printf->aborted = true;
Tony-LunarG04717522019-10-17 10:41:17 -060077 return;
78 }
Tony-LunarG9586e732020-03-04 10:50:30 -070079
Mark Lobodzinski90eea5b2020-05-15 12:54:00 -060080 if (enabled[gpu_validation]) {
Tony-LunarG9586e732020-03-04 10:50:30 -070081 ReportSetupProblem(device,
82 "Debug Printf cannot be enabled when gpu assisted validation is enabled. "
83 "Debug Printf disabled.");
Tony-LunarGb5fae462020-03-05 12:43:25 -070084 device_debug_printf->aborted = true;
Tony-LunarG9586e732020-03-04 10:50:30 -070085 return;
86 }
87
Tony-LunarG1dce2392019-10-23 16:49:29 -060088 std::vector<VkDescriptorSetLayoutBinding> bindings;
89 VkDescriptorSetLayoutBinding binding = {3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
Tony-LunarGc7ed2082020-06-11 14:00:04 -060090 VK_SHADER_STAGE_ALL_GRAPHICS | VK_SHADER_STAGE_MESH_BIT_NV |
91 VK_SHADER_STAGE_TASK_BIT_NV | VK_SHADER_STAGE_COMPUTE_BIT |
92 kShaderStageAllRayTracing,
Tony-LunarG1dce2392019-10-23 16:49:29 -060093 NULL};
94 bindings.push_back(binding);
Tony-LunarGb5fae462020-03-05 12:43:25 -070095 UtilPostCallRecordCreateDevice(pCreateInfo, bindings, device_debug_printf, device_debug_printf->phys_dev_props);
Tony-LunarG04717522019-10-17 10:41:17 -060096}
97
Tony-LunarGb5fae462020-03-05 12:43:25 -070098void DebugPrintf::PreCallRecordDestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
99 UtilPreCallRecordDestroyDevice(this);
Tony-LunarG04717522019-10-17 10:41:17 -0600100}
101
102// Modify the pipeline layout to include our debug descriptor set and any needed padding with the dummy descriptor set.
Tony-LunarGb5fae462020-03-05 12:43:25 -0700103void DebugPrintf::PreCallRecordCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
104 const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout,
105 void *cpl_state_data) {
Tony-LunarG04717522019-10-17 10:41:17 -0600106 if (aborted) {
107 return;
108 }
109
110 create_pipeline_layout_api_state *cpl_state = reinterpret_cast<create_pipeline_layout_api_state *>(cpl_state_data);
111
112 if (cpl_state->modified_create_info.setLayoutCount >= adjusted_max_desc_sets) {
113 std::ostringstream strm;
114 strm << "Pipeline Layout conflict with validation's descriptor set at slot " << desc_set_bind_index << ". "
Tony-LunarGbbbed672020-03-04 10:51:11 -0700115 << "Application has too many descriptor sets in the pipeline layout to continue with debug printf. "
Tony-LunarG04717522019-10-17 10:41:17 -0600116 << "Not modifying the pipeline layout. "
117 << "Instrumented shaders are replaced with non-instrumented shaders.";
Tony-LunarG1dce2392019-10-23 16:49:29 -0600118 ReportSetupProblem(device, strm.str().c_str());
Tony-LunarG04717522019-10-17 10:41:17 -0600119 } else {
Tony-LunarGb5fae462020-03-05 12:43:25 -0700120 UtilPreCallRecordCreatePipelineLayout(cpl_state, this, pCreateInfo);
Tony-LunarG04717522019-10-17 10:41:17 -0600121 }
122}
123
Tony-LunarGb5fae462020-03-05 12:43:25 -0700124void DebugPrintf::PostCallRecordCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
125 const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout,
126 VkResult result) {
Tony-LunarG04717522019-10-17 10:41:17 -0600127 ValidationStateTracker::PostCallRecordCreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout, result);
128 if (result != VK_SUCCESS) {
Tony-LunarG1dce2392019-10-23 16:49:29 -0600129 ReportSetupProblem(device, "Unable to create pipeline layout. Device could become unstable.");
Tony-LunarG04717522019-10-17 10:41:17 -0600130 aborted = true;
131 }
132}
133
134// Free the device memory and descriptor set associated with a command buffer.
Tony-LunarGb5fae462020-03-05 12:43:25 -0700135void DebugPrintf::ResetCommandBuffer(VkCommandBuffer commandBuffer) {
Tony-LunarG04717522019-10-17 10:41:17 -0600136 if (aborted) {
137 return;
138 }
Tony-LunarGb5fae462020-03-05 12:43:25 -0700139 auto debug_printf_buffer_list = GetBufferInfo(commandBuffer);
140 for (auto buffer_info : debug_printf_buffer_list) {
Tony-LunarG04717522019-10-17 10:41:17 -0600141 vmaDestroyBuffer(vmaAllocator, buffer_info.output_mem_block.buffer, buffer_info.output_mem_block.allocation);
142 if (buffer_info.desc_set != VK_NULL_HANDLE) {
143 desc_set_manager->PutBackDescriptorSet(buffer_info.desc_pool, buffer_info.desc_set);
144 }
145 }
146 command_buffer_map.erase(commandBuffer);
147}
148
149// Just gives a warning about a possible deadlock.
Tony-LunarGb5fae462020-03-05 12:43:25 -0700150bool DebugPrintf::PreCallValidateCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
151 VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
152 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
153 uint32_t bufferMemoryBarrierCount,
154 const VkBufferMemoryBarrier *pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount,
155 const VkImageMemoryBarrier *pImageMemoryBarriers) const {
Tony-LunarG04717522019-10-17 10:41:17 -0600156 if (srcStageMask & VK_PIPELINE_STAGE_HOST_BIT) {
Tony-LunarG1dce2392019-10-23 16:49:29 -0600157 ReportSetupProblem(commandBuffer,
158 "CmdWaitEvents recorded with VK_PIPELINE_STAGE_HOST_BIT set. "
Tony-LunarGbbbed672020-03-04 10:51:11 -0700159 "Debug Printf waits on queue completion. "
Tony-LunarG1dce2392019-10-23 16:49:29 -0600160 "This wait could block the host's signaling of this event, resulting in deadlock.");
Tony-LunarG04717522019-10-17 10:41:17 -0600161 }
162 return false;
163}
164
Tony-LunarGb5fae462020-03-05 12:43:25 -0700165void DebugPrintf::PreCallRecordCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
166 const VkGraphicsPipelineCreateInfo *pCreateInfos,
167 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
168 void *cgpl_state_data) {
Tony-LunarG04717522019-10-17 10:41:17 -0600169 std::vector<safe_VkGraphicsPipelineCreateInfo> new_pipeline_create_infos;
170 create_graphics_pipeline_api_state *cgpl_state = reinterpret_cast<create_graphics_pipeline_api_state *>(cgpl_state_data);
Tony-LunarGb5fae462020-03-05 12:43:25 -0700171 UtilPreCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, cgpl_state->pipe_state,
172 &new_pipeline_create_infos, VK_PIPELINE_BIND_POINT_GRAPHICS, this);
Tony-LunarG04717522019-10-17 10:41:17 -0600173 cgpl_state->printf_create_infos = new_pipeline_create_infos;
174 cgpl_state->pCreateInfos = reinterpret_cast<VkGraphicsPipelineCreateInfo *>(cgpl_state->printf_create_infos.data());
175}
176
Tony-LunarGb5fae462020-03-05 12:43:25 -0700177void DebugPrintf::PreCallRecordCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
178 const VkComputePipelineCreateInfo *pCreateInfos,
179 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
180 void *ccpl_state_data) {
Tony-LunarG04717522019-10-17 10:41:17 -0600181 std::vector<safe_VkComputePipelineCreateInfo> new_pipeline_create_infos;
182 auto *ccpl_state = reinterpret_cast<create_compute_pipeline_api_state *>(ccpl_state_data);
Tony-LunarGb5fae462020-03-05 12:43:25 -0700183 UtilPreCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, ccpl_state->pipe_state,
184 &new_pipeline_create_infos, VK_PIPELINE_BIND_POINT_COMPUTE, this);
Tony-LunarG04717522019-10-17 10:41:17 -0600185 ccpl_state->printf_create_infos = new_pipeline_create_infos;
186 ccpl_state->pCreateInfos = reinterpret_cast<VkComputePipelineCreateInfo *>(ccpl_state->gpu_create_infos.data());
187}
188
Tony-LunarGb5fae462020-03-05 12:43:25 -0700189void DebugPrintf::PreCallRecordCreateRayTracingPipelinesNV(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
190 const VkRayTracingPipelineCreateInfoNV *pCreateInfos,
191 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
192 void *crtpl_state_data) {
Tony-LunarG04717522019-10-17 10:41:17 -0600193 std::vector<safe_VkRayTracingPipelineCreateInfoCommon> new_pipeline_create_infos;
194 auto *crtpl_state = reinterpret_cast<create_ray_tracing_pipeline_api_state *>(crtpl_state_data);
Tony-LunarGb5fae462020-03-05 12:43:25 -0700195 UtilPreCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, crtpl_state->pipe_state,
196 &new_pipeline_create_infos, VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, this);
Tony-LunarG04717522019-10-17 10:41:17 -0600197 crtpl_state->printf_create_infos = new_pipeline_create_infos;
198 crtpl_state->pCreateInfos = reinterpret_cast<VkRayTracingPipelineCreateInfoNV *>(crtpl_state->gpu_create_infos.data());
199}
200
Tony-LunarGb5fae462020-03-05 12:43:25 -0700201void DebugPrintf::PreCallRecordCreateRayTracingPipelinesKHR(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
202 const VkRayTracingPipelineCreateInfoKHR *pCreateInfos,
203 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
204 void *crtpl_state_data) {
Tony-LunarG04717522019-10-17 10:41:17 -0600205 std::vector<safe_VkRayTracingPipelineCreateInfoCommon> new_pipeline_create_infos;
206 auto *crtpl_state = reinterpret_cast<create_ray_tracing_pipeline_khr_api_state *>(crtpl_state_data);
Tony-LunarGb5fae462020-03-05 12:43:25 -0700207 UtilPreCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, crtpl_state->pipe_state,
208 &new_pipeline_create_infos, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, this);
Tony-LunarG04717522019-10-17 10:41:17 -0600209 crtpl_state->gpu_create_infos = new_pipeline_create_infos;
210 crtpl_state->pCreateInfos = reinterpret_cast<VkRayTracingPipelineCreateInfoKHR *>(crtpl_state->gpu_create_infos.data());
211}
Tony-LunarG04717522019-10-17 10:41:17 -0600212
Tony-LunarGb5fae462020-03-05 12:43:25 -0700213void DebugPrintf::PostCallRecordCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
214 const VkGraphicsPipelineCreateInfo *pCreateInfos,
215 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
216 VkResult result, void *cgpl_state_data) {
Tony-LunarG04717522019-10-17 10:41:17 -0600217 ValidationStateTracker::PostCallRecordCreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pAllocator,
218 pPipelines, result, cgpl_state_data);
Tony-LunarGc876c6e2020-09-09 15:19:43 -0600219 create_graphics_pipeline_api_state *cgpl_state = reinterpret_cast<create_graphics_pipeline_api_state *>(cgpl_state_data);
220 UtilCopyCreatePipelineFeedbackData(count, pCreateInfos, cgpl_state->printf_create_infos.data());
Tony-LunarGb5fae462020-03-05 12:43:25 -0700221 UtilPostCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, VK_PIPELINE_BIND_POINT_GRAPHICS, this);
Tony-LunarG04717522019-10-17 10:41:17 -0600222}
223
Tony-LunarGb5fae462020-03-05 12:43:25 -0700224void DebugPrintf::PostCallRecordCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
225 const VkComputePipelineCreateInfo *pCreateInfos,
226 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
227 VkResult result, void *ccpl_state_data) {
Tony-LunarG04717522019-10-17 10:41:17 -0600228 ValidationStateTracker::PostCallRecordCreateComputePipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines,
229 result, ccpl_state_data);
Tony-LunarGc876c6e2020-09-09 15:19:43 -0600230 create_compute_pipeline_api_state *ccpl_state = reinterpret_cast<create_compute_pipeline_api_state *>(ccpl_state_data);
231 UtilCopyCreatePipelineFeedbackData(count, pCreateInfos, ccpl_state->printf_create_infos.data());
Tony-LunarGb5fae462020-03-05 12:43:25 -0700232 UtilPostCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, VK_PIPELINE_BIND_POINT_COMPUTE, this);
Tony-LunarG04717522019-10-17 10:41:17 -0600233}
234
Tony-LunarGb5fae462020-03-05 12:43:25 -0700235void DebugPrintf::PostCallRecordCreateRayTracingPipelinesNV(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
236 const VkRayTracingPipelineCreateInfoNV *pCreateInfos,
237 const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
238 VkResult result, void *crtpl_state_data) {
Tony-LunarGc876c6e2020-09-09 15:19:43 -0600239 auto *crtpl_state = reinterpret_cast<create_ray_tracing_pipeline_khr_api_state *>(crtpl_state_data);
Tony-LunarG04717522019-10-17 10:41:17 -0600240 ValidationStateTracker::PostCallRecordCreateRayTracingPipelinesNV(device, pipelineCache, count, pCreateInfos, pAllocator,
241 pPipelines, result, crtpl_state_data);
Tony-LunarGc876c6e2020-09-09 15:19:43 -0600242 UtilCopyCreatePipelineFeedbackData(count, pCreateInfos, crtpl_state->gpu_create_infos.data());
Tony-LunarGb5fae462020-03-05 12:43:25 -0700243 UtilPostCallRecordPipelineCreations(count, pCreateInfos, pAllocator, pPipelines, VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, this);
Tony-LunarG04717522019-10-17 10:41:17 -0600244}
245
246// Remove all the shader trackers associated with this destroyed pipeline.
Tony-LunarGb5fae462020-03-05 12:43:25 -0700247void DebugPrintf::PreCallRecordDestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) {
Tony-LunarG04717522019-10-17 10:41:17 -0600248 for (auto it = shader_map.begin(); it != shader_map.end();) {
249 if (it->second.pipeline == pipeline) {
250 it = shader_map.erase(it);
251 } else {
252 ++it;
253 }
254 }
255 ValidationStateTracker::PreCallRecordDestroyPipeline(device, pipeline, pAllocator);
256}
257// Call the SPIR-V Optimizer to run the instrumentation pass on the shader.
Tony-LunarGb5fae462020-03-05 12:43:25 -0700258bool DebugPrintf::InstrumentShader(const VkShaderModuleCreateInfo *pCreateInfo, std::vector<unsigned int> &new_pgm,
259 uint32_t *unique_shader_id) {
Tony-LunarG04717522019-10-17 10:41:17 -0600260 if (aborted) return false;
261 if (pCreateInfo->pCode[0] != spv::MagicNumber) return false;
262
263 // Load original shader SPIR-V
264 uint32_t num_words = static_cast<uint32_t>(pCreateInfo->codeSize / 4);
265 new_pgm.clear();
266 new_pgm.reserve(num_words);
267 new_pgm.insert(new_pgm.end(), &pCreateInfo->pCode[0], &pCreateInfo->pCode[num_words]);
268
269 // Call the optimizer to instrument the shader.
270 // Use the unique_shader_module_id as a shader ID so we can look up its handle later in the shader_map.
271 // If descriptor indexing is enabled, enable length checks and updated descriptor checks
272 using namespace spvtools;
Tony-LunarG8a51b7d2020-07-01 15:57:23 -0600273 spv_target_env target_env = PickSpirvEnv(api_version, (device_extensions.vk_khr_spirv_1_4 != kNotEnabled));
Tony-LunarG9fe69a42020-07-23 15:09:37 -0600274 spvtools::ValidatorOptions options;
275 AdjustValidatorOptions(device_extensions, enabled_features, options);
Tony-LunarG04717522019-10-17 10:41:17 -0600276 Optimizer optimizer(target_env);
Tony-LunarG79641702020-07-13 15:43:05 -0600277 const spvtools::MessageConsumer DebugPrintfConsoleMessageConsumer =
278 [this](spv_message_level_t level, const char *, const spv_position_t &position, const char *message) -> void {
279 switch (level) {
280 case SPV_MSG_FATAL:
281 case SPV_MSG_INTERNAL_ERROR:
282 case SPV_MSG_ERROR:
283 this->LogError(this->device, "UNASSIGNED-Debug-Printf", "Error during shader instrumentation: line %zu: %s",
284 position.index, message);
285 break;
286 default:
287 break;
288 }
289 };
290 optimizer.SetMessageConsumer(DebugPrintfConsoleMessageConsumer);
Tony-LunarG04717522019-10-17 10:41:17 -0600291 optimizer.RegisterPass(CreateInstDebugPrintfPass(desc_set_bind_index, unique_shader_module_id));
Tony-LunarG9fe69a42020-07-23 15:09:37 -0600292 bool pass = optimizer.Run(new_pgm.data(), new_pgm.size(), &new_pgm, options, false);
Tony-LunarG04717522019-10-17 10:41:17 -0600293 if (!pass) {
Tony-LunarG1dce2392019-10-23 16:49:29 -0600294 ReportSetupProblem(device, "Failure to instrument shader. Proceeding with non-instrumented shader.");
Tony-LunarG04717522019-10-17 10:41:17 -0600295 }
296 *unique_shader_id = unique_shader_module_id++;
297 return pass;
298}
299// Create the instrumented shader data to provide to the driver.
Tony-LunarGb5fae462020-03-05 12:43:25 -0700300void DebugPrintf::PreCallRecordCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
301 const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule,
302 void *csm_state_data) {
Tony-LunarG04717522019-10-17 10:41:17 -0600303 create_shader_module_api_state *csm_state = reinterpret_cast<create_shader_module_api_state *>(csm_state_data);
304 bool pass = InstrumentShader(pCreateInfo, csm_state->instrumented_pgm, &csm_state->unique_shader_id);
305 if (pass) {
306 csm_state->instrumented_create_info.pCode = csm_state->instrumented_pgm.data();
307 csm_state->instrumented_create_info.codeSize = csm_state->instrumented_pgm.size() * sizeof(unsigned int);
308 }
309}
Tony-LunarG04717522019-10-17 10:41:17 -0600310
311vartype vartype_lookup(char intype) {
312 switch (intype) {
313 case 'd':
314 case 'i':
315 return varsigned;
316 break;
317
318 case 'f':
319 case 'F':
320 case 'a':
321 case 'A':
322 case 'e':
323 case 'E':
324 case 'g':
325 case 'G':
326 return varfloat;
327 break;
328
329 case 'u':
330 case 'x':
331 case 'o':
332 default:
333 return varunsigned;
334 break;
335 }
336}
337
Tony-LunarGa19e31e2020-03-30 13:30:29 -0600338std::vector<DPFSubstring> DebugPrintf::ParseFormatString(const std::string format_string) {
339 const char types[] = {'d', 'i', 'o', 'u', 'x', 'X', 'a', 'A', 'e', 'E', 'f', 'F', 'g', 'G', 'v', '\0'};
Tony-LunarGb5fae462020-03-05 12:43:25 -0700340 std::vector<DPFSubstring> parsed_strings;
Tony-LunarG04717522019-10-17 10:41:17 -0600341 size_t pos = 0;
342 size_t begin = 0;
343 size_t percent = 0;
344
345 while (begin < format_string.length()) {
Tony-LunarGb5fae462020-03-05 12:43:25 -0700346 DPFSubstring substring;
Tony-LunarG04717522019-10-17 10:41:17 -0600347
348 // Find a percent sign
349 pos = percent = format_string.find_first_of('%', pos);
350 if (pos == std::string::npos) {
351 // End of the format string Push the rest of the characters
352 substring.string = format_string.substr(begin, format_string.length());
353 substring.needs_value = false;
354 parsed_strings.push_back(substring);
355 break;
356 }
357 pos++;
358 if (format_string[pos] == '%') {
359 pos++;
360 continue; // %% - skip it
361 }
362 // Find the type of the value
363 pos = format_string.find_first_of(types, pos);
364 if (pos == format_string.npos)
365 // This really shouldn't happen with a legal value string
366 pos = format_string.length();
367 else {
368 char tempstring[32];
369 int count = 0;
370 std::string specifier = {};
371
372 if (format_string[pos] == 'v') {
373 // Vector must be of size 2, 3, or 4
374 // and format %v<size><type>
375 specifier = format_string.substr(percent, pos - percent);
376 count = atoi(&format_string[pos + 1]);
377 pos += 2;
378
379 // skip v<count>, handle long
380 specifier.push_back(format_string[pos]);
381 if (format_string[pos + 1] == 'l') {
382 specifier.push_back('l');
383 pos++;
384 }
385
386 // Take the preceding characters, and the percent through the type
387 substring.string = format_string.substr(begin, percent - begin);
388 substring.string += specifier;
389 substring.needs_value = true;
390 substring.type = vartype_lookup(specifier.back());
391 parsed_strings.push_back(substring);
392
393 // Continue with a comma separated list
394 sprintf(tempstring, ", %s", specifier.c_str());
395 substring.string = tempstring;
396 for (int i = 0; i < (count - 1); i++) {
397 parsed_strings.push_back(substring);
398 }
399 } else {
400 // Single non-vector value
401 if (format_string[pos + 1] == 'l') pos++; // Save long size
402 substring.string = format_string.substr(begin, pos - begin + 1);
403 substring.needs_value = true;
404 substring.type = vartype_lookup(format_string[pos]);
405 parsed_strings.push_back(substring);
406 }
407 begin = pos + 1;
408 }
409 }
410 return parsed_strings;
411}
412
Tony-LunarGb5fae462020-03-05 12:43:25 -0700413std::string DebugPrintf::FindFormatString(std::vector<unsigned int> pgm, uint32_t string_id) {
Tony-LunarG04717522019-10-17 10:41:17 -0600414 std::string format_string;
415 SHADER_MODULE_STATE shader;
416 shader.words = pgm;
417 if (shader.words.size() > 0) {
418 for (auto insn : shader) {
419 if (insn.opcode() == spv::OpString) {
420 uint32_t offset = insn.offset();
421 if (pgm[offset + 1] == string_id) {
422 format_string = reinterpret_cast<char *>(&pgm[offset + 2]);
423 break;
424 }
425 }
426 }
427 }
428
429 return format_string;
430}
431
Corentin Wallez171ac5e2020-03-31 16:09:05 +0200432// GCC and clang don't like using variables as format strings in sprintf.
433// #pragma GCC is recognized by both compilers
434#if defined(__GNUC__) || defined(__clang__)
Tony-LunarG04717522019-10-17 10:41:17 -0600435#pragma GCC diagnostic push
436#pragma GCC diagnostic ignored "-Wformat-security"
437#endif
438
Tony-LunarGb5fae462020-03-05 12:43:25 -0700439void snprintf_with_malloc(std::stringstream &shader_message, DPFSubstring substring, size_t needed, void *values) {
Tony-LunarG04717522019-10-17 10:41:17 -0600440 char *buffer = static_cast<char *>(malloc((needed + 1) * sizeof(char))); // Add 1 for terminator
441 if (substring.longval) {
442 snprintf(buffer, needed, substring.string.c_str(), substring.longval);
443 } else if (!substring.needs_value) {
444 snprintf(buffer, needed, substring.string.c_str());
445 } else {
446 switch (substring.type) {
447 case varunsigned:
448 needed = snprintf(buffer, needed, substring.string.c_str(), *static_cast<uint32_t *>(values) - 1);
449 break;
450
451 case varsigned:
452 needed = snprintf(buffer, needed, substring.string.c_str(), *static_cast<int32_t *>(values) - 1);
453 break;
454
455 case varfloat:
456 needed = snprintf(buffer, needed, substring.string.c_str(), *static_cast<float *>(values) - 1);
457 break;
458 }
459 }
460 shader_message << buffer;
461 free(buffer);
462}
463
Tony-LunarGb5fae462020-03-05 12:43:25 -0700464void DebugPrintf::AnalyzeAndGenerateMessages(VkCommandBuffer command_buffer, VkQueue queue, VkPipelineBindPoint pipeline_bind_point,
465 uint32_t operation_index, uint32_t *const debug_output_buffer) {
Tony-LunarG04717522019-10-17 10:41:17 -0600466 // Word Content
467 // 0 Size of output record, including this word
468 // 1 Shader ID
469 // 2 Instruction Position
470 // 3 Stage Ordinal
471 // 4 Stage - specific Info Word 0
472 // 5 Stage - specific Info Word 1
473 // 6 Stage - specific Info Word 2
474 // 7 Printf Format String Id
475 // 8 Printf Values Word 0 (optional)
476 // 9 Printf Values Word 1 (optional)
Tony-LunarG12a7ec32019-11-01 13:00:05 -0600477 uint32_t expect = debug_output_buffer[0];
478 if (!expect) return;
Tony-LunarG04717522019-10-17 10:41:17 -0600479
Tony-LunarG12a7ec32019-11-01 13:00:05 -0600480 uint32_t index = 1;
Tony-LunarG04717522019-10-17 10:41:17 -0600481 while (debug_output_buffer[index]) {
Tony-LunarG04717522019-10-17 10:41:17 -0600482 std::stringstream shader_message;
Tony-LunarG04717522019-10-17 10:41:17 -0600483 VkShaderModule shader_module_handle = VK_NULL_HANDLE;
484 VkPipeline pipeline_handle = VK_NULL_HANDLE;
485 std::vector<unsigned int> pgm;
486
Tony-LunarGb5fae462020-03-05 12:43:25 -0700487 DPFOutputRecord *debug_record = reinterpret_cast<DPFOutputRecord *>(&debug_output_buffer[index]);
Tony-LunarG04717522019-10-17 10:41:17 -0600488 // Lookup the VkShaderModule handle and SPIR-V code used to create the shader, using the unique shader ID value returned
489 // by the instrumented shader.
490 auto it = shader_map.find(debug_record->shader_id);
491 if (it != shader_map.end()) {
492 shader_module_handle = it->second.shader_module;
493 pipeline_handle = it->second.pipeline;
494 pgm = it->second.pgm;
495 }
496 // Search through the shader source for the printf format string for this invocation
497 auto format_string = FindFormatString(pgm, debug_record->format_string_id);
498 // Break the format string into strings with 1 or 0 value
499 auto format_substrings = ParseFormatString(format_string);
500 void *values = static_cast<void *>(&debug_record->values);
501 const uint32_t static_size = 1024;
502 // Sprintf each format substring into a temporary string then add that to the message
503 for (auto &substring : format_substrings) {
504 char temp_string[static_size];
505 size_t needed = 0;
506 const size_t ul_pos = substring.string.find("%ul");
507 if (ul_pos != std::string::npos) {
508 // Unsigned 64 bit value
509 substring.longval = *static_cast<uint64_t *>(values);
510 values = static_cast<uint64_t *>(values) + 1;
511 substring.string.replace(ul_pos + 1, 2, PRIx64);
512 needed = snprintf(temp_string, static_size, substring.string.c_str(), substring.longval);
513 } else {
514 if (substring.needs_value) {
515 switch (substring.type) {
516 case varunsigned:
517 needed = snprintf(temp_string, static_size, substring.string.c_str(), *static_cast<uint32_t *>(values));
518 break;
519
520 case varsigned:
521 needed = snprintf(temp_string, static_size, substring.string.c_str(), *static_cast<int32_t *>(values));
522 break;
523
524 case varfloat:
525 needed = snprintf(temp_string, static_size, substring.string.c_str(), *static_cast<float *>(values));
526 break;
527 }
528 values = static_cast<uint32_t *>(values) + 1;
529 } else
530 needed = snprintf(temp_string, static_size, substring.string.c_str());
531 }
532
533 if (needed < static_size)
534 shader_message << temp_string;
535 else {
536 // Static buffer not big enough for message, use malloc to get enough
537 snprintf_with_malloc(shader_message, substring, needed, values);
538 }
539 }
Tony-LunarG43416b42019-10-31 16:47:24 -0600540
541 if (verbose) {
542 std::string stage_message;
543 std::string common_message;
544 std::string filename_message;
545 std::string source_message;
Tony-LunarGb5fae462020-03-05 12:43:25 -0700546 UtilGenerateStageMessage(&debug_output_buffer[index], stage_message);
547 UtilGenerateCommonMessage(report_data, command_buffer, &debug_output_buffer[index], shader_module_handle,
548 pipeline_handle, pipeline_bind_point, operation_index, common_message);
549 UtilGenerateSourceMessages(pgm, &debug_output_buffer[index], true, filename_message, source_message);
Tony-LunarG43416b42019-10-31 16:47:24 -0600550 if (use_stdout) {
Tony-LunarG5af54eb2020-03-27 15:32:51 -0600551 std::cout << "UNASSIGNED-DEBUG-PRINTF " << common_message.c_str() << " " << stage_message.c_str() << " "
Tony-LunarGb5fae462020-03-05 12:43:25 -0700552 << shader_message.str().c_str() << " " << filename_message.c_str() << " " << source_message.c_str();
Tony-LunarG43416b42019-10-31 16:47:24 -0600553 } else {
Tony-LunarG5af54eb2020-03-27 15:32:51 -0600554 LogInfo(queue, "UNASSIGNED-DEBUG-PRINTF", "%s %s %s %s%s", common_message.c_str(), stage_message.c_str(),
555 shader_message.str().c_str(), filename_message.c_str(), source_message.c_str());
Tony-LunarG43416b42019-10-31 16:47:24 -0600556 }
557 } else {
Tony-LunarG5af54eb2020-03-27 15:32:51 -0600558 if (use_stdout) {
Tony-LunarG43416b42019-10-31 16:47:24 -0600559 std::cout << shader_message.str();
Tony-LunarG5af54eb2020-03-27 15:32:51 -0600560 } else {
561 // Don't let LogInfo process any '%'s in the string
562 LogInfo(device, "UNASSIGNED-DEBUG-PRINTF", "%s", shader_message.str().c_str());
563 }
Tony-LunarG43416b42019-10-31 16:47:24 -0600564 }
Tony-LunarG04717522019-10-17 10:41:17 -0600565 index += debug_record->size;
566 }
Tony-LunarG12a7ec32019-11-01 13:00:05 -0600567 if ((index - 1) != expect) {
Tony-LunarG5af54eb2020-03-27 15:32:51 -0600568 LogWarning(device, "UNASSIGNED-DEBUG-PRINTF",
569 "WARNING - Debug Printf message was truncated, likely due to a buffer size that was too small for the message");
Tony-LunarG12a7ec32019-11-01 13:00:05 -0600570 }
Tony-LunarG04717522019-10-17 10:41:17 -0600571 memset(debug_output_buffer, 0, 4 * (debug_output_buffer[0] + 1));
572}
Tony-LunarG43416b42019-10-31 16:47:24 -0600573
Tony-LunarG04717522019-10-17 10:41:17 -0600574#if defined(__GNUC__)
575#pragma GCC diagnostic pop
576#endif
577
Tony-LunarG04717522019-10-17 10:41:17 -0600578// Issue a memory barrier to make GPU-written data available to host.
579// Wait for the queue to complete execution.
580// Check the debug buffers for all the command buffers that were submitted.
Tony-LunarGb5fae462020-03-05 12:43:25 -0700581void DebugPrintf::PostCallRecordQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence,
582 VkResult result) {
Tony-LunarG04717522019-10-17 10:41:17 -0600583 ValidationStateTracker::PostCallRecordQueueSubmit(queue, submitCount, pSubmits, fence, result);
584
Mark Lobodzinski09379db2020-05-07 08:22:01 -0600585 if (aborted || (result != VK_SUCCESS)) return;
Tony-LunarG04717522019-10-17 10:41:17 -0600586 bool buffers_present = false;
587 // Don't QueueWaitIdle if there's nothing to process
588 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
589 const VkSubmitInfo *submit = &pSubmits[submit_idx];
590 for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
591 auto cb_node = GetCBState(submit->pCommandBuffers[i]);
Tony-LunarG1dce2392019-10-23 16:49:29 -0600592 if (GetBufferInfo(cb_node->commandBuffer).size()) buffers_present = true;
Tony-LunarG04717522019-10-17 10:41:17 -0600593 for (auto secondaryCmdBuffer : cb_node->linkedCommandBuffers) {
Tony-LunarG1dce2392019-10-23 16:49:29 -0600594 if (GetBufferInfo(secondaryCmdBuffer->commandBuffer).size()) buffers_present = true;
Tony-LunarG04717522019-10-17 10:41:17 -0600595 }
596 }
597 }
598 if (!buffers_present) return;
599
Tony-LunarGb5fae462020-03-05 12:43:25 -0700600 UtilSubmitBarrier(queue, this);
Tony-LunarG04717522019-10-17 10:41:17 -0600601
602 DispatchQueueWaitIdle(queue);
603
604 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
605 const VkSubmitInfo *submit = &pSubmits[submit_idx];
606 for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
607 auto cb_node = GetCBState(submit->pCommandBuffers[i]);
Tony-LunarGb5fae462020-03-05 12:43:25 -0700608 UtilProcessInstrumentationBuffer(queue, cb_node, this);
Tony-LunarG04717522019-10-17 10:41:17 -0600609 for (auto secondaryCmdBuffer : cb_node->linkedCommandBuffers) {
Tony-LunarGb5fae462020-03-05 12:43:25 -0700610 UtilProcessInstrumentationBuffer(queue, secondaryCmdBuffer, this);
Tony-LunarG04717522019-10-17 10:41:17 -0600611 }
612 }
613 }
614}
615
Tony-LunarGb5fae462020-03-05 12:43:25 -0700616void DebugPrintf::PreCallRecordCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount,
617 uint32_t firstVertex, uint32_t firstInstance) {
618 AllocateDebugPrintfResources(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS);
Tony-LunarG04717522019-10-17 10:41:17 -0600619}
620
Tony-LunarGb5fae462020-03-05 12:43:25 -0700621void DebugPrintf::PreCallRecordCmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount,
622 uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) {
623 AllocateDebugPrintfResources(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS);
Tony-LunarG04717522019-10-17 10:41:17 -0600624}
625
Tony-LunarGb5fae462020-03-05 12:43:25 -0700626void DebugPrintf::PreCallRecordCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count,
627 uint32_t stride) {
628 AllocateDebugPrintfResources(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS);
Tony-LunarG04717522019-10-17 10:41:17 -0600629}
630
Tony-LunarGb5fae462020-03-05 12:43:25 -0700631void DebugPrintf::PreCallRecordCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
632 uint32_t count, uint32_t stride) {
633 AllocateDebugPrintfResources(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS);
Tony-LunarG04717522019-10-17 10:41:17 -0600634}
635
Tony-LunarGb5fae462020-03-05 12:43:25 -0700636void DebugPrintf::PreCallRecordCmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) {
637 AllocateDebugPrintfResources(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE);
Tony-LunarG04717522019-10-17 10:41:17 -0600638}
639
Tony-LunarGb5fae462020-03-05 12:43:25 -0700640void DebugPrintf::PreCallRecordCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) {
641 AllocateDebugPrintfResources(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE);
Tony-LunarG04717522019-10-17 10:41:17 -0600642}
643
Tony-LunarGd13f9b52020-09-08 15:45:45 -0600644void DebugPrintf::PreCallRecordCmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY,
645 uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY,
646 uint32_t groupCountZ) {
647 AllocateDebugPrintfResources(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE);
648}
649
Tony-LunarG52c8c602020-09-10 16:29:56 -0600650void DebugPrintf::PreCallRecordCmdDispatchBaseKHR(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY,
651 uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY,
652 uint32_t groupCountZ) {
653 AllocateDebugPrintfResources(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE);
654}
655
Tony-LunarG2fb8ff02020-06-11 12:45:07 -0600656void DebugPrintf::PreCallRecordCmdDrawIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
657 VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount,
658 uint32_t stride) {
659 ValidationStateTracker::PreCallRecordCmdDrawIndirectCountKHR(commandBuffer, buffer, offset, countBuffer, countBufferOffset,
660 maxDrawCount, stride);
661 AllocateDebugPrintfResources(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS);
662}
663
664void DebugPrintf::PreCallRecordCmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
665 VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount,
666 uint32_t stride) {
667 ValidationStateTracker::PreCallRecordCmdDrawIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset,
668 maxDrawCount, stride);
669 AllocateDebugPrintfResources(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS);
670}
671
672void DebugPrintf::PreCallRecordCmdDrawIndexedIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
673 VkBuffer countBuffer, VkDeviceSize countBufferOffset,
674 uint32_t maxDrawCount, uint32_t stride) {
675 ValidationStateTracker::PreCallRecordCmdDrawIndexedIndirectCountKHR(commandBuffer, buffer, offset, countBuffer,
676 countBufferOffset, maxDrawCount, stride);
677 AllocateDebugPrintfResources(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS);
678}
679
680void DebugPrintf::PreCallRecordCmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
681 VkBuffer countBuffer, VkDeviceSize countBufferOffset,
682 uint32_t maxDrawCount, uint32_t stride) {
683 ValidationStateTracker::PreCallRecordCmdDrawIndexedIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset,
684 maxDrawCount, stride);
685 AllocateDebugPrintfResources(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS);
686}
687
688void DebugPrintf::PreCallRecordCmdDrawMeshTasksNV(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask) {
689 ValidationStateTracker::PreCallRecordCmdDrawMeshTasksNV(commandBuffer, taskCount, firstTask);
690 AllocateDebugPrintfResources(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS);
691}
692
693void DebugPrintf::PreCallRecordCmdDrawMeshTasksIndirectNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
694 uint32_t drawCount, uint32_t stride) {
695 ValidationStateTracker::PreCallRecordCmdDrawMeshTasksIndirectNV(commandBuffer, buffer, offset, drawCount, stride);
696 AllocateDebugPrintfResources(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS);
697}
698
699void DebugPrintf::PreCallRecordCmdDrawMeshTasksIndirectCountNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
700 VkBuffer countBuffer, VkDeviceSize countBufferOffset,
701 uint32_t maxDrawCount, uint32_t stride) {
702 ValidationStateTracker::PreCallRecordCmdDrawMeshTasksIndirectCountNV(commandBuffer, buffer, offset, countBuffer,
703 countBufferOffset, maxDrawCount, stride);
704 AllocateDebugPrintfResources(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS);
705}
706
Tony-LunarGb5fae462020-03-05 12:43:25 -0700707void DebugPrintf::PreCallRecordCmdTraceRaysNV(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer,
708 VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer,
709 VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride,
710 VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset,
711 VkDeviceSize hitShaderBindingStride, VkBuffer callableShaderBindingTableBuffer,
712 VkDeviceSize callableShaderBindingOffset, VkDeviceSize callableShaderBindingStride,
713 uint32_t width, uint32_t height, uint32_t depth) {
714 AllocateDebugPrintfResources(commandBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_NV);
715}
716
717void DebugPrintf::PostCallRecordCmdTraceRaysNV(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer,
Tony-LunarG04717522019-10-17 10:41:17 -0600718 VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer,
719 VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride,
720 VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset,
721 VkDeviceSize hitShaderBindingStride, VkBuffer callableShaderBindingTableBuffer,
722 VkDeviceSize callableShaderBindingOffset, VkDeviceSize callableShaderBindingStride,
723 uint32_t width, uint32_t height, uint32_t depth) {
Tony-LunarG04717522019-10-17 10:41:17 -0600724 CMD_BUFFER_STATE *cb_state = GetCBState(commandBuffer);
725 cb_state->hasTraceRaysCmd = true;
726}
727
Tony-LunarGb5fae462020-03-05 12:43:25 -0700728void DebugPrintf::PreCallRecordCmdTraceRaysKHR(VkCommandBuffer commandBuffer,
729 const VkStridedBufferRegionKHR *pRaygenShaderBindingTable,
730 const VkStridedBufferRegionKHR *pMissShaderBindingTable,
731 const VkStridedBufferRegionKHR *pHitShaderBindingTable,
732 const VkStridedBufferRegionKHR *pCallableShaderBindingTable, uint32_t width,
733 uint32_t height, uint32_t depth) {
734 AllocateDebugPrintfResources(commandBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR);
Tony-LunarG1dce2392019-10-23 16:49:29 -0600735}
736
Tony-LunarGb5fae462020-03-05 12:43:25 -0700737void DebugPrintf::PostCallRecordCmdTraceRaysKHR(VkCommandBuffer commandBuffer,
738 const VkStridedBufferRegionKHR *pRaygenShaderBindingTable,
739 const VkStridedBufferRegionKHR *pMissShaderBindingTable,
740 const VkStridedBufferRegionKHR *pHitShaderBindingTable,
741 const VkStridedBufferRegionKHR *pCallableShaderBindingTable, uint32_t width,
742 uint32_t height, uint32_t depth) {
Tony-LunarG1dce2392019-10-23 16:49:29 -0600743 CMD_BUFFER_STATE *cb_state = GetCBState(commandBuffer);
744 cb_state->hasTraceRaysCmd = true;
745}
746
Tony-LunarGb5fae462020-03-05 12:43:25 -0700747void DebugPrintf::PreCallRecordCmdTraceRaysIndirectKHR(VkCommandBuffer commandBuffer,
748 const VkStridedBufferRegionKHR *pRaygenShaderBindingTable,
749 const VkStridedBufferRegionKHR *pMissShaderBindingTable,
750 const VkStridedBufferRegionKHR *pHitShaderBindingTable,
751 const VkStridedBufferRegionKHR *pCallableShaderBindingTable, VkBuffer buffer,
752 VkDeviceSize offset) {
753 AllocateDebugPrintfResources(commandBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR);
Tony-LunarG1dce2392019-10-23 16:49:29 -0600754}
755
Tony-LunarGb5fae462020-03-05 12:43:25 -0700756void DebugPrintf::PostCallRecordCmdTraceRaysIndirectKHR(VkCommandBuffer commandBuffer,
757 const VkStridedBufferRegionKHR *pRaygenShaderBindingTable,
758 const VkStridedBufferRegionKHR *pMissShaderBindingTable,
759 const VkStridedBufferRegionKHR *pHitShaderBindingTable,
760 const VkStridedBufferRegionKHR *pCallableShaderBindingTable,
761 VkBuffer buffer, VkDeviceSize offset) {
Tony-LunarG1dce2392019-10-23 16:49:29 -0600762 CMD_BUFFER_STATE *cb_state = GetCBState(commandBuffer);
763 cb_state->hasTraceRaysCmd = true;
764}
765
Tony-LunarGb5fae462020-03-05 12:43:25 -0700766void DebugPrintf::AllocateDebugPrintfResources(const VkCommandBuffer cmd_buffer, const VkPipelineBindPoint bind_point) {
Tony-LunarG04717522019-10-17 10:41:17 -0600767 if (bind_point != VK_PIPELINE_BIND_POINT_GRAPHICS && bind_point != VK_PIPELINE_BIND_POINT_COMPUTE &&
768 bind_point != VK_PIPELINE_BIND_POINT_RAY_TRACING_NV) {
769 return;
770 }
771 VkResult result;
772
773 if (aborted) return;
774
775 std::vector<VkDescriptorSet> desc_sets;
776 VkDescriptorPool desc_pool = VK_NULL_HANDLE;
Tony-LunarG1dce2392019-10-23 16:49:29 -0600777 result = desc_set_manager->GetDescriptorSets(1, &desc_pool, debug_desc_layout, &desc_sets);
Tony-LunarG04717522019-10-17 10:41:17 -0600778 assert(result == VK_SUCCESS);
779 if (result != VK_SUCCESS) {
Tony-LunarG1dce2392019-10-23 16:49:29 -0600780 ReportSetupProblem(device, "Unable to allocate descriptor sets. Device could become unstable.");
Tony-LunarG04717522019-10-17 10:41:17 -0600781 aborted = true;
782 return;
783 }
784
785 VkDescriptorBufferInfo output_desc_buffer_info = {};
786 output_desc_buffer_info.range = output_buffer_size;
787
788 auto cb_node = GetCBState(cmd_buffer);
789 if (!cb_node) {
Tony-LunarG1dce2392019-10-23 16:49:29 -0600790 ReportSetupProblem(device, "Unrecognized command buffer");
Tony-LunarG04717522019-10-17 10:41:17 -0600791 aborted = true;
792 return;
793 }
794
795 // Allocate memory for the output block that the gpu will use to return values for printf
Tony-LunarGb5fae462020-03-05 12:43:25 -0700796 DPFDeviceMemoryBlock output_block = {};
Tony-LunarG04717522019-10-17 10:41:17 -0600797 VkBufferCreateInfo bufferInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO};
798 bufferInfo.size = output_buffer_size;
799 bufferInfo.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
800 VmaAllocationCreateInfo allocInfo = {};
801 allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
802 result = vmaCreateBuffer(vmaAllocator, &bufferInfo, &allocInfo, &output_block.buffer, &output_block.allocation, nullptr);
803 if (result != VK_SUCCESS) {
Tony-LunarG1dce2392019-10-23 16:49:29 -0600804 ReportSetupProblem(device, "Unable to allocate device memory. Device could become unstable.");
Tony-LunarG04717522019-10-17 10:41:17 -0600805 aborted = true;
806 return;
807 }
808
809 // Clear the output block to zeros so that only printf values from the gpu will be present
810 uint32_t *pData;
811 result = vmaMapMemory(vmaAllocator, output_block.allocation, (void **)&pData);
812 if (result == VK_SUCCESS) {
813 memset(pData, 0, output_buffer_size);
814 vmaUnmapMemory(vmaAllocator, output_block.allocation);
815 }
816
817 VkWriteDescriptorSet desc_writes[1] = {};
818 const uint32_t desc_count = 1;
819
820 // Write the descriptor
821 output_desc_buffer_info.buffer = output_block.buffer;
822 output_desc_buffer_info.offset = 0;
823
824 desc_writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
825 desc_writes[0].descriptorCount = 1;
826 desc_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
827 desc_writes[0].pBufferInfo = &output_desc_buffer_info;
828 desc_writes[0].dstSet = desc_sets[0];
829 desc_writes[0].dstBinding = 3;
830 DispatchUpdateDescriptorSets(device, desc_count, desc_writes, 0, NULL);
831
832 auto iter = cb_node->lastBound.find(bind_point); // find() allows read-only access to cb_state
833 if (iter != cb_node->lastBound.end()) {
834 auto pipeline_state = iter->second.pipeline_state;
835 if (pipeline_state && (pipeline_state->pipeline_layout->set_layouts.size() <= desc_set_bind_index)) {
836 DispatchCmdBindDescriptorSets(cmd_buffer, bind_point, pipeline_state->pipeline_layout->layout, desc_set_bind_index, 1,
837 desc_sets.data(), 0, nullptr);
838 }
839 // Record buffer and memory info in CB state tracking
Tony-LunarG1dce2392019-10-23 16:49:29 -0600840 GetBufferInfo(cmd_buffer).emplace_back(output_block, desc_sets[0], desc_pool, bind_point);
Tony-LunarG04717522019-10-17 10:41:17 -0600841 } else {
Tony-LunarG1dce2392019-10-23 16:49:29 -0600842 ReportSetupProblem(device, "Unable to find pipeline state");
Tony-LunarG04717522019-10-17 10:41:17 -0600843 vmaDestroyBuffer(vmaAllocator, output_block.buffer, output_block.allocation);
844 aborted = true;
845 return;
846 }
847}