From ef329ef041b9342c86cd1536d41bd201ed61c0ff Mon Sep 17 00:00:00 2001 From: Jon Ashburn Date: Mon, 13 Apr 2015 18:10:06 -0600 Subject: [PATCH] loader: Fix GetProcAddr to return proper function pointers for app Add case of handling null gpu object for global functions. For device specifc functions use the dispatch table or the loader entrypoints depending on if the trampoline code can be skipped or not. Conflicts: loader/CMakeLists.txt vk-generate.py v2: undo accidental rename of LayerInterceptProcSubcommand fix WinDefFileSubcommand due to rebase (olv) --- loader/CMakeLists.txt | 10 ++++-- loader/loader.c | 42 +++++++++++++++++++++++--- vk-generate.py | 84 ++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 121 insertions(+), 15 deletions(-) diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt index d803930..002e405 100644 --- a/loader/CMakeLists.txt +++ b/loader/CMakeLists.txt @@ -11,6 +11,10 @@ add_custom_command(OUTPUT vulkan.def COMMAND ${PYTHON_CMD} ${PROJECT_SOURCE_DIR}/vk-generate.py win-def-file vulkan all > vulkan.def DEPENDS ${PROJECT_SOURCE_DIR}/vk-generate.py ${PROJECT_SOURCE_DIR}/vulkan.py) +add_custom_command(OUTPUT gpa_helper.h + COMMAND ${PYTHON_CMD} ${PROJECT_SOURCE_DIR}/vk-generate.py loader-get-proc-addr loader > gpa_helper.h + DEPENDS ${PROJECT_SOURCE_DIR}/vk-generate.py ${PROJECT_SOURCE_DIR}/vulkan.py) + include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} @@ -23,16 +27,16 @@ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") if (WIN32) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DVK_PROTOTYPES -D_CRT_SECURE_NO_WARNINGS -DXCB_NVIDIA") - add_library(vulkan SHARED loader.c loader.h dirent_on_windows.c dispatch.c table_ops.h vulkan.def) + add_library(vulkan SHARED loader.c loader.h dirent_on_windows.c dispatch.c table_ops.h gpa_helper.h vulkan.def) set_target_properties(vulkan PROPERTIES LINK_FLAGS "/DEF:${PROJECT_SOURCE_DIR}/loader/vulkan.def") - add_library(VKstatic STATIC loader.c loader.h dirent_on_windows.c dispatch.c table_ops.h) + add_library(VKstatic STATIC loader.c loader.h dirent_on_windows.c dispatch.c table_ops.h gpa_helper.h) set_target_properties(VKstatic PROPERTIES OUTPUT_NAME VKstatic) target_link_libraries(vulkan) endif() if (NOT WIN32) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DVK_PROTOTYPES -Wpointer-arith") - add_library(vulkan SHARED loader.c dispatch.c table_ops.h) + add_library(vulkan SHARED loader.c dispatch.c table_ops.h gpa_helper.h) set_target_properties(vulkan PROPERTIES SOVERSION 0) target_link_libraries(vulkan -ldl -lpthread) endif() diff --git a/loader/loader.c b/loader/loader.c index 3ce99f0..712118a 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -42,6 +42,7 @@ #endif // WIN32 #include "loader_platform.h" #include "table_ops.h" +#include "gpa_helper.h" #include "loader.h" #include "vkIcd.h" // The following is #included again to catch certain OS-specific functions @@ -711,6 +712,28 @@ static void loader_init_dispatch_table(VkLayerDispatchTable *tab, PFN_vkGetProcA tab->EnumerateLayers = vkEnumerateLayers; } +static void *loader_gpa_internal(VkPhysicalGpu gpu, const char * pName) +{ + if (gpu == NULL) { + return NULL;; + } + VkBaseLayerObject* gpuw = (VkBaseLayerObject *) gpu; + VkLayerDispatchTable * disp_table = * (VkLayerDispatchTable **) gpuw->baseObject; + void *addr; + + if (disp_table == NULL) + return NULL; + + addr = loader_lookup_dispatch_table(disp_table, pName); + if (addr) + return addr; + else { + if (disp_table->GetProcAddr == NULL) + return NULL; + return disp_table->GetProcAddr(gpuw->nextObject, pName); + } +} + extern struct loader_icd * loader_get_icd(const VkBaseLayerObject *gpu, uint32_t *gpu_index) { /* @@ -971,7 +994,7 @@ extern uint32_t loader_activate_layers(struct loader_icd *icd, uint32_t gpu_inde if (!loader_layers_activated(icd, gpu_index)) { VkBaseLayerObject *gpuObj = gpu; VkBaseLayerObject *nextGpuObj, *baseObj = gpuObj->baseObject; - PFN_vkGetProcAddr nextGPA = vkGetProcAddr; + PFN_vkGetProcAddr nextGPA = loader_gpa_internal; count = loader_get_layer_libs(icd, gpu_index, ext_count, ext_names, &pLayerNames); if (!count) @@ -1211,12 +1234,21 @@ LOADER_EXPORT VkResult VKAPI vkEnumerateGpus( LOADER_EXPORT void * VKAPI vkGetProcAddr(VkPhysicalGpu gpu, const char * pName) { if (gpu == NULL) { - return NULL; + + /* return entrypoint addresses that are global (in the loader)*/ + return globalGetProcAddr(pName); } - VkBaseLayerObject* gpuw = (VkBaseLayerObject *) gpu; - VkLayerDispatchTable * disp_table = * (VkLayerDispatchTable **) gpuw->baseObject; + void *addr; + /* for entrypoints that loader must handle (ie non-dispatchable or create object) + make sure the loader entrypoint is returned */ + addr = loader_non_passthrough_gpa(pName); + if (addr) + return addr; + + /* return the dispatch table entrypoint for the fastest case */ + const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) gpu; if (disp_table == NULL) return NULL; @@ -1226,7 +1258,7 @@ LOADER_EXPORT void * VKAPI vkGetProcAddr(VkPhysicalGpu gpu, const char * pName) else { if (disp_table->GetProcAddr == NULL) return NULL; - return disp_table->GetProcAddr(gpuw->nextObject, pName); + return disp_table->GetProcAddr(gpu, pName); } } diff --git a/vk-generate.py b/vk-generate.py index 29b9d17..dec7175 100755 --- a/vk-generate.py +++ b/vk-generate.py @@ -33,7 +33,6 @@ def generate_get_proc_addr_check(name): return " if (!%s || %s[0] != 'v' || %s[1] != 'k')\n" \ " return NULL;" % ((name,) * 3) - class Subcommand(object): def __init__(self, argv): self.argv = argv @@ -43,6 +42,18 @@ class Subcommand(object): def run(self): print(self.generate()) + def _does_function_create_object(self, proto): + out_objs = proto.object_out_params() + if proto.name == "ResetFences": + return False + return out_objs and out_objs[-1] == proto.params[-1] + + def _is_loader_special_case(self, proto): + if proto.name in ["GetProcAddr", "EnumerateGpus", "EnumerateLayers"]: + return True + return not self.is_dispatchable_object_first_param(proto) + + def is_dispatchable_object_first_param(self, proto): in_objs = proto.object_in_params() non_dispatch_objs = ["VkInstance"] @@ -107,12 +118,6 @@ class LoaderEntrypointsSubcommand(Subcommand): def generate_header(self): return "#include \"loader.h\"" - def _is_loader_special_case(self, proto): - if proto.name in ["GetProcAddr", "EnumerateGpus", "EnumerateLayers"]: - return True - - return not self.is_dispatchable_object_first_param(proto) - def _generate_object_setup(self, proto): method = "loader_init_data" cond = "res == VK_SUCCESS" @@ -454,6 +459,70 @@ class WinDefFileSubcommand(Subcommand): return "\n".join(body) +class LoaderGetProcAddrSubcommand(Subcommand): + def run(self): + self.prefix = "vk" + + # we could get the list from argv if wanted + self.intercepted = [proto.name for proto in self.protos] + + for proto in self.protos: + if proto.name == "GetProcAddr": + self.gpa = proto + + super().run() + + def generate_header(self): + return "\n".join(["#include "]) + + def generate_body(self): + lookups = [] + for proto in self.protos: + if proto.name not in self.intercepted: + lookups.append("/* no %s%s */" % (self.prefix, proto.name)) + continue + + if 'WsiX11AssociateConnection' == proto.name: + lookups.append("#if defined(__linux__) || defined(XCB_NVIDIA)") + lookups.append("if (!strcmp(name, \"%s\"))" % proto.name) + lookups.append(" return (%s) %s%s;" % + (self.gpa.ret, self.prefix, proto.name)) + lookups.append("#endif") + + special_lookups = [] + # these functions require special trampoline code beyond just the normal create object trampoline code + special_names = ["AllocDescriptorSets", "GetMultiGpuCompatibility"] + for proto in self.protos: + if self._is_loader_special_case(proto) or self._does_function_create_object(proto) or proto.name in special_names: + special_lookups.append("if (!strcmp(name, \"%s\"))" % proto.name) + special_lookups.append(" return (%s) %s%s;" % + (self.gpa.ret, self.prefix, proto.name)) + else: + continue + body = [] + body.append("static inline %s globalGetProcAddr(const char *name)" % + self.gpa.ret) + body.append("{") + body.append(generate_get_proc_addr_check("name")) + body.append("") + body.append(" name += 2;") + body.append(" %s" % "\n ".join(lookups)) + body.append("") + body.append(" return NULL;") + body.append("}") + body.append("") + body.append("static inline void *loader_non_passthrough_gpa(const char *name)") + body.append("{") + body.append(generate_get_proc_addr_check("name")) + body.append("") + body.append(" name += 2;") + body.append(" %s" % "\n ".join(special_lookups)) + body.append("") + body.append(" return NULL;") + body.append("}") + + return "\n".join(body) + def main(): subcommands = { "loader-entrypoints": LoaderEntrypointsSubcommand, @@ -462,6 +531,7 @@ def main(): "icd-get-proc-addr": IcdGetProcAddrSubcommand, "layer-intercept-proc": LayerInterceptProcSubcommand, "win-def-file": WinDefFileSubcommand, + "loader-get-proc-addr": LoaderGetProcAddrSubcommand, } if len(sys.argv) < 2 or sys.argv[1] not in subcommands: -- 2.7.4