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