blob: 2b39c5291e060e0197551dd47d5935aeab668704 [file] [log] [blame]
Chris Forbes2778f302015-04-02 13:22:31 +13001/*
2 * Vulkan
3 *
4 * Copyright (C) 2015 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24#include <string.h>
25#include <stdlib.h>
26#include <assert.h>
Chris Forbes06e8fc32015-04-13 12:14:52 +120027#include <map>
Chris Forbes2778f302015-04-02 13:22:31 +130028#include <unordered_map>
Chris Forbes41002452015-04-08 10:19:16 +120029#include <map>
Chris Forbes3b1c4212015-04-08 10:11:59 +120030#include <vector>
Courtney Goeltzenleuchteree4027d2015-06-28 13:01:17 -060031#include <string>
Tobin Ehlisb80b4252015-09-01 11:59:36 -060032#include <iostream>
Tobin Ehlisb835d1b2015-07-03 10:34:49 -060033#include "vk_loader_platform.h"
Chris Forbes2778f302015-04-02 13:22:31 +130034#include "vk_dispatch_table_helper.h"
Tobin Ehlis0c6f9ee2015-07-03 09:42:57 -060035#include "vk_layer.h"
Tobin Ehlisa0cb02e2015-07-03 10:15:26 -060036#include "vk_layer_config.h"
Tobin Ehlisa0cb02e2015-07-03 10:15:26 -060037#include "vk_layer_table.h"
Chris Forbesb1dee272015-07-03 13:50:24 +120038#include "vk_layer_logging.h"
Chris Forbes401784b2015-05-04 14:04:24 +120039#include "vk_enum_string_helper.h"
Chris Forbes6b2ead62015-04-17 10:13:28 +120040#include "shader_checker.h"
Courtney Goeltzenleuchterda8adfe2015-07-07 10:05:05 -060041#include "vk_layer_extension_utils.h"
Chris Forbes2778f302015-04-02 13:22:31 +130042
GregF7c45bed2015-07-21 17:22:50 -060043#include "spirv/spirv.hpp"
Chris Forbes2778f302015-04-02 13:22:31 +130044
Chris Forbes2778f302015-04-02 13:22:31 +130045
Cody Northrop55443ef2015-09-28 15:09:32 -060046struct layer_data {
Chris Forbesb1dee272015-07-03 13:50:24 +120047 debug_report_data *report_data;
48 // TODO: put instance data here
Courtney Goeltzenleuchtered12e712015-10-05 15:59:58 -060049 std::vector<VkDbgMsgCallback> logging_callback;
Cody Northrop55443ef2015-09-28 15:09:32 -060050
51 layer_data() :
Courtney Goeltzenleuchtered12e712015-10-05 15:59:58 -060052 report_data(nullptr)
Cody Northrop55443ef2015-09-28 15:09:32 -060053 {};
54};
Chris Forbesb1dee272015-07-03 13:50:24 +120055
56static std::unordered_map<void *, layer_data *> layer_data_map;
57static device_table_map shader_checker_device_table_map;
58static instance_table_map shader_checker_instance_table_map;
59
60
61template layer_data *get_my_data_ptr<layer_data>(
62 void *data_key,
63 std::unordered_map<void *, layer_data *> &data_map);
64
Chris Forbes9715d4a2015-07-10 09:06:54 +120065debug_report_data *mdd(void *object)
Chris Forbesb1dee272015-07-03 13:50:24 +120066{
67 dispatch_key key = get_dispatch_key(object);
68 layer_data *my_data = get_my_data_ptr(key, layer_data_map);
69#if DISPATCH_MAP_DEBUG
70 fprintf(stderr, "MDD: map: %p, object: %p, key: %p, data: %p\n", &layer_data_map, object, key, my_data);
71#endif
72 return my_data->report_data;
73}
74
75debug_report_data *mid(VkInstance object)
76{
77 dispatch_key key = get_dispatch_key(object);
Tobin Ehlisbfbac252015-09-01 11:46:36 -060078 layer_data *my_data = get_my_data_ptr(key, layer_data_map);
Chris Forbesb1dee272015-07-03 13:50:24 +120079#if DISPATCH_MAP_DEBUG
80 fprintf(stderr, "MID: map: %p, object: %p, key: %p, data: %p\n", &layer_data_map, object, key, my_data);
81#endif
82 return my_data->report_data;
83}
84
Chris Forbesb6b8c462015-04-15 06:59:41 +120085static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(g_initOnce);
Chris Forbes7f963832015-05-29 14:55:18 +120086// TODO : This can be much smarter, using separate locks for separate global data
87static int globalLockInitialized = 0;
88static loader_platform_thread_mutex globalLock;
Chris Forbes3b1c4212015-04-08 10:11:59 +120089
Chris Forbes3a5e99a2015-04-10 11:41:20 +120090
Courtney Goeltzenleuchter8f8367e2015-10-07 08:38:30 -060091std::unordered_map<uint64_t, std::vector<VkDescriptorSetLayoutBinding>*> descriptor_set_layout_map;
Chris Forbes2b8493a2015-08-12 15:03:22 +120092
93VK_LAYER_EXPORT VkResult VKAPI vkCreateDescriptorSetLayout(
94 VkDevice device,
95 const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
96 VkDescriptorSetLayout* pSetLayout)
97{
98 /* stash a copy of the layout bindings */
99 VkLayerDispatchTable *pDeviceTable = get_dispatch_table(shader_checker_device_table_map, device);
100 VkResult result = pDeviceTable->CreateDescriptorSetLayout(device, pCreateInfo, pSetLayout);
101
102 if (VK_SUCCESS == result) {
103 loader_platform_thread_lock_mutex(&globalLock);
104 auto& bindings = descriptor_set_layout_map[pSetLayout->handle];
105 bindings = new std::vector<VkDescriptorSetLayoutBinding>(
106 pCreateInfo->pBinding, pCreateInfo->pBinding + pCreateInfo->count);
107 loader_platform_thread_unlock_mutex(&globalLock);
108 }
109
110 return result;
111}
112
113
Courtney Goeltzenleuchter8f8367e2015-10-07 08:38:30 -0600114std::unordered_map<uint64_t, std::vector<std::vector<VkDescriptorSetLayoutBinding>*>*> pipeline_layout_map;
Chris Forbes2b8493a2015-08-12 15:03:22 +1200115
116VK_LAYER_EXPORT VkResult VKAPI vkCreatePipelineLayout(
117 VkDevice device,
118 const VkPipelineLayoutCreateInfo* pCreateInfo,
119 VkPipelineLayout* pPipelineLayout)
120{
121 VkLayerDispatchTable *pDeviceTable = get_dispatch_table(shader_checker_device_table_map, device);
122 VkResult result = pDeviceTable->CreatePipelineLayout(device, pCreateInfo, pPipelineLayout);
123
124 if (VK_SUCCESS == result) {
125 loader_platform_thread_lock_mutex(&globalLock);
126 auto& layouts = pipeline_layout_map[pPipelineLayout->handle];
127 layouts = new std::vector<std::vector<VkDescriptorSetLayoutBinding>*>();
128 layouts->reserve(pCreateInfo->descriptorSetCount);
129 for (unsigned i = 0; i < pCreateInfo->descriptorSetCount; i++) {
130 layouts->push_back(descriptor_set_layout_map[pCreateInfo->pSetLayouts[i].handle]);
131 }
132 loader_platform_thread_unlock_mutex(&globalLock);
133 }
134
135 return result;
136}
137
138
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200139static void
140build_type_def_index(std::vector<unsigned> const &words, std::unordered_map<unsigned, unsigned> &type_def_index)
141{
142 unsigned int const *code = (unsigned int const *)&words[0];
143 size_t size = words.size();
144
145 unsigned word = 5;
146 while (word < size) {
147 unsigned opcode = code[word] & 0x0ffffu;
148 unsigned oplen = (code[word] & 0xffff0000u) >> 16;
149
150 switch (opcode) {
151 case spv::OpTypeVoid:
152 case spv::OpTypeBool:
153 case spv::OpTypeInt:
154 case spv::OpTypeFloat:
155 case spv::OpTypeVector:
156 case spv::OpTypeMatrix:
GregF7c45bed2015-07-21 17:22:50 -0600157 case spv::OpTypeImage:
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200158 case spv::OpTypeSampler:
GregF7c45bed2015-07-21 17:22:50 -0600159 case spv::OpTypeSampledImage:
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200160 case spv::OpTypeArray:
161 case spv::OpTypeRuntimeArray:
162 case spv::OpTypeStruct:
163 case spv::OpTypeOpaque:
164 case spv::OpTypePointer:
165 case spv::OpTypeFunction:
166 case spv::OpTypeEvent:
167 case spv::OpTypeDeviceEvent:
168 case spv::OpTypeReserveId:
169 case spv::OpTypeQueue:
170 case spv::OpTypePipe:
171 type_def_index[code[word+1]] = word;
172 break;
173
174 default:
175 /* We only care about type definitions */
176 break;
177 }
178
179 word += oplen;
180 }
181}
182
Chris Forbes46794b82015-09-18 11:40:23 +1200183
184bool
185shader_is_spirv(VkShaderModuleCreateInfo const *pCreateInfo)
186{
187 uint32_t *words = (uint32_t *)pCreateInfo->pCode;
Courtney Goeltzenleuchter8f8367e2015-10-07 08:38:30 -0600188 size_t sizeInWords = pCreateInfo->codeSize / sizeof(uint32_t);
Chris Forbes46794b82015-09-18 11:40:23 +1200189
190 /* Just validate that the header makes sense. */
191 return sizeInWords >= 5 && words[0] == spv::MagicNumber && words[1] == spv::Version;
192}
193
Courtney Goeltzenleuchteree4027d2015-06-28 13:01:17 -0600194struct shader_module {
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200195 /* the spirv image itself */
Chris Forbes3b1c4212015-04-08 10:11:59 +1200196 std::vector<uint32_t> words;
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200197 /* a mapping of <id> to the first word of its def. this is useful because walking type
198 * trees requires jumping all over the instruction stream.
199 */
200 std::unordered_map<unsigned, unsigned> type_def_index;
Chris Forbes3b1c4212015-04-08 10:11:59 +1200201
Chris Forbes46794b82015-09-18 11:40:23 +1200202 shader_module(VkShaderModuleCreateInfo const *pCreateInfo) :
Chris Forbesf044ec92015-06-05 15:01:08 +1200203 words((uint32_t *)pCreateInfo->pCode, (uint32_t *)pCreateInfo->pCode + pCreateInfo->codeSize / sizeof(uint32_t)),
Chris Forbes46794b82015-09-18 11:40:23 +1200204 type_def_index() {
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200205
206 build_type_def_index(words, type_def_index);
Chris Forbes3b1c4212015-04-08 10:11:59 +1200207 }
208};
209
210
Chris Forbes9715d4a2015-07-10 09:06:54 +1200211static std::unordered_map<uint64_t, shader_module *> shader_module_map;
Courtney Goeltzenleuchteree4027d2015-06-28 13:01:17 -0600212
213struct shader_object {
214 std::string name;
215 struct shader_module *module;
216
217 shader_object(VkShaderCreateInfo const *pCreateInfo)
218 {
Chris Forbes9715d4a2015-07-10 09:06:54 +1200219 module = shader_module_map[pCreateInfo->module.handle];
Courtney Goeltzenleuchteree4027d2015-06-28 13:01:17 -0600220 name = pCreateInfo->pName;
221 }
222};
Chris Forbes9715d4a2015-07-10 09:06:54 +1200223static std::unordered_map<uint64_t, shader_object *> shader_object_map;
Chris Forbes3b1c4212015-04-08 10:11:59 +1200224
Chia-I Wu08accc62015-07-07 11:50:03 +0800225struct render_pass {
226 std::vector<std::vector<VkFormat>> subpass_color_formats;
227
228 render_pass(VkRenderPassCreateInfo const *pCreateInfo)
229 {
230 uint32_t i;
231
232 subpass_color_formats.reserve(pCreateInfo->subpassCount);
233 for (i = 0; i < pCreateInfo->subpassCount; i++) {
234 const VkSubpassDescription *subpass = &pCreateInfo->pSubpasses[i];
235 std::vector<VkFormat> color_formats;
236 uint32_t j;
237
238 color_formats.reserve(subpass->colorCount);
239 for (j = 0; j < subpass->colorCount; j++) {
Cody Northropa505dda2015-08-04 11:16:41 -0600240 const uint32_t att = subpass->pColorAttachments[j].attachment;
Chia-I Wu08accc62015-07-07 11:50:03 +0800241 const VkFormat format = pCreateInfo->pAttachments[att].format;
242
243 color_formats.push_back(pCreateInfo->pAttachments[att].format);
244 }
245
246 subpass_color_formats.push_back(color_formats);
247 }
248 }
249};
Chris Forbes9715d4a2015-07-10 09:06:54 +1200250static std::unordered_map<uint64_t, render_pass *> render_pass_map;
Chia-I Wu08accc62015-07-07 11:50:03 +0800251
Chris Forbes3b1c4212015-04-08 10:11:59 +1200252
Chris Forbesb6b8c462015-04-15 06:59:41 +1200253static void
Chris Forbesb1dee272015-07-03 13:50:24 +1200254init_shader_checker(layer_data *my_data)
Chris Forbesb6b8c462015-04-15 06:59:41 +1200255{
Chris Forbesb1dee272015-07-03 13:50:24 +1200256 uint32_t report_flags = 0;
257 uint32_t debug_action = 0;
258 FILE *log_output = NULL;
259 const char *option_str;
Courtney Goeltzenleuchtered12e712015-10-05 15:59:58 -0600260 VkDbgMsgCallback callback;
Chris Forbesb6b8c462015-04-15 06:59:41 +1200261 // initialize ShaderChecker options
Chris Forbesb1dee272015-07-03 13:50:24 +1200262 report_flags = getLayerOptionFlags("ShaderCheckerReportFlags", 0);
263 getLayerOptionEnum("ShaderCheckerDebugAction", (uint32_t *) &debug_action);
Chris Forbesb6b8c462015-04-15 06:59:41 +1200264
Chris Forbesb1dee272015-07-03 13:50:24 +1200265 if (debug_action & VK_DBG_LAYER_ACTION_LOG_MSG)
Chris Forbesb6b8c462015-04-15 06:59:41 +1200266 {
Chris Forbesb1dee272015-07-03 13:50:24 +1200267 option_str = getLayerOption("ShaderCheckerLogFilename");
Tobin Ehlisb1df55e2015-09-15 09:55:54 -0600268 log_output = getLayerLogOutput(option_str, "ShaderChecker");
Courtney Goeltzenleuchtered12e712015-10-05 15:59:58 -0600269 layer_create_msg_callback(my_data->report_data, report_flags, log_callback, (void *) log_output, &callback);
270 my_data->logging_callback.push_back(callback);
271 }
272
273 if (debug_action & VK_DBG_LAYER_ACTION_DEBUG_OUTPUT) {
274 layer_create_msg_callback(my_data->report_data, report_flags, win32_debug_output_msg, NULL, &callback);
275 my_data->logging_callback.push_back(callback);
Chris Forbesb1dee272015-07-03 13:50:24 +1200276 }
277
278 if (!globalLockInitialized)
279 {
280 // TODO/TBD: Need to delete this mutex sometime. How??? One
281 // suggestion is to call this during vkCreateInstance(), and then we
282 // can clean it up during vkDestroyInstance(). However, that requires
283 // that the layer have per-instance locks. We need to come back and
284 // address this soon.
285 loader_platform_thread_create_mutex(&globalLock);
286 globalLockInitialized = 1;
Chris Forbesb6b8c462015-04-15 06:59:41 +1200287 }
288}
289
Courtney Goeltzenleuchterda8adfe2015-07-07 10:05:05 -0600290static const VkLayerProperties shader_checker_global_layers[] = {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600291 {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600292 "ShaderChecker",
Courtney Goeltzenleuchterda8adfe2015-07-07 10:05:05 -0600293 VK_API_VERSION,
294 VK_MAKE_VERSION(0, 1, 0),
295 "Validation layer: ShaderChecker",
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600296 }
Chris Forbes2778f302015-04-02 13:22:31 +1300297};
298
Courtney Goeltzenleuchter35985f62015-09-14 17:22:16 -0600299VK_LAYER_EXPORT VkResult VKAPI vkEnumerateInstanceExtensionProperties(
Courtney Goeltzenleuchterda8adfe2015-07-07 10:05:05 -0600300 const char *pLayerName,
301 uint32_t *pCount,
302 VkExtensionProperties* pProperties)
Chris Forbes2778f302015-04-02 13:22:31 +1300303{
Courtney Goeltzenleuchterda8adfe2015-07-07 10:05:05 -0600304 /* shader checker does not have any global extensions */
305 return util_GetExtensionProperties(0, NULL, pCount, pProperties);
Chris Forbes2778f302015-04-02 13:22:31 +1300306}
307
Courtney Goeltzenleuchter35985f62015-09-14 17:22:16 -0600308VK_LAYER_EXPORT VkResult VKAPI vkEnumerateInstanceLayerProperties(
Courtney Goeltzenleuchterda8adfe2015-07-07 10:05:05 -0600309 uint32_t *pCount,
310 VkLayerProperties* pProperties)
Tony Barbour59a47322015-06-24 16:06:58 -0600311{
Courtney Goeltzenleuchterda8adfe2015-07-07 10:05:05 -0600312 return util_GetLayerProperties(ARRAY_SIZE(shader_checker_global_layers),
313 shader_checker_global_layers,
314 pCount, pProperties);
Tony Barbour59a47322015-06-24 16:06:58 -0600315}
316
Courtney Goeltzenleuchter35985f62015-09-14 17:22:16 -0600317VK_LAYER_EXPORT VkResult VKAPI vkEnumerateDeviceExtensionProperties(
Courtney Goeltzenleuchterda8adfe2015-07-07 10:05:05 -0600318 VkPhysicalDevice physicalDevice,
319 const char* pLayerName,
320 uint32_t* pCount,
321 VkExtensionProperties* pProperties)
Jon Ashburn207a3af2015-06-10 16:43:31 -0600322{
Courtney Goeltzenleuchterda8adfe2015-07-07 10:05:05 -0600323 /* Shader checker does not have any physical device extensions */
324 return util_GetExtensionProperties(0, NULL, pCount, pProperties);
325}
Jon Ashburn207a3af2015-06-10 16:43:31 -0600326
Courtney Goeltzenleuchter35985f62015-09-14 17:22:16 -0600327VK_LAYER_EXPORT VkResult VKAPI vkEnumerateDeviceLayerProperties(
Courtney Goeltzenleuchterda8adfe2015-07-07 10:05:05 -0600328 VkPhysicalDevice physicalDevice,
329 uint32_t* pCount,
330 VkLayerProperties* pProperties)
331{
332 /* Shader checker physical device layers are the same as global */
333 return util_GetLayerProperties(ARRAY_SIZE(shader_checker_global_layers),
334 shader_checker_global_layers,
335 pCount, pProperties);
Jon Ashburn207a3af2015-06-10 16:43:31 -0600336}
Chris Forbes2778f302015-04-02 13:22:31 +1300337
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200338static char const *
339storage_class_name(unsigned sc)
340{
341 switch (sc) {
Cody Northrop97e52d82015-04-20 14:09:40 -0600342 case spv::StorageClassInput: return "input";
343 case spv::StorageClassOutput: return "output";
344 case spv::StorageClassUniformConstant: return "const uniform";
345 case spv::StorageClassUniform: return "uniform";
346 case spv::StorageClassWorkgroupLocal: return "workgroup local";
347 case spv::StorageClassWorkgroupGlobal: return "workgroup global";
348 case spv::StorageClassPrivateGlobal: return "private global";
349 case spv::StorageClassFunction: return "function";
350 case spv::StorageClassGeneric: return "generic";
Cody Northrop97e52d82015-04-20 14:09:40 -0600351 case spv::StorageClassAtomicCounter: return "atomic counter";
GregF7c45bed2015-07-21 17:22:50 -0600352 case spv::StorageClassImage: return "image";
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200353 default: return "unknown";
354 }
355}
356
357
358/* returns ptr to null terminator */
359static char *
Courtney Goeltzenleuchteree4027d2015-06-28 13:01:17 -0600360describe_type(char *dst, shader_module const *src, unsigned type)
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200361{
362 auto type_def_it = src->type_def_index.find(type);
363
364 if (type_def_it == src->type_def_index.end()) {
365 return dst + sprintf(dst, "undef");
366 }
367
368 unsigned int const *code = (unsigned int const *)&src->words[type_def_it->second];
369 unsigned opcode = code[0] & 0x0ffffu;
370 switch (opcode) {
371 case spv::OpTypeBool:
372 return dst + sprintf(dst, "bool");
373 case spv::OpTypeInt:
374 return dst + sprintf(dst, "%cint%d", code[3] ? 's' : 'u', code[2]);
375 case spv::OpTypeFloat:
376 return dst + sprintf(dst, "float%d", code[2]);
377 case spv::OpTypeVector:
378 dst += sprintf(dst, "vec%d of ", code[3]);
379 return describe_type(dst, src, code[2]);
380 case spv::OpTypeMatrix:
381 dst += sprintf(dst, "mat%d of ", code[3]);
382 return describe_type(dst, src, code[2]);
383 case spv::OpTypeArray:
384 dst += sprintf(dst, "arr[%d] of ", code[3]);
385 return describe_type(dst, src, code[2]);
386 case spv::OpTypePointer:
387 dst += sprintf(dst, "ptr to %s ", storage_class_name(code[2]));
388 return describe_type(dst, src, code[3]);
389 case spv::OpTypeStruct:
390 {
391 unsigned oplen = code[0] >> 16;
392 dst += sprintf(dst, "struct of (");
Ian Elliott1cb62222015-04-17 11:05:04 -0600393 for (unsigned i = 2; i < oplen; i++) {
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200394 dst = describe_type(dst, src, code[i]);
395 dst += sprintf(dst, i == oplen-1 ? ")" : ", ");
396 }
397 return dst;
398 }
Chris Forbes0ae15802015-08-14 12:04:39 +1200399 case spv::OpTypeSampler:
400 return dst + sprintf(dst, "sampler");
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200401 default:
402 return dst + sprintf(dst, "oddtype");
403 }
404}
405
406
407static bool
Courtney Goeltzenleuchteree4027d2015-06-28 13:01:17 -0600408types_match(shader_module const *a, shader_module const *b, unsigned a_type, unsigned b_type, bool b_arrayed)
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200409{
410 auto a_type_def_it = a->type_def_index.find(a_type);
411 auto b_type_def_it = b->type_def_index.find(b_type);
412
413 if (a_type_def_it == a->type_def_index.end()) {
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200414 return false;
415 }
416
417 if (b_type_def_it == b->type_def_index.end()) {
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200418 return false;
419 }
420
421 /* walk two type trees together, and complain about differences */
422 unsigned int const *a_code = (unsigned int const *)&a->words[a_type_def_it->second];
423 unsigned int const *b_code = (unsigned int const *)&b->words[b_type_def_it->second];
424
425 unsigned a_opcode = a_code[0] & 0x0ffffu;
426 unsigned b_opcode = b_code[0] & 0x0ffffu;
427
Chris Forbesf3fc0332015-06-05 14:57:05 +1200428 if (b_arrayed && b_opcode == spv::OpTypeArray) {
429 /* we probably just found the extra level of arrayness in b_type: compare the type inside it to a_type */
430 return types_match(a, b, a_type, b_code[2], false);
431 }
432
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200433 if (a_opcode != b_opcode) {
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200434 return false;
435 }
436
437 switch (a_opcode) {
Chris Forbesf3fc0332015-06-05 14:57:05 +1200438 /* if b_arrayed and we hit a leaf type, then we can't match -- there's nowhere for the extra OpTypeArray to be! */
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200439 case spv::OpTypeBool:
Chris Forbesf3fc0332015-06-05 14:57:05 +1200440 return true && !b_arrayed;
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200441 case spv::OpTypeInt:
442 /* match on width, signedness */
Chris Forbesf3fc0332015-06-05 14:57:05 +1200443 return a_code[2] == b_code[2] && a_code[3] == b_code[3] && !b_arrayed;
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200444 case spv::OpTypeFloat:
445 /* match on width */
Chris Forbesf3fc0332015-06-05 14:57:05 +1200446 return a_code[2] == b_code[2] && !b_arrayed;
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200447 case spv::OpTypeVector:
448 case spv::OpTypeMatrix:
449 case spv::OpTypeArray:
Chris Forbesf3fc0332015-06-05 14:57:05 +1200450 /* match on element type, count. these all have the same layout. we don't get here if
451 * b_arrayed -- that is handled above. */
452 return !b_arrayed && types_match(a, b, a_code[2], b_code[2], b_arrayed) && a_code[3] == b_code[3];
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200453 case spv::OpTypeStruct:
454 /* match on all element types */
455 {
Chris Forbesf3fc0332015-06-05 14:57:05 +1200456 if (b_arrayed) {
457 /* for the purposes of matching different levels of arrayness, structs are leaves. */
458 return false;
459 }
460
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200461 unsigned a_len = a_code[0] >> 16;
462 unsigned b_len = b_code[0] >> 16;
463
464 if (a_len != b_len) {
465 return false; /* structs cannot match if member counts differ */
466 }
467
Ian Elliott1cb62222015-04-17 11:05:04 -0600468 for (unsigned i = 2; i < a_len; i++) {
Chris Forbesf3fc0332015-06-05 14:57:05 +1200469 if (!types_match(a, b, a_code[i], b_code[i], b_arrayed)) {
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200470 return false;
471 }
472 }
473
474 return true;
475 }
476 case spv::OpTypePointer:
477 /* match on pointee type. storage class is expected to differ */
Chris Forbesf3fc0332015-06-05 14:57:05 +1200478 return types_match(a, b, a_code[3], b_code[3], b_arrayed);
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200479
480 default:
481 /* remaining types are CLisms, or may not appear in the interfaces we
482 * are interested in. Just claim no match.
483 */
484 return false;
485
486 }
487}
488
489
Chris Forbes06e8fc32015-04-13 12:14:52 +1200490static int
491value_or_default(std::unordered_map<unsigned, unsigned> const &map, unsigned id, int def)
492{
493 auto it = map.find(id);
494 if (it == map.end())
495 return def;
496 else
497 return it->second;
498}
499
500
501struct interface_var {
502 uint32_t id;
503 uint32_t type_id;
504 /* TODO: collect the name, too? Isn't required to be present. */
505};
506
507
508static void
Chris Forbesb1dee272015-07-03 13:50:24 +1200509collect_interface_by_location(VkDevice dev,
510 shader_module const *src, spv::StorageClass sinterface,
Chris Forbes06e8fc32015-04-13 12:14:52 +1200511 std::map<uint32_t, interface_var> &out,
512 std::map<uint32_t, interface_var> &builtins_out)
513{
514 unsigned int const *code = (unsigned int const *)&src->words[0];
515 size_t size = src->words.size();
516
Chris Forbes06e8fc32015-04-13 12:14:52 +1200517 std::unordered_map<unsigned, unsigned> var_locations;
518 std::unordered_map<unsigned, unsigned> var_builtins;
519
520 unsigned word = 5;
521 while (word < size) {
522
523 unsigned opcode = code[word] & 0x0ffffu;
524 unsigned oplen = (code[word] & 0xffff0000u) >> 16;
525
526 /* We consider two interface models: SSO rendezvous-by-location, and
527 * builtins. Complain about anything that fits neither model.
528 */
529 if (opcode == spv::OpDecorate) {
Cody Northrop97e52d82015-04-20 14:09:40 -0600530 if (code[word+2] == spv::DecorationLocation) {
Chris Forbes06e8fc32015-04-13 12:14:52 +1200531 var_locations[code[word+1]] = code[word+3];
532 }
533
Cody Northrop97e52d82015-04-20 14:09:40 -0600534 if (code[word+2] == spv::DecorationBuiltIn) {
Chris Forbes06e8fc32015-04-13 12:14:52 +1200535 var_builtins[code[word+1]] = code[word+3];
536 }
537 }
538
539 /* TODO: handle grouped decorations */
540 /* TODO: handle index=1 dual source outputs from FS -- two vars will
541 * have the same location, and we DONT want to clobber. */
542
Ian Elliott1cb62222015-04-17 11:05:04 -0600543 if (opcode == spv::OpVariable && code[word+3] == sinterface) {
Chris Forbes06e8fc32015-04-13 12:14:52 +1200544 int location = value_or_default(var_locations, code[word+2], -1);
545 int builtin = value_or_default(var_builtins, code[word+2], -1);
546
547 if (location == -1 && builtin == -1) {
548 /* No location defined, and not bound to an API builtin.
549 * The spec says nothing about how this case works (or doesn't)
550 * for interface matching.
551 */
Chris Forbes9715d4a2015-07-10 09:06:54 +1200552 log_msg(mdd(dev), VK_DBG_REPORT_WARN_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_INCONSISTENT_SPIRV, "SC",
Chris Forbesb1dee272015-07-03 13:50:24 +1200553 "var %d (type %d) in %s interface has no Location or Builtin decoration",
554 code[word+2], code[word+1], storage_class_name(sinterface));
Chris Forbes06e8fc32015-04-13 12:14:52 +1200555 }
556 else if (location != -1) {
557 /* A user-defined interface variable, with a location. */
558 interface_var v;
559 v.id = code[word+2];
560 v.type_id = code[word+1];
561 out[location] = v;
562 }
563 else {
564 /* A builtin interface variable */
565 interface_var v;
566 v.id = code[word+2];
567 v.type_id = code[word+1];
568 builtins_out[builtin] = v;
569 }
570 }
571
572 word += oplen;
573 }
574}
575
576
Chris Forbes0ae15802015-08-14 12:04:39 +1200577static void
578collect_interface_by_descriptor_slot(VkDevice dev,
579 shader_module const *src, spv::StorageClass sinterface,
580 std::map<std::pair<unsigned, unsigned>, interface_var> &out)
581{
582 unsigned int const *code = (unsigned int const *)&src->words[0];
583 size_t size = src->words.size();
584
585 std::unordered_map<unsigned, unsigned> var_sets;
586 std::unordered_map<unsigned, unsigned> var_bindings;
587
588 unsigned word = 5;
589 while (word < size) {
590
591 unsigned opcode = code[word] & 0x0ffffu;
592 unsigned oplen = (code[word] & 0xffff0000u) >> 16;
593
594 /* We consider two interface models: SSO rendezvous-by-location, and
595 * builtins. Complain about anything that fits neither model.
596 */
597 if (opcode == spv::OpDecorate) {
598 if (code[word+2] == spv::DecorationDescriptorSet) {
599 var_sets[code[word+1]] = code[word+3];
600 }
601
602 if (code[word+2] == spv::DecorationBinding) {
603 var_bindings[code[word+1]] = code[word+3];
604 }
605 }
606
607 if (opcode == spv::OpVariable && (code[word+3] == spv::StorageClassUniform ||
608 code[word+3] == spv::StorageClassUniformConstant)) {
609 unsigned set = value_or_default(var_sets, code[word+2], 0);
610 unsigned binding = value_or_default(var_bindings, code[word+2], 0);
611
612 auto existing_it = out.find(std::make_pair(set, binding));
613 if (existing_it != out.end()) {
614 /* conflict within spv image */
615 log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0,
616 SHADER_CHECKER_INCONSISTENT_SPIRV, "SC",
617 "var %d (type %d) in %s interface in descriptor slot (%u,%u) conflicts with existing definition",
618 code[word+2], code[word+1], storage_class_name(sinterface),
619 existing_it->first.first, existing_it->first.second);
620 }
621
622 interface_var v;
623 v.id = code[word+2];
624 v.type_id = code[word+1];
625 out[std::make_pair(set, binding)] = v;
626 }
627
628 word += oplen;
629 }
630}
631
632
Courtney Goeltzenleuchteree4027d2015-06-28 13:01:17 -0600633VK_LAYER_EXPORT VkResult VKAPI vkCreateShaderModule(
634 VkDevice device,
635 const VkShaderModuleCreateInfo *pCreateInfo,
636 VkShaderModule *pShaderModule)
Chris Forbes2778f302015-04-02 13:22:31 +1300637{
Chris Forbes46794b82015-09-18 11:40:23 +1200638 /* Protect the driver from non-SPIRV shaders */
639 if (!shader_is_spirv(pCreateInfo)) {
640 log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE,
641 /* dev */ 0, 0, SHADER_CHECKER_NON_SPIRV_SHADER, "SC",
642 "Shader is not SPIR-V");
643 return VK_ERROR_VALIDATION_FAILED;
644 }
645
Chris Forbesb1dee272015-07-03 13:50:24 +1200646 VkResult res = get_dispatch_table(shader_checker_device_table_map, device)->CreateShaderModule(device, pCreateInfo, pShaderModule);
Chris Forbes3b1c4212015-04-08 10:11:59 +1200647
Courtney Goeltzenleuchterb5afdbf2015-09-16 12:57:55 -0600648 if (res == VK_SUCCESS) {
649 loader_platform_thread_lock_mutex(&globalLock);
Chris Forbes46794b82015-09-18 11:40:23 +1200650 shader_module_map[pShaderModule->handle] = new shader_module(pCreateInfo);
Courtney Goeltzenleuchterb5afdbf2015-09-16 12:57:55 -0600651 loader_platform_thread_unlock_mutex(&globalLock);
652 }
Chris Forbes2778f302015-04-02 13:22:31 +1300653 return res;
654}
655
Courtney Goeltzenleuchteree4027d2015-06-28 13:01:17 -0600656VK_LAYER_EXPORT VkResult VKAPI vkCreateShader(
657 VkDevice device,
658 const VkShaderCreateInfo *pCreateInfo,
659 VkShader *pShader)
660{
Chris Forbesb1dee272015-07-03 13:50:24 +1200661 VkResult res = get_dispatch_table(shader_checker_device_table_map, device)->CreateShader(device, pCreateInfo, pShader);
Courtney Goeltzenleuchteree4027d2015-06-28 13:01:17 -0600662
Courtney Goeltzenleuchterb5afdbf2015-09-16 12:57:55 -0600663 loader_platform_thread_lock_mutex(&globalLock);
Chris Forbes9715d4a2015-07-10 09:06:54 +1200664 shader_object_map[pShader->handle] = new shader_object(pCreateInfo);
Courtney Goeltzenleuchteree4027d2015-06-28 13:01:17 -0600665 loader_platform_thread_unlock_mutex(&globalLock);
666 return res;
667}
Chris Forbes2778f302015-04-02 13:22:31 +1300668
Chia-I Wu08accc62015-07-07 11:50:03 +0800669VK_LAYER_EXPORT VkResult VKAPI vkCreateRenderPass(
670 VkDevice device,
671 const VkRenderPassCreateInfo *pCreateInfo,
672 VkRenderPass *pRenderPass)
673{
Chia-I Wu08accc62015-07-07 11:50:03 +0800674 VkResult res = get_dispatch_table(shader_checker_device_table_map, device)->CreateRenderPass(device, pCreateInfo, pRenderPass);
675
Courtney Goeltzenleuchterb5afdbf2015-09-16 12:57:55 -0600676 loader_platform_thread_lock_mutex(&globalLock);
Chris Forbes9715d4a2015-07-10 09:06:54 +1200677 render_pass_map[pRenderPass->handle] = new render_pass(pCreateInfo);
Chia-I Wu08accc62015-07-07 11:50:03 +0800678 loader_platform_thread_unlock_mutex(&globalLock);
679 return res;
680}
681
Chris Forbesee99b9b2015-05-25 11:13:22 +1200682static bool
Chris Forbesb1dee272015-07-03 13:50:24 +1200683validate_interface_between_stages(VkDevice dev,
684 shader_module const *producer, char const *producer_name,
Courtney Goeltzenleuchteree4027d2015-06-28 13:01:17 -0600685 shader_module const *consumer, char const *consumer_name,
Chris Forbesf044ec92015-06-05 15:01:08 +1200686 bool consumer_arrayed_input)
Chris Forbes41002452015-04-08 10:19:16 +1200687{
688 std::map<uint32_t, interface_var> outputs;
689 std::map<uint32_t, interface_var> inputs;
690
691 std::map<uint32_t, interface_var> builtin_outputs;
692 std::map<uint32_t, interface_var> builtin_inputs;
693
Chris Forbesee99b9b2015-05-25 11:13:22 +1200694 bool pass = true;
Chris Forbes41002452015-04-08 10:19:16 +1200695
Chris Forbesb1dee272015-07-03 13:50:24 +1200696 collect_interface_by_location(dev, producer, spv::StorageClassOutput, outputs, builtin_outputs);
697 collect_interface_by_location(dev, consumer, spv::StorageClassInput, inputs, builtin_inputs);
Chris Forbes41002452015-04-08 10:19:16 +1200698
699 auto a_it = outputs.begin();
700 auto b_it = inputs.begin();
701
702 /* maps sorted by key (location); walk them together to find mismatches */
David Pinedod8f83d82015-04-27 16:36:17 -0600703 while ((outputs.size() > 0 && a_it != outputs.end()) || ( inputs.size() && b_it != inputs.end())) {
704 bool a_at_end = outputs.size() == 0 || a_it == outputs.end();
705 bool b_at_end = inputs.size() == 0 || b_it == inputs.end();
Chris Forbes62cc3fc2015-06-10 08:37:27 +1200706 auto a_first = a_at_end ? 0 : a_it->first;
707 auto b_first = b_at_end ? 0 : b_it->first;
David Pinedod8f83d82015-04-27 16:36:17 -0600708
Mike Stroyan19a6de22015-09-10 14:10:25 -0600709 if (b_at_end || ((!a_at_end) && (a_first < b_first))) {
Mike Stroyan830368a2015-09-10 14:12:01 -0600710 if (log_msg(mdd(dev), VK_DBG_REPORT_WARN_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
711 "%s writes to output location %d which is not consumed by %s", producer_name, a_first, consumer_name)) {
712 pass = false;
713 }
Chris Forbes41002452015-04-08 10:19:16 +1200714 a_it++;
715 }
David Pinedod8f83d82015-04-27 16:36:17 -0600716 else if (a_at_end || a_first > b_first) {
Mike Stroyan830368a2015-09-10 14:12:01 -0600717 if (log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC",
718 "%s consumes input location %d which is not written by %s", consumer_name, b_first, producer_name)) {
719 pass = false;
720 }
Chris Forbes41002452015-04-08 10:19:16 +1200721 b_it++;
722 }
723 else {
Chris Forbesf044ec92015-06-05 15:01:08 +1200724 if (types_match(producer, consumer, a_it->second.type_id, b_it->second.type_id, consumer_arrayed_input)) {
Chris Forbes6b2ead62015-04-17 10:13:28 +1200725 /* OK! */
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200726 }
727 else {
728 char producer_type[1024];
729 char consumer_type[1024];
730 describe_type(producer_type, producer, a_it->second.type_id);
731 describe_type(consumer_type, consumer, b_it->second.type_id);
732
Mike Stroyan830368a2015-09-10 14:12:01 -0600733 if (log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
734 "Type mismatch on location %d: '%s' vs '%s'", a_it->first, producer_type, consumer_type)) {
Chris Forbesee99b9b2015-05-25 11:13:22 +1200735 pass = false;
Mike Stroyan830368a2015-09-10 14:12:01 -0600736 }
Chris Forbes3a5e99a2015-04-10 11:41:20 +1200737 }
Chris Forbes41002452015-04-08 10:19:16 +1200738 a_it++;
739 b_it++;
740 }
741 }
Chris Forbesee99b9b2015-05-25 11:13:22 +1200742
743 return pass;
Chris Forbes41002452015-04-08 10:19:16 +1200744}
745
746
Chris Forbes3616b462015-04-08 10:37:20 +1200747enum FORMAT_TYPE {
748 FORMAT_TYPE_UNDEFINED,
749 FORMAT_TYPE_FLOAT, /* UNORM, SNORM, FLOAT, USCALED, SSCALED, SRGB -- anything we consider float in the shader */
750 FORMAT_TYPE_SINT,
751 FORMAT_TYPE_UINT,
752};
753
754
755static unsigned
756get_format_type(VkFormat fmt) {
757 switch (fmt) {
Chia-I Wua3b9a202015-04-17 02:00:54 +0800758 case VK_FORMAT_UNDEFINED:
Chris Forbes3616b462015-04-08 10:37:20 +1200759 return FORMAT_TYPE_UNDEFINED;
Chia-I Wua3b9a202015-04-17 02:00:54 +0800760 case VK_FORMAT_R8_SINT:
761 case VK_FORMAT_R8G8_SINT:
762 case VK_FORMAT_R8G8B8_SINT:
763 case VK_FORMAT_R8G8B8A8_SINT:
764 case VK_FORMAT_R16_SINT:
765 case VK_FORMAT_R16G16_SINT:
766 case VK_FORMAT_R16G16B16_SINT:
767 case VK_FORMAT_R16G16B16A16_SINT:
768 case VK_FORMAT_R32_SINT:
769 case VK_FORMAT_R32G32_SINT:
770 case VK_FORMAT_R32G32B32_SINT:
771 case VK_FORMAT_R32G32B32A32_SINT:
772 case VK_FORMAT_B8G8R8_SINT:
773 case VK_FORMAT_B8G8R8A8_SINT:
774 case VK_FORMAT_R10G10B10A2_SINT:
775 case VK_FORMAT_B10G10R10A2_SINT:
Chris Forbes3616b462015-04-08 10:37:20 +1200776 return FORMAT_TYPE_SINT;
Chia-I Wua3b9a202015-04-17 02:00:54 +0800777 case VK_FORMAT_R8_UINT:
778 case VK_FORMAT_R8G8_UINT:
779 case VK_FORMAT_R8G8B8_UINT:
780 case VK_FORMAT_R8G8B8A8_UINT:
781 case VK_FORMAT_R16_UINT:
782 case VK_FORMAT_R16G16_UINT:
783 case VK_FORMAT_R16G16B16_UINT:
784 case VK_FORMAT_R16G16B16A16_UINT:
785 case VK_FORMAT_R32_UINT:
786 case VK_FORMAT_R32G32_UINT:
787 case VK_FORMAT_R32G32B32_UINT:
788 case VK_FORMAT_R32G32B32A32_UINT:
789 case VK_FORMAT_B8G8R8_UINT:
790 case VK_FORMAT_B8G8R8A8_UINT:
791 case VK_FORMAT_R10G10B10A2_UINT:
792 case VK_FORMAT_B10G10R10A2_UINT:
Chris Forbes3616b462015-04-08 10:37:20 +1200793 return FORMAT_TYPE_UINT;
794 default:
795 return FORMAT_TYPE_FLOAT;
796 }
797}
798
799
Chris Forbes156a1162015-05-04 14:04:06 +1200800/* characterizes a SPIR-V type appearing in an interface to a FF stage,
801 * for comparison to a VkFormat's characterization above. */
802static unsigned
Courtney Goeltzenleuchteree4027d2015-06-28 13:01:17 -0600803get_fundamental_type(shader_module const *src, unsigned type)
Chris Forbes156a1162015-05-04 14:04:06 +1200804{
805 auto type_def_it = src->type_def_index.find(type);
806
807 if (type_def_it == src->type_def_index.end()) {
808 return FORMAT_TYPE_UNDEFINED;
809 }
810
811 unsigned int const *code = (unsigned int const *)&src->words[type_def_it->second];
812 unsigned opcode = code[0] & 0x0ffffu;
813 switch (opcode) {
814 case spv::OpTypeInt:
815 return code[3] ? FORMAT_TYPE_SINT : FORMAT_TYPE_UINT;
816 case spv::OpTypeFloat:
817 return FORMAT_TYPE_FLOAT;
818 case spv::OpTypeVector:
819 return get_fundamental_type(src, code[2]);
820 case spv::OpTypeMatrix:
821 return get_fundamental_type(src, code[2]);
822 case spv::OpTypeArray:
823 return get_fundamental_type(src, code[2]);
824 case spv::OpTypePointer:
825 return get_fundamental_type(src, code[3]);
826 default:
827 return FORMAT_TYPE_UNDEFINED;
828 }
829}
830
831
Chris Forbesee99b9b2015-05-25 11:13:22 +1200832static bool
Chris Forbesb1dee272015-07-03 13:50:24 +1200833validate_vi_consistency(VkDevice dev, VkPipelineVertexInputStateCreateInfo const *vi)
Chris Forbes280ba2c2015-06-12 11:16:41 +1200834{
835 /* walk the binding descriptions, which describe the step rate and stride of each vertex buffer.
836 * each binding should be specified only once.
837 */
838 std::unordered_map<uint32_t, VkVertexInputBindingDescription const *> bindings;
Chris Forbes280ba2c2015-06-12 11:16:41 +1200839 bool pass = true;
840
841 for (unsigned i = 0; i < vi->bindingCount; i++) {
842 auto desc = &vi->pVertexBindingDescriptions[i];
843 auto & binding = bindings[desc->binding];
844 if (binding) {
Mike Stroyan830368a2015-09-10 14:12:01 -0600845 if (log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_INCONSISTENT_VI, "SC",
846 "Duplicate vertex input binding descriptions for binding %d", desc->binding)) {
847 pass = false;
848 }
Chris Forbes280ba2c2015-06-12 11:16:41 +1200849 }
850 else {
851 binding = desc;
852 }
853 }
854
855 return pass;
856}
857
858
859static bool
Chris Forbesb1dee272015-07-03 13:50:24 +1200860validate_vi_against_vs_inputs(VkDevice dev, VkPipelineVertexInputStateCreateInfo const *vi, shader_module const *vs)
Chris Forbes772d03b2015-04-08 10:36:37 +1200861{
862 std::map<uint32_t, interface_var> inputs;
863 /* we collect builtin inputs, but they will never appear in the VI state --
864 * the vs builtin inputs are generated in the pipeline, not sourced from buffers (VertexID, etc)
865 */
866 std::map<uint32_t, interface_var> builtin_inputs;
Chris Forbesee99b9b2015-05-25 11:13:22 +1200867 bool pass = true;
Chris Forbes772d03b2015-04-08 10:36:37 +1200868
Chris Forbesb1dee272015-07-03 13:50:24 +1200869 collect_interface_by_location(dev, vs, spv::StorageClassInput, inputs, builtin_inputs);
Chris Forbes772d03b2015-04-08 10:36:37 +1200870
871 /* Build index by location */
872 std::map<uint32_t, VkVertexInputAttributeDescription const *> attribs;
Chris Forbes7191cd52015-05-25 11:13:24 +1200873 if (vi) {
874 for (unsigned i = 0; i < vi->attributeCount; i++)
875 attribs[vi->pVertexAttributeDescriptions[i].location] = &vi->pVertexAttributeDescriptions[i];
876 }
Chris Forbes772d03b2015-04-08 10:36:37 +1200877
878 auto it_a = attribs.begin();
879 auto it_b = inputs.begin();
880
David Pinedod8f83d82015-04-27 16:36:17 -0600881 while ((attribs.size() > 0 && it_a != attribs.end()) || (inputs.size() > 0 && it_b != inputs.end())) {
882 bool a_at_end = attribs.size() == 0 || it_a == attribs.end();
883 bool b_at_end = inputs.size() == 0 || it_b == inputs.end();
Chris Forbes62cc3fc2015-06-10 08:37:27 +1200884 auto a_first = a_at_end ? 0 : it_a->first;
885 auto b_first = b_at_end ? 0 : it_b->first;
David Pinedod8f83d82015-04-27 16:36:17 -0600886 if (b_at_end || a_first < b_first) {
Mike Stroyan830368a2015-09-10 14:12:01 -0600887 if (log_msg(mdd(dev), VK_DBG_REPORT_WARN_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
888 "Vertex attribute at location %d not consumed by VS", a_first)) {
889 pass = false;
890 }
Chris Forbes772d03b2015-04-08 10:36:37 +1200891 it_a++;
892 }
David Pinedod8f83d82015-04-27 16:36:17 -0600893 else if (a_at_end || b_first < a_first) {
Mike Stroyan830368a2015-09-10 14:12:01 -0600894 if (log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC",
895 "VS consumes input at location %d but not provided", b_first)) {
896 pass = false;
897 }
Chris Forbes772d03b2015-04-08 10:36:37 +1200898 it_b++;
899 }
900 else {
Chris Forbes401784b2015-05-04 14:04:24 +1200901 unsigned attrib_type = get_format_type(it_a->second->format);
902 unsigned input_type = get_fundamental_type(vs, it_b->second.type_id);
903
904 /* type checking */
905 if (attrib_type != FORMAT_TYPE_UNDEFINED && input_type != FORMAT_TYPE_UNDEFINED && attrib_type != input_type) {
906 char vs_type[1024];
907 describe_type(vs_type, vs, it_b->second.type_id);
Mike Stroyan830368a2015-09-10 14:12:01 -0600908 if (log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
Chris Forbesb1dee272015-07-03 13:50:24 +1200909 "Attribute type of `%s` at location %d does not match VS input type of `%s`",
Mike Stroyan830368a2015-09-10 14:12:01 -0600910 string_VkFormat(it_a->second->format), a_first, vs_type)) {
911 pass = false;
912 }
Chris Forbes401784b2015-05-04 14:04:24 +1200913 }
914
Chris Forbes6b2ead62015-04-17 10:13:28 +1200915 /* OK! */
Chris Forbes772d03b2015-04-08 10:36:37 +1200916 it_a++;
917 it_b++;
918 }
919 }
Chris Forbesee99b9b2015-05-25 11:13:22 +1200920
921 return pass;
Chris Forbes772d03b2015-04-08 10:36:37 +1200922}
923
924
Chris Forbesee99b9b2015-05-25 11:13:22 +1200925static bool
Chia-I Wu08accc62015-07-07 11:50:03 +0800926validate_fs_outputs_against_render_pass(VkDevice dev, shader_module const *fs, render_pass const *rp, uint32_t subpass)
Chris Forbes3616b462015-04-08 10:37:20 +1200927{
Chia-I Wu08accc62015-07-07 11:50:03 +0800928 const std::vector<VkFormat> &color_formats = rp->subpass_color_formats[subpass];
Chris Forbes3616b462015-04-08 10:37:20 +1200929 std::map<uint32_t, interface_var> outputs;
930 std::map<uint32_t, interface_var> builtin_outputs;
Chris Forbesee99b9b2015-05-25 11:13:22 +1200931 bool pass = true;
Chris Forbes3616b462015-04-08 10:37:20 +1200932
933 /* TODO: dual source blend index (spv::DecIndex, zero if not provided) */
934
Chris Forbesb1dee272015-07-03 13:50:24 +1200935 collect_interface_by_location(dev, fs, spv::StorageClassOutput, outputs, builtin_outputs);
Chris Forbes3616b462015-04-08 10:37:20 +1200936
937 /* Check for legacy gl_FragColor broadcast: In this case, we should have no user-defined outputs,
938 * and all color attachment should be UNORM/SNORM/FLOAT.
939 */
940 if (builtin_outputs.find(spv::BuiltInFragColor) != builtin_outputs.end()) {
Chris Forbes3616b462015-04-08 10:37:20 +1200941 if (outputs.size()) {
Mike Stroyan830368a2015-09-10 14:12:01 -0600942 if (log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_FS_MIXED_BROADCAST, "SC",
943 "Should not have user-defined FS outputs when using broadcast")) {
944 pass = false;
945 }
Chris Forbes3616b462015-04-08 10:37:20 +1200946 }
947
Chia-I Wu08accc62015-07-07 11:50:03 +0800948 for (unsigned i = 0; i < color_formats.size(); i++) {
949 unsigned attachmentType = get_format_type(color_formats[i]);
Chris Forbes3616b462015-04-08 10:37:20 +1200950 if (attachmentType == FORMAT_TYPE_SINT || attachmentType == FORMAT_TYPE_UINT) {
Mike Stroyan830368a2015-09-10 14:12:01 -0600951 if (log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
952 "CB format should not be SINT or UINT when using broadcast")) {
953 pass = false;
954 }
Chris Forbes3616b462015-04-08 10:37:20 +1200955 }
956 }
957
Chris Forbesee99b9b2015-05-25 11:13:22 +1200958 return pass;
Chris Forbes3616b462015-04-08 10:37:20 +1200959 }
960
961 auto it = outputs.begin();
962 uint32_t attachment = 0;
963
964 /* Walk attachment list and outputs together -- this is a little overpowered since attachments
965 * are currently dense, but the parallel with matching between shader stages is nice.
966 */
967
Chris Forbes9715d4a2015-07-10 09:06:54 +1200968 /* TODO: Figure out compile error with cb->attachmentCount */
Chris Forbesc2cbb0a2015-07-11 11:05:01 +1200969 while ((outputs.size() > 0 && it != outputs.end()) || attachment < color_formats.size()) {
970 if (attachment == color_formats.size() || ( it != outputs.end() && it->first < attachment)) {
Mike Stroyan830368a2015-09-10 14:12:01 -0600971 if (log_msg(mdd(dev), VK_DBG_REPORT_WARN_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
972 "FS writes to output location %d with no matching attachment", it->first)) {
973 pass = false;
974 }
Chris Forbes3616b462015-04-08 10:37:20 +1200975 it++;
976 }
977 else if (it == outputs.end() || it->first > attachment) {
Mike Stroyan830368a2015-09-10 14:12:01 -0600978 if (log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC",
979 "Attachment %d not written by FS", attachment)) {
980 pass = false;
981 }
Chris Forbes3616b462015-04-08 10:37:20 +1200982 attachment++;
983 }
984 else {
Chris Forbes46d31e52015-05-04 14:20:10 +1200985 unsigned output_type = get_fundamental_type(fs, it->second.type_id);
Chia-I Wu08accc62015-07-07 11:50:03 +0800986 unsigned att_type = get_format_type(color_formats[attachment]);
Chris Forbes46d31e52015-05-04 14:20:10 +1200987
988 /* type checking */
989 if (att_type != FORMAT_TYPE_UNDEFINED && output_type != FORMAT_TYPE_UNDEFINED && att_type != output_type) {
990 char fs_type[1024];
991 describe_type(fs_type, fs, it->second.type_id);
Mike Stroyan830368a2015-09-10 14:12:01 -0600992 if (log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
Chris Forbesb1dee272015-07-03 13:50:24 +1200993 "Attachment %d of type `%s` does not match FS output type of `%s`",
Mike Stroyan830368a2015-09-10 14:12:01 -0600994 attachment, string_VkFormat(color_formats[attachment]), fs_type)) {
995 pass = false;
996 }
Chris Forbes46d31e52015-05-04 14:20:10 +1200997 }
998
Chris Forbes6b2ead62015-04-17 10:13:28 +1200999 /* OK! */
Chris Forbes3616b462015-04-08 10:37:20 +12001000 it++;
1001 attachment++;
1002 }
1003 }
Chris Forbesee99b9b2015-05-25 11:13:22 +12001004
1005 return pass;
Chris Forbes3616b462015-04-08 10:37:20 +12001006}
1007
1008
Chris Forbesf044ec92015-06-05 15:01:08 +12001009struct shader_stage_attributes {
1010 char const * const name;
1011 bool arrayed_input;
1012};
1013
1014
1015static shader_stage_attributes
1016shader_stage_attribs[VK_SHADER_STAGE_FRAGMENT + 1] = {
1017 { "vertex shader", false },
1018 { "tessellation control shader", true },
1019 { "tessellation evaluation shader", false },
1020 { "geometry shader", true },
1021 { "fragment shader", false },
1022};
1023
1024
Chris Forbes556c76c2015-08-14 12:04:59 +12001025static VkDescriptorSetLayoutBinding *
1026find_descriptor_binding(std::vector<std::vector<VkDescriptorSetLayoutBinding>*>* layout,
1027 std::pair<unsigned, unsigned> slot)
1028{
1029 if (!layout)
1030 return nullptr;
1031
1032 if (slot.first >= layout->size())
1033 return nullptr;
1034
1035 auto set = (*layout)[slot.first];
1036
1037 if (slot.second >= set->size())
1038 return nullptr;
1039
1040 return &(*set)[slot.second];
1041}
1042
1043
Chris Forbes81874ba2015-06-04 20:23:00 +12001044static bool
Chris Forbes36a372f2015-07-24 13:53:47 +12001045validate_graphics_pipeline(VkDevice dev, VkGraphicsPipelineCreateInfo const *pCreateInfo)
Chris Forbes4175e6f2015-04-08 10:15:35 +12001046{
Chris Forbesf6800b52015-04-08 10:16:45 +12001047 /* We seem to allow pipeline stages to be specified out of order, so collect and identify them
1048 * before trying to do anything more: */
1049
Courtney Goeltzenleuchteree4027d2015-06-28 13:01:17 -06001050 shader_module const *shaders[VK_SHADER_STAGE_FRAGMENT + 1]; /* exclude CS */
Chris Forbesf044ec92015-06-05 15:01:08 +12001051 memset(shaders, 0, sizeof(shaders));
Chia-I Wu08accc62015-07-07 11:50:03 +08001052 render_pass const *rp = 0;
Mark Lobodzinskid5732f32015-06-23 15:11:57 -06001053 VkPipelineVertexInputStateCreateInfo const *vi = 0;
Chris Forbesee99b9b2015-05-25 11:13:22 +12001054 bool pass = true;
Chris Forbesf6800b52015-04-08 10:16:45 +12001055
Chris Forbes7f963832015-05-29 14:55:18 +12001056 loader_platform_thread_lock_mutex(&globalLock);
1057
Tony Barbour92503c62015-07-13 15:28:47 -06001058 for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
Mark Lobodzinskid5732f32015-06-23 15:11:57 -06001059 VkPipelineShaderStageCreateInfo const *pStage = &pCreateInfo->pStages[i];
1060 if (pStage->sType == VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO) {
Chris Forbesf6800b52015-04-08 10:16:45 +12001061
Mark Lobodzinskid5732f32015-06-23 15:11:57 -06001062 if (pStage->stage < VK_SHADER_STAGE_VERTEX || pStage->stage > VK_SHADER_STAGE_FRAGMENT) {
Mike Stroyan830368a2015-09-10 14:12:01 -06001063 if (log_msg(mdd(dev), VK_DBG_REPORT_WARN_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_UNKNOWN_STAGE, "SC",
1064 "Unknown shader stage %d", pStage->stage)) {
1065 pass = false;
1066 }
Chris Forbes6b2ead62015-04-17 10:13:28 +12001067 }
Chris Forbesf044ec92015-06-05 15:01:08 +12001068 else {
Chris Forbes9715d4a2015-07-10 09:06:54 +12001069 struct shader_object *shader = shader_object_map[pStage->shader.handle];
Courtney Goeltzenleuchteree4027d2015-06-28 13:01:17 -06001070 shaders[pStage->stage] = shader->module;
Chris Forbes556c76c2015-08-14 12:04:59 +12001071
1072 /* validate descriptor set layout against what the spirv module actually uses */
Chris Forbes46794b82015-09-18 11:40:23 +12001073 std::map<std::pair<unsigned, unsigned>, interface_var> descriptor_uses;
1074 collect_interface_by_descriptor_slot(dev, shader->module, spv::StorageClassUniform,
1075 descriptor_uses);
Chris Forbes556c76c2015-08-14 12:04:59 +12001076
Chris Forbes46794b82015-09-18 11:40:23 +12001077 auto layout = pCreateInfo->layout.handle ?
1078 pipeline_layout_map[pCreateInfo->layout.handle] : nullptr;
Chris Forbes556c76c2015-08-14 12:04:59 +12001079
Chris Forbes46794b82015-09-18 11:40:23 +12001080 for (auto it = descriptor_uses.begin(); it != descriptor_uses.end(); it++) {
Chris Forbes556c76c2015-08-14 12:04:59 +12001081
Chris Forbes46794b82015-09-18 11:40:23 +12001082 /* find the matching binding */
1083 auto binding = find_descriptor_binding(layout, it->first);
Chris Forbes556c76c2015-08-14 12:04:59 +12001084
Chris Forbes46794b82015-09-18 11:40:23 +12001085 if (binding == nullptr) {
1086 char type_name[1024];
1087 describe_type(type_name, shader->module, it->second.type_id);
Mike Stroyan830368a2015-09-10 14:12:01 -06001088 if (log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0,
Chris Forbes46794b82015-09-18 11:40:23 +12001089 SHADER_CHECKER_MISSING_DESCRIPTOR, "SC",
1090 "Shader uses descriptor slot %u.%u (used as type `%s`) but not declared in pipeline layout",
Mike Stroyan830368a2015-09-10 14:12:01 -06001091 it->first.first, it->first.second, type_name)) {
1092 pass = false;
1093 }
Chris Forbes556c76c2015-08-14 12:04:59 +12001094 }
1095 }
Chris Forbesf044ec92015-06-05 15:01:08 +12001096 }
Chris Forbesf6800b52015-04-08 10:16:45 +12001097 }
Chris Forbesf6800b52015-04-08 10:16:45 +12001098 }
1099
Chia-I Wu08accc62015-07-07 11:50:03 +08001100 if (pCreateInfo->renderPass != VK_NULL_HANDLE)
Chris Forbes9715d4a2015-07-10 09:06:54 +12001101 rp = render_pass_map[pCreateInfo->renderPass.handle];
Chia-I Wu08accc62015-07-07 11:50:03 +08001102
Mark Lobodzinskid5732f32015-06-23 15:11:57 -06001103 vi = pCreateInfo->pVertexInputState;
1104
Chris Forbes280ba2c2015-06-12 11:16:41 +12001105 if (vi) {
Chris Forbesb1dee272015-07-03 13:50:24 +12001106 pass = validate_vi_consistency(dev, vi) && pass;
Chris Forbes280ba2c2015-06-12 11:16:41 +12001107 }
1108
Chris Forbes46794b82015-09-18 11:40:23 +12001109 if (shaders[VK_SHADER_STAGE_VERTEX]) {
Chris Forbesb1dee272015-07-03 13:50:24 +12001110 pass = validate_vi_against_vs_inputs(dev, vi, shaders[VK_SHADER_STAGE_VERTEX]) && pass;
Chris Forbes772d03b2015-04-08 10:36:37 +12001111 }
1112
Chris Forbesf044ec92015-06-05 15:01:08 +12001113 /* TODO: enforce rules about present combinations of shaders */
1114 int producer = VK_SHADER_STAGE_VERTEX;
1115 int consumer = VK_SHADER_STAGE_GEOMETRY;
1116
1117 while (!shaders[producer] && producer != VK_SHADER_STAGE_FRAGMENT) {
1118 producer++;
1119 consumer++;
Chris Forbes41002452015-04-08 10:19:16 +12001120 }
1121
Tony Barbour0102a902015-06-11 15:04:25 -06001122 for (; producer != VK_SHADER_STAGE_FRAGMENT && consumer <= VK_SHADER_STAGE_FRAGMENT; consumer++) {
Chris Forbesf044ec92015-06-05 15:01:08 +12001123 assert(shaders[producer]);
1124 if (shaders[consumer]) {
Chris Forbes46794b82015-09-18 11:40:23 +12001125 pass = validate_interface_between_stages(dev,
1126 shaders[producer], shader_stage_attribs[producer].name,
1127 shaders[consumer], shader_stage_attribs[consumer].name,
1128 shader_stage_attribs[consumer].arrayed_input) && pass;
Chris Forbesf044ec92015-06-05 15:01:08 +12001129
1130 producer = consumer;
1131 }
1132 }
1133
Chris Forbes46794b82015-09-18 11:40:23 +12001134 if (shaders[VK_SHADER_STAGE_FRAGMENT] && rp) {
Chia-I Wu08accc62015-07-07 11:50:03 +08001135 pass = validate_fs_outputs_against_render_pass(dev, shaders[VK_SHADER_STAGE_FRAGMENT], rp, pCreateInfo->subpass) && pass;
Chris Forbes3616b462015-04-08 10:37:20 +12001136 }
1137
Chris Forbes7f963832015-05-29 14:55:18 +12001138 loader_platform_thread_unlock_mutex(&globalLock);
Chris Forbes81874ba2015-06-04 20:23:00 +12001139 return pass;
1140}
1141
Jon Ashburnc669cc62015-07-09 15:02:25 -06001142//TODO handle pipelineCache entry points
Chris Forbes39d8d752015-06-04 20:27:09 +12001143VK_LAYER_EXPORT VkResult VKAPI
Jon Ashburnc669cc62015-07-09 15:02:25 -06001144vkCreateGraphicsPipelines(VkDevice device,
1145 VkPipelineCache pipelineCache,
1146 uint32_t count,
1147 const VkGraphicsPipelineCreateInfo *pCreateInfos,
1148 VkPipeline *pPipelines)
Chris Forbes81874ba2015-06-04 20:23:00 +12001149{
Chris Forbes36a372f2015-07-24 13:53:47 +12001150 bool pass = true;
1151 for (uint32_t i = 0; i < count; i++) {
1152 pass = validate_graphics_pipeline(device, &pCreateInfos[i]) && pass;
1153 }
Chris Forbesee99b9b2015-05-25 11:13:22 +12001154
1155 if (pass) {
1156 /* The driver is allowed to crash if passed junk. Only actually create the
1157 * pipeline if we didn't run into any showstoppers above.
1158 */
Jon Ashburnc669cc62015-07-09 15:02:25 -06001159 return get_dispatch_table(shader_checker_device_table_map, device)->CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pPipelines);
Chris Forbesee99b9b2015-05-25 11:13:22 +12001160 }
1161 else {
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06001162 return VK_ERROR_VALIDATION_FAILED;
Chris Forbesee99b9b2015-05-25 11:13:22 +12001163 }
Chris Forbes4175e6f2015-04-08 10:15:35 +12001164}
1165
1166
Chris Forbesb1dee272015-07-03 13:50:24 +12001167VK_LAYER_EXPORT VkResult VKAPI vkCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice)
1168{
1169 VkLayerDispatchTable *pDeviceTable = get_dispatch_table(shader_checker_device_table_map, *pDevice);
1170 VkResult result = pDeviceTable->CreateDevice(gpu, pCreateInfo, pDevice);
1171 if (result == VK_SUCCESS) {
1172 layer_data *my_instance_data = get_my_data_ptr(get_dispatch_key(gpu), layer_data_map);
1173 VkLayerDispatchTable *pTable = get_dispatch_table(shader_checker_device_table_map, *pDevice);
1174 layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map);
1175 my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice);
1176 }
1177 return result;
1178}
Chris Forbes39d8d752015-06-04 20:27:09 +12001179
Jon Ashburn9a8a2e22015-05-19 16:34:53 -06001180/* hook DextroyDevice to remove tableMap entry */
Mark Lobodzinski2141f652015-09-07 13:59:43 -06001181VK_LAYER_EXPORT void VKAPI vkDestroyDevice(VkDevice device)
Jon Ashburn9a8a2e22015-05-19 16:34:53 -06001182{
Courtney Goeltzenleuchter0daf2282015-06-13 21:22:12 -06001183 dispatch_key key = get_dispatch_key(device);
Chris Forbesb1dee272015-07-03 13:50:24 +12001184 VkLayerDispatchTable *pDisp = get_dispatch_table(shader_checker_device_table_map, device);
Mark Lobodzinski2141f652015-09-07 13:59:43 -06001185 pDisp->DestroyDevice(device);
Chris Forbesb1dee272015-07-03 13:50:24 +12001186 shader_checker_device_table_map.erase(key);
Jon Ashburn9a8a2e22015-05-19 16:34:53 -06001187}
1188
Courtney Goeltzenleuchterbfd2c662015-06-01 14:46:33 -06001189VkResult VKAPI vkCreateInstance(
1190 const VkInstanceCreateInfo* pCreateInfo,
1191 VkInstance* pInstance)
1192{
Chris Forbesb1dee272015-07-03 13:50:24 +12001193 VkLayerInstanceDispatchTable *pTable = get_dispatch_table(shader_checker_instance_table_map,*pInstance);
Courtney Goeltzenleuchterbfd2c662015-06-01 14:46:33 -06001194 VkResult result = pTable->CreateInstance(pCreateInfo, pInstance);
1195
1196 if (result == VK_SUCCESS) {
Chris Forbesb1dee272015-07-03 13:50:24 +12001197 layer_data *my_data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map);
1198 my_data->report_data = debug_report_create_instance(
1199 pTable,
1200 *pInstance,
1201 pCreateInfo->extensionCount,
1202 pCreateInfo->ppEnabledExtensionNames);
Courtney Goeltzenleuchterd02a9642015-06-08 14:58:39 -06001203
Chris Forbesb1dee272015-07-03 13:50:24 +12001204 init_shader_checker(my_data);
Courtney Goeltzenleuchterbfd2c662015-06-01 14:46:33 -06001205 }
1206 return result;
1207}
1208
Jon Ashburn9a8a2e22015-05-19 16:34:53 -06001209/* hook DestroyInstance to remove tableInstanceMap entry */
Mark Lobodzinski2141f652015-09-07 13:59:43 -06001210VK_LAYER_EXPORT void VKAPI vkDestroyInstance(VkInstance instance)
Jon Ashburn9a8a2e22015-05-19 16:34:53 -06001211{
Courtney Goeltzenleuchter0daf2282015-06-13 21:22:12 -06001212 dispatch_key key = get_dispatch_key(instance);
Chris Forbesb1dee272015-07-03 13:50:24 +12001213 VkLayerInstanceDispatchTable *pTable = get_dispatch_table(shader_checker_instance_table_map, instance);
Mark Lobodzinski2141f652015-09-07 13:59:43 -06001214 pTable->DestroyInstance(instance);
Chris Forbesb1dee272015-07-03 13:50:24 +12001215
1216 // Clean up logging callback, if any
1217 layer_data *my_data = get_my_data_ptr(key, layer_data_map);
Courtney Goeltzenleuchtered12e712015-10-05 15:59:58 -06001218 while (my_data->logging_callback.size() > 0) {
1219 VkDbgMsgCallback callback = my_data->logging_callback.back();
1220 layer_destroy_msg_callback(my_data->report_data, callback);
1221 my_data->logging_callback.pop_back();
Chris Forbesb1dee272015-07-03 13:50:24 +12001222 }
1223
1224 layer_debug_report_destroy_instance(my_data->report_data);
1225 layer_data_map.erase(pTable);
1226
1227 shader_checker_instance_table_map.erase(key);
Jon Ashburn9a8a2e22015-05-19 16:34:53 -06001228}
Chris Forbesdb467bd2015-05-25 11:12:59 +12001229
Courtney Goeltzenleuchterbfd2c662015-06-01 14:46:33 -06001230VK_LAYER_EXPORT VkResult VKAPI vkDbgCreateMsgCallback(
Chris Forbesb1dee272015-07-03 13:50:24 +12001231 VkInstance instance,
1232 VkFlags msgFlags,
1233 const PFN_vkDbgMsgCallback pfnMsgCallback,
1234 void* pUserData,
1235 VkDbgMsgCallback* pMsgCallback)
Courtney Goeltzenleuchterbfd2c662015-06-01 14:46:33 -06001236{
Chris Forbesb1dee272015-07-03 13:50:24 +12001237 VkLayerInstanceDispatchTable *pTable = get_dispatch_table(shader_checker_instance_table_map, instance);
1238 VkResult res = pTable->DbgCreateMsgCallback(instance, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
1239 if (VK_SUCCESS == res) {
1240 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
1241 res = layer_create_msg_callback(my_data->report_data, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
1242 }
1243 return res;
Courtney Goeltzenleuchterbfd2c662015-06-01 14:46:33 -06001244}
1245
1246VK_LAYER_EXPORT VkResult VKAPI vkDbgDestroyMsgCallback(
Chris Forbesb1dee272015-07-03 13:50:24 +12001247 VkInstance instance,
1248 VkDbgMsgCallback msgCallback)
Courtney Goeltzenleuchterbfd2c662015-06-01 14:46:33 -06001249{
Chris Forbesb1dee272015-07-03 13:50:24 +12001250 VkLayerInstanceDispatchTable *pTable = get_dispatch_table(shader_checker_instance_table_map, instance);
1251 VkResult res = pTable->DbgDestroyMsgCallback(instance, msgCallback);
1252 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
1253 layer_destroy_msg_callback(my_data->report_data, msgCallback);
1254 return res;
Courtney Goeltzenleuchterbfd2c662015-06-01 14:46:33 -06001255}
1256
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06001257VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI vkGetDeviceProcAddr(VkDevice dev, const char* funcName)
Chris Forbes2778f302015-04-02 13:22:31 +13001258{
Chris Forbesb1dee272015-07-03 13:50:24 +12001259 if (dev == NULL)
Chris Forbes2778f302015-04-02 13:22:31 +13001260 return NULL;
1261
Jon Ashburn8fd08252015-05-28 16:25:02 -06001262 /* loader uses this to force layer initialization; device object is wrapped */
Chris Forbesb1dee272015-07-03 13:50:24 +12001263 if (!strcmp("vkGetDeviceProcAddr", funcName)) {
1264 initDeviceTable(shader_checker_device_table_map, (const VkBaseLayerObject *) dev);
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06001265 return (PFN_vkVoidFunction) vkGetDeviceProcAddr;
Jon Ashburn8fd08252015-05-28 16:25:02 -06001266 }
1267
Chris Forbes2778f302015-04-02 13:22:31 +13001268#define ADD_HOOK(fn) \
Chris Forbesb1dee272015-07-03 13:50:24 +12001269 if (!strncmp(#fn, funcName, sizeof(#fn))) \
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06001270 return (PFN_vkVoidFunction) fn
Chris Forbes2778f302015-04-02 13:22:31 +13001271
Chris Forbesb1dee272015-07-03 13:50:24 +12001272 ADD_HOOK(vkCreateDevice);
Courtney Goeltzenleuchteree4027d2015-06-28 13:01:17 -06001273 ADD_HOOK(vkCreateShaderModule);
Chris Forbes2778f302015-04-02 13:22:31 +13001274 ADD_HOOK(vkCreateShader);
Chia-I Wu08accc62015-07-07 11:50:03 +08001275 ADD_HOOK(vkCreateRenderPass);
Jon Ashburn9a8a2e22015-05-19 16:34:53 -06001276 ADD_HOOK(vkDestroyDevice);
Jon Ashburnc669cc62015-07-09 15:02:25 -06001277 ADD_HOOK(vkCreateGraphicsPipelines);
Chris Forbes2b8493a2015-08-12 15:03:22 +12001278 ADD_HOOK(vkCreateDescriptorSetLayout);
1279 ADD_HOOK(vkCreatePipelineLayout);
Jon Ashburne59f84f2015-05-18 09:08:41 -06001280#undef ADD_HOOK
Chris Forbesb1dee272015-07-03 13:50:24 +12001281
1282 VkLayerDispatchTable* pTable = get_dispatch_table(shader_checker_device_table_map, dev);
1283 {
1284 if (pTable->GetDeviceProcAddr == NULL)
1285 return NULL;
1286 return pTable->GetDeviceProcAddr(dev, funcName);
1287 }
Jon Ashburnf6b33db2015-05-05 14:22:52 -06001288}
1289
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06001290VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI vkGetInstanceProcAddr(VkInstance instance, const char* funcName)
Jon Ashburnf6b33db2015-05-05 14:22:52 -06001291{
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06001292 PFN_vkVoidFunction fptr;
Courtney Goeltzenleuchterbfd2c662015-06-01 14:46:33 -06001293
Chris Forbesb1dee272015-07-03 13:50:24 +12001294 if (instance == NULL)
Jon Ashburnf6b33db2015-05-05 14:22:52 -06001295 return NULL;
1296
Chris Forbesb1dee272015-07-03 13:50:24 +12001297 if (!strcmp("vkGetInstanceProcAddr", funcName)) {
1298 initInstanceTable(shader_checker_instance_table_map, (const VkBaseLayerObject *) instance);
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06001299 return (PFN_vkVoidFunction) vkGetInstanceProcAddr;
Jon Ashburn8fd08252015-05-28 16:25:02 -06001300 }
Jon Ashburnf6b33db2015-05-05 14:22:52 -06001301#define ADD_HOOK(fn) \
Chris Forbesb1dee272015-07-03 13:50:24 +12001302 if (!strncmp(#fn, funcName, sizeof(#fn))) \
Courtney Goeltzenleuchter2d3ba632015-07-12 14:35:22 -06001303 return (PFN_vkVoidFunction) fn
Jon Ashburnf6b33db2015-05-05 14:22:52 -06001304
Courtney Goeltzenleuchterbfd2c662015-06-01 14:46:33 -06001305 ADD_HOOK(vkCreateInstance);
Jon Ashburn9a8a2e22015-05-19 16:34:53 -06001306 ADD_HOOK(vkDestroyInstance);
Courtney Goeltzenleuchter35985f62015-09-14 17:22:16 -06001307 ADD_HOOK(vkEnumerateInstanceExtensionProperties);
1308 ADD_HOOK(vkEnumerateDeviceExtensionProperties);
1309 ADD_HOOK(vkEnumerateInstanceLayerProperties);
1310 ADD_HOOK(vkEnumerateDeviceLayerProperties);
Jon Ashburne59f84f2015-05-18 09:08:41 -06001311#undef ADD_HOOK
Jon Ashburnf6b33db2015-05-05 14:22:52 -06001312
Chris Forbesb1dee272015-07-03 13:50:24 +12001313
1314 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
1315 fptr = debug_report_get_instance_proc_addr(my_data->report_data, funcName);
Courtney Goeltzenleuchterbfd2c662015-06-01 14:46:33 -06001316 if (fptr)
1317 return fptr;
1318
Chris Forbesb1dee272015-07-03 13:50:24 +12001319 {
1320 VkLayerInstanceDispatchTable* pTable = get_dispatch_table(shader_checker_instance_table_map, instance);
1321 if (pTable->GetInstanceProcAddr == NULL)
1322 return NULL;
1323 return pTable->GetInstanceProcAddr(instance, funcName);
1324 }
Chris Forbes2778f302015-04-02 13:22:31 +13001325}