blob: 64feaf0e6db9d6d19259ffccab3f9089bbd3a5fa [file] [log] [blame]
Chris Forbesaab9d112015-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 Forbes67cc36f2015-04-13 12:14:52 +120027#include <map>
Chris Forbesaab9d112015-04-02 13:22:31 +130028#include <unordered_map>
Chris Forbesbb164b62015-04-08 10:19:16 +120029#include <map>
Chris Forbes4396ff52015-04-08 10:11:59 +120030#include <vector>
Courtney Goeltzenleuchter2d034fd2015-06-28 13:01:17 -060031#include <string>
Tobin Ehlisaf14e9f2015-09-01 11:59:36 -060032#include <iostream>
Tobin Ehlis7a51d902015-07-03 10:34:49 -060033#include "vk_loader_platform.h"
Chris Forbesaab9d112015-04-02 13:22:31 +130034#include "vk_dispatch_table_helper.h"
Tobin Ehlis2d1d9702015-07-03 09:42:57 -060035#include "vk_layer.h"
Courtney Goeltzenleuchter8e2f0972015-10-21 17:08:06 -060036#include "vk_layer_utils.h"
Tobin Ehlis56d204a2015-07-03 10:15:26 -060037#include "vk_layer_config.h"
Tobin Ehlis56d204a2015-07-03 10:15:26 -060038#include "vk_layer_table.h"
Chris Forbese20111c2015-07-03 13:50:24 +120039#include "vk_layer_logging.h"
Chris Forbes3317b382015-05-04 14:04:24 +120040#include "vk_enum_string_helper.h"
Chris Forbes5c75afe2015-04-17 10:13:28 +120041#include "shader_checker.h"
Courtney Goeltzenleuchter7abf8e52015-07-07 10:05:05 -060042#include "vk_layer_extension_utils.h"
Chris Forbesaab9d112015-04-02 13:22:31 +130043
GregF3aaa0882015-07-21 17:22:50 -060044#include "spirv/spirv.hpp"
Chris Forbesaab9d112015-04-02 13:22:31 +130045
Chris Forbesaab9d112015-04-02 13:22:31 +130046
Cody Northrop73bb6572015-09-28 15:09:32 -060047struct layer_data {
Chris Forbese20111c2015-07-03 13:50:24 +120048 debug_report_data *report_data;
49 // TODO: put instance data here
Courtney Goeltzenleuchtercc8c8f32015-10-05 15:59:58 -060050 std::vector<VkDbgMsgCallback> logging_callback;
Cody Northrop73bb6572015-09-28 15:09:32 -060051
52 layer_data() :
Courtney Goeltzenleuchtercc8c8f32015-10-05 15:59:58 -060053 report_data(nullptr)
Cody Northrop73bb6572015-09-28 15:09:32 -060054 {};
55};
Chris Forbese20111c2015-07-03 13:50:24 +120056
57static std::unordered_map<void *, layer_data *> layer_data_map;
58static device_table_map shader_checker_device_table_map;
59static instance_table_map shader_checker_instance_table_map;
60
61
62template layer_data *get_my_data_ptr<layer_data>(
63 void *data_key,
64 std::unordered_map<void *, layer_data *> &data_map);
65
Chris Forbes2b7c0002015-07-10 09:06:54 +120066debug_report_data *mdd(void *object)
Chris Forbese20111c2015-07-03 13:50:24 +120067{
68 dispatch_key key = get_dispatch_key(object);
69 layer_data *my_data = get_my_data_ptr(key, layer_data_map);
70#if DISPATCH_MAP_DEBUG
71 fprintf(stderr, "MDD: map: %p, object: %p, key: %p, data: %p\n", &layer_data_map, object, key, my_data);
72#endif
73 return my_data->report_data;
74}
75
76debug_report_data *mid(VkInstance object)
77{
78 dispatch_key key = get_dispatch_key(object);
Tobin Ehlis8354e022015-09-01 11:46:36 -060079 layer_data *my_data = get_my_data_ptr(key, layer_data_map);
Chris Forbese20111c2015-07-03 13:50:24 +120080#if DISPATCH_MAP_DEBUG
81 fprintf(stderr, "MID: map: %p, object: %p, key: %p, data: %p\n", &layer_data_map, object, key, my_data);
82#endif
83 return my_data->report_data;
84}
85
Chris Forbes1b466bd2015-04-15 06:59:41 +120086static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(g_initOnce);
Chris Forbes1ed0f982015-05-29 14:55:18 +120087// TODO : This can be much smarter, using separate locks for separate global data
88static int globalLockInitialized = 0;
89static loader_platform_thread_mutex globalLock;
Chris Forbes4396ff52015-04-08 10:11:59 +120090
Chris Forbes1bb5a2e2015-04-10 11:41:20 +120091
Courtney Goeltzenleuchter6ff93732015-10-07 08:38:30 -060092std::unordered_map<uint64_t, std::vector<VkDescriptorSetLayoutBinding>*> descriptor_set_layout_map;
Chris Forbese0e94992015-08-12 15:03:22 +120093
94VK_LAYER_EXPORT VkResult VKAPI vkCreateDescriptorSetLayout(
95 VkDevice device,
96 const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
97 VkDescriptorSetLayout* pSetLayout)
98{
99 /* stash a copy of the layout bindings */
100 VkLayerDispatchTable *pDeviceTable = get_dispatch_table(shader_checker_device_table_map, device);
101 VkResult result = pDeviceTable->CreateDescriptorSetLayout(device, pCreateInfo, pSetLayout);
102
103 if (VK_SUCCESS == result) {
104 loader_platform_thread_lock_mutex(&globalLock);
105 auto& bindings = descriptor_set_layout_map[pSetLayout->handle];
106 bindings = new std::vector<VkDescriptorSetLayoutBinding>(
107 pCreateInfo->pBinding, pCreateInfo->pBinding + pCreateInfo->count);
108 loader_platform_thread_unlock_mutex(&globalLock);
109 }
110
111 return result;
112}
113
114
Courtney Goeltzenleuchter6ff93732015-10-07 08:38:30 -0600115std::unordered_map<uint64_t, std::vector<std::vector<VkDescriptorSetLayoutBinding>*>*> pipeline_layout_map;
Chris Forbese0e94992015-08-12 15:03:22 +1200116
117VK_LAYER_EXPORT VkResult VKAPI vkCreatePipelineLayout(
118 VkDevice device,
119 const VkPipelineLayoutCreateInfo* pCreateInfo,
120 VkPipelineLayout* pPipelineLayout)
121{
122 VkLayerDispatchTable *pDeviceTable = get_dispatch_table(shader_checker_device_table_map, device);
123 VkResult result = pDeviceTable->CreatePipelineLayout(device, pCreateInfo, pPipelineLayout);
124
125 if (VK_SUCCESS == result) {
126 loader_platform_thread_lock_mutex(&globalLock);
127 auto& layouts = pipeline_layout_map[pPipelineLayout->handle];
128 layouts = new std::vector<std::vector<VkDescriptorSetLayoutBinding>*>();
129 layouts->reserve(pCreateInfo->descriptorSetCount);
130 for (unsigned i = 0; i < pCreateInfo->descriptorSetCount; i++) {
131 layouts->push_back(descriptor_set_layout_map[pCreateInfo->pSetLayouts[i].handle]);
132 }
133 loader_platform_thread_unlock_mutex(&globalLock);
134 }
135
136 return result;
137}
138
139
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200140static void
141build_type_def_index(std::vector<unsigned> const &words, std::unordered_map<unsigned, unsigned> &type_def_index)
142{
143 unsigned int const *code = (unsigned int const *)&words[0];
144 size_t size = words.size();
145
146 unsigned word = 5;
147 while (word < size) {
148 unsigned opcode = code[word] & 0x0ffffu;
149 unsigned oplen = (code[word] & 0xffff0000u) >> 16;
150
151 switch (opcode) {
152 case spv::OpTypeVoid:
153 case spv::OpTypeBool:
154 case spv::OpTypeInt:
155 case spv::OpTypeFloat:
156 case spv::OpTypeVector:
157 case spv::OpTypeMatrix:
GregF3aaa0882015-07-21 17:22:50 -0600158 case spv::OpTypeImage:
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200159 case spv::OpTypeSampler:
GregF3aaa0882015-07-21 17:22:50 -0600160 case spv::OpTypeSampledImage:
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200161 case spv::OpTypeArray:
162 case spv::OpTypeRuntimeArray:
163 case spv::OpTypeStruct:
164 case spv::OpTypeOpaque:
165 case spv::OpTypePointer:
166 case spv::OpTypeFunction:
167 case spv::OpTypeEvent:
168 case spv::OpTypeDeviceEvent:
169 case spv::OpTypeReserveId:
170 case spv::OpTypeQueue:
171 case spv::OpTypePipe:
172 type_def_index[code[word+1]] = word;
173 break;
174
175 default:
176 /* We only care about type definitions */
177 break;
178 }
179
180 word += oplen;
181 }
182}
183
Chris Forbes96b81762015-09-18 11:40:23 +1200184
185bool
186shader_is_spirv(VkShaderModuleCreateInfo const *pCreateInfo)
187{
188 uint32_t *words = (uint32_t *)pCreateInfo->pCode;
Courtney Goeltzenleuchter6ff93732015-10-07 08:38:30 -0600189 size_t sizeInWords = pCreateInfo->codeSize / sizeof(uint32_t);
Chris Forbes96b81762015-09-18 11:40:23 +1200190
191 /* Just validate that the header makes sense. */
192 return sizeInWords >= 5 && words[0] == spv::MagicNumber && words[1] == spv::Version;
193}
194
Courtney Goeltzenleuchter2d034fd2015-06-28 13:01:17 -0600195struct shader_module {
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200196 /* the spirv image itself */
Chris Forbes4396ff52015-04-08 10:11:59 +1200197 std::vector<uint32_t> words;
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200198 /* a mapping of <id> to the first word of its def. this is useful because walking type
199 * trees requires jumping all over the instruction stream.
200 */
201 std::unordered_map<unsigned, unsigned> type_def_index;
Chris Forbes4396ff52015-04-08 10:11:59 +1200202
Chris Forbes96b81762015-09-18 11:40:23 +1200203 shader_module(VkShaderModuleCreateInfo const *pCreateInfo) :
Chris Forbes4453c772015-06-05 15:01:08 +1200204 words((uint32_t *)pCreateInfo->pCode, (uint32_t *)pCreateInfo->pCode + pCreateInfo->codeSize / sizeof(uint32_t)),
Chris Forbes96b81762015-09-18 11:40:23 +1200205 type_def_index() {
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200206
207 build_type_def_index(words, type_def_index);
Chris Forbes4396ff52015-04-08 10:11:59 +1200208 }
209};
210
211
Chris Forbes2b7c0002015-07-10 09:06:54 +1200212static std::unordered_map<uint64_t, shader_module *> shader_module_map;
Courtney Goeltzenleuchter2d034fd2015-06-28 13:01:17 -0600213
214struct shader_object {
215 std::string name;
216 struct shader_module *module;
217
218 shader_object(VkShaderCreateInfo const *pCreateInfo)
219 {
Chris Forbes2b7c0002015-07-10 09:06:54 +1200220 module = shader_module_map[pCreateInfo->module.handle];
Courtney Goeltzenleuchter2d034fd2015-06-28 13:01:17 -0600221 name = pCreateInfo->pName;
222 }
223};
Chris Forbes2b7c0002015-07-10 09:06:54 +1200224static std::unordered_map<uint64_t, shader_object *> shader_object_map;
Chris Forbes4396ff52015-04-08 10:11:59 +1200225
Chia-I Wuc278df82015-07-07 11:50:03 +0800226struct render_pass {
227 std::vector<std::vector<VkFormat>> subpass_color_formats;
228
229 render_pass(VkRenderPassCreateInfo const *pCreateInfo)
230 {
231 uint32_t i;
232
233 subpass_color_formats.reserve(pCreateInfo->subpassCount);
234 for (i = 0; i < pCreateInfo->subpassCount; i++) {
235 const VkSubpassDescription *subpass = &pCreateInfo->pSubpasses[i];
236 std::vector<VkFormat> color_formats;
237 uint32_t j;
238
239 color_formats.reserve(subpass->colorCount);
240 for (j = 0; j < subpass->colorCount; j++) {
Cody Northrop6de6b0b2015-08-04 11:16:41 -0600241 const uint32_t att = subpass->pColorAttachments[j].attachment;
Chia-I Wuc278df82015-07-07 11:50:03 +0800242 const VkFormat format = pCreateInfo->pAttachments[att].format;
243
244 color_formats.push_back(pCreateInfo->pAttachments[att].format);
245 }
246
247 subpass_color_formats.push_back(color_formats);
248 }
249 }
250};
Chris Forbes2b7c0002015-07-10 09:06:54 +1200251static std::unordered_map<uint64_t, render_pass *> render_pass_map;
Chia-I Wuc278df82015-07-07 11:50:03 +0800252
Chris Forbes4396ff52015-04-08 10:11:59 +1200253
Chris Forbes1b466bd2015-04-15 06:59:41 +1200254static void
Chris Forbese20111c2015-07-03 13:50:24 +1200255init_shader_checker(layer_data *my_data)
Chris Forbes1b466bd2015-04-15 06:59:41 +1200256{
Chris Forbese20111c2015-07-03 13:50:24 +1200257 uint32_t report_flags = 0;
258 uint32_t debug_action = 0;
259 FILE *log_output = NULL;
260 const char *option_str;
Courtney Goeltzenleuchtercc8c8f32015-10-05 15:59:58 -0600261 VkDbgMsgCallback callback;
Chris Forbes1b466bd2015-04-15 06:59:41 +1200262 // initialize ShaderChecker options
Chris Forbese20111c2015-07-03 13:50:24 +1200263 report_flags = getLayerOptionFlags("ShaderCheckerReportFlags", 0);
264 getLayerOptionEnum("ShaderCheckerDebugAction", (uint32_t *) &debug_action);
Chris Forbes1b466bd2015-04-15 06:59:41 +1200265
Chris Forbese20111c2015-07-03 13:50:24 +1200266 if (debug_action & VK_DBG_LAYER_ACTION_LOG_MSG)
Chris Forbes1b466bd2015-04-15 06:59:41 +1200267 {
Chris Forbese20111c2015-07-03 13:50:24 +1200268 option_str = getLayerOption("ShaderCheckerLogFilename");
Tobin Ehlisb4b6e7c2015-09-15 09:55:54 -0600269 log_output = getLayerLogOutput(option_str, "ShaderChecker");
Courtney Goeltzenleuchtercc8c8f32015-10-05 15:59:58 -0600270 layer_create_msg_callback(my_data->report_data, report_flags, log_callback, (void *) log_output, &callback);
271 my_data->logging_callback.push_back(callback);
272 }
273
274 if (debug_action & VK_DBG_LAYER_ACTION_DEBUG_OUTPUT) {
275 layer_create_msg_callback(my_data->report_data, report_flags, win32_debug_output_msg, NULL, &callback);
276 my_data->logging_callback.push_back(callback);
Chris Forbese20111c2015-07-03 13:50:24 +1200277 }
278
279 if (!globalLockInitialized)
280 {
281 // TODO/TBD: Need to delete this mutex sometime. How??? One
282 // suggestion is to call this during vkCreateInstance(), and then we
283 // can clean it up during vkDestroyInstance(). However, that requires
284 // that the layer have per-instance locks. We need to come back and
285 // address this soon.
286 loader_platform_thread_create_mutex(&globalLock);
287 globalLockInitialized = 1;
Chris Forbes1b466bd2015-04-15 06:59:41 +1200288 }
289}
290
Courtney Goeltzenleuchter7abf8e52015-07-07 10:05:05 -0600291static const VkLayerProperties shader_checker_global_layers[] = {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600292 {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600293 "ShaderChecker",
Courtney Goeltzenleuchter7abf8e52015-07-07 10:05:05 -0600294 VK_API_VERSION,
295 VK_MAKE_VERSION(0, 1, 0),
296 "Validation layer: ShaderChecker",
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600297 }
Chris Forbesaab9d112015-04-02 13:22:31 +1300298};
299
Courtney Goeltzenleuchter74c4ce92015-09-14 17:22:16 -0600300VK_LAYER_EXPORT VkResult VKAPI vkEnumerateInstanceExtensionProperties(
Courtney Goeltzenleuchter7abf8e52015-07-07 10:05:05 -0600301 const char *pLayerName,
302 uint32_t *pCount,
303 VkExtensionProperties* pProperties)
Chris Forbesaab9d112015-04-02 13:22:31 +1300304{
Courtney Goeltzenleuchter7abf8e52015-07-07 10:05:05 -0600305 /* shader checker does not have any global extensions */
306 return util_GetExtensionProperties(0, NULL, pCount, pProperties);
Chris Forbesaab9d112015-04-02 13:22:31 +1300307}
308
Courtney Goeltzenleuchter74c4ce92015-09-14 17:22:16 -0600309VK_LAYER_EXPORT VkResult VKAPI vkEnumerateInstanceLayerProperties(
Courtney Goeltzenleuchter7abf8e52015-07-07 10:05:05 -0600310 uint32_t *pCount,
311 VkLayerProperties* pProperties)
Tony Barbour426b9052015-06-24 16:06:58 -0600312{
Courtney Goeltzenleuchter7abf8e52015-07-07 10:05:05 -0600313 return util_GetLayerProperties(ARRAY_SIZE(shader_checker_global_layers),
314 shader_checker_global_layers,
315 pCount, pProperties);
Tony Barbour426b9052015-06-24 16:06:58 -0600316}
317
Courtney Goeltzenleuchter74c4ce92015-09-14 17:22:16 -0600318VK_LAYER_EXPORT VkResult VKAPI vkEnumerateDeviceExtensionProperties(
Courtney Goeltzenleuchter7abf8e52015-07-07 10:05:05 -0600319 VkPhysicalDevice physicalDevice,
320 const char* pLayerName,
321 uint32_t* pCount,
322 VkExtensionProperties* pProperties)
Jon Ashburnade3bee2015-06-10 16:43:31 -0600323{
Courtney Goeltzenleuchter7abf8e52015-07-07 10:05:05 -0600324 /* Shader checker does not have any physical device extensions */
325 return util_GetExtensionProperties(0, NULL, pCount, pProperties);
326}
Jon Ashburnade3bee2015-06-10 16:43:31 -0600327
Courtney Goeltzenleuchter74c4ce92015-09-14 17:22:16 -0600328VK_LAYER_EXPORT VkResult VKAPI vkEnumerateDeviceLayerProperties(
Courtney Goeltzenleuchter7abf8e52015-07-07 10:05:05 -0600329 VkPhysicalDevice physicalDevice,
330 uint32_t* pCount,
331 VkLayerProperties* pProperties)
332{
333 /* Shader checker physical device layers are the same as global */
334 return util_GetLayerProperties(ARRAY_SIZE(shader_checker_global_layers),
335 shader_checker_global_layers,
336 pCount, pProperties);
Jon Ashburnade3bee2015-06-10 16:43:31 -0600337}
Chris Forbesaab9d112015-04-02 13:22:31 +1300338
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200339static char const *
340storage_class_name(unsigned sc)
341{
342 switch (sc) {
Cody Northrop812b4612015-04-20 14:09:40 -0600343 case spv::StorageClassInput: return "input";
344 case spv::StorageClassOutput: return "output";
345 case spv::StorageClassUniformConstant: return "const uniform";
346 case spv::StorageClassUniform: return "uniform";
347 case spv::StorageClassWorkgroupLocal: return "workgroup local";
348 case spv::StorageClassWorkgroupGlobal: return "workgroup global";
349 case spv::StorageClassPrivateGlobal: return "private global";
350 case spv::StorageClassFunction: return "function";
351 case spv::StorageClassGeneric: return "generic";
Cody Northrop812b4612015-04-20 14:09:40 -0600352 case spv::StorageClassAtomicCounter: return "atomic counter";
GregF3aaa0882015-07-21 17:22:50 -0600353 case spv::StorageClassImage: return "image";
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200354 default: return "unknown";
355 }
356}
357
358
359/* returns ptr to null terminator */
360static char *
Courtney Goeltzenleuchter2d034fd2015-06-28 13:01:17 -0600361describe_type(char *dst, shader_module const *src, unsigned type)
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200362{
363 auto type_def_it = src->type_def_index.find(type);
364
365 if (type_def_it == src->type_def_index.end()) {
366 return dst + sprintf(dst, "undef");
367 }
368
369 unsigned int const *code = (unsigned int const *)&src->words[type_def_it->second];
370 unsigned opcode = code[0] & 0x0ffffu;
371 switch (opcode) {
372 case spv::OpTypeBool:
373 return dst + sprintf(dst, "bool");
374 case spv::OpTypeInt:
375 return dst + sprintf(dst, "%cint%d", code[3] ? 's' : 'u', code[2]);
376 case spv::OpTypeFloat:
377 return dst + sprintf(dst, "float%d", code[2]);
378 case spv::OpTypeVector:
379 dst += sprintf(dst, "vec%d of ", code[3]);
380 return describe_type(dst, src, code[2]);
381 case spv::OpTypeMatrix:
382 dst += sprintf(dst, "mat%d of ", code[3]);
383 return describe_type(dst, src, code[2]);
384 case spv::OpTypeArray:
385 dst += sprintf(dst, "arr[%d] of ", code[3]);
386 return describe_type(dst, src, code[2]);
387 case spv::OpTypePointer:
388 dst += sprintf(dst, "ptr to %s ", storage_class_name(code[2]));
389 return describe_type(dst, src, code[3]);
390 case spv::OpTypeStruct:
391 {
392 unsigned oplen = code[0] >> 16;
393 dst += sprintf(dst, "struct of (");
Ian Elliottf21f14b2015-04-17 11:05:04 -0600394 for (unsigned i = 2; i < oplen; i++) {
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200395 dst = describe_type(dst, src, code[i]);
396 dst += sprintf(dst, i == oplen-1 ? ")" : ", ");
397 }
398 return dst;
399 }
Chris Forbes118e5e02015-08-14 12:04:39 +1200400 case spv::OpTypeSampler:
401 return dst + sprintf(dst, "sampler");
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200402 default:
403 return dst + sprintf(dst, "oddtype");
404 }
405}
406
407
408static bool
Courtney Goeltzenleuchter2d034fd2015-06-28 13:01:17 -0600409types_match(shader_module const *a, shader_module const *b, unsigned a_type, unsigned b_type, bool b_arrayed)
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200410{
411 auto a_type_def_it = a->type_def_index.find(a_type);
412 auto b_type_def_it = b->type_def_index.find(b_type);
413
414 if (a_type_def_it == a->type_def_index.end()) {
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200415 return false;
416 }
417
418 if (b_type_def_it == b->type_def_index.end()) {
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200419 return false;
420 }
421
422 /* walk two type trees together, and complain about differences */
423 unsigned int const *a_code = (unsigned int const *)&a->words[a_type_def_it->second];
424 unsigned int const *b_code = (unsigned int const *)&b->words[b_type_def_it->second];
425
426 unsigned a_opcode = a_code[0] & 0x0ffffu;
427 unsigned b_opcode = b_code[0] & 0x0ffffu;
428
Chris Forbes0a94a372015-06-05 14:57:05 +1200429 if (b_arrayed && b_opcode == spv::OpTypeArray) {
430 /* we probably just found the extra level of arrayness in b_type: compare the type inside it to a_type */
431 return types_match(a, b, a_type, b_code[2], false);
432 }
433
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200434 if (a_opcode != b_opcode) {
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200435 return false;
436 }
437
438 switch (a_opcode) {
Chris Forbes0a94a372015-06-05 14:57:05 +1200439 /* if b_arrayed and we hit a leaf type, then we can't match -- there's nowhere for the extra OpTypeArray to be! */
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200440 case spv::OpTypeBool:
Chris Forbes0a94a372015-06-05 14:57:05 +1200441 return true && !b_arrayed;
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200442 case spv::OpTypeInt:
443 /* match on width, signedness */
Chris Forbes0a94a372015-06-05 14:57:05 +1200444 return a_code[2] == b_code[2] && a_code[3] == b_code[3] && !b_arrayed;
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200445 case spv::OpTypeFloat:
446 /* match on width */
Chris Forbes0a94a372015-06-05 14:57:05 +1200447 return a_code[2] == b_code[2] && !b_arrayed;
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200448 case spv::OpTypeVector:
449 case spv::OpTypeMatrix:
450 case spv::OpTypeArray:
Chris Forbes0a94a372015-06-05 14:57:05 +1200451 /* match on element type, count. these all have the same layout. we don't get here if
452 * b_arrayed -- that is handled above. */
453 return !b_arrayed && types_match(a, b, a_code[2], b_code[2], b_arrayed) && a_code[3] == b_code[3];
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200454 case spv::OpTypeStruct:
455 /* match on all element types */
456 {
Chris Forbes0a94a372015-06-05 14:57:05 +1200457 if (b_arrayed) {
458 /* for the purposes of matching different levels of arrayness, structs are leaves. */
459 return false;
460 }
461
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200462 unsigned a_len = a_code[0] >> 16;
463 unsigned b_len = b_code[0] >> 16;
464
465 if (a_len != b_len) {
466 return false; /* structs cannot match if member counts differ */
467 }
468
Ian Elliottf21f14b2015-04-17 11:05:04 -0600469 for (unsigned i = 2; i < a_len; i++) {
Chris Forbes0a94a372015-06-05 14:57:05 +1200470 if (!types_match(a, b, a_code[i], b_code[i], b_arrayed)) {
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200471 return false;
472 }
473 }
474
475 return true;
476 }
477 case spv::OpTypePointer:
478 /* match on pointee type. storage class is expected to differ */
Chris Forbes0a94a372015-06-05 14:57:05 +1200479 return types_match(a, b, a_code[3], b_code[3], b_arrayed);
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200480
481 default:
482 /* remaining types are CLisms, or may not appear in the interfaces we
483 * are interested in. Just claim no match.
484 */
485 return false;
486
487 }
488}
489
490
Chris Forbes67cc36f2015-04-13 12:14:52 +1200491static int
492value_or_default(std::unordered_map<unsigned, unsigned> const &map, unsigned id, int def)
493{
494 auto it = map.find(id);
495 if (it == map.end())
496 return def;
497 else
498 return it->second;
499}
500
501
502struct interface_var {
503 uint32_t id;
504 uint32_t type_id;
505 /* TODO: collect the name, too? Isn't required to be present. */
506};
507
508
509static void
Chris Forbese20111c2015-07-03 13:50:24 +1200510collect_interface_by_location(VkDevice dev,
511 shader_module const *src, spv::StorageClass sinterface,
Chris Forbes67cc36f2015-04-13 12:14:52 +1200512 std::map<uint32_t, interface_var> &out,
513 std::map<uint32_t, interface_var> &builtins_out)
514{
515 unsigned int const *code = (unsigned int const *)&src->words[0];
516 size_t size = src->words.size();
517
Chris Forbes67cc36f2015-04-13 12:14:52 +1200518 std::unordered_map<unsigned, unsigned> var_locations;
519 std::unordered_map<unsigned, unsigned> var_builtins;
520
521 unsigned word = 5;
522 while (word < size) {
523
524 unsigned opcode = code[word] & 0x0ffffu;
525 unsigned oplen = (code[word] & 0xffff0000u) >> 16;
526
527 /* We consider two interface models: SSO rendezvous-by-location, and
528 * builtins. Complain about anything that fits neither model.
529 */
530 if (opcode == spv::OpDecorate) {
Cody Northrop812b4612015-04-20 14:09:40 -0600531 if (code[word+2] == spv::DecorationLocation) {
Chris Forbes67cc36f2015-04-13 12:14:52 +1200532 var_locations[code[word+1]] = code[word+3];
533 }
534
Cody Northrop812b4612015-04-20 14:09:40 -0600535 if (code[word+2] == spv::DecorationBuiltIn) {
Chris Forbes67cc36f2015-04-13 12:14:52 +1200536 var_builtins[code[word+1]] = code[word+3];
537 }
538 }
539
540 /* TODO: handle grouped decorations */
541 /* TODO: handle index=1 dual source outputs from FS -- two vars will
542 * have the same location, and we DONT want to clobber. */
543
Ian Elliottf21f14b2015-04-17 11:05:04 -0600544 if (opcode == spv::OpVariable && code[word+3] == sinterface) {
Chris Forbes67cc36f2015-04-13 12:14:52 +1200545 int location = value_or_default(var_locations, code[word+2], -1);
546 int builtin = value_or_default(var_builtins, code[word+2], -1);
547
548 if (location == -1 && builtin == -1) {
549 /* No location defined, and not bound to an API builtin.
550 * The spec says nothing about how this case works (or doesn't)
551 * for interface matching.
552 */
Chris Forbes2b7c0002015-07-10 09:06:54 +1200553 log_msg(mdd(dev), VK_DBG_REPORT_WARN_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_INCONSISTENT_SPIRV, "SC",
Chris Forbese20111c2015-07-03 13:50:24 +1200554 "var %d (type %d) in %s interface has no Location or Builtin decoration",
555 code[word+2], code[word+1], storage_class_name(sinterface));
Chris Forbes67cc36f2015-04-13 12:14:52 +1200556 }
557 else if (location != -1) {
558 /* A user-defined interface variable, with a location. */
559 interface_var v;
560 v.id = code[word+2];
561 v.type_id = code[word+1];
562 out[location] = v;
563 }
564 else {
565 /* A builtin interface variable */
566 interface_var v;
567 v.id = code[word+2];
568 v.type_id = code[word+1];
569 builtins_out[builtin] = v;
570 }
571 }
572
573 word += oplen;
574 }
575}
576
577
Chris Forbes118e5e02015-08-14 12:04:39 +1200578static void
579collect_interface_by_descriptor_slot(VkDevice dev,
580 shader_module const *src, spv::StorageClass sinterface,
581 std::map<std::pair<unsigned, unsigned>, interface_var> &out)
582{
583 unsigned int const *code = (unsigned int const *)&src->words[0];
584 size_t size = src->words.size();
585
586 std::unordered_map<unsigned, unsigned> var_sets;
587 std::unordered_map<unsigned, unsigned> var_bindings;
588
589 unsigned word = 5;
590 while (word < size) {
591
592 unsigned opcode = code[word] & 0x0ffffu;
593 unsigned oplen = (code[word] & 0xffff0000u) >> 16;
594
595 /* We consider two interface models: SSO rendezvous-by-location, and
596 * builtins. Complain about anything that fits neither model.
597 */
598 if (opcode == spv::OpDecorate) {
599 if (code[word+2] == spv::DecorationDescriptorSet) {
600 var_sets[code[word+1]] = code[word+3];
601 }
602
603 if (code[word+2] == spv::DecorationBinding) {
604 var_bindings[code[word+1]] = code[word+3];
605 }
606 }
607
608 if (opcode == spv::OpVariable && (code[word+3] == spv::StorageClassUniform ||
609 code[word+3] == spv::StorageClassUniformConstant)) {
610 unsigned set = value_or_default(var_sets, code[word+2], 0);
611 unsigned binding = value_or_default(var_bindings, code[word+2], 0);
612
613 auto existing_it = out.find(std::make_pair(set, binding));
614 if (existing_it != out.end()) {
615 /* conflict within spv image */
616 log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0,
617 SHADER_CHECKER_INCONSISTENT_SPIRV, "SC",
618 "var %d (type %d) in %s interface in descriptor slot (%u,%u) conflicts with existing definition",
619 code[word+2], code[word+1], storage_class_name(sinterface),
620 existing_it->first.first, existing_it->first.second);
621 }
622
623 interface_var v;
624 v.id = code[word+2];
625 v.type_id = code[word+1];
626 out[std::make_pair(set, binding)] = v;
627 }
628
629 word += oplen;
630 }
631}
632
633
Courtney Goeltzenleuchter2d034fd2015-06-28 13:01:17 -0600634VK_LAYER_EXPORT VkResult VKAPI vkCreateShaderModule(
635 VkDevice device,
636 const VkShaderModuleCreateInfo *pCreateInfo,
637 VkShaderModule *pShaderModule)
Chris Forbesaab9d112015-04-02 13:22:31 +1300638{
Chris Forbes96b81762015-09-18 11:40:23 +1200639 /* Protect the driver from non-SPIRV shaders */
640 if (!shader_is_spirv(pCreateInfo)) {
641 log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE,
642 /* dev */ 0, 0, SHADER_CHECKER_NON_SPIRV_SHADER, "SC",
643 "Shader is not SPIR-V");
644 return VK_ERROR_VALIDATION_FAILED;
645 }
646
Chris Forbese20111c2015-07-03 13:50:24 +1200647 VkResult res = get_dispatch_table(shader_checker_device_table_map, device)->CreateShaderModule(device, pCreateInfo, pShaderModule);
Chris Forbes4396ff52015-04-08 10:11:59 +1200648
Courtney Goeltzenleuchter0b590602015-09-16 12:57:55 -0600649 if (res == VK_SUCCESS) {
650 loader_platform_thread_lock_mutex(&globalLock);
Chris Forbes96b81762015-09-18 11:40:23 +1200651 shader_module_map[pShaderModule->handle] = new shader_module(pCreateInfo);
Courtney Goeltzenleuchter0b590602015-09-16 12:57:55 -0600652 loader_platform_thread_unlock_mutex(&globalLock);
653 }
Chris Forbesaab9d112015-04-02 13:22:31 +1300654 return res;
655}
656
Courtney Goeltzenleuchter2d034fd2015-06-28 13:01:17 -0600657VK_LAYER_EXPORT VkResult VKAPI vkCreateShader(
658 VkDevice device,
659 const VkShaderCreateInfo *pCreateInfo,
660 VkShader *pShader)
661{
Chris Forbese20111c2015-07-03 13:50:24 +1200662 VkResult res = get_dispatch_table(shader_checker_device_table_map, device)->CreateShader(device, pCreateInfo, pShader);
Courtney Goeltzenleuchter2d034fd2015-06-28 13:01:17 -0600663
Courtney Goeltzenleuchter0b590602015-09-16 12:57:55 -0600664 loader_platform_thread_lock_mutex(&globalLock);
Chris Forbes2b7c0002015-07-10 09:06:54 +1200665 shader_object_map[pShader->handle] = new shader_object(pCreateInfo);
Courtney Goeltzenleuchter2d034fd2015-06-28 13:01:17 -0600666 loader_platform_thread_unlock_mutex(&globalLock);
667 return res;
668}
Chris Forbesaab9d112015-04-02 13:22:31 +1300669
Chia-I Wuc278df82015-07-07 11:50:03 +0800670VK_LAYER_EXPORT VkResult VKAPI vkCreateRenderPass(
671 VkDevice device,
672 const VkRenderPassCreateInfo *pCreateInfo,
673 VkRenderPass *pRenderPass)
674{
Chia-I Wuc278df82015-07-07 11:50:03 +0800675 VkResult res = get_dispatch_table(shader_checker_device_table_map, device)->CreateRenderPass(device, pCreateInfo, pRenderPass);
676
Courtney Goeltzenleuchter0b590602015-09-16 12:57:55 -0600677 loader_platform_thread_lock_mutex(&globalLock);
Chris Forbes2b7c0002015-07-10 09:06:54 +1200678 render_pass_map[pRenderPass->handle] = new render_pass(pCreateInfo);
Chia-I Wuc278df82015-07-07 11:50:03 +0800679 loader_platform_thread_unlock_mutex(&globalLock);
680 return res;
681}
682
Chris Forbes5f362d02015-05-25 11:13:22 +1200683static bool
Chris Forbese20111c2015-07-03 13:50:24 +1200684validate_interface_between_stages(VkDevice dev,
685 shader_module const *producer, char const *producer_name,
Courtney Goeltzenleuchter2d034fd2015-06-28 13:01:17 -0600686 shader_module const *consumer, char const *consumer_name,
Chris Forbes4453c772015-06-05 15:01:08 +1200687 bool consumer_arrayed_input)
Chris Forbesbb164b62015-04-08 10:19:16 +1200688{
689 std::map<uint32_t, interface_var> outputs;
690 std::map<uint32_t, interface_var> inputs;
691
692 std::map<uint32_t, interface_var> builtin_outputs;
693 std::map<uint32_t, interface_var> builtin_inputs;
694
Chris Forbes5f362d02015-05-25 11:13:22 +1200695 bool pass = true;
Chris Forbesbb164b62015-04-08 10:19:16 +1200696
Chris Forbese20111c2015-07-03 13:50:24 +1200697 collect_interface_by_location(dev, producer, spv::StorageClassOutput, outputs, builtin_outputs);
698 collect_interface_by_location(dev, consumer, spv::StorageClassInput, inputs, builtin_inputs);
Chris Forbesbb164b62015-04-08 10:19:16 +1200699
700 auto a_it = outputs.begin();
701 auto b_it = inputs.begin();
702
703 /* maps sorted by key (location); walk them together to find mismatches */
David Pinedof5997ab2015-04-27 16:36:17 -0600704 while ((outputs.size() > 0 && a_it != outputs.end()) || ( inputs.size() && b_it != inputs.end())) {
705 bool a_at_end = outputs.size() == 0 || a_it == outputs.end();
706 bool b_at_end = inputs.size() == 0 || b_it == inputs.end();
Chris Forbes4cb97672015-06-10 08:37:27 +1200707 auto a_first = a_at_end ? 0 : a_it->first;
708 auto b_first = b_at_end ? 0 : b_it->first;
David Pinedof5997ab2015-04-27 16:36:17 -0600709
Mike Stroyan223e4d02015-09-10 14:10:25 -0600710 if (b_at_end || ((!a_at_end) && (a_first < b_first))) {
Mike Stroyane3881182015-09-10 14:12:01 -0600711 if (log_msg(mdd(dev), VK_DBG_REPORT_WARN_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
712 "%s writes to output location %d which is not consumed by %s", producer_name, a_first, consumer_name)) {
713 pass = false;
714 }
Chris Forbesbb164b62015-04-08 10:19:16 +1200715 a_it++;
716 }
David Pinedof5997ab2015-04-27 16:36:17 -0600717 else if (a_at_end || a_first > b_first) {
Mike Stroyane3881182015-09-10 14:12:01 -0600718 if (log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC",
719 "%s consumes input location %d which is not written by %s", consumer_name, b_first, producer_name)) {
720 pass = false;
721 }
Chris Forbesbb164b62015-04-08 10:19:16 +1200722 b_it++;
723 }
724 else {
Chris Forbes4453c772015-06-05 15:01:08 +1200725 if (types_match(producer, consumer, a_it->second.type_id, b_it->second.type_id, consumer_arrayed_input)) {
Chris Forbes5c75afe2015-04-17 10:13:28 +1200726 /* OK! */
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200727 }
728 else {
729 char producer_type[1024];
730 char consumer_type[1024];
731 describe_type(producer_type, producer, a_it->second.type_id);
732 describe_type(consumer_type, consumer, b_it->second.type_id);
733
Mike Stroyane3881182015-09-10 14:12:01 -0600734 if (log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
735 "Type mismatch on location %d: '%s' vs '%s'", a_it->first, producer_type, consumer_type)) {
Chris Forbes5f362d02015-05-25 11:13:22 +1200736 pass = false;
Mike Stroyane3881182015-09-10 14:12:01 -0600737 }
Chris Forbes1bb5a2e2015-04-10 11:41:20 +1200738 }
Chris Forbesbb164b62015-04-08 10:19:16 +1200739 a_it++;
740 b_it++;
741 }
742 }
Chris Forbes5f362d02015-05-25 11:13:22 +1200743
744 return pass;
Chris Forbesbb164b62015-04-08 10:19:16 +1200745}
746
747
Chris Forbes9b9f5fe2015-04-08 10:37:20 +1200748enum FORMAT_TYPE {
749 FORMAT_TYPE_UNDEFINED,
750 FORMAT_TYPE_FLOAT, /* UNORM, SNORM, FLOAT, USCALED, SSCALED, SRGB -- anything we consider float in the shader */
751 FORMAT_TYPE_SINT,
752 FORMAT_TYPE_UINT,
753};
754
755
756static unsigned
757get_format_type(VkFormat fmt) {
758 switch (fmt) {
Chia-I Wu6097f3a2015-04-17 02:00:54 +0800759 case VK_FORMAT_UNDEFINED:
Chris Forbes9b9f5fe2015-04-08 10:37:20 +1200760 return FORMAT_TYPE_UNDEFINED;
Chia-I Wu6097f3a2015-04-17 02:00:54 +0800761 case VK_FORMAT_R8_SINT:
762 case VK_FORMAT_R8G8_SINT:
763 case VK_FORMAT_R8G8B8_SINT:
764 case VK_FORMAT_R8G8B8A8_SINT:
765 case VK_FORMAT_R16_SINT:
766 case VK_FORMAT_R16G16_SINT:
767 case VK_FORMAT_R16G16B16_SINT:
768 case VK_FORMAT_R16G16B16A16_SINT:
769 case VK_FORMAT_R32_SINT:
770 case VK_FORMAT_R32G32_SINT:
771 case VK_FORMAT_R32G32B32_SINT:
772 case VK_FORMAT_R32G32B32A32_SINT:
773 case VK_FORMAT_B8G8R8_SINT:
774 case VK_FORMAT_B8G8R8A8_SINT:
775 case VK_FORMAT_R10G10B10A2_SINT:
776 case VK_FORMAT_B10G10R10A2_SINT:
Chris Forbes9b9f5fe2015-04-08 10:37:20 +1200777 return FORMAT_TYPE_SINT;
Chia-I Wu6097f3a2015-04-17 02:00:54 +0800778 case VK_FORMAT_R8_UINT:
779 case VK_FORMAT_R8G8_UINT:
780 case VK_FORMAT_R8G8B8_UINT:
781 case VK_FORMAT_R8G8B8A8_UINT:
782 case VK_FORMAT_R16_UINT:
783 case VK_FORMAT_R16G16_UINT:
784 case VK_FORMAT_R16G16B16_UINT:
785 case VK_FORMAT_R16G16B16A16_UINT:
786 case VK_FORMAT_R32_UINT:
787 case VK_FORMAT_R32G32_UINT:
788 case VK_FORMAT_R32G32B32_UINT:
789 case VK_FORMAT_R32G32B32A32_UINT:
790 case VK_FORMAT_B8G8R8_UINT:
791 case VK_FORMAT_B8G8R8A8_UINT:
792 case VK_FORMAT_R10G10B10A2_UINT:
793 case VK_FORMAT_B10G10R10A2_UINT:
Chris Forbes9b9f5fe2015-04-08 10:37:20 +1200794 return FORMAT_TYPE_UINT;
795 default:
796 return FORMAT_TYPE_FLOAT;
797 }
798}
799
800
Chris Forbes28c50882015-05-04 14:04:06 +1200801/* characterizes a SPIR-V type appearing in an interface to a FF stage,
802 * for comparison to a VkFormat's characterization above. */
803static unsigned
Courtney Goeltzenleuchter2d034fd2015-06-28 13:01:17 -0600804get_fundamental_type(shader_module const *src, unsigned type)
Chris Forbes28c50882015-05-04 14:04:06 +1200805{
806 auto type_def_it = src->type_def_index.find(type);
807
808 if (type_def_it == src->type_def_index.end()) {
809 return FORMAT_TYPE_UNDEFINED;
810 }
811
812 unsigned int const *code = (unsigned int const *)&src->words[type_def_it->second];
813 unsigned opcode = code[0] & 0x0ffffu;
814 switch (opcode) {
815 case spv::OpTypeInt:
816 return code[3] ? FORMAT_TYPE_SINT : FORMAT_TYPE_UINT;
817 case spv::OpTypeFloat:
818 return FORMAT_TYPE_FLOAT;
819 case spv::OpTypeVector:
820 return get_fundamental_type(src, code[2]);
821 case spv::OpTypeMatrix:
822 return get_fundamental_type(src, code[2]);
823 case spv::OpTypeArray:
824 return get_fundamental_type(src, code[2]);
825 case spv::OpTypePointer:
826 return get_fundamental_type(src, code[3]);
827 default:
828 return FORMAT_TYPE_UNDEFINED;
829 }
830}
831
832
Chris Forbes5f362d02015-05-25 11:13:22 +1200833static bool
Chris Forbese20111c2015-07-03 13:50:24 +1200834validate_vi_consistency(VkDevice dev, VkPipelineVertexInputStateCreateInfo const *vi)
Chris Forbes0bf8fe12015-06-12 11:16:41 +1200835{
836 /* walk the binding descriptions, which describe the step rate and stride of each vertex buffer.
837 * each binding should be specified only once.
838 */
839 std::unordered_map<uint32_t, VkVertexInputBindingDescription const *> bindings;
Chris Forbes0bf8fe12015-06-12 11:16:41 +1200840 bool pass = true;
841
842 for (unsigned i = 0; i < vi->bindingCount; i++) {
843 auto desc = &vi->pVertexBindingDescriptions[i];
844 auto & binding = bindings[desc->binding];
845 if (binding) {
Mike Stroyane3881182015-09-10 14:12:01 -0600846 if (log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_INCONSISTENT_VI, "SC",
847 "Duplicate vertex input binding descriptions for binding %d", desc->binding)) {
848 pass = false;
849 }
Chris Forbes0bf8fe12015-06-12 11:16:41 +1200850 }
851 else {
852 binding = desc;
853 }
854 }
855
856 return pass;
857}
858
859
860static bool
Chris Forbese20111c2015-07-03 13:50:24 +1200861validate_vi_against_vs_inputs(VkDevice dev, VkPipelineVertexInputStateCreateInfo const *vi, shader_module const *vs)
Chris Forbesfcd05f12015-04-08 10:36:37 +1200862{
863 std::map<uint32_t, interface_var> inputs;
864 /* we collect builtin inputs, but they will never appear in the VI state --
865 * the vs builtin inputs are generated in the pipeline, not sourced from buffers (VertexID, etc)
866 */
867 std::map<uint32_t, interface_var> builtin_inputs;
Chris Forbes5f362d02015-05-25 11:13:22 +1200868 bool pass = true;
Chris Forbesfcd05f12015-04-08 10:36:37 +1200869
Chris Forbese20111c2015-07-03 13:50:24 +1200870 collect_interface_by_location(dev, vs, spv::StorageClassInput, inputs, builtin_inputs);
Chris Forbesfcd05f12015-04-08 10:36:37 +1200871
872 /* Build index by location */
873 std::map<uint32_t, VkVertexInputAttributeDescription const *> attribs;
Chris Forbes6f2ab982015-05-25 11:13:24 +1200874 if (vi) {
875 for (unsigned i = 0; i < vi->attributeCount; i++)
876 attribs[vi->pVertexAttributeDescriptions[i].location] = &vi->pVertexAttributeDescriptions[i];
877 }
Chris Forbesfcd05f12015-04-08 10:36:37 +1200878
879 auto it_a = attribs.begin();
880 auto it_b = inputs.begin();
881
David Pinedof5997ab2015-04-27 16:36:17 -0600882 while ((attribs.size() > 0 && it_a != attribs.end()) || (inputs.size() > 0 && it_b != inputs.end())) {
883 bool a_at_end = attribs.size() == 0 || it_a == attribs.end();
884 bool b_at_end = inputs.size() == 0 || it_b == inputs.end();
Chris Forbes4cb97672015-06-10 08:37:27 +1200885 auto a_first = a_at_end ? 0 : it_a->first;
886 auto b_first = b_at_end ? 0 : it_b->first;
David Pinedof5997ab2015-04-27 16:36:17 -0600887 if (b_at_end || a_first < b_first) {
Mike Stroyane3881182015-09-10 14:12:01 -0600888 if (log_msg(mdd(dev), VK_DBG_REPORT_WARN_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
889 "Vertex attribute at location %d not consumed by VS", a_first)) {
890 pass = false;
891 }
Chris Forbesfcd05f12015-04-08 10:36:37 +1200892 it_a++;
893 }
David Pinedof5997ab2015-04-27 16:36:17 -0600894 else if (a_at_end || b_first < a_first) {
Mike Stroyane3881182015-09-10 14:12:01 -0600895 if (log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC",
896 "VS consumes input at location %d but not provided", b_first)) {
897 pass = false;
898 }
Chris Forbesfcd05f12015-04-08 10:36:37 +1200899 it_b++;
900 }
901 else {
Chris Forbes3317b382015-05-04 14:04:24 +1200902 unsigned attrib_type = get_format_type(it_a->second->format);
903 unsigned input_type = get_fundamental_type(vs, it_b->second.type_id);
904
905 /* type checking */
906 if (attrib_type != FORMAT_TYPE_UNDEFINED && input_type != FORMAT_TYPE_UNDEFINED && attrib_type != input_type) {
907 char vs_type[1024];
908 describe_type(vs_type, vs, it_b->second.type_id);
Mike Stroyane3881182015-09-10 14:12:01 -0600909 if (log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
Chris Forbese20111c2015-07-03 13:50:24 +1200910 "Attribute type of `%s` at location %d does not match VS input type of `%s`",
Mike Stroyane3881182015-09-10 14:12:01 -0600911 string_VkFormat(it_a->second->format), a_first, vs_type)) {
912 pass = false;
913 }
Chris Forbes3317b382015-05-04 14:04:24 +1200914 }
915
Chris Forbes5c75afe2015-04-17 10:13:28 +1200916 /* OK! */
Chris Forbesfcd05f12015-04-08 10:36:37 +1200917 it_a++;
918 it_b++;
919 }
920 }
Chris Forbes5f362d02015-05-25 11:13:22 +1200921
922 return pass;
Chris Forbesfcd05f12015-04-08 10:36:37 +1200923}
924
925
Chris Forbes5f362d02015-05-25 11:13:22 +1200926static bool
Chia-I Wuc278df82015-07-07 11:50:03 +0800927validate_fs_outputs_against_render_pass(VkDevice dev, shader_module const *fs, render_pass const *rp, uint32_t subpass)
Chris Forbes9b9f5fe2015-04-08 10:37:20 +1200928{
Chia-I Wuc278df82015-07-07 11:50:03 +0800929 const std::vector<VkFormat> &color_formats = rp->subpass_color_formats[subpass];
Chris Forbes9b9f5fe2015-04-08 10:37:20 +1200930 std::map<uint32_t, interface_var> outputs;
931 std::map<uint32_t, interface_var> builtin_outputs;
Chris Forbes5f362d02015-05-25 11:13:22 +1200932 bool pass = true;
Chris Forbes9b9f5fe2015-04-08 10:37:20 +1200933
934 /* TODO: dual source blend index (spv::DecIndex, zero if not provided) */
935
Chris Forbese20111c2015-07-03 13:50:24 +1200936 collect_interface_by_location(dev, fs, spv::StorageClassOutput, outputs, builtin_outputs);
Chris Forbes9b9f5fe2015-04-08 10:37:20 +1200937
938 /* Check for legacy gl_FragColor broadcast: In this case, we should have no user-defined outputs,
939 * and all color attachment should be UNORM/SNORM/FLOAT.
940 */
941 if (builtin_outputs.find(spv::BuiltInFragColor) != builtin_outputs.end()) {
Chris Forbes9b9f5fe2015-04-08 10:37:20 +1200942 if (outputs.size()) {
Mike Stroyane3881182015-09-10 14:12:01 -0600943 if (log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_FS_MIXED_BROADCAST, "SC",
944 "Should not have user-defined FS outputs when using broadcast")) {
945 pass = false;
946 }
Chris Forbes9b9f5fe2015-04-08 10:37:20 +1200947 }
948
Chia-I Wuc278df82015-07-07 11:50:03 +0800949 for (unsigned i = 0; i < color_formats.size(); i++) {
950 unsigned attachmentType = get_format_type(color_formats[i]);
Chris Forbes9b9f5fe2015-04-08 10:37:20 +1200951 if (attachmentType == FORMAT_TYPE_SINT || attachmentType == FORMAT_TYPE_UINT) {
Mike Stroyane3881182015-09-10 14:12:01 -0600952 if (log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
953 "CB format should not be SINT or UINT when using broadcast")) {
954 pass = false;
955 }
Chris Forbes9b9f5fe2015-04-08 10:37:20 +1200956 }
957 }
958
Chris Forbes5f362d02015-05-25 11:13:22 +1200959 return pass;
Chris Forbes9b9f5fe2015-04-08 10:37:20 +1200960 }
961
962 auto it = outputs.begin();
963 uint32_t attachment = 0;
964
965 /* Walk attachment list and outputs together -- this is a little overpowered since attachments
966 * are currently dense, but the parallel with matching between shader stages is nice.
967 */
968
Chris Forbes2b7c0002015-07-10 09:06:54 +1200969 /* TODO: Figure out compile error with cb->attachmentCount */
Chris Forbes768eead2015-07-11 11:05:01 +1200970 while ((outputs.size() > 0 && it != outputs.end()) || attachment < color_formats.size()) {
971 if (attachment == color_formats.size() || ( it != outputs.end() && it->first < attachment)) {
Mike Stroyane3881182015-09-10 14:12:01 -0600972 if (log_msg(mdd(dev), VK_DBG_REPORT_WARN_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
973 "FS writes to output location %d with no matching attachment", it->first)) {
974 pass = false;
975 }
Chris Forbes9b9f5fe2015-04-08 10:37:20 +1200976 it++;
977 }
978 else if (it == outputs.end() || it->first > attachment) {
Mike Stroyane3881182015-09-10 14:12:01 -0600979 if (log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC",
980 "Attachment %d not written by FS", attachment)) {
981 pass = false;
982 }
Chris Forbes9b9f5fe2015-04-08 10:37:20 +1200983 attachment++;
984 }
985 else {
Chris Forbes4b009002015-05-04 14:20:10 +1200986 unsigned output_type = get_fundamental_type(fs, it->second.type_id);
Chia-I Wuc278df82015-07-07 11:50:03 +0800987 unsigned att_type = get_format_type(color_formats[attachment]);
Chris Forbes4b009002015-05-04 14:20:10 +1200988
989 /* type checking */
990 if (att_type != FORMAT_TYPE_UNDEFINED && output_type != FORMAT_TYPE_UNDEFINED && att_type != output_type) {
991 char fs_type[1024];
992 describe_type(fs_type, fs, it->second.type_id);
Mike Stroyane3881182015-09-10 14:12:01 -0600993 if (log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
Chris Forbese20111c2015-07-03 13:50:24 +1200994 "Attachment %d of type `%s` does not match FS output type of `%s`",
Mike Stroyane3881182015-09-10 14:12:01 -0600995 attachment, string_VkFormat(color_formats[attachment]), fs_type)) {
996 pass = false;
997 }
Chris Forbes4b009002015-05-04 14:20:10 +1200998 }
999
Chris Forbes5c75afe2015-04-17 10:13:28 +12001000 /* OK! */
Chris Forbes9b9f5fe2015-04-08 10:37:20 +12001001 it++;
1002 attachment++;
1003 }
1004 }
Chris Forbes5f362d02015-05-25 11:13:22 +12001005
1006 return pass;
Chris Forbes9b9f5fe2015-04-08 10:37:20 +12001007}
1008
1009
Chris Forbes4453c772015-06-05 15:01:08 +12001010struct shader_stage_attributes {
1011 char const * const name;
1012 bool arrayed_input;
1013};
1014
1015
1016static shader_stage_attributes
Courtney Goeltzenleuchter8e2f0972015-10-21 17:08:06 -06001017shader_stage_attribs[] = {
Chris Forbes4453c772015-06-05 15:01:08 +12001018 { "vertex shader", false },
1019 { "tessellation control shader", true },
1020 { "tessellation evaluation shader", false },
1021 { "geometry shader", true },
1022 { "fragment shader", false },
1023};
1024
1025
Chris Forbes76ce7882015-08-14 12:04:59 +12001026static VkDescriptorSetLayoutBinding *
1027find_descriptor_binding(std::vector<std::vector<VkDescriptorSetLayoutBinding>*>* layout,
1028 std::pair<unsigned, unsigned> slot)
1029{
1030 if (!layout)
1031 return nullptr;
1032
1033 if (slot.first >= layout->size())
1034 return nullptr;
1035
1036 auto set = (*layout)[slot.first];
1037
1038 if (slot.second >= set->size())
1039 return nullptr;
1040
1041 return &(*set)[slot.second];
1042}
1043
Courtney Goeltzenleuchter8e2f0972015-10-21 17:08:06 -06001044static uint32_t get_shader_stage_id(VkShaderStageFlagBits stage)
1045{
1046 uint32_t bit_pos = u_ffs(stage);
1047 return bit_pos-1;
1048}
Chris Forbes76ce7882015-08-14 12:04:59 +12001049
Chris Forbesf1060ca2015-06-04 20:23:00 +12001050static bool
Chris Forbesd8bde292015-07-24 13:53:47 +12001051validate_graphics_pipeline(VkDevice dev, VkGraphicsPipelineCreateInfo const *pCreateInfo)
Chris Forbes60540932015-04-08 10:15:35 +12001052{
Chris Forbes8f600932015-04-08 10:16:45 +12001053 /* We seem to allow pipeline stages to be specified out of order, so collect and identify them
1054 * before trying to do anything more: */
Courtney Goeltzenleuchter8e2f0972015-10-21 17:08:06 -06001055 int vertex_stage = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
1056 int geometry_stage = get_shader_stage_id(VK_SHADER_STAGE_GEOMETRY_BIT);
1057 int fragment_stage = get_shader_stage_id(VK_SHADER_STAGE_FRAGMENT_BIT);
Chris Forbes8f600932015-04-08 10:16:45 +12001058
Courtney Goeltzenleuchter5970b252015-10-27 11:32:31 -06001059 shader_module **shaders = new shader_module*[fragment_stage + 1]; /* exclude CS */
1060 memset(shaders, 0, sizeof(shader_module *) * (fragment_stage +1));
Chia-I Wuc278df82015-07-07 11:50:03 +08001061 render_pass const *rp = 0;
Mark Lobodzinski0e0fb5c2015-06-23 15:11:57 -06001062 VkPipelineVertexInputStateCreateInfo const *vi = 0;
Chris Forbes5f362d02015-05-25 11:13:22 +12001063 bool pass = true;
Chris Forbes8f600932015-04-08 10:16:45 +12001064
Chris Forbes1ed0f982015-05-29 14:55:18 +12001065 loader_platform_thread_lock_mutex(&globalLock);
1066
Tony Barbourb2cc40a2015-07-13 15:28:47 -06001067 for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
Mark Lobodzinski0e0fb5c2015-06-23 15:11:57 -06001068 VkPipelineShaderStageCreateInfo const *pStage = &pCreateInfo->pStages[i];
1069 if (pStage->sType == VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO) {
Chris Forbes8f600932015-04-08 10:16:45 +12001070
Courtney Goeltzenleuchter8e2f0972015-10-21 17:08:06 -06001071 if ((pStage->stage & (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
1072 | VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) == 0) {
Mike Stroyane3881182015-09-10 14:12:01 -06001073 if (log_msg(mdd(dev), VK_DBG_REPORT_WARN_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0, SHADER_CHECKER_UNKNOWN_STAGE, "SC",
1074 "Unknown shader stage %d", pStage->stage)) {
1075 pass = false;
1076 }
Chris Forbes5c75afe2015-04-17 10:13:28 +12001077 }
Chris Forbes4453c772015-06-05 15:01:08 +12001078 else {
Chris Forbes2b7c0002015-07-10 09:06:54 +12001079 struct shader_object *shader = shader_object_map[pStage->shader.handle];
Courtney Goeltzenleuchter8e2f0972015-10-21 17:08:06 -06001080 shaders[get_shader_stage_id(pStage->stage)] = shader->module;
Chris Forbes76ce7882015-08-14 12:04:59 +12001081
1082 /* validate descriptor set layout against what the spirv module actually uses */
Chris Forbes96b81762015-09-18 11:40:23 +12001083 std::map<std::pair<unsigned, unsigned>, interface_var> descriptor_uses;
1084 collect_interface_by_descriptor_slot(dev, shader->module, spv::StorageClassUniform,
1085 descriptor_uses);
Chris Forbes76ce7882015-08-14 12:04:59 +12001086
Chris Forbes96b81762015-09-18 11:40:23 +12001087 auto layout = pCreateInfo->layout.handle ?
1088 pipeline_layout_map[pCreateInfo->layout.handle] : nullptr;
Chris Forbes76ce7882015-08-14 12:04:59 +12001089
Chris Forbes96b81762015-09-18 11:40:23 +12001090 for (auto it = descriptor_uses.begin(); it != descriptor_uses.end(); it++) {
Chris Forbes76ce7882015-08-14 12:04:59 +12001091
Chris Forbes96b81762015-09-18 11:40:23 +12001092 /* find the matching binding */
1093 auto binding = find_descriptor_binding(layout, it->first);
Chris Forbes76ce7882015-08-14 12:04:59 +12001094
Chris Forbes96b81762015-09-18 11:40:23 +12001095 if (binding == nullptr) {
1096 char type_name[1024];
1097 describe_type(type_name, shader->module, it->second.type_id);
Mike Stroyane3881182015-09-10 14:12:01 -06001098 if (log_msg(mdd(dev), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, /*dev*/0, 0,
Chris Forbes96b81762015-09-18 11:40:23 +12001099 SHADER_CHECKER_MISSING_DESCRIPTOR, "SC",
1100 "Shader uses descriptor slot %u.%u (used as type `%s`) but not declared in pipeline layout",
Mike Stroyane3881182015-09-10 14:12:01 -06001101 it->first.first, it->first.second, type_name)) {
1102 pass = false;
1103 }
Chris Forbes76ce7882015-08-14 12:04:59 +12001104 }
1105 }
Chris Forbes4453c772015-06-05 15:01:08 +12001106 }
Chris Forbes8f600932015-04-08 10:16:45 +12001107 }
Chris Forbes8f600932015-04-08 10:16:45 +12001108 }
1109
Chia-I Wuc278df82015-07-07 11:50:03 +08001110 if (pCreateInfo->renderPass != VK_NULL_HANDLE)
Chris Forbes2b7c0002015-07-10 09:06:54 +12001111 rp = render_pass_map[pCreateInfo->renderPass.handle];
Chia-I Wuc278df82015-07-07 11:50:03 +08001112
Mark Lobodzinski0e0fb5c2015-06-23 15:11:57 -06001113 vi = pCreateInfo->pVertexInputState;
1114
Chris Forbes0bf8fe12015-06-12 11:16:41 +12001115 if (vi) {
Chris Forbese20111c2015-07-03 13:50:24 +12001116 pass = validate_vi_consistency(dev, vi) && pass;
Chris Forbes0bf8fe12015-06-12 11:16:41 +12001117 }
1118
Courtney Goeltzenleuchter8e2f0972015-10-21 17:08:06 -06001119 if (shaders[vertex_stage]) {
1120 pass = validate_vi_against_vs_inputs(dev, vi, shaders[vertex_stage]) && pass;
Chris Forbesfcd05f12015-04-08 10:36:37 +12001121 }
1122
Chris Forbes4453c772015-06-05 15:01:08 +12001123 /* TODO: enforce rules about present combinations of shaders */
Courtney Goeltzenleuchter8e2f0972015-10-21 17:08:06 -06001124 int producer = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
1125 int consumer = get_shader_stage_id(VK_SHADER_STAGE_GEOMETRY_BIT);
Chris Forbes4453c772015-06-05 15:01:08 +12001126
Courtney Goeltzenleuchter8e2f0972015-10-21 17:08:06 -06001127 while (!shaders[producer] && producer != fragment_stage) {
Chris Forbes4453c772015-06-05 15:01:08 +12001128 producer++;
1129 consumer++;
Chris Forbesbb164b62015-04-08 10:19:16 +12001130 }
1131
Courtney Goeltzenleuchter8e2f0972015-10-21 17:08:06 -06001132 for (; producer != fragment_stage && consumer <= fragment_stage; consumer++) {
Chris Forbes4453c772015-06-05 15:01:08 +12001133 assert(shaders[producer]);
1134 if (shaders[consumer]) {
Chris Forbes96b81762015-09-18 11:40:23 +12001135 pass = validate_interface_between_stages(dev,
1136 shaders[producer], shader_stage_attribs[producer].name,
1137 shaders[consumer], shader_stage_attribs[consumer].name,
1138 shader_stage_attribs[consumer].arrayed_input) && pass;
Chris Forbes4453c772015-06-05 15:01:08 +12001139
1140 producer = consumer;
1141 }
1142 }
1143
Courtney Goeltzenleuchter8e2f0972015-10-21 17:08:06 -06001144 if (shaders[fragment_stage] && rp) {
1145 pass = validate_fs_outputs_against_render_pass(dev, shaders[fragment_stage], rp, pCreateInfo->subpass) && pass;
Chris Forbes9b9f5fe2015-04-08 10:37:20 +12001146 }
1147
Courtney Goeltzenleuchter5970b252015-10-27 11:32:31 -06001148 delete shaders;
1149
Chris Forbes1ed0f982015-05-29 14:55:18 +12001150 loader_platform_thread_unlock_mutex(&globalLock);
Chris Forbesf1060ca2015-06-04 20:23:00 +12001151 return pass;
1152}
1153
Jon Ashburn0d60d272015-07-09 15:02:25 -06001154//TODO handle pipelineCache entry points
Chris Forbesd0f7f7c2015-06-04 20:27:09 +12001155VK_LAYER_EXPORT VkResult VKAPI
Jon Ashburn0d60d272015-07-09 15:02:25 -06001156vkCreateGraphicsPipelines(VkDevice device,
1157 VkPipelineCache pipelineCache,
1158 uint32_t count,
1159 const VkGraphicsPipelineCreateInfo *pCreateInfos,
1160 VkPipeline *pPipelines)
Chris Forbesf1060ca2015-06-04 20:23:00 +12001161{
Chris Forbesd8bde292015-07-24 13:53:47 +12001162 bool pass = true;
1163 for (uint32_t i = 0; i < count; i++) {
1164 pass = validate_graphics_pipeline(device, &pCreateInfos[i]) && pass;
1165 }
Chris Forbes5f362d02015-05-25 11:13:22 +12001166
1167 if (pass) {
1168 /* The driver is allowed to crash if passed junk. Only actually create the
1169 * pipeline if we didn't run into any showstoppers above.
1170 */
Jon Ashburn0d60d272015-07-09 15:02:25 -06001171 return get_dispatch_table(shader_checker_device_table_map, device)->CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pPipelines);
Chris Forbes5f362d02015-05-25 11:13:22 +12001172 }
1173 else {
Courtney Goeltzenleuchterac544f32015-09-14 18:01:17 -06001174 return VK_ERROR_VALIDATION_FAILED;
Chris Forbes5f362d02015-05-25 11:13:22 +12001175 }
Chris Forbes60540932015-04-08 10:15:35 +12001176}
1177
1178
Chris Forbese20111c2015-07-03 13:50:24 +12001179VK_LAYER_EXPORT VkResult VKAPI vkCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice)
1180{
1181 VkLayerDispatchTable *pDeviceTable = get_dispatch_table(shader_checker_device_table_map, *pDevice);
1182 VkResult result = pDeviceTable->CreateDevice(gpu, pCreateInfo, pDevice);
1183 if (result == VK_SUCCESS) {
1184 layer_data *my_instance_data = get_my_data_ptr(get_dispatch_key(gpu), layer_data_map);
1185 VkLayerDispatchTable *pTable = get_dispatch_table(shader_checker_device_table_map, *pDevice);
1186 layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map);
1187 my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice);
1188 }
1189 return result;
1190}
Chris Forbesd0f7f7c2015-06-04 20:27:09 +12001191
Jon Ashburn17f37372015-05-19 16:34:53 -06001192/* hook DextroyDevice to remove tableMap entry */
Mark Lobodzinski67b42b72015-09-07 13:59:43 -06001193VK_LAYER_EXPORT void VKAPI vkDestroyDevice(VkDevice device)
Jon Ashburn17f37372015-05-19 16:34:53 -06001194{
Courtney Goeltzenleuchter9f171942015-06-13 21:22:12 -06001195 dispatch_key key = get_dispatch_key(device);
Chris Forbese20111c2015-07-03 13:50:24 +12001196 VkLayerDispatchTable *pDisp = get_dispatch_table(shader_checker_device_table_map, device);
Mark Lobodzinski67b42b72015-09-07 13:59:43 -06001197 pDisp->DestroyDevice(device);
Chris Forbese20111c2015-07-03 13:50:24 +12001198 shader_checker_device_table_map.erase(key);
Jon Ashburn17f37372015-05-19 16:34:53 -06001199}
1200
Courtney Goeltzenleuchter6c813dc2015-06-01 14:46:33 -06001201VkResult VKAPI vkCreateInstance(
1202 const VkInstanceCreateInfo* pCreateInfo,
1203 VkInstance* pInstance)
1204{
Chris Forbese20111c2015-07-03 13:50:24 +12001205 VkLayerInstanceDispatchTable *pTable = get_dispatch_table(shader_checker_instance_table_map,*pInstance);
Courtney Goeltzenleuchter6c813dc2015-06-01 14:46:33 -06001206 VkResult result = pTable->CreateInstance(pCreateInfo, pInstance);
1207
1208 if (result == VK_SUCCESS) {
Chris Forbese20111c2015-07-03 13:50:24 +12001209 layer_data *my_data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map);
1210 my_data->report_data = debug_report_create_instance(
1211 pTable,
1212 *pInstance,
1213 pCreateInfo->extensionCount,
1214 pCreateInfo->ppEnabledExtensionNames);
Courtney Goeltzenleuchterf4a2eba2015-06-08 14:58:39 -06001215
Chris Forbese20111c2015-07-03 13:50:24 +12001216 init_shader_checker(my_data);
Courtney Goeltzenleuchter6c813dc2015-06-01 14:46:33 -06001217 }
1218 return result;
1219}
1220
Jon Ashburn17f37372015-05-19 16:34:53 -06001221/* hook DestroyInstance to remove tableInstanceMap entry */
Mark Lobodzinski67b42b72015-09-07 13:59:43 -06001222VK_LAYER_EXPORT void VKAPI vkDestroyInstance(VkInstance instance)
Jon Ashburn17f37372015-05-19 16:34:53 -06001223{
Courtney Goeltzenleuchter9f171942015-06-13 21:22:12 -06001224 dispatch_key key = get_dispatch_key(instance);
Chris Forbese20111c2015-07-03 13:50:24 +12001225 VkLayerInstanceDispatchTable *pTable = get_dispatch_table(shader_checker_instance_table_map, instance);
Mark Lobodzinski67b42b72015-09-07 13:59:43 -06001226 pTable->DestroyInstance(instance);
Chris Forbese20111c2015-07-03 13:50:24 +12001227
1228 // Clean up logging callback, if any
1229 layer_data *my_data = get_my_data_ptr(key, layer_data_map);
Courtney Goeltzenleuchtercc8c8f32015-10-05 15:59:58 -06001230 while (my_data->logging_callback.size() > 0) {
1231 VkDbgMsgCallback callback = my_data->logging_callback.back();
1232 layer_destroy_msg_callback(my_data->report_data, callback);
1233 my_data->logging_callback.pop_back();
Chris Forbese20111c2015-07-03 13:50:24 +12001234 }
1235
1236 layer_debug_report_destroy_instance(my_data->report_data);
1237 layer_data_map.erase(pTable);
1238
1239 shader_checker_instance_table_map.erase(key);
Jon Ashburn17f37372015-05-19 16:34:53 -06001240}
Chris Forbesb65ba352015-05-25 11:12:59 +12001241
Courtney Goeltzenleuchter6c813dc2015-06-01 14:46:33 -06001242VK_LAYER_EXPORT VkResult VKAPI vkDbgCreateMsgCallback(
Chris Forbese20111c2015-07-03 13:50:24 +12001243 VkInstance instance,
1244 VkFlags msgFlags,
1245 const PFN_vkDbgMsgCallback pfnMsgCallback,
1246 void* pUserData,
1247 VkDbgMsgCallback* pMsgCallback)
Courtney Goeltzenleuchter6c813dc2015-06-01 14:46:33 -06001248{
Chris Forbese20111c2015-07-03 13:50:24 +12001249 VkLayerInstanceDispatchTable *pTable = get_dispatch_table(shader_checker_instance_table_map, instance);
1250 VkResult res = pTable->DbgCreateMsgCallback(instance, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
1251 if (VK_SUCCESS == res) {
1252 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
1253 res = layer_create_msg_callback(my_data->report_data, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
1254 }
1255 return res;
Courtney Goeltzenleuchter6c813dc2015-06-01 14:46:33 -06001256}
1257
1258VK_LAYER_EXPORT VkResult VKAPI vkDbgDestroyMsgCallback(
Chris Forbese20111c2015-07-03 13:50:24 +12001259 VkInstance instance,
1260 VkDbgMsgCallback msgCallback)
Courtney Goeltzenleuchter6c813dc2015-06-01 14:46:33 -06001261{
Chris Forbese20111c2015-07-03 13:50:24 +12001262 VkLayerInstanceDispatchTable *pTable = get_dispatch_table(shader_checker_instance_table_map, instance);
1263 VkResult res = pTable->DbgDestroyMsgCallback(instance, msgCallback);
1264 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
1265 layer_destroy_msg_callback(my_data->report_data, msgCallback);
1266 return res;
Courtney Goeltzenleuchter6c813dc2015-06-01 14:46:33 -06001267}
1268
Courtney Goeltzenleuchtera4c8c712015-07-12 14:35:22 -06001269VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI vkGetDeviceProcAddr(VkDevice dev, const char* funcName)
Chris Forbesaab9d112015-04-02 13:22:31 +13001270{
Chris Forbese20111c2015-07-03 13:50:24 +12001271 if (dev == NULL)
Chris Forbesaab9d112015-04-02 13:22:31 +13001272 return NULL;
1273
Jon Ashburn4f2575f2015-05-28 16:25:02 -06001274 /* loader uses this to force layer initialization; device object is wrapped */
Chris Forbese20111c2015-07-03 13:50:24 +12001275 if (!strcmp("vkGetDeviceProcAddr", funcName)) {
1276 initDeviceTable(shader_checker_device_table_map, (const VkBaseLayerObject *) dev);
Courtney Goeltzenleuchtera4c8c712015-07-12 14:35:22 -06001277 return (PFN_vkVoidFunction) vkGetDeviceProcAddr;
Jon Ashburn4f2575f2015-05-28 16:25:02 -06001278 }
1279
Chris Forbesaab9d112015-04-02 13:22:31 +13001280#define ADD_HOOK(fn) \
Chris Forbese20111c2015-07-03 13:50:24 +12001281 if (!strncmp(#fn, funcName, sizeof(#fn))) \
Courtney Goeltzenleuchtera4c8c712015-07-12 14:35:22 -06001282 return (PFN_vkVoidFunction) fn
Chris Forbesaab9d112015-04-02 13:22:31 +13001283
Chris Forbese20111c2015-07-03 13:50:24 +12001284 ADD_HOOK(vkCreateDevice);
Courtney Goeltzenleuchter2d034fd2015-06-28 13:01:17 -06001285 ADD_HOOK(vkCreateShaderModule);
Chris Forbesaab9d112015-04-02 13:22:31 +13001286 ADD_HOOK(vkCreateShader);
Chia-I Wuc278df82015-07-07 11:50:03 +08001287 ADD_HOOK(vkCreateRenderPass);
Jon Ashburn17f37372015-05-19 16:34:53 -06001288 ADD_HOOK(vkDestroyDevice);
Jon Ashburn0d60d272015-07-09 15:02:25 -06001289 ADD_HOOK(vkCreateGraphicsPipelines);
Chris Forbese0e94992015-08-12 15:03:22 +12001290 ADD_HOOK(vkCreateDescriptorSetLayout);
1291 ADD_HOOK(vkCreatePipelineLayout);
Jon Ashburn8198fd02015-05-18 09:08:41 -06001292#undef ADD_HOOK
Chris Forbese20111c2015-07-03 13:50:24 +12001293
1294 VkLayerDispatchTable* pTable = get_dispatch_table(shader_checker_device_table_map, dev);
1295 {
1296 if (pTable->GetDeviceProcAddr == NULL)
1297 return NULL;
1298 return pTable->GetDeviceProcAddr(dev, funcName);
1299 }
Jon Ashburn79b78ac2015-05-05 14:22:52 -06001300}
1301
Courtney Goeltzenleuchtera4c8c712015-07-12 14:35:22 -06001302VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI vkGetInstanceProcAddr(VkInstance instance, const char* funcName)
Jon Ashburn79b78ac2015-05-05 14:22:52 -06001303{
Courtney Goeltzenleuchtera4c8c712015-07-12 14:35:22 -06001304 PFN_vkVoidFunction fptr;
Courtney Goeltzenleuchter6c813dc2015-06-01 14:46:33 -06001305
Chris Forbese20111c2015-07-03 13:50:24 +12001306 if (instance == NULL)
Jon Ashburn79b78ac2015-05-05 14:22:52 -06001307 return NULL;
1308
Chris Forbese20111c2015-07-03 13:50:24 +12001309 if (!strcmp("vkGetInstanceProcAddr", funcName)) {
1310 initInstanceTable(shader_checker_instance_table_map, (const VkBaseLayerObject *) instance);
Courtney Goeltzenleuchtera4c8c712015-07-12 14:35:22 -06001311 return (PFN_vkVoidFunction) vkGetInstanceProcAddr;
Jon Ashburn4f2575f2015-05-28 16:25:02 -06001312 }
Jon Ashburn79b78ac2015-05-05 14:22:52 -06001313#define ADD_HOOK(fn) \
Chris Forbese20111c2015-07-03 13:50:24 +12001314 if (!strncmp(#fn, funcName, sizeof(#fn))) \
Courtney Goeltzenleuchtera4c8c712015-07-12 14:35:22 -06001315 return (PFN_vkVoidFunction) fn
Jon Ashburn79b78ac2015-05-05 14:22:52 -06001316
Courtney Goeltzenleuchter6c813dc2015-06-01 14:46:33 -06001317 ADD_HOOK(vkCreateInstance);
Jon Ashburn17f37372015-05-19 16:34:53 -06001318 ADD_HOOK(vkDestroyInstance);
Courtney Goeltzenleuchter74c4ce92015-09-14 17:22:16 -06001319 ADD_HOOK(vkEnumerateInstanceExtensionProperties);
1320 ADD_HOOK(vkEnumerateDeviceExtensionProperties);
1321 ADD_HOOK(vkEnumerateInstanceLayerProperties);
1322 ADD_HOOK(vkEnumerateDeviceLayerProperties);
Jon Ashburn8198fd02015-05-18 09:08:41 -06001323#undef ADD_HOOK
Jon Ashburn79b78ac2015-05-05 14:22:52 -06001324
Chris Forbese20111c2015-07-03 13:50:24 +12001325
1326 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
1327 fptr = debug_report_get_instance_proc_addr(my_data->report_data, funcName);
Courtney Goeltzenleuchter6c813dc2015-06-01 14:46:33 -06001328 if (fptr)
1329 return fptr;
1330
Chris Forbese20111c2015-07-03 13:50:24 +12001331 {
1332 VkLayerInstanceDispatchTable* pTable = get_dispatch_table(shader_checker_instance_table_map, instance);
1333 if (pTable->GetInstanceProcAddr == NULL)
1334 return NULL;
1335 return pTable->GetInstanceProcAddr(instance, funcName);
1336 }
Chris Forbesaab9d112015-04-02 13:22:31 +13001337}