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 <aruby@blackberry.com>
Acked-by: Yonggang Luo <luoyonggang@gmail.com>
Acked-by: Adam Jackson <ajax@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27246>
This commit is contained in:
Jason Macnak
2024-04-12 16:04:47 +00:00
committed by Marge Bot
parent d6af74d9b0
commit 8ebd422fcd
4 changed files with 422 additions and 506 deletions

View File

@@ -4,6 +4,7 @@ from .encoder import *
from .extensionstructs import * from .extensionstructs import *
from .frontend import * from .frontend import *
from .functable import * from .functable import *
from .mesa_functable import *
from .marshaling import * from .marshaling import *
from .reservedmarshaling import * from .reservedmarshaling import *
from .counting import * from .counting import *

View File

@@ -2,10 +2,6 @@ from .common.codegen import CodeGen, VulkanWrapperGenerator
from .common.vulkantypes import \ from .common.vulkantypes import \
VulkanAPI, makeVulkanTypeSimple, iterateVulkanType VulkanAPI, makeVulkanTypeSimple, iterateVulkanType
from .common.vulkantypes import EXCLUDED_APIS from .common.vulkantypes import EXCLUDED_APIS
from .common.vulkantypes import HANDLE_TYPES
import copy
import re
RESOURCE_TRACKER_ENTRIES = [ RESOURCE_TRACKER_ENTRIES = [
"vkEnumerateInstanceExtensionProperties", "vkEnumerateInstanceExtensionProperties",
@@ -49,7 +45,6 @@ RESOURCE_TRACKER_ENTRIES = [
"vkCreateSamplerYcbcrConversionKHR", "vkCreateSamplerYcbcrConversionKHR",
"vkDestroySamplerYcbcrConversionKHR", "vkDestroySamplerYcbcrConversionKHR",
"vkUpdateDescriptorSetWithTemplate", "vkUpdateDescriptorSetWithTemplate",
"vkUpdateDescriptorSetWithTemplateKHR",
"vkGetPhysicalDeviceImageFormatProperties2", "vkGetPhysicalDeviceImageFormatProperties2",
"vkGetPhysicalDeviceImageFormatProperties2KHR", "vkGetPhysicalDeviceImageFormatProperties2KHR",
"vkBeginCommandBuffer", "vkBeginCommandBuffer",
@@ -72,6 +67,7 @@ RESOURCE_TRACKER_ENTRIES = [
"vkAllocateDescriptorSets", "vkAllocateDescriptorSets",
"vkFreeDescriptorSets", "vkFreeDescriptorSets",
"vkCreateDescriptorSetLayout", "vkCreateDescriptorSetLayout",
"vkUpdateDescriptorSets",
"vkCmdExecuteCommands", "vkCmdExecuteCommands",
"vkCmdBindDescriptorSets", "vkCmdBindDescriptorSets",
"vkDestroyDescriptorSetLayout", "vkDestroyDescriptorSetLayout",
@@ -95,78 +91,13 @@ SUCCESS_VAL = {
"VkResult" : ["VK_SUCCESS"], "VkResult" : ["VK_SUCCESS"],
} }
HANDWRITTEN_ENTRY_POINTS = [ POSTPROCESSES = {
# Instance/device/physical-device special-handling, dispatch tables, etc.. "vkResetCommandPool" : """if (vkResetCommandPool_VkResult_return == VK_SUCCESS) {
"vkCreateInstance", ResourceTracker::get()->resetCommandPoolStagingInfo(commandPool);
"vkDestroyInstance", }""",
"vkGetInstanceProcAddr", "vkAllocateCommandBuffers" : """if (vkAllocateCommandBuffers_VkResult_return == VK_SUCCESS) {
"vkEnumerateInstanceVersion", ResourceTracker::get()->addToCommandPool(pAllocateInfo->commandPool, pAllocateInfo->commandBufferCount, pCommandBuffers);
"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): def is_cmdbuf_dispatch(api):
@@ -175,59 +106,6 @@ def is_cmdbuf_dispatch(api):
def is_queue_dispatch(api): def is_queue_dispatch(api):
return "VkQueue" == api.parameters[0].typeName 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): class VulkanFuncTable(VulkanWrapperGenerator):
def __init__(self, module, typeInfo): def __init__(self, module, typeInfo):
VulkanWrapperGenerator.__init__(self, module, typeInfo) VulkanWrapperGenerator.__init__(self, module, typeInfo)
@@ -241,6 +119,11 @@ class VulkanFuncTable(VulkanWrapperGenerator):
def onBegin(self,): def onBegin(self,):
cgen = self.cgen 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()) self.module.appendImpl(cgen.swapCode())
pass pass
@@ -261,365 +144,264 @@ class VulkanFuncTable(VulkanWrapperGenerator):
api = typeInfo.apis[name] api = typeInfo.apis[name]
self.entries.append(api) self.entries.append(api)
self.entryFeatures.append(self.feature) self.entryFeatures.append(self.feature)
self.loopVars = ["i", "j", "k", "l", "m", "n"]
self.loopVarIndex = 0
def getNextLoopVar(): def genEncoderOrResourceTrackerCall(cgen, api, declareResources=True):
if self.loopVarIndex >= len(self.loopVars): cgen.stmt("AEMU_SCOPED_TRACE(\"%s\")" % api.name)
raise
loopVar = self.loopVars[self.loopVarIndex]
self.loopVarIndex += 1
return loopVar
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<std::vector<%s>> %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 <type>*' (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): 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): 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: else:
cgen.stmt("auto vkEnc = gfxstream::vk::ResourceTracker::getThreadLocalEncoder()") cgen.stmt("auto vkEnc = ResourceTracker::getThreadLocalEncoder()")
callLhs = None callLhs = None
retTypeName = api.getRetTypeExpr() retTypeName = api.getRetTypeExpr()
if retTypeName != "void": 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 name in RESOURCE_TRACKER_ENTRIES:
if declareResources: if declareResources:
cgen.stmt("auto resources = gfxstream::vk::ResourceTracker::get()") cgen.stmt("auto resources = ResourceTracker::get()")
cgen.funcCall( cgen.funcCall(
callLhs, "resources->" + "on_" + api.name, callLhs, "resources->" + "on_" + api.name,
["vkEnc"] + SUCCESS_VAL.get(retTypeName, []) + \ ["vkEnc"] + SUCCESS_VAL.get(retTypeName, []) + \
[p.paramName for p in parameters]) [p.paramName for p in api.parameters])
else: else:
cgen.funcCall( 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(): if name in POSTPROCESSES:
retTypeName = api.getRetTypeExpr() cgen.line(POSTPROCESSES[name])
# 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": 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:]) api_entry = api.withModifiedName("entry_" + api.name)
if api.name not in HANDWRITTEN_ENTRY_POINTS:
cgen.line(self.cgen.makeFuncProto(api_entry)) 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() 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() cgen.endBlock()
self.module.appendImpl(cgen.swapCode())
self.module.appendImpl(cgen.swapCode())
def onEnd(self,): 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): def isDeviceDispatch(self, api):
# TODO(230793667): improve the heuristic and just use "cmdToFeatureType" # TODO(230793667): improve the heuristic and just use "cmdToFeatureType"

View File

@@ -334,6 +334,26 @@ class IOStream;
#include "VkEncoder.h" #include "VkEncoder.h"
#include "../OpenglSystemCommon/HostConnection.h" #include "../OpenglSystemCommon/HostConnection.h"
#include "ResourceTracker.h" #include "ResourceTracker.h"
#include "goldfish_vk_private_defs.h"
#include <log/log.h>
#include <cstring>
// 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_entrypoints.h"
#include "gfxstream_vk_private.h" #include "gfxstream_vk_private.h"
@@ -351,6 +371,7 @@ class IOStream;
#undef VK_ANDROID_native_buffer #undef VK_ANDROID_native_buffer
#endif #endif
""" """
marshalIncludeGuest = """ marshalIncludeGuest = """
#include "goldfish_vk_marshaling_guest.h" #include "goldfish_vk_marshaling_guest.h"
#include "goldfish_vk_private_defs.h" #include "goldfish_vk_private_defs.h"
@@ -593,8 +614,9 @@ class BumpPool;
suppressVulkanHeaders=True, suppressVulkanHeaders=True,
extraHeader=createVkExtensionStructureTypePreamble('VK_GOOGLE_GFXSTREAM')) extraHeader=createVkExtensionStructureTypePreamble('VK_GOOGLE_GFXSTREAM'))
self.addGuestEncoderModule("func_table", extraImpl=functableImplInclude, implOnly = True, self.addGuestEncoderModule("func_table", extraImpl=functableImplInclude)
useNamespace = False) self.addGuestEncoderModule("mesa_func_table", extraImpl=mesaFunctableImplInclude, implOnly = True,
useNamespace = False)
self.addWrapper(cereal.VulkanEncoder, "VkEncoder") self.addWrapper(cereal.VulkanEncoder, "VkEncoder")
self.addWrapper(cereal.VulkanExtensionStructs, "goldfish_vk_extension_structs_guest", variant = "guest") 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.VulkanCounting, "goldfish_vk_counting_guest")
self.addWrapper(cereal.VulkanTransform, "goldfish_vk_transform_guest") self.addWrapper(cereal.VulkanTransform, "goldfish_vk_transform_guest")
self.addWrapper(cereal.VulkanFuncTable, "func_table") self.addWrapper(cereal.VulkanFuncTable, "func_table")
self.addWrapper(cereal.VulkanMesaFuncTable, "mesa_func_table")
self.addWrapper(cereal.VulkanGfxstreamStructureType, self.addWrapper(cereal.VulkanGfxstreamStructureType,
"vulkan_gfxstream_structure_type_guest") "vulkan_gfxstream_structure_type_guest")

View File

@@ -4,65 +4,175 @@
*/ */
#include <errno.h> #include <errno.h>
#include <hardware/hardware.h>
#include <hardware/hwvulkan.h> #include <hardware/hwvulkan.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <vulkan/vk_icd.h>
#include "gfxstream_vk_entrypoints.h" #include "HostConnection.h"
#include "util/macros.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, namespace {
struct hw_device_t** dev);
static int gfxstream_vk_hal_close(struct hw_device_t* dev);
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 = { HostConnection* getConnection(void) {
.open = gfxstream_vk_hal_open, 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 = .common =
{ {
.tag = HARDWARE_MODULE_TAG, .tag = HARDWARE_MODULE_TAG,
.module_api_version = HWVULKAN_MODULE_API_VERSION_0_1, .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, .id = HWVULKAN_HARDWARE_MODULE_ID,
.name = "gfxstream Vulkan HAL", .name = "Gfxstream Vulkan Driver",
.author = "Android Open Source Project", .author = "The Android Open Source Project",
.methods = &(gfxstream_vk_hal_ops), .methods = &gfxstream_vulkan_module_methods,
}, },
}; };
static int gfxstream_vk_hal_open(const struct hw_module_t* mod, const char* id, hwvulkan_device_t gfxstream_vulkan_device = {
struct hw_device_t** dev) { .common =
assert(mod == &HAL_MODULE_INFO_SYM.common); {
assert(strcmp(id, HWVULKAN_DEVICE_0) == 0); .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)); int OpenDevice(const hw_module_t* /*module*/, const char* id, hw_device_t** device) {
if (!hal_dev) return -1; if (strcmp(id, HWVULKAN_DEVICE_0) == 0) {
*device = &gfxstream_vulkan_device.common;
*hal_dev = (hwvulkan_device_t){ gfxstream::vk::ResourceTracker::get();
.common = return 0;
{ }
.tag = HARDWARE_DEVICE_TAG, return -ENOENT;
.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;
} }
static int gfxstream_vk_hal_close(struct hw_device_t* dev) { int CloseDevice(struct hw_device_t* /*device*/) { return 0; }
/* hwvulkan.h claims that hw_device_t::close() is never called. */
return -1;
}