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