xref: /aosp_15_r20/external/mesa3d/src/gfxstream/codegen/scripts/cerealgenerator.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1# Copyright 2023 Google LLC
2# SPDX-License-Identifier: MIT
3
4import os, re, sys
5from generator import *
6from pathlib import Path, PurePosixPath
7
8import cereal
9from cereal.wrapperdefs import VULKAN_STREAM_TYPE
10from cereal.wrapperdefs import VULKAN_STREAM_TYPE_GUEST
11
12# CerealGenerator - generates set of driver sources
13# while being agnostic to the stream implementation
14from reg import GroupInfo, TypeInfo, EnumInfo
15
16VK_CEREAL_FLAG_HOST = 1
17VK_CEREAL_FLAG_GUEST = 2
18VK_CEREAL_FLAG_ALL = VK_CEREAL_FLAG_GUEST | VK_CEREAL_FLAG_HOST
19
20SUPPORTED_FEATURES = [
21    "VK_VERSION_1_0",
22    "VK_VERSION_1_1",
23    "VK_VERSION_1_2",
24    "VK_VERSION_1_3",
25    # Instance extensions
26    "VK_KHR_get_physical_device_properties2",
27    "VK_KHR_external_semaphore_capabilities",
28    "VK_KHR_external_memory_capabilities",
29    "VK_KHR_external_fence_capabilities",
30    "VK_EXT_debug_utils",
31    "VK_EXT_debug_report",
32    "VK_EXT_validation_features",
33    # Device extensions
34    "VK_EXT_external_memory_host",
35    "VK_KHR_storage_buffer_storage_class",
36    "VK_KHR_vulkan_memory_model",
37    "VK_KHR_buffer_device_address",
38    "VK_KHR_maintenance1",
39    "VK_KHR_maintenance2",
40    "VK_KHR_maintenance3",
41    "VK_KHR_bind_memory2",
42    "VK_KHR_dedicated_allocation",
43    "VK_KHR_get_memory_requirements2",
44    "VK_KHR_sampler_ycbcr_conversion",
45    "VK_KHR_shader_float16_int8",
46    "VK_AMD_gpu_shader_half_float",
47    "VK_NV_shader_subgroup_partitioned",
48    "VK_KHR_shader_subgroup_extended_types",
49    "VK_EXT_provoking_vertex",
50    "VK_EXT_line_rasterization",
51    "VK_KHR_line_rasterization",
52    "VK_EXT_transform_feedback",
53    "VK_EXT_primitive_topology_list_restart",
54    "VK_EXT_index_type_uint8",
55    "VK_EXT_load_store_op_none",
56    "VK_EXT_swapchain_colorspace",
57    "VK_EXT_custom_border_color",
58    "VK_EXT_shader_stencil_export",
59    "VK_KHR_image_format_list",
60    "VK_KHR_incremental_present",
61    "VK_KHR_pipeline_executable_properties",
62    "VK_EXT_queue_family_foreign",
63    "VK_EXT_scalar_block_layout",
64    "VK_KHR_external_semaphore",
65    "VK_KHR_external_semaphore_fd",
66    "VK_KHR_external_memory",
67    "VK_KHR_external_fence",
68    "VK_KHR_external_fence_fd",
69    "VK_EXT_device_memory_report",
70    "VK_KHR_create_renderpass2",
71    "VK_KHR_imageless_framebuffer",
72    "VK_KHR_descriptor_update_template",
73    "VK_EXT_depth_clip_enable",
74    "VK_EXT_robustness2",
75    # see aosp/2736079 + b/268351352
76    "VK_EXT_swapchain_maintenance1",
77    "VK_KHR_maintenance5",
78    "VK_EXT_host_image_copy",
79    "VK_EXT_image_compression_control",
80    "VK_EXT_image_compression_control_swapchain",
81    "VK_EXT_image_drm_format_modifier",
82    # VK1.3 extensions: see b/298704840
83    "VK_KHR_copy_commands2",
84    "VK_KHR_dynamic_rendering",
85    "VK_KHR_format_feature_flags2",
86    "VK_KHR_maintenance4",
87    "VK_KHR_shader_integer_dot_product",
88    "VK_KHR_shader_non_semantic_info",
89    "VK_KHR_shader_terminate_invocation",
90    "VK_KHR_synchronization2",
91    "VK_KHR_zero_initialize_workgroup_memory",
92    "VK_EXT_4444_formats",
93    "VK_EXT_extended_dynamic_state",
94    "VK_EXT_extended_dynamic_state2",
95    "VK_EXT_image_robustness",
96    "VK_EXT_inline_uniform_block",
97    "VK_EXT_pipeline_creation_cache_control",
98    "VK_EXT_pipeline_creation_feedback",
99    "VK_EXT_private_data",
100    "VK_EXT_shader_demote_to_helper_invocation",
101    "VK_EXT_subgroup_size_control",
102    "VK_EXT_texel_buffer_alignment",
103    "VK_EXT_texture_compression_astc_hdr",
104    "VK_EXT_tooling_info",
105    "VK_EXT_ycbcr_2plane_444_formats",
106    # Host dispatch
107    "VK_KHR_surface",
108    "VK_KHR_swapchain",
109    "VK_KHR_xcb_surface",
110    "VK_KHR_win32_surface",
111    "VK_EXT_metal_surface",
112    "VK_EXT_metal_objects",
113    "VK_EXT_external_memory_metal",
114    "VK_KHR_external_semaphore_win32",
115    "VK_KHR_external_memory_win32",
116    "VK_NV_device_diagnostic_checkpoints",
117    "VK_KHR_ray_tracing_pipeline",
118    "VK_KHR_pipeline_library",
119    # Android
120    "VK_ANDROID_native_buffer",
121    "VK_ANDROID_external_memory_android_hardware_buffer",
122    "VK_KHR_android_surface",
123    # Linux
124    "VK_KHR_external_memory_fd",
125    # Custom
126    "VK_GOOGLE_gfxstream",
127    # Used in tests without proper support checks
128    "VK_EXT_graphics_pipeline_library",
129    # Used by guest ANGLE
130    "VK_EXT_vertex_attribute_divisor",
131    # QNX
132    "VK_QNX_external_memory_screen_buffer",
133    # b/320855472 Chrome
134    "VK_EXT_fragment_density_map",
135    # b/349122558 Zink
136    "VK_EXT_color_write_enable",
137]
138
139HOST_MODULES = ["goldfish_vk_extension_structs", "goldfish_vk_marshaling",
140                "goldfish_vk_reserved_marshaling", "goldfish_vk_deepcopy",
141                "goldfish_vk_dispatch", "goldfish_vk_transform", "VkDecoder",
142                "VkDecoderSnapshot", "VkSubDecoder"]
143
144# By default, the all wrappers are run all on all features.  In certain cases,
145# we wish run wrappers when the module requires it. For example, `VK_GOOGLE_gfxstream`
146# shouldn't generate a function table entry since it's an internal interface.
147SUPPORTED_MODULES = {
148    "VK_EXT_external_memory_host": HOST_MODULES,
149    "VK_EXT_debug_utils": HOST_MODULES,
150    "VK_EXT_debug_report": HOST_MODULES,
151    "VK_EXT_validation_features": HOST_MODULES,
152    "VK_KHR_surface": ["goldfish_vk_dispatch"],
153    "VK_KHR_xcb_surface": ["goldfish_vk_dispatch"],
154    "VK_KHR_win32_surface": ["goldfish_vk_dispatch"],
155    "VK_EXT_metal_surface": ["goldfish_vk_dispatch"],
156    "VK_EXT_metal_objects": ["goldfish_vk_dispatch"],
157    "VK_EXT_external_memory_metal": ["goldfish_vk_dispatch"],
158    "VK_KHR_external_semaphore_win32" : ["goldfish_vk_dispatch"],
159    "VK_KHR_external_memory_win32" : ["goldfish_vk_dispatch"],
160    # Host dispatch for Linux hosts + and entrypoint for guests
161    "VK_KHR_external_memory_fd": ["goldfish_vk_dispatch", "func_table"],
162    "VK_QNX_external_memory_screen_buffer": ["goldfish_vk_dispatch"],
163    "VK_ANDROID_external_memory_android_hardware_buffer": ["func_table"],
164    "VK_KHR_android_surface": ["func_table"],
165    "VK_EXT_swapchain_maintenance1" : HOST_MODULES,
166    "VK_KHR_swapchain" : HOST_MODULES,
167    "VK_NV_device_diagnostic_checkpoints": ["goldfish_vk_dispatch"],
168    "VK_KHR_ray_tracing_pipeline": HOST_MODULES,
169    "VK_KHR_pipeline_library": HOST_MODULES,
170}
171
172# These modules will be used when the feature is not supported.
173# This is necessary to cover all extensions where needed.
174UNSUPPORTED_FEATURE_MODULES = {
175    "goldfish_vk_extension_structs",
176}
177
178
179REQUIRED_TYPES = {
180    "int",
181    "uint16_t",
182    "int64_t",
183    "double",
184    "VkPresentScalingFlagsEXT",
185    "VkPresentGravityFlagsEXT",
186}
187
188copyrightHeader = """// Copyright (C) 2018 The Android Open Source Project
189// Copyright (C) 2018 Google Inc.
190//
191// Licensed under the Apache License, Version 2.0 (the "License");
192// you may not use this file except in compliance with the License.
193// You may obtain a copy of the License at
194//
195// http://www.apache.org/licenses/LICENSE-2.0
196//
197// Unless required by applicable law or agreed to in writing, software
198// distributed under the License is distributed on an "AS IS" BASIS,
199// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200// See the License for the specific language governing permissions and
201// limitations under the License.
202"""
203
204# We put the long generated commands in a separate paragraph, so that the formatter won't mess up
205# with other texts.
206autogeneratedHeaderTemplate = """
207// Autogenerated module %s
208//
209// %s
210//
211// Please do not modify directly;
212// re-run mesa3d/src/gfxstream/codegen/generate-gfxstream-vulkan.sh,
213// or directly from Python by defining:
214// VULKAN_REGISTRY_XML_DIR : Directory containing vk.xml
215// VULKAN_REGISTRY_SCRIPTS_DIR : Directory containing genvk.py
216// CEREAL_OUTPUT_DIR: Where to put the generated sources.
217//
218// python3 $VULKAN_REGISTRY_SCRIPTS_DIR/genvk.py -registry $VULKAN_REGISTRY_XML_DIR/vk.xml cereal -o $CEREAL_OUTPUT_DIR
219//
220"""
221namespaceBegin ="""
222namespace gfxstream {
223namespace vk {\n
224"""
225
226namespaceEnd = """
227}  // namespace vk
228}  // namespace gfxstream
229"""
230
231def banner_command(argv):
232    """Return sanitized command-line description.
233       |argv| must be a list of command-line parameters, e.g. sys.argv.
234       Return a string corresponding to the command, with platform-specific
235       paths removed."""
236
237    def makePosixRelative(someArg):
238        # Do not use relative for /tmp/ to avoid effects of checkout location
239        if os.path.exists(someArg) and someArg != "/tmp/":
240            return str(PurePosixPath(Path(os.path.relpath(someArg))))
241        return someArg
242
243    return ' '.join(map(makePosixRelative, argv))
244
245def envGetOrDefault(key, default=None):
246    if key in os.environ:
247        return os.environ[key]
248    return default
249
250# ---- methods overriding base class ----
251# beginFile(genOpts)
252# endFile()
253# beginFeature(interface, emit)
254# endFeature()
255# genType(typeinfo,name)
256# genStruct(typeinfo,name)
257# genGroup(groupinfo,name)
258# genEnum(enuminfo, name)
259# genCmd(cmdinfo)
260class CerealGenerator(OutputGenerator):
261
262    """Generate serialization code"""
263    def __init__(self, errFile = sys.stderr,
264                       warnFile = sys.stderr,
265                       diagFile = sys.stdout):
266        OutputGenerator.__init__(self, errFile, warnFile, diagFile)
267
268        self.typeInfo = cereal.VulkanTypeInfo(self)
269
270        self.modules = {}
271        self.protos = {}
272        self.moduleList = []
273        self.protoList = []
274
275        self.wrappers = []
276
277        self.codegen = cereal.CodeGen()
278        self.featureSupported = False
279        self.supportedModules = None
280
281        self.baseLibDirPrefix = "aemu/base"
282        self.utilsHeaderDirPrefix = "utils"
283
284        # The cereal variant should be an environmental variable of one of
285        # the following:
286        #    - "guest"
287        #    - "host"
288        #    - "both"
289        cerealVariant = envGetOrDefault("CEREAL_VARIANT", "both")
290        if cerealVariant == "guest":
291          self.cerealFlags = VK_CEREAL_FLAG_GUEST
292        elif cerealVariant == "host":
293          self.cerealFlags = VK_CEREAL_FLAG_HOST
294        else:
295          self.cerealFlags = VK_CEREAL_FLAG_ALL
296
297        # THe host always needs all possible guest struct definitions, while the guest only needs
298        # platform sepcific headers.
299        self.hostCommonExtraVulkanHeaders = '#include "vk_android_native_buffer_gfxstream.h"'
300
301        encoderInclude = f"""
302#include "goldfish_vk_private_defs.h"
303#include <memory>
304
305namespace gfxstream {{
306namespace guest {{
307class IOStream;
308}}  // namespace guest
309}}  // namespace gfxstream
310"""
311        encoderImplInclude = f"""
312#include "Resources.h"
313#include "ResourceTracker.h"
314#include "Validation.h"
315#include "%s.h"
316#include "gfxstream/guest/IOStream.h"
317
318#include "AlignedBuf.h"
319#include "BumpPool.h"
320
321#include "goldfish_vk_marshaling_guest.h"
322#include "goldfish_vk_reserved_marshaling_guest.h"
323#include "goldfish_vk_deepcopy_guest.h"
324#include "goldfish_vk_counting_guest.h"
325#include "goldfish_vk_private_defs.h"
326#include "goldfish_vk_transform_guest.h"
327
328#include <memory>
329#include <optional>
330#include <unordered_map>
331#include <string>
332#include <vector>
333
334""" % VULKAN_STREAM_TYPE_GUEST
335
336        functableImplInclude = """
337#include "VkEncoder.h"
338#include "ResourceTracker.h"
339#include "gfxstream_vk_entrypoints.h"
340#include "gfxstream_vk_private.h"
341
342#include "goldfish_vk_private_defs.h"
343
344#include <cstring>
345
346// Stuff we are not going to use but if included,
347// will cause compile errors. These are Android Vulkan
348// required extensions, but the approach will be to
349// implement them completely on the guest side.
350#undef VK_KHR_android_surface
351#if defined(LINUX_GUEST_BUILD) || defined(__Fuchsia__)
352#undef VK_ANDROID_native_buffer
353#endif
354"""
355        marshalIncludeGuest = """
356#include "goldfish_vk_marshaling_guest.h"
357#include "goldfish_vk_private_defs.h"
358#include "%s.h"
359
360// Stuff we are not going to use but if included,
361// will cause compile errors. These are Android Vulkan
362// required extensions, but the approach will be to
363// implement them completely on the guest side.
364#undef VK_KHR_android_surface
365#undef VK_ANDROID_external_memory_android_hardware_buffer
366""" % VULKAN_STREAM_TYPE_GUEST
367
368        reservedmarshalIncludeGuest = """
369#include "goldfish_vk_marshaling_guest.h"
370#include "goldfish_vk_private_defs.h"
371#include "%s.h"
372
373// Stuff we are not going to use but if included,
374// will cause compile errors. These are Android Vulkan
375// required extensions, but the approach will be to
376// implement them completely on the guest side.
377#undef VK_KHR_android_surface
378#undef VK_ANDROID_external_memory_android_hardware_buffer
379""" % VULKAN_STREAM_TYPE_GUEST
380
381        reservedmarshalImplIncludeGuest = """
382#include "Resources.h"
383"""
384
385        vulkanStreamIncludeHost = f"""
386{self.hostCommonExtraVulkanHeaders}
387#include "goldfish_vk_private_defs.h"
388
389#include "%s.h"
390#include "{self.baseLibDirPrefix}/files/StreamSerializing.h"
391""" % VULKAN_STREAM_TYPE
392
393        poolInclude = f"""
394{self.hostCommonExtraVulkanHeaders}
395#include "goldfish_vk_private_defs.h"
396#include "{self.baseLibDirPrefix}/BumpPool.h"
397using android::base::Allocator;
398using android::base::BumpPool;
399"""
400        transformIncludeGuest = """
401#include "goldfish_vk_private_defs.h"
402"""
403        transformInclude = f"""
404{self.hostCommonExtraVulkanHeaders}
405#include "goldfish_vk_private_defs.h"
406#include "goldfish_vk_extension_structs.h"
407"""
408        transformImplIncludeGuest = """
409#include "ResourceTracker.h"
410"""
411        transformImplInclude = """
412#include "VkDecoderGlobalState.h"
413"""
414        deepcopyInclude = """
415#include "vk_util.h"
416"""
417        poolIncludeGuest = f"""
418#include "goldfish_vk_private_defs.h"
419#include "BumpPool.h"
420using gfxstream::aemu::Allocator;
421using gfxstream::aemu::BumpPool;
422// Stuff we are not going to use but if included,
423// will cause compile errors. These are Android Vulkan
424// required extensions, but the approach will be to
425// implement them completely on the guest side.
426#undef VK_KHR_android_surface
427#undef VK_ANDROID_external_memory_android_hardware_buffer
428"""
429        dispatchHeaderDefs = f"""
430{self.hostCommonExtraVulkanHeaders}
431#include "goldfish_vk_private_defs.h"
432namespace gfxstream {{
433namespace vk {{
434
435struct VulkanDispatch;
436
437}} // namespace vk
438}} // namespace gfxstream
439using DlOpenFunc = void* (void);
440using DlSymFunc = void* (void*, const char*);
441"""
442
443        extensionStructsInclude = f"""
444{self.hostCommonExtraVulkanHeaders}
445#include "goldfish_vk_private_defs.h"
446#include "host-common/GfxstreamFatalError.h"
447#include "vulkan/vk_enum_string_helper.h"
448"""
449
450        extensionStructsIncludeGuest = """
451#include "vk_platform_compat.h"
452#include "goldfish_vk_private_defs.h"
453// Stuff we are not going to use but if included,
454// will cause compile errors. These are Android Vulkan
455// required extensions, but the approach will be to
456// implement them completely on the guest side.
457#undef VK_KHR_android_surface
458#undef VK_ANDROID_external_memory_android_hardware_buffer
459"""
460        commonCerealImplIncludes = """
461#include "goldfish_vk_extension_structs.h"
462#include "goldfish_vk_private_defs.h"
463#include <string.h>
464"""
465        commonCerealIncludesGuest = """
466#include "vk_platform_compat.h"
467"""
468        commonCerealImplIncludesGuest = """
469#include "goldfish_vk_extension_structs_guest.h"
470#include "goldfish_vk_private_defs.h"
471
472#include <cstring>
473"""
474        countingIncludes = """
475#include "vk_platform_compat.h"
476#include "goldfish_vk_private_defs.h"
477"""
478
479        dispatchImplIncludes = """
480#include <stdio.h>
481#include <stdlib.h>
482#include <string.h>
483"""
484
485        decoderSnapshotHeaderIncludes = f"""
486#include <memory>
487#include "{self.utilsHeaderDirPrefix}/GfxApiLogger.h"
488#include "{self.baseLibDirPrefix}/HealthMonitor.h"
489#include "goldfish_vk_private_defs.h"
490"""
491        decoderSnapshotImplIncludes = f"""
492#include "VulkanHandleMapping.h"
493#include "VkDecoderGlobalState.h"
494#include "VkReconstruction.h"
495
496#include "{self.baseLibDirPrefix}/synchronization/Lock.h"
497"""
498
499        decoderHeaderIncludes = f"""
500#include "VkDecoderContext.h"
501#include "ProcessResources.h"
502
503#include <memory>
504
505namespace android {{
506namespace base {{
507class BumpPool;
508}} // namespace android
509}} // namespace base
510
511"""
512
513        decoderImplIncludes = f"""
514#include "common/goldfish_vk_marshaling.h"
515#include "common/goldfish_vk_reserved_marshaling.h"
516#include "goldfish_vk_private_defs.h"
517#include "common/goldfish_vk_transform.h"
518
519#include "{self.baseLibDirPrefix}/BumpPool.h"
520#include "{self.baseLibDirPrefix}/system/System.h"
521#include "{self.baseLibDirPrefix}/Metrics.h"
522#include "render-utils/IOStream.h"
523#include "FrameBuffer.h"
524#include "gfxstream/host/Tracing.h"
525#include "host-common/feature_control.h"
526#include "host-common/GfxstreamFatalError.h"
527#include "host-common/logging.h"
528
529#include "VkDecoderGlobalState.h"
530#include "VkDecoderSnapshot.h"
531
532#include "VulkanDispatch.h"
533#include "%s.h"
534
535#include <functional>
536#include <optional>
537#include <unordered_map>
538""" % VULKAN_STREAM_TYPE
539
540        def createVkExtensionStructureTypePreamble(extensionName: str) -> str:
541            return f"""
542#define {extensionName}_ENUM(type,id) \
543    ((type)(1000000000 + (1000 * ({extensionName}_NUMBER - 1)) + (id)))
544"""
545        self.guest_encoder_tag = "guest_encoder"
546        self.host_tag = "host"
547
548        default_guest_abs_encoder_destination = \
549            os.path.join(
550                os.getcwd(),
551                "..", "..",
552                "device", "generic", "goldfish-opengl",
553                "system", "vulkan_enc")
554        self.guest_abs_encoder_destination = \
555            envGetOrDefault("GFXSTREAM_GUEST_ENCODER_DIR",
556                            default_guest_abs_encoder_destination)
557
558        default_host_abs_decoder_destination = \
559            os.path.join(
560                os.getcwd(),
561                "android", "android-emugl", "host",
562                "libs", "libOpenglRender", "vulkan")
563        self.host_abs_decoder_destination = \
564            envGetOrDefault("GFXSTREAM_HOST_DECODER_DIR",
565                            default_host_abs_decoder_destination)
566        self.host_script_destination = envGetOrDefault("GFXSTREAM_SCRIPTS_DIR")
567
568        if self.cerealFlags & VK_CEREAL_FLAG_GUEST:
569            self.addGuestEncoderModule(
570                "VkEncoder",
571                extraHeader = encoderInclude,
572                extraImpl = encoderImplInclude)
573
574            self.addGuestEncoderModule("goldfish_vk_extension_structs_guest",
575                                       extraHeader=extensionStructsIncludeGuest)
576            self.addGuestEncoderModule("goldfish_vk_marshaling_guest",
577                                       extraHeader=commonCerealIncludesGuest + marshalIncludeGuest,
578                                       extraImpl=commonCerealImplIncludesGuest)
579            self.addGuestEncoderModule("goldfish_vk_reserved_marshaling_guest",
580                                       extraHeader=commonCerealIncludesGuest + reservedmarshalIncludeGuest,
581                                       extraImpl=commonCerealImplIncludesGuest + reservedmarshalImplIncludeGuest)
582            self.addGuestEncoderModule("goldfish_vk_deepcopy_guest",
583                                       extraHeader=commonCerealIncludesGuest + poolIncludeGuest,
584                                       extraImpl=commonCerealImplIncludesGuest + deepcopyInclude)
585            self.addGuestEncoderModule("goldfish_vk_counting_guest",
586                                       extraHeader=countingIncludes,
587                                       extraImpl=commonCerealImplIncludesGuest)
588            self.addGuestEncoderModule("goldfish_vk_transform_guest",
589                                       extraHeader=commonCerealIncludesGuest + transformIncludeGuest,
590                                       extraImpl=commonCerealImplIncludesGuest + transformImplIncludeGuest)
591            self.addGuestEncoderModule(
592                "vulkan_gfxstream_structure_type", headerOnly=True, suppressFeatureGuards=True,
593                moduleName="vulkan_gfxstream_structure_type_guest", useNamespace=False,
594                suppressVulkanHeaders=True,
595                extraHeader=createVkExtensionStructureTypePreamble('VK_GOOGLE_GFXSTREAM'))
596
597            self.addGuestEncoderModule("func_table", extraImpl=functableImplInclude, implOnly = True,
598                                    useNamespace = False)
599
600            self.addWrapper(cereal.VulkanEncoder, "VkEncoder")
601            self.addWrapper(cereal.VulkanExtensionStructs, "goldfish_vk_extension_structs_guest", variant = "guest")
602            self.addWrapper(cereal.VulkanMarshaling, "goldfish_vk_marshaling_guest", variant = "guest")
603            self.addWrapper(cereal.VulkanReservedMarshaling, "goldfish_vk_reserved_marshaling_guest", variant = "guest")
604            self.addWrapper(cereal.VulkanDeepcopy, "goldfish_vk_deepcopy_guest")
605            self.addWrapper(cereal.VulkanCounting, "goldfish_vk_counting_guest")
606            self.addWrapper(cereal.VulkanTransform, "goldfish_vk_transform_guest")
607            self.addWrapper(cereal.VulkanFuncTable, "func_table")
608            self.addWrapper(cereal.VulkanGfxstreamStructureType,
609                            "vulkan_gfxstream_structure_type_guest")
610
611        if self.cerealFlags & VK_CEREAL_FLAG_HOST:
612            self.addCppModule("common", "goldfish_vk_extension_structs",
613                           extraHeader=extensionStructsInclude)
614            self.addCppModule("common", "goldfish_vk_marshaling",
615                           extraHeader=vulkanStreamIncludeHost,
616                           extraImpl=commonCerealImplIncludes)
617            self.addCppModule("common", "goldfish_vk_reserved_marshaling",
618                           extraHeader=vulkanStreamIncludeHost,
619                           extraImpl=commonCerealImplIncludes)
620            self.addCppModule("common", "goldfish_vk_deepcopy",
621                           extraHeader=poolInclude,
622                           extraImpl=commonCerealImplIncludes + deepcopyInclude)
623            self.addCppModule("common", "goldfish_vk_dispatch",
624                           extraHeader=dispatchHeaderDefs,
625                           extraImpl=dispatchImplIncludes)
626            self.addCppModule("common", "goldfish_vk_transform",
627                           extraHeader=transformInclude,
628                           extraImpl=transformImplInclude)
629            self.addHostModule("VkDecoder",
630                               extraHeader=decoderHeaderIncludes,
631                               extraImpl=decoderImplIncludes,
632                               useNamespace=False)
633            self.addHostModule("VkDecoderSnapshot",
634                               extraHeader=decoderSnapshotHeaderIncludes,
635                               extraImpl=decoderSnapshotImplIncludes,
636                               useNamespace=False)
637            self.addHostModule("VkSubDecoder",
638                               extraHeader="",
639                               extraImpl="",
640                               useNamespace=False,
641                               implOnly=True)
642
643            self.addModule(cereal.PyScript(self.host_tag, "vulkan_printer", customAbsDir=Path(
644                self.host_script_destination) / "print_gfx_logs"), moduleName="ApiLogDecoder")
645            self.addHostModule(
646                "vulkan_gfxstream_structure_type", headerOnly=True, suppressFeatureGuards=True,
647                moduleName="vulkan_gfxstream_structure_type_host", useNamespace=False,
648                suppressVulkanHeaders=True,
649                extraHeader=createVkExtensionStructureTypePreamble('VK_GOOGLE_GFXSTREAM'))
650            self.addHostModule(
651                "vk_android_native_buffer_structure_type", headerOnly=True, suppressFeatureGuards=True,
652                useNamespace=False, suppressVulkanHeaders=True,
653                extraHeader=createVkExtensionStructureTypePreamble('VK_ANDROID_NATIVE_BUFFER'))
654
655            self.addWrapper(cereal.VulkanExtensionStructs, "goldfish_vk_extension_structs", variant = "host")
656            self.addWrapper(cereal.VulkanMarshaling, "goldfish_vk_marshaling")
657            self.addWrapper(cereal.VulkanReservedMarshaling, "goldfish_vk_reserved_marshaling", variant = "host")
658            self.addWrapper(cereal.VulkanDeepcopy, "goldfish_vk_deepcopy")
659            self.addWrapper(cereal.VulkanDispatch, "goldfish_vk_dispatch")
660            self.addWrapper(cereal.VulkanTransform, "goldfish_vk_transform", resourceTrackerTypeName="VkDecoderGlobalState")
661            self.addWrapper(cereal.VulkanDecoder, "VkDecoder")
662            self.addWrapper(cereal.VulkanDecoderSnapshot, "VkDecoderSnapshot")
663            self.addWrapper(cereal.VulkanSubDecoder, "VkSubDecoder")
664            self.addWrapper(cereal.ApiLogDecoder, "ApiLogDecoder")
665            self.addWrapper(cereal.VulkanGfxstreamStructureType, "vulkan_gfxstream_structure_type_host")
666            self.addWrapper(cereal.VulkanAndroidNativeBufferStructureType,
667                            "vk_android_native_buffer_structure_type")
668
669    def addGuestEncoderModule(
670            self, basename, extraHeader="", extraImpl="", useNamespace=True, headerOnly=False,
671            suppressFeatureGuards=False, moduleName=None, suppressVulkanHeaders=False, implOnly=False):
672        if not os.path.exists(self.guest_abs_encoder_destination):
673            print("Path [%s] not found (guest encoder path), skipping" % self.guest_abs_encoder_destination)
674            return
675        self.addCppModule(self.guest_encoder_tag, basename, extraHeader=extraHeader,
676                       extraImpl=extraImpl, customAbsDir=self.guest_abs_encoder_destination,
677                       useNamespace=useNamespace, implOnly=implOnly, headerOnly=headerOnly,
678                       suppressFeatureGuards=suppressFeatureGuards, moduleName=moduleName,
679                       suppressVulkanHeaders=suppressVulkanHeaders)
680
681    def addHostModule(
682            self, basename, extraHeader="", extraImpl="", useNamespace=True, implOnly=False,
683            suppress=False, headerOnly=False, suppressFeatureGuards=False, moduleName=None,
684            suppressVulkanHeaders=False):
685        if not os.path.exists(self.host_abs_decoder_destination):
686            print("Path [%s] not found (host encoder path), skipping" %
687                  self.host_abs_decoder_destination)
688            return
689        if not suppressVulkanHeaders:
690            extraHeader = self.hostCommonExtraVulkanHeaders + '\n' + extraHeader
691        self.addCppModule(
692            self.host_tag, basename, extraHeader=extraHeader, extraImpl=extraImpl,
693            customAbsDir=self.host_abs_decoder_destination, useNamespace=useNamespace,
694            implOnly=implOnly, suppress=suppress, headerOnly=headerOnly,
695            suppressFeatureGuards=suppressFeatureGuards, moduleName=moduleName,
696            suppressVulkanHeaders=suppressVulkanHeaders)
697
698    def addModule(self, module, moduleName=None):
699        if moduleName is None:
700            moduleName = module.basename
701        self.moduleList.append(moduleName)
702        self.modules[moduleName] = module
703
704    def addCppModule(
705            self, directory, basename, extraHeader="", extraImpl="", customAbsDir=None,
706            useNamespace=True, implOnly=False, suppress=False, headerOnly=False,
707            suppressFeatureGuards=False, moduleName=None, suppressVulkanHeaders=False):
708        module = cereal.Module(
709            directory, basename, customAbsDir=customAbsDir, suppress=suppress, implOnly=implOnly,
710            headerOnly=headerOnly, suppressFeatureGuards=suppressFeatureGuards)
711        self.addModule(module, moduleName=moduleName)
712        module.headerPreamble = copyrightHeader
713        module.headerPreamble += \
714                autogeneratedHeaderTemplate % \
715                (basename, "(header) generated by %s" % banner_command(sys.argv))
716
717        module.headerPreamble += "#pragma once\n"
718        if (not suppressVulkanHeaders):
719            module.headerPreamble += "#include <vulkan/vulkan.h>\n"
720            module.headerPreamble += '#include "vulkan_gfxstream.h"\n'
721            module.headerPreamble += '#include "vk_android_native_buffer_gfxstream.h"\n'
722        module.headerPreamble += extraHeader + '\n'
723        if useNamespace:
724            module.headerPreamble += namespaceBegin
725
726        module.implPreamble = copyrightHeader
727        module.implPreamble += \
728                autogeneratedHeaderTemplate % \
729                (basename, "(impl) generated by %s" % \
730                    banner_command(sys.argv))
731        if not implOnly:
732            module.implPreamble += '\n#include "%s.h"' % \
733                (basename)
734
735        module.implPreamble += extraImpl
736
737        if useNamespace:
738            module.implPreamble += namespaceBegin
739            module.implPostamble += namespaceEnd
740            module.headerPostamble += namespaceEnd
741
742    def addWrapper(self, moduleType, moduleName, **kwargs):
743        if moduleName not in self.modules:
744            print(f'Unknown module: {moduleName}. All known modules are: {", ".join(self.modules)}.')
745            return
746        self.wrappers.append(
747            (moduleType(
748                self.modules[moduleName],
749                self.typeInfo, **kwargs),
750             moduleName)
751            )
752
753    def forEachModule(self, func):
754        for moduleName in self.moduleList:
755            func(self.modules[moduleName])
756
757    def forEachWrapper(self, func, supportedModules):
758        for wrapper in self.wrappers:
759            if supportedModules is None:
760                func(wrapper[0])
761            elif wrapper[1] in supportedModules:
762                func(wrapper[0])
763
764## Overrides####################################################################
765
766    def beginFile(self, genOpts):
767        OutputGenerator.beginFile(self, genOpts)
768
769        self.forEachModule(lambda m: m.begin(self.genOpts.directory))
770        self.forEachWrapper(lambda w: w.onBegin(), None)
771
772    def endFile(self):
773        OutputGenerator.endFile(self)
774
775        self.typeInfo.onEnd()
776
777        self.forEachWrapper(lambda w: w.onEnd(), None)
778        self.forEachModule(lambda m: m.end())
779
780    def beginFeature(self, interface, emit):
781        # Start processing in superclass
782        OutputGenerator.beginFeature(self, interface, emit)
783
784        for supportedFeature in SUPPORTED_FEATURES:
785            if self.featureName == supportedFeature:
786                self.featureSupported = True
787
788        if self.featureSupported == False and UNSUPPORTED_FEATURE_MODULES:
789            self.featureSupported = True
790            self.supportedModules = UNSUPPORTED_FEATURE_MODULES
791        elif self.featureSupported == False:
792            return
793        else:
794            self.supportedModules = SUPPORTED_MODULES.get(self.featureName)
795
796        self.typeInfo.onBeginFeature(self.featureName, self.featureType)
797
798        self.forEachModule(
799            lambda m: m.appendHeader("#ifdef %s\n" % self.featureName)
800            if isinstance(m, cereal.Module) and not m.suppressFeatureGuards else None)
801        self.forEachModule(
802            lambda m: m.appendImpl("#ifdef %s\n" % self.featureName)
803            if isinstance(m, cereal.Module) and not m.suppressFeatureGuards else None)
804        self.forEachWrapper(lambda w: w.onBeginFeature(self.featureName, self.featureType), self.supportedModules)
805        # functable needs to understand the feature type (device vs instance) of each cmd
806        for features in interface.findall('require'):
807            for c in features.findall('command'):
808                self.forEachWrapper(lambda w: w.onFeatureNewCmd(c.get('name')), self.supportedModules)
809
810    def endFeature(self):
811        # Finish processing in superclass
812        OutputGenerator.endFeature(self)
813
814        if self.featureSupported == False:
815            return
816
817        self.featureSupported = False
818
819        self.typeInfo.onEndFeature()
820
821        self.forEachModule(lambda m: m.appendHeader("#endif\n") if isinstance(
822            m, cereal.Module) and not m.suppressFeatureGuards else None)
823        self.forEachModule(lambda m: m.appendImpl("#endif\n") if isinstance(
824            m, cereal.Module) and not m.suppressFeatureGuards else None)
825        self.forEachWrapper(lambda w: w.onEndFeature(), self.supportedModules)
826
827    def genType(self, typeinfo: TypeInfo, name, alias):
828        OutputGenerator.genType(self, typeinfo, name, alias)
829
830        # Maybe this check can be removed if we refactor other things inside
831        # the cereal subdirectory.
832        if self.featureSupported == False and name in REQUIRED_TYPES:
833            self.typeInfo.onGenType(typeinfo, name, alias)
834            return
835
836        if self.featureSupported == False:
837            return
838
839        self.typeInfo.onGenType(typeinfo, name, alias)
840        self.forEachWrapper(lambda w: w.onGenType(typeinfo, name, alias), self.supportedModules)
841
842    def genStruct(self, typeinfo, typeName, alias):
843        OutputGenerator.genStruct(self, typeinfo, typeName, alias)
844        if self.featureSupported == False:
845            return
846
847        self.typeInfo.onGenStruct(typeinfo, typeName, alias)
848        self.forEachWrapper(lambda w: w.onGenStruct(typeinfo, typeName, alias), self.supportedModules)
849
850    def genGroup(self, groupinfo: GroupInfo, groupName, alias = None):
851        OutputGenerator.genGroup(self, groupinfo, groupName, alias)
852        if self.featureSupported == False:
853            return
854
855        self.typeInfo.onGenGroup(groupinfo, groupName, alias)
856        self.forEachWrapper(lambda w: w.onGenGroup(groupinfo, groupName, alias), self.supportedModules)
857
858    def genEnum(self, enuminfo: EnumInfo, name, alias):
859        OutputGenerator.genEnum(self, enuminfo, name, alias)
860        if self.featureSupported == False:
861            return
862        self.typeInfo.onGenEnum(enuminfo, name, alias)
863        self.forEachWrapper(lambda w: w.onGenEnum(enuminfo, name, alias), self.supportedModules)
864
865    def genCmd(self, cmdinfo, name, alias):
866        OutputGenerator.genCmd(self, cmdinfo, name, alias)
867        if self.featureSupported == False:
868            return
869
870        self.typeInfo.onGenCmd(cmdinfo, name, alias)
871        self.forEachWrapper(lambda w: w.onGenCmd(cmdinfo, name, alias), self.supportedModules)
872