1#Copyright 2021 Google LLC 2#SPDX - License - Identifier : MIT 3 4import argparse 5import json 6import os 7 8SIMPLE_OBJECT_CREATE_DRIVER_HANDLE_TEMPL = ''' 9/* create a driver {vk_type} and update the vkr_{vkr_type} */ 10static inline VkResult 11vkr_{create_func_name}_create_driver_handle( 12 UNUSED struct vkr_context *ctx, 13 struct vn_command_{create_cmd} *args, 14 struct vkr_{vkr_type} *obj) 15{{ 16 struct vkr_device *dev = vkr_device_from_handle(args->device); 17 struct vn_device_proc_table *vk = &dev->proc_table; 18 19 /* handles in args are replaced */ 20 vn_replace_{create_cmd}_args_handle(args); 21 args->ret = vk->{proc_create}(args->device, args->{create_info}, NULL, 22 &obj->base.handle.{vkr_type}); 23 return args->ret; 24}} 25''' 26 27POOL_OBJECT_CREATE_DRIVER_HANDLES_TEMPL = ''' 28/* create an array of driver {vk_type}s from a pool and update the 29 * object_array 30 */ 31static inline 32VkResult vkr_{create_func_name}_create_driver_handles( 33 UNUSED struct vkr_context *ctx, 34 struct vn_command_{create_cmd} *args, 35 struct object_array *arr) 36{{ 37 struct vkr_device *dev = vkr_device_from_handle(args->device); 38 struct vn_device_proc_table *vk = &dev->proc_table; 39 40 /* handles in args are replaced */ 41 vn_replace_{create_cmd}_args_handle(args); 42 args->ret = vk->{proc_create}(args->device, args->{create_info}, 43 arr->handle_storage); 44 return args->ret; 45}} 46''' 47 48PIPELINE_OBJECT_CREATE_DRIVER_HANDLES_TEMPL = ''' 49/* create an array of driver {vk_type}s and update the object_array */ 50static inline VkResult 51vkr_{create_func_name}_create_driver_handles( 52 UNUSED struct vkr_context *ctx, 53 struct vn_command_{create_cmd} *args, 54 struct object_array *arr) 55{{ 56 struct vkr_device *dev = vkr_device_from_handle(args->device); 57 struct vn_device_proc_table *vk = &dev->proc_table; 58 59 /* handles in args are replaced */ 60 vn_replace_{create_cmd}_args_handle(args); 61 args->ret = vk->{proc_create}(args->device, args->{create_cache}, 62 args->{create_count}, args->{create_info}, NULL, 63 arr->handle_storage); 64 return args->ret; 65}} 66''' 67 68SIMPLE_OBJECT_DESTROY_DRIVER_HANDLE_TEMPL = ''' 69/* destroy a driver {vk_type} */ 70static inline void 71vkr_{destroy_func_name}_destroy_driver_handle( 72 UNUSED struct vkr_context *ctx, 73 struct vn_command_{destroy_cmd} *args) 74{{ 75 struct vkr_device *dev = vkr_device_from_handle(args->device); 76 struct vn_device_proc_table *vk = &dev->proc_table; 77 78 /* handles in args are replaced */ 79 vn_replace_{destroy_cmd}_args_handle(args); 80 vk->{proc_destroy}(args->device, args->{destroy_obj}, NULL); 81}} 82''' 83 84POOL_OBJECT_DESTROY_DRIVER_HANDLES_TEMPL = ''' 85/* destroy an array of driver {vk_type}s from a pool, remove them from the 86 * vkr_{pool_type}, and return the list of affected vkr_{vkr_type}s 87 */ 88static inline void 89vkr_{destroy_func_name}_destroy_driver_handles( 90 UNUSED struct vkr_context *ctx, 91 struct vn_command_{destroy_cmd} *args, 92 struct list_head *free_list) 93{{ 94 struct vkr_device *dev = vkr_device_from_handle(args->device); 95 struct vn_device_proc_table *vk = &dev->proc_table; 96 97 list_inithead(free_list); 98 for (uint32_t i = 0; i < args->{destroy_count}; i++) {{ 99 struct vkr_{vkr_type} *obj = 100 vkr_{vkr_type}_from_handle(args->{destroy_objs}[i]); 101 if (!obj) 102 continue; 103 104 list_del(&obj->base.track_head); 105 list_addtail(&obj->base.track_head, free_list); 106 }} 107 108 /* handles in args are replaced */ 109 vn_replace_{destroy_cmd}_args_handle(args); 110 vk->{proc_destroy}(args->device, args->{destroy_pool}, 111 args->{destroy_count}, args->{destroy_objs}); 112}} 113''' 114 115PIPELINE_OBJECT_DESTROY_DRIVER_HANDLE_TEMPL = SIMPLE_OBJECT_DESTROY_DRIVER_HANDLE_TEMPL 116 117COMMON_OBJECT_INIT_ARRAY_TEMPL = ''' 118/* initialize an object_array for vkr_{vkr_type}s */ 119static inline VkResult 120vkr_{create_func_name}_init_array( 121 struct vkr_context *ctx, 122 struct vn_command_{create_cmd} *args, 123 struct object_array *arr) 124{{ 125 args->ret = object_array_init(ctx, arr, args->{create_count}, 126 {vk_enum}, sizeof(struct vkr_{vkr_type}), 127 sizeof(*args->{create_objs}), 128 args->{create_objs}) 129 ? VK_SUCCESS 130 : VK_ERROR_OUT_OF_HOST_MEMORY; 131 return args->ret; 132}} 133''' 134 135POOL_OBJECT_INIT_ARRAY_TEMPL = COMMON_OBJECT_INIT_ARRAY_TEMPL 136PIPELINE_OBJECT_INIT_ARRAY_TEMPL = COMMON_OBJECT_INIT_ARRAY_TEMPL 137 138SIMPLE_OBJECT_CREATE_TEMPL = ''' 139/* create a vkr_{vkr_type} */ 140static inline struct vkr_{vkr_type} * 141vkr_{create_func_name}_create( 142 struct vkr_context *ctx, 143 struct vn_command_{create_cmd} *args) 144{{ 145 struct vkr_{vkr_type} *obj = vkr_context_alloc_object(ctx, sizeof(*obj), 146 {vk_enum}, args->{create_obj}); 147 if (!obj) {{ 148 args->ret = VK_ERROR_OUT_OF_HOST_MEMORY; 149 return NULL; 150 }} 151 152 /* handles in args are replaced */ 153 if (vkr_{create_func_name}_create_driver_handle(ctx, args, obj) != VK_SUCCESS) {{ 154 free(obj); 155 return NULL; 156 }} 157 158 return obj; 159}} 160''' 161 162COMMON_OBJECT_CREATE_ARRAY_TEMPL = ''' 163/* create an array of vkr_{vkr_type}s */ 164static inline VkResult 165vkr_{create_func_name}_create_array( 166 struct vkr_context *ctx, 167 struct vn_command_{create_cmd} *args, 168 struct object_array *arr) 169{{ 170 if (vkr_{create_func_name}_init_array(ctx, args, arr) != VK_SUCCESS) 171 return args->ret; 172 173 if (vkr_{create_func_name}_create_driver_handles(ctx, args, arr) < VK_SUCCESS) {{ 174 /* In case the client expects a reply, clear all returned handles to 175 * VK_NULL_HANDLE. 176 */ 177 memset(args->{create_objs}, 0, 178 args->{create_count} * sizeof(args->{create_objs}[0])); 179 object_array_fini(arr); 180 return args->ret; 181 }} 182 183 return args->ret; 184}} 185''' 186 187POOL_OBJECT_CREATE_ARRAY_TEMPL = COMMON_OBJECT_CREATE_ARRAY_TEMPL 188PIPELINE_OBJECT_CREATE_ARRAY_TEMPL = COMMON_OBJECT_CREATE_ARRAY_TEMPL 189 190SIMPLE_OBJECT_CREATE_AND_ADD_TEMPL = ''' 191/* create a vkr_{vkr_type} and add it to the vkr_device */ 192static inline struct vkr_{vkr_type} * 193vkr_{create_func_name}_create_and_add( 194 struct vkr_context *ctx, 195 struct vn_command_{create_cmd} *args) 196{{ 197 struct vkr_device *dev = vkr_device_from_handle(args->device); 198 199 struct vkr_{vkr_type} *obj = vkr_{create_func_name}_create(ctx, args); 200 if (!obj) 201 return NULL; 202 203 vkr_device_add_object(ctx, dev, &obj->base); 204 return obj; 205}} 206''' 207 208POOL_OBJECT_ADD_ARRAY_TEMPL = ''' 209/* steal vkr_{vkr_type}s from an object_array and add them to the 210 * vkr_{pool_type} and the context 211 */ 212static inline 213void vkr_{create_func_name}_add_array( 214 struct vkr_context *ctx, 215 struct vkr_device *dev, 216 struct vkr_{pool_type} *pool, 217 struct object_array *arr) 218{{ 219 for (uint32_t i = 0; i < arr->count; i++) {{ 220 struct vkr_{vkr_type} *obj = arr->objects[i]; 221 222 obj->base.handle.{vkr_type} = (({vk_type} *)arr->handle_storage)[i]; 223 obj->device = dev; 224 225 /* pool objects are tracked by the pool other than the device */ 226 list_add(&obj->base.track_head, &pool->{vkr_type}s); 227 228 vkr_context_add_object(ctx, &obj->base); 229 }} 230 231 arr->objects_stolen = true; 232 object_array_fini(arr); 233}} 234''' 235 236PIPELINE_OBJECT_ADD_ARRAY_TEMPL = ''' 237/* steal vkr_{vkr_type}s from an object_array and add them to the device */ 238static inline void 239vkr_{create_func_name}_add_array( 240 struct vkr_context *ctx, 241 struct vkr_device *dev, 242 struct object_array *arr, 243 {vk_type} *args_{create_objs}) 244{{ 245 for (uint32_t i = 0; i < arr->count; i++) {{ 246 struct vkr_{vkr_type} *obj = arr->objects[i]; 247 248 obj->base.handle.{vkr_type} = (({vk_type} *)arr->handle_storage)[i]; 249 250 /* Individual pipelines may fail creation. */ 251 if (obj->base.handle.{vkr_type} == VK_NULL_HANDLE) {{ 252 free(obj); 253 arr->objects[i] = NULL; 254 args_{create_objs}[i] = VK_NULL_HANDLE; 255 }} else {{ 256 vkr_device_add_object(ctx, dev, &obj->base); 257 }} 258 }} 259 260 arr->objects_stolen = true; 261 object_array_fini(arr); 262}} 263''' 264 265SIMPLE_OBJECT_DESTROY_AND_REMOVE_TEMPL = ''' 266/* remove a vkr_{vkr_type} from the device and destroy it */ 267static inline void 268vkr_{destroy_func_name}_destroy_and_remove( 269 struct vkr_context *ctx, 270 struct vn_command_{destroy_cmd} *args) 271{{ 272 struct vkr_device *dev = vkr_device_from_handle(args->device); 273 struct vkr_{vkr_type} *obj = vkr_{vkr_type}_from_handle(args->{destroy_obj}); 274 if (!obj) 275 return; 276 277 vkr_{destroy_func_name}_destroy_driver_handle(ctx, args); 278 279 vkr_device_remove_object(ctx, dev, &obj->base); 280}} 281''' 282 283PIPELINE_OBJECT_DESTROY_AND_REMOVE_TEMPL = SIMPLE_OBJECT_DESTROY_AND_REMOVE_TEMPL 284 285def apply_variant(json_obj, json_variant): 286 tmp_obj = json_obj.copy() 287 for key, val in json_variant.items(): 288 tmp_obj[key] = val 289 return tmp_obj 290 291def simple_object_generator(json_obj): 292 '''Generate functions for a simple object. 293 294 For most device objects, object creation can be broken down into 3 steps 295 296 (1) allocate and initialize the object 297 (2) create the driver handle 298 (3) add the object to the device and the object table 299 300 SIMPLE_OBJECT_CREATE_DRIVER_HANDLE_TEMPL defines a function for (2). 301 SIMPLE_OBJECT_CREATE_TEMPL defines a function for (1) and (2). 302 SIMPLE_OBJECT_CREATE_AND_ADD_TEMPL defines a function for all steps. 303 304 Object destruction can be broken down into 2 steps 305 306 (1) destroy the driver handle 307 (2) remove the object from the device and the object table 308 309 SIMPLE_OBJECT_DESTROY_DRIVER_HANDLE_TEMPL defines a function for (1). 310 SIMPLE_OBJECT_DESTROY_AND_REMOVE_TEMPL defines a function for both steps. 311 ''' 312 contents = '' 313 314 contents += SIMPLE_OBJECT_CREATE_DRIVER_HANDLE_TEMPL.format(**json_obj) 315 contents += SIMPLE_OBJECT_CREATE_TEMPL.format(**json_obj) 316 contents += SIMPLE_OBJECT_CREATE_AND_ADD_TEMPL.format(**json_obj) 317 318 contents += SIMPLE_OBJECT_DESTROY_DRIVER_HANDLE_TEMPL.format(**json_obj) 319 contents += SIMPLE_OBJECT_DESTROY_AND_REMOVE_TEMPL.format(**json_obj) 320 321 for json_variant in json_obj['variants']: 322 tmp_obj = apply_variant(json_obj, json_variant) 323 contents += SIMPLE_OBJECT_CREATE_DRIVER_HANDLE_TEMPL.format(**tmp_obj) 324 contents += SIMPLE_OBJECT_CREATE_TEMPL.format(**tmp_obj) 325 contents += SIMPLE_OBJECT_CREATE_AND_ADD_TEMPL.format(**tmp_obj) 326 327 return contents 328 329def pool_object_generator(json_obj): 330 '''Generate functions for a pool object. 331 332 For VkCommandBuffer and VkDescriptorSet, object creation can be broken down 333 into 3 steps 334 335 (1) allocate and initialize the object array 336 (2) create the driver handles 337 (3) add the object array to the device and the object table 338 339 POOL_OBJECT_INIT_ARRAY_TEMPL defines a function for (1). 340 POOL_OBJECT_CREATE_DRIVER_HANDLES_TEMPL defines a function for (2). 341 POOL_OBJECT_CREATE_ARRAY_TEMPL defines a function for (1) and (2). 342 POOL_OBJECT_ADD_ARRAY_TEMPL defines a function for step (3). 343 344 Object destruction can be broken down into 2 steps 345 346 (1) destroy the driver handles 347 (2) remove the objects from the pool and the object table 348 349 POOL_OBJECT_DESTROY_DRIVER_HANDLES_TEMPL defines a function for (1) and 350 the first half of (2). 351 ''' 352 contents = '' 353 354 contents += POOL_OBJECT_INIT_ARRAY_TEMPL.format(**json_obj) 355 contents += POOL_OBJECT_CREATE_DRIVER_HANDLES_TEMPL.format(**json_obj) 356 contents += POOL_OBJECT_CREATE_ARRAY_TEMPL.format(**json_obj) 357 contents += POOL_OBJECT_ADD_ARRAY_TEMPL.format(**json_obj) 358 359 contents += POOL_OBJECT_DESTROY_DRIVER_HANDLES_TEMPL.format(**json_obj) 360 361 assert not json_obj['variants'] 362 363 return contents 364 365def pipeline_object_generator(json_obj): 366 '''Generate functions for a pipeline object. 367 368 For VkPipeline, object creation can be broken down into 3 steps 369 370 (1) allocate and initialize the object array 371 (2) create the driver handles 372 (3) add the object array to the device and the object table 373 374 PIPELINE_OBJECT_INIT_ARRAY_TEMPL defines a function for (1). 375 PIPELINE_OBJECT_CREATE_DRIVER_HANDLES_TEMPL defines a function for (2). 376 PIPELINE_OBJECT_CREATE_ARRAY_TEMPL defines a function for (1) and (2). 377 PIPELINE_OBJECT_ADD_ARRAY_TEMPL defines a function for step (3). 378 379 Object destruction can be broken down into 2 steps 380 381 (1) destroy the driver handle 382 (2) remove the object from the device and the object table 383 384 PIPELINE_OBJECT_DESTROY_DRIVER_HANDLE_TEMPL defines a function for (1). 385 PIPELINE_OBJECT_DESTROY_AND_REMOVE_TEMPL defines a function for both steps. 386 ''' 387 contents = '' 388 389 contents += PIPELINE_OBJECT_INIT_ARRAY_TEMPL.format(**json_obj) 390 contents += PIPELINE_OBJECT_CREATE_DRIVER_HANDLES_TEMPL.format(**json_obj) 391 contents += PIPELINE_OBJECT_CREATE_ARRAY_TEMPL.format(**json_obj) 392 393 # shared by both graphics and compute 394 tmp_obj = json_obj.copy() 395 tmp_obj['create_func_name'] = tmp_obj['vkr_type'] 396 contents += PIPELINE_OBJECT_ADD_ARRAY_TEMPL.format(**tmp_obj) 397 398 contents += PIPELINE_OBJECT_DESTROY_DRIVER_HANDLE_TEMPL.format(**json_obj) 399 contents += PIPELINE_OBJECT_DESTROY_AND_REMOVE_TEMPL.format(**json_obj) 400 401 for json_variant in json_obj['variants']: 402 tmp_obj = apply_variant(json_obj, json_variant) 403 contents += PIPELINE_OBJECT_INIT_ARRAY_TEMPL.format(**tmp_obj) 404 contents += PIPELINE_OBJECT_CREATE_DRIVER_HANDLES_TEMPL.format(**tmp_obj) 405 contents += PIPELINE_OBJECT_CREATE_ARRAY_TEMPL.format(**tmp_obj) 406 407 return contents 408 409object_generators = { 410 'simple-object': simple_object_generator, 411 'pool-object': pool_object_generator, 412 'pipeline-object': pipeline_object_generator, 413} 414 415FILE_HEADER_TEMPL = ''' 416/* This file is generated by {script}. */ 417 418#ifndef {guard} 419#define {guard} 420 421#include "vkr_common.h" 422 423{protocol_includes} 424 425#include "vkr_context.h" 426#include "vkr_device.h" 427''' 428 429FILE_FOOTER_TEMPL = ''' 430#endif /* {guard} */ 431''' 432 433def get_guard(filename): 434 return filename.upper().translate(str.maketrans('.', '_')) 435 436def file_header_generator(json_file): 437 script = os.path.basename(__file__) 438 guard = get_guard(json_file['filename']) 439 440 include_filenames = [] 441 for json_obj in json_file['objects']: 442 name = 'venus-protocol/vn_protocol_renderer_{}.h'.format( 443 json_obj['vkr_type']) 444 include_filenames.append(name) 445 protocol_includes = '#include "' + '"\n#include "'.join(include_filenames) + '"' 446 447 return FILE_HEADER_TEMPL.format(script=script, guard=guard, 448 protocol_includes=protocol_includes).lstrip() 449 450def file_footer_generator(json_file): 451 guard = get_guard(json_file['filename']) 452 return FILE_FOOTER_TEMPL.format(guard=guard) 453 454def process_objects(json_objs): 455 for json_obj in json_objs: 456 json_obj.setdefault('create_func_name', json_obj['vkr_type']) 457 json_obj.setdefault('destroy_func_name', json_obj['vkr_type']) 458 json_obj.setdefault('variants', []) 459 json_obj['proc_create'] = json_obj.get('create_cmd')[2:] 460 json_obj['proc_destroy'] = json_obj.get('destroy_cmd')[2:] 461 for variant in json_obj.get('variants'): 462 if variant.get('create_cmd') != None: 463 variant['proc_create'] = variant.get('create_cmd')[2:] 464 if variant.get('destroy_cmd') != None: 465 variant['proc_destroy'] = variant.get('create_cmd')[2:] 466 467def file_generator(json_file): 468 contents = file_header_generator(json_file) 469 for json_obj in json_file['objects']: 470 contents += object_generators[json_obj['generator']](json_obj) 471 contents += file_footer_generator(json_file) 472 473 return contents 474 475def parse_args(): 476 parser = argparse.ArgumentParser() 477 parser.add_argument('json', help='specifies the input JSON file') 478 parser.add_argument('-o', '--output-dir', required=True, 479 help='specifies output directory') 480 return parser.parse_args() 481 482def main(): 483 args = parse_args() 484 with open(args.json) as f: 485 json_files = json.load(f) 486 487 for json_file in json_files: 488 process_objects(json_file['objects']) 489 490 output = os.path.join(args.output_dir, json_file['filename']) 491 with open(output, 'wb') as f: 492 contents = file_generator(json_file) 493 f.write(contents.encode()) 494 495if __name__ == '__main__': 496 main() 497