| Adithya Srinivasan | 0136414 | 2019-07-02 15:52:49 -0700 | [diff] [blame] | 1 | #!/usr/bin/env python3 | 
 | 2 | # | 
 | 3 | # Copyright 2019 The Android Open Source Project | 
 | 4 | # | 
 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 6 | # you may not use this file except in compliance with the License. | 
 | 7 | # You may obtain a copy of the License at | 
 | 8 | # | 
 | 9 | #      http://www.apache.org/licenses/LICENSE-2.0 | 
 | 10 | # | 
 | 11 | # Unless required by applicable law or agreed to in writing, software | 
 | 12 | # distributed under the License is distributed on an "AS IS" BASIS, | 
 | 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | 14 | # See the License for the specific language governing permissions and | 
 | 15 | # limitations under the License. | 
 | 16 | # | 
 | 17 | # This script provides the functions for generating the | 
 | 18 | # vulkan driver framework directly from the vulkan registry (vk.xml). | 
 | 19 |  | 
 | 20 | import generator_common as gencom | 
 | 21 | import os | 
 | 22 |  | 
 | 23 | interceptedExtensions = [ | 
 | 24 |   'VK_ANDROID_native_buffer', | 
 | 25 |   'VK_EXT_debug_report', | 
 | 26 |   'VK_EXT_hdr_metadata', | 
 | 27 |   'VK_EXT_swapchain_colorspace', | 
 | 28 |   'VK_GOOGLE_display_timing', | 
 | 29 |   'VK_KHR_android_surface', | 
 | 30 |   'VK_KHR_incremental_present', | 
 | 31 |   'VK_KHR_shared_presentable_image', | 
 | 32 |   'VK_KHR_surface', | 
 | 33 |   'VK_KHR_swapchain', | 
 | 34 |   'VK_KHR_get_surface_capabilities2' | 
 | 35 | ] | 
 | 36 |  | 
 | 37 | knownExtensions = interceptedExtensions + [ | 
 | 38 |   'VK_KHR_get_physical_device_properties2', | 
 | 39 |   'VK_ANDROID_external_memory_android_hardware_buffer', | 
 | 40 |   'VK_KHR_bind_memory2' | 
 | 41 | ] | 
 | 42 |  | 
 | 43 | def defineProcHookType(f): | 
 | 44 |   f.write ("""struct ProcHook { | 
 | 45 |     enum Type { | 
 | 46 |         GLOBAL, | 
 | 47 |         INSTANCE, | 
 | 48 |         DEVICE, | 
 | 49 |     }; | 
 | 50 |     enum Extension {\n""") | 
 | 51 |   for exts in knownExtensions: | 
 | 52 |     f.write (gencom.clang_off_spaces*2 + exts[3:] + ',\n') | 
 | 53 |   f.write ('\n') | 
 | 54 |   f.write (gencom.clang_off_spaces*2 + """EXTENSION_CORE,  // valid bit | 
 | 55 |         EXTENSION_COUNT, | 
 | 56 |         EXTENSION_UNKNOWN, | 
 | 57 |     }; | 
 | 58 |  | 
 | 59 |     const char* name; | 
 | 60 |     Type type; | 
 | 61 |     Extension extension; | 
 | 62 |  | 
 | 63 |     PFN_vkVoidFunction proc; | 
 | 64 |     PFN_vkVoidFunction checked_proc;  // always nullptr for non-device hooks | 
 | 65 | };\n\n""") | 
 | 66 |  | 
 | 67 | def isExtensionIntercepted(extensionName): | 
 | 68 |   if extensionName in interceptedExtensions: | 
 | 69 |     return True | 
 | 70 |   return False | 
 | 71 |  | 
 | 72 | def isDriverTableEntry(functionName): | 
 | 73 |   switchCase = { | 
 | 74 |     # Create functions of dispatchable objects | 
 | 75 |     'vkCreateDevice' : True, | 
 | 76 |     'vkGetDeviceQueue' : True, | 
 | 77 |     'vkGetDeviceQueue2' : True, | 
 | 78 |     'vkAllocateCommandBuffers' : True, | 
 | 79 |  | 
 | 80 |     # Destroy functions of dispatchable objects | 
 | 81 |     'vkDestroyInstance' : True, | 
 | 82 |     'vkDestroyDevice' : True, | 
 | 83 |  | 
 | 84 |     # Enumeration of extensions | 
 | 85 |     'vkEnumerateDeviceExtensionProperties' : True, | 
 | 86 |  | 
 | 87 |     # We cache physical devices in loader.cpp | 
 | 88 |     'vkEnumeratePhysicalDevices' : True, | 
 | 89 |     'vkEnumeratePhysicalDeviceGroups' : True, | 
 | 90 |  | 
 | 91 |     'vkGetInstanceProcAddr' : True, | 
 | 92 |     'vkGetDeviceProcAddr' : True, | 
 | 93 |  | 
 | 94 |     # VK_KHR_swapchain->VK_ANDROID_native_buffer translation | 
 | 95 |     'vkCreateImage' : True, | 
 | 96 |     'vkDestroyImage' : True, | 
 | 97 |  | 
 | 98 |     'vkGetPhysicalDeviceProperties' : True, | 
 | 99 |     'vkGetPhysicalDeviceProperties2' : True, | 
 | 100 |     'vkGetPhysicalDeviceProperties2KHR' : True, | 
 | 101 |  | 
 | 102 |     # VK_KHR_swapchain v69 requirement | 
 | 103 |     'vkBindImageMemory2' : True, | 
 | 104 |     'vkBindImageMemory2KHR' : True | 
 | 105 |   } | 
 | 106 |   if gencom.isFunctionSupported(functionName): | 
 | 107 |     if functionName in switchCase: | 
 | 108 |       return True | 
 | 109 |     if functionName in gencom.extensionsDict: | 
 | 110 |       if gencom.extensionsDict[functionName] == 'VK_ANDROID_native_buffer' or gencom.extensionsDict[functionName] == 'VK_EXT_debug_report': | 
 | 111 |         return True | 
 | 112 |   return False | 
 | 113 |  | 
 | 114 | def isInstanceDriverTableEntry(functionName): | 
 | 115 |   if isDriverTableEntry(functionName) and gencom.isInstanceDispatched(functionName): | 
 | 116 |     return True | 
 | 117 |   return False | 
 | 118 |  | 
 | 119 | def isDeviceDriverTableEntry(functionName): | 
 | 120 |   if isDriverTableEntry(functionName) and gencom.isDeviceDispatched(functionName): | 
 | 121 |     return True | 
 | 122 |   return False | 
 | 123 |  | 
 | 124 | def driver_genh(): | 
 | 125 |   header = """#ifndef LIBVULKAN_DRIVER_GEN_H | 
 | 126 | #define LIBVULKAN_DRIVER_GEN_H | 
 | 127 |  | 
 | 128 | #include <vulkan/vk_android_native_buffer.h> | 
 | 129 | #include <vulkan/vulkan.h> | 
 | 130 |  | 
 | 131 | #include <bitset> | 
 | 132 |  | 
 | 133 | namespace vulkan { | 
 | 134 | namespace driver {\n\n""" | 
| Adithya Srinivasan | 8dce9d7 | 2019-07-11 14:26:04 -0700 | [diff] [blame] | 135 |   genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','driver_gen.h') | 
| Adithya Srinivasan | 0136414 | 2019-07-02 15:52:49 -0700 | [diff] [blame] | 136 |   with open(genfile, 'w') as f: | 
 | 137 |     f.write (gencom.copyright) | 
 | 138 |     f.write (gencom.warning) | 
 | 139 |     f.write (header) | 
 | 140 |     defineProcHookType(f) | 
 | 141 |     f.write ('struct InstanceDriverTable {\n') | 
 | 142 |     gencom.clang_off(f, 1) | 
 | 143 |     for cmds in gencom.allCommandsList: | 
 | 144 |       if isInstanceDriverTableEntry(cmds): | 
 | 145 |         f.write (gencom.clang_off_spaces + 'PFN_' + cmds + ' ' + cmds[2:] + ';\n') | 
 | 146 |     gencom.clang_on(f, 1) | 
 | 147 |     f.write ('};\n\n') | 
 | 148 |     f.write ('struct DeviceDriverTable {\n') | 
 | 149 |     gencom.clang_off(f,1) | 
 | 150 |     for cmds in gencom.allCommandsList: | 
 | 151 |       if isDeviceDriverTableEntry(cmds): | 
 | 152 |         f.write (gencom.clang_off_spaces + 'PFN_' + cmds + ' ' + cmds[2:] + ';\n') | 
 | 153 |     gencom.clang_on(f,1) | 
 | 154 |     f.write ('};\n\n') | 
 | 155 |     f.write ("""const ProcHook* GetProcHook(const char* name); | 
 | 156 | ProcHook::Extension GetProcHookExtension(const char* name); | 
 | 157 |  | 
 | 158 | bool InitDriverTable(VkInstance instance, | 
 | 159 |                      PFN_vkGetInstanceProcAddr get_proc, | 
 | 160 |                      const std::bitset<ProcHook::EXTENSION_COUNT>& extensions); | 
 | 161 | bool InitDriverTable(VkDevice dev, | 
 | 162 |                      PFN_vkGetDeviceProcAddr get_proc, | 
 | 163 |                      const std::bitset<ProcHook::EXTENSION_COUNT>& extensions); | 
 | 164 |  | 
 | 165 | }  // namespace driver | 
 | 166 | }  // namespace vulkan | 
 | 167 |  | 
 | 168 | #endif  // LIBVULKAN_DRIVER_TABLE_H\n""") | 
| Adithya Srinivasan | 8dce9d7 | 2019-07-11 14:26:04 -0700 | [diff] [blame] | 169 |     f.close() | 
 | 170 |   gencom.runClangFormat(genfile) | 
| Adithya Srinivasan | 0136414 | 2019-07-02 15:52:49 -0700 | [diff] [blame] | 171 |  | 
 | 172 | def isIntercepted(functionName): | 
 | 173 |   switchCase = { | 
 | 174 |     # Create functions of dispatchable objects | 
 | 175 |     'vkCreateInstance' : True, | 
 | 176 |     'vkCreateDevice' : True, | 
 | 177 |     'vkEnumeratePhysicalDevices' : True, | 
 | 178 |     'vkEnumeratePhysicalDeviceGroups' : True, | 
 | 179 |     'vkGetDeviceQueue' : True, | 
 | 180 |     'vkGetDeviceQueue2' : True, | 
 | 181 |     'vkAllocateCommandBuffers' : True, | 
 | 182 |  | 
 | 183 |     # Destroy functions of dispatchable objects | 
 | 184 |     'vkDestroyInstance' : True, | 
 | 185 |     'vkDestroyDevice' : True, | 
 | 186 |  | 
 | 187 |     # Enumeration of extensions | 
 | 188 |     'vkEnumerateInstanceExtensionProperties' : True, | 
 | 189 |     'vkEnumerateDeviceExtensionProperties' : True, | 
 | 190 |  | 
 | 191 |     'vkGetInstanceProcAddr' : True, | 
 | 192 |     'vkGetDeviceProcAddr' : True, | 
 | 193 |  | 
 | 194 |     # VK_KHR_swapchain v69 requirement | 
 | 195 |     'vkBindImageMemory2' : True, | 
 | 196 |     'vkBindImageMemory2KHR' : True | 
 | 197 |   } | 
 | 198 |   if gencom.isFunctionSupported(functionName): | 
 | 199 |     if functionName in switchCase: | 
 | 200 |       return switchCase[functionName] | 
 | 201 |  | 
 | 202 |     if functionName in gencom.extensionsDict: | 
 | 203 |       return isExtensionIntercepted(gencom.extensionsDict[functionName]) | 
 | 204 |   return False | 
 | 205 |  | 
 | 206 | def needProcHookStub(functionName): | 
 | 207 |   if isIntercepted(functionName) and gencom.isDeviceDispatched(functionName): | 
 | 208 |     if functionName in gencom.extensionsDict: | 
 | 209 |       if not gencom.isExtensionInternal(gencom.extensionsDict[functionName]): | 
 | 210 |         return True | 
 | 211 |   return False | 
 | 212 |  | 
 | 213 | def defineInitProc(name, f): | 
 | 214 |   f.write ('#define UNLIKELY(expr) __builtin_expect((expr), 0)\n') | 
 | 215 |   f.write ('\n') | 
 | 216 |   f.write ("""#define INIT_PROC(required, obj, proc)                                 \\ | 
 | 217 |     do {                                                               \\ | 
 | 218 |         data.""" + name + """.proc =                                             \\ | 
 | 219 |             reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\ | 
 | 220 |         if (UNLIKELY(required && !data.""" + name + """.proc)) {                 \\ | 
 | 221 |             ALOGE("missing " #obj " proc: vk" #proc);                  \\ | 
 | 222 |             success = false;                                           \\ | 
 | 223 |         }                                                              \\ | 
 | 224 |     } while (0)\n\n""") | 
 | 225 |  | 
 | 226 | def defineInitProcExt(f): | 
 | 227 |   f.write ("""#define INIT_PROC_EXT(ext, required, obj, proc) \\ | 
 | 228 |     do {                                        \\ | 
 | 229 |         if (extensions[ProcHook::ext])          \\ | 
 | 230 |             INIT_PROC(required, obj, proc);     \\ | 
 | 231 |     } while (0)\n\n""") | 
 | 232 |  | 
 | 233 | def defineProcHookStub(functionName, f): | 
 | 234 |   if needProcHookStub(functionName): | 
 | 235 |     ext_name = gencom.extensionsDict[functionName] | 
 | 236 |     base_name = functionName[2:] | 
 | 237 |     paramList = [''.join(i) for i in gencom.paramDict[functionName]] | 
 | 238 |     p0 = gencom.paramDict[functionName][0][1] | 
 | 239 |     f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[functionName] + ' checked' + base_name + '(' + ', '.join(paramList) + ') {\n') | 
 | 240 |     ext_hook = 'ProcHook::' + ext_name[3:] | 
 | 241 |  | 
 | 242 |     f.write (gencom.clang_off_spaces + 'if (GetData(' + p0 + ').hook_extensions[' + ext_hook + ']) {\n') | 
 | 243 |     f.write (gencom.clang_off_spaces *2) | 
 | 244 |     if gencom.returnTypeDict[functionName] != 'void': | 
 | 245 |       f.write ('return ') | 
 | 246 |     paramNames = [''.join(i[1]) for i in gencom.paramDict[functionName]] | 
 | 247 |     f.write (base_name + '(' + ', '.join(paramNames) + ');\n') | 
 | 248 |     f.write (gencom.clang_off_spaces + '} else {\n') | 
 | 249 |     f.write (gencom.clang_off_spaces*2 + 'Logger(' + p0 + ').Err(' + p0 + ', \"' + ext_name + ' not enabled. ' + functionName + ' not executed.\");\n') | 
 | 250 |     if gencom.returnTypeDict[functionName] != 'void': | 
 | 251 |       f.write (gencom.clang_off_spaces*2 + 'return VK_SUCCESS;\n') | 
 | 252 |     f.write (gencom.clang_off_spaces + '}\n') | 
 | 253 |     f.write ('}\n\n') | 
 | 254 |  | 
 | 255 | def defineGlobalProcHook(functionName, f): | 
 | 256 |   base_name = functionName[2:] | 
 | 257 |   assert (functionName not in gencom.extensionsDict) | 
 | 258 |   f.write (gencom.clang_off_spaces + '{\n' + gencom.clang_off_spaces*2 + '\"' + functionName + '\",\n' + gencom.clang_off_spaces*2) | 
 | 259 |   f.write ("""ProcHook::GLOBAL, | 
 | 260 |         ProcHook::EXTENSION_CORE, | 
 | 261 |         reinterpret_cast<PFN_vkVoidFunction>(""" + base_name  + """), | 
 | 262 |         nullptr, | 
 | 263 |     },\n""") | 
 | 264 |  | 
 | 265 | def defineInstanceProcHook(functionName, f): | 
 | 266 |   base_name = functionName[2:] | 
 | 267 |   f.write (gencom.clang_off_spaces + '{\n') | 
 | 268 |   f.write (gencom.clang_off_spaces*2 + '\"' + functionName + '\",\n') | 
 | 269 |   f.write (gencom.clang_off_spaces*2 + 'ProcHook::INSTANCE,\n') | 
 | 270 |  | 
 | 271 |   if functionName in gencom.extensionsDict: | 
 | 272 |     ext_name = gencom.extensionsDict[functionName] | 
 | 273 |     f.write (gencom.clang_off_spaces*2 + 'ProcHook::' + ext_name[3:] + ',\n') | 
 | 274 |     if gencom.isExtensionInternal(ext_name): | 
 | 275 |       f.write (gencom.clang_off_spaces*2 + 'nullptr,\n' + gencom.clang_off_spaces*2 + 'nullptr,\n') | 
 | 276 |     else: | 
 | 277 |       f.write (gencom.clang_off_spaces*2 + 'reinterpret_cast<PFN_vkVoidFunction>(' + base_name + '),\n' + gencom.clang_off_spaces*2 + 'nullptr,\n') | 
 | 278 |  | 
 | 279 |   else: | 
 | 280 |     f.write (gencom.clang_off_spaces*2 + """ProcHook::EXTENSION_CORE, | 
 | 281 |         reinterpret_cast<PFN_vkVoidFunction>(""" + base_name + """), | 
 | 282 |         nullptr,\n""") | 
 | 283 |  | 
 | 284 |   f.write (gencom.clang_off_spaces + '},\n') | 
 | 285 |  | 
 | 286 | def defineDeviceProcHook(functionName, f): | 
 | 287 |   base_name = functionName[2:] | 
 | 288 |   f.write (gencom.clang_off_spaces + '{\n') | 
 | 289 |   f.write (gencom.clang_off_spaces*2 + '\"' + functionName + '\",\n') | 
 | 290 |   f.write (gencom.clang_off_spaces*2 + 'ProcHook::DEVICE,\n') | 
 | 291 |  | 
 | 292 |   if functionName in gencom.extensionsDict: | 
 | 293 |     ext_name = gencom.extensionsDict[functionName] | 
 | 294 |     f.write (gencom.clang_off_spaces*2 + 'ProcHook::' + ext_name[3:] + ',\n') | 
 | 295 |     if gencom.isExtensionInternal(ext_name): | 
 | 296 |       f.write (gencom.clang_off_spaces*2 + 'nullptr,\n' + gencom.clang_off_spaces*2 + 'nullptr,\n') | 
 | 297 |     else: | 
 | 298 |       f.write (gencom.clang_off_spaces*2 + 'reinterpret_cast<PFN_vkVoidFunction>(' + base_name + '),\n' + gencom.clang_off_spaces*2 + 'reinterpret_cast<PFN_vkVoidFunction>(checked' + base_name + '),\n') | 
 | 299 |  | 
 | 300 |   else: | 
 | 301 |     f.write (gencom.clang_off_spaces*2 + """ProcHook::EXTENSION_CORE, | 
 | 302 |         reinterpret_cast<PFN_vkVoidFunction>(""" + base_name + """), | 
 | 303 |         nullptr,\n""") | 
 | 304 |  | 
 | 305 |   f.write (gencom.clang_off_spaces + '},\n') | 
 | 306 |  | 
 | 307 | def driver_gencpp(): | 
 | 308 |   header = """#include <log/log.h> | 
 | 309 | #include <string.h> | 
 | 310 |  | 
 | 311 | #include <algorithm> | 
 | 312 |  | 
 | 313 | #include "driver.h" | 
 | 314 |  | 
 | 315 | namespace vulkan { | 
 | 316 | namespace driver { | 
 | 317 |  | 
 | 318 | namespace { | 
 | 319 |  | 
 | 320 | // clang-format off\n\n""" | 
 | 321 |  | 
| Adithya Srinivasan | 8dce9d7 | 2019-07-11 14:26:04 -0700 | [diff] [blame] | 322 |   genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','driver_gen.cpp') | 
| Adithya Srinivasan | 0136414 | 2019-07-02 15:52:49 -0700 | [diff] [blame] | 323 |  | 
 | 324 |   with open(genfile, 'w') as f: | 
 | 325 |     f.write (gencom.copyright) | 
 | 326 |     f.write (gencom.warning) | 
 | 327 |     f.write (header) | 
 | 328 |  | 
 | 329 |     for cmds in gencom.allCommandsList: | 
 | 330 |       defineProcHookStub(cmds, f) | 
 | 331 |     gencom.clang_on(f, 0) | 
 | 332 |     f.write ('\n') | 
 | 333 |  | 
 | 334 |     f.write ('const ProcHook g_proc_hooks[] = {\n') | 
 | 335 |     gencom.clang_off(f, 1) | 
 | 336 |     sortedCommandsList = sorted(gencom.allCommandsList) | 
 | 337 |     for cmds in sortedCommandsList: | 
 | 338 |       if isIntercepted(cmds): | 
 | 339 |         if gencom.isGloballyDispatched(cmds): | 
 | 340 |           defineGlobalProcHook(cmds, f) | 
 | 341 |         elif gencom.isInstanceDispatched(cmds): | 
 | 342 |           defineInstanceProcHook(cmds, f) | 
 | 343 |         elif gencom.isDeviceDispatched(cmds): | 
 | 344 |           defineDeviceProcHook(cmds, f) | 
 | 345 |     gencom.clang_on(f, 1) | 
 | 346 |     f.write ('};\n\n}  // namespace\n\n') | 
 | 347 |  | 
 | 348 |     f.write ("""const ProcHook* GetProcHook(const char* name) { | 
 | 349 |     const auto& begin = g_proc_hooks; | 
 | 350 |     const auto& end = | 
 | 351 |         g_proc_hooks + sizeof(g_proc_hooks) / sizeof(g_proc_hooks[0]); | 
 | 352 |     const auto hook = std::lower_bound( | 
 | 353 |         begin, end, name, | 
 | 354 |         [](const ProcHook& e, const char* n) { return strcmp(e.name, n) < 0; }); | 
 | 355 |     return (hook < end && strcmp(hook->name, name) == 0) ? hook : nullptr; | 
 | 356 | }\n\n""") | 
 | 357 |  | 
 | 358 |     f.write ('ProcHook::Extension GetProcHookExtension(const char* name) {\n') | 
 | 359 |     gencom.clang_off(f, 1) | 
 | 360 |     for exts in knownExtensions: | 
 | 361 |       f.write (gencom.clang_off_spaces + 'if (strcmp(name, \"' + exts + '\") == 0) return ProcHook::' + exts[3:] + ';\n') | 
 | 362 |     gencom.clang_on(f, 1) | 
 | 363 |     f.write (gencom.clang_off_spaces + 'return ProcHook::EXTENSION_UNKNOWN;\n') | 
 | 364 |     f.write ('}\n\n') | 
 | 365 |  | 
 | 366 |     defineInitProc('driver', f) | 
 | 367 |     defineInitProcExt(f) | 
 | 368 |  | 
 | 369 |     f.write ("""bool InitDriverTable(VkInstance instance, | 
 | 370 |                      PFN_vkGetInstanceProcAddr get_proc, | 
 | 371 |                      const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) { | 
 | 372 |     auto& data = GetData(instance); | 
 | 373 |     bool success = true;\n\n""") | 
 | 374 |     gencom.clang_off(f, 1) | 
 | 375 |     for cmds in gencom.allCommandsList: | 
 | 376 |       if isInstanceDriverTableEntry(cmds): | 
 | 377 |         gencom.initProc(cmds, f) | 
 | 378 |     gencom.clang_on(f, 1) | 
 | 379 |     f.write ('\n' + gencom.clang_off_spaces + 'return success;\n') | 
 | 380 |     f.write ('}\n\n') | 
 | 381 |  | 
 | 382 |     f.write ("""bool InitDriverTable(VkDevice dev, | 
 | 383 |                      PFN_vkGetDeviceProcAddr get_proc, | 
 | 384 |                      const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) { | 
 | 385 |     auto& data = GetData(dev); | 
 | 386 |     bool success = true;\n\n""") | 
 | 387 |     gencom.clang_off(f, 1) | 
 | 388 |     for cmds in gencom.allCommandsList: | 
 | 389 |       if isDeviceDriverTableEntry(cmds): | 
 | 390 |         gencom.initProc(cmds, f) | 
 | 391 |     gencom.clang_on(f, 1) | 
 | 392 |     f.write ('\n' + gencom.clang_off_spaces + 'return success;\n') | 
 | 393 |     f.write ('}\n\n}  // namespace driver\n}  // namespace vulkan\n\n') | 
 | 394 |     gencom.clang_on(f, 0) | 
| Adithya Srinivasan | 8dce9d7 | 2019-07-11 14:26:04 -0700 | [diff] [blame] | 395 |     f.close() | 
 | 396 |   gencom.runClangFormat(genfile) |