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