xref: /aosp_15_r20/external/virglrenderer/src/venus/vkr_device_object.py (revision bbecb9d118dfdb95f99bd754f8fa9be01f189df3)
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