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