blob: bde0a953a15434c76aa60c052fec38fd8b47d874 [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};
Tony Barbour426b9052015-06-24 16:06:58 -0600218VK_LAYER_EXPORT VkResult VKAPI vkGetGlobalExtensionCount(
219 uint32_t* pCount)
220{
221 *pCount = IMAGE_LAYER_EXT_ARRAY_SIZE;
222 return VK_SUCCESS;
223}
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600224
Tony Barbour426b9052015-06-24 16:06:58 -0600225VK_LAYER_EXPORT VkResult VKAPI vkGetGlobalExtensionProperties(
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600226 uint32_t extensionIndex,
Tony Barbour426b9052015-06-24 16:06:58 -0600227 VkExtensionProperties* pProperties)
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600228{
229 /* This entrypoint is NOT going to init it's own dispatch table since loader calls here early */
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600230
Tony Barbour426b9052015-06-24 16:06:58 -0600231 if (extensionIndex >= IMAGE_LAYER_EXT_ARRAY_SIZE)
232 return VK_ERROR_INVALID_VALUE;
233 memcpy(pProperties, &pcExts[extensionIndex], sizeof(VkExtensionProperties));
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600234
235 return VK_SUCCESS;
236}
237
Tony Barbour426b9052015-06-24 16:06:58 -0600238VK_LAYER_EXPORT VkResult VKAPI vkGetPhysicalDeviceExtensionCount(
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600239 VkPhysicalDevice gpu,
Tony Barbour426b9052015-06-24 16:06:58 -0600240 uint32_t* pCount)
241{
242 *pCount = IMAGE_LAYER_EXT_ARRAY_SIZE;
243 return VK_SUCCESS;
244}
245
246VK_LAYER_EXPORT VkResult VKAPI vkGetPhysicalDeviceExtensionProperties(
247 VkPhysicalDevice gpu,
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600248 uint32_t extensionIndex,
Tony Barbour426b9052015-06-24 16:06:58 -0600249 VkExtensionProperties* pProperties)
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600250{
251 /* This entrypoint is NOT going to init it's own dispatch table since loader calls here early */
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600252
Tony Barbour426b9052015-06-24 16:06:58 -0600253 if (extensionIndex >= IMAGE_LAYER_EXT_ARRAY_SIZE)
254 return VK_ERROR_INVALID_VALUE;
255 memcpy(pProperties, &pcExts[extensionIndex], sizeof(VkExtensionProperties));
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600256
257 return VK_SUCCESS;
258}
259
260VK_LAYER_EXPORT VkResult VKAPI vkCreateImage(VkDevice device, const VkImageCreateInfo* pCreateInfo, VkImage* pImage)
261{
262 if(pCreateInfo->format != VK_FORMAT_UNDEFINED)
263 {
Courtney Goeltzenleuchter07199212015-06-22 16:19:14 -0600264 layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600265 VkFormatProperties properties;
Chris Forbesd7576302015-06-21 22:55:02 +1200266 VkResult result = get_dispatch_table(image_instance_table_map, device_data->physicalDevice)->GetPhysicalDeviceFormatInfo(
267 device_data->physicalDevice, pCreateInfo->format, &properties);
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600268 if(result != VK_SUCCESS)
269 {
270 char const str[] = "vkCreateImage parameter, VkFormat pCreateInfo->format, cannot be validated";
271 log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", str);
272 }
273
274 if((properties.linearTilingFeatures) == 0 && (properties.optimalTilingFeatures == 0))
275 {
276 char const str[] = "vkCreateImage parameter, VkFormat pCreateInfo->format, contains unsupported format";
277 log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", str);
278 }
279 }
280
281 VkResult result = get_dispatch_table(image_device_table_map, device)->CreateImage(device, pCreateInfo, pImage);
282
283 return result;
284}
285
286VK_LAYER_EXPORT VkResult VKAPI vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, VkRenderPass* pRenderPass)
287{
288 for(uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; ++i)
289 {
290 if(pCreateInfo->pColorFormats[i] != VK_FORMAT_UNDEFINED)
291 {
Courtney Goeltzenleuchter07199212015-06-22 16:19:14 -0600292 layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600293 VkFormatProperties properties;
Chris Forbesd7576302015-06-21 22:55:02 +1200294 VkResult result = get_dispatch_table(image_instance_table_map, device_data->physicalDevice)->GetPhysicalDeviceFormatInfo(
295 device_data->physicalDevice, pCreateInfo->pColorFormats[i], &properties);
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600296 if(result != VK_SUCCESS)
297 {
298 std::stringstream ss;
299 ss << "vkCreateRenderPass parameter, VkFormat pCreateInfo->pColorFormats[" << i << "], cannot be validated";
300 log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", ss.str().c_str());
301 continue;
302 }
303
304 if((properties.linearTilingFeatures) == 0 && (properties.optimalTilingFeatures == 0))
305 {
306 std::stringstream ss;
307 ss << "vkCreateRenderPass parameter, VkFormat pCreateInfo->pColorFormats[" << i << "], contains unsupported format";
308 log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", ss.str().c_str());
309 }
310 }
311 }
312
313 for(uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; ++i)
314 {
315 if(!validate_VkImageLayout(pCreateInfo->pColorLayouts[i]))
316 {
317 std::stringstream ss;
318 ss << "vkCreateRenderPass parameter, VkImageLayout pCreateInfo->pColorLayouts[" << i << "], is unrecognized";
319 log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", ss.str().c_str());
320 }
321 }
322
323 for(uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; ++i)
324 {
325 if(!validate_VkAttachmentLoadOp(pCreateInfo->pColorLoadOps[i]))
326 {
327 std::stringstream ss;
328 ss << "vkCreateRenderPass parameter, VkAttachmentLoadOp pCreateInfo->pColorLoadOps[" << i << "], is unrecognized";
329 log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", ss.str().c_str());
330 }
331 }
332
333 for(uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; ++i)
334 {
335 if(!validate_VkAttachmentStoreOp(pCreateInfo->pColorStoreOps[i]))
336 {
337 std::stringstream ss;
338 ss << "vkCreateRenderPass parameter, VkAttachmentStoreOp pCreateInfo->pColorStoreOps[" << i << "], is unrecognized";
339 log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", ss.str().c_str());
340 }
341 }
342
343 for(uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; ++i)
344 {
345 if(!vk_validate_vkclearcolor(&(pCreateInfo->pColorLoadClearValues[i])))
346 {
347 std::stringstream ss;
348 ss << "vkCreateRenderPass parameter, VkClearColor pCreateInfo->pColorLoadClearValues[" << i << "], is invalid";
349 log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", ss.str().c_str());
350 }
351 }
352
353 if(pCreateInfo->depthStencilFormat != VK_FORMAT_UNDEFINED)
354 {
Courtney Goeltzenleuchter07199212015-06-22 16:19:14 -0600355 layer_data *device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600356 VkFormatProperties properties;
Chris Forbesd7576302015-06-21 22:55:02 +1200357 VkResult result = get_dispatch_table(image_instance_table_map, device_data->physicalDevice)->GetPhysicalDeviceFormatInfo(
358 device_data->physicalDevice, pCreateInfo->depthStencilFormat, &properties);
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600359 if(result != VK_SUCCESS)
360 {
361 char const str[] = "vkCreateRenderPass parameter, VkFormat pCreateInfo->depthStencilFormat, cannot be validated";
362 log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", str);
363 }
364
365 if((properties.linearTilingFeatures) == 0 && (properties.optimalTilingFeatures == 0))
366 {
367 char const str[] = "vkCreateRenderPass parameter, VkFormat pCreateInfo->depthStencilFormat, contains unsupported format";
368 log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "IMAGE", str);
369 }
370 }
371
372 VkResult result = get_dispatch_table(image_device_table_map, device)->CreateRenderPass(device, pCreateInfo, pRenderPass);
373
374 return result;
375}
376
377VK_LAYER_EXPORT void* VKAPI vkGetDeviceProcAddr(VkDevice device, const char* funcName)
378{
379 if (device == NULL) {
380 return NULL;
381 }
382
383 /* loader uses this to force layer initialization; device object is wrapped */
384 if (!strcmp(funcName, "vkGetDeviceProcAddr")) {
385 initDeviceTable(image_device_table_map, (const VkBaseLayerObject *) device);
386 return (void*) vkGetDeviceProcAddr;
387 }
388
389 if (!strcmp(funcName, "vkDestroyDevice"))
390 return (void*) vkDestroyDevice;
391 if (!strcmp(funcName, "vkCreateImage"))
392 return (void*) vkCreateImage;
393 if (!strcmp(funcName, "vkCreateRenderPass"))
394 return (void*) vkCreateRenderPass;
Tony Barbour426b9052015-06-24 16:06:58 -0600395 if (!strcmp(funcName, "vkGetGlobalExtensionProperties"))
396 return (void*) vkGetGlobalExtensionProperties;
397 if (!strcmp(funcName, "vkGetGlobalExtensionCount"))
398 return (void*) vkGetGlobalExtensionCount;
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600399
400 {
401 if (get_dispatch_table(image_device_table_map, device)->GetDeviceProcAddr == NULL)
402 return NULL;
403 return get_dispatch_table(image_device_table_map, device)->GetDeviceProcAddr(device, funcName);
404 }
405}
406
407VK_LAYER_EXPORT void* VKAPI vkGetInstanceProcAddr(VkInstance instance, const char* funcName)
408{
409 if (instance == NULL) {
410 return NULL;
411 }
412
413 /* loader uses this to force layer initialization; instance object is wrapped */
414 if (!strcmp(funcName, "vkGetInstanceProcAddr")) {
415 initInstanceTable(image_instance_table_map, (const VkBaseLayerObject *) instance);
416 return (void *) vkGetInstanceProcAddr;
417 }
418
419 if (!strcmp(funcName, "vkCreateInstance"))
420 return (void*) vkCreateInstance;
421 if (!strcmp(funcName, "vkDestroyInstance"))
422 return (void *) vkDestroyInstance;
423 if (!strcmp(funcName, "vkCreateDevice"))
424 return (void*) vkCreateDevice;
Tony Barbour426b9052015-06-24 16:06:58 -0600425 if (!strcmp(funcName, "vkGetPhysicalDeviceExtensionProperties"))
426 return (void*) vkGetPhysicalDeviceExtensionProperties;
427 if (!strcmp(funcName, "vkGetPhysicalDeviceExtensionCount"))
428 return (void*) vkGetPhysicalDeviceExtensionCount;
Jeremy Hayesb707aa52015-06-18 10:12:39 -0600429
430 layer_data *data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
431 void* fptr = debug_report_get_instance_proc_addr(data->report_data, funcName);
432 if(fptr)
433 return fptr;
434
435 {
436 if (get_dispatch_table(image_instance_table_map, instance)->GetInstanceProcAddr == NULL)
437 return NULL;
438 return get_dispatch_table(image_instance_table_map, instance)->GetInstanceProcAddr(instance, funcName);
439 }
440}