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] 74 75SUCCESS_VAL = { 76 "VkResult" : ["VK_SUCCESS"], 77} 78 79POSTPROCESSES = { 80 "vkResetCommandPool" : """if (vkResetCommandPool_VkResult_return == VK_SUCCESS) { 81 ResourceTracker::get()->resetCommandPoolStagingInfo(commandPool); 82 }""", 83 "vkAllocateCommandBuffers" : """if (vkAllocateCommandBuffers_VkResult_return == VK_SUCCESS) { 84 ResourceTracker::get()->addToCommandPool(pAllocateInfo->commandPool, pAllocateInfo->commandBufferCount, pCommandBuffers); 85 }""", 86} 87 88def is_cmdbuf_dispatch(api): 89 return "VkCommandBuffer" == api.parameters[0].typeName 90 91def is_queue_dispatch(api): 92 return "VkQueue" == api.parameters[0].typeName 93 94class VulkanFuncTable(VulkanWrapperGenerator): 95 def __init__(self, module, typeInfo): 96 VulkanWrapperGenerator.__init__(self, module, typeInfo) 97 self.typeInfo = typeInfo 98 self.cgen = CodeGen() 99 self.entries = [] 100 self.entryFeatures = [] 101 self.feature = None 102 103 def onBegin(self,): 104 cgen = self.cgen 105 cgen.line("static void sOnInvalidDynamicallyCheckedCall(const char* apiname, const char* neededFeature)") 106 cgen.beginBlock() 107 cgen.stmt("ALOGE(\"invalid call to %s: %s not supported\", apiname, neededFeature)") 108 cgen.stmt("abort()") 109 cgen.endBlock() 110 self.module.appendImpl(cgen.swapCode()) 111 pass 112 113 def onBeginFeature(self, featureName): 114 self.feature = featureName 115 116 def onGenCmd(self, cmdinfo, name, alias): 117 typeInfo = self.typeInfo 118 cgen = self.cgen 119 api = typeInfo.apis[name] 120 self.entries.append(api) 121 self.entryFeatures.append(self.feature) 122 123 def genEncoderOrResourceTrackerCall(cgen, api, declareResources=True): 124 cgen.stmt("AEMU_SCOPED_TRACE(\"%s\")" % api.name) 125 126 if is_cmdbuf_dispatch(api): 127 cgen.stmt("auto vkEnc = ResourceTracker::getCommandBufferEncoder(commandBuffer)") 128 elif is_queue_dispatch(api): 129 cgen.stmt("auto vkEnc = ResourceTracker::getQueueEncoder(queue)") 130 else: 131 cgen.stmt("auto vkEnc = ResourceTracker::getThreadLocalEncoder()") 132 callLhs = None 133 retTypeName = api.getRetTypeExpr() 134 if retTypeName != "void": 135 retVar = api.getRetVarExpr() 136 cgen.stmt("%s %s = (%s)0" % (retTypeName, retVar, retTypeName)) 137 callLhs = retVar 138 139 if name in RESOURCE_TRACKER_ENTRIES: 140 if declareResources: 141 cgen.stmt("auto resources = ResourceTracker::get()") 142 cgen.funcCall( 143 callLhs, "resources->" + "on_" + api.name, 144 ["vkEnc"] + SUCCESS_VAL.get(retTypeName, []) + \ 145 [p.paramName for p in api.parameters]) 146 else: 147 cgen.funcCall( 148 callLhs, "vkEnc->" + api.name, [p.paramName for p in api.parameters] + ["true /* do lock */"]) 149 150 if name in POSTPROCESSES: 151 cgen.line(POSTPROCESSES[name]) 152 153 if retTypeName != "void": 154 cgen.stmt("return %s" % retVar) 155 156 157 api_entry = api.withModifiedName("entry_" + api.name) 158 159 cgen.line("static " + self.cgen.makeFuncProto(api_entry)) 160 cgen.beginBlock() 161 genEncoderOrResourceTrackerCall(cgen, api) 162 cgen.endBlock() 163 164 if self.isDeviceDispatch(api) and self.feature != "VK_VERSION_1_0": 165 api_entry_dyn_check = api.withModifiedName("dynCheck_entry_" + api.name) 166 cgen.line("static " + self.cgen.makeFuncProto(api_entry_dyn_check)) 167 cgen.beginBlock() 168 if self.feature == "VK_VERSION_1_1": 169 cgen.stmt("auto resources = ResourceTracker::get()") 170 cgen.beginIf("resources->getApiVersionFromDevice(device) < VK_API_VERSION_1_1") 171 cgen.stmt("sOnInvalidDynamicallyCheckedCall(\"%s\", \"%s\")" % (api.name, self.feature)) 172 cgen.endIf() 173 elif self.feature != "VK_VERSION_1_0": 174 cgen.stmt("auto resources = ResourceTracker::get()") 175 cgen.beginIf("!resources->hasDeviceExtension(device, \"%s\")" % self.feature) 176 cgen.stmt("sOnInvalidDynamicallyCheckedCall(\"%s\", \"%s\")" % (api.name, self.feature)) 177 cgen.endIf() 178 else: 179 print("About to generate a frivolous api!: dynCheck entry: %s" % api.name) 180 raise 181 genEncoderOrResourceTrackerCall(cgen, api, declareResources = False) 182 cgen.endBlock() 183 184 self.module.appendImpl(cgen.swapCode()) 185 186 def onEnd(self,): 187 getProcAddressDecl = "void* goldfish_vulkan_get_proc_address(const char* name)" 188 self.module.appendHeader(getProcAddressDecl + ";\n") 189 self.module.appendImpl(getProcAddressDecl) 190 self.cgen.beginBlock() 191 192 prevFeature = None 193 for e, f in zip(self.entries, self.entryFeatures): 194 featureEndif = prevFeature is not None and (f != prevFeature) 195 featureif = not featureEndif and (f != prevFeature) 196 197 if featureEndif: 198 self.cgen.leftline("#endif") 199 self.cgen.leftline("#ifdef %s" % f) 200 201 if featureif: 202 self.cgen.leftline("#ifdef %s" % f) 203 204 self.cgen.beginIf("!strcmp(name, \"%s\")" % e.name) 205 if e.name in EXCLUDED_APIS: 206 self.cgen.stmt("return nullptr") 207 elif f == "VK_VERSION_1_1": 208 self.cgen.stmt("return nullptr") 209 elif f != "VK_VERSION_1_0": 210 self.cgen.stmt("return nullptr") 211 else: 212 self.cgen.stmt("return (void*)%s" % ("entry_" + e.name)) 213 self.cgen.endIf() 214 prevFeature = f 215 216 self.cgen.leftline("#endif") 217 218 self.cgen.stmt("return nullptr") 219 self.cgen.endBlock() 220 self.module.appendImpl(self.cgen.swapCode()) 221 222 getInstanceProcAddressDecl = "void* goldfish_vulkan_get_instance_proc_address(VkInstance instance, const char* name)" 223 self.module.appendHeader(getInstanceProcAddressDecl + ";\n") 224 self.module.appendImpl(getInstanceProcAddressDecl) 225 self.cgen.beginBlock() 226 227 self.cgen.stmt( 228 "auto resources = ResourceTracker::get()") 229 self.cgen.stmt( 230 "bool has1_1OrHigher = resources->getApiVersionFromInstance(instance) >= VK_API_VERSION_1_1") 231 232 prevFeature = None 233 for e, f in zip(self.entries, self.entryFeatures): 234 featureEndif = prevFeature is not None and (f != prevFeature) 235 featureif = not featureEndif and (f != prevFeature) 236 237 if featureEndif: 238 self.cgen.leftline("#endif") 239 self.cgen.leftline("#ifdef %s" % f) 240 241 if featureif: 242 self.cgen.leftline("#ifdef %s" % f) 243 244 self.cgen.beginIf("!strcmp(name, \"%s\")" % e.name) 245 246 entryPointExpr = "(void*)%s" % ("entry_" + e.name) 247 248 if e.name in EXCLUDED_APIS: 249 self.cgen.stmt("return nullptr") 250 elif f == "VK_VERSION_1_1": 251 if self.isDeviceDispatch(e): 252 self.cgen.stmt("return (void*)dynCheck_entry_%s" % e.name) 253 else: 254 self.cgen.stmt( \ 255 "return has1_1OrHigher ? %s : nullptr" % \ 256 entryPointExpr) 257 elif f != "VK_VERSION_1_0": 258 if self.isDeviceDispatch(e): 259 self.cgen.stmt("return (void*)dynCheck_entry_%s" % e.name) 260 else: 261 self.cgen.stmt( \ 262 "bool hasExt = resources->hasInstanceExtension(instance, \"%s\")" % f) 263 self.cgen.stmt("return hasExt ? %s : nullptr" % entryPointExpr) 264 else: 265 self.cgen.stmt("return %s" % entryPointExpr) 266 self.cgen.endIf() 267 prevFeature = f 268 269 self.cgen.leftline("#endif") 270 271 self.cgen.stmt("return nullptr") 272 self.cgen.endBlock() 273 self.module.appendImpl(self.cgen.swapCode()) 274 275 getDeviceProcAddressDecl = "void* goldfish_vulkan_get_device_proc_address(VkDevice device, const char* name)" 276 self.module.appendHeader(getDeviceProcAddressDecl + ";\n") 277 self.module.appendImpl(getDeviceProcAddressDecl) 278 self.cgen.beginBlock() 279 280 self.cgen.stmt( 281 "auto resources = ResourceTracker::get()") 282 self.cgen.stmt( 283 "bool has1_1OrHigher = resources->getApiVersionFromDevice(device) >= VK_API_VERSION_1_1") 284 285 prevFeature = None 286 for e, f in zip(self.entries, self.entryFeatures): 287 featureEndif = prevFeature is not None and (f != prevFeature) 288 featureif = not featureEndif and (f != prevFeature) 289 290 if featureEndif: 291 self.cgen.leftline("#endif") 292 self.cgen.leftline("#ifdef %s" % f) 293 294 if featureif: 295 self.cgen.leftline("#ifdef %s" % f) 296 297 self.cgen.beginIf("!strcmp(name, \"%s\")" % e.name) 298 299 entryPointExpr = "(void*)%s" % ("entry_" + e.name) 300 301 if e.name in EXCLUDED_APIS: 302 self.cgen.stmt("return nullptr") 303 elif f == "VK_VERSION_1_1": 304 self.cgen.stmt( \ 305 "return has1_1OrHigher ? %s : nullptr" % \ 306 entryPointExpr) 307 elif f != "VK_VERSION_1_0": 308 self.cgen.stmt( \ 309 "bool hasExt = resources->hasDeviceExtension(device, \"%s\")" % f) 310 self.cgen.stmt("return hasExt ? %s : nullptr" % entryPointExpr) 311 else: 312 self.cgen.stmt("return %s" % entryPointExpr) 313 self.cgen.endIf() 314 prevFeature = f 315 316 self.cgen.leftline("#endif") 317 318 self.cgen.stmt("return nullptr") 319 self.cgen.endBlock() 320 321 self.module.appendImpl(self.cgen.swapCode()) 322 323 def isDeviceDispatch(self, api): 324 return len(api.parameters) > 0 and "VkDevice" == api.parameters[0].typeName 325