• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from .common.codegen import CodeGen, VulkanWrapperGenerator
2from .common.vulkantypes import \
3        VulkanAPI, makeVulkanTypeSimple, iterateVulkanType
4from .common.vulkantypes import EXCLUDED_APIS
5from .common.vulkantypes import HANDLE_TYPES
6
7import copy
8import re
9
10RESOURCE_TRACKER_ENTRIES = [
11    "vkEnumerateInstanceExtensionProperties",
12    "vkEnumerateDeviceExtensionProperties",
13    "vkEnumeratePhysicalDevices",
14    "vkAllocateMemory",
15    "vkFreeMemory",
16    "vkCreateImage",
17    "vkDestroyImage",
18    "vkGetImageMemoryRequirements",
19    "vkGetImageMemoryRequirements2",
20    "vkGetImageMemoryRequirements2KHR",
21    "vkBindImageMemory",
22    "vkBindImageMemory2",
23    "vkBindImageMemory2KHR",
24    "vkCreateBuffer",
25    "vkDestroyBuffer",
26    "vkGetBufferMemoryRequirements",
27    "vkGetBufferMemoryRequirements2",
28    "vkGetBufferMemoryRequirements2KHR",
29    "vkBindBufferMemory",
30    "vkBindBufferMemory2",
31    "vkBindBufferMemory2KHR",
32    "vkCreateSemaphore",
33    "vkDestroySemaphore",
34    "vkQueueSubmit",
35    "vkQueueSubmit2",
36    "vkQueueWaitIdle",
37    "vkImportSemaphoreFdKHR",
38    "vkGetSemaphoreFdKHR",
39    # Warning: These need to be defined in vk.xml (currently no-op) {
40    "vkGetMemoryFuchsiaHandleKHR",
41    "vkGetMemoryFuchsiaHandlePropertiesKHR",
42    "vkGetSemaphoreFuchsiaHandleKHR",
43    "vkImportSemaphoreFuchsiaHandleKHR",
44    # } end Warning: These need to be defined in vk.xml (currently no-op)
45    "vkGetAndroidHardwareBufferPropertiesANDROID",
46    "vkGetMemoryAndroidHardwareBufferANDROID",
47    "vkCreateSamplerYcbcrConversion",
48    "vkDestroySamplerYcbcrConversion",
49    "vkCreateSamplerYcbcrConversionKHR",
50    "vkDestroySamplerYcbcrConversionKHR",
51    "vkUpdateDescriptorSetWithTemplate",
52    "vkGetPhysicalDeviceImageFormatProperties2",
53    "vkGetPhysicalDeviceImageFormatProperties2KHR",
54    "vkBeginCommandBuffer",
55    "vkEndCommandBuffer",
56    "vkResetCommandBuffer",
57    "vkCreateImageView",
58    "vkCreateSampler",
59    "vkGetPhysicalDeviceExternalFenceProperties",
60    "vkGetPhysicalDeviceExternalFencePropertiesKHR",
61    "vkGetPhysicalDeviceExternalBufferProperties",
62    "vkGetPhysicalDeviceExternalBufferPropertiesKHR",
63    "vkCreateFence",
64    "vkResetFences",
65    "vkImportFenceFdKHR",
66    "vkGetFenceFdKHR",
67    "vkWaitForFences",
68    "vkCreateDescriptorPool",
69    "vkDestroyDescriptorPool",
70    "vkResetDescriptorPool",
71    "vkAllocateDescriptorSets",
72    "vkFreeDescriptorSets",
73    "vkCreateDescriptorSetLayout",
74    "vkCmdExecuteCommands",
75    "vkCmdBindDescriptorSets",
76    "vkDestroyDescriptorSetLayout",
77    "vkAllocateCommandBuffers",
78    "vkQueueSignalReleaseImageANDROID",
79    "vkCmdPipelineBarrier",
80    "vkCreateGraphicsPipelines",
81    # Fuchsia
82    "vkGetMemoryZirconHandleFUCHSIA",
83    "vkGetMemoryZirconHandlePropertiesFUCHSIA",
84    "vkGetSemaphoreZirconHandleFUCHSIA",
85    "vkImportSemaphoreZirconHandleFUCHSIA",
86    "vkCreateBufferCollectionFUCHSIA",
87    "vkDestroyBufferCollectionFUCHSIA",
88    "vkSetBufferCollectionImageConstraintsFUCHSIA",
89    "vkSetBufferCollectionBufferConstraintsFUCHSIA",
90    "vkGetBufferCollectionPropertiesFUCHSIA",
91]
92
93SUCCESS_VAL = {
94    "VkResult" : ["VK_SUCCESS"],
95}
96
97HANDWRITTEN_ENTRY_POINTS = [
98    # Instance/device/physical-device special-handling, dispatch tables, etc..
99    "vkCreateInstance",
100    "vkDestroyInstance",
101    "vkGetInstanceProcAddr",
102    "vkEnumerateInstanceVersion",
103    "vkEnumerateInstanceLayerProperties",
104    "vkEnumerateInstanceExtensionProperties",
105    "vkEnumerateDeviceExtensionProperties",
106    "vkGetDeviceProcAddr",
107    "vkEnumeratePhysicalDevices",
108    "vkEnumeratePhysicalDeviceGroups",
109    "vkCreateDevice",
110    "vkDestroyDevice",
111    "vkCreateComputePipelines",
112    # Manual alloc/free + vk_*_init/free() call w/ special params
113    "vkGetDeviceQueue",
114    "vkGetDeviceQueue2",
115    # Command pool/buffer handling
116    "vkCreateCommandPool",
117    "vkDestroyCommandPool",
118    "vkAllocateCommandBuffers",
119    "vkResetCommandPool",
120    "vkFreeCommandBuffers",
121    "vkResetCommandPool",
122    # Special cases to handle struct translations in the pNext chain
123    # TODO: Make a codegen module (use deepcopy as reference) to make this more robust
124    "vkCmdBeginRenderPass2KHR",
125    "vkCmdBeginRenderPass",
126    "vkAllocateMemory",
127    "vkUpdateDescriptorSets",
128    "vkQueueCommitDescriptorSetUpdatesGOOGLE",
129]
130
131# TODO: handles with no equivalent gfxstream objects (yet).
132#  Might need some special handling.
133HANDLES_DONT_TRANSLATE = {
134    "VkSurfaceKHR",
135    ## The following objects have no need for mesa counterparts
136    # Allows removal of handwritten create/destroy (for array).
137    "VkDescriptorSet",
138    # Bug in translation
139    "VkSampler",
140    "VkSamplerYcbcrConversion",
141}
142
143# Handles whose gfxstream object have non-base-object vk_ structs
144# Optionally includes array of pairs of extraParams: {index, extraParam}
145# -1 means drop parameter of paramName specified by extraParam
146HANDLES_MESA_VK = {
147    # Handwritten handlers (added here for completeness)
148    "VkInstance" : None,
149    "VkPhysicalDevice" : None,
150    "VkDevice" : None,
151    "VkQueue" : None,
152    "VkCommandPool" : None,
153    "VkCommandBuffer" : None,
154    # Auto-generated creation/destroy
155    "VkDeviceMemory" : None,
156    "VkQueryPool" : None,
157    "VkBuffer" : [[-1, "pMemoryRequirements"]],
158    "VkBufferView" : None,
159    "VkImage" : [[-1, "pMemoryRequirements"]],
160    "VkImageView": [[1, "false /* driver_internal */"]],
161    "VkSampler" : None,
162}
163
164# Types that have a corresponding method for transforming
165# an input list to its internal counterpart
166TYPES_TRANSFORM_LIST_METHOD = {
167    "VkSemaphore",
168    "VkSemaphoreSubmitInfo",
169}
170
171def is_cmdbuf_dispatch(api):
172    return "VkCommandBuffer" == api.parameters[0].typeName
173
174def is_queue_dispatch(api):
175    return "VkQueue" == api.parameters[0].typeName
176
177def getCreateParam(api):
178    for param in api.parameters:
179        if param.isCreatedBy(api):
180            return param
181    return None
182
183def getDestroyParam(api):
184    for param in api.parameters:
185        if param.isDestroyedBy(api):
186            return param
187    return None
188
189# i.e. VkQueryPool --> vk_query_pool
190def typeNameToMesaType(typeName):
191    vkTypeNameRegex = "(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])"
192    words = re.split(vkTypeNameRegex, typeName)
193    outputType = "vk"
194    for word in words[1:]:
195        outputType += "_"
196        outputType += word.lower()
197    return outputType
198
199def typeNameToBaseName(typeName):
200    return typeNameToMesaType(typeName)[len("vk_"):]
201
202def paramNameToObjectName(paramName):
203    return "gfxstream_%s" % paramName
204
205def typeNameToVkObjectType(typeName):
206    return "VK_OBJECT_TYPE_%s" % typeNameToBaseName(typeName).upper()
207
208def typeNameToObjectType(typeName):
209    return "gfxstream_vk_%s" % typeNameToBaseName(typeName)
210
211def transformListFuncName(typeName):
212    return "transform%sList" % (typeName)
213
214def hasMesaVkObject(typeName):
215    return typeName in HANDLES_MESA_VK
216
217def isAllocatorParam(param):
218    ALLOCATOR_TYPE_NAME = "VkAllocationCallbacks"
219    return (param.pointerIndirectionLevels == 1
220            and param.isConst
221            and param.typeName == ALLOCATOR_TYPE_NAME)
222
223def isArrayParam(param):
224    return (1 == param.pointerIndirectionLevels
225            and param.isConst
226            and "len" in param.attribs)
227
228INTERNAL_OBJECT_NAME = "internal_object"
229
230class VulkanFuncTable(VulkanWrapperGenerator):
231    def __init__(self, module, typeInfo):
232        VulkanWrapperGenerator.__init__(self, module, typeInfo)
233        self.typeInfo = typeInfo
234        self.cgen = CodeGen()
235        self.entries = []
236        self.entryFeatures = []
237        self.cmdToFeatureType = {}
238        self.feature = None
239        self.featureType = None
240
241    def onBegin(self,):
242        cgen = self.cgen
243        self.module.appendImpl(cgen.swapCode())
244        pass
245
246    def onBeginFeature(self, featureName, featureType):
247        self.feature = featureName
248        self.featureType = featureType
249
250    def onEndFeature(self):
251        self.feature = None
252        self.featureType = None
253
254    def onFeatureNewCmd(self, name):
255        self.cmdToFeatureType[name] = self.featureType
256
257    def onGenCmd(self, cmdinfo, name, alias):
258        typeInfo = self.typeInfo
259        cgen = self.cgen
260        api = typeInfo.apis[name]
261        self.entries.append(api)
262        self.entryFeatures.append(self.feature)
263        self.loopVars = ["i", "j", "k", "l", "m", "n"]
264        self.loopVarIndex = 0
265
266        def getNextLoopVar():
267            if self.loopVarIndex >= len(self.loopVars):
268                raise
269            loopVar = self.loopVars[self.loopVarIndex]
270            self.loopVarIndex += 1
271            return loopVar
272
273        def isCompoundType(typeName):
274            return typeInfo.isCompoundType(typeName)
275
276        def handleTranslationRequired(typeName):
277            return typeName in HANDLE_TYPES and typeName not in HANDLES_DONT_TRANSLATE
278
279        def translationRequired(typeName):
280            if isCompoundType(typeName):
281                struct = typeInfo.structs[typeName]
282                for member in struct.members:
283                    if translationRequired(member.typeName):
284                        return True
285                return False
286            else:
287                return handleTranslationRequired(typeName)
288
289        def genDestroyGfxstreamObjects():
290            destroyParam = getDestroyParam(api)
291            if not destroyParam:
292                return
293            if not translationRequired(destroyParam.typeName):
294                return
295            objectName = paramNameToObjectName(destroyParam.paramName)
296            allocatorParam = "NULL"
297            for p in api.parameters:
298                if isAllocatorParam(p):
299                    allocatorParam = p.paramName
300            if not hasMesaVkObject(destroyParam.typeName):
301                deviceParam = api.parameters[0]
302                if "VkDevice" != deviceParam.typeName:
303                    print("ERROR: Unhandled non-VkDevice parameters[0]: %s (for API: %s)" %(deviceParam.typeName, api.name))
304                    raise
305                # call vk_object_free() directly
306                mesaObjectDestroy = "(void *)%s" % objectName
307                cgen.funcCall(
308                    None,
309                    "vk_object_free",
310                    ["&%s->vk" % paramNameToObjectName(deviceParam.paramName), allocatorParam, mesaObjectDestroy]
311                )
312            else:
313                baseName = typeNameToBaseName(destroyParam.typeName)
314                # objectName for destroy always at the back
315                mesaObjectPrimary = "&%s->vk" % paramNameToObjectName(api.parameters[0].paramName)
316                mesaObjectDestroy = "&%s->vk" % objectName
317                cgen.funcCall(
318                    None,
319                    "vk_%s_destroy" % (baseName),
320                    [mesaObjectPrimary, allocatorParam, mesaObjectDestroy]
321                )
322
323        def genMesaObjectAlloc(allocCallLhs):
324            deviceParam = api.parameters[0]
325            if "VkDevice" != deviceParam.typeName:
326                print("ERROR: Unhandled non-VkDevice parameters[0]: %s (for API: %s)" %(deviceParam.typeName, api.name))
327                raise
328            allocatorParam = "NULL"
329            for p in api.parameters:
330                if isAllocatorParam(p):
331                    allocatorParam = p.paramName
332            createParam = getCreateParam(api)
333            objectType = typeNameToObjectType(createParam.typeName)
334            # Call vk_object_zalloc directly
335            cgen.funcCall(
336                allocCallLhs,
337                "(%s *)vk_object_zalloc" % objectType,
338                ["&%s->vk" % paramNameToObjectName(deviceParam.paramName), allocatorParam, ("sizeof(%s)" % objectType), typeNameToVkObjectType(createParam.typeName)]
339            )
340
341        def genMesaObjectCreate(createCallLhs):
342            def dropParam(params, drop):
343                for p in params:
344                    if p == drop:
345                        params.remove(p)
346                return params
347            createParam = getCreateParam(api)
348            objectType = "struct %s" % typeNameToObjectType(createParam.typeName)
349            modParams = copy.deepcopy(api.parameters)
350            # Mod params for the vk_%s_create() call i.e. vk_buffer_create()
351            for p in modParams:
352                if p.paramName == createParam.paramName:
353                    modParams.remove(p)
354                elif handleTranslationRequired(p.typeName):
355                    # Cast handle to the mesa type
356                    p.paramName = ("(%s*)%s" % (typeNameToMesaType(p.typeName), paramNameToObjectName(p.paramName)))
357            mesaCreateParams = [p.paramName for p in modParams] + ["sizeof(%s)" % objectType]
358            # Some special handling
359            extraParams = HANDLES_MESA_VK[createParam.typeName]
360            if extraParams:
361                for pair in extraParams:
362                    if -1 == pair[0]:
363                        mesaCreateParams = dropParam(mesaCreateParams, pair[1])
364                    else:
365                        mesaCreateParams.insert(pair[0], pair[1])
366            cgen.funcCall(
367                createCallLhs,
368                "(%s *)vk_%s_create" % (objectType, typeNameToBaseName(createParam.typeName)),
369                mesaCreateParams
370            )
371
372        # Alloc/create gfxstream_vk_* object
373        def genCreateGfxstreamObjects():
374            createParam = getCreateParam(api)
375            if not createParam:
376                return False
377            if not handleTranslationRequired(createParam.typeName):
378                return False
379            objectType = "struct %s" % typeNameToObjectType(createParam.typeName)
380            callLhs = "%s *%s" % (objectType, paramNameToObjectName(createParam.paramName))
381            if hasMesaVkObject(createParam.typeName):
382                genMesaObjectCreate(callLhs)
383            else:
384                genMesaObjectAlloc(callLhs)
385
386            retVar = api.getRetVarExpr()
387            if retVar:
388                retTypeName = api.getRetTypeExpr()
389                # ex: vkCreateBuffer_VkResult_return = gfxstream_buffer ? VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY;
390                cgen.stmt("%s = %s ? %s : %s" %
391                          (retVar, paramNameToObjectName(createParam.paramName), SUCCESS_VAL[retTypeName][0], "VK_ERROR_OUT_OF_HOST_MEMORY"))
392            return True
393
394        def genVkFromHandle(param, fromName):
395            objectName = paramNameToObjectName(param.paramName)
396            cgen.stmt("VK_FROM_HANDLE(%s, %s, %s)" %
397                      (typeNameToObjectType(param.typeName), objectName, fromName))
398            return objectName
399
400        def genGetGfxstreamHandles():
401            createParam = getCreateParam(api)
402            for param in api.parameters:
403                if not handleTranslationRequired(param.typeName):
404                    continue
405                elif isArrayParam(param):
406                    continue
407                elif param != createParam:
408                    if param.pointerIndirectionLevels > 0:
409                        print("ERROR: Unhandled pointerIndirectionLevels > 1 for API %s (param %s)" % (api.name, param.paramName))
410                        raise
411                    genVkFromHandle(param, param.paramName)
412
413        def internalNestedParamName(param):
414            parentName = ""
415            if param.parent:
416                parentName = "_%s" % param.parent.typeName
417            return "internal%s_%s" % (parentName, param.paramName)
418
419        def genInternalArrayDeclarations(param, countParamName, nestLevel=0):
420            internalArray = None
421            if 0 == nestLevel:
422                internalArray = "internal_%s" % param.paramName
423                cgen.stmt("std::vector<%s> %s(%s)" % (param.typeName, internalArray, countParamName))
424            elif 1 == nestLevel or 2 == nestLevel:
425                internalArray = internalNestedParamName(param)
426                if isArrayParam(param):
427                    cgen.stmt("std::vector<std::vector<%s>> %s" % (param.typeName, internalArray))
428                else:
429                    cgen.stmt("std::vector<%s> %s" % (param.typeName, internalArray))
430            else:
431                print("ERROR: nestLevel > 2 not verified.")
432                raise
433            if isCompoundType(param.typeName):
434                for member in typeInfo.structs[param.typeName].members:
435                    if translationRequired(member.typeName):
436                        if handleTranslationRequired(member.typeName) and not isArrayParam(member):
437                            # No declarations for non-array handleType
438                            continue
439                        genInternalArrayDeclarations(member, countParamName, nestLevel + 1)
440            return internalArray
441
442        def genInternalCompoundType(param, outName, inName, currLoopVar):
443            nextLoopVar = None
444            cgen.stmt("%s = %s" % (outName, inName))
445            for member in typeInfo.structs[param.typeName].members:
446                if not translationRequired(member.typeName):
447                    continue
448                cgen.line("/* %s::%s */" % (param.typeName, member.paramName))
449                nestedOutName = ("%s[%s]" % (internalNestedParamName(member), currLoopVar))
450                if isArrayParam(member):
451                    countParamName = "%s.%s" % (outName, member.attribs["len"])
452                    inArrayName = "%s.%s" % (outName, member.paramName)
453                    cgen.stmt("%s.push_back(std::vector<%s>())" % (internalNestedParamName(member), member.typeName))
454                    if member.typeName in TYPES_TRANSFORM_LIST_METHOD:
455                        # Use the corresponding transformList call
456                        cgen.funcCall(nestedOutName, transformListFuncName(member.typeName), [inArrayName, countParamName])
457                        cgen.stmt("%s = %s.data()" % (inArrayName, nestedOutName))
458                        cgen.stmt("%s = %s.size()" % (countParamName, nestedOutName))
459                    else:
460                        # Standard translation
461                        cgen.stmt("%s.reserve(%s)" % (nestedOutName, countParamName))
462                        cgen.stmt("memset(&%s[0], 0, sizeof(%s) * %s)" % (nestedOutName, member.typeName, countParamName))
463                        if not nextLoopVar:
464                            nextLoopVar = getNextLoopVar()
465                        internalArray = genInternalArray(member, countParamName, nestedOutName, inArrayName, nextLoopVar)
466                        cgen.stmt("%s = %s" %(inArrayName, internalArray))
467                elif isCompoundType(member.typeName):
468                    memberFullName = "%s.%s" % (outName, member.paramName)
469                    if 1 == member.pointerIndirectionLevels:
470                        cgen.beginIf(memberFullName)
471                        inParamName = "%s[0]" % memberFullName
472                        genInternalCompoundType(member, nestedOutName, inParamName, currLoopVar)
473                        cgen.stmt("%s.%s = &%s" % (outName, member.paramName,  nestedOutName))
474                    else:
475                        cgen.beginBlock()
476                        genInternalCompoundType(member, nestedOutName, memberFullName, currLoopVar)
477                        cgen.stmt("%s.%s = %s" % (outName, member.paramName,  nestedOutName))
478                    cgen.endBlock()
479                else:
480                    # Replace member with internal object
481                    replaceName = "%s.%s" % (outName, member.paramName)
482                    if member.isOptional:
483                        cgen.beginIf(replaceName)
484                    gfxstreamObject = genVkFromHandle(member, replaceName)
485                    cgen.stmt("%s = %s->%s" % (replaceName, gfxstreamObject, INTERNAL_OBJECT_NAME))
486                    if member.isOptional:
487                        cgen.endIf()
488
489        def genInternalArray(param, countParamName, outArrayName, inArrayName, loopVar):
490            cgen.beginFor("uint32_t %s = 0" % loopVar, "%s < %s" % (loopVar, countParamName), "++%s" % loopVar)
491            if param.isOptional:
492                cgen.beginIf(inArrayName)
493            if isCompoundType(param.typeName):
494                genInternalCompoundType(param, ("%s[%s]" % (outArrayName, loopVar)), "%s[%s]" % (inArrayName, loopVar), loopVar)
495            else:
496                gfxstreamObject = genVkFromHandle(param, "%s[%s]" % (inArrayName, loopVar))
497                cgen.stmt("%s[%s] = %s->%s" % (outArrayName, loopVar, gfxstreamObject, INTERNAL_OBJECT_NAME))
498            if param.isOptional:
499                cgen.endIf()
500            cgen.endFor()
501            return "%s.data()" % outArrayName
502
503        # Translate params into params needed for gfxstream-internal
504        #  encoder/resource-tracker calls
505        def getEncoderOrResourceTrackerParams():
506            createParam = getCreateParam(api)
507            outParams = copy.deepcopy(api.parameters)
508            nextLoopVar = getNextLoopVar()
509            for param in outParams:
510                if not translationRequired(param.typeName):
511                    continue
512                elif isArrayParam(param) or isCompoundType(param.typeName):
513                    if param.possiblyOutput():
514                        print("ERROR: Unhandled CompoundType / Array output for API %s (param %s)" % (api.name, param.paramName))
515                        raise
516                    if 1 != param.pointerIndirectionLevels or not param.isConst:
517                        print("ERROR: Compound type / array input is not 'const <type>*' (API: %s, paramName: %s)" % (api.name, param.paramName))
518                        raise
519                    countParamName = "1"
520                    if "len" in param.attribs:
521                        countParamName = param.attribs["len"]
522                    internalArrayName = genInternalArrayDeclarations(param, countParamName)
523                    param.paramName = genInternalArray(param, countParamName, internalArrayName, param.paramName, nextLoopVar)
524                elif 0 == param.pointerIndirectionLevels:
525                    if param.isOptional:
526                        param.paramName = ("%s ? %s->%s : VK_NULL_HANDLE" % (paramNameToObjectName(param.paramName), paramNameToObjectName(param.paramName), INTERNAL_OBJECT_NAME))
527                    else:
528                        param.paramName = ("%s->%s" % (paramNameToObjectName(param.paramName), INTERNAL_OBJECT_NAME))
529                elif createParam and param.paramName == createParam.paramName:
530                    param.paramName = ("&%s->%s" % (paramNameToObjectName(param.paramName), INTERNAL_OBJECT_NAME))
531                else:
532                    print("ERROR: Unknown handling for param: %s (API: %s)" % (param, api.name))
533                    raise
534            return outParams
535
536        def genEncoderOrResourceTrackerCall(declareResources=True):
537            if is_cmdbuf_dispatch(api):
538                cgen.stmt("auto vkEnc = gfxstream::vk::ResourceTracker::getCommandBufferEncoder(%s->%s)" % (paramNameToObjectName(api.parameters[0].paramName), INTERNAL_OBJECT_NAME))
539            elif is_queue_dispatch(api):
540                cgen.stmt("auto vkEnc = gfxstream::vk::ResourceTracker::getQueueEncoder(%s->%s)" % (paramNameToObjectName(api.parameters[0].paramName), INTERNAL_OBJECT_NAME))
541            else:
542                cgen.stmt("auto vkEnc = gfxstream::vk::ResourceTracker::getThreadLocalEncoder()")
543            callLhs = None
544            retTypeName = api.getRetTypeExpr()
545            if retTypeName != "void":
546                callLhs = api.getRetVarExpr()
547
548            # Get parameter list modded for gfxstream-internal call
549            parameters = getEncoderOrResourceTrackerParams()
550            if name in RESOURCE_TRACKER_ENTRIES:
551                if declareResources:
552                    cgen.stmt("auto resources = gfxstream::vk::ResourceTracker::get()")
553                cgen.funcCall(
554                    callLhs, "resources->" + "on_" + api.name,
555                    ["vkEnc"] + SUCCESS_VAL.get(retTypeName, []) + \
556                    [p.paramName for p in parameters])
557            else:
558                cgen.funcCall(
559                    callLhs, "vkEnc->" + api.name, [p.paramName for p in parameters] + ["true /* do lock */"])
560
561        def genReturnExpression():
562            retTypeName = api.getRetTypeExpr()
563            # Set the createParam output, if applicable
564            createParam = getCreateParam(api)
565            if createParam and handleTranslationRequired(createParam.typeName):
566                if 1 != createParam.pointerIndirectionLevels:
567                    print("ERROR: Unhandled pointerIndirectionLevels != 1 in return for API %s (createParam %s)" % api.name, createParam.paramName)
568                    raise
569                # ex: *pBuffer = gfxstream_vk_buffer_to_handle(gfxstream_buffer)
570                cgen.funcCall(
571                    "*%s" % createParam.paramName,
572                    "%s_to_handle" % typeNameToObjectType(createParam.typeName),
573                    [paramNameToObjectName(createParam.paramName)]
574                )
575
576            if retTypeName != "void":
577                cgen.stmt("return %s" % api.getRetVarExpr())
578
579        def genGfxstreamEntry(declareResources=True):
580            cgen.stmt("AEMU_SCOPED_TRACE(\"%s\")" % api.name)
581            # declare returnVar
582            retTypeName = api.getRetTypeExpr()
583            retVar = api.getRetVarExpr()
584            if retVar:
585                cgen.stmt("%s %s = (%s)0" % (retTypeName, retVar, retTypeName))
586            # Check non-null destroy param for free/destroy calls
587            destroyParam = getDestroyParam(api)
588            if destroyParam:
589                cgen.beginIf("VK_NULL_HANDLE == %s" % destroyParam.paramName)
590                if api.getRetTypeExpr() != "void":
591                    cgen.stmt("return %s" % api.getRetVarExpr())
592                else:
593                    cgen.stmt("return")
594                cgen.endIf()
595            # Translate handles
596            genGetGfxstreamHandles()
597            # Translation/creation of objects
598            createdObject = genCreateGfxstreamObjects()
599            # Make encoder/resource-tracker call
600            if retVar and createdObject:
601                cgen.beginIf("%s == %s" % (SUCCESS_VAL[retTypeName][0], retVar))
602            else:
603                cgen.beginBlock()
604            genEncoderOrResourceTrackerCall()
605            cgen.endBlock()
606            # Destroy gfxstream objects
607            genDestroyGfxstreamObjects()
608            # Set output / return variables
609            genReturnExpression()
610
611        api_entry = api.withModifiedName("gfxstream_vk_" + api.name[2:])
612        if api.name not in HANDWRITTEN_ENTRY_POINTS:
613            cgen.line(self.cgen.makeFuncProto(api_entry))
614            cgen.beginBlock()
615            genGfxstreamEntry()
616            cgen.endBlock()
617            self.module.appendImpl(cgen.swapCode())
618
619
620    def onEnd(self,):
621        pass
622
623    def isDeviceDispatch(self, api):
624        # TODO(230793667): improve the heuristic and just use "cmdToFeatureType"
625        return (len(api.parameters) > 0 and
626            "VkDevice" == api.parameters[0].typeName) or (
627            "VkCommandBuffer" == api.parameters[0].typeName and
628            self.cmdToFeatureType.get(api.name, "") == "device")
629