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