summaryrefslogtreecommitdiff
path: root/codegen/vulkan/scripts/cereal/dispatch.py
diff options
context:
space:
mode:
Diffstat (limited to 'codegen/vulkan/scripts/cereal/dispatch.py')
-rw-r--r--codegen/vulkan/scripts/cereal/dispatch.py499
1 files changed, 499 insertions, 0 deletions
diff --git a/codegen/vulkan/scripts/cereal/dispatch.py b/codegen/vulkan/scripts/cereal/dispatch.py
new file mode 100644
index 00000000..42cba8ca
--- /dev/null
+++ b/codegen/vulkan/scripts/cereal/dispatch.py
@@ -0,0 +1,499 @@
+# Copyright (c) 2018 The Android Open Source Project
+# Copyright (c) 2018 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from .common.codegen import CodeGen
+from .common.vulkantypes import \
+ VulkanAPI, makeVulkanTypeSimple, iterateVulkanType
+
+from .wrapperdefs import VulkanWrapperGenerator
+
+# No real good way to automatically infer the most important Vulkan API
+# functions as it relates to which getProcAddress function to use, plus
+# we might want to control which function to use depending on our
+# performance needs.
+
+# This is based on the minimum set of functions needed to be directly
+# queried with dlsym and not returning null.
+getProcAddrFuncs = [
+ "vkGetInstanceProcAddr",
+ "vkDestroyInstance",
+ "vkEnumeratePhysicalDevices",
+ "vkGetPhysicalDeviceFeatures",
+ "vkGetPhysicalDeviceFormatProperties",
+ "vkGetPhysicalDeviceImageFormatProperties",
+ "vkGetPhysicalDeviceProperties",
+ "vkGetPhysicalDeviceQueueFamilyProperties",
+ "vkGetPhysicalDeviceMemoryProperties",
+ "vkCreateDevice",
+ "vkDestroyDevice",
+ "vkEnumerateDeviceExtensionProperties",
+ "vkEnumerateDeviceLayerProperties",
+]
+
+# Some methods can only be found using dlsym() while we cannot get the function
+# address using vkGetInstProcAddr() or vkGetDeviceProcAddr(). These function
+# pointers should only be initialized when setting up the dispatch from system
+# loader.
+getProcAddrOnlyFuncs = [
+ "vkGetMTLDeviceMVK",
+ "vkSetMTLTextureMVK",
+ "vkGetMTLTextureMVK",
+ "vkGetMTLBufferMVK",
+ "vkUseIOSurfaceMVK",
+ "vkGetIOSurfaceMVK",
+]
+
+getInstanceProcAddrNoInstanceFuncs = [
+ "vkCreateInstance",
+ "vkEnumerateInstanceExtensionProperties",
+ "vkEnumerateInstanceLayerProperties",
+]
+
+getInstanceProcAddrFuncs = [
+ "vkGetDeviceProcAddr",
+ "vkCreateSwapchainKHR",
+ "vkDestroySwapchainKHR",
+ "vkGetSwapchainImagesKHR",
+ "vkAcquireNextImageKHR",
+ "vkQueuePresentKHR",
+ "vkCreateMacOSSurfaceMVK",
+ "vkCreateWin32SurfaceKHR",
+ "vkGetPhysicalDeviceWin32PresentationSupportKHR",
+ "vkCreateXlibSurfaceKHR",
+ "vkGetPhysicalDeviceXlibPresentationSupportKHR",
+ "vkCreateXcbSurfaceKHR",
+ "vkGetPhysicalDeviceXcbPresentationSupportKHR",
+ "vkGetPhysicalDeviceSparseImageFormatProperties",
+ "vkEnumerateInstanceVersion",
+ "vkEnumeratePhysicalDeviceGroups",
+ "vkGetPhysicalDeviceFeatures2",
+ "vkGetPhysicalDeviceProperties2",
+ "vkGetPhysicalDeviceFormatProperties2",
+ "vkGetPhysicalDeviceImageFormatProperties2",
+ "vkGetPhysicalDeviceQueueFamilyProperties2",
+ "vkGetPhysicalDeviceMemoryProperties2",
+ "vkGetPhysicalDeviceSparseImageFormatProperties2",
+ "vkGetPhysicalDeviceExternalBufferProperties",
+ "vkGetPhysicalDeviceExternalFenceProperties",
+ "vkGetPhysicalDeviceExternalSemaphoreProperties",
+]
+
+# Implicitly, everything else is going to be obtained
+# with vkGetDeviceProcAddr,
+# unless it has instance in the arg.
+
+def isGetProcAddressAPI(vulkanApi):
+ return vulkanApi.name in getProcAddrFuncs
+
+def isGetProcAddressOnlyAPI(vulkanApi):
+ return vulkanApi.name in getProcAddrOnlyFuncs
+
+def isGetInstanceProcAddressNoInstanceAPI(vulkanApi):
+ return vulkanApi.name in getInstanceProcAddrNoInstanceFuncs
+
+def isGetInstanceProcAddressAPI(vulkanApi):
+ if vulkanApi.name in getInstanceProcAddrFuncs:
+ return True
+
+ if vulkanApi.parameters[0].typeName == "VkInstance":
+ return True
+
+ return False
+
+def isGetDeviceProcAddressAPI(vulkanApi):
+ if isGetProcAddressAPI(vulkanApi):
+ return False
+
+ if isGetProcAddressOnlyAPI(vulkanApi):
+ return False
+
+ if isGetInstanceProcAddressAPI(vulkanApi):
+ return False
+
+ return True
+
+def inferProcAddressFuncType(vulkanApi):
+ if isGetProcAddressAPI(vulkanApi):
+ return "global"
+ if isGetProcAddressOnlyAPI(vulkanApi):
+ return "global-only"
+ if isGetInstanceProcAddressNoInstanceAPI(vulkanApi):
+ return "global-instance"
+ if isGetInstanceProcAddressAPI(vulkanApi):
+ return "instance"
+ return "device"
+
+# VulkanDispatch defines a struct, VulkanDispatch,
+# that is populated by function pointers from the Vulkan
+# loader. No attempt is made to do something different
+# for instance vs device functions.
+class VulkanDispatch(VulkanWrapperGenerator):
+ def __init__(self, module, typeInfo):
+ VulkanWrapperGenerator.__init__(self, module, typeInfo)
+
+ self.apisToGet = {}
+
+ self.cgenHeader = CodeGen()
+ self.cgenImpl = CodeGen()
+ self.typeInfo = typeInfo
+
+ self.currentFeature = ""
+ self.featureForCodegen = ""
+
+ def onBegin(self):
+
+ # The first way is to use just the loader to get symbols. This doesn't
+ # necessarily work with extensions because at that point the dispatch
+ # table needs to be specific to a particular Vulkan instance or device.
+
+ self.cgenHeader.line("""
+void init_vulkan_dispatch_from_system_loader(
+ DlOpenFunc dlOpenFunc,
+ DlSymFunc dlSymFunc,
+ VulkanDispatch* dispatch_out);
+""")
+
+ # The second way is to initialize the table from a given Vulkan
+ # instance or device. Provided the instance or device was created with
+ # the right extensions, we can obtain function pointers to extension
+ # functions this way.
+
+ self.cgenHeader.line("""
+void init_vulkan_dispatch_from_instance(
+ VulkanDispatch* vk,
+ VkInstance instance,
+ VulkanDispatch* dispatch_out);
+""")
+ self.cgenHeader.line("""
+void init_vulkan_dispatch_from_device(
+ VulkanDispatch* vk,
+ VkDevice device,
+ VulkanDispatch* dispatch_out);
+""")
+
+ # After populating a VulkanDispatch with the above methods,
+ # it can be useful to check whether the Vulkan 1.0 or 1.1 methods
+ # are all there.
+ def emit_feature_check_decl(cgen, tag, featureToCheck):
+ cgen.line("""
+bool vulkan_dispatch_check_%s_%s(
+ const VulkanDispatch* vk);
+""" % (tag, featureToCheck))
+
+ emit_feature_check_decl(self.cgenHeader, "instance", "VK_VERSION_1_0")
+ emit_feature_check_decl(self.cgenHeader, "instance", "VK_VERSION_1_1")
+ emit_feature_check_decl(self.cgenHeader, "device", "VK_VERSION_1_0")
+ emit_feature_check_decl(self.cgenHeader, "device", "VK_VERSION_1_1")
+
+ self.cgenHeader.line("struct VulkanDispatch {")
+ self.module.appendHeader(self.cgenHeader.swapCode())
+
+ def syncFeatureQuiet(self, cgen, feature):
+ if self.featureForCodegen != feature:
+ if feature == "":
+ self.featureForCodegen = feature
+ return
+
+ self.featureForCodegen = feature
+
+ def syncFeature(self, cgen, feature):
+ if self.featureForCodegen != feature:
+ if feature == "":
+ cgen.leftline("#endif")
+ self.featureForCodegen = feature
+ return
+
+ if self.featureForCodegen != "":
+ cgen.leftline("#endif")
+
+ cgen.leftline("#ifdef %s" % feature)
+ self.featureForCodegen = feature
+
+ def makeDlsymCall(self, cgen, apiname, typedecl):
+ cgen.stmt( \
+ "out->%s = (%s)dlSymFunc(lib, \"%s\")" % \
+ (apiname, typedecl, apiname))
+
+ def makeGetInstanceProcAddrCall(self, cgen, dispatch, instance, apiname, typedecl):
+ cgen.stmt( \
+ "out->%s = (%s)%s->vkGetInstanceProcAddr(%s, \"%s\")" % \
+ (apiname, typedecl, dispatch, instance, apiname))
+
+ def makeGetDeviceProcAddrCall(self, cgen, dispatch, device, apiname, typedecl):
+ cgen.stmt( \
+ "out->%s = (%s)%s->vkGetDeviceProcAddr(%s, \"%s\")" % \
+ (apiname, typedecl, dispatch, device, apiname))
+
+ def onEnd(self):
+ self.cgenHeader.line("};")
+ self.module.appendHeader(self.cgenHeader.swapCode())
+
+ # Getting dispatch tables from the loader
+ self.cgenImpl.line("""
+void init_vulkan_dispatch_from_system_loader(
+ DlOpenFunc dlOpenFunc,
+ DlSymFunc dlSymFunc,
+ VulkanDispatch* out)""")
+
+ self.cgenImpl.beginBlock()
+
+ self.cgenImpl.stmt("memset(out, 0x0, sizeof(VulkanDispatch))")
+
+ self.cgenImpl.stmt("void* lib = dlOpenFunc()")
+ self.cgenImpl.stmt("if (!lib) return")
+
+ apis = \
+ self.apisToGet["global"] + \
+ self.apisToGet["global-instance"] + \
+ self.apisToGet["instance"] + \
+ self.apisToGet["device"] + \
+ self.apisToGet["global-only"]
+
+ for vulkanApi, typeDecl, feature in apis:
+ self.syncFeature(self.cgenImpl, feature)
+ self.makeDlsymCall(self.cgenImpl, vulkanApi.name, typeDecl)
+
+ self.syncFeature(self.cgenImpl, "")
+ self.cgenImpl.endBlock()
+
+ # Getting instance dispatch tables
+ self.cgenImpl.line("""
+void init_vulkan_dispatch_from_instance(
+ VulkanDispatch* vk,
+ VkInstance instance,
+ VulkanDispatch* out)""")
+
+ self.cgenImpl.beginBlock()
+
+ self.cgenImpl.stmt("memset(out, 0x0, sizeof(VulkanDispatch))")
+
+ apis = \
+ self.apisToGet["global"] + \
+ self.apisToGet["global-instance"] + \
+ self.apisToGet["instance"] + \
+ self.apisToGet["device"]
+
+ for vulkanApi, typeDecl, feature in apis:
+ self.syncFeature(self.cgenImpl, feature)
+ self.makeGetInstanceProcAddrCall(
+ self.cgenImpl, "vk", "instance", vulkanApi.name, typeDecl)
+
+ self.syncFeature(self.cgenImpl, "")
+ self.cgenImpl.endBlock()
+
+ # Getting device dispatch tables
+ self.cgenImpl.line("""
+void init_vulkan_dispatch_from_device(
+ VulkanDispatch* vk,
+ VkDevice device,
+ VulkanDispatch* out)""")
+
+ self.cgenImpl.beginBlock()
+
+ self.cgenImpl.stmt("memset(out, 0x0, sizeof(VulkanDispatch))")
+
+ apis = \
+ self.apisToGet["global"] + \
+ self.apisToGet["global-instance"] + \
+ self.apisToGet["instance"] + \
+ self.apisToGet["device"]
+
+ for vulkanApi, typeDecl, feature in apis:
+ self.syncFeature(self.cgenImpl, feature)
+ self.makeGetDeviceProcAddrCall(
+ self.cgenImpl, "vk", "device", vulkanApi.name, typeDecl)
+
+ self.syncFeature(self.cgenImpl, "")
+ self.cgenImpl.endBlock()
+
+ # Check Vulkan 1.0 / 1.1 functions
+
+ def emit_check_impl(cgen, dispatchVar, feature, featureToCheck, apiName):
+ if feature == featureToCheck:
+ cgen.beginIf("!%s->%s" % (dispatchVar, apiName))
+ cgen.stmt("fprintf(stderr, \"%s check failed: %s not found\\n\")" % (featureToCheck, apiName))
+ cgen.stmt("good = false")
+ cgen.endIf()
+
+ def emit_feature_check_impl(context, cgen, tag, featureToCheck, apis):
+ cgen.line("""
+bool vulkan_dispatch_check_%s_%s(
+ const VulkanDispatch* vk)
+""" % (tag, featureToCheck))
+
+ cgen.beginBlock()
+
+ cgen.stmt("bool good = true")
+
+ for vulkanApi, typeDecl, feature in apis:
+ context.syncFeatureQuiet(self.cgenImpl, feature)
+ emit_check_impl(cgen, "vk", feature, featureToCheck, vulkanApi.name)
+
+ context.syncFeatureQuiet(self.cgenImpl, "")
+
+ cgen.stmt("return good")
+ cgen.endBlock()
+
+ instanceApis = self.apisToGet["global-instance"] + self.apisToGet["instance"]
+
+ emit_feature_check_impl(self, self.cgenImpl, "instance", "VK_VERSION_1_0", instanceApis)
+ emit_feature_check_impl(self, self.cgenImpl, "instance", "VK_VERSION_1_1", instanceApis)
+ emit_feature_check_impl(self, self.cgenImpl, "device", "VK_VERSION_1_0", self.apisToGet["device"])
+ emit_feature_check_impl(self, self.cgenImpl, "device", "VK_VERSION_1_1", self.apisToGet["device"])
+
+ self.module.appendImpl(self.cgenImpl.swapCode())
+
+ def onBeginFeature(self, featureName, featureType):
+ self.currentFeature = featureName
+
+ def onGenType(self, typeXml, name, alias):
+ VulkanWrapperGenerator.onGenType(self, typeXml, name, alias)
+
+ def onGenCmd(self, cmdinfo, name, alias):
+ VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
+
+ vulkanApi = self.typeInfo.apis[name]
+
+ typeDecl = "PFN_%s" % name
+
+ procAddressType = inferProcAddressFuncType(vulkanApi)
+
+ self.cgenHeader.stmt("%s %s" % (typeDecl, name));
+ self.module.appendHeader(self.cgenHeader.swapCode())
+
+ current = self.apisToGet.get(procAddressType, [])
+ if current == []:
+ self.apisToGet[procAddressType] = current
+ current.append((vulkanApi, typeDecl, self.currentFeature))
+
+# VulkanDispatchFast allows one to get the optimal function pointers
+# for a given Vulkan API call, in order to improve performance.
+#
+# We can optionally query VkDevices to get function pointers that are
+# closer to the ICD and have fewer levels of indirection from the loader
+# to get there.
+# See
+# https://github.com/KhronosGroup/Vulkan-Loader/blob/master/loader/LoaderAndLayerInterface.md
+# for more info.
+#
+# This requires the calling C++ code to provide functions to
+# generate the desired instances and devices, otherwise we won't know
+# which instance or device to pass to vkGet(Instance|Device)ProcAddr,
+# so it does push more complexity to the user.
+class VulkanDispatchFast(VulkanDispatch):
+
+ def __init__(self, module, typeInfo):
+ VulkanDispatch.__init__(self, module, typeInfo)
+
+ def onBegin(self):
+ self.cgenHeader.line("""
+void init_vulkan_dispatch_from_system_loader(
+ DlOpenFunc dlOpenFunc,
+ DlSymFunc dlSymFunc,
+ InstanceGetter instanceGetter,
+ DeviceGetter deviceGetter,
+ VulkanDispatch* dispatch_out);
+""")
+
+ self.cgenHeader.line("struct VulkanDispatch {")
+ self.cgenHeader.line("VkInstance instance;")
+ self.cgenHeader.line("VkPhysicalDevice physicalDevice;")
+ self.cgenHeader.line("uint32_t physicalDeviceQueueFamilyInfoCount;")
+ self.cgenHeader.line("VkQueueFamilyProperties* physicalDeviceQueueFamilyInfos;")
+ self.cgenHeader.line("VkDevice device;")
+ self.cgenHeader.line("bool presentCapable;")
+ self.module.appendHeader(self.cgenHeader.swapCode())
+
+ def makeGetProcAddr(self, cgen, dispatchLevel, dispatch, apiname, typedecl):
+ if dispatchLevel == "instance":
+ funcname = "vkGetInstanceProcAddr"
+ elif dispatchLevel == "device":
+ funcname = "vkGetDeviceProcAddr"
+ else:
+ raise
+
+ cgen.stmt( \
+ "out->%s = (%s)out->%s(%s, \"%s\")" % \
+ (apiname, typedecl, funcname, dispatch, apiname))
+
+ def onEnd(self):
+ self.cgenHeader.line("};")
+ self.module.appendHeader(self.cgenHeader.swapCode())
+
+ self.cgenImpl.line("""
+void init_vulkan_dispatch_from_system_loader(
+ DlOpenFunc dlOpenFunc,
+ DlSymFunc dlSymFunc,
+ InstanceGetter instanceGetter,
+ DeviceGetter deviceGetter,
+ VulkanDispatch* out)""")
+
+ self.cgenImpl.beginBlock()
+
+ self.cgenImpl.stmt("out->instance = nullptr")
+ self.cgenImpl.stmt("out->physicalDevice = nullptr")
+ self.cgenImpl.stmt("out->physicalDeviceQueueFamilyInfoCount = 0")
+ self.cgenImpl.stmt("out->physicalDeviceQueueFamilyInfos = nullptr")
+ self.cgenImpl.stmt("out->device = nullptr")
+ self.cgenImpl.stmt("out->presentCapable = false")
+
+ self.cgenImpl.stmt("void* lib = dlOpenFunc()")
+ self.cgenImpl.stmt("if (!lib) return")
+
+ for vulkanApi, typeDecl, feature in self.apisToGet["global"]:
+ self.syncFeature(self.cgenImpl, feature)
+ self.makeDlsymCall(self.cgenImpl, vulkanApi.name, typeDecl)
+
+ self.syncFeature(self.cgenImpl, "")
+ self.cgenImpl.stmt("if (!out->vkGetInstanceProcAddr) return")
+
+ for vulkanApi, typeDecl, feature in self.apisToGet["global-instance"]:
+ self.syncFeature(self.cgenImpl, feature)
+ self.makeGetProcAddr( \
+ self.cgenImpl, "instance", "nullptr", vulkanApi.name, typeDecl);
+
+ self.syncFeature(self.cgenImpl, "")
+ self.cgenImpl.stmt("if (!instanceGetter(out, &out->instance)) return")
+
+ for vulkanApi, typeDecl, feature in self.apisToGet["instance"]:
+ self.syncFeature(self.cgenImpl, feature)
+ self.makeGetProcAddr( \
+ self.cgenImpl, "instance", "out->instance", vulkanApi.name, typeDecl);
+
+ self.syncFeature(self.cgenImpl, "")
+
+ self.cgenImpl.stmt("if (!deviceGetter(out, out->instance, &out->physicalDevice, &out->physicalDeviceQueueFamilyInfoCount, nullptr, &out->device, &out->presentCapable)) return")
+ self.cgenImpl.stmt("out->physicalDeviceQueueFamilyInfos = (VkQueueFamilyProperties*)malloc(out->physicalDeviceQueueFamilyInfoCount * sizeof(VkQueueFamilyProperties))");
+ self.cgenImpl.stmt("if (!deviceGetter(out, out->instance, &out->physicalDevice, &out->physicalDeviceQueueFamilyInfoCount, out->physicalDeviceQueueFamilyInfos, &out->device, &out->presentCapable)) return")
+
+ for vulkanApi, typeDecl, feature in self.apisToGet["device"]:
+ self.syncFeature(self.cgenImpl, feature)
+ self.makeGetProcAddr( \
+ self.cgenImpl, "device", "out->device", vulkanApi.name, typeDecl);
+
+ self.syncFeature(self.cgenImpl, "")
+
+ self.cgenImpl.endBlock()
+
+ self.module.appendImpl(self.cgenImpl.swapCode())
+
+ def onBeginFeature(self, featureName, featureType):
+ VulkanDispatch.onBeginFeature(self, featureName, featureType);
+
+ def onGenType(self, typeXml, name, alias):
+ VulkanDispatch.onGenType(self, typeXml, name, alias);
+
+ def onGenCmd(self, cmdinfo, name, alias):
+ VulkanDispatch.onGenCmd(self, cmdinfo, name, alias);