diff --git a/src/gfxstream/codegen/scripts/cereal/__init__.py b/src/gfxstream/codegen/scripts/cereal/__init__.py index 809a1776964..1966572ffc4 100644 --- a/src/gfxstream/codegen/scripts/cereal/__init__.py +++ b/src/gfxstream/codegen/scripts/cereal/__init__.py @@ -4,7 +4,6 @@ from .encoder import * from .extensionstructs import * from .frontend import * from .functable import * -from .mesa_functable import * from .marshaling import * from .reservedmarshaling import * from .counting import * diff --git a/src/gfxstream/codegen/scripts/cereal/functable.py b/src/gfxstream/codegen/scripts/cereal/functable.py index 016d6cac67a..2d3415059eb 100644 --- a/src/gfxstream/codegen/scripts/cereal/functable.py +++ b/src/gfxstream/codegen/scripts/cereal/functable.py @@ -2,6 +2,10 @@ from .common.codegen import CodeGen, VulkanWrapperGenerator from .common.vulkantypes import \ VulkanAPI, makeVulkanTypeSimple, iterateVulkanType from .common.vulkantypes import EXCLUDED_APIS +from .common.vulkantypes import HANDLE_TYPES + +import copy +import re RESOURCE_TRACKER_ENTRIES = [ "vkEnumerateInstanceExtensionProperties", @@ -45,6 +49,7 @@ RESOURCE_TRACKER_ENTRIES = [ "vkCreateSamplerYcbcrConversionKHR", "vkDestroySamplerYcbcrConversionKHR", "vkUpdateDescriptorSetWithTemplate", + "vkUpdateDescriptorSetWithTemplateKHR", "vkGetPhysicalDeviceImageFormatProperties2", "vkGetPhysicalDeviceImageFormatProperties2KHR", "vkBeginCommandBuffer", @@ -67,7 +72,6 @@ RESOURCE_TRACKER_ENTRIES = [ "vkAllocateDescriptorSets", "vkFreeDescriptorSets", "vkCreateDescriptorSetLayout", - "vkUpdateDescriptorSets", "vkCmdExecuteCommands", "vkCmdBindDescriptorSets", "vkDestroyDescriptorSetLayout", @@ -91,13 +95,78 @@ 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); - }""", +HANDWRITTEN_ENTRY_POINTS = [ + # Instance/device/physical-device special-handling, dispatch tables, etc.. + "vkCreateInstance", + "vkDestroyInstance", + "vkGetInstanceProcAddr", + "vkEnumerateInstanceVersion", + "vkEnumerateInstanceLayerProperties", + "vkEnumerateInstanceExtensionProperties", + "vkEnumerateDeviceExtensionProperties", + "vkGetDeviceProcAddr", + "vkEnumeratePhysicalDevices", + "vkEnumeratePhysicalDeviceGroups", + "vkCreateDevice", + "vkDestroyDevice", + "vkCreateComputePipelines", + # Manual alloc/free + vk_*_init/free() call w/ special params + "vkGetDeviceQueue", + "vkGetDeviceQueue2", + # Command pool/buffer handling + "vkCreateCommandPool", + "vkDestroyCommandPool", + "vkAllocateCommandBuffers", + "vkResetCommandPool", + "vkFreeCommandBuffers", + "vkResetCommandPool", + # Special cases to handle struct translations in the pNext chain + # TODO: Make a codegen module (use deepcopy as reference) to make this more robust + "vkCmdBeginRenderPass2KHR", + "vkCmdBeginRenderPass", + "vkAllocateMemory", + "vkUpdateDescriptorSets", + "vkQueueCommitDescriptorSetUpdatesGOOGLE", +] + +# TODO: handles with no equivalent gfxstream objects (yet). +# Might need some special handling. +HANDLES_DONT_TRANSLATE = { + "VkSurfaceKHR", + ## The following objects have no need for mesa counterparts + # Allows removal of handwritten create/destroy (for array). + "VkDescriptorSet", + # Bug in translation + "VkSampler", + "VkSamplerYcbcrConversion", +} + +# Handles whose gfxstream object have non-base-object vk_ structs +# Optionally includes array of pairs of extraParams: {index, extraParam} +# -1 means drop parameter of paramName specified by extraParam +HANDLES_MESA_VK = { + # Handwritten handlers (added here for completeness) + "VkInstance" : None, + "VkPhysicalDevice" : None, + "VkDevice" : None, + "VkQueue" : None, + "VkCommandPool" : None, + "VkCommandBuffer" : None, + # Auto-generated creation/destroy + "VkDeviceMemory" : None, + "VkQueryPool" : None, + "VkBuffer" : [[-1, "pMemoryRequirements"]], + "VkBufferView" : None, + "VkImage" : [[-1, "pMemoryRequirements"]], + "VkImageView": [[1, "false /* driver_internal */"]], + "VkSampler" : None, +} + +# Types that have a corresponding method for transforming +# an input list to its internal counterpart +TYPES_TRANSFORM_LIST_METHOD = { + "VkSemaphore", + "VkSemaphoreSubmitInfo", } def is_cmdbuf_dispatch(api): @@ -106,6 +175,59 @@ def is_cmdbuf_dispatch(api): def is_queue_dispatch(api): return "VkQueue" == api.parameters[0].typeName +def getCreateParam(api): + for param in api.parameters: + if param.isCreatedBy(api): + return param + return None + +def getDestroyParam(api): + for param in api.parameters: + if param.isDestroyedBy(api): + return param + return None + +# i.e. VkQueryPool --> vk_query_pool +def typeNameToMesaType(typeName): + vkTypeNameRegex = "(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])" + words = re.split(vkTypeNameRegex, typeName) + outputType = "vk" + for word in words[1:]: + outputType += "_" + outputType += word.lower() + return outputType + +def typeNameToBaseName(typeName): + return typeNameToMesaType(typeName)[len("vk_"):] + +def paramNameToObjectName(paramName): + return "gfxstream_%s" % paramName + +def typeNameToVkObjectType(typeName): + return "VK_OBJECT_TYPE_%s" % typeNameToBaseName(typeName).upper() + +def typeNameToObjectType(typeName): + return "gfxstream_vk_%s" % typeNameToBaseName(typeName) + +def transformListFuncName(typeName): + return "transform%sList" % (typeName) + +def hasMesaVkObject(typeName): + return typeName in HANDLES_MESA_VK + +def isAllocatorParam(param): + ALLOCATOR_TYPE_NAME = "VkAllocationCallbacks" + return (param.pointerIndirectionLevels == 1 + and param.isConst + and param.typeName == ALLOCATOR_TYPE_NAME) + +def isArrayParam(param): + return (1 == param.pointerIndirectionLevels + and param.isConst + and "len" in param.attribs) + +INTERNAL_OBJECT_NAME = "internal_object" + class VulkanFuncTable(VulkanWrapperGenerator): def __init__(self, module, typeInfo): VulkanWrapperGenerator.__init__(self, module, typeInfo) @@ -119,11 +241,6 @@ class VulkanFuncTable(VulkanWrapperGenerator): 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 @@ -144,264 +261,365 @@ class VulkanFuncTable(VulkanWrapperGenerator): api = typeInfo.apis[name] self.entries.append(api) self.entryFeatures.append(self.feature) + self.loopVars = ["i", "j", "k", "l", "m", "n"] + self.loopVarIndex = 0 - def genEncoderOrResourceTrackerCall(cgen, api, declareResources=True): - cgen.stmt("AEMU_SCOPED_TRACE(\"%s\")" % api.name) + def getNextLoopVar(): + if self.loopVarIndex >= len(self.loopVars): + raise + loopVar = self.loopVars[self.loopVarIndex] + self.loopVarIndex += 1 + return loopVar - if is_cmdbuf_dispatch(api): - cgen.stmt("auto vkEnc = ResourceTracker::getCommandBufferEncoder(commandBuffer)") - elif is_queue_dispatch(api): - cgen.stmt("auto vkEnc = ResourceTracker::getQueueEncoder(queue)") + def isCompoundType(typeName): + return typeInfo.isCompoundType(typeName) + + def handleTranslationRequired(typeName): + return typeName in HANDLE_TYPES and typeName not in HANDLES_DONT_TRANSLATE + + def translationRequired(typeName): + if isCompoundType(typeName): + struct = typeInfo.structs[typeName] + for member in struct.members: + if translationRequired(member.typeName): + return True + return False else: - cgen.stmt("auto vkEnc = ResourceTracker::getThreadLocalEncoder()") + return handleTranslationRequired(typeName) + + def genDestroyGfxstreamObjects(): + destroyParam = getDestroyParam(api) + if not destroyParam: + return + if not translationRequired(destroyParam.typeName): + return + objectName = paramNameToObjectName(destroyParam.paramName) + allocatorParam = "NULL" + for p in api.parameters: + if isAllocatorParam(p): + allocatorParam = p.paramName + if not hasMesaVkObject(destroyParam.typeName): + deviceParam = api.parameters[0] + if "VkDevice" != deviceParam.typeName: + print("ERROR: Unhandled non-VkDevice parameters[0]: %s (for API: %s)" %(deviceParam.typeName, api.name)) + raise + # call vk_object_free() directly + mesaObjectDestroy = "(void *)%s" % objectName + cgen.funcCall( + None, + "vk_object_free", + ["&%s->vk" % paramNameToObjectName(deviceParam.paramName), allocatorParam, mesaObjectDestroy] + ) + else: + baseName = typeNameToBaseName(destroyParam.typeName) + # objectName for destroy always at the back + mesaObjectPrimary = "&%s->vk" % paramNameToObjectName(api.parameters[0].paramName) + mesaObjectDestroy = "&%s->vk" % objectName + cgen.funcCall( + None, + "vk_%s_destroy" % (baseName), + [mesaObjectPrimary, allocatorParam, mesaObjectDestroy] + ) + + def genMesaObjectAlloc(allocCallLhs): + deviceParam = api.parameters[0] + if "VkDevice" != deviceParam.typeName: + print("ERROR: Unhandled non-VkDevice parameters[0]: %s (for API: %s)" %(deviceParam.typeName, api.name)) + raise + allocatorParam = "NULL" + for p in api.parameters: + if isAllocatorParam(p): + allocatorParam = p.paramName + createParam = getCreateParam(api) + objectType = typeNameToObjectType(createParam.typeName) + # Call vk_object_zalloc directly + cgen.funcCall( + allocCallLhs, + "(%s *)vk_object_zalloc" % objectType, + ["&%s->vk" % paramNameToObjectName(deviceParam.paramName), allocatorParam, ("sizeof(%s)" % objectType), typeNameToVkObjectType(createParam.typeName)] + ) + + def genMesaObjectCreate(createCallLhs): + def dropParam(params, drop): + for p in params: + if p == drop: + params.remove(p) + return params + createParam = getCreateParam(api) + objectType = "struct %s" % typeNameToObjectType(createParam.typeName) + modParams = copy.deepcopy(api.parameters) + # Mod params for the vk_%s_create() call i.e. vk_buffer_create() + for p in modParams: + if p.paramName == createParam.paramName: + modParams.remove(p) + elif handleTranslationRequired(p.typeName): + # Cast handle to the mesa type + p.paramName = ("(%s*)%s" % (typeNameToMesaType(p.typeName), paramNameToObjectName(p.paramName))) + mesaCreateParams = [p.paramName for p in modParams] + ["sizeof(%s)" % objectType] + # Some special handling + extraParams = HANDLES_MESA_VK[createParam.typeName] + if extraParams: + for pair in extraParams: + if -1 == pair[0]: + mesaCreateParams = dropParam(mesaCreateParams, pair[1]) + else: + mesaCreateParams.insert(pair[0], pair[1]) + cgen.funcCall( + createCallLhs, + "(%s *)vk_%s_create" % (objectType, typeNameToBaseName(createParam.typeName)), + mesaCreateParams + ) + + # Alloc/create gfxstream_vk_* object + def genCreateGfxstreamObjects(): + createParam = getCreateParam(api) + if not createParam: + return False + if not handleTranslationRequired(createParam.typeName): + return False + objectType = "struct %s" % typeNameToObjectType(createParam.typeName) + callLhs = "%s *%s" % (objectType, paramNameToObjectName(createParam.paramName)) + if hasMesaVkObject(createParam.typeName): + genMesaObjectCreate(callLhs) + else: + genMesaObjectAlloc(callLhs) + + retVar = api.getRetVarExpr() + if retVar: + retTypeName = api.getRetTypeExpr() + # ex: vkCreateBuffer_VkResult_return = gfxstream_buffer ? VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY; + cgen.stmt("%s = %s ? %s : %s" % + (retVar, paramNameToObjectName(createParam.paramName), SUCCESS_VAL[retTypeName][0], "VK_ERROR_OUT_OF_HOST_MEMORY")) + return True + + def genVkFromHandle(param, fromName): + objectName = paramNameToObjectName(param.paramName) + cgen.stmt("VK_FROM_HANDLE(%s, %s, %s)" % + (typeNameToObjectType(param.typeName), objectName, fromName)) + return objectName + + def genGetGfxstreamHandles(): + createParam = getCreateParam(api) + for param in api.parameters: + if not handleTranslationRequired(param.typeName): + continue + elif isArrayParam(param): + continue + elif param != createParam: + if param.pointerIndirectionLevels > 0: + print("ERROR: Unhandled pointerIndirectionLevels > 1 for API %s (param %s)" % (api.name, param.paramName)) + raise + genVkFromHandle(param, param.paramName) + + def internalNestedParamName(param): + parentName = "" + if param.parent: + parentName = "_%s" % param.parent.typeName + return "internal%s_%s" % (parentName, param.paramName) + + def genInternalArrayDeclarations(param, countParamName, nestLevel=0): + internalArray = None + if 0 == nestLevel: + internalArray = "internal_%s" % param.paramName + cgen.stmt("std::vector<%s> %s(%s)" % (param.typeName, internalArray, countParamName)) + elif 1 == nestLevel or 2 == nestLevel: + internalArray = internalNestedParamName(param) + if isArrayParam(param): + cgen.stmt("std::vector> %s" % (param.typeName, internalArray)) + else: + cgen.stmt("std::vector<%s> %s" % (param.typeName, internalArray)) + else: + print("ERROR: nestLevel > 2 not verified.") + raise + if isCompoundType(param.typeName): + for member in typeInfo.structs[param.typeName].members: + if translationRequired(member.typeName): + if handleTranslationRequired(member.typeName) and not isArrayParam(member): + # No declarations for non-array handleType + continue + genInternalArrayDeclarations(member, countParamName, nestLevel + 1) + return internalArray + + def genInternalCompoundType(param, outName, inName, currLoopVar): + nextLoopVar = None + cgen.stmt("%s = %s" % (outName, inName)) + for member in typeInfo.structs[param.typeName].members: + if not translationRequired(member.typeName): + continue + cgen.line("/* %s::%s */" % (param.typeName, member.paramName)) + nestedOutName = ("%s[%s]" % (internalNestedParamName(member), currLoopVar)) + if isArrayParam(member): + countParamName = "%s.%s" % (outName, member.attribs["len"]) + inArrayName = "%s.%s" % (outName, member.paramName) + cgen.stmt("%s.push_back(std::vector<%s>())" % (internalNestedParamName(member), member.typeName)) + if member.typeName in TYPES_TRANSFORM_LIST_METHOD: + # Use the corresponding transformList call + cgen.funcCall(nestedOutName, transformListFuncName(member.typeName), [inArrayName, countParamName]) + cgen.stmt("%s = %s.data()" % (inArrayName, nestedOutName)) + cgen.stmt("%s = %s.size()" % (countParamName, nestedOutName)) + else: + # Standard translation + cgen.stmt("%s.reserve(%s)" % (nestedOutName, countParamName)) + cgen.stmt("memset(&%s[0], 0, sizeof(%s) * %s)" % (nestedOutName, member.typeName, countParamName)) + if not nextLoopVar: + nextLoopVar = getNextLoopVar() + internalArray = genInternalArray(member, countParamName, nestedOutName, inArrayName, nextLoopVar) + cgen.stmt("%s = %s" %(inArrayName, internalArray)) + elif isCompoundType(member.typeName): + memberFullName = "%s.%s" % (outName, member.paramName) + if 1 == member.pointerIndirectionLevels: + cgen.beginIf(memberFullName) + inParamName = "%s[0]" % memberFullName + genInternalCompoundType(member, nestedOutName, inParamName, currLoopVar) + cgen.stmt("%s.%s = &%s" % (outName, member.paramName, nestedOutName)) + else: + cgen.beginBlock() + genInternalCompoundType(member, nestedOutName, memberFullName, currLoopVar) + cgen.stmt("%s.%s = %s" % (outName, member.paramName, nestedOutName)) + cgen.endBlock() + else: + # Replace member with internal object + replaceName = "%s.%s" % (outName, member.paramName) + if member.isOptional: + cgen.beginIf(replaceName) + gfxstreamObject = genVkFromHandle(member, replaceName) + cgen.stmt("%s = %s->%s" % (replaceName, gfxstreamObject, INTERNAL_OBJECT_NAME)) + if member.isOptional: + cgen.endIf() + + def genInternalArray(param, countParamName, outArrayName, inArrayName, loopVar): + cgen.beginFor("uint32_t %s = 0" % loopVar, "%s < %s" % (loopVar, countParamName), "++%s" % loopVar) + if param.isOptional: + cgen.beginIf(inArrayName) + if isCompoundType(param.typeName): + genInternalCompoundType(param, ("%s[%s]" % (outArrayName, loopVar)), "%s[%s]" % (inArrayName, loopVar), loopVar) + else: + gfxstreamObject = genVkFromHandle(param, "%s[%s]" % (inArrayName, loopVar)) + cgen.stmt("%s[%s] = %s->%s" % (outArrayName, loopVar, gfxstreamObject, INTERNAL_OBJECT_NAME)) + if param.isOptional: + cgen.endIf() + cgen.endFor() + return "%s.data()" % outArrayName + + # Translate params into params needed for gfxstream-internal + # encoder/resource-tracker calls + def getEncoderOrResourceTrackerParams(): + createParam = getCreateParam(api) + outParams = copy.deepcopy(api.parameters) + nextLoopVar = getNextLoopVar() + for param in outParams: + if not translationRequired(param.typeName): + continue + elif isArrayParam(param) or isCompoundType(param.typeName): + if param.possiblyOutput(): + print("ERROR: Unhandled CompoundType / Array output for API %s (param %s)" % (api.name, param.paramName)) + raise + if 1 != param.pointerIndirectionLevels or not param.isConst: + print("ERROR: Compound type / array input is not 'const *' (API: %s, paramName: %s)" % (api.name, param.paramName)) + raise + countParamName = "1" + if "len" in param.attribs: + countParamName = param.attribs["len"] + internalArrayName = genInternalArrayDeclarations(param, countParamName) + param.paramName = genInternalArray(param, countParamName, internalArrayName, param.paramName, nextLoopVar) + elif 0 == param.pointerIndirectionLevels: + if param.isOptional: + param.paramName = ("%s ? %s->%s : VK_NULL_HANDLE" % (paramNameToObjectName(param.paramName), paramNameToObjectName(param.paramName), INTERNAL_OBJECT_NAME)) + else: + param.paramName = ("%s->%s" % (paramNameToObjectName(param.paramName), INTERNAL_OBJECT_NAME)) + elif createParam and param.paramName == createParam.paramName: + param.paramName = ("&%s->%s" % (paramNameToObjectName(param.paramName), INTERNAL_OBJECT_NAME)) + else: + print("ERROR: Unknown handling for param: %s (API: %s)" % (param, api.name)) + raise + return outParams + + def genEncoderOrResourceTrackerCall(declareResources=True): + if is_cmdbuf_dispatch(api): + cgen.stmt("auto vkEnc = gfxstream::vk::ResourceTracker::getCommandBufferEncoder(%s->%s)" % (paramNameToObjectName(api.parameters[0].paramName), INTERNAL_OBJECT_NAME)) + elif is_queue_dispatch(api): + cgen.stmt("auto vkEnc = gfxstream::vk::ResourceTracker::getQueueEncoder(%s->%s)" % (paramNameToObjectName(api.parameters[0].paramName), INTERNAL_OBJECT_NAME)) + else: + cgen.stmt("auto vkEnc = gfxstream::vk::ResourceTracker::getThreadLocalEncoder()") callLhs = None retTypeName = api.getRetTypeExpr() if retTypeName != "void": - retVar = api.getRetVarExpr() - cgen.stmt("%s %s = (%s)0" % (retTypeName, retVar, retTypeName)) - callLhs = retVar + callLhs = api.getRetVarExpr() + # Get parameter list modded for gfxstream-internal call + parameters = getEncoderOrResourceTrackerParams() if name in RESOURCE_TRACKER_ENTRIES: if declareResources: - cgen.stmt("auto resources = ResourceTracker::get()") + cgen.stmt("auto resources = gfxstream::vk::ResourceTracker::get()") cgen.funcCall( callLhs, "resources->" + "on_" + api.name, ["vkEnc"] + SUCCESS_VAL.get(retTypeName, []) + \ - [p.paramName for p in api.parameters]) + [p.paramName for p in parameters]) else: cgen.funcCall( - callLhs, "vkEnc->" + api.name, [p.paramName for p in api.parameters] + ["true /* do lock */"]) + callLhs, "vkEnc->" + api.name, [p.paramName for p in parameters] + ["true /* do lock */"]) - if name in POSTPROCESSES: - cgen.line(POSTPROCESSES[name]) + def genReturnExpression(): + retTypeName = api.getRetTypeExpr() + # Set the createParam output, if applicable + createParam = getCreateParam(api) + if createParam and handleTranslationRequired(createParam.typeName): + if 1 != createParam.pointerIndirectionLevels: + print("ERROR: Unhandled pointerIndirectionLevels != 1 in return for API %s (createParam %s)" % api.name, createParam.paramName) + raise + # ex: *pBuffer = gfxstream_vk_buffer_to_handle(gfxstream_buffer) + cgen.funcCall( + "*%s" % createParam.paramName, + "%s_to_handle" % typeNameToObjectType(createParam.typeName), + [paramNameToObjectName(createParam.paramName)] + ) if retTypeName != "void": - cgen.stmt("return %s" % retVar) + cgen.stmt("return %s" % api.getRetVarExpr()) - - 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_3": - 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_3") - cgen.stmt("sOnInvalidDynamicallyCheckedCall(\"%s\", \"%s\")" % (api.name, self.feature)) - cgen.endIf() - elif self.feature == "VK_VERSION_1_2": - 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_2") - cgen.stmt("sOnInvalidDynamicallyCheckedCall(\"%s\", \"%s\")" % (api.name, self.feature)) - cgen.endIf() - elif 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)) + def genGfxstreamEntry(declareResources=True): + cgen.stmt("AEMU_SCOPED_TRACE(\"%s\")" % api.name) + # declare returnVar + retTypeName = api.getRetTypeExpr() + retVar = api.getRetVarExpr() + if retVar: + cgen.stmt("%s %s = (%s)0" % (retTypeName, retVar, retTypeName)) + # Check non-null destroy param for free/destroy calls + destroyParam = getDestroyParam(api) + if destroyParam: + cgen.beginIf("VK_NULL_HANDLE == %s" % destroyParam.paramName) + if api.getRetTypeExpr() != "void": + cgen.stmt("return %s" % api.getRetVarExpr()) + else: + cgen.stmt("return") cgen.endIf() + # Translate handles + genGetGfxstreamHandles() + # Translation/creation of objects + createdObject = genCreateGfxstreamObjects() + # Make encoder/resource-tracker call + if retVar and createdObject: + cgen.beginIf("%s == %s" % (SUCCESS_VAL[retTypeName][0], retVar)) else: - print("About to generate a frivolous api!: dynCheck entry: %s" % api.name) - raise - genEncoderOrResourceTrackerCall(cgen, api, declareResources = False) + cgen.beginBlock() + genEncoderOrResourceTrackerCall() cgen.endBlock() + # Destroy gfxstream objects + genDestroyGfxstreamObjects() + # Set output / return variables + genReturnExpression() + + api_entry = api.withModifiedName("gfxstream_vk_" + api.name[2:]) + if api.name not in HANDWRITTEN_ENTRY_POINTS: + cgen.line(self.cgen.makeFuncProto(api_entry)) + cgen.beginBlock() + genGfxstreamEntry() + cgen.endBlock() + self.module.appendImpl(cgen.swapCode()) - 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_3": - self.cgen.stmt("return nullptr") - elif f == "VK_VERSION_1_2": - 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") - self.cgen.stmt( - "bool has1_3OrHigher = resources->getApiVersionFromInstance(instance) >= VK_API_VERSION_1_3") - - 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_3": - if self.isDeviceDispatch(e): - self.cgen.stmt("return (void*)dynCheck_entry_%s" % e.name) - else: - self.cgen.stmt( \ - "return has1_3OrHigher ? %s : nullptr" % \ - entryPointExpr) - 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") - self.cgen.stmt( - "bool has1_2OrHigher = resources->getApiVersionFromDevice(device) >= VK_API_VERSION_1_2") - self.cgen.stmt( - "bool has1_3OrHigher = resources->getApiVersionFromDevice(device) >= VK_API_VERSION_1_3") - 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_3": - self.cgen.stmt( \ - "return has1_3OrHigher ? %s : nullptr" % \ - entryPointExpr) - elif f == "VK_VERSION_1_2": - self.cgen.stmt( \ - "return has1_2OrHigher ? %s : nullptr" % \ - entryPointExpr) - 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()) + pass def isDeviceDispatch(self, api): # TODO(230793667): improve the heuristic and just use "cmdToFeatureType" diff --git a/src/gfxstream/codegen/scripts/cerealgenerator.py b/src/gfxstream/codegen/scripts/cerealgenerator.py index ad4bf1d6d12..aa957f8724d 100644 --- a/src/gfxstream/codegen/scripts/cerealgenerator.py +++ b/src/gfxstream/codegen/scripts/cerealgenerator.py @@ -334,26 +334,6 @@ class IOStream; #include "VkEncoder.h" #include "../OpenglSystemCommon/HostConnection.h" #include "ResourceTracker.h" - -#include "goldfish_vk_private_defs.h" - -#include -#include - -// Stuff we are not going to use but if included, -// will cause compile errors. These are Android Vulkan -// required extensions, but the approach will be to -// implement them completely on the guest side. -#undef VK_KHR_android_surface -#if defined(LINUX_GUEST_BUILD) || defined(__Fuchsia__) -#undef VK_ANDROID_native_buffer -#endif -""" - - mesaFunctableImplInclude = """ -#include "VkEncoder.h" -#include "../OpenglSystemCommon/HostConnection.h" -#include "ResourceTracker.h" #include "gfxstream_vk_entrypoints.h" #include "gfxstream_vk_private.h" @@ -371,7 +351,6 @@ class IOStream; #undef VK_ANDROID_native_buffer #endif """ - marshalIncludeGuest = """ #include "goldfish_vk_marshaling_guest.h" #include "goldfish_vk_private_defs.h" @@ -614,9 +593,8 @@ class BumpPool; suppressVulkanHeaders=True, extraHeader=createVkExtensionStructureTypePreamble('VK_GOOGLE_GFXSTREAM')) - self.addGuestEncoderModule("func_table", extraImpl=functableImplInclude) - self.addGuestEncoderModule("mesa_func_table", extraImpl=mesaFunctableImplInclude, implOnly = True, - useNamespace = False) + self.addGuestEncoderModule("func_table", extraImpl=functableImplInclude, implOnly = True, + useNamespace = False) self.addWrapper(cereal.VulkanEncoder, "VkEncoder") self.addWrapper(cereal.VulkanExtensionStructs, "goldfish_vk_extension_structs_guest", variant = "guest") @@ -626,7 +604,6 @@ class BumpPool; self.addWrapper(cereal.VulkanCounting, "goldfish_vk_counting_guest") self.addWrapper(cereal.VulkanTransform, "goldfish_vk_transform_guest") self.addWrapper(cereal.VulkanFuncTable, "func_table") - self.addWrapper(cereal.VulkanMesaFuncTable, "mesa_func_table") self.addWrapper(cereal.VulkanGfxstreamStructureType, "vulkan_gfxstream_structure_type_guest") diff --git a/src/gfxstream/guest/vulkan/gfxstream_vk_android.cpp b/src/gfxstream/guest/vulkan/gfxstream_vk_android.cpp index 9a180afbf99..9b07c2bde6e 100644 --- a/src/gfxstream/guest/vulkan/gfxstream_vk_android.cpp +++ b/src/gfxstream/guest/vulkan/gfxstream_vk_android.cpp @@ -4,175 +4,65 @@ */ #include +#include #include #include #include #include +#include -#include "HostConnection.h" -#include "ProcessPipe.h" -#include "ResourceTracker.h" -#include "VkEncoder.h" -#include "func_table.h" +#include "gfxstream_vk_entrypoints.h" +#include "util/macros.h" -namespace { +static int gfxstream_vk_hal_open(const struct hw_module_t* mod, const char* id, + struct hw_device_t** dev); +static int gfxstream_vk_hal_close(struct hw_device_t* dev); -#define VK_HOST_CONNECTION(ret) \ - HostConnection* hostCon = HostConnection::getOrCreate(kCapsetGfxStreamVulkan); \ - gfxstream::vk::VkEncoder* vkEnc = hostCon->vkEncoder(); \ - if (!vkEnc) { \ - ALOGE("vulkan: Failed to get Vulkan encoder\n"); \ - return ret; \ - } +static_assert(HWVULKAN_DISPATCH_MAGIC == ICD_LOADER_MAGIC, ""); -HostConnection* getConnection(void) { - auto hostCon = HostConnection::get(); - return hostCon; -} - -gfxstream::vk::VkEncoder* getVkEncoder(HostConnection* con) { return con->vkEncoder(); } - -gfxstream::vk::ResourceTracker::ThreadingCallbacks threadingCallbacks = { - .hostConnectionGetFunc = getConnection, - .vkEncoderGetFunc = getVkEncoder, +hw_module_methods_t gfxstream_vk_hal_ops = { + .open = gfxstream_vk_hal_open, }; -VkResult SetupInstance(void) { - HostConnection* hostCon = HostConnection::getOrCreate(kCapsetGfxStreamVulkan); - if (!hostCon) { - ALOGE("vulkan: Failed to get host connection\n"); - return VK_ERROR_DEVICE_LOST; - } - - uint32_t noRenderControlEnc = 0; - gfxstream::vk::ResourceTracker::get()->setupCaps(noRenderControlEnc); - // Legacy goldfish path: could be deleted once goldfish not used guest-side. - if (!noRenderControlEnc) { - // Implicitly sets up sequence number - ExtendedRCEncoderContext* rcEnc = hostCon->rcEncoder(); - if (!rcEnc) { - ALOGE("vulkan: Failed to get renderControl encoder context\n"); - return VK_ERROR_DEVICE_LOST; - } - - gfxstream::vk::ResourceTracker::get()->setupFeatures(rcEnc->featureInfo_const()); - } - - gfxstream::vk::ResourceTracker::get()->setThreadingCallbacks(threadingCallbacks); - gfxstream::vk::ResourceTracker::get()->setSeqnoPtr(getSeqnoPtrForProcess()); - gfxstream::vk::VkEncoder* vkEnc = hostCon->vkEncoder(); - if (!vkEnc) { - ALOGE("vulkan: Failed to get Vulkan encoder\n"); - return VK_ERROR_DEVICE_LOST; - } - - return VK_SUCCESS; -} - -VKAPI_ATTR -VkResult EnumerateInstanceExtensionProperties(const char* layer_name, uint32_t* count, - VkExtensionProperties* properties) { - VkResult res = SetupInstance(); - if (res != VK_SUCCESS) { - return res; - } - - VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST) - - res = gfxstream::vk::ResourceTracker::get()->on_vkEnumerateInstanceExtensionProperties( - vkEnc, VK_SUCCESS, layer_name, count, properties); - - return res; -} - -VKAPI_ATTR -VkResult CreateInstance(const VkInstanceCreateInfo* create_info, - const VkAllocationCallbacks* allocator, VkInstance* out_instance) { - VkResult res = SetupInstance(); - if (res != VK_SUCCESS) { - return res; - } - - VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST) - res = vkEnc->vkCreateInstance(create_info, nullptr, out_instance, true /* do lock */); - - return res; -} - -PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* name) { - VK_HOST_CONNECTION(nullptr) - - if (!strcmp(name, "vkGetDeviceProcAddr")) { - return (PFN_vkVoidFunction)(GetDeviceProcAddr); - } - return ( - PFN_vkVoidFunction)(gfxstream::vk::goldfish_vulkan_get_device_proc_address(device, name)); -} - -VKAPI_ATTR -PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* name) { - VkResult res = SetupInstance(); - if (res != VK_SUCCESS) { - return nullptr; - } - - VK_HOST_CONNECTION(nullptr) - - if (!strcmp(name, "vkEnumerateInstanceExtensionProperties")) { - return (PFN_vkVoidFunction)EnumerateInstanceExtensionProperties; - } - if (!strcmp(name, "vkCreateInstance")) { - return (PFN_vkVoidFunction)CreateInstance; - } - if (!strcmp(name, "vkGetDeviceProcAddr")) { - return (PFN_vkVoidFunction)(GetDeviceProcAddr); - } - return (PFN_vkVoidFunction)(gfxstream::vk::goldfish_vulkan_get_instance_proc_address(instance, - name)); -} - -} // namespace - -int OpenDevice(const hw_module_t* /*module*/, const char* id, hw_device_t** device); -int CloseDevice(struct hw_device_t* /*device*/); - -hw_module_methods_t gfxstream_vulkan_module_methods = { - .open = OpenDevice, -}; - -__attribute__((visibility("default"))) hwvulkan_module_t HAL_MODULE_INFO_SYM = { +PUBLIC struct hwvulkan_module_t HAL_MODULE_INFO_SYM = { .common = { .tag = HARDWARE_MODULE_TAG, .module_api_version = HWVULKAN_MODULE_API_VERSION_0_1, - .hal_api_version = HARDWARE_HAL_API_VERSION, + .hal_api_version = HARDWARE_MAKE_API_VERSION(1, 0), .id = HWVULKAN_HARDWARE_MODULE_ID, - .name = "Gfxstream Vulkan Driver", - .author = "The Android Open Source Project", - .methods = &gfxstream_vulkan_module_methods, + .name = "gfxstream Vulkan HAL", + .author = "Android Open Source Project", + .methods = &(gfxstream_vk_hal_ops), }, }; -hwvulkan_device_t gfxstream_vulkan_device = { - .common = - { - .tag = HARDWARE_DEVICE_TAG, - .version = HWVULKAN_DEVICE_API_VERSION_0_1, - .module = &HAL_MODULE_INFO_SYM.common, - .close = CloseDevice, - }, - .EnumerateInstanceExtensionProperties = EnumerateInstanceExtensionProperties, - .CreateInstance = CreateInstance, - .GetInstanceProcAddr = GetInstanceProcAddr, -}; +static int gfxstream_vk_hal_open(const struct hw_module_t* mod, const char* id, + struct hw_device_t** dev) { + assert(mod == &HAL_MODULE_INFO_SYM.common); + assert(strcmp(id, HWVULKAN_DEVICE_0) == 0); -int OpenDevice(const hw_module_t* /*module*/, const char* id, hw_device_t** device) { - if (strcmp(id, HWVULKAN_DEVICE_0) == 0) { - *device = &gfxstream_vulkan_device.common; - gfxstream::vk::ResourceTracker::get(); - return 0; - } - return -ENOENT; + hwvulkan_device_t* hal_dev = (hwvulkan_device_t*)calloc(1, sizeof(*hal_dev)); + if (!hal_dev) return -1; + + *hal_dev = (hwvulkan_device_t){ + .common = + { + .tag = HARDWARE_DEVICE_TAG, + .version = HWVULKAN_DEVICE_API_VERSION_0_1, + .module = &HAL_MODULE_INFO_SYM.common, + .close = gfxstream_vk_hal_close, + }, + .EnumerateInstanceExtensionProperties = gfxstream_vk_EnumerateInstanceExtensionProperties, + .CreateInstance = gfxstream_vk_CreateInstance, + .GetInstanceProcAddr = gfxstream_vk_GetInstanceProcAddr, + }; + + *dev = &hal_dev->common; + return 0; } -int CloseDevice(struct hw_device_t* /*device*/) { return 0; } +static int gfxstream_vk_hal_close(struct hw_device_t* dev) { + /* hwvulkan.h claims that hw_device_t::close() is never called. */ + return -1; +}