blob: b1fc81f67360d3b44b89d3b5e7bec57fb1a241f1 [file] [log] [blame]
Jeremy Hayesb707aa52015-06-18 10:12:39 -06001/*
2 * Vulkan
3 *
4 * Copyright (C) 2014 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
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28
29#include <iostream>
30#include <string>
31#include <sstream>
32#include <unordered_map>
33
34#include "loader_platform.h"
35#include "vkLayer.h"
36#include "layers_config.h"
37#include "vk_enum_validate_helper.h"
38#include "vk_struct_validate_helper.h"
39//The following is #included again to catch certain OS-specific functions being used:
40#include "loader_platform.h"
41
42#include "layers_table.h"
43#include "layer_data.h"
44#include "layer_logging.h"
45
46typedef struct _layer_data {
47 debug_report_data *report_data;
48 VkDbgMsgCallback logging_callback;
Chris Forbesd7576302015-06-21 22:55:02 +120049 VkPhysicalDevice physicalDevice;
Jeremy Hayesb707aa52015-06-18 10:12:39 -060050} layer_data;
51
52static std::unordered_map<void*, layer_data*> layer_data_map;
53static device_table_map image_device_table_map;
54static instance_table_map image_instance_table_map;
55
56// "my device data"
57debug_report_data *mdd(VkObject object)
58{
59 dispatch_key key = get_dispatch_key(object);
60 layer_data *data = get_my_data_ptr(key, layer_data_map);
61#if DISPATCH_MAP_DEBUG
62 fprintf(stderr, "MDD: map: %p, object: %p, key: %p, data: %p\n", &layer_data_map, object, key, data);
63#endif
64 assert(data->report_data != NULL);
65 return data->report_data;
66}
67
68// "my instance data"
69debug_report_data *mid(VkInstance object)
70{
71 dispatch_key key = get_dispatch_key(object);
Courtney Goeltzenleuchter07199212015-06-22 16:19:14 -060072 layer_data *data = get_my_data_ptr(key, layer_data_map);
Jeremy Hayesb707aa52015-06-18 10:12:39 -060073#if DISPATCH_MAP_DEBUG
74 fprintf(stderr, "MID: map: %p, object: %p, key: %p, data: %p\n", &layer_data_map, object, key, data);
75#endif
76 assert(data->report_data != NULL);
77 return data->report_data;
78}
79
80static void InitImage(layer_data *data)
81{
82 uint32_t report_flags = getLayerOptionFlags("ImageReportFlags", 0);
83
84 uint32_t debug_action = 0;
85 getLayerOptionEnum("ImageDebugAction", (uint32_t *) &debug_action);
86 if(debug_action & VK_DBG_LAYER_ACTION_LOG_MSG)
87 {
88 FILE *log_output = NULL;
89 const char* option_str = getLayerOption("ImageLogFilename");
90 if(option_str)
91 {
92 log_output = fopen(option_str, "w");
93 }
94 if(log_output == NULL)
95 {
96 log_output = stdout;
97 }
98
99 layer_create_msg_callback(data->report_data, report_flags, log_callback, (void*)log_output, &data->logging_callback);
100 }
101}
102
103VK_LAYER_EXPORT VkResult VKAPI vkDbgCreateMsgCallback(
104 VkInstance instance,
105 VkFlags msgFlags,
106 const PFN_vkDbgMsgCallback pfnMsgCallback,
107 void* pUserData,
108 VkDbgMsgCallback* pMsgCallback)
109{
110 VkLayerInstanceDispatchTable *pTable = get_dispatch_table(image_instance_table_map, instance);
111 VkResult res = pTable->DbgCreateMsgCallback(instance, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
112 if (res == VK_SUCCESS) {
113 layer_data *data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
114
115 res = layer_create_msg_callback(data->report_data, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
116 }
117 return res;
118}
119
120VK_LAYER_EXPORT VkResult VKAPI vkDbgDestroyMsgCallback(
121 VkInstance instance,
122 VkDbgMsgCallback msgCallback)
123{
124 VkLayerInstanceDispatchTable *pTable = get_dispatch_table(image_instance_table_map, instance);
125 VkResult res = pTable->DbgDestroyMsgCallback(instance, msgCallback);
126
127 layer_data *data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
128 layer_destroy_msg_callback(data->report_data, msgCallback);
129
130 return res;
131}
132
133VK_LAYER_EXPORT VkResult VKAPI vkCreateInstance(const VkInstanceCreateInfo* pCreateInfo, VkInstance* pInstance)
134{
135 VkLayerInstanceDispatchTable *pTable = get_dispatch_table(image_instance_table_map, *pInstance);
136 VkResult result = pTable->CreateInstance(pCreateInfo, pInstance);
137
138 if (result == VK_SUCCESS) {
139 layer_data *data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map);
140 data->report_data = debug_report_create_instance(pTable, *pInstance, pCreateInfo->extensionCount,
141 pCreateInfo->pEnabledExtensions);
142
143 InitImage(data);
144 }
145
146 return result;
147}
148
149VK_LAYER_EXPORT VkResult VKAPI vkDestroyInstance(VkInstance instance)
150{
151 // Grab the key before the instance is destroyed.
152 dispatch_key key = get_dispatch_key(instance);
153 VkLayerInstanceDispatchTable *pTable = get_dispatch_table(image_instance_table_map, instance);
154 VkResult result = pTable->DestroyInstance(instance);
155
156 // Clean up logging callback, if any
157 layer_data *data = get_my_data_ptr(key, layer_data_map);
158 if(data->logging_callback)
159 {
160 layer_destroy_msg_callback(data->report_data, data->logging_callback);
161 }
162
163 layer_debug_report_destroy_instance(mid(instance));
164 layer_data_map.erase(pTable);
165
166 image_instance_table_map.erase(key);
167 assert(image_instance_table_map.size() == 0 && "Should not have any instance mappings hanging around");
168
169 return result;
170}
171
172VK_LAYER_EXPORT VkResult VKAPI vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice)
173{
174 VkLayerInstanceDispatchTable *pTable = get_dispatch_table(image_instance_table_map, physicalDevice);
175 VkResult result = pTable->CreateDevice(physicalDevice, pCreateInfo, pDevice);
176 if(result == VK_SUCCESS)
177 {
178 layer_data *instance_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
179 layer_data *device_data = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map);
180 device_data->report_data = layer_debug_report_create_device(instance_data->report_data, *pDevice);
Chris Forbesd7576302015-06-21 22:55:02 +1200181 device_data->physicalDevice = physicalDevice;
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600182 }
183
184 return result;
185}
186
187VK_LAYER_EXPORT VkResult VKAPI vkDestroyDevice(VkDevice device)
188{
189 layer_debug_report_destroy_device(device);
190
191 dispatch_key key = get_dispatch_key(device);
192#if DISPATCH_MAP_DEBUG
193 fprintf(stderr, "Device: %p, key: %p\n", device, key);
194#endif
195
196 VkResult result = get_dispatch_table(image_device_table_map, device)->DestroyDevice(device);
197 image_device_table_map.erase(key);
198 assert(image_device_table_map.size() == 0 && "Should not have any instance mappings hanging around");
199
200 return result;
201}
202
203#define IMAGE_LAYER_EXT_ARRAY_SIZE 2
204static const VkExtensionProperties pcExts[IMAGE_LAYER_EXT_ARRAY_SIZE] = {
205 {
206 VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES,
207 "Image",
208 0x10,
209 "Sample layer: Image",
210 },
211 {
212 VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES,
213 "Validation",
214 0x10,
215 "Sample layer: Image",
216 }
217};
218
219VK_LAYER_EXPORT VkResult VKAPI vkGetGlobalExtensionInfo(
220 VkExtensionInfoType infoType,
221 uint32_t extensionIndex,
222 size_t* pDataSize,
223 void* pData)
224{
225 /* This entrypoint is NOT going to init it's own dispatch table since loader calls here early */
226 uint32_t *count = NULL;
227
228 if (pDataSize == NULL)
229 {
230 return VK_ERROR_INVALID_POINTER;
231 }
232
233 switch (infoType) {
234 case VK_EXTENSION_INFO_TYPE_COUNT:
235 *pDataSize = sizeof(uint32_t);
236 if (pData == NULL)
237 return VK_SUCCESS;
238 count = (uint32_t *) pData;
239 *count = IMAGE_LAYER_EXT_ARRAY_SIZE;
240 break;
241 case VK_EXTENSION_INFO_TYPE_PROPERTIES:
242 *pDataSize = sizeof(VkExtensionProperties);
243 if (pData == NULL)
244 return VK_SUCCESS;
245 if (extensionIndex >= IMAGE_LAYER_EXT_ARRAY_SIZE)
246 return VK_ERROR_INVALID_VALUE;
247 memcpy((VkExtensionProperties *) pData, &pcExts[extensionIndex], sizeof(VkExtensionProperties));
248 break;
249 default:
250 return VK_ERROR_INVALID_VALUE;
251 };
252
253 return VK_SUCCESS;
254}
255
256VK_LAYER_EXPORT VkResult VKAPI vkGetPhysicalDeviceExtensionInfo(
257 VkPhysicalDevice gpu,
258 VkExtensionInfoType infoType,
259 uint32_t extensionIndex,
260 size_t* pDataSize,
261 void* pData)
262{
263 /* This entrypoint is NOT going to init it's own dispatch table since loader calls here early */
264 uint32_t *count = NULL;
265
266 if (pDataSize == NULL)
267 {
268 return VK_ERROR_INVALID_POINTER;
269 }
270
271 switch (infoType) {
272 case VK_EXTENSION_INFO_TYPE_COUNT:
273 *pDataSize = sizeof(uint32_t);
274 if (pData == NULL)
275 return VK_SUCCESS;
276 count = (uint32_t *) pData;
277 *count = IMAGE_LAYER_EXT_ARRAY_SIZE;
278 break;
279 case VK_EXTENSION_INFO_TYPE_PROPERTIES:
280 *pDataSize = sizeof(VkExtensionProperties);
281 if (pData == NULL)
282 return VK_SUCCESS;
283 if (extensionIndex >= IMAGE_LAYER_EXT_ARRAY_SIZE)
284 return VK_ERROR_INVALID_VALUE;
285 memcpy((VkExtensionProperties *) pData, &pcExts[extensionIndex], sizeof(VkExtensionProperties));
286 break;
287 default:
288 return VK_ERROR_INVALID_VALUE;
289 };
290
291 return VK_SUCCESS;
292}
293
294VK_LAYER_EXPORT VkResult VKAPI vkCreateImage(VkDevice device, const VkImageCreateInfo* pCreateInfo, VkImage* pImage)
295{
296 if(pCreateInfo->format != VK_FORMAT_UNDEFINED)
297 {
Courtney Goeltzenleuchter07199212015-06-22 16:19:14 -0600298 layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600299 VkFormatProperties properties;
Chris Forbesd7576302015-06-21 22:55:02 +1200300 VkResult result = get_dispatch_table(image_instance_table_map, device_data->physicalDevice)->GetPhysicalDeviceFormatInfo(
301 device_data->physicalDevice, pCreateInfo->format, &properties);
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600302 if(result != VK_SUCCESS)
303 {
304 char const str[] = "vkCreateImage parameter, VkFormat pCreateInfo->format, cannot be validated";
305 log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", str);
306 }
307
308 if((properties.linearTilingFeatures) == 0 && (properties.optimalTilingFeatures == 0))
309 {
310 char const str[] = "vkCreateImage parameter, VkFormat pCreateInfo->format, contains unsupported format";
311 log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", str);
312 }
313 }
314
315 VkResult result = get_dispatch_table(image_device_table_map, device)->CreateImage(device, pCreateInfo, pImage);
316
317 return result;
318}
319
320VK_LAYER_EXPORT VkResult VKAPI vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, VkRenderPass* pRenderPass)
321{
322 for(uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; ++i)
323 {
324 if(pCreateInfo->pColorFormats[i] != VK_FORMAT_UNDEFINED)
325 {
Courtney Goeltzenleuchter07199212015-06-22 16:19:14 -0600326 layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600327 VkFormatProperties properties;
Chris Forbesd7576302015-06-21 22:55:02 +1200328 VkResult result = get_dispatch_table(image_instance_table_map, device_data->physicalDevice)->GetPhysicalDeviceFormatInfo(
329 device_data->physicalDevice, pCreateInfo->pColorFormats[i], &properties);
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600330 if(result != VK_SUCCESS)
331 {
332 std::stringstream ss;
333 ss << "vkCreateRenderPass parameter, VkFormat pCreateInfo->pColorFormats[" << i << "], cannot be validated";
334 log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", ss.str().c_str());
335 continue;
336 }
337
338 if((properties.linearTilingFeatures) == 0 && (properties.optimalTilingFeatures == 0))
339 {
340 std::stringstream ss;
341 ss << "vkCreateRenderPass parameter, VkFormat pCreateInfo->pColorFormats[" << i << "], contains unsupported format";
342 log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", ss.str().c_str());
343 }
344 }
345 }
346
347 for(uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; ++i)
348 {
349 if(!validate_VkImageLayout(pCreateInfo->pColorLayouts[i]))
350 {
351 std::stringstream ss;
352 ss << "vkCreateRenderPass parameter, VkImageLayout pCreateInfo->pColorLayouts[" << i << "], is unrecognized";
353 log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", ss.str().c_str());
354 }
355 }
356
357 for(uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; ++i)
358 {
359 if(!validate_VkAttachmentLoadOp(pCreateInfo->pColorLoadOps[i]))
360 {
361 std::stringstream ss;
362 ss << "vkCreateRenderPass parameter, VkAttachmentLoadOp pCreateInfo->pColorLoadOps[" << i << "], is unrecognized";
363 log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", ss.str().c_str());
364 }
365 }
366
367 for(uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; ++i)
368 {
369 if(!validate_VkAttachmentStoreOp(pCreateInfo->pColorStoreOps[i]))
370 {
371 std::stringstream ss;
372 ss << "vkCreateRenderPass parameter, VkAttachmentStoreOp pCreateInfo->pColorStoreOps[" << i << "], is unrecognized";
373 log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", ss.str().c_str());
374 }
375 }
376
377 for(uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; ++i)
378 {
379 if(!vk_validate_vkclearcolor(&(pCreateInfo->pColorLoadClearValues[i])))
380 {
381 std::stringstream ss;
382 ss << "vkCreateRenderPass parameter, VkClearColor pCreateInfo->pColorLoadClearValues[" << i << "], is invalid";
383 log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", ss.str().c_str());
384 }
385 }
386
387 if(pCreateInfo->depthStencilFormat != VK_FORMAT_UNDEFINED)
388 {
Courtney Goeltzenleuchter07199212015-06-22 16:19:14 -0600389 layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600390 VkFormatProperties properties;
Chris Forbesd7576302015-06-21 22:55:02 +1200391 VkResult result = get_dispatch_table(image_instance_table_map, device_data->physicalDevice)->GetPhysicalDeviceFormatInfo(
392 device_data->physicalDevice, pCreateInfo->depthStencilFormat, &properties);
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600393 if(result != VK_SUCCESS)
394 {
395 char const str[] = "vkCreateRenderPass parameter, VkFormat pCreateInfo->depthStencilFormat, cannot be validated";
396 log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", str);
397 }
398
399 if((properties.linearTilingFeatures) == 0 && (properties.optimalTilingFeatures == 0))
400 {
401 char const str[] = "vkCreateRenderPass parameter, VkFormat pCreateInfo->depthStencilFormat, contains unsupported format";
402 log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", str);
403 }
404 }
405
406 VkResult result = get_dispatch_table(image_device_table_map, device)->CreateRenderPass(device, pCreateInfo, pRenderPass);
407
408 return result;
409}
410
411VK_LAYER_EXPORT void* VKAPI vkGetDeviceProcAddr(VkDevice device, const char* funcName)
412{
413 if (device == NULL) {
414 return NULL;
415 }
416
417 /* loader uses this to force layer initialization; device object is wrapped */
418 if (!strcmp(funcName, "vkGetDeviceProcAddr")) {
419 initDeviceTable(image_device_table_map, (const VkBaseLayerObject *) device);
420 return (void*) vkGetDeviceProcAddr;
421 }
422
423 if (!strcmp(funcName, "vkDestroyDevice"))
424 return (void*) vkDestroyDevice;
425 if (!strcmp(funcName, "vkCreateImage"))
426 return (void*) vkCreateImage;
427 if (!strcmp(funcName, "vkCreateRenderPass"))
428 return (void*) vkCreateRenderPass;
429
430 {
431 if (get_dispatch_table(image_device_table_map, device)->GetDeviceProcAddr == NULL)
432 return NULL;
433 return get_dispatch_table(image_device_table_map, device)->GetDeviceProcAddr(device, funcName);
434 }
435}
436
437VK_LAYER_EXPORT void* VKAPI vkGetInstanceProcAddr(VkInstance instance, const char* funcName)
438{
439 if (instance == NULL) {
440 return NULL;
441 }
442
443 /* loader uses this to force layer initialization; instance object is wrapped */
444 if (!strcmp(funcName, "vkGetInstanceProcAddr")) {
445 initInstanceTable(image_instance_table_map, (const VkBaseLayerObject *) instance);
446 return (void *) vkGetInstanceProcAddr;
447 }
448
449 if (!strcmp(funcName, "vkCreateInstance"))
450 return (void*) vkCreateInstance;
451 if (!strcmp(funcName, "vkDestroyInstance"))
452 return (void *) vkDestroyInstance;
453 if (!strcmp(funcName, "vkCreateDevice"))
454 return (void*) vkCreateDevice;
455 if (!strcmp(funcName, "vkGetGlobalExtensionInfo"))
456 return (void*) vkGetGlobalExtensionInfo;
457 if (!strcmp(funcName, "vkGetPhysicalDeviceExtensionInfo"))
458 return (void*) vkGetPhysicalDeviceExtensionInfo;
459
460 layer_data *data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
461 void* fptr = debug_report_get_instance_proc_addr(data->report_data, funcName);
462 if(fptr)
463 return fptr;
464
465 {
466 if (get_dispatch_table(image_instance_table_map, instance)->GetInstanceProcAddr == NULL)
467 return NULL;
468 return get_dispatch_table(image_instance_table_map, instance)->GetInstanceProcAddr(instance, funcName);
469 }
470}