• 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
5
6RESOURCE_TRACKER_ENTRIES = [
7    "vkEnumerateInstanceExtensionProperties",
8    "vkEnumerateDeviceExtensionProperties",
9    "vkEnumeratePhysicalDevices",
10    "vkAllocateMemory",
11    "vkFreeMemory",
12    "vkCreateImage",
13    "vkDestroyImage",
14    "vkGetImageMemoryRequirements",
15    "vkGetImageMemoryRequirements2",
16    "vkGetImageMemoryRequirements2KHR",
17    "vkBindImageMemory",
18    "vkBindImageMemory2",
19    "vkBindImageMemory2KHR",
20    "vkCreateBuffer",
21    "vkDestroyBuffer",
22    "vkGetBufferMemoryRequirements",
23    "vkGetBufferMemoryRequirements2",
24    "vkGetBufferMemoryRequirements2KHR",
25    "vkBindBufferMemory",
26    "vkBindBufferMemory2",
27    "vkBindBufferMemory2KHR",
28    "vkCreateSemaphore",
29    "vkDestroySemaphore",
30    "vkQueueSubmit",
31    "vkQueueWaitIdle",
32    "vkImportSemaphoreFdKHR",
33    "vkGetSemaphoreFdKHR",
34    # Warning: These need to be defined in vk.xml (currently no-op) {
35    "vkGetMemoryFuchsiaHandleKHR",
36    "vkGetMemoryFuchsiaHandlePropertiesKHR",
37    "vkGetSemaphoreFuchsiaHandleKHR",
38    "vkImportSemaphoreFuchsiaHandleKHR",
39    # } end Warning: These need to be defined in vk.xml (currently no-op)
40    "vkGetAndroidHardwareBufferPropertiesANDROID",
41    "vkGetMemoryAndroidHardwareBufferANDROID",
42    "vkCreateSamplerYcbcrConversion",
43    "vkDestroySamplerYcbcrConversion",
44    "vkCreateSamplerYcbcrConversionKHR",
45    "vkDestroySamplerYcbcrConversionKHR",
46    "vkUpdateDescriptorSetWithTemplate",
47    "vkGetPhysicalDeviceImageFormatProperties2",
48    "vkGetPhysicalDeviceImageFormatProperties2KHR",
49    "vkBeginCommandBuffer",
50    "vkEndCommandBuffer",
51    "vkResetCommandBuffer",
52    "vkCreateImageView",
53    "vkCreateSampler",
54    "vkGetPhysicalDeviceExternalFenceProperties",
55    "vkGetPhysicalDeviceExternalFencePropertiesKHR",
56    "vkCreateFence",
57    "vkResetFences",
58    "vkImportFenceFdKHR",
59    "vkGetFenceFdKHR",
60    "vkWaitForFences",
61    "vkCreateDescriptorPool",
62    "vkDestroyDescriptorPool",
63    "vkResetDescriptorPool",
64    "vkAllocateDescriptorSets",
65    "vkFreeDescriptorSets",
66    "vkCreateDescriptorSetLayout",
67    "vkUpdateDescriptorSets",
68    "vkCmdExecuteCommands",
69    "vkCmdBindDescriptorSets",
70    "vkDestroyDescriptorSetLayout",
71    "vkAllocateCommandBuffers",
72    "vkQueueSignalReleaseImageANDROID",
73    "vkCmdPipelineBarrier",
74    "vkCreateGraphicsPipelines",
75]
76
77SUCCESS_VAL = {
78    "VkResult" : ["VK_SUCCESS"],
79}
80
81POSTPROCESSES = {
82    "vkResetCommandPool" : """if (vkResetCommandPool_VkResult_return == VK_SUCCESS) {
83        ResourceTracker::get()->resetCommandPoolStagingInfo(commandPool);
84    }""",
85    "vkAllocateCommandBuffers" : """if (vkAllocateCommandBuffers_VkResult_return == VK_SUCCESS) {
86        ResourceTracker::get()->addToCommandPool(pAllocateInfo->commandPool, pAllocateInfo->commandBufferCount, pCommandBuffers);
87    }""",
88}
89
90def is_cmdbuf_dispatch(api):
91    return "VkCommandBuffer" == api.parameters[0].typeName
92
93def is_queue_dispatch(api):
94    return "VkQueue" == api.parameters[0].typeName
95
96class VulkanFuncTable(VulkanWrapperGenerator):
97    def __init__(self, module, typeInfo):
98        VulkanWrapperGenerator.__init__(self, module, typeInfo)
99        self.typeInfo = typeInfo
100        self.cgen = CodeGen()
101        self.entries = []
102        self.entryFeatures = []
103        self.cmdToFeatureType = {}
104        self.feature = None
105        self.featureType = None
106
107    def onBegin(self,):
108        cgen = self.cgen
109        cgen.line("static void sOnInvalidDynamicallyCheckedCall(const char* apiname, const char* neededFeature)")
110        cgen.beginBlock()
111        cgen.stmt("ALOGE(\"invalid call to %s: %s not supported\", apiname, neededFeature)")
112        cgen.stmt("abort()")
113        cgen.endBlock()
114        self.module.appendImpl(cgen.swapCode())
115        pass
116
117    def onBeginFeature(self, featureName, featureType):
118        self.feature = featureName
119        self.featureType = featureType
120
121    def onEndFeature(self):
122        self.feature = None
123        self.featureType = None
124
125    def onFeatureNewCmd(self, name):
126        self.cmdToFeatureType[name] = self.featureType
127
128    def onGenCmd(self, cmdinfo, name, alias):
129        typeInfo = self.typeInfo
130        cgen = self.cgen
131        api = typeInfo.apis[name]
132        self.entries.append(api)
133        self.entryFeatures.append(self.feature)
134
135        def genEncoderOrResourceTrackerCall(cgen, api, declareResources=True):
136            cgen.stmt("AEMU_SCOPED_TRACE(\"%s\")" % api.name)
137
138            if is_cmdbuf_dispatch(api):
139                cgen.stmt("auto vkEnc = ResourceTracker::getCommandBufferEncoder(commandBuffer)")
140            elif is_queue_dispatch(api):
141                cgen.stmt("auto vkEnc = ResourceTracker::getQueueEncoder(queue)")
142            else:
143                cgen.stmt("auto vkEnc = ResourceTracker::getThreadLocalEncoder()")
144            callLhs = None
145            retTypeName = api.getRetTypeExpr()
146            if retTypeName != "void":
147                retVar = api.getRetVarExpr()
148                cgen.stmt("%s %s = (%s)0" % (retTypeName, retVar, retTypeName))
149                callLhs = retVar
150
151            if name in RESOURCE_TRACKER_ENTRIES:
152                if declareResources:
153                    cgen.stmt("auto resources = ResourceTracker::get()")
154                cgen.funcCall(
155                    callLhs, "resources->" + "on_" + api.name,
156                    ["vkEnc"] + SUCCESS_VAL.get(retTypeName, []) + \
157                    [p.paramName for p in api.parameters])
158            else:
159                cgen.funcCall(
160                    callLhs, "vkEnc->" + api.name, [p.paramName for p in api.parameters] + ["true /* do lock */"])
161
162            if name in POSTPROCESSES:
163                cgen.line(POSTPROCESSES[name])
164
165            if retTypeName != "void":
166                cgen.stmt("return %s" % retVar)
167
168
169        api_entry = api.withModifiedName("entry_" + api.name)
170
171        cgen.line("static " + self.cgen.makeFuncProto(api_entry))
172        cgen.beginBlock()
173        genEncoderOrResourceTrackerCall(cgen, api)
174        cgen.endBlock()
175
176        if self.isDeviceDispatch(api) and self.feature != "VK_VERSION_1_0":
177            api_entry_dyn_check = api.withModifiedName("dynCheck_entry_" + api.name)
178            cgen.line("static " + self.cgen.makeFuncProto(api_entry_dyn_check))
179            cgen.beginBlock()
180            if self.feature == "VK_VERSION_1_1":
181                cgen.stmt("auto resources = ResourceTracker::get()")
182                if "VkCommandBuffer" == api.parameters[0].typeName:
183                    cgen.stmt("VkDevice device = resources->getDevice(commandBuffer)")
184                cgen.beginIf("resources->getApiVersionFromDevice(device) < VK_API_VERSION_1_1")
185                cgen.stmt("sOnInvalidDynamicallyCheckedCall(\"%s\", \"%s\")" % (api.name, self.feature))
186                cgen.endIf()
187            elif self.feature != "VK_VERSION_1_0":
188                cgen.stmt("auto resources = ResourceTracker::get()")
189                if "VkCommandBuffer" == api.parameters[0].typeName:
190                    cgen.stmt("VkDevice device = resources->getDevice(commandBuffer);")
191                cgen.beginIf("!resources->hasDeviceExtension(device, \"%s\")" % self.feature)
192                cgen.stmt("sOnInvalidDynamicallyCheckedCall(\"%s\", \"%s\")" % (api.name, self.feature))
193                cgen.endIf()
194            else:
195                print("About to generate a frivolous api!: dynCheck entry: %s" % api.name)
196                raise
197            genEncoderOrResourceTrackerCall(cgen, api, declareResources = False)
198            cgen.endBlock()
199
200        self.module.appendImpl(cgen.swapCode())
201
202    def onEnd(self,):
203        getProcAddressDecl = "void* goldfish_vulkan_get_proc_address(const char* name)"
204        self.module.appendHeader(getProcAddressDecl + ";\n")
205        self.module.appendImpl(getProcAddressDecl)
206        self.cgen.beginBlock()
207
208        prevFeature = None
209        for e, f in zip(self.entries, self.entryFeatures):
210            featureEndif = prevFeature is not None and (f != prevFeature)
211            featureif = not featureEndif and (f != prevFeature)
212
213            if featureEndif:
214                self.cgen.leftline("#endif")
215                self.cgen.leftline("#ifdef %s" % f)
216
217            if featureif:
218                self.cgen.leftline("#ifdef %s" % f)
219
220            self.cgen.beginIf("!strcmp(name, \"%s\")" % e.name)
221            if e.name in EXCLUDED_APIS:
222                self.cgen.stmt("return nullptr")
223            elif f == "VK_VERSION_1_1":
224                self.cgen.stmt("return nullptr")
225            elif f != "VK_VERSION_1_0":
226                self.cgen.stmt("return nullptr")
227            else:
228                self.cgen.stmt("return (void*)%s" % ("entry_" + e.name))
229            self.cgen.endIf()
230            prevFeature = f
231
232        self.cgen.leftline("#endif")
233
234        self.cgen.stmt("return nullptr")
235        self.cgen.endBlock()
236        self.module.appendImpl(self.cgen.swapCode())
237
238        getInstanceProcAddressDecl = "void* goldfish_vulkan_get_instance_proc_address(VkInstance instance, const char* name)"
239        self.module.appendHeader(getInstanceProcAddressDecl + ";\n")
240        self.module.appendImpl(getInstanceProcAddressDecl)
241        self.cgen.beginBlock()
242
243        self.cgen.stmt(
244            "auto resources = ResourceTracker::get()")
245        self.cgen.stmt(
246            "bool has1_1OrHigher = resources->getApiVersionFromInstance(instance) >= VK_API_VERSION_1_1")
247        self.cgen.stmt(
248            "bool has1_2OrHigher = resources->getApiVersionFromInstance(instance) >= VK_API_VERSION_1_2")
249
250        prevFeature = None
251        for e, f in zip(self.entries, self.entryFeatures):
252            featureEndif = prevFeature is not None and (f != prevFeature)
253            featureif = not featureEndif and (f != prevFeature)
254
255            if featureEndif:
256                self.cgen.leftline("#endif")
257                self.cgen.leftline("#ifdef %s" % f)
258
259            if featureif:
260                self.cgen.leftline("#ifdef %s" % f)
261
262            self.cgen.beginIf("!strcmp(name, \"%s\")" % e.name)
263
264            entryPointExpr = "(void*)%s" % ("entry_" + e.name)
265
266            if e.name in EXCLUDED_APIS:
267                self.cgen.stmt("return nullptr")
268            elif f == "VK_VERSION_1_2":
269                if self.isDeviceDispatch(e):
270                    self.cgen.stmt("return (void*)dynCheck_entry_%s" % e.name)
271                else:
272                    self.cgen.stmt( \
273                        "return has1_2OrHigher ? %s : nullptr" % \
274                        entryPointExpr)
275            elif f == "VK_VERSION_1_1":
276                if self.isDeviceDispatch(e):
277                    self.cgen.stmt("return (void*)dynCheck_entry_%s" % e.name)
278                else:
279                    self.cgen.stmt( \
280                        "return has1_1OrHigher ? %s : nullptr" % \
281                        entryPointExpr)
282            elif f != "VK_VERSION_1_0":
283                entryNeedsInstanceExtensionCheck = self.cmdToFeatureType[e.name] == "instance"
284
285                entryPrefix = "dynCheck_" if self.isDeviceDispatch(e) else ""
286                entryPointExpr = "(void*)%sentry_%s" % (entryPrefix, e.name)
287
288                if entryNeedsInstanceExtensionCheck:
289                    self.cgen.stmt("bool hasExt = resources->hasInstanceExtension(instance, \"%s\")"  % f)
290                    self.cgen.stmt("return hasExt ? %s : nullptr" % entryPointExpr)
291                else:
292                    # TODO(b/236246382): We need to check the device extension support here.
293                    self.cgen.stmt("// TODO(b/236246382): Check support for device extension");
294                    self.cgen.stmt("return %s" % entryPointExpr)
295
296            else:
297                self.cgen.stmt("return %s" % entryPointExpr)
298            self.cgen.endIf()
299            prevFeature = f
300
301        self.cgen.leftline("#endif")
302
303        self.cgen.stmt("return nullptr")
304        self.cgen.endBlock()
305        self.module.appendImpl(self.cgen.swapCode())
306
307        getDeviceProcAddressDecl = "void* goldfish_vulkan_get_device_proc_address(VkDevice device, const char* name)"
308        self.module.appendHeader(getDeviceProcAddressDecl + ";\n")
309        self.module.appendImpl(getDeviceProcAddressDecl)
310        self.cgen.beginBlock()
311
312        self.cgen.stmt(
313            "auto resources = ResourceTracker::get()")
314        self.cgen.stmt(
315            "bool has1_1OrHigher = resources->getApiVersionFromDevice(device) >= VK_API_VERSION_1_1")
316
317        prevFeature = None
318        for e, f in zip(self.entries, self.entryFeatures):
319            featureEndif = prevFeature is not None and (f != prevFeature)
320            featureif = not featureEndif and (f != prevFeature)
321
322            if featureEndif:
323                self.cgen.leftline("#endif")
324                self.cgen.leftline("#ifdef %s" % f)
325
326            if featureif:
327                self.cgen.leftline("#ifdef %s" % f)
328
329            self.cgen.beginIf("!strcmp(name, \"%s\")" % e.name)
330
331            entryPointExpr = "(void*)%s" % ("entry_" + e.name)
332
333            if e.name in EXCLUDED_APIS:
334                self.cgen.stmt("return nullptr")
335            elif f == "VK_VERSION_1_1":
336                self.cgen.stmt( \
337                    "return has1_1OrHigher ? %s : nullptr" % \
338                    entryPointExpr)
339            elif f != "VK_VERSION_1_0":
340                self.cgen.stmt( \
341                    "bool hasExt = resources->hasDeviceExtension(device, \"%s\")"  % f)
342                self.cgen.stmt("return hasExt ? %s : nullptr" % entryPointExpr)
343            else:
344                self.cgen.stmt("return %s" % entryPointExpr)
345            self.cgen.endIf()
346            prevFeature = f
347
348        self.cgen.leftline("#endif")
349
350        self.cgen.stmt("return nullptr")
351        self.cgen.endBlock()
352
353        self.module.appendImpl(self.cgen.swapCode())
354
355    def isDeviceDispatch(self, api):
356        # TODO(230793667): improve the heuristic and just use "cmdToFeatureType"
357        return (len(api.parameters) > 0 and
358            "VkDevice" == api.parameters[0].typeName) or (
359            "VkCommandBuffer" == api.parameters[0].typeName and
360            self.cmdToFeatureType.get(api.name, "") == "device")
361