blob: b110bbf077baaf5ec3b3e89148a61c6fa4fb0b2c [file] [log] [blame]
Mike Stroyan845bdc42015-11-02 15:30:20 -07001/*
2 * Vulkan
3 *
4 * Copyright (C) 2015 Valve, Inc.
5 * Copyright (C) 2016 Google, Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 */
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unordered_map>
29#include <list>
Mike Stroyan845bdc42015-11-02 15:30:20 -070030
Dustin Graves899960f2016-02-05 15:53:12 -070031#include "vk_loader_platform.h"
Mike Stroyan3409fcd2016-01-29 15:11:28 -070032#include "vulkan/vk_layer.h"
Mike Stroyan845bdc42015-11-02 15:30:20 -070033#include "vk_layer_config.h"
34#include "vk_layer_extension_utils.h"
35#include "vk_layer_utils.h"
36#include "vk_enum_validate_helper.h"
37#include "vk_struct_validate_helper.h"
38#include "vk_layer_table.h"
39#include "vk_layer_logging.h"
40#include "threading.h"
41
Mike Stroyan845bdc42015-11-02 15:30:20 -070042#include "vk_dispatch_table_helper.h"
43#include "vk_struct_string_helper_cpp.h"
44#include "vk_layer_data.h"
45
46#include "thread_check.h"
47
48static void initThreading(layer_data *my_data, const VkAllocationCallbacks *pAllocator)
49{
50
51 uint32_t report_flags = 0;
52 uint32_t debug_action = 0;
53 FILE *log_output = NULL;
54 const char *strOpt;
55 VkDebugReportCallbackEXT callback;
56 // initialize Threading options
57 report_flags = getLayerOptionFlags("ThreadingReportFlags", 0);
58 getLayerOptionEnum("ThreadingDebugAction", (uint32_t *) &debug_action);
59
60 if (debug_action & VK_DBG_LAYER_ACTION_LOG_MSG)
61 {
62 strOpt = getLayerOption("ThreadingLogFilename");
63 log_output = getLayerLogOutput(strOpt, "Threading");
64 VkDebugReportCallbackCreateInfoEXT dbgCreateInfo;
65 memset(&dbgCreateInfo, 0, sizeof(dbgCreateInfo));
66 dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
67 dbgCreateInfo.flags = report_flags;
68 dbgCreateInfo.pfnCallback = log_callback;
69 dbgCreateInfo.pUserData = (void *) log_output;
70 layer_create_msg_callback(my_data->report_data, &dbgCreateInfo, pAllocator, &callback);
71 my_data->logging_callback.push_back(callback);
72 }
73
74 if (debug_action & VK_DBG_LAYER_ACTION_DEBUG_OUTPUT) {
75 VkDebugReportCallbackCreateInfoEXT dbgCreateInfo;
76 memset(&dbgCreateInfo, 0, sizeof(dbgCreateInfo));
77 dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
78 dbgCreateInfo.flags = report_flags;
79 dbgCreateInfo.pfnCallback = win32_debug_output_msg;
80 dbgCreateInfo.pUserData = NULL;
81 layer_create_msg_callback(my_data->report_data, &dbgCreateInfo, pAllocator, &callback);
82 my_data->logging_callback.push_back(callback);
83 }
84
85 if (!threadingLockInitialized)
86 {
87 loader_platform_thread_create_mutex(&threadingLock);
88 loader_platform_thread_init_cond(&threadingCond);
89 threadingLockInitialized = 1;
90 }
91}
92
93
94VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance)
95{
96 VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
97
98 assert(chain_info->u.pLayerInfo);
99 PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
100 PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance) fpGetInstanceProcAddr(NULL, "vkCreateInstance");
101 if (fpCreateInstance == NULL) {
102 return VK_ERROR_INITIALIZATION_FAILED;
103 }
104
105 // Advance the link info for the next element on the chain
106 chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
107
108 VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
109 if (result != VK_SUCCESS)
110 return result;
111
112 layer_data *my_data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map);
113 my_data->instance_dispatch_table = new VkLayerInstanceDispatchTable;
114 layer_init_instance_dispatch_table(*pInstance, my_data->instance_dispatch_table, fpGetInstanceProcAddr);
115
116 my_data->report_data = debug_report_create_instance(
117 my_data->instance_dispatch_table,
118 *pInstance,
119 pCreateInfo->enabledExtensionCount,
120 pCreateInfo->ppEnabledExtensionNames);
121 initThreading(my_data, pAllocator);
122 return result;
123}
124
125
126VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks* pAllocator)
127{
128 dispatch_key key = get_dispatch_key(instance);
129 layer_data *my_data = get_my_data_ptr(key, layer_data_map);
130 VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
Mike Stroyana7bf3282016-02-04 16:39:53 -0700131 startWriteObject(my_data, instance);
Mike Stroyan845bdc42015-11-02 15:30:20 -0700132 pTable->DestroyInstance(instance, pAllocator);
Mike Stroyana7bf3282016-02-04 16:39:53 -0700133 finishWriteObject(my_data, instance);
Mike Stroyan845bdc42015-11-02 15:30:20 -0700134
135 // Clean up logging callback, if any
136 while (my_data->logging_callback.size() > 0) {
137 VkDebugReportCallbackEXT callback = my_data->logging_callback.back();
138 layer_destroy_msg_callback(my_data->report_data, callback, pAllocator);
139 my_data->logging_callback.pop_back();
140 }
141
142 layer_debug_report_destroy_instance(my_data->report_data);
143 delete my_data->instance_dispatch_table;
144 layer_data_map.erase(key);
145
146 if (layer_data_map.empty()) {
147 // Release mutex when destroying last instance.
148 loader_platform_thread_delete_mutex(&threadingLock);
149 threadingLockInitialized = 0;
150 }
151}
152
153
154VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice)
155{
156 VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
157
158 assert(chain_info->u.pLayerInfo);
159 PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
160 PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
161 PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice) fpGetInstanceProcAddr(NULL, "vkCreateDevice");
162 if (fpCreateDevice == NULL) {
163 return VK_ERROR_INITIALIZATION_FAILED;
164 }
165
166 // Advance the link info for the next element on the chain
167 chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
168
169 VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
170 if (result != VK_SUCCESS) {
171 return result;
172 }
173
174 layer_data *my_instance_data = get_my_data_ptr(get_dispatch_key(gpu), layer_data_map);
175 layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map);
176
177 // Setup device dispatch table
178 my_device_data->device_dispatch_table = new VkLayerDispatchTable;
179 layer_init_device_dispatch_table(*pDevice, my_device_data->device_dispatch_table, fpGetDeviceProcAddr);
180
181 my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice);
182 return result;
183}
184
185
186VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator)
187{
188 dispatch_key key = get_dispatch_key(device);
189 layer_data* dev_data = get_my_data_ptr(key, layer_data_map);
Mike Stroyana7bf3282016-02-04 16:39:53 -0700190 startWriteObject(dev_data, device);
Mike Stroyan845bdc42015-11-02 15:30:20 -0700191 dev_data->device_dispatch_table->DestroyDevice(device, pAllocator);
Mike Stroyana7bf3282016-02-04 16:39:53 -0700192 finishWriteObject(dev_data, device);
Mike Stroyan845bdc42015-11-02 15:30:20 -0700193 layer_data_map.erase(key);
194}
195
Courtney Goeltzenleuchterf3d39702016-02-12 13:30:20 -0700196static const VkExtensionProperties threading_extensions[] = {
197 {
198 VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
199 VK_EXT_DEBUG_REPORT_SPEC_VERSION
200 }
201};
Mike Stroyan845bdc42015-11-02 15:30:20 -0700202
203VK_LAYER_EXPORT VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, VkExtensionProperties* pProperties)
204{
Courtney Goeltzenleuchterf3d39702016-02-12 13:30:20 -0700205 return util_GetExtensionProperties(ARRAY_SIZE(threading_extensions), threading_extensions, pCount, pProperties);
Mike Stroyan845bdc42015-11-02 15:30:20 -0700206}
207
208static const VkLayerProperties globalLayerProps[] = {
209 {
Courtney Goeltzenleuchter76885322016-02-06 17:11:22 -0700210 "VK_LAYER_GOOGLE_threading",
Mike Stroyan845bdc42015-11-02 15:30:20 -0700211 VK_API_VERSION, // specVersion
Courtney Goeltzenleuchter76885322016-02-06 17:11:22 -0700212 1,
Courtney Goeltzenleuchtera4784fb2016-02-12 13:22:04 -0700213 "Google Validation Layer",
Mike Stroyan845bdc42015-11-02 15:30:20 -0700214 }
215};
216
217
218VK_LAYER_EXPORT VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties* pProperties)
219{
220 return util_GetLayerProperties(ARRAY_SIZE(globalLayerProps), globalLayerProps, pCount, pProperties);
221}
222
223static const VkLayerProperties deviceLayerProps[] = {
224 {
Courtney Goeltzenleuchter76885322016-02-06 17:11:22 -0700225 "VK_LAYER_GOOGLE_threading",
226 VK_API_VERSION, // specVersion
227 1,
Courtney Goeltzenleuchtera4784fb2016-02-12 13:22:04 -0700228 "Google Validation Layer",
Mike Stroyan845bdc42015-11-02 15:30:20 -0700229 }
230};
Courtney Goeltzenleuchtera4784fb2016-02-12 13:22:04 -0700231
Courtney Goeltzenleuchterf3d39702016-02-12 13:30:20 -0700232VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(
233 VkPhysicalDevice physicalDevice,
234 const char *pLayerName,
235 uint32_t *pCount,
236 VkExtensionProperties* pProperties)
237{
238 if (pLayerName == NULL) {
239 dispatch_key key = get_dispatch_key(physicalDevice);
240 layer_data *my_data = get_my_data_ptr(key, layer_data_map);
241 return my_data->instance_dispatch_table->EnumerateDeviceExtensionProperties(
242 physicalDevice,
243 NULL,
244 pCount,
245 pProperties);
246 } else {
247 // Threading layer does not have any device extensions
248 return util_GetExtensionProperties(0,
249 nullptr,
250 pCount, pProperties);
251 }
252}
253
Mike Stroyan845bdc42015-11-02 15:30:20 -0700254VK_LAYER_EXPORT VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount, VkLayerProperties* pProperties)
255{
256 return util_GetLayerProperties(ARRAY_SIZE(deviceLayerProps), deviceLayerProps, pCount, pProperties);
257}
258
Mike Stroyan845bdc42015-11-02 15:30:20 -0700259static inline PFN_vkVoidFunction layer_intercept_proc(const char *name)
260{
261 for (int i=0; i<sizeof(procmap)/sizeof(procmap[0]); i++) {
262 if (!strcmp(name, procmap[i].name)) return procmap[i].pFunc;
263 }
264 return NULL;
265}
266
267
268static inline PFN_vkVoidFunction layer_intercept_instance_proc(const char *name)
269{
270 if (!name || name[0] != 'v' || name[1] != 'k')
271 return NULL;
272
273 name += 2;
274 if (!strcmp(name, "CreateInstance"))
275 return (PFN_vkVoidFunction) vkCreateInstance;
276 if (!strcmp(name, "DestroyInstance"))
277 return (PFN_vkVoidFunction) vkDestroyInstance;
278 if (!strcmp(name, "EnumerateInstanceExtensionProperties"))
279 return (PFN_vkVoidFunction) vkEnumerateInstanceExtensionProperties;
280 if (!strcmp(name, "EnumerateInstanceLayerProperties"))
281 return (PFN_vkVoidFunction) vkEnumerateInstanceLayerProperties;
Courtney Goeltzenleuchterf3d39702016-02-12 13:30:20 -0700282 if (!strcmp(name, "EnumerateDeviceExtensionProperties"))
283 return (PFN_vkVoidFunction) vkEnumerateDeviceExtensionProperties;
Mike Stroyan845bdc42015-11-02 15:30:20 -0700284 if (!strcmp(name, "EnumerateDeviceLayerProperties"))
285 return (PFN_vkVoidFunction) vkEnumerateDeviceLayerProperties;
286 if (!strcmp(name, "CreateDevice"))
287 return (PFN_vkVoidFunction) vkCreateDevice;
288 if (!strcmp(name, "GetInstanceProcAddr"))
289 return (PFN_vkVoidFunction) vkGetInstanceProcAddr;
290
291 return NULL;
292}
293
294VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice device, const char* funcName)
295{
296 PFN_vkVoidFunction addr;
297 layer_data *dev_data;
298 if (device == VK_NULL_HANDLE) {
299 return NULL;
300 }
301
302 addr = layer_intercept_proc(funcName);
303 if (addr)
304 return addr;
305
306 dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
307 VkLayerDispatchTable* pTable = dev_data->device_dispatch_table;
308
309 if (pTable->GetDeviceProcAddr == NULL)
310 return NULL;
311 return pTable->GetDeviceProcAddr(device, funcName);
312}
313
314VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char* funcName)
315{
316 PFN_vkVoidFunction addr;
317 layer_data* my_data;
318
Mike Stroyan845bdc42015-11-02 15:30:20 -0700319 addr = layer_intercept_instance_proc(funcName);
320 if (addr) {
321 return addr;
322 }
323
Karl Schultz929f8792016-02-07 15:17:26 -0700324 if (instance == VK_NULL_HANDLE) {
325 return NULL;
326 }
327
Mike Stroyan845bdc42015-11-02 15:30:20 -0700328 my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
329 addr = debug_report_get_instance_proc_addr(my_data->report_data, funcName);
330 if (addr) {
331 return addr;
332 }
333
334 VkLayerInstanceDispatchTable* pTable = my_data->instance_dispatch_table;
335 if (pTable->GetInstanceProcAddr == NULL) {
336 return NULL;
337 }
338 return pTable->GetInstanceProcAddr(instance, funcName);
339}
340
341VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(
342 VkInstance instance,
343 const VkDebugReportCallbackCreateInfoEXT* pCreateInfo,
344 const VkAllocationCallbacks* pAllocator,
345 VkDebugReportCallbackEXT* pMsgCallback)
346{
347 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
348 startReadObject(my_data, instance);
349 VkResult result = my_data->instance_dispatch_table->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
350 if (VK_SUCCESS == result) {
351 result = layer_create_msg_callback(my_data->report_data, pCreateInfo, pAllocator, pMsgCallback);
352 }
353 finishReadObject(my_data, instance);
354 return result;
355}
356
357VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(
358 VkInstance instance,
359 VkDebugReportCallbackEXT callback,
360 const VkAllocationCallbacks* pAllocator)
361{
362 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
363 startReadObject(my_data, instance);
364 startWriteObject(my_data, callback);
365 my_data->instance_dispatch_table->DestroyDebugReportCallbackEXT(instance, callback, pAllocator);
366 layer_destroy_msg_callback(my_data->report_data, callback, pAllocator);
367 finishReadObject(my_data, instance);
368 finishWriteObject(my_data, callback);
369}
370
371VkResult VKAPI_CALL vkAllocateCommandBuffers(
372 VkDevice device,
373 const VkCommandBufferAllocateInfo* pAllocateInfo,
374 VkCommandBuffer* pCommandBuffers)
375{
376 dispatch_key key = get_dispatch_key(device);
377 layer_data *my_data = get_my_data_ptr(key, layer_data_map);
378 VkLayerDispatchTable *pTable = my_data->device_dispatch_table;
379 VkResult result;
380 startReadObject(my_data, device);
381 startWriteObject(my_data, pAllocateInfo->commandPool);
382
383 result = pTable->AllocateCommandBuffers(device, pAllocateInfo, pCommandBuffers);
384 finishReadObject(my_data, device);
385 finishWriteObject(my_data, pAllocateInfo->commandPool);
386
387 // Record mapping from command buffer to command pool
388 if (VK_SUCCESS == result) {
389 for (int index=0;index<pAllocateInfo->commandBufferCount;index++) {
Mike Stroyanae8e8a72016-02-08 10:27:55 -0700390 loader_platform_thread_lock_mutex(&threadingLock);
Mike Stroyan845bdc42015-11-02 15:30:20 -0700391 command_pool_map[pCommandBuffers[index]] = pAllocateInfo->commandPool;
Mike Stroyanae8e8a72016-02-08 10:27:55 -0700392 loader_platform_thread_unlock_mutex(&threadingLock);
Mike Stroyan845bdc42015-11-02 15:30:20 -0700393 }
394 }
395
396 return result;
397}
398
399void VKAPI_CALL vkFreeCommandBuffers(
400 VkDevice device,
401 VkCommandPool commandPool,
402 uint32_t commandBufferCount,
403 const VkCommandBuffer* pCommandBuffers)
404{
405 dispatch_key key = get_dispatch_key(device);
406 layer_data *my_data = get_my_data_ptr(key, layer_data_map);
407 VkLayerDispatchTable *pTable = my_data->device_dispatch_table;
408 const bool lockCommandPool = false; // pool is already directly locked
409 startReadObject(my_data, device);
410 startWriteObject(my_data, commandPool);
411 for (int index=0;index<commandBufferCount;index++) {
412 startWriteObject(my_data, pCommandBuffers[index], lockCommandPool);
413 }
414
415 pTable->FreeCommandBuffers(device,commandPool,commandBufferCount,pCommandBuffers);
416 finishReadObject(my_data, device);
417 finishWriteObject(my_data, commandPool);
418 for (int index=0;index<commandBufferCount;index++) {
419 finishWriteObject(my_data, pCommandBuffers[index], lockCommandPool);
Mike Stroyanae8e8a72016-02-08 10:27:55 -0700420 loader_platform_thread_lock_mutex(&threadingLock);
Mike Stroyan845bdc42015-11-02 15:30:20 -0700421 command_pool_map.erase(pCommandBuffers[index]);
Mike Stroyanae8e8a72016-02-08 10:27:55 -0700422 loader_platform_thread_unlock_mutex(&threadingLock);
Mike Stroyan845bdc42015-11-02 15:30:20 -0700423 }
424}
425