From 8ebd422fcd78eb69044a9d01c3a3c3d6bfa21967 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Fri, 12 Apr 2024 16:04:47 +0000 Subject: [PATCH] Reland "Partial revert of aosp/2858589 to avoid Mesa layer for Android" This reverts commit 9eef6d0aefcf0aa1c07d42d9b307b1092a6deec9. ... as this does not yet have a way to generically convert Mesa handles into Gfxstream handles in extension structs which causes breakage in dEQP VK for many tests. Moves the mesa based codegen to a separate `mesa_func_table`. Reland fixes the end2end test guest vulkan ICD. cts -m CtsDeqpTestCases --module-arg CtsDeqpTestCases:include-filter:dEQP-VK.* Reviewed-by: Aaron Ruby Acked-by: Yonggang Luo Acked-by: Adam Jackson Part-of: --- .../codegen/scripts/cereal/__init__.py | 1 + .../codegen/scripts/cereal/functable.py | 708 ++++++------------ .../codegen/scripts/cerealgenerator.py | 27 +- .../guest/vulkan/gfxstream_vk_android.cpp | 192 ++++- 4 files changed, 422 insertions(+), 506 deletions(-) diff --git a/src/gfxstream/codegen/scripts/cereal/__init__.py b/src/gfxstream/codegen/scripts/cereal/__init__.py index 1966572ffc4..809a1776964 100644 --- a/src/gfxstream/codegen/scripts/cereal/__init__.py +++ b/src/gfxstream/codegen/scripts/cereal/__init__.py @@ -4,6 +4,7 @@ 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 2d3415059eb..016d6cac67a 100644 --- a/src/gfxstream/codegen/scripts/cereal/functable.py +++ b/src/gfxstream/codegen/scripts/cereal/functable.py @@ -2,10 +2,6 @@ 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", @@ -49,7 +45,6 @@ RESOURCE_TRACKER_ENTRIES = [ "vkCreateSamplerYcbcrConversionKHR", "vkDestroySamplerYcbcrConversionKHR", "vkUpdateDescriptorSetWithTemplate", - "vkUpdateDescriptorSetWithTemplateKHR", "vkGetPhysicalDeviceImageFormatProperties2", "vkGetPhysicalDeviceImageFormatProperties2KHR", "vkBeginCommandBuffer", @@ -72,6 +67,7 @@ RESOURCE_TRACKER_ENTRIES = [ "vkAllocateDescriptorSets", "vkFreeDescriptorSets", "vkCreateDescriptorSetLayout", + "vkUpdateDescriptorSets", "vkCmdExecuteCommands", "vkCmdBindDescriptorSets", "vkDestroyDescriptorSetLayout", @@ -95,78 +91,13 @@ SUCCESS_VAL = { "VkResult" : ["VK_SUCCESS"], } -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", +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): @@ -175,59 +106,6 @@ 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) @@ -241,6 +119,11 @@ 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 @@ -261,365 +144,264 @@ 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 getNextLoopVar(): - if self.loopVarIndex >= len(self.loopVars): - raise - loopVar = self.loopVars[self.loopVarIndex] - self.loopVarIndex += 1 - return loopVar + def genEncoderOrResourceTrackerCall(cgen, api, declareResources=True): + cgen.stmt("AEMU_SCOPED_TRACE(\"%s\")" % api.name) - 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: - 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)) + cgen.stmt("auto vkEnc = ResourceTracker::getCommandBufferEncoder(commandBuffer)") elif is_queue_dispatch(api): - cgen.stmt("auto vkEnc = gfxstream::vk::ResourceTracker::getQueueEncoder(%s->%s)" % (paramNameToObjectName(api.parameters[0].paramName), INTERNAL_OBJECT_NAME)) + cgen.stmt("auto vkEnc = ResourceTracker::getQueueEncoder(queue)") else: - cgen.stmt("auto vkEnc = gfxstream::vk::ResourceTracker::getThreadLocalEncoder()") + cgen.stmt("auto vkEnc = ResourceTracker::getThreadLocalEncoder()") callLhs = None retTypeName = api.getRetTypeExpr() if retTypeName != "void": - callLhs = api.getRetVarExpr() + retVar = api.getRetVarExpr() + cgen.stmt("%s %s = (%s)0" % (retTypeName, retVar, retTypeName)) + callLhs = retVar - # Get parameter list modded for gfxstream-internal call - parameters = getEncoderOrResourceTrackerParams() if name in RESOURCE_TRACKER_ENTRIES: if declareResources: - cgen.stmt("auto resources = gfxstream::vk::ResourceTracker::get()") + cgen.stmt("auto resources = ResourceTracker::get()") cgen.funcCall( callLhs, "resources->" + "on_" + api.name, ["vkEnc"] + SUCCESS_VAL.get(retTypeName, []) + \ - [p.paramName for p in parameters]) + [p.paramName for p in api.parameters]) else: cgen.funcCall( - callLhs, "vkEnc->" + api.name, [p.paramName for p in parameters] + ["true /* do lock */"]) + callLhs, "vkEnc->" + api.name, [p.paramName for p in api.parameters] + ["true /* do lock */"]) - 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 name in POSTPROCESSES: + cgen.line(POSTPROCESSES[name]) if retTypeName != "void": - cgen.stmt("return %s" % api.getRetVarExpr()) + cgen.stmt("return %s" % retVar) - 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: - 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)) + 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() - genGfxstreamEntry() + 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)) + 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()) + self.module.appendImpl(cgen.swapCode()) def onEnd(self,): - pass + 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()) 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 aa957f8724d..ad4bf1d6d12 100644 --- a/src/gfxstream/codegen/scripts/cerealgenerator.py +++ b/src/gfxstream/codegen/scripts/cerealgenerator.py @@ -334,6 +334,26 @@ 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" @@ -351,6 +371,7 @@ class IOStream; #undef VK_ANDROID_native_buffer #endif """ + marshalIncludeGuest = """ #include "goldfish_vk_marshaling_guest.h" #include "goldfish_vk_private_defs.h" @@ -593,8 +614,9 @@ class BumpPool; suppressVulkanHeaders=True, extraHeader=createVkExtensionStructureTypePreamble('VK_GOOGLE_GFXSTREAM')) - self.addGuestEncoderModule("func_table", extraImpl=functableImplInclude, implOnly = True, - useNamespace = False) + self.addGuestEncoderModule("func_table", extraImpl=functableImplInclude) + self.addGuestEncoderModule("mesa_func_table", extraImpl=mesaFunctableImplInclude, implOnly = True, + useNamespace = False) self.addWrapper(cereal.VulkanEncoder, "VkEncoder") self.addWrapper(cereal.VulkanExtensionStructs, "goldfish_vk_extension_structs_guest", variant = "guest") @@ -604,6 +626,7 @@ 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 9b07c2bde6e..9a180afbf99 100644 --- a/src/gfxstream/guest/vulkan/gfxstream_vk_android.cpp +++ b/src/gfxstream/guest/vulkan/gfxstream_vk_android.cpp @@ -4,65 +4,175 @@ */ #include -#include #include #include #include #include -#include -#include "gfxstream_vk_entrypoints.h" -#include "util/macros.h" +#include "HostConnection.h" +#include "ProcessPipe.h" +#include "ResourceTracker.h" +#include "VkEncoder.h" +#include "func_table.h" -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); +namespace { -static_assert(HWVULKAN_DISPATCH_MAGIC == ICD_LOADER_MAGIC, ""); +#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; \ + } -hw_module_methods_t gfxstream_vk_hal_ops = { - .open = gfxstream_vk_hal_open, +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, }; -PUBLIC struct hwvulkan_module_t HAL_MODULE_INFO_SYM = { +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 = { .common = { .tag = HARDWARE_MODULE_TAG, .module_api_version = HWVULKAN_MODULE_API_VERSION_0_1, - .hal_api_version = HARDWARE_MAKE_API_VERSION(1, 0), + .hal_api_version = HARDWARE_HAL_API_VERSION, .id = HWVULKAN_HARDWARE_MODULE_ID, - .name = "gfxstream Vulkan HAL", - .author = "Android Open Source Project", - .methods = &(gfxstream_vk_hal_ops), + .name = "Gfxstream Vulkan Driver", + .author = "The Android Open Source Project", + .methods = &gfxstream_vulkan_module_methods, }, }; -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); +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, +}; - 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 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; } -static int gfxstream_vk_hal_close(struct hw_device_t* dev) { - /* hwvulkan.h claims that hw_device_t::close() is never called. */ - return -1; -} +int CloseDevice(struct hw_device_t* /*device*/) { return 0; }