blob: a27fcd60e9c64c6340134022eab771c1607fd499 [file] [log] [blame]
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -06001#!/usr/bin/python3 -i
2#
3# Copyright (c) 2015-2016 Valve Corporation
4# Copyright (c) 2015-2016 LunarG, Inc.
5# Copyright (c) 2015-2016 Google Inc.
6#
7# Licensed under the Apache License, Version 2.0 (the "License");
8# you may not use this file except in compliance with the License.
9# You may obtain a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS,
15# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16# See the License for the specific language governing permissions and
17# limitations under the License.
18#
19# Author: Tobin Ehlis <tobine@google.com>
20# Author: Mark Lobodzinski <mark@lunarg.com>
21#
22# This script generates the dispatch portion of a factory layer which intercepts
23# all Vulkan functions. The resultant factory layer allows rapid development of
24# layers and interceptors.
25
26import os,re,sys
27from generator import *
28from common_codegen import *
29
30# LayerFactoryGeneratorOptions - subclass of GeneratorOptions.
31#
32# Adds options used by LayerFactoryOutputGenerator objects during factory
33# layer generation.
34#
35# Additional members
36# prefixText - list of strings to prefix generated header with
37# (usually a copyright statement + calling convention macros).
38# protectFile - True if multiple inclusion protection should be
39# generated (based on the filename) around the entire header.
40# protectFeature - True if #ifndef..#endif protection should be
41# generated around a feature interface in the header file.
42# genFuncPointers - True if function pointer typedefs should be
43# generated
44# protectProto - If conditional protection should be generated
45# around prototype declarations, set to either '#ifdef'
46# to require opt-in (#ifdef protectProtoStr) or '#ifndef'
47# to require opt-out (#ifndef protectProtoStr). Otherwise
48# set to None.
49# protectProtoStr - #ifdef/#ifndef symbol to use around prototype
50# declarations, if protectProto is set
51# apicall - string to use for the function declaration prefix,
52# such as APICALL on Windows.
53# apientry - string to use for the calling convention macro,
54# in typedefs, such as APIENTRY.
55# apientryp - string to use for the calling convention macro
56# in function pointer typedefs, such as APIENTRYP.
57# indentFuncProto - True if prototype declarations should put each
58# parameter on a separate line
59# indentFuncPointer - True if typedefed function pointers should put each
60# parameter on a separate line
61# alignFuncParam - if nonzero and parameters are being put on a
62# separate line, align parameter names at the specified column
63class LayerChassisGeneratorOptions(GeneratorOptions):
64 def __init__(self,
65 filename = None,
66 directory = '.',
67 apiname = None,
68 profile = None,
69 versions = '.*',
70 emitversions = '.*',
71 defaultExtensions = None,
72 addExtensions = None,
73 removeExtensions = None,
74 emitExtensions = None,
75 sortProcedure = regSortFeatures,
76 prefixText = "",
77 genFuncPointers = True,
78 protectFile = True,
79 protectFeature = True,
80 apicall = '',
81 apientry = '',
82 apientryp = '',
83 indentFuncProto = True,
84 indentFuncPointer = False,
85 alignFuncParam = 0,
86 helper_file_type = '',
87 expandEnumerants = True):
88 GeneratorOptions.__init__(self, filename, directory, apiname, profile,
89 versions, emitversions, defaultExtensions,
90 addExtensions, removeExtensions, emitExtensions, sortProcedure)
91 self.prefixText = prefixText
92 self.genFuncPointers = genFuncPointers
93 self.protectFile = protectFile
94 self.protectFeature = protectFeature
95 self.apicall = apicall
96 self.apientry = apientry
97 self.apientryp = apientryp
98 self.indentFuncProto = indentFuncProto
99 self.indentFuncPointer = indentFuncPointer
100 self.alignFuncParam = alignFuncParam
101
102# LayerChassisOutputGenerator - subclass of OutputGenerator.
103# Generates a LayerFactory layer that intercepts all API entrypoints
104# This is intended to be used as a starting point for creating custom layers
105#
106# ---- methods ----
107# LayerChassisOutputGenerator(errFile, warnFile, diagFile) - args as for
108# OutputGenerator. Defines additional internal state.
109# ---- methods overriding base class ----
110# beginFile(genOpts)
111# endFile()
112# beginFeature(interface, emit)
113# endFeature()
114# genType(typeinfo,name)
115# genStruct(typeinfo,name)
116# genGroup(groupinfo,name)
117# genEnum(enuminfo, name)
118# genCmd(cmdinfo)
119class LayerChassisOutputGenerator(OutputGenerator):
120 """Generate specified API interfaces in a specific style, such as a C header"""
121 # This is an ordered list of sections in the header file.
122 TYPE_SECTIONS = ['include', 'define', 'basetype', 'handle', 'enum',
123 'group', 'bitmask', 'funcpointer', 'struct']
124 ALL_SECTIONS = TYPE_SECTIONS + ['command']
125
126
127
128
129 inline_custom_source_preamble = """
130// This file is ***GENERATED***. Do Not Edit.
131// See layer_chassis_generator.py for modifications.
132
133/* Copyright (c) 2015-2018 The Khronos Group Inc.
134 * Copyright (c) 2015-2018 Valve Corporation
135 * Copyright (c) 2015-2018 LunarG, Inc.
136 * Copyright (c) 2015-2018 Google Inc.
137 *
138 * Licensed under the Apache License, Version 2.0 (the "License");
139 * you may not use this file except in compliance with the License.
140 * You may obtain a copy of the License at
141 *
142 * http://www.apache.org/licenses/LICENSE-2.0
143 *
144 * Unless required by applicable law or agreed to in writing, software
145 * distributed under the License is distributed on an "AS IS" BASIS,
146 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
147 * See the License for the specific language governing permissions and
148 * limitations under the License.
149 *
150 * Author: Mark Lobodzinski <mark@lunarg.com>
151 */
152
153#include <string.h>
154#include <mutex>
155
156#define VALIDATION_ERROR_MAP_IMPL
157
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600158#include "chassis.h"
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600159
160class layer_chassis;
161
162std::vector<layer_chassis *> global_interceptor_list;
163debug_report_data *report_data = VK_NULL_HANDLE;
164
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600165std::unordered_map<void *, layer_data *> layer_data_map;
166std::unordered_map<void *, instance_layer_data *> instance_layer_data_map;
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600167
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600168// Create an object_lifetime object and add it to the global_interceptor_list
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600169#include "interceptor_objects.h"
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600170ObjectLifetimes object_tracker_object;
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600171
172using mutex_t = std::mutex;
173using lock_guard_t = std::lock_guard<mutex_t>;
174using unique_lock_t = std::unique_lock<mutex_t>;
175
176namespace vulkan_layer_chassis {
177
178using std::unordered_map;
179
180static mutex_t global_lock;
181
182static const VkLayerProperties global_layer = {
183 "VK_LAYER_KHRONOS_validation", VK_LAYER_API_VERSION, 1, "LunarG validation Layer",
184};
185
186static const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
187
188extern const std::unordered_map<std::string, void*> name_to_funcptr_map;
189
190
191// Manually written functions
192
193VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) {
194 assert(device);
195 layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
196 const auto &item = name_to_funcptr_map.find(funcName);
197 if (item != name_to_funcptr_map.end()) {
198 return reinterpret_cast<PFN_vkVoidFunction>(item->second);
199 }
200 auto &table = device_data->dispatch_table;
201 if (!table.GetDeviceProcAddr) return nullptr;
202 return table.GetDeviceProcAddr(device, funcName);
203}
204
205VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) {
206 instance_layer_data *instance_data;
207 const auto &item = name_to_funcptr_map.find(funcName);
208 if (item != name_to_funcptr_map.end()) {
209 return reinterpret_cast<PFN_vkVoidFunction>(item->second);
210 }
211 instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
212 auto &table = instance_data->dispatch_table;
213 if (!table.GetInstanceProcAddr) return nullptr;
214 return table.GetInstanceProcAddr(instance, funcName);
215}
216
217VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
218 instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
219 auto &table = instance_data->dispatch_table;
220 if (!table.GetPhysicalDeviceProcAddr) return nullptr;
221 return table.GetPhysicalDeviceProcAddr(instance, funcName);
222}
223
224VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
225 return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
226}
227
228VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
229 VkLayerProperties *pProperties) {
230 return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
231}
232
233VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
234 VkExtensionProperties *pProperties) {
235 if (pLayerName && !strcmp(pLayerName, global_layer.layerName))
236 return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties);
237
238 return VK_ERROR_LAYER_NOT_PRESENT;
239}
240
241VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName,
242 uint32_t *pCount, VkExtensionProperties *pProperties) {
243 if (pLayerName && !strcmp(pLayerName, global_layer.layerName)) return util_GetExtensionProperties(0, NULL, pCount, pProperties);
244
245 assert(physicalDevice);
246
247 instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
248 return instance_data->dispatch_table.EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
249}
250
251VKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
252 VkInstance *pInstance) {
253 VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
254
255 assert(chain_info->u.pLayerInfo);
256 PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
257 PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
258 if (fpCreateInstance == NULL) return VK_ERROR_INITIALIZATION_FAILED;
259 chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
260
261 // Init dispatch array and call registration functions
262 for (auto intercept : global_interceptor_list) {
263 intercept->PreCallValidateCreateInstance(pCreateInfo, pAllocator, pInstance);
264 }
265 for (auto intercept : global_interceptor_list) {
266 intercept->PreCallRecordCreateInstance(pCreateInfo, pAllocator, pInstance);
267 }
268
269 VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
270
271 instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(*pInstance), instance_layer_data_map);
272 instance_data->instance = *pInstance;
273 layer_init_instance_dispatch_table(*pInstance, &instance_data->dispatch_table, fpGetInstanceProcAddr);
274 instance_data->report_data = debug_utils_create_instance(
275 &instance_data->dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
276 instance_data->extensions.InitFromInstanceCreateInfo((pCreateInfo->pApplicationInfo ? pCreateInfo->pApplicationInfo->apiVersion : VK_API_VERSION_1_0), pCreateInfo);
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600277 layer_debug_messenger_actions(instance_data->report_data, instance_data->logging_messenger, pAllocator, "lunarg_object_tracker");
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600278 report_data = instance_data->report_data;
279
280 for (auto intercept : global_interceptor_list) {
281 intercept->PostCallRecordCreateInstance(pCreateInfo, pAllocator, pInstance);
282 }
283
284 return result;
285}
286
287VKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
288 dispatch_key key = get_dispatch_key(instance);
289 instance_layer_data *instance_data = GetLayerDataPtr(key, instance_layer_data_map);
290 for (auto intercept : global_interceptor_list) {
291 intercept->PreCallValidateDestroyInstance(instance, pAllocator);
292 }
293 for (auto intercept : global_interceptor_list) {
294 intercept->PreCallRecordDestroyInstance(instance, pAllocator);
295 }
296
297 instance_data->dispatch_table.DestroyInstance(instance, pAllocator);
298
299 lock_guard_t lock(global_lock);
300 for (auto intercept : global_interceptor_list) {
301 intercept->PostCallRecordDestroyInstance(instance, pAllocator);
302 }
303 // Clean up logging callback, if any
304 while (instance_data->logging_messenger.size() > 0) {
305 VkDebugUtilsMessengerEXT messenger = instance_data->logging_messenger.back();
306 layer_destroy_messenger_callback(instance_data->report_data, messenger, pAllocator);
307 instance_data->logging_messenger.pop_back();
308 }
309 while (instance_data->logging_callback.size() > 0) {
310 VkDebugReportCallbackEXT callback = instance_data->logging_callback.back();
311 layer_destroy_report_callback(instance_data->report_data, callback, pAllocator);
312 instance_data->logging_callback.pop_back();
313 }
314 for (auto intercept : global_interceptor_list) {
315 intercept->PostCallRecordDestroyInstance(instance, pAllocator);
316 }
317 layer_debug_utils_destroy_instance(instance_data->report_data);
318 FreeLayerDataPtr(key, instance_layer_data_map);
319}
320
321VKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
322 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
323 instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(gpu), instance_layer_data_map);
324
325 unique_lock_t lock(global_lock);
326 VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
327 PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
328 PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
329 PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(instance_data->instance, "vkCreateDevice");
330 chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
331
332 for (auto intercept : global_interceptor_list) {
333 intercept->PreCallValidateCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
334 }
335 for (auto intercept : global_interceptor_list) {
336 intercept->PreCallRecordCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
337 }
338 lock.unlock();
339
340 VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
341
342 lock.lock();
343 for (auto intercept : global_interceptor_list) {
344 intercept->PostCallRecordCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
345 }
346 layer_data *device_data = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
347 device_data->instance_data = instance_data;
348 layer_init_device_dispatch_table(*pDevice, &device_data->dispatch_table, fpGetDeviceProcAddr);
349 device_data->device = *pDevice;
350 device_data->physical_device = gpu;
351 device_data->report_data = layer_debug_utils_create_device(instance_data->report_data, *pDevice);
352 VkPhysicalDeviceProperties physical_device_properties{};
353 instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &physical_device_properties);
354 device_data->extensions.InitFromDeviceCreateInfo(&instance_data->extensions, physical_device_properties.apiVersion, pCreateInfo);
355 lock.unlock();
356
357 return result;
358}
359
360VKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
361 dispatch_key key = get_dispatch_key(device);
362 layer_data *device_data = GetLayerDataPtr(key, layer_data_map);
363
364 unique_lock_t lock(global_lock);
365 for (auto intercept : global_interceptor_list) {
366 intercept->PreCallValidateDestroyDevice(device, pAllocator);
367 }
368 for (auto intercept : global_interceptor_list) {
369 intercept->PreCallRecordDestroyDevice(device, pAllocator);
370 }
371 layer_debug_utils_destroy_device(device);
372 lock.unlock();
373
374 device_data->dispatch_table.DestroyDevice(device, pAllocator);
375
376 lock.lock();
377 for (auto intercept : global_interceptor_list) {
378 intercept->PostCallRecordDestroyDevice(device, pAllocator);
379 }
380
381 FreeLayerDataPtr(key, layer_data_map);
382}
383
384VKAPI_ATTR VkResult VKAPI_CALL CreateDebugReportCallbackEXT(VkInstance instance,
385 const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
386 const VkAllocationCallbacks *pAllocator,
387 VkDebugReportCallbackEXT *pCallback) {
388 instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
389 for (auto intercept : global_interceptor_list) {
390 intercept->PreCallValidateCreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);
391 }
392 for (auto intercept : global_interceptor_list) {
393 intercept->PreCallRecordCreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);
394 }
395 VkResult result = instance_data->dispatch_table.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);
396 result = layer_create_report_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pCallback);
397 for (auto intercept : global_interceptor_list) {
398 intercept->PostCallRecordCreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);
399 }
400 return result;
401}
402
403VKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback,
404 const VkAllocationCallbacks *pAllocator) {
405 instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
406 for (auto intercept : global_interceptor_list) {
407 intercept->PreCallValidateDestroyDebugReportCallbackEXT(instance, callback, pAllocator);
408 }
409 for (auto intercept : global_interceptor_list) {
410 intercept->PreCallRecordDestroyDebugReportCallbackEXT(instance, callback, pAllocator);
411 }
412 instance_data->dispatch_table.DestroyDebugReportCallbackEXT(instance, callback, pAllocator);
413 layer_destroy_report_callback(instance_data->report_data, callback, pAllocator);
414 for (auto intercept : global_interceptor_list) {
415 intercept->PostCallRecordDestroyDebugReportCallbackEXT(instance, callback, pAllocator);
416 }
417}
418"""
419
420 inline_custom_source_postamble = """
421// loader-layer interface v0, just wrappers since there is only a layer
422
423VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
424 VkExtensionProperties *pProperties) {
425 return vulkan_layer_chassis::EnumerateInstanceExtensionProperties(pLayerName, pCount, pProperties);
426}
427
428VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount,
429 VkLayerProperties *pProperties) {
430 return vulkan_layer_chassis::EnumerateInstanceLayerProperties(pCount, pProperties);
431}
432
433VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
434 VkLayerProperties *pProperties) {
435 // the layer command handles VK_NULL_HANDLE just fine internally
436 assert(physicalDevice == VK_NULL_HANDLE);
437 return vulkan_layer_chassis::EnumerateDeviceLayerProperties(VK_NULL_HANDLE, pCount, pProperties);
438}
439
440VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
441 const char *pLayerName, uint32_t *pCount,
442 VkExtensionProperties *pProperties) {
443 // the layer command handles VK_NULL_HANDLE just fine internally
444 assert(physicalDevice == VK_NULL_HANDLE);
445 return vulkan_layer_chassis::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
446}
447
448VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
449 return vulkan_layer_chassis::GetDeviceProcAddr(dev, funcName);
450}
451
452VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
453 return vulkan_layer_chassis::GetInstanceProcAddr(instance, funcName);
454}
455
456VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance,
457 const char *funcName) {
458 return vulkan_layer_chassis::GetPhysicalDeviceProcAddr(instance, funcName);
459}
460
461VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
462 assert(pVersionStruct != NULL);
463 assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
464
465 // Fill in the function pointers if our version is at least capable of having the structure contain them.
466 if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
467 pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
468 pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
469 pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
470 }
471
472 return VK_SUCCESS;
473}"""
474
475
476
477
478
479 def __init__(self,
480 errFile = sys.stderr,
481 warnFile = sys.stderr,
482 diagFile = sys.stdout):
483 OutputGenerator.__init__(self, errFile, warnFile, diagFile)
484 # Internal state - accumulators for different inner block text
485 self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
486 self.intercepts = []
487 self.layer_factory = '' # String containing base layer factory class definition
488
489 # Check if the parameter passed in is a pointer to an array
490 def paramIsArray(self, param):
491 return param.attrib.get('len') is not None
492
493 # Check if the parameter passed in is a pointer
494 def paramIsPointer(self, param):
495 ispointer = False
496 for elem in param:
497 if ((elem.tag is not 'type') and (elem.tail is not None)) and '*' in elem.tail:
498 ispointer = True
499 return ispointer
500
501 # Check if an object is a non-dispatchable handle
502 def isHandleTypeNonDispatchable(self, handletype):
503 handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
504 if handle is not None and handle.find('type').text == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE':
505 return True
506 else:
507 return False
508
509 # Check if an object is a dispatchable handle
510 def isHandleTypeDispatchable(self, handletype):
511 handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
512 if handle is not None and handle.find('type').text == 'VK_DEFINE_HANDLE':
513 return True
514 else:
515 return False
516
517 def beginFile(self, genOpts):
518 OutputGenerator.beginFile(self, genOpts)
519 # Multiple inclusion protection & C++ namespace.
520 self.header = False
521 if (self.genOpts.filename and 'h' == self.genOpts.filename[-1]):
522 self.header = True
523 write('#pragma once', file=self.outFile)
524 self.newline()
525 # User-supplied prefix text, if any (list of strings)
526 if self.header:
527 if (genOpts.prefixText):
528 for s in genOpts.prefixText:
529 write(s, file=self.outFile)
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600530 write('#include <mutex>', file=self.outFile)
531 write('#include <cinttypes>', file=self.outFile)
532 write('#include <stdio.h>', file=self.outFile)
533 write('#include <stdlib.h>', file=self.outFile)
534 write('#include <string.h>', file=self.outFile)
535 write('#include <unordered_map>', file=self.outFile)
536 write('#include <unordered_set>', file=self.outFile)
537
538 write('#include "vk_loader_platform.h"', file=self.outFile)
539 write('#include "vulkan/vulkan.h"', file=self.outFile)
540 write('#include "vk_layer_config.h"', file=self.outFile)
541 write('#include "vk_layer_data.h"', file=self.outFile)
542 write('#include "vk_layer_logging.h"', file=self.outFile)
543 write('#include "vk_object_types.h"', file=self.outFile)
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600544 write('#include "vulkan/vk_layer.h"', file=self.outFile)
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600545 write('#include "vk_enum_string_helper.h"', file=self.outFile)
546 write('#include "vk_layer_extension_utils.h"', file=self.outFile)
547 write('#include "vk_layer_utils.h"', file=self.outFile)
548 write('#include "vulkan/vk_layer.h"', file=self.outFile)
549 write('#include "vk_dispatch_table_helper.h"', file=self.outFile)
550 write('#include "vk_validation_error_messages.h"', file=self.outFile)
551 write('#include "vk_extension_helper.h"', file=self.outFile)
552 write('', file=self.outFile)
553
554
555 # TODO: Need some ifdef code here for which layer is being built!
556 write('#include "object_lifetimes.h"', file=self.outFile)
557 write('', file=self.outFile)
558
559 write('struct instance_layer_data {', file=self.outFile)
560 write(' VkLayerInstanceDispatchTable dispatch_table;', file=self.outFile)
561 write(' VkInstance instance = VK_NULL_HANDLE;', file=self.outFile)
562 write(' debug_report_data *report_data = nullptr;', file=self.outFile)
563 write(' std::vector<VkDebugReportCallbackEXT> logging_callback;', file=self.outFile)
564 write(' std::vector<VkDebugUtilsMessengerEXT> logging_messenger;', file=self.outFile)
565 write(' InstanceExtensions extensions;', file=self.outFile)
566 write('', file=self.outFile)
567 # TODO: Need some ifdef code here for which layer is being built!
568 write(' object_lifetime objdata;', file=self.outFile)
569 write('};', file=self.outFile)
570 write('', file=self.outFile)
571 write('struct layer_data {', file=self.outFile)
572 write(' debug_report_data *report_data = nullptr;', file=self.outFile)
573 write(' VkLayerDispatchTable dispatch_table;', file=self.outFile)
574 write(' DeviceExtensions extensions = {};', file=self.outFile)
575 write(' VkDevice device = VK_NULL_HANDLE;', file=self.outFile)
576 write(' VkPhysicalDevice physical_device = VK_NULL_HANDLE;', file=self.outFile)
577 write(' instance_layer_data *instance_data = nullptr;', file=self.outFile)
578 write('', file=self.outFile)
579 # TODO: Need some ifdef code here for which layer is being built!
580 write(' object_lifetime objdata;', file=self.outFile)
581 write('};', file=self.outFile)
582 write('', file=self.outFile)
583 write('extern std::unordered_map<void *, layer_data *> layer_data_map;', file=self.outFile)
584 write('extern std::unordered_map<void *, instance_layer_data *> instance_layer_data_map;', file=self.outFile)
585 write('', file=self.outFile)
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600586 write('class layer_chassis;', file=self.outFile)
587 write('extern std::vector<layer_chassis *> global_interceptor_list;', file=self.outFile)
588 write('extern debug_report_data *report_data;\n', file=self.outFile)
589 write('namespace vulkan_layer_chassis {\n', file=self.outFile)
590 else:
591 write(self.inline_custom_source_preamble, file=self.outFile)
592
593 # Initialize Enum Section
594 self.layer_factory += '// Layer Factory base class definition\n'
595 self.layer_factory += 'class layer_chassis {\n'
596 self.layer_factory += ' public:\n'
597 self.layer_factory += ' layer_chassis() {\n'
598 self.layer_factory += ' global_interceptor_list.emplace_back(this);\n'
599 self.layer_factory += ' };\n'
600 self.layer_factory += '\n'
601 self.layer_factory += ' std::string layer_name = "CHASSIS";\n'
602 self.layer_factory += '\n'
603 self.layer_factory += ' // Pre/post hook point declarations\n'
604 #
605 def endFile(self):
606 # Finish C++ namespace and multiple inclusion protection
607 self.newline()
608 if not self.header:
609 # Record intercepted procedures
610 write('// Map of all APIs to be intercepted by this layer', file=self.outFile)
611 write('const std::unordered_map<std::string, void*> name_to_funcptr_map = {', file=self.outFile)
612 write('\n'.join(self.intercepts), file=self.outFile)
613 write('};\n', file=self.outFile)
614 self.newline()
615 write('} // namespace vulkan_layer_chassis', file=self.outFile)
616 if self.header:
617 self.newline()
618 # Output Layer Factory Class Definitions
619 self.layer_factory += '};\n'
620 write(self.layer_factory, file=self.outFile)
621 else:
622 write(self.inline_custom_source_postamble, file=self.outFile)
623 # Finish processing in superclass
624 OutputGenerator.endFile(self)
625
626 def beginFeature(self, interface, emit):
627 # Start processing in superclass
628 OutputGenerator.beginFeature(self, interface, emit)
629 # Get feature extra protect
630 self.featureExtraProtect = GetFeatureProtect(interface)
631 # Accumulate includes, defines, types, enums, function pointer typedefs, end function prototypes separately for this
632 # feature. They're only printed in endFeature().
633 self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
634
635 def endFeature(self):
636 # Actually write the interface to the output file.
637 if (self.emit):
638 self.newline()
639 # If type declarations are needed by other features based on this one, it may be necessary to suppress the ExtraProtect,
640 # or move it below the 'for section...' loop.
641 if (self.featureExtraProtect != None):
642 write('#ifdef', self.featureExtraProtect, file=self.outFile)
643 for section in self.TYPE_SECTIONS:
644 contents = self.sections[section]
645 if contents:
646 write('\n'.join(contents), file=self.outFile)
647 self.newline()
648 if (self.sections['command']):
649 write('\n'.join(self.sections['command']), end=u'', file=self.outFile)
650 self.newline()
651 if (self.featureExtraProtect != None):
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600652 write('#endif //', self.featureExtraProtect, file=self.outFile)
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600653 # Finish processing in superclass
654 OutputGenerator.endFeature(self)
655 #
656 # Append a definition to the specified section
657 def appendSection(self, section, text):
658 self.sections[section].append(text)
659 #
660 # Type generation
661 def genType(self, typeinfo, name, alias):
662 pass
663 #
664 # Struct (e.g. C "struct" type) generation. This is a special case of the <type> tag where the contents are
665 # interpreted as a set of <member> tags instead of freeform C type declarations. The <member> tags are just like <param>
666 # tags - they are a declaration of a struct or union member. Only simple member declarations are supported (no nested
667 # structs etc.)
668 def genStruct(self, typeinfo, typeName):
669 OutputGenerator.genStruct(self, typeinfo, typeName)
670 body = 'typedef ' + typeinfo.elem.get('category') + ' ' + typeName + ' {\n'
671 # paramdecl = self.makeCParamDecl(typeinfo.elem, self.genOpts.alignFuncParam)
672 for member in typeinfo.elem.findall('.//member'):
673 body += self.makeCParamDecl(member, self.genOpts.alignFuncParam)
674 body += ';\n'
675 body += '} ' + typeName + ';\n'
676 self.appendSection('struct', body)
677 #
678 # Group (e.g. C "enum" type) generation. These are concatenated together with other types.
679 def genGroup(self, groupinfo, groupName, alias):
680 pass
681 # Enumerant generation
682 # <enum> tags may specify their values in several ways, but are usually just integers.
683 def genEnum(self, enuminfo, name, alias):
684 pass
685 #
686 # Customize Cdecl for layer factory base class
687 def BaseClassCdecl(self, elem, name):
688 raw = self.makeCDecls(elem)[1]
689
690 # Toss everything before the undecorated name
691 prototype = raw.split("VKAPI_PTR *PFN_vk")[1]
692 prototype = prototype.replace(")", "", 1)
693 prototype = prototype.replace(";", " {};")
694
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600695 # Build up pre/post call virtual function declarations
696 pre_call_validate = 'virtual bool PreCallValidate' + prototype
697 pre_call_validate = pre_call_validate.replace("{}", " { return false; }")
698 pre_call_record = 'virtual void PreCallRecord' + prototype
699 post_call_record = 'virtual void PostCallRecord' + prototype
700 return ' %s\n %s\n %s\n' % (pre_call_validate, pre_call_record, post_call_record)
701 #
702 # Command generation
703 def genCmd(self, cmdinfo, name, alias):
704 ignore_functions = [
705 'vkEnumerateInstanceVersion'
706 ]
707
708 if name in ignore_functions:
709 return
710
711 if self.header: # In the header declare all intercepts
712 self.appendSection('command', '')
713 self.appendSection('command', self.makeCDecls(cmdinfo.elem)[0])
714 if (self.featureExtraProtect != None):
715 self.intercepts += [ '#ifdef %s' % self.featureExtraProtect ]
716 self.layer_factory += '#ifdef %s\n' % self.featureExtraProtect
717 # Update base class with virtual function declarations
718 self.layer_factory += self.BaseClassCdecl(cmdinfo.elem, name)
719 # Update function intercepts
720 self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ]
721 if (self.featureExtraProtect != None):
722 self.intercepts += [ '#endif' ]
723 self.layer_factory += '#endif\n'
724 return
725
726 manual_functions = [
727 # Include functions here to be interecpted w/ manually implemented function bodies
728 'vkGetDeviceProcAddr',
729 'vkGetInstanceProcAddr',
730 'vkGetPhysicalDeviceProcAddr',
731 'vkCreateDevice',
732 'vkDestroyDevice',
733 'vkCreateInstance',
734 'vkDestroyInstance',
735 'vkCreateDebugReportCallbackEXT',
736 'vkDestroyDebugReportCallbackEXT',
737 'vkEnumerateInstanceLayerProperties',
738 'vkEnumerateInstanceExtensionProperties',
739 'vkEnumerateDeviceLayerProperties',
740 'vkEnumerateDeviceExtensionProperties',
741 ]
742 if name in manual_functions:
743 self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ]
744 return
745 # Record that the function will be intercepted
746 if (self.featureExtraProtect != None):
747 self.intercepts += [ '#ifdef %s' % self.featureExtraProtect ]
748 self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ]
749 if (self.featureExtraProtect != None):
750 self.intercepts += [ '#endif' ]
751 OutputGenerator.genCmd(self, cmdinfo, name, alias)
752 #
753 decls = self.makeCDecls(cmdinfo.elem)
754 self.appendSection('command', '')
755 self.appendSection('command', '%s {' % decls[0][:-1])
756 # Setup common to call wrappers. First parameter is always dispatchable
757 dispatchable_type = cmdinfo.elem.find('param/type').text
758 dispatchable_name = cmdinfo.elem.find('param/name').text
759 # Default to device
760 device_or_instance = 'device'
761 map_name = 'layer_data'
762 dispatch_table_name = 'VkLayerDispatchTable'
763 # Set to instance as necessary
764 if dispatchable_type in ["VkPhysicalDevice", "VkInstance"] or name == 'vkCreateInstance':
765 device_or_instance = 'instance'
766 dispatch_table_name = 'VkLayerInstanceDispatchTable'
767 map_name = 'instance_layer_data'
768 self.appendSection('command', ' %s *%s_data = GetLayerDataPtr(get_dispatch_key(%s), %s_map);' % (map_name, device_or_instance, dispatchable_name, map_name))
769 api_function_name = cmdinfo.elem.attrib.get('name')
770 params = cmdinfo.elem.findall('param/name')
771 paramstext = ', '.join([str(param.text) for param in params])
772 API = api_function_name.replace('vk','%s_data->dispatch_table.' % (device_or_instance),1)
773
774 # Declare result variable, if any.
775 return_map = {
776 'void': 'return;',
777 'VkResult': 'return VK_ERROR_VALIDATION_FAILED_EXT;',
778 'PFN_vkVoidFunction': 'return nullptr;',
779 'VkBool32': 'return VK_FALSE;',
780 }
781 resulttype = cmdinfo.elem.find('proto/type')
782 assignresult = ''
783 if (resulttype.text != 'void'):
784 assignresult = resulttype.text + ' result = '
785
786 # Set up skip and locking
787 self.appendSection('command', ' {')
788 self.appendSection('command', ' bool skip = false;')
789 self.appendSection('command', ' std::lock_guard<std::mutex> lock(global_lock);')
790
791 # Generate pre-call validation source code
792 self.appendSection('command', ' for (auto intercept : global_interceptor_list) {')
793 self.appendSection('command', ' skip |= intercept->PreCallValidate%s(%s);' % (api_function_name[2:], paramstext))
794 self.appendSection('command', ' if (skip) %s' % return_map[resulttype.text])
795 self.appendSection('command', ' }')
796
797 # Generate pre-call state recording source code
798 self.appendSection('command', ' for (auto intercept : global_interceptor_list) {')
799 self.appendSection('command', ' intercept->PreCallRecord%s(%s);' % (api_function_name[2:], paramstext))
800 self.appendSection('command', ' }')
801 self.appendSection('command', ' }')
802
803 self.appendSection('command', ' ' + assignresult + API + '(' + paramstext + ');')
804
805 # Generate post-call object processing source code
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600806 return_check = ''
807 if (resulttype.text == 'VkResult'):
808 return_check = 'if (VK_SUCCESS == result) '
809 self.appendSection('command', ' %s{' % return_check)
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600810 self.appendSection('command', ' std::lock_guard<std::mutex> lock(global_lock);')
811 self.appendSection('command', ' for (auto intercept : global_interceptor_list) {')
812 self.appendSection('command', ' intercept->PostCallRecord%s(%s);' % (api_function_name[2:], paramstext))
813 self.appendSection('command', ' }')
814 self.appendSection('command', ' }')
815
816 # Return result variable, if any.
817 if (resulttype.text != 'void'):
818 self.appendSection('command', ' return result;')
819 self.appendSection('command', '}')
820 #
821 # Override makeProtoName to drop the "vk" prefix
822 def makeProtoName(self, name, tail):
823 return self.genOpts.apientry + name[2:] + tail