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