blob: c85dc7feed666a6d6ccc16bd69b679d382fc957e [file] [log] [blame]
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -06001#!/usr/bin/python3 -i
2#
Mark Lobodzinskid939fcb2019-01-10 15:49:12 -07003# Copyright (c) 2015-2019 Valve Corporation
4# Copyright (c) 2015-2019 LunarG, Inc.
5# Copyright (c) 2015-2019 Google Inc.
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -06006#
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
Mark Lobodzinski09f86362018-12-13 14:07:20 -0700126 manual_functions = [
127 # Include functions here to be interecpted w/ manually implemented function bodies
128 'vkGetDeviceProcAddr',
129 'vkGetInstanceProcAddr',
130 'vkGetPhysicalDeviceProcAddr',
131 'vkCreateDevice',
132 'vkDestroyDevice',
133 'vkCreateInstance',
134 'vkDestroyInstance',
135 'vkCreateDebugReportCallbackEXT',
136 'vkDestroyDebugReportCallbackEXT',
137 'vkEnumerateInstanceLayerProperties',
138 'vkEnumerateInstanceExtensionProperties',
139 'vkEnumerateDeviceLayerProperties',
140 'vkEnumerateDeviceExtensionProperties',
141 ]
142
143 alt_ret_codes = [
144 # Include functions here which must tolerate VK_INCOMPLETE as a return code
145 'vkEnumeratePhysicalDevices',
146 'vkEnumeratePhysicalDeviceGroupsKHR',
147 'vkGetValidationCacheDataEXT',
148 'vkGetPipelineCacheData',
149 'vkGetShaderInfoAMD',
150 'vkGetPhysicalDeviceDisplayPropertiesKHR',
151 'vkGetPhysicalDeviceDisplayProperties2KHR',
152 'vkGetPhysicalDeviceDisplayPlanePropertiesKHR',
153 'vkGetDisplayPlaneSupportedDisplaysKHR',
154 'vkGetDisplayModePropertiesKHR',
155 'vkGetDisplayModeProperties2KHR',
156 'vkGetPhysicalDeviceSurfaceFormatsKHR',
157 'vkGetPhysicalDeviceSurfacePresentModesKHR',
158 'vkGetPhysicalDevicePresentRectanglesKHR',
159 'vkGetPastPresentationTimingGOOGLE',
160 'vkGetSwapchainImagesKHR',
161 'vkEnumerateInstanceLayerProperties',
162 'vkEnumerateDeviceLayerProperties',
163 'vkEnumerateInstanceExtensionProperties',
164 'vkEnumerateDeviceExtensionProperties',
165 'vkGetPhysicalDeviceCalibrateableTimeDomainsEXT',
166 ]
167
Mark Lobodzinskif57e8282018-12-13 11:34:33 -0700168 pre_dispatch_debug_utils_functions = {
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -0700169 'vkDebugMarkerSetObjectNameEXT' : 'layer_data->report_data->DebugReportSetMarkerObjectName(pNameInfo);',
170 'vkSetDebugUtilsObjectNameEXT' : 'layer_data->report_data->DebugReportSetUtilsObjectName(pNameInfo);',
Mark Lobodzinskif57e8282018-12-13 11:34:33 -0700171 'vkQueueBeginDebugUtilsLabelEXT' : 'BeginQueueDebugUtilsLabel(layer_data->report_data, queue, pLabelInfo);',
172 'vkQueueInsertDebugUtilsLabelEXT' : 'InsertQueueDebugUtilsLabel(layer_data->report_data, queue, pLabelInfo);',
173 'vkCmdBeginDebugUtilsLabelEXT' : 'BeginCmdDebugUtilsLabel(layer_data->report_data, commandBuffer, pLabelInfo);',
174 'vkCmdInsertDebugUtilsLabelEXT' : 'InsertCmdDebugUtilsLabel(layer_data->report_data, commandBuffer, pLabelInfo);'
175 }
176
177 post_dispatch_debug_utils_functions = {
178 'vkQueueEndDebugUtilsLabelEXT' : 'EndQueueDebugUtilsLabel(layer_data->report_data, queue);',
179 'vkCmdEndDebugUtilsLabelEXT' : 'EndCmdDebugUtilsLabel(layer_data->report_data, commandBuffer);',
180 'vkCmdInsertDebugUtilsLabelEXT' : 'InsertCmdDebugUtilsLabel(layer_data->report_data, commandBuffer, pLabelInfo);'
181 }
182
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600183 precallvalidate_loop = "for (auto intercept : layer_data->object_dispatch) {"
184 precallrecord_loop = precallvalidate_loop
185 postcallrecord_loop = "for (auto intercept : layer_data->object_dispatch) {"
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600186
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700187 inline_custom_header_preamble = """
188#define NOMINMAX
189#include <mutex>
190#include <cinttypes>
191#include <stdio.h>
192#include <stdlib.h>
193#include <string.h>
194#include <unordered_map>
195#include <unordered_set>
196#include <algorithm>
197#include <memory>
198
199#include "vk_loader_platform.h"
200#include "vulkan/vulkan.h"
201#include "vk_layer_config.h"
202#include "vk_layer_data.h"
203#include "vk_layer_logging.h"
204#include "vk_object_types.h"
205#include "vulkan/vk_layer.h"
206#include "vk_enum_string_helper.h"
207#include "vk_layer_extension_utils.h"
208#include "vk_layer_utils.h"
209#include "vulkan/vk_layer.h"
210#include "vk_dispatch_table_helper.h"
211#include "vk_validation_error_messages.h"
212#include "vk_extension_helper.h"
213#include "vk_safe_struct.h"
214
215extern uint64_t global_unique_id;
216extern std::unordered_map<uint64_t, uint64_t> unique_id_mapping;
217"""
218
219 inline_custom_header_class_definition = """
220
221// Layer object type identifiers
222enum LayerObjectTypeId {
223 LayerObjectTypeThreading,
224 LayerObjectTypeParameterValidation,
225 LayerObjectTypeObjectTracker,
226 LayerObjectTypeCoreValidation,
227};
228
229struct TEMPLATE_STATE {
230 VkDescriptorUpdateTemplateKHR desc_update_template;
231 safe_VkDescriptorUpdateTemplateCreateInfo create_info;
232
233 TEMPLATE_STATE(VkDescriptorUpdateTemplateKHR update_template, safe_VkDescriptorUpdateTemplateCreateInfo *pCreateInfo)
234 : desc_update_template(update_template), create_info(*pCreateInfo) {}
235};
236
Mark Lobodzinskicc4e4a22018-12-18 16:16:21 -0700237class LAYER_PHYS_DEV_PROPERTIES {
238public:
239 VkPhysicalDeviceProperties properties;
240 std::vector<VkQueueFamilyProperties> queue_family_properties;
241};
242
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700243// Layer chassis validation object base class definition
244class ValidationObject {
245 public:
246 uint32_t api_version;
247 debug_report_data* report_data = nullptr;
248 std::vector<VkDebugReportCallbackEXT> logging_callback;
249 std::vector<VkDebugUtilsMessengerEXT> logging_messenger;
250
251 VkLayerInstanceDispatchTable instance_dispatch_table;
252 VkLayerDispatchTable device_dispatch_table;
253
254 InstanceExtensions instance_extensions;
255 DeviceExtensions device_extensions = {};
256
257 VkInstance instance = VK_NULL_HANDLE;
258 VkPhysicalDevice physical_device = VK_NULL_HANDLE;
259 VkDevice device = VK_NULL_HANDLE;
Mark Lobodzinskicc4e4a22018-12-18 16:16:21 -0700260 LAYER_PHYS_DEV_PROPERTIES phys_dev_properties = {};
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700261
262 std::vector<ValidationObject*> object_dispatch;
263 LayerObjectTypeId container_type;
264
265 // Constructor
266 ValidationObject(){};
267 // Destructor
268 virtual ~ValidationObject() {};
269
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700270 std::mutex validation_object_mutex;
Jeremy Hayesd4a3ec32019-01-29 14:42:08 -0700271 virtual std::unique_lock<std::mutex> write_lock() {
272 return std::unique_lock<std::mutex>(validation_object_mutex);
273 }
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700274
Mark Lobodzinski64b39c12018-12-25 10:01:48 -0700275 ValidationObject* GetValidationObject(std::vector<ValidationObject*>& object_dispatch, LayerObjectTypeId object_type) {
276 for (auto validation_object : object_dispatch) {
277 if (validation_object->container_type == object_type) {
278 return validation_object;
279 }
280 }
281 return nullptr;
282 };
283
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700284 std::string layer_name = "CHASSIS";
285
286 // Handle Wrapping Data
287 // Reverse map display handles
288 std::unordered_map<VkDisplayKHR, uint64_t> display_id_reverse_mapping;
289 std::unordered_map<uint64_t, std::unique_ptr<TEMPLATE_STATE>> desc_template_map;
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700290 struct SubpassesUsageStates {
291 std::unordered_set<uint32_t> subpasses_using_color_attachment;
292 std::unordered_set<uint32_t> subpasses_using_depthstencil_attachment;
293 };
294 // Uses unwrapped handles
295 std::unordered_map<VkRenderPass, SubpassesUsageStates> renderpasses_states;
296 // Map of wrapped swapchain handles to arrays of wrapped swapchain image IDs
297 // Each swapchain has an immutable list of wrapped swapchain image IDs -- always return these IDs if they exist
298 std::unordered_map<VkSwapchainKHR, std::vector<VkImage>> swapchain_wrapped_image_handle_map;
Mike Schuchardt1df790d2018-12-11 16:24:47 -0700299 // Map of wrapped descriptor pools to set of wrapped descriptor sets allocated from each pool
300 std::unordered_map<VkDescriptorPool, std::unordered_set<VkDescriptorSet>> pool_descriptor_sets_map;
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700301
302
303 // Unwrap a handle. Must hold lock.
304 template <typename HandleType>
305 HandleType Unwrap(HandleType wrappedHandle) {
306 // TODO: don't use operator[] here.
307 return (HandleType)unique_id_mapping[reinterpret_cast<uint64_t const &>(wrappedHandle)];
308 }
309
310 // Wrap a newly created handle with a new unique ID, and return the new ID -- must hold lock.
311 template <typename HandleType>
312 HandleType WrapNew(HandleType newlyCreatedHandle) {
313 auto unique_id = global_unique_id++;
314 unique_id_mapping[unique_id] = reinterpret_cast<uint64_t const &>(newlyCreatedHandle);
315 return (HandleType)unique_id;
316 }
317
318 // Specialized handling for VkDisplayKHR. Adds an entry to enable reverse-lookup. Must hold lock.
319 VkDisplayKHR WrapDisplay(VkDisplayKHR newlyCreatedHandle, ValidationObject *map_data) {
320 auto unique_id = global_unique_id++;
321 unique_id_mapping[unique_id] = reinterpret_cast<uint64_t const &>(newlyCreatedHandle);
322 map_data->display_id_reverse_mapping[newlyCreatedHandle] = unique_id;
323 return (VkDisplayKHR)unique_id;
324 }
325
326 // VkDisplayKHR objects don't have a single point of creation, so we need to see if one already exists in the map before
327 // creating another. Must hold lock.
328 VkDisplayKHR MaybeWrapDisplay(VkDisplayKHR handle, ValidationObject *map_data) {
329 // See if this display is already known
330 auto it = map_data->display_id_reverse_mapping.find(handle);
331 if (it != map_data->display_id_reverse_mapping.end()) return (VkDisplayKHR)it->second;
332 // Unknown, so wrap
333 return WrapDisplay(handle, map_data);
334 }
335
336 // Pre/post hook point declarations
337"""
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600338
Mark Lobodzinskid03ed352018-11-09 09:34:24 -0700339 inline_copyright_message = """
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600340// This file is ***GENERATED***. Do Not Edit.
341// See layer_chassis_generator.py for modifications.
342
Shannon McPherson9a4ae982019-01-07 16:05:25 -0700343/* Copyright (c) 2015-2019 The Khronos Group Inc.
344 * Copyright (c) 2015-2019 Valve Corporation
345 * Copyright (c) 2015-2019 LunarG, Inc.
346 * Copyright (c) 2015-2019 Google Inc.
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600347 *
348 * Licensed under the Apache License, Version 2.0 (the "License");
349 * you may not use this file except in compliance with the License.
350 * You may obtain a copy of the License at
351 *
352 * http://www.apache.org/licenses/LICENSE-2.0
353 *
354 * Unless required by applicable law or agreed to in writing, software
355 * distributed under the License is distributed on an "AS IS" BASIS,
356 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
357 * See the License for the specific language governing permissions and
358 * limitations under the License.
359 *
360 * Author: Mark Lobodzinski <mark@lunarg.com>
Mark Lobodzinskid03ed352018-11-09 09:34:24 -0700361 */"""
362
363 inline_custom_source_preamble = """
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600364
365#include <string.h>
366#include <mutex>
367
368#define VALIDATION_ERROR_MAP_IMPL
369
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600370#include "chassis.h"
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700371#include "layer_chassis_dispatch.h"
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600372
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600373std::unordered_map<void*, ValidationObject*> layer_data_map;
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600374
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700375// Global unique object identifier. All increments must be guarded by a lock.
376uint64_t global_unique_id = 1;
377// Map uniqueID to actual object handle
378std::unordered_map<uint64_t, uint64_t> unique_id_mapping;
379
380// TODO: This variable controls handle wrapping -- in the future it should be hooked
381// up to the new VALIDATION_FEATURES extension. Temporarily, control with a compile-time flag.
382#if defined(LAYER_CHASSIS_CAN_WRAP_HANDLES)
383bool wrap_handles = true;
384#else
385const bool wrap_handles = false;
386#endif
387
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600388// Include child object (layer) definitions
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700389#if BUILD_OBJECT_TRACKER
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600390#include "object_lifetime_validation.h"
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700391#define OBJECT_LAYER_NAME "VK_LAYER_LUNARG_object_tracker"
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700392#elif BUILD_THREAD_SAFETY
Mark Lobodzinski706e52b2018-12-11 13:21:52 -0700393#include "thread_safety.h"
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700394#define OBJECT_LAYER_NAME "VK_LAYER_GOOGLE_threading"
395#elif BUILD_PARAMETER_VALIDATION
Mark Lobodzinskiaf7c0382018-12-18 11:55:55 -0700396#include "stateless_validation.h"
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700397#define OBJECT_LAYER_NAME "VK_LAYER_LUNARG_parameter_validation"
398#elif BUILD_CORE_VALIDATION
399#define OBJECT_LAYER_NAME "VK_LAYER_LUNARG_core_validation"
400#else
401#define OBJECT_LAYER_NAME "VK_LAYER_GOOGLE_unique_objects"
402#endif
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600403
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600404namespace vulkan_layer_chassis {
405
406using std::unordered_map;
407
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600408static const VkLayerProperties global_layer = {
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700409 OBJECT_LAYER_NAME, VK_LAYER_API_VERSION, 1, "LunarG validation Layer",
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600410};
411
412static const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
413
414extern const std::unordered_map<std::string, void*> name_to_funcptr_map;
415
416
417// Manually written functions
418
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700419// Check enabled instance extensions against supported instance extension whitelist
420static void InstanceExtensionWhitelist(ValidationObject *layer_data, const VkInstanceCreateInfo *pCreateInfo, VkInstance instance) {
421 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
422 // Check for recognized instance extensions
423 if (!white_list(pCreateInfo->ppEnabledExtensionNames[i], kInstanceExtensionNames)) {
424 log_msg(layer_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
425 kVUIDUndefined,
426 "Instance Extension %s is not supported by this layer. Using this extension may adversely affect validation "
427 "results and/or produce undefined behavior.",
428 pCreateInfo->ppEnabledExtensionNames[i]);
429 }
430 }
431}
432
433// Check enabled device extensions against supported device extension whitelist
434static void DeviceExtensionWhitelist(ValidationObject *layer_data, const VkDeviceCreateInfo *pCreateInfo, VkDevice device) {
435 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
436 // Check for recognized device extensions
437 if (!white_list(pCreateInfo->ppEnabledExtensionNames[i], kDeviceExtensionNames)) {
438 log_msg(layer_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
439 kVUIDUndefined,
440 "Device Extension %s is not supported by this layer. Using this extension may adversely affect validation "
441 "results and/or produce undefined behavior.",
442 pCreateInfo->ppEnabledExtensionNames[i]);
443 }
444 }
445}
446
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600447VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) {
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600448 auto layer_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
Mark Lobodzinskicc4e4a22018-12-18 16:16:21 -0700449 if (!ApiParentExtensionEnabled(funcName, layer_data->device_extensions.device_extension_set)) {
Mark Lobodzinski2fc88fe2018-12-11 12:28:57 -0700450 return nullptr;
451 }
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600452 const auto &item = name_to_funcptr_map.find(funcName);
453 if (item != name_to_funcptr_map.end()) {
454 return reinterpret_cast<PFN_vkVoidFunction>(item->second);
455 }
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600456 auto &table = layer_data->device_dispatch_table;
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600457 if (!table.GetDeviceProcAddr) return nullptr;
458 return table.GetDeviceProcAddr(device, funcName);
459}
460
461VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName) {
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600462 const auto &item = name_to_funcptr_map.find(funcName);
463 if (item != name_to_funcptr_map.end()) {
464 return reinterpret_cast<PFN_vkVoidFunction>(item->second);
465 }
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600466 auto layer_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
467 auto &table = layer_data->instance_dispatch_table;
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600468 if (!table.GetInstanceProcAddr) return nullptr;
469 return table.GetInstanceProcAddr(instance, funcName);
470}
471
472VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600473 auto layer_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
474 auto &table = layer_data->instance_dispatch_table;
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600475 if (!table.GetPhysicalDeviceProcAddr) return nullptr;
476 return table.GetPhysicalDeviceProcAddr(instance, funcName);
477}
478
479VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
480 return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
481}
482
483VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
484 VkLayerProperties *pProperties) {
485 return util_GetLayerProperties(1, &global_layer, pCount, pProperties);
486}
487
488VKAPI_ATTR VkResult VKAPI_CALL EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
489 VkExtensionProperties *pProperties) {
490 if (pLayerName && !strcmp(pLayerName, global_layer.layerName))
491 return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties);
492
493 return VK_ERROR_LAYER_NOT_PRESENT;
494}
495
496VKAPI_ATTR VkResult VKAPI_CALL EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName,
497 uint32_t *pCount, VkExtensionProperties *pProperties) {
498 if (pLayerName && !strcmp(pLayerName, global_layer.layerName)) return util_GetExtensionProperties(0, NULL, pCount, pProperties);
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600499 assert(physicalDevice);
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600500 auto layer_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), layer_data_map);
501 return layer_data->instance_dispatch_table.EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600502}
503
504VKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
505 VkInstance *pInstance) {
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600506 VkLayerInstanceCreateInfo* chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600507
508 assert(chain_info->u.pLayerInfo);
509 PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
510 PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
511 if (fpCreateInstance == NULL) return VK_ERROR_INITIALIZATION_FAILED;
512 chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
Mark Lobodzinskic1608f22019-01-11 14:47:55 -0700513 uint32_t specified_version = (pCreateInfo->pApplicationInfo ? pCreateInfo->pApplicationInfo->apiVersion : VK_API_VERSION_1_0);
514 uint32_t api_version = (specified_version < VK_API_VERSION_1_1) ? VK_API_VERSION_1_0 : VK_API_VERSION_1_1;
515
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600516
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600517 // Create temporary dispatch vector for pre-calls until instance is created
518 std::vector<ValidationObject*> local_object_dispatch;
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700519#if BUILD_OBJECT_TRACKER
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600520 auto object_tracker = new ObjectLifetimes;
521 local_object_dispatch.emplace_back(object_tracker);
522 object_tracker->container_type = LayerObjectTypeObjectTracker;
Mark Lobodzinskic1608f22019-01-11 14:47:55 -0700523 object_tracker->api_version = api_version;
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700524#elif BUILD_THREAD_SAFETY
525 auto thread_checker = new ThreadSafety;
526 local_object_dispatch.emplace_back(thread_checker);
527 thread_checker->container_type = LayerObjectTypeThreading;
Mark Lobodzinskic1608f22019-01-11 14:47:55 -0700528 thread_checker->api_version = api_version;
Mark Lobodzinskiaf7c0382018-12-18 11:55:55 -0700529#elif BUILD_PARAMETER_VALIDATION
530 auto parameter_validation = new StatelessValidation;
531 local_object_dispatch.emplace_back(parameter_validation);
532 parameter_validation->container_type = LayerObjectTypeParameterValidation;
Mark Lobodzinskic1608f22019-01-11 14:47:55 -0700533 parameter_validation->api_version = api_version;
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700534#endif
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600535
536
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600537 // Init dispatch array and call registration functions
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600538 for (auto intercept : local_object_dispatch) {
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600539 intercept->PreCallValidateCreateInstance(pCreateInfo, pAllocator, pInstance);
540 }
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600541 for (auto intercept : local_object_dispatch) {
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600542 intercept->PreCallRecordCreateInstance(pCreateInfo, pAllocator, pInstance);
543 }
544
545 VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600546 if (result != VK_SUCCESS) return result;
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600547
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600548 auto framework = GetLayerDataPtr(get_dispatch_key(*pInstance), layer_data_map);
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600549
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600550 framework->object_dispatch = local_object_dispatch;
551
552 framework->instance = *pInstance;
553 layer_init_instance_dispatch_table(*pInstance, &framework->instance_dispatch_table, fpGetInstanceProcAddr);
554 framework->report_data = debug_utils_create_instance(&framework->instance_dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount,
555 pCreateInfo->ppEnabledExtensionNames);
Mark Lobodzinskic1608f22019-01-11 14:47:55 -0700556 framework->api_version = api_version;
557 framework->instance_extensions.InitFromInstanceCreateInfo(specified_version, pCreateInfo);
558
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700559#if BUILD_OBJECT_TRACKER
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600560 layer_debug_messenger_actions(framework->report_data, framework->logging_messenger, pAllocator, "lunarg_object_tracker");
Mark Lobodzinskiaf7c0382018-12-18 11:55:55 -0700561 object_tracker->report_data = framework->report_data;
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700562#elif BUILD_THREAD_SAFETY
563 layer_debug_messenger_actions(framework->report_data, framework->logging_messenger, pAllocator, "google_thread_checker");
Mark Lobodzinskiaf7c0382018-12-18 11:55:55 -0700564 thread_checker->report_data = framework->report_data;
Mark Lobodzinskiaf7c0382018-12-18 11:55:55 -0700565#elif BUILD_PARAMETER_VALIDATION
566 layer_debug_messenger_actions(framework->report_data, framework->logging_messenger, pAllocator, "lunarg_parameter_validation");
567 parameter_validation->report_data = framework->report_data;
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700568#else
569 layer_debug_messenger_actions(framework->report_data, framework->logging_messenger, pAllocator, "lunarg_unique_objects");
570#endif
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600571
572 for (auto intercept : framework->object_dispatch) {
Mark Lobodzinskicd05c1e2019-01-17 15:33:46 -0700573 intercept->PostCallRecordCreateInstance(pCreateInfo, pAllocator, pInstance, result);
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600574 }
575
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700576 InstanceExtensionWhitelist(framework, pCreateInfo, *pInstance);
577
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600578 return result;
579}
580
581VKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
582 dispatch_key key = get_dispatch_key(instance);
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600583 auto layer_data = GetLayerDataPtr(key, layer_data_map);
584 """ + precallvalidate_loop + """
Jeremy Hayesd4a3ec32019-01-29 14:42:08 -0700585 auto lock = intercept->write_lock();
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600586 intercept->PreCallValidateDestroyInstance(instance, pAllocator);
587 }
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600588 """ + precallrecord_loop + """
Jeremy Hayesd4a3ec32019-01-29 14:42:08 -0700589 auto lock = intercept->write_lock();
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600590 intercept->PreCallRecordDestroyInstance(instance, pAllocator);
591 }
592
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600593 layer_data->instance_dispatch_table.DestroyInstance(instance, pAllocator);
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600594
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600595 """ + postcallrecord_loop + """
Jeremy Hayesd4a3ec32019-01-29 14:42:08 -0700596 auto lock = intercept->write_lock();
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600597 intercept->PostCallRecordDestroyInstance(instance, pAllocator);
598 }
599 // Clean up logging callback, if any
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600600 while (layer_data->logging_messenger.size() > 0) {
601 VkDebugUtilsMessengerEXT messenger = layer_data->logging_messenger.back();
602 layer_destroy_messenger_callback(layer_data->report_data, messenger, pAllocator);
603 layer_data->logging_messenger.pop_back();
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600604 }
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600605 while (layer_data->logging_callback.size() > 0) {
606 VkDebugReportCallbackEXT callback = layer_data->logging_callback.back();
607 layer_destroy_report_callback(layer_data->report_data, callback, pAllocator);
608 layer_data->logging_callback.pop_back();
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600609 }
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600610
611 layer_debug_utils_destroy_instance(layer_data->report_data);
612
Mark Lobodzinskic5003372018-12-17 16:36:01 -0700613 for (auto item = layer_data->object_dispatch.begin(); item != layer_data->object_dispatch.end(); item++) {
614 delete *item;
615 }
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600616 FreeLayerDataPtr(key, layer_data_map);
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600617}
618
619VKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
620 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600621 VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600622
623 auto instance_interceptor = GetLayerDataPtr(get_dispatch_key(gpu), layer_data_map);
624
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600625 PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
626 PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600627 PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(instance_interceptor->instance, "vkCreateDevice");
628 if (fpCreateDevice == NULL) {
629 return VK_ERROR_INITIALIZATION_FAILED;
630 }
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600631 chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
632
Mark Lobodzinski0068bd82018-12-28 12:08:44 -0700633 // Get physical device limits for device
634 VkPhysicalDeviceProperties device_properties = {};
635 instance_interceptor->instance_dispatch_table.GetPhysicalDeviceProperties(gpu, &device_properties);
636
637 // Setup the validation tables based on the application API version from the instance and the capabilities of the device driver
638 uint32_t effective_api_version = std::min(device_properties.apiVersion, instance_interceptor->api_version);
639
640 DeviceExtensions device_extensions = {};
641 device_extensions.InitFromDeviceCreateInfo(&instance_interceptor->instance_extensions, effective_api_version, pCreateInfo);
642 for (auto item : instance_interceptor->object_dispatch) {
643 item->device_extensions = device_extensions;
644 }
645
646 bool skip = false;
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600647 for (auto intercept : instance_interceptor->object_dispatch) {
Jeremy Hayesd4a3ec32019-01-29 14:42:08 -0700648 auto lock = intercept->write_lock();
Mark Lobodzinski0068bd82018-12-28 12:08:44 -0700649 skip |= intercept->PreCallValidateCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
Mark Lobodzinski0068bd82018-12-28 12:08:44 -0700650 if (skip) return VK_ERROR_VALIDATION_FAILED_EXT;
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600651 }
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600652 for (auto intercept : instance_interceptor->object_dispatch) {
Jeremy Hayesd4a3ec32019-01-29 14:42:08 -0700653 auto lock = intercept->write_lock();
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600654 intercept->PreCallRecordCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
655 }
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600656
657 VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600658 if (result != VK_SUCCESS) {
659 return result;
660 }
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600661
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600662 auto device_interceptor = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
Mark Lobodzinskicc4e4a22018-12-18 16:16:21 -0700663
Mark Lobodzinski0068bd82018-12-28 12:08:44 -0700664 // Save local info in device object
665 device_interceptor->phys_dev_properties.properties = device_properties;
Mark Lobodzinskicc4e4a22018-12-18 16:16:21 -0700666 device_interceptor->api_version = device_interceptor->device_extensions.InitFromDeviceCreateInfo(
667 &instance_interceptor->instance_extensions, effective_api_version, pCreateInfo);
Mark Lobodzinski0068bd82018-12-28 12:08:44 -0700668 device_interceptor->device_extensions = device_extensions;
Mark Lobodzinskicc4e4a22018-12-18 16:16:21 -0700669
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600670 layer_init_device_dispatch_table(*pDevice, &device_interceptor->device_dispatch_table, fpGetDeviceProcAddr);
Mark Lobodzinskicc4e4a22018-12-18 16:16:21 -0700671
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600672 device_interceptor->device = *pDevice;
673 device_interceptor->physical_device = gpu;
674 device_interceptor->instance = instance_interceptor->instance;
675 device_interceptor->report_data = layer_debug_utils_create_device(instance_interceptor->report_data, *pDevice);
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600676
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700677#if BUILD_OBJECT_TRACKER
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600678 // Create child layer objects for this key and add to dispatch vector
679 auto object_tracker = new ObjectLifetimes;
680 // TODO: Initialize child objects with parent info thru constuctor taking a parent object
681 object_tracker->container_type = LayerObjectTypeObjectTracker;
682 object_tracker->physical_device = gpu;
683 object_tracker->instance = instance_interceptor->instance;
684 object_tracker->report_data = device_interceptor->report_data;
685 object_tracker->device_dispatch_table = device_interceptor->device_dispatch_table;
Mark Lobodzinskiaf7c0382018-12-18 11:55:55 -0700686 object_tracker->api_version = device_interceptor->api_version;
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600687 device_interceptor->object_dispatch.emplace_back(object_tracker);
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700688#elif BUILD_THREAD_SAFETY
689 auto thread_safety = new ThreadSafety;
690 // TODO: Initialize child objects with parent info thru constuctor taking a parent object
691 thread_safety->container_type = LayerObjectTypeThreading;
692 thread_safety->physical_device = gpu;
693 thread_safety->instance = instance_interceptor->instance;
694 thread_safety->report_data = device_interceptor->report_data;
695 thread_safety->device_dispatch_table = device_interceptor->device_dispatch_table;
Mark Lobodzinskiaf7c0382018-12-18 11:55:55 -0700696 thread_safety->api_version = device_interceptor->api_version;
Mark Lobodzinski1f2ba262018-12-04 14:15:47 -0700697 device_interceptor->object_dispatch.emplace_back(thread_safety);
Mark Lobodzinskiaf7c0382018-12-18 11:55:55 -0700698#elif BUILD_PARAMETER_VALIDATION
699 auto stateless_validation = new StatelessValidation;
700 // TODO: Initialize child objects with parent info thru constuctor taking a parent object
701 stateless_validation->container_type = LayerObjectTypeParameterValidation;
702 stateless_validation->physical_device = gpu;
703 stateless_validation->instance = instance_interceptor->instance;
704 stateless_validation->report_data = device_interceptor->report_data;
705 stateless_validation->device_dispatch_table = device_interceptor->device_dispatch_table;
706 stateless_validation->api_version = device_interceptor->api_version;
707 device_interceptor->object_dispatch.emplace_back(stateless_validation);
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700708#endif
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600709
710 for (auto intercept : instance_interceptor->object_dispatch) {
Jeremy Hayesd4a3ec32019-01-29 14:42:08 -0700711 auto lock = intercept->write_lock();
Mark Lobodzinskicd05c1e2019-01-17 15:33:46 -0700712 intercept->PostCallRecordCreateDevice(gpu, pCreateInfo, pAllocator, pDevice, result);
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600713 }
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600714
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700715 DeviceExtensionWhitelist(device_interceptor, pCreateInfo, *pDevice);
716
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600717 return result;
718}
719
720VKAPI_ATTR void VKAPI_CALL DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
721 dispatch_key key = get_dispatch_key(device);
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600722 auto layer_data = GetLayerDataPtr(key, layer_data_map);
723 """ + precallvalidate_loop + """
Jeremy Hayesd4a3ec32019-01-29 14:42:08 -0700724 auto lock = intercept->write_lock();
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600725 intercept->PreCallValidateDestroyDevice(device, pAllocator);
726 }
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600727 """ + precallrecord_loop + """
Jeremy Hayesd4a3ec32019-01-29 14:42:08 -0700728 auto lock = intercept->write_lock();
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600729 intercept->PreCallRecordDestroyDevice(device, pAllocator);
730 }
731 layer_debug_utils_destroy_device(device);
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600732
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600733 layer_data->device_dispatch_table.DestroyDevice(device, pAllocator);
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600734
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600735 """ + postcallrecord_loop + """
Jeremy Hayesd4a3ec32019-01-29 14:42:08 -0700736 auto lock = intercept->write_lock();
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600737 intercept->PostCallRecordDestroyDevice(device, pAllocator);
738 }
739
Mark Lobodzinskic5003372018-12-17 16:36:01 -0700740 for (auto item = layer_data->object_dispatch.begin(); item != layer_data->object_dispatch.end(); item++) {
741 delete *item;
742 }
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600743 FreeLayerDataPtr(key, layer_data_map);
744}
745
746VKAPI_ATTR VkResult VKAPI_CALL CreateDebugReportCallbackEXT(VkInstance instance,
747 const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
748 const VkAllocationCallbacks *pAllocator,
749 VkDebugReportCallbackEXT *pCallback) {
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600750 auto layer_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
751 """ + precallvalidate_loop + """
Jeremy Hayesd4a3ec32019-01-29 14:42:08 -0700752 auto lock = intercept->write_lock();
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600753 intercept->PreCallValidateCreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);
754 }
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600755 """ + precallrecord_loop + """
Jeremy Hayesd4a3ec32019-01-29 14:42:08 -0700756 auto lock = intercept->write_lock();
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600757 intercept->PreCallRecordCreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);
758 }
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700759 VkResult result = DispatchCreateDebugReportCallbackEXT(layer_data, instance, pCreateInfo, pAllocator, pCallback);
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600760 result = layer_create_report_callback(layer_data->report_data, false, pCreateInfo, pAllocator, pCallback);
761 """ + postcallrecord_loop + """
Jeremy Hayesd4a3ec32019-01-29 14:42:08 -0700762 auto lock = intercept->write_lock();
Mark Lobodzinskicd05c1e2019-01-17 15:33:46 -0700763 intercept->PostCallRecordCreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback, result);
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600764 }
765 return result;
766}
767
768VKAPI_ATTR void VKAPI_CALL DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback,
769 const VkAllocationCallbacks *pAllocator) {
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600770 auto layer_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
771 """ + precallvalidate_loop + """
Jeremy Hayesd4a3ec32019-01-29 14:42:08 -0700772 auto lock = intercept->write_lock();
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600773 intercept->PreCallValidateDestroyDebugReportCallbackEXT(instance, callback, pAllocator);
774 }
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600775 """ + precallrecord_loop + """
Jeremy Hayesd4a3ec32019-01-29 14:42:08 -0700776 auto lock = intercept->write_lock();
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600777 intercept->PreCallRecordDestroyDebugReportCallbackEXT(instance, callback, pAllocator);
778 }
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700779 DispatchDestroyDebugReportCallbackEXT(layer_data, instance, callback, pAllocator);
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600780 layer_destroy_report_callback(layer_data->report_data, callback, pAllocator);
781 """ + postcallrecord_loop + """
Jeremy Hayesd4a3ec32019-01-29 14:42:08 -0700782 auto lock = intercept->write_lock();
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600783 intercept->PostCallRecordDestroyDebugReportCallbackEXT(instance, callback, pAllocator);
784 }
Mark Lobodzinskif57e8282018-12-13 11:34:33 -0700785}"""
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600786
787 inline_custom_source_postamble = """
788// loader-layer interface v0, just wrappers since there is only a layer
789
790VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount,
791 VkExtensionProperties *pProperties) {
792 return vulkan_layer_chassis::EnumerateInstanceExtensionProperties(pLayerName, pCount, pProperties);
793}
794
795VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount,
796 VkLayerProperties *pProperties) {
797 return vulkan_layer_chassis::EnumerateInstanceLayerProperties(pCount, pProperties);
798}
799
800VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount,
801 VkLayerProperties *pProperties) {
802 // the layer command handles VK_NULL_HANDLE just fine internally
803 assert(physicalDevice == VK_NULL_HANDLE);
804 return vulkan_layer_chassis::EnumerateDeviceLayerProperties(VK_NULL_HANDLE, pCount, pProperties);
805}
806
807VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
808 const char *pLayerName, uint32_t *pCount,
809 VkExtensionProperties *pProperties) {
810 // the layer command handles VK_NULL_HANDLE just fine internally
811 assert(physicalDevice == VK_NULL_HANDLE);
812 return vulkan_layer_chassis::EnumerateDeviceExtensionProperties(VK_NULL_HANDLE, pLayerName, pCount, pProperties);
813}
814
815VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
816 return vulkan_layer_chassis::GetDeviceProcAddr(dev, funcName);
817}
818
819VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
820 return vulkan_layer_chassis::GetInstanceProcAddr(instance, funcName);
821}
822
823VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance,
824 const char *funcName) {
825 return vulkan_layer_chassis::GetPhysicalDeviceProcAddr(instance, funcName);
826}
827
828VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
829 assert(pVersionStruct != NULL);
830 assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
831
832 // Fill in the function pointers if our version is at least capable of having the structure contain them.
833 if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
834 pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
835 pVersionStruct->pfnGetDeviceProcAddr = vkGetDeviceProcAddr;
836 pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
837 }
838
839 return VK_SUCCESS;
840}"""
841
842
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600843 def __init__(self,
844 errFile = sys.stderr,
845 warnFile = sys.stderr,
846 diagFile = sys.stdout):
847 OutputGenerator.__init__(self, errFile, warnFile, diagFile)
848 # Internal state - accumulators for different inner block text
849 self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
850 self.intercepts = []
851 self.layer_factory = '' # String containing base layer factory class definition
852
853 # Check if the parameter passed in is a pointer to an array
854 def paramIsArray(self, param):
855 return param.attrib.get('len') is not None
856
857 # Check if the parameter passed in is a pointer
858 def paramIsPointer(self, param):
859 ispointer = False
860 for elem in param:
861 if ((elem.tag is not 'type') and (elem.tail is not None)) and '*' in elem.tail:
862 ispointer = True
863 return ispointer
864
865 # Check if an object is a non-dispatchable handle
866 def isHandleTypeNonDispatchable(self, handletype):
867 handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
868 if handle is not None and handle.find('type').text == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE':
869 return True
870 else:
871 return False
872
873 # Check if an object is a dispatchable handle
874 def isHandleTypeDispatchable(self, handletype):
875 handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
876 if handle is not None and handle.find('type').text == 'VK_DEFINE_HANDLE':
877 return True
878 else:
879 return False
Mark Lobodzinskid03ed352018-11-09 09:34:24 -0700880 #
881 #
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600882 def beginFile(self, genOpts):
883 OutputGenerator.beginFile(self, genOpts)
Mark Lobodzinskid03ed352018-11-09 09:34:24 -0700884 # Output Copyright
885 write(self.inline_copyright_message, file=self.outFile)
886 # Multiple inclusion protection
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600887 self.header = False
888 if (self.genOpts.filename and 'h' == self.genOpts.filename[-1]):
889 self.header = True
890 write('#pragma once', file=self.outFile)
891 self.newline()
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600892 if self.header:
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700893 write(self.inline_custom_header_preamble, file=self.outFile)
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600894 else:
895 write(self.inline_custom_source_preamble, file=self.outFile)
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -0700896 self.layer_factory += self.inline_custom_header_class_definition
Mark Lobodzinskid03ed352018-11-09 09:34:24 -0700897 #
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600898 #
899 def endFile(self):
900 # Finish C++ namespace and multiple inclusion protection
901 self.newline()
902 if not self.header:
903 # Record intercepted procedures
904 write('// Map of all APIs to be intercepted by this layer', file=self.outFile)
905 write('const std::unordered_map<std::string, void*> name_to_funcptr_map = {', file=self.outFile)
906 write('\n'.join(self.intercepts), file=self.outFile)
907 write('};\n', file=self.outFile)
908 self.newline()
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600909 write('} // namespace vulkan_layer_chassis', file=self.outFile)
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600910 if self.header:
911 self.newline()
912 # Output Layer Factory Class Definitions
Mark Lobodzinskiadd93232018-10-09 11:49:42 -0600913 self.layer_factory += '};\n\n'
914 self.layer_factory += 'extern std::unordered_map<void*, ValidationObject*> layer_data_map;'
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600915 write(self.layer_factory, file=self.outFile)
916 else:
917 write(self.inline_custom_source_postamble, file=self.outFile)
918 # Finish processing in superclass
919 OutputGenerator.endFile(self)
920
921 def beginFeature(self, interface, emit):
922 # Start processing in superclass
923 OutputGenerator.beginFeature(self, interface, emit)
924 # Get feature extra protect
925 self.featureExtraProtect = GetFeatureProtect(interface)
926 # Accumulate includes, defines, types, enums, function pointer typedefs, end function prototypes separately for this
927 # feature. They're only printed in endFeature().
928 self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
929
930 def endFeature(self):
931 # Actually write the interface to the output file.
932 if (self.emit):
933 self.newline()
934 # If type declarations are needed by other features based on this one, it may be necessary to suppress the ExtraProtect,
935 # or move it below the 'for section...' loop.
936 if (self.featureExtraProtect != None):
937 write('#ifdef', self.featureExtraProtect, file=self.outFile)
938 for section in self.TYPE_SECTIONS:
939 contents = self.sections[section]
940 if contents:
941 write('\n'.join(contents), file=self.outFile)
942 self.newline()
943 if (self.sections['command']):
944 write('\n'.join(self.sections['command']), end=u'', file=self.outFile)
945 self.newline()
946 if (self.featureExtraProtect != None):
Mark Lobodzinski0c668462018-09-27 10:13:19 -0600947 write('#endif //', self.featureExtraProtect, file=self.outFile)
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600948 # Finish processing in superclass
949 OutputGenerator.endFeature(self)
950 #
951 # Append a definition to the specified section
952 def appendSection(self, section, text):
953 self.sections[section].append(text)
954 #
955 # Type generation
956 def genType(self, typeinfo, name, alias):
957 pass
958 #
959 # Struct (e.g. C "struct" type) generation. This is a special case of the <type> tag where the contents are
960 # interpreted as a set of <member> tags instead of freeform C type declarations. The <member> tags are just like <param>
961 # tags - they are a declaration of a struct or union member. Only simple member declarations are supported (no nested
962 # structs etc.)
963 def genStruct(self, typeinfo, typeName):
964 OutputGenerator.genStruct(self, typeinfo, typeName)
965 body = 'typedef ' + typeinfo.elem.get('category') + ' ' + typeName + ' {\n'
966 # paramdecl = self.makeCParamDecl(typeinfo.elem, self.genOpts.alignFuncParam)
967 for member in typeinfo.elem.findall('.//member'):
968 body += self.makeCParamDecl(member, self.genOpts.alignFuncParam)
969 body += ';\n'
970 body += '} ' + typeName + ';\n'
971 self.appendSection('struct', body)
972 #
973 # Group (e.g. C "enum" type) generation. These are concatenated together with other types.
974 def genGroup(self, groupinfo, groupName, alias):
975 pass
976 # Enumerant generation
977 # <enum> tags may specify their values in several ways, but are usually just integers.
978 def genEnum(self, enuminfo, name, alias):
979 pass
980 #
981 # Customize Cdecl for layer factory base class
982 def BaseClassCdecl(self, elem, name):
983 raw = self.makeCDecls(elem)[1]
984
985 # Toss everything before the undecorated name
986 prototype = raw.split("VKAPI_PTR *PFN_vk")[1]
987 prototype = prototype.replace(")", "", 1)
988 prototype = prototype.replace(";", " {};")
989
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600990 # Build up pre/post call virtual function declarations
991 pre_call_validate = 'virtual bool PreCallValidate' + prototype
992 pre_call_validate = pre_call_validate.replace("{}", " { return false; }")
993 pre_call_record = 'virtual void PreCallRecord' + prototype
994 post_call_record = 'virtual void PostCallRecord' + prototype
Mark Lobodzinskicd05c1e2019-01-17 15:33:46 -0700995 resulttype = elem.find('proto/type')
996 if resulttype.text == 'VkResult':
997 post_call_record = post_call_record.replace(')', ', VkResult result)')
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -0600998 return ' %s\n %s\n %s\n' % (pre_call_validate, pre_call_record, post_call_record)
999 #
1000 # Command generation
1001 def genCmd(self, cmdinfo, name, alias):
1002 ignore_functions = [
1003 'vkEnumerateInstanceVersion'
1004 ]
1005
1006 if name in ignore_functions:
1007 return
1008
1009 if self.header: # In the header declare all intercepts
1010 self.appendSection('command', '')
1011 self.appendSection('command', self.makeCDecls(cmdinfo.elem)[0])
1012 if (self.featureExtraProtect != None):
1013 self.intercepts += [ '#ifdef %s' % self.featureExtraProtect ]
1014 self.layer_factory += '#ifdef %s\n' % self.featureExtraProtect
1015 # Update base class with virtual function declarations
1016 self.layer_factory += self.BaseClassCdecl(cmdinfo.elem, name)
1017 # Update function intercepts
1018 self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ]
1019 if (self.featureExtraProtect != None):
1020 self.intercepts += [ '#endif' ]
1021 self.layer_factory += '#endif\n'
1022 return
1023
Mark Lobodzinski09f86362018-12-13 14:07:20 -07001024 if name in self.manual_functions:
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -06001025 self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ]
1026 return
1027 # Record that the function will be intercepted
1028 if (self.featureExtraProtect != None):
1029 self.intercepts += [ '#ifdef %s' % self.featureExtraProtect ]
1030 self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ]
1031 if (self.featureExtraProtect != None):
1032 self.intercepts += [ '#endif' ]
1033 OutputGenerator.genCmd(self, cmdinfo, name, alias)
1034 #
1035 decls = self.makeCDecls(cmdinfo.elem)
1036 self.appendSection('command', '')
1037 self.appendSection('command', '%s {' % decls[0][:-1])
1038 # Setup common to call wrappers. First parameter is always dispatchable
1039 dispatchable_type = cmdinfo.elem.find('param/type').text
1040 dispatchable_name = cmdinfo.elem.find('param/name').text
1041 # Default to device
1042 device_or_instance = 'device'
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -06001043 dispatch_table_name = 'VkLayerDispatchTable'
1044 # Set to instance as necessary
1045 if dispatchable_type in ["VkPhysicalDevice", "VkInstance"] or name == 'vkCreateInstance':
1046 device_or_instance = 'instance'
1047 dispatch_table_name = 'VkLayerInstanceDispatchTable'
Mark Lobodzinskiadd93232018-10-09 11:49:42 -06001048 self.appendSection('command', ' auto layer_data = GetLayerDataPtr(get_dispatch_key(%s), layer_data_map);' % (dispatchable_name))
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -06001049 api_function_name = cmdinfo.elem.attrib.get('name')
1050 params = cmdinfo.elem.findall('param/name')
1051 paramstext = ', '.join([str(param.text) for param in params])
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -07001052 API = api_function_name.replace('vk','Dispatch') + '(layer_data, '
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -06001053
1054 # Declare result variable, if any.
1055 return_map = {
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -06001056 'PFN_vkVoidFunction': 'return nullptr;',
1057 'VkBool32': 'return VK_FALSE;',
Shannon McPherson9a4ae982019-01-07 16:05:25 -07001058 'VkDeviceAddress': 'return 0;',
1059 'VkResult': 'return VK_ERROR_VALIDATION_FAILED_EXT;',
1060 'void': 'return;',
Eric Wernessf46b8a02019-01-30 12:24:39 -08001061 'uint32_t': 'return 0;'
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -06001062 }
1063 resulttype = cmdinfo.elem.find('proto/type')
1064 assignresult = ''
1065 if (resulttype.text != 'void'):
1066 assignresult = resulttype.text + ' result = '
1067
1068 # Set up skip and locking
Mark Lobodzinskie37e2fc2018-11-26 16:31:17 -07001069 self.appendSection('command', ' bool skip = false;')
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -06001070
1071 # Generate pre-call validation source code
Mark Lobodzinskiadd93232018-10-09 11:49:42 -06001072 self.appendSection('command', ' %s' % self.precallvalidate_loop)
Jeremy Hayesd4a3ec32019-01-29 14:42:08 -07001073 self.appendSection('command', ' auto lock = intercept->write_lock();')
Mark Lobodzinskie37e2fc2018-11-26 16:31:17 -07001074 self.appendSection('command', ' skip |= intercept->PreCallValidate%s(%s);' % (api_function_name[2:], paramstext))
1075 self.appendSection('command', ' if (skip) %s' % return_map[resulttype.text])
1076 self.appendSection('command', ' }')
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -06001077
1078 # Generate pre-call state recording source code
Mark Lobodzinskiadd93232018-10-09 11:49:42 -06001079 self.appendSection('command', ' %s' % self.precallrecord_loop)
Jeremy Hayesd4a3ec32019-01-29 14:42:08 -07001080 self.appendSection('command', ' auto lock = intercept->write_lock();')
Mark Lobodzinskie37e2fc2018-11-26 16:31:17 -07001081 self.appendSection('command', ' intercept->PreCallRecord%s(%s);' % (api_function_name[2:], paramstext))
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -06001082 self.appendSection('command', ' }')
1083
Mark Lobodzinskif57e8282018-12-13 11:34:33 -07001084 # Insert pre-dispatch debug utils function call
1085 if name in self.pre_dispatch_debug_utils_functions:
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -07001086 self.appendSection('command', ' %s' % self.pre_dispatch_debug_utils_functions[name])
Mark Lobodzinskif57e8282018-12-13 11:34:33 -07001087
1088 # Output dispatch (down-chain) function call
Mark Lobodzinskia5b163f2018-11-08 12:31:46 -07001089 self.appendSection('command', ' ' + assignresult + API + paramstext + ');')
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -06001090
Mark Lobodzinskif57e8282018-12-13 11:34:33 -07001091 # Insert post-dispatch debug utils function call
1092 if name in self.post_dispatch_debug_utils_functions:
Mark Lobodzinskifa4d6a62019-02-07 10:23:21 -07001093 self.appendSection('command', ' %s' % self.post_dispatch_debug_utils_functions[name])
Mark Lobodzinskif57e8282018-12-13 11:34:33 -07001094
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -06001095 # Generate post-call object processing source code
Mark Lobodzinskid939fcb2019-01-10 15:49:12 -07001096 self.appendSection('command', ' %s' % self.postcallrecord_loop)
Mark Lobodzinskicd05c1e2019-01-17 15:33:46 -07001097 returnparam = ''
Mark Lobodzinski0c668462018-09-27 10:13:19 -06001098 if (resulttype.text == 'VkResult'):
Mark Lobodzinskicd05c1e2019-01-17 15:33:46 -07001099 returnparam = ', result'
Jeremy Hayesd4a3ec32019-01-29 14:42:08 -07001100 self.appendSection('command', ' auto lock = intercept->write_lock();')
Mark Lobodzinskicd05c1e2019-01-17 15:33:46 -07001101 self.appendSection('command', ' intercept->PostCallRecord%s(%s%s);' % (api_function_name[2:], paramstext, returnparam))
Mark Lobodzinskicd05c1e2019-01-17 15:33:46 -07001102 self.appendSection('command', ' }')
Mark Lobodzinski9b6522d2018-09-26 11:07:45 -06001103 # Return result variable, if any.
1104 if (resulttype.text != 'void'):
1105 self.appendSection('command', ' return result;')
1106 self.appendSection('command', '}')
1107 #
1108 # Override makeProtoName to drop the "vk" prefix
1109 def makeProtoName(self, name, tail):
1110 return self.genOpts.apientry + name[2:] + tail