361 lines
14 KiB
Python
361 lines
14 KiB
Python
from .common.codegen import CodeGen, VulkanWrapperGenerator
|
|
from .common.vulkantypes import \
|
|
VulkanAPI, makeVulkanTypeSimple, iterateVulkanType
|
|
from .common.vulkantypes import EXCLUDED_APIS
|
|
|
|
RESOURCE_TRACKER_ENTRIES = [
|
|
"vkEnumerateInstanceExtensionProperties",
|
|
"vkEnumerateDeviceExtensionProperties",
|
|
"vkEnumeratePhysicalDevices",
|
|
"vkAllocateMemory",
|
|
"vkFreeMemory",
|
|
"vkCreateImage",
|
|
"vkDestroyImage",
|
|
"vkGetImageMemoryRequirements",
|
|
"vkGetImageMemoryRequirements2",
|
|
"vkGetImageMemoryRequirements2KHR",
|
|
"vkBindImageMemory",
|
|
"vkBindImageMemory2",
|
|
"vkBindImageMemory2KHR",
|
|
"vkCreateBuffer",
|
|
"vkDestroyBuffer",
|
|
"vkGetBufferMemoryRequirements",
|
|
"vkGetBufferMemoryRequirements2",
|
|
"vkGetBufferMemoryRequirements2KHR",
|
|
"vkBindBufferMemory",
|
|
"vkBindBufferMemory2",
|
|
"vkBindBufferMemory2KHR",
|
|
"vkCreateSemaphore",
|
|
"vkDestroySemaphore",
|
|
"vkQueueSubmit",
|
|
"vkQueueWaitIdle",
|
|
"vkImportSemaphoreFdKHR",
|
|
"vkGetSemaphoreFdKHR",
|
|
# Warning: These need to be defined in vk.xml (currently no-op) {
|
|
"vkGetMemoryFuchsiaHandleKHR",
|
|
"vkGetMemoryFuchsiaHandlePropertiesKHR",
|
|
"vkGetSemaphoreFuchsiaHandleKHR",
|
|
"vkImportSemaphoreFuchsiaHandleKHR",
|
|
# } end Warning: These need to be defined in vk.xml (currently no-op)
|
|
"vkGetAndroidHardwareBufferPropertiesANDROID",
|
|
"vkGetMemoryAndroidHardwareBufferANDROID",
|
|
"vkCreateSamplerYcbcrConversion",
|
|
"vkDestroySamplerYcbcrConversion",
|
|
"vkCreateSamplerYcbcrConversionKHR",
|
|
"vkDestroySamplerYcbcrConversionKHR",
|
|
"vkUpdateDescriptorSetWithTemplate",
|
|
"vkGetPhysicalDeviceImageFormatProperties2",
|
|
"vkGetPhysicalDeviceImageFormatProperties2KHR",
|
|
"vkBeginCommandBuffer",
|
|
"vkEndCommandBuffer",
|
|
"vkResetCommandBuffer",
|
|
"vkCreateImageView",
|
|
"vkCreateSampler",
|
|
"vkGetPhysicalDeviceExternalFenceProperties",
|
|
"vkGetPhysicalDeviceExternalFencePropertiesKHR",
|
|
"vkCreateFence",
|
|
"vkResetFences",
|
|
"vkImportFenceFdKHR",
|
|
"vkGetFenceFdKHR",
|
|
"vkWaitForFences",
|
|
"vkCreateDescriptorPool",
|
|
"vkDestroyDescriptorPool",
|
|
"vkResetDescriptorPool",
|
|
"vkAllocateDescriptorSets",
|
|
"vkFreeDescriptorSets",
|
|
"vkCreateDescriptorSetLayout",
|
|
"vkUpdateDescriptorSets",
|
|
"vkCmdExecuteCommands",
|
|
"vkCmdBindDescriptorSets",
|
|
"vkDestroyDescriptorSetLayout",
|
|
"vkAllocateCommandBuffers",
|
|
"vkQueueSignalReleaseImageANDROID",
|
|
"vkCmdPipelineBarrier",
|
|
"vkCreateGraphicsPipelines",
|
|
]
|
|
|
|
SUCCESS_VAL = {
|
|
"VkResult" : ["VK_SUCCESS"],
|
|
}
|
|
|
|
POSTPROCESSES = {
|
|
"vkResetCommandPool" : """if (vkResetCommandPool_VkResult_return == VK_SUCCESS) {
|
|
ResourceTracker::get()->resetCommandPoolStagingInfo(commandPool);
|
|
}""",
|
|
"vkAllocateCommandBuffers" : """if (vkAllocateCommandBuffers_VkResult_return == VK_SUCCESS) {
|
|
ResourceTracker::get()->addToCommandPool(pAllocateInfo->commandPool, pAllocateInfo->commandBufferCount, pCommandBuffers);
|
|
}""",
|
|
}
|
|
|
|
def is_cmdbuf_dispatch(api):
|
|
return "VkCommandBuffer" == api.parameters[0].typeName
|
|
|
|
def is_queue_dispatch(api):
|
|
return "VkQueue" == api.parameters[0].typeName
|
|
|
|
class VulkanFuncTable(VulkanWrapperGenerator):
|
|
def __init__(self, module, typeInfo):
|
|
VulkanWrapperGenerator.__init__(self, module, typeInfo)
|
|
self.typeInfo = typeInfo
|
|
self.cgen = CodeGen()
|
|
self.entries = []
|
|
self.entryFeatures = []
|
|
self.cmdToFeatureType = {}
|
|
self.feature = None
|
|
self.featureType = None
|
|
|
|
def onBegin(self,):
|
|
cgen = self.cgen
|
|
cgen.line("static void sOnInvalidDynamicallyCheckedCall(const char* apiname, const char* neededFeature)")
|
|
cgen.beginBlock()
|
|
cgen.stmt("ALOGE(\"invalid call to %s: %s not supported\", apiname, neededFeature)")
|
|
cgen.stmt("abort()")
|
|
cgen.endBlock()
|
|
self.module.appendImpl(cgen.swapCode())
|
|
pass
|
|
|
|
def onBeginFeature(self, featureName, featureType):
|
|
self.feature = featureName
|
|
self.featureType = featureType
|
|
|
|
def onEndFeature(self):
|
|
self.feature = None
|
|
self.featureType = None
|
|
|
|
def onFeatureNewCmd(self, name):
|
|
self.cmdToFeatureType[name] = self.featureType
|
|
|
|
def onGenCmd(self, cmdinfo, name, alias):
|
|
typeInfo = self.typeInfo
|
|
cgen = self.cgen
|
|
api = typeInfo.apis[name]
|
|
self.entries.append(api)
|
|
self.entryFeatures.append(self.feature)
|
|
|
|
def genEncoderOrResourceTrackerCall(cgen, api, declareResources=True):
|
|
cgen.stmt("AEMU_SCOPED_TRACE(\"%s\")" % api.name)
|
|
|
|
if is_cmdbuf_dispatch(api):
|
|
cgen.stmt("auto vkEnc = ResourceTracker::getCommandBufferEncoder(commandBuffer)")
|
|
elif is_queue_dispatch(api):
|
|
cgen.stmt("auto vkEnc = ResourceTracker::getQueueEncoder(queue)")
|
|
else:
|
|
cgen.stmt("auto vkEnc = ResourceTracker::getThreadLocalEncoder()")
|
|
callLhs = None
|
|
retTypeName = api.getRetTypeExpr()
|
|
if retTypeName != "void":
|
|
retVar = api.getRetVarExpr()
|
|
cgen.stmt("%s %s = (%s)0" % (retTypeName, retVar, retTypeName))
|
|
callLhs = retVar
|
|
|
|
if name in RESOURCE_TRACKER_ENTRIES:
|
|
if declareResources:
|
|
cgen.stmt("auto resources = ResourceTracker::get()")
|
|
cgen.funcCall(
|
|
callLhs, "resources->" + "on_" + api.name,
|
|
["vkEnc"] + SUCCESS_VAL.get(retTypeName, []) + \
|
|
[p.paramName for p in api.parameters])
|
|
else:
|
|
cgen.funcCall(
|
|
callLhs, "vkEnc->" + api.name, [p.paramName for p in api.parameters] + ["true /* do lock */"])
|
|
|
|
if name in POSTPROCESSES:
|
|
cgen.line(POSTPROCESSES[name])
|
|
|
|
if retTypeName != "void":
|
|
cgen.stmt("return %s" % retVar)
|
|
|
|
|
|
api_entry = api.withModifiedName("entry_" + api.name)
|
|
|
|
cgen.line("static " + self.cgen.makeFuncProto(api_entry))
|
|
cgen.beginBlock()
|
|
genEncoderOrResourceTrackerCall(cgen, api)
|
|
cgen.endBlock()
|
|
|
|
if self.isDeviceDispatch(api) and self.feature != "VK_VERSION_1_0":
|
|
api_entry_dyn_check = api.withModifiedName("dynCheck_entry_" + api.name)
|
|
cgen.line("static " + self.cgen.makeFuncProto(api_entry_dyn_check))
|
|
cgen.beginBlock()
|
|
if self.feature == "VK_VERSION_1_1":
|
|
cgen.stmt("auto resources = ResourceTracker::get()")
|
|
if "VkCommandBuffer" == api.parameters[0].typeName:
|
|
cgen.stmt("VkDevice device = resources->getDevice(commandBuffer)")
|
|
cgen.beginIf("resources->getApiVersionFromDevice(device) < VK_API_VERSION_1_1")
|
|
cgen.stmt("sOnInvalidDynamicallyCheckedCall(\"%s\", \"%s\")" % (api.name, self.feature))
|
|
cgen.endIf()
|
|
elif self.feature != "VK_VERSION_1_0":
|
|
cgen.stmt("auto resources = ResourceTracker::get()")
|
|
if "VkCommandBuffer" == api.parameters[0].typeName:
|
|
cgen.stmt("VkDevice device = resources->getDevice(commandBuffer);")
|
|
cgen.beginIf("!resources->hasDeviceExtension(device, \"%s\")" % self.feature)
|
|
cgen.stmt("sOnInvalidDynamicallyCheckedCall(\"%s\", \"%s\")" % (api.name, self.feature))
|
|
cgen.endIf()
|
|
else:
|
|
print("About to generate a frivolous api!: dynCheck entry: %s" % api.name)
|
|
raise
|
|
genEncoderOrResourceTrackerCall(cgen, api, declareResources = False)
|
|
cgen.endBlock()
|
|
|
|
self.module.appendImpl(cgen.swapCode())
|
|
|
|
def onEnd(self,):
|
|
getProcAddressDecl = "void* goldfish_vulkan_get_proc_address(const char* name)"
|
|
self.module.appendHeader(getProcAddressDecl + ";\n")
|
|
self.module.appendImpl(getProcAddressDecl)
|
|
self.cgen.beginBlock()
|
|
|
|
prevFeature = None
|
|
for e, f in zip(self.entries, self.entryFeatures):
|
|
featureEndif = prevFeature is not None and (f != prevFeature)
|
|
featureif = not featureEndif and (f != prevFeature)
|
|
|
|
if featureEndif:
|
|
self.cgen.leftline("#endif")
|
|
self.cgen.leftline("#ifdef %s" % f)
|
|
|
|
if featureif:
|
|
self.cgen.leftline("#ifdef %s" % f)
|
|
|
|
self.cgen.beginIf("!strcmp(name, \"%s\")" % e.name)
|
|
if e.name in EXCLUDED_APIS:
|
|
self.cgen.stmt("return nullptr")
|
|
elif f == "VK_VERSION_1_1":
|
|
self.cgen.stmt("return nullptr")
|
|
elif f != "VK_VERSION_1_0":
|
|
self.cgen.stmt("return nullptr")
|
|
else:
|
|
self.cgen.stmt("return (void*)%s" % ("entry_" + e.name))
|
|
self.cgen.endIf()
|
|
prevFeature = f
|
|
|
|
self.cgen.leftline("#endif")
|
|
|
|
self.cgen.stmt("return nullptr")
|
|
self.cgen.endBlock()
|
|
self.module.appendImpl(self.cgen.swapCode())
|
|
|
|
getInstanceProcAddressDecl = "void* goldfish_vulkan_get_instance_proc_address(VkInstance instance, const char* name)"
|
|
self.module.appendHeader(getInstanceProcAddressDecl + ";\n")
|
|
self.module.appendImpl(getInstanceProcAddressDecl)
|
|
self.cgen.beginBlock()
|
|
|
|
self.cgen.stmt(
|
|
"auto resources = ResourceTracker::get()")
|
|
self.cgen.stmt(
|
|
"bool has1_1OrHigher = resources->getApiVersionFromInstance(instance) >= VK_API_VERSION_1_1")
|
|
self.cgen.stmt(
|
|
"bool has1_2OrHigher = resources->getApiVersionFromInstance(instance) >= VK_API_VERSION_1_2")
|
|
|
|
prevFeature = None
|
|
for e, f in zip(self.entries, self.entryFeatures):
|
|
featureEndif = prevFeature is not None and (f != prevFeature)
|
|
featureif = not featureEndif and (f != prevFeature)
|
|
|
|
if featureEndif:
|
|
self.cgen.leftline("#endif")
|
|
self.cgen.leftline("#ifdef %s" % f)
|
|
|
|
if featureif:
|
|
self.cgen.leftline("#ifdef %s" % f)
|
|
|
|
self.cgen.beginIf("!strcmp(name, \"%s\")" % e.name)
|
|
|
|
entryPointExpr = "(void*)%s" % ("entry_" + e.name)
|
|
|
|
if e.name in EXCLUDED_APIS:
|
|
self.cgen.stmt("return nullptr")
|
|
elif f == "VK_VERSION_1_2":
|
|
if self.isDeviceDispatch(e):
|
|
self.cgen.stmt("return (void*)dynCheck_entry_%s" % e.name)
|
|
else:
|
|
self.cgen.stmt( \
|
|
"return has1_2OrHigher ? %s : nullptr" % \
|
|
entryPointExpr)
|
|
elif f == "VK_VERSION_1_1":
|
|
if self.isDeviceDispatch(e):
|
|
self.cgen.stmt("return (void*)dynCheck_entry_%s" % e.name)
|
|
else:
|
|
self.cgen.stmt( \
|
|
"return has1_1OrHigher ? %s : nullptr" % \
|
|
entryPointExpr)
|
|
elif f != "VK_VERSION_1_0":
|
|
entryNeedsInstanceExtensionCheck = self.cmdToFeatureType[e.name] == "instance"
|
|
|
|
entryPrefix = "dynCheck_" if self.isDeviceDispatch(e) else ""
|
|
entryPointExpr = "(void*)%sentry_%s" % (entryPrefix, e.name)
|
|
|
|
if entryNeedsInstanceExtensionCheck:
|
|
self.cgen.stmt("bool hasExt = resources->hasInstanceExtension(instance, \"%s\")" % f)
|
|
self.cgen.stmt("return hasExt ? %s : nullptr" % entryPointExpr)
|
|
else:
|
|
# TODO(b/236246382): We need to check the device extension support here.
|
|
self.cgen.stmt("// TODO(b/236246382): Check support for device extension");
|
|
self.cgen.stmt("return %s" % entryPointExpr)
|
|
|
|
else:
|
|
self.cgen.stmt("return %s" % entryPointExpr)
|
|
self.cgen.endIf()
|
|
prevFeature = f
|
|
|
|
self.cgen.leftline("#endif")
|
|
|
|
self.cgen.stmt("return nullptr")
|
|
self.cgen.endBlock()
|
|
self.module.appendImpl(self.cgen.swapCode())
|
|
|
|
getDeviceProcAddressDecl = "void* goldfish_vulkan_get_device_proc_address(VkDevice device, const char* name)"
|
|
self.module.appendHeader(getDeviceProcAddressDecl + ";\n")
|
|
self.module.appendImpl(getDeviceProcAddressDecl)
|
|
self.cgen.beginBlock()
|
|
|
|
self.cgen.stmt(
|
|
"auto resources = ResourceTracker::get()")
|
|
self.cgen.stmt(
|
|
"bool has1_1OrHigher = resources->getApiVersionFromDevice(device) >= VK_API_VERSION_1_1")
|
|
|
|
prevFeature = None
|
|
for e, f in zip(self.entries, self.entryFeatures):
|
|
featureEndif = prevFeature is not None and (f != prevFeature)
|
|
featureif = not featureEndif and (f != prevFeature)
|
|
|
|
if featureEndif:
|
|
self.cgen.leftline("#endif")
|
|
self.cgen.leftline("#ifdef %s" % f)
|
|
|
|
if featureif:
|
|
self.cgen.leftline("#ifdef %s" % f)
|
|
|
|
self.cgen.beginIf("!strcmp(name, \"%s\")" % e.name)
|
|
|
|
entryPointExpr = "(void*)%s" % ("entry_" + e.name)
|
|
|
|
if e.name in EXCLUDED_APIS:
|
|
self.cgen.stmt("return nullptr")
|
|
elif f == "VK_VERSION_1_1":
|
|
self.cgen.stmt( \
|
|
"return has1_1OrHigher ? %s : nullptr" % \
|
|
entryPointExpr)
|
|
elif f != "VK_VERSION_1_0":
|
|
self.cgen.stmt( \
|
|
"bool hasExt = resources->hasDeviceExtension(device, \"%s\")" % f)
|
|
self.cgen.stmt("return hasExt ? %s : nullptr" % entryPointExpr)
|
|
else:
|
|
self.cgen.stmt("return %s" % entryPointExpr)
|
|
self.cgen.endIf()
|
|
prevFeature = f
|
|
|
|
self.cgen.leftline("#endif")
|
|
|
|
self.cgen.stmt("return nullptr")
|
|
self.cgen.endBlock()
|
|
|
|
self.module.appendImpl(self.cgen.swapCode())
|
|
|
|
def isDeviceDispatch(self, api):
|
|
# TODO(230793667): improve the heuristic and just use "cmdToFeatureType"
|
|
return (len(api.parameters) > 0 and
|
|
"VkDevice" == api.parameters[0].typeName) or (
|
|
"VkCommandBuffer" == api.parameters[0].typeName and
|
|
self.cmdToFeatureType.get(api.name, "") == "device")
|