Signed-off-by: Georg Lehmann dadschoorse@gmail.com --- dlls/winevulkan/make_vulkan | 47 +++++++++++++++++++++++++++----- dlls/winevulkan/vulkan.c | 6 +++- dlls/winevulkan/vulkan_private.h | 1 + 3 files changed, 46 insertions(+), 8 deletions(-)
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 3ad210e4701..a4c4d16eaaa 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -584,7 +584,7 @@ class VkFunction(object):
def is_device_func(self): # If none of the other, it must be a device function - return not self.is_global_func() and not self.is_instance_func() + return not self.is_global_func() and not self.is_instance_func() and not self.is_phys_dev_func()
def is_driver_func(self): """ Returns if function is part of Wine driver interface. """ @@ -601,8 +601,14 @@ class VkFunction(object): return True
def is_instance_func(self): - # Instance functions are passed VkInstance or VkPhysicalDevice. - if self.params[0].type in ["VkInstance", "VkPhysicalDevice"]: + # Instance functions are passed VkInstance. + if self.params[0].type == "VkInstance": + return True + return False + + def is_phys_dev_func(self): + # Physical device functions are passed VkPhysicalDevice. + if self.params[0].type == "VkPhysicalDevice": return True return False
@@ -2270,6 +2276,14 @@ class VkGenerator(object): f.write(" {{"{0}", &{1}{0}}},\n".format(vk_func.name, prefix)) f.write("};\n\n")
+ f.write("static const struct vulkan_func vk_phys_dev_dispatch_table[] =\n{\n") + for vk_func in self.registry.phys_dev_funcs: + if not vk_func.is_required(): + continue + + f.write(" {{"{0}", &{1}{0}}},\n".format(vk_func.name, prefix)) + f.write("};\n\n") + f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n") for vk_func in self.registry.instance_funcs: if not vk_func.is_required(): @@ -2292,6 +2306,20 @@ class VkGenerator(object): f.write(" return NULL;\n") f.write("}\n\n")
+ f.write("void *wine_vk_get_phys_dev_proc_addr(const char *name)\n") + f.write("{\n") + f.write(" unsigned int i;\n") + f.write(" for (i = 0; i < ARRAY_SIZE(vk_phys_dev_dispatch_table); i++)\n") + f.write(" {\n") + f.write(" if (strcmp(vk_phys_dev_dispatch_table[i].name, name) == 0)\n") + f.write(" {\n") + f.write(" TRACE("Found name=%s in physical device table\n", debugstr_a(name));\n") + f.write(" return vk_phys_dev_dispatch_table[i].func;\n") + f.write(" }\n") + f.write(" }\n") + f.write(" return NULL;\n") + f.write("}\n\n") + f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n") f.write("{\n") f.write(" unsigned int i;\n") @@ -2434,7 +2462,7 @@ class VkGenerator(object):
f.write("/* For use by vkInstance and children */\n") f.write("struct vulkan_instance_funcs\n{\n") - for vk_func in self.registry.instance_funcs: + for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs: if not vk_func.is_required(): continue
@@ -2471,7 +2499,7 @@ class VkGenerator(object):
f.write("#define ALL_VK_INSTANCE_FUNCS() \\n") first = True - for vk_func in self.registry.instance_funcs: + for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs: if not vk_func.is_required(): continue
@@ -2635,7 +2663,7 @@ class VkGenerator(object): f.write("\n") f.write(" if (!instance) return NULL;\n\n") for vk_func in self.registry.funcs.values(): - if vk_func.is_driver_func() and vk_func.is_instance_func(): + if vk_func.is_driver_func() and (vk_func.is_instance_func() or vk_func.is_phys_dev_func()): f.write(' if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:])) f.write(' return vulkan_funcs->p_{0};\n'.format(vk_func.name)) f.write("\n") @@ -2836,21 +2864,26 @@ class VkRegistry(object): funcs[func.name] = func
# To make life easy for the code generation, separate all function - # calls out in the 3 types of Vulkan functions: device, global and instance. + # calls out in the 4 types of Vulkan functions: + # device, global, physical device and instance. device_funcs = [] global_funcs = [] + phys_dev_funcs = [] instance_funcs = [] for func in funcs.values(): if func.is_device_func(): device_funcs.append(func) elif func.is_global_func(): global_funcs.append(func) + elif func.is_phys_dev_func(): + phys_dev_funcs.append(func) else: instance_funcs.append(func)
# Sort function lists by name and store them. self.device_funcs = sorted(device_funcs, key=lambda func: func.name) self.global_funcs = sorted(global_funcs, key=lambda func: func.name) + self.phys_dev_funcs = sorted(phys_dev_funcs, key=lambda func: func.name) self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name)
# The funcs dictionary is used as a convenient way to lookup function diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 971394eb9dd..87cbc3b0e4c 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -1156,7 +1156,8 @@ PFN_vkVoidFunction WINAPI wine_vkGetDeviceProcAddr(VkDevice device, const char * * https://github.com/KhronosGroup/Vulkan-Docs/issues/655 */ if (device->quirks & WINEVULKAN_QUIRK_GET_DEVICE_PROC_ADDR - && (func = wine_vk_get_instance_proc_addr(name))) + && ((func = wine_vk_get_instance_proc_addr(name)) + || (func = wine_vk_get_phys_dev_proc_addr(name)))) { WARN("Returning instance function %s.\n", debugstr_a(name)); return func; @@ -1219,6 +1220,9 @@ PFN_vkVoidFunction WINAPI wine_vkGetInstanceProcAddr(VkInstance instance, const func = wine_vk_get_instance_proc_addr(name); if (func) return func;
+ func = wine_vk_get_phys_dev_proc_addr(name); + if (func) return func; + /* vkGetInstanceProcAddr also loads any children of instance, so device functions as well. */ func = wine_vk_get_device_proc_addr(name); if (func) return func; diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 4a41a15461e..322d27079ea 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -232,6 +232,7 @@ static inline VkSurfaceKHR wine_surface_to_handle(struct wine_surface *surface) }
void *wine_vk_get_device_proc_addr(const char *name) DECLSPEC_HIDDEN; +void *wine_vk_get_phys_dev_proc_addr(const char *name) DECLSPEC_HIDDEN; void *wine_vk_get_instance_proc_addr(const char *name) DECLSPEC_HIDDEN;
BOOL wine_vk_device_extension_supported(const char *name) DECLSPEC_HIDDEN;
When using the windows vulkan loader vk_icdGetPhysicalDeviceProcAddr is used for unknown physical device functions. Fixes Red Dead Redemption 2 with vkd3d-proton. The game replaces wine's vulkan-1.dll with a windows version that doesn't know functions used by vkd3d-proton.
Signed-off-by: Georg Lehmann dadschoorse@gmail.com --- dlls/winevulkan/make_vulkan | 1 + dlls/winevulkan/vulkan.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index a4c4d16eaaa..d0b21c9b559 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -2675,6 +2675,7 @@ class VkGenerator(object): def generate_vulkan_spec(self, f): self._generate_copyright(f, spec_file=True) f.write("@ stdcall -private vk_icdGetInstanceProcAddr(ptr str) wine_vk_icdGetInstanceProcAddr\n") + f.write("@ stdcall -private vk_icdGetPhysicalDeviceProcAddr(ptr str) wine_vk_icdGetPhysicalDeviceProcAddr\n") f.write("@ stdcall -private vk_icdNegotiateLoaderICDInterfaceVersion(ptr) wine_vk_icdNegotiateLoaderICDInterfaceVersion\n") f.write("@ cdecl -norelay native_vkGetInstanceProcAddrWINE(ptr str)\n")
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 87cbc3b0e4c..803e40da047 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -37,9 +37,7 @@ DEFINE_DEVPROPKEY(DEVPROPKEY_GPU_LUID, 0x60b193cb, 0x5276, 0x4d0f, 0x96, 0xfc, 0 DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_GPU_VULKAN_UUID, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5c, 2);
/* For now default to 4 as it felt like a reasonable version feature wise to support. - * Don't support the optional vk_icdGetPhysicalDeviceProcAddr introduced in this version - * as it is unlikely we will implement physical device extensions, which the loader is not - * aware of. Version 5 adds more extensive version checks. Something to tackle later. + * Version 5 adds more extensive version checks. Something to tackle later. */ #define WINE_VULKAN_ICD_VERSION 4
@@ -1231,6 +1229,13 @@ PFN_vkVoidFunction WINAPI wine_vkGetInstanceProcAddr(VkInstance instance, const return NULL; }
+void * WINAPI wine_vk_icdGetPhysicalDeviceProcAddr(VkInstance instance, const char *name) +{ + TRACE("%p, %s\n", instance, debugstr_a(name)); + + return wine_vk_get_phys_dev_proc_addr(name); +} + void * WINAPI wine_vk_icdGetInstanceProcAddr(VkInstance instance, const char *name) { TRACE("%p, %s\n", instance, debugstr_a(name));
Signed-off-by: Joshua Ashton joshua@froggi.es
On 3/23/21 5:42 PM, Georg Lehmann wrote:
When using the windows vulkan loader vk_icdGetPhysicalDeviceProcAddr is used for unknown physical device functions. Fixes Red Dead Redemption 2 with vkd3d-proton. The game replaces wine's vulkan-1.dll with a windows version that doesn't know functions used by vkd3d-proton.
Signed-off-by: Georg Lehmann dadschoorse@gmail.com
dlls/winevulkan/make_vulkan | 1 + dlls/winevulkan/vulkan.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index a4c4d16eaaa..d0b21c9b559 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -2675,6 +2675,7 @@ class VkGenerator(object): def generate_vulkan_spec(self, f): self._generate_copyright(f, spec_file=True) f.write("@ stdcall -private vk_icdGetInstanceProcAddr(ptr str) wine_vk_icdGetInstanceProcAddr\n")
f.write("@ stdcall -private vk_icdGetPhysicalDeviceProcAddr(ptr str) wine_vk_icdGetPhysicalDeviceProcAddr\n") f.write("@ stdcall -private vk_icdNegotiateLoaderICDInterfaceVersion(ptr) wine_vk_icdNegotiateLoaderICDInterfaceVersion\n") f.write("@ cdecl -norelay native_vkGetInstanceProcAddrWINE(ptr str)\n")
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 87cbc3b0e4c..803e40da047 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -37,9 +37,7 @@ DEFINE_DEVPROPKEY(DEVPROPKEY_GPU_LUID, 0x60b193cb, 0x5276, 0x4d0f, 0x96, 0xfc, 0 DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_GPU_VULKAN_UUID, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5c, 2);
/* For now default to 4 as it felt like a reasonable version feature wise to support.
- Don't support the optional vk_icdGetPhysicalDeviceProcAddr introduced in this version
- as it is unlikely we will implement physical device extensions, which the loader is not
- aware of. Version 5 adds more extensive version checks. Something to tackle later.
*/ #define WINE_VULKAN_ICD_VERSION 4
- Version 5 adds more extensive version checks. Something to tackle later.
@@ -1231,6 +1229,13 @@ PFN_vkVoidFunction WINAPI wine_vkGetInstanceProcAddr(VkInstance instance, const return NULL; }
+void * WINAPI wine_vk_icdGetPhysicalDeviceProcAddr(VkInstance instance, const char *name) +{
- TRACE("%p, %s\n", instance, debugstr_a(name));
- return wine_vk_get_phys_dev_proc_addr(name);
+}
- void * WINAPI wine_vk_icdGetInstanceProcAddr(VkInstance instance, const char *name) { TRACE("%p, %s\n", instance, debugstr_a(name));
Signed-off-by: Joshua Ashton joshua@froggi.es
On 3/23/21 5:42 PM, Georg Lehmann wrote:
Signed-off-by: Georg Lehmann dadschoorse@gmail.com
dlls/winevulkan/make_vulkan | 47 +++++++++++++++++++++++++++----- dlls/winevulkan/vulkan.c | 6 +++- dlls/winevulkan/vulkan_private.h | 1 + 3 files changed, 46 insertions(+), 8 deletions(-)
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 3ad210e4701..a4c4d16eaaa 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -584,7 +584,7 @@ class VkFunction(object):
def is_device_func(self): # If none of the other, it must be a device function
return not self.is_global_func() and not self.is_instance_func()
return not self.is_global_func() and not self.is_instance_func() and not self.is_phys_dev_func() def is_driver_func(self): """ Returns if function is part of Wine driver interface. """
@@ -601,8 +601,14 @@ class VkFunction(object): return True
def is_instance_func(self):
# Instance functions are passed VkInstance or VkPhysicalDevice.
if self.params[0].type in ["VkInstance", "VkPhysicalDevice"]:
# Instance functions are passed VkInstance.
if self.params[0].type == "VkInstance":
return True
return False
- def is_phys_dev_func(self):
# Physical device functions are passed VkPhysicalDevice.
if self.params[0].type == "VkPhysicalDevice": return True return False
@@ -2270,6 +2276,14 @@ class VkGenerator(object): f.write(" {{"{0}", &{1}{0}}},\n".format(vk_func.name, prefix)) f.write("};\n\n")
f.write("static const struct vulkan_func vk_phys_dev_dispatch_table[] =\n{\n")
for vk_func in self.registry.phys_dev_funcs:
if not vk_func.is_required():
continue
f.write(" {{\"{0}\", &{1}{0}}},\n".format(vk_func.name, prefix))
f.write("};\n\n")
f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n") for vk_func in self.registry.instance_funcs: if not vk_func.is_required():
@@ -2292,6 +2306,20 @@ class VkGenerator(object): f.write(" return NULL;\n") f.write("}\n\n")
f.write("void *wine_vk_get_phys_dev_proc_addr(const char *name)\n")
f.write("{\n")
f.write(" unsigned int i;\n")
f.write(" for (i = 0; i < ARRAY_SIZE(vk_phys_dev_dispatch_table); i++)\n")
f.write(" {\n")
f.write(" if (strcmp(vk_phys_dev_dispatch_table[i].name, name) == 0)\n")
f.write(" {\n")
f.write(" TRACE(\"Found name=%s in physical device table\\n\", debugstr_a(name));\n")
f.write(" return vk_phys_dev_dispatch_table[i].func;\n")
f.write(" }\n")
f.write(" }\n")
f.write(" return NULL;\n")
f.write("}\n\n")
f.write("void *wine_vk_get_instance_proc_addr(const char *name)\n") f.write("{\n") f.write(" unsigned int i;\n")
@@ -2434,7 +2462,7 @@ class VkGenerator(object):
f.write("/* For use by vkInstance and children */\n") f.write("struct vulkan_instance_funcs\n{\n")
for vk_func in self.registry.instance_funcs:
for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs: if not vk_func.is_required(): continue
@@ -2471,7 +2499,7 @@ class VkGenerator(object):
f.write("#define ALL_VK_INSTANCE_FUNCS() \\\n") first = True
for vk_func in self.registry.instance_funcs:
for vk_func in self.registry.instance_funcs + self.registry.phys_dev_funcs: if not vk_func.is_required(): continue
@@ -2635,7 +2663,7 @@ class VkGenerator(object): f.write("\n") f.write(" if (!instance) return NULL;\n\n") for vk_func in self.registry.funcs.values():
if vk_func.is_driver_func() and vk_func.is_instance_func():
if vk_func.is_driver_func() and (vk_func.is_instance_func() or vk_func.is_phys_dev_func()): f.write(' if (!strcmp(name, "{0}"))\n'.format(vk_func.name[2:])) f.write(' return vulkan_funcs->p_{0};\n'.format(vk_func.name)) f.write("\n")
@@ -2836,21 +2864,26 @@ class VkRegistry(object): funcs[func.name] = func
# To make life easy for the code generation, separate all function
# calls out in the 3 types of Vulkan functions: device, global and instance.
# calls out in the 4 types of Vulkan functions:
# device, global, physical device and instance. device_funcs = [] global_funcs = []
phys_dev_funcs = [] instance_funcs = [] for func in funcs.values(): if func.is_device_func(): device_funcs.append(func) elif func.is_global_func(): global_funcs.append(func)
elif func.is_phys_dev_func():
phys_dev_funcs.append(func) else: instance_funcs.append(func) # Sort function lists by name and store them. self.device_funcs = sorted(device_funcs, key=lambda func: func.name) self.global_funcs = sorted(global_funcs, key=lambda func: func.name)
self.phys_dev_funcs = sorted(phys_dev_funcs, key=lambda func: func.name) self.instance_funcs = sorted(instance_funcs, key=lambda func: func.name) # The funcs dictionary is used as a convenient way to lookup function
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 971394eb9dd..87cbc3b0e4c 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -1156,7 +1156,8 @@ PFN_vkVoidFunction WINAPI wine_vkGetDeviceProcAddr(VkDevice device, const char * * https://github.com/KhronosGroup/Vulkan-Docs/issues/655 */ if (device->quirks & WINEVULKAN_QUIRK_GET_DEVICE_PROC_ADDR
&& (func = wine_vk_get_instance_proc_addr(name)))
&& ((func = wine_vk_get_instance_proc_addr(name))
|| (func = wine_vk_get_phys_dev_proc_addr(name)))) { WARN("Returning instance function %s.\n", debugstr_a(name)); return func;
@@ -1219,6 +1220,9 @@ PFN_vkVoidFunction WINAPI wine_vkGetInstanceProcAddr(VkInstance instance, const func = wine_vk_get_instance_proc_addr(name); if (func) return func;
- func = wine_vk_get_phys_dev_proc_addr(name);
- if (func) return func;
/* vkGetInstanceProcAddr also loads any children of instance, so device functions as well. */ func = wine_vk_get_device_proc_addr(name); if (func) return func;
diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 4a41a15461e..322d27079ea 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -232,6 +232,7 @@ static inline VkSurfaceKHR wine_surface_to_handle(struct wine_surface *surface) }
void *wine_vk_get_device_proc_addr(const char *name) DECLSPEC_HIDDEN; +void *wine_vk_get_phys_dev_proc_addr(const char *name) DECLSPEC_HIDDEN; void *wine_vk_get_instance_proc_addr(const char *name) DECLSPEC_HIDDEN;
BOOL wine_vk_device_extension_supported(const char *name) DECLSPEC_HIDDEN;