blob: 1106eeb534b500d8ca994c82f74729f26c12f10d [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
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600172namespace vulkan_layer_chassis {
173
174using std::unordered_map;
175
Mark Lobodzinskifb6eb502018-11-26 16:05:16 -0700176static std::mutex global_lock;
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600177
178static const VkLayerProperties global_layer = {
179 "VK_LAYER_KHRONOS_validation", VK_LAYER_API_VERSION, 1, "LunarG validation Layer",
180};
181
182static const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
183
184extern const std::unordered_map<std::string, void*> name_to_funcptr_map;
185
186
187// Manually written functions
188
189VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) {
190 assert(device);
191 layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
192 const auto &item = name_to_funcptr_map.find(funcName);
193 if (item != name_to_funcptr_map.end()) {
194 return reinterpret_cast<PFN_vkVoidFunction>(item->second);
195 }
196 auto &table = device_data->dispatch_table;
197 if (!table.GetDeviceProcAddr) return nullptr;
198 return table.GetDeviceProcAddr(device, funcName);
199}
200
201VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) {
202 instance_layer_data *instance_data;
203 const auto &item = name_to_funcptr_map.find(funcName);
204 if (item != name_to_funcptr_map.end()) {
205 return reinterpret_cast<PFN_vkVoidFunction>(item->second);
206 }
207 instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
208 auto &table = instance_data->dispatch_table;
209 if (!table.GetInstanceProcAddr) return nullptr;
210 return table.GetInstanceProcAddr(instance, funcName);
211}
212
213VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
214 instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
215 auto &table = instance_data->dispatch_table;
216 if (!table.GetPhysicalDeviceProcAddr) return nullptr;
217 return table.GetPhysicalDeviceProcAddr(instance, funcName);
218}
219
220VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
221 return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
222}
223
224VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
225 VkLayerProperties *pProperties) {
226 return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
227}
228
229VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
230 VkExtensionProperties *pProperties) {
231 if (pLayerName && !strcmp(pLayerName, global_layer.layerName))
232 return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties);
233
234 return VK_ERROR_LAYER_NOT_PRESENT;
235}
236
237VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName,
238 uint32_t *pCount, VkExtensionProperties *pProperties) {
239 if (pLayerName && !strcmp(pLayerName, global_layer.layerName)) return util_GetExtensionProperties(0, NULL, pCount, pProperties);
240
241 assert(physicalDevice);
242
243 instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
244 return instance_data->dispatch_table.EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
245}
246
247VKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
248 VkInstance *pInstance) {
249 VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
250
251 assert(chain_info->u.pLayerInfo);
252 PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
253 PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
254 if (fpCreateInstance == NULL) return VK_ERROR_INITIALIZATION_FAILED;
255 chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
256
257 // Init dispatch array and call registration functions
258 for (auto intercept : global_interceptor_list) {
259 intercept->PreCallValidateCreateInstance(pCreateInfo, pAllocator, pInstance);
260 }
261 for (auto intercept : global_interceptor_list) {
262 intercept->PreCallRecordCreateInstance(pCreateInfo, pAllocator, pInstance);
263 }
264
265 VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
266
267 instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(*pInstance), instance_layer_data_map);
268 instance_data->instance = *pInstance;
269 layer_init_instance_dispatch_table(*pInstance, &instance_data->dispatch_table, fpGetInstanceProcAddr);
270 instance_data->report_data = debug_utils_create_instance(
271 &instance_data->dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames);
272 instance_data->extensions.InitFromInstanceCreateInfo((pCreateInfo->pApplicationInfo ? pCreateInfo->pApplicationInfo->apiVersion : VK_API_VERSION_1_0), pCreateInfo);
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600273 layer_debug_messenger_actions(instance_data->report_data, instance_data->logging_messenger, pAllocator, "lunarg_object_tracker");
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600274 report_data = instance_data->report_data;
275
276 for (auto intercept : global_interceptor_list) {
277 intercept->PostCallRecordCreateInstance(pCreateInfo, pAllocator, pInstance);
278 }
279
280 return result;
281}
282
283VKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
284 dispatch_key key = get_dispatch_key(instance);
285 instance_layer_data *instance_data = GetLayerDataPtr(key, instance_layer_data_map);
286 for (auto intercept : global_interceptor_list) {
287 intercept->PreCallValidateDestroyInstance(instance, pAllocator);
288 }
289 for (auto intercept : global_interceptor_list) {
290 intercept->PreCallRecordDestroyInstance(instance, pAllocator);
291 }
292
293 instance_data->dispatch_table.DestroyInstance(instance, pAllocator);
294
Mark Lobodzinskifb6eb502018-11-26 16:05:16 -0700295 std::lock_guard<std::mutex> lock(global_lock);
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600296 for (auto intercept : global_interceptor_list) {
297 intercept->PostCallRecordDestroyInstance(instance, pAllocator);
298 }
299 // Clean up logging callback, if any
300 while (instance_data->logging_messenger.size() > 0) {
301 VkDebugUtilsMessengerEXT messenger = instance_data->logging_messenger.back();
302 layer_destroy_messenger_callback(instance_data->report_data, messenger, pAllocator);
303 instance_data->logging_messenger.pop_back();
304 }
305 while (instance_data->logging_callback.size() > 0) {
306 VkDebugReportCallbackEXT callback = instance_data->logging_callback.back();
307 layer_destroy_report_callback(instance_data->report_data, callback, pAllocator);
308 instance_data->logging_callback.pop_back();
309 }
310 for (auto intercept : global_interceptor_list) {
311 intercept->PostCallRecordDestroyInstance(instance, pAllocator);
312 }
313 layer_debug_utils_destroy_instance(instance_data->report_data);
314 FreeLayerDataPtr(key, instance_layer_data_map);
315}
316
317VKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
318 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
319 instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(gpu), instance_layer_data_map);
320
Mark Lobodzinskifb6eb502018-11-26 16:05:16 -0700321 std::unique_lock <std::mutex> lock(global_lock);
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600322 VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
323 PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
324 PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
325 PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(instance_data->instance, "vkCreateDevice");
326 chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
327
328 for (auto intercept : global_interceptor_list) {
329 intercept->PreCallValidateCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
330 }
331 for (auto intercept : global_interceptor_list) {
332 intercept->PreCallRecordCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
333 }
334 lock.unlock();
335
336 VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
337
338 lock.lock();
339 for (auto intercept : global_interceptor_list) {
340 intercept->PostCallRecordCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
341 }
342 layer_data *device_data = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
343 device_data->instance_data = instance_data;
344 layer_init_device_dispatch_table(*pDevice, &device_data->dispatch_table, fpGetDeviceProcAddr);
345 device_data->device = *pDevice;
346 device_data->physical_device = gpu;
347 device_data->report_data = layer_debug_utils_create_device(instance_data->report_data, *pDevice);
348 VkPhysicalDeviceProperties physical_device_properties{};
349 instance_data->dispatch_table.GetPhysicalDeviceProperties(gpu, &physical_device_properties);
350 device_data->extensions.InitFromDeviceCreateInfo(&instance_data->extensions, physical_device_properties.apiVersion, pCreateInfo);
351 lock.unlock();
352
353 return result;
354}
355
356VKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
357 dispatch_key key = get_dispatch_key(device);
358 layer_data *device_data = GetLayerDataPtr(key, layer_data_map);
359
Mark Lobodzinskifb6eb502018-11-26 16:05:16 -0700360 std::unique_lock <std::mutex> lock(global_lock);
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600361 for (auto intercept : global_interceptor_list) {
362 intercept->PreCallValidateDestroyDevice(device, pAllocator);
363 }
364 for (auto intercept : global_interceptor_list) {
365 intercept->PreCallRecordDestroyDevice(device, pAllocator);
366 }
367 layer_debug_utils_destroy_device(device);
368 lock.unlock();
369
370 device_data->dispatch_table.DestroyDevice(device, pAllocator);
371
372 lock.lock();
373 for (auto intercept : global_interceptor_list) {
374 intercept->PostCallRecordDestroyDevice(device, pAllocator);
375 }
376
377 FreeLayerDataPtr(key, layer_data_map);
378}
379
380VKAPI_ATTR VkResult VKAPI_CALL CreateDebugReportCallbackEXT(VkInstance instance,
381 const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
382 const VkAllocationCallbacks *pAllocator,
383 VkDebugReportCallbackEXT *pCallback) {
384 instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
385 for (auto intercept : global_interceptor_list) {
386 intercept->PreCallValidateCreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);
387 }
388 for (auto intercept : global_interceptor_list) {
389 intercept->PreCallRecordCreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);
390 }
391 VkResult result = instance_data->dispatch_table.CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);
392 result = layer_create_report_callback(instance_data->report_data, false, pCreateInfo, pAllocator, pCallback);
393 for (auto intercept : global_interceptor_list) {
394 intercept->PostCallRecordCreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);
395 }
396 return result;
397}
398
399VKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback,
400 const VkAllocationCallbacks *pAllocator) {
401 instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), instance_layer_data_map);
402 for (auto intercept : global_interceptor_list) {
403 intercept->PreCallValidateDestroyDebugReportCallbackEXT(instance, callback, pAllocator);
404 }
405 for (auto intercept : global_interceptor_list) {
406 intercept->PreCallRecordDestroyDebugReportCallbackEXT(instance, callback, pAllocator);
407 }
408 instance_data->dispatch_table.DestroyDebugReportCallbackEXT(instance, callback, pAllocator);
409 layer_destroy_report_callback(instance_data->report_data, callback, pAllocator);
410 for (auto intercept : global_interceptor_list) {
411 intercept->PostCallRecordDestroyDebugReportCallbackEXT(instance, callback, pAllocator);
412 }
413}
414"""
415
416 inline_custom_source_postamble = """
417// loader-layer interface v0, just wrappers since there is only a layer
418
419VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
420 VkExtensionProperties *pProperties) {
421 return vulkan_layer_chassis::EnumerateInstanceExtensionProperties(pLayerName, pCount, pProperties);
422}
423
424VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount,
425 VkLayerProperties *pProperties) {
426 return vulkan_layer_chassis::EnumerateInstanceLayerProperties(pCount, pProperties);
427}
428
429VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
430 VkLayerProperties *pProperties) {
431 // the layer command handles VK_NULL_HANDLE just fine internally
432 assert(physicalDevice == VK_NULL_HANDLE);
433 return vulkan_layer_chassis::EnumerateDeviceLayerProperties(VK_NULL_HANDLE, pCount, pProperties);
434}
435
436VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
437 const char *pLayerName, uint32_t *pCount,
438 VkExtensionProperties *pProperties) {
439 // the layer command handles VK_NULL_HANDLE just fine internally
440 assert(physicalDevice == VK_NULL_HANDLE);
441 return vulkan_layer_chassis::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
442}
443
444VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
445 return vulkan_layer_chassis::GetDeviceProcAddr(dev, funcName);
446}
447
448VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
449 return vulkan_layer_chassis::GetInstanceProcAddr(instance, funcName);
450}
451
452VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance,
453 const char *funcName) {
454 return vulkan_layer_chassis::GetPhysicalDeviceProcAddr(instance, funcName);
455}
456
457VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
458 assert(pVersionStruct != NULL);
459 assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
460
461 // Fill in the function pointers if our version is at least capable of having the structure contain them.
462 if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
463 pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
464 pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
465 pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
466 }
467
468 return VK_SUCCESS;
469}"""
470
471
472
473
474
475 def __init__(self,
476 errFile = sys.stderr,
477 warnFile = sys.stderr,
478 diagFile = sys.stdout):
479 OutputGenerator.__init__(self, errFile, warnFile, diagFile)
480 # Internal state - accumulators for different inner block text
481 self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
482 self.intercepts = []
483 self.layer_factory = '' # String containing base layer factory class definition
484
485 # Check if the parameter passed in is a pointer to an array
486 def paramIsArray(self, param):
487 return param.attrib.get('len') is not None
488
489 # Check if the parameter passed in is a pointer
490 def paramIsPointer(self, param):
491 ispointer = False
492 for elem in param:
493 if ((elem.tag is not 'type') and (elem.tail is not None)) and '*' in elem.tail:
494 ispointer = True
495 return ispointer
496
497 # Check if an object is a non-dispatchable handle
498 def isHandleTypeNonDispatchable(self, handletype):
499 handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
500 if handle is not None and handle.find('type').text == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE':
501 return True
502 else:
503 return False
504
505 # Check if an object is a dispatchable handle
506 def isHandleTypeDispatchable(self, handletype):
507 handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
508 if handle is not None and handle.find('type').text == 'VK_DEFINE_HANDLE':
509 return True
510 else:
511 return False
512
513 def beginFile(self, genOpts):
514 OutputGenerator.beginFile(self, genOpts)
515 # Multiple inclusion protection & C++ namespace.
516 self.header = False
517 if (self.genOpts.filename and 'h' == self.genOpts.filename[-1]):
518 self.header = True
519 write('#pragma once', file=self.outFile)
520 self.newline()
521 # User-supplied prefix text, if any (list of strings)
522 if self.header:
523 if (genOpts.prefixText):
524 for s in genOpts.prefixText:
525 write(s, file=self.outFile)
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600526 write('#include <mutex>', file=self.outFile)
527 write('#include <cinttypes>', file=self.outFile)
528 write('#include <stdio.h>', file=self.outFile)
529 write('#include <stdlib.h>', file=self.outFile)
530 write('#include <string.h>', file=self.outFile)
531 write('#include <unordered_map>', file=self.outFile)
532 write('#include <unordered_set>', file=self.outFile)
533
534 write('#include "vk_loader_platform.h"', file=self.outFile)
535 write('#include "vulkan/vulkan.h"', file=self.outFile)
536 write('#include "vk_layer_config.h"', file=self.outFile)
537 write('#include "vk_layer_data.h"', file=self.outFile)
538 write('#include "vk_layer_logging.h"', file=self.outFile)
539 write('#include "vk_object_types.h"', file=self.outFile)
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600540 write('#include "vulkan/vk_layer.h"', file=self.outFile)
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600541 write('#include "vk_enum_string_helper.h"', file=self.outFile)
542 write('#include "vk_layer_extension_utils.h"', file=self.outFile)
543 write('#include "vk_layer_utils.h"', file=self.outFile)
544 write('#include "vulkan/vk_layer.h"', file=self.outFile)
545 write('#include "vk_dispatch_table_helper.h"', file=self.outFile)
546 write('#include "vk_validation_error_messages.h"', file=self.outFile)
547 write('#include "vk_extension_helper.h"', file=self.outFile)
548 write('', file=self.outFile)
549
550
551 # TODO: Need some ifdef code here for which layer is being built!
552 write('#include "object_lifetimes.h"', file=self.outFile)
553 write('', file=self.outFile)
554
555 write('struct instance_layer_data {', file=self.outFile)
556 write(' VkLayerInstanceDispatchTable dispatch_table;', file=self.outFile)
557 write(' VkInstance instance = VK_NULL_HANDLE;', file=self.outFile)
558 write(' debug_report_data *report_data = nullptr;', file=self.outFile)
559 write(' std::vector<VkDebugReportCallbackEXT> logging_callback;', file=self.outFile)
560 write(' std::vector<VkDebugUtilsMessengerEXT> logging_messenger;', file=self.outFile)
561 write(' InstanceExtensions extensions;', file=self.outFile)
562 write('', file=self.outFile)
563 # TODO: Need some ifdef code here for which layer is being built!
564 write(' object_lifetime objdata;', file=self.outFile)
565 write('};', file=self.outFile)
566 write('', file=self.outFile)
567 write('struct layer_data {', file=self.outFile)
568 write(' debug_report_data *report_data = nullptr;', file=self.outFile)
569 write(' VkLayerDispatchTable dispatch_table;', file=self.outFile)
570 write(' DeviceExtensions extensions = {};', file=self.outFile)
571 write(' VkDevice device = VK_NULL_HANDLE;', file=self.outFile)
572 write(' VkPhysicalDevice physical_device = VK_NULL_HANDLE;', file=self.outFile)
573 write(' instance_layer_data *instance_data = nullptr;', file=self.outFile)
574 write('', file=self.outFile)
575 # TODO: Need some ifdef code here for which layer is being built!
576 write(' object_lifetime objdata;', file=self.outFile)
577 write('};', file=self.outFile)
578 write('', file=self.outFile)
579 write('extern std::unordered_map<void *, layer_data *> layer_data_map;', file=self.outFile)
580 write('extern std::unordered_map<void *, instance_layer_data *> instance_layer_data_map;', file=self.outFile)
581 write('', file=self.outFile)
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600582 write('class layer_chassis;', file=self.outFile)
583 write('extern std::vector<layer_chassis *> global_interceptor_list;', file=self.outFile)
584 write('extern debug_report_data *report_data;\n', file=self.outFile)
585 write('namespace vulkan_layer_chassis {\n', file=self.outFile)
586 else:
587 write(self.inline_custom_source_preamble, file=self.outFile)
588
589 # Initialize Enum Section
590 self.layer_factory += '// Layer Factory base class definition\n'
591 self.layer_factory += 'class layer_chassis {\n'
592 self.layer_factory += ' public:\n'
593 self.layer_factory += ' layer_chassis() {\n'
594 self.layer_factory += ' global_interceptor_list.emplace_back(this);\n'
595 self.layer_factory += ' };\n'
596 self.layer_factory += '\n'
597 self.layer_factory += ' std::string layer_name = "CHASSIS";\n'
598 self.layer_factory += '\n'
599 self.layer_factory += ' // Pre/post hook point declarations\n'
600 #
601 def endFile(self):
602 # Finish C++ namespace and multiple inclusion protection
603 self.newline()
604 if not self.header:
605 # Record intercepted procedures
606 write('// Map of all APIs to be intercepted by this layer', file=self.outFile)
607 write('const std::unordered_map<std::string, void*> name_to_funcptr_map = {', file=self.outFile)
608 write('\n'.join(self.intercepts), file=self.outFile)
609 write('};\n', file=self.outFile)
610 self.newline()
611 write('} // namespace vulkan_layer_chassis', file=self.outFile)
612 if self.header:
613 self.newline()
614 # Output Layer Factory Class Definitions
615 self.layer_factory += '};\n'
616 write(self.layer_factory, file=self.outFile)
617 else:
618 write(self.inline_custom_source_postamble, file=self.outFile)
619 # Finish processing in superclass
620 OutputGenerator.endFile(self)
621
622 def beginFeature(self, interface, emit):
623 # Start processing in superclass
624 OutputGenerator.beginFeature(self, interface, emit)
625 # Get feature extra protect
626 self.featureExtraProtect = GetFeatureProtect(interface)
627 # Accumulate includes, defines, types, enums, function pointer typedefs, end function prototypes separately for this
628 # feature. They're only printed in endFeature().
629 self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
630
631 def endFeature(self):
632 # Actually write the interface to the output file.
633 if (self.emit):
634 self.newline()
635 # If type declarations are needed by other features based on this one, it may be necessary to suppress the ExtraProtect,
636 # or move it below the 'for section...' loop.
637 if (self.featureExtraProtect != None):
638 write('#ifdef', self.featureExtraProtect, file=self.outFile)
639 for section in self.TYPE_SECTIONS:
640 contents = self.sections[section]
641 if contents:
642 write('\n'.join(contents), file=self.outFile)
643 self.newline()
644 if (self.sections['command']):
645 write('\n'.join(self.sections['command']), end=u'', file=self.outFile)
646 self.newline()
647 if (self.featureExtraProtect != None):
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600648 write('#endif //', self.featureExtraProtect, file=self.outFile)
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600649 # Finish processing in superclass
650 OutputGenerator.endFeature(self)
651 #
652 # Append a definition to the specified section
653 def appendSection(self, section, text):
654 self.sections[section].append(text)
655 #
656 # Type generation
657 def genType(self, typeinfo, name, alias):
658 pass
659 #
660 # Struct (e.g. C "struct" type) generation. This is a special case of the <type> tag where the contents are
661 # interpreted as a set of <member> tags instead of freeform C type declarations. The <member> tags are just like <param>
662 # tags - they are a declaration of a struct or union member. Only simple member declarations are supported (no nested
663 # structs etc.)
664 def genStruct(self, typeinfo, typeName):
665 OutputGenerator.genStruct(self, typeinfo, typeName)
666 body = 'typedef ' + typeinfo.elem.get('category') + ' ' + typeName + ' {\n'
667 # paramdecl = self.makeCParamDecl(typeinfo.elem, self.genOpts.alignFuncParam)
668 for member in typeinfo.elem.findall('.//member'):
669 body += self.makeCParamDecl(member, self.genOpts.alignFuncParam)
670 body += ';\n'
671 body += '} ' + typeName + ';\n'
672 self.appendSection('struct', body)
673 #
674 # Group (e.g. C "enum" type) generation. These are concatenated together with other types.
675 def genGroup(self, groupinfo, groupName, alias):
676 pass
677 # Enumerant generation
678 # <enum> tags may specify their values in several ways, but are usually just integers.
679 def genEnum(self, enuminfo, name, alias):
680 pass
681 #
682 # Customize Cdecl for layer factory base class
683 def BaseClassCdecl(self, elem, name):
684 raw = self.makeCDecls(elem)[1]
685
686 # Toss everything before the undecorated name
687 prototype = raw.split("VKAPI_PTR *PFN_vk")[1]
688 prototype = prototype.replace(")", "", 1)
689 prototype = prototype.replace(";", " {};")
690
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600691 # Build up pre/post call virtual function declarations
692 pre_call_validate = 'virtual bool PreCallValidate' + prototype
693 pre_call_validate = pre_call_validate.replace("{}", " { return false; }")
694 pre_call_record = 'virtual void PreCallRecord' + prototype
695 post_call_record = 'virtual void PostCallRecord' + prototype
696 return ' %s\n %s\n %s\n' % (pre_call_validate, pre_call_record, post_call_record)
697 #
698 # Command generation
699 def genCmd(self, cmdinfo, name, alias):
700 ignore_functions = [
701 'vkEnumerateInstanceVersion'
702 ]
703
704 if name in ignore_functions:
705 return
706
707 if self.header: # In the header declare all intercepts
708 self.appendSection('command', '')
709 self.appendSection('command', self.makeCDecls(cmdinfo.elem)[0])
710 if (self.featureExtraProtect != None):
711 self.intercepts += [ '#ifdef %s' % self.featureExtraProtect ]
712 self.layer_factory += '#ifdef %s\n' % self.featureExtraProtect
713 # Update base class with virtual function declarations
714 self.layer_factory += self.BaseClassCdecl(cmdinfo.elem, name)
715 # Update function intercepts
716 self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ]
717 if (self.featureExtraProtect != None):
718 self.intercepts += [ '#endif' ]
719 self.layer_factory += '#endif\n'
720 return
721
722 manual_functions = [
723 # Include functions here to be interecpted w/ manually implemented function bodies
724 'vkGetDeviceProcAddr',
725 'vkGetInstanceProcAddr',
726 'vkGetPhysicalDeviceProcAddr',
727 'vkCreateDevice',
728 'vkDestroyDevice',
729 'vkCreateInstance',
730 'vkDestroyInstance',
731 'vkCreateDebugReportCallbackEXT',
732 'vkDestroyDebugReportCallbackEXT',
733 'vkEnumerateInstanceLayerProperties',
734 'vkEnumerateInstanceExtensionProperties',
735 'vkEnumerateDeviceLayerProperties',
736 'vkEnumerateDeviceExtensionProperties',
737 ]
738 if name in manual_functions:
739 self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ]
740 return
741 # Record that the function will be intercepted
742 if (self.featureExtraProtect != None):
743 self.intercepts += [ '#ifdef %s' % self.featureExtraProtect ]
744 self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ]
745 if (self.featureExtraProtect != None):
746 self.intercepts += [ '#endif' ]
747 OutputGenerator.genCmd(self, cmdinfo, name, alias)
748 #
749 decls = self.makeCDecls(cmdinfo.elem)
750 self.appendSection('command', '')
751 self.appendSection('command', '%s {' % decls[0][:-1])
752 # Setup common to call wrappers. First parameter is always dispatchable
753 dispatchable_type = cmdinfo.elem.find('param/type').text
754 dispatchable_name = cmdinfo.elem.find('param/name').text
755 # Default to device
756 device_or_instance = 'device'
757 map_name = 'layer_data'
758 dispatch_table_name = 'VkLayerDispatchTable'
759 # Set to instance as necessary
760 if dispatchable_type in ["VkPhysicalDevice", "VkInstance"] or name == 'vkCreateInstance':
761 device_or_instance = 'instance'
762 dispatch_table_name = 'VkLayerInstanceDispatchTable'
763 map_name = 'instance_layer_data'
764 self.appendSection('command', ' %s *%s_data = GetLayerDataPtr(get_dispatch_key(%s), %s_map);' % (map_name, device_or_instance, dispatchable_name, map_name))
765 api_function_name = cmdinfo.elem.attrib.get('name')
766 params = cmdinfo.elem.findall('param/name')
767 paramstext = ', '.join([str(param.text) for param in params])
768 API = api_function_name.replace('vk','%s_data->dispatch_table.' % (device_or_instance),1)
769
770 # Declare result variable, if any.
771 return_map = {
772 'void': 'return;',
773 'VkResult': 'return VK_ERROR_VALIDATION_FAILED_EXT;',
774 'PFN_vkVoidFunction': 'return nullptr;',
775 'VkBool32': 'return VK_FALSE;',
776 }
777 resulttype = cmdinfo.elem.find('proto/type')
778 assignresult = ''
779 if (resulttype.text != 'void'):
780 assignresult = resulttype.text + ' result = '
781
782 # Set up skip and locking
783 self.appendSection('command', ' {')
784 self.appendSection('command', ' bool skip = false;')
785 self.appendSection('command', ' std::lock_guard<std::mutex> lock(global_lock);')
786
787 # Generate pre-call validation source code
788 self.appendSection('command', ' for (auto intercept : global_interceptor_list) {')
789 self.appendSection('command', ' skip |= intercept->PreCallValidate%s(%s);' % (api_function_name[2:], paramstext))
790 self.appendSection('command', ' if (skip) %s' % return_map[resulttype.text])
791 self.appendSection('command', ' }')
792
793 # Generate pre-call state recording source code
794 self.appendSection('command', ' for (auto intercept : global_interceptor_list) {')
795 self.appendSection('command', ' intercept->PreCallRecord%s(%s);' % (api_function_name[2:], paramstext))
796 self.appendSection('command', ' }')
797 self.appendSection('command', ' }')
798
799 self.appendSection('command', ' ' + assignresult + API + '(' + paramstext + ');')
800
801 # Generate post-call object processing source code
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600802 return_check = ''
803 if (resulttype.text == 'VkResult'):
804 return_check = 'if (VK_SUCCESS == result) '
805 self.appendSection('command', ' %s{' % return_check)
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600806 self.appendSection('command', ' std::lock_guard<std::mutex> lock(global_lock);')
807 self.appendSection('command', ' for (auto intercept : global_interceptor_list) {')
808 self.appendSection('command', ' intercept->PostCallRecord%s(%s);' % (api_function_name[2:], paramstext))
809 self.appendSection('command', ' }')
810 self.appendSection('command', ' }')
811
812 # Return result variable, if any.
813 if (resulttype.text != 'void'):
814 self.appendSection('command', ' return result;')
815 self.appendSection('command', '}')
816 #
817 # Override makeProtoName to drop the "vk" prefix
818 def makeProtoName(self, name, tail):
819 return self.genOpts.apientry + name[2:] + tail