Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/winevulkan/make_vulkan | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index cc79b0a58cd..7f76d328fc8 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -256,10 +256,11 @@ FUNCTION_OVERRIDES = { "vkDebugMarkerSetObjectTagEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE}, }
-STRUCT_CHAIN_CONVERSIONS = [ - "VkDeviceCreateInfo", - "VkInstanceCreateInfo", -] +STRUCT_CHAIN_CONVERSIONS = { + # Ignore to not confuse host loader. + "VkDeviceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO"], + "VkInstanceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO"], +}
class Direction(Enum): @@ -2417,9 +2418,10 @@ class FreeFunction(object):
class StructChainConversionFunction(object): - def __init__(self, direction, struct): + def __init__(self, direction, struct, ignores): self.direction = direction self.struct = struct + self.ignores = ignores self.type = struct.name
self.name = "convert_{0}_struct_chain".format(self.type) @@ -2444,9 +2446,8 @@ class StructChainConversionFunction(object): body += " switch (in_header->sType)\n" body += " {\n"
- # Ignore to not confuse host loader. - body += " case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO:\n" - body += " case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO:\n" + for i in self.ignores: + body += " case {0}:\n".format(i) body += " break;\n\n"
for e in self.struct.struct_extensions: @@ -2455,6 +2456,9 @@ class StructChainConversionFunction(object):
stype = next(x for x in e.members if x.name == "sType")
+ if stype.values in self.ignores: + continue + body += " case {0}:\n".format(stype.values) body += " {\n"
@@ -2604,7 +2608,7 @@ class VkGenerator(object):
for struct in self.registry.structs: if struct.name in STRUCT_CHAIN_CONVERSIONS: - self.struct_chain_conversions.append(StructChainConversionFunction(Direction.INPUT, struct)) + self.struct_chain_conversions.append(StructChainConversionFunction(Direction.INPUT, struct, STRUCT_CHAIN_CONVERSIONS[struct.name])) self.struct_chain_conversions.append(FreeStructChainFunction(struct)) # Once we decide to support pNext chains conversion everywhere, move this under get_conversions for e in struct.struct_extensions:
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- This patch is dead code, being used later for VK_KHR_external_memory_fd. I was informed that commits like this are normal for winevulkan, since exposing an extension w/ stubs can break applications. --- dlls/winevulkan/make_vulkan | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 7f76d328fc8..7e1d7c0f043 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -120,6 +120,9 @@ UNSUPPORTED_EXTENSIONS = [ "VK_NV_external_memory_win32", ]
+# Extensions which aren't present on the win32 platform, but which winevulkan may use. +UNEXPOSED_EXTENSIONS = [] + # The Vulkan loader provides entry-points for core functionality and important # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51. CORE_EXTENSIONS = [ @@ -521,7 +524,7 @@ class VkEnumValue(object):
class VkFunction(object): - def __init__(self, _type=None, name=None, params=[], extensions=[], alias=None): + def __init__(self, _type=None, name=None, params=[], alias=None): self.extensions = [] self.name = name self.type = _type @@ -665,6 +668,9 @@ class VkFunction(object): def needs_private_thunk(self): return self.thunk_type == ThunkType.PRIVATE
+ def needs_exposed(self): + return not any(x for x in self.extensions if x in UNEXPOSED_EXTENSIONS) + def pfn(self, prefix="p", call_conv=None, conv=False): """ Create function pointer. """
@@ -2656,6 +2662,9 @@ class VkGenerator(object): if not vk_func.is_required(): continue
+ if not vk_func.needs_exposed(): + continue + if vk_func.is_global_func(): continue
@@ -2676,6 +2685,8 @@ class VkGenerator(object): for ext in self.registry.extensions: if ext["type"] != "device": continue + if ext["name"] in UNEXPOSED_EXTENSIONS: + continue
f.write(" "{0}",\n".format(ext["name"])) f.write("};\n\n") @@ -2685,6 +2696,8 @@ class VkGenerator(object): for ext in self.registry.extensions: if ext["type"] != "instance": continue + if ext["name"] in UNEXPOSED_EXTENSIONS: + continue
f.write(" "{0}",\n".format(ext["name"])) f.write("};\n\n") @@ -2746,6 +2759,8 @@ class VkGenerator(object): for vk_func in self.registry.funcs.values(): if not vk_func.is_required(): continue + if not vk_func.needs_exposed(): + continue if vk_func.loader_thunk_type == ThunkType.NONE: continue
@@ -2767,6 +2782,8 @@ class VkGenerator(object): continue if vk_func.needs_thunk() and not vk_func.needs_private_thunk(): continue + if not vk_func.needs_exposed(): + continue
if vk_func.is_core_func(): f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix=prefix))) @@ -2874,6 +2891,8 @@ class VkGenerator(object): for vk_func in self.registry.funcs.values(): if not vk_func.is_required(): continue + if not vk_func.needs_exposed(): + continue if vk_func.loader_thunk_type != ThunkType.PUBLIC: continue
@@ -2883,6 +2902,8 @@ class VkGenerator(object): for vk_func in self.registry.device_funcs: if not vk_func.is_required(): continue + if not vk_func.needs_exposed(): + continue
f.write(" {{"{0}", &{0}}},\n".format(vk_func.name)) f.write("};\n\n") @@ -2891,6 +2912,8 @@ class VkGenerator(object): for vk_func in self.registry.phys_dev_funcs: if not vk_func.is_required(): continue + if not vk_func.needs_exposed(): + continue
f.write(" {{"{0}", &{0}}},\n".format(vk_func.name)) f.write("};\n\n") @@ -2899,6 +2922,8 @@ class VkGenerator(object): for vk_func in self.registry.instance_funcs: if not vk_func.is_required(): continue + if not vk_func.needs_exposed(): + continue
f.write(" {{"{0}", &{0}}},\n".format(vk_func.name)) f.write("};\n\n") @@ -2956,6 +2981,8 @@ class VkGenerator(object): for vk_func in self.registry.funcs.values(): if not vk_func.is_required(): continue + if not vk_func.needs_exposed(): + continue if vk_func.loader_thunk_type == ThunkType.NONE: continue
On 5/17/21 1:00 PM, Derek Lesho wrote:
Signed-off-by: Derek Lesho dlesho@codeweavers.com
This patch is dead code, being used later for VK_KHR_external_memory_fd. I was informed that commits like this are normal for winevulkan, since exposing an extension w/ stubs can break applications.
I don't agree with the wording here, so let me re-iterate what I said when you asked me earlier today:
I personally think that submitting known broken code (which has potential to break apps in unexpected ways) is significantly worse than submitting code is used on a later change in a patchset.
there’s a difference between submitting something for the unknown future and submitting something where it’s used at the end of the same patchset.
But you should be asking these questions on #winehackers not in VKx discord
I personally don't consider this dead code. Typically when I think of dead code, it's something that was once used but is no longer. That said, unused code with the future promise of use isn't very useful, but as I quoted from myself above, I think that scaffolding is appropriate given that you have a later patch in the series which makes use of it.
dlls/winevulkan/make_vulkan | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 7f76d328fc8..7e1d7c0f043 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -120,6 +120,9 @@ UNSUPPORTED_EXTENSIONS = [ "VK_NV_external_memory_win32", ]
+# Extensions which aren't present on the win32 platform, but which winevulkan may use. +UNEXPOSED_EXTENSIONS = []
nit: Could we call this something like WINEVULKAN_INTERNAL_EXTENSIONS? These extensions are for use only by winevulkan internally. Really the name is fine either way just a matter of personal preference. I just picture this in my head as "extensions for use internal to winevulkan" rather than "extensions that winevulkan must not: expose".
- # The Vulkan loader provides entry-points for core functionality and important # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51. CORE_EXTENSIONS = [
@@ -521,7 +524,7 @@ class VkEnumValue(object):
class VkFunction(object):
- def __init__(self, _type=None, name=None, params=[], extensions=[], alias=None):
- def __init__(self, _type=None, name=None, params=[], alias=None): self.extensions = [] self.name = name self.type = _type
@@ -665,6 +668,9 @@ class VkFunction(object): def needs_private_thunk(self): return self.thunk_type == ThunkType.PRIVATE
- def needs_exposed(self):
return not any(x for x in self.extensions if x in UNEXPOSED_EXTENSIONS)
Is this syntax correct? I'm used to seeing list comprehensions use []'s to surround them, like so:
return not any([x for x in self.extensions if x in UNEXPOSED_EXTENSIONS])
Also this logic is a bit confusing to read as-is. Is the check for seeing if VkFunction.extensions intersects with UNEXPOSED_EXTENSIONS and if there is an intersection to not expose the extension? What happens in the case (although I'm not sure this can exist) where an extension is marked as "unexposed" and has a function that is shared by say, Vulkan x.y core?
But it's probably best to add a comment either way clarifying the right set logic here. Also python has a set() type if that's any easier to use here.
Thanks,
Liam Middlebrook
def pfn(self, prefix="p", call_conv=None, conv=False): """ Create function pointer. """
@@ -2656,6 +2662,9 @@ class VkGenerator(object): if not vk_func.is_required(): continue
if not vk_func.needs_exposed():
continue
if vk_func.is_global_func(): continue
@@ -2676,6 +2685,8 @@ class VkGenerator(object): for ext in self.registry.extensions: if ext["type"] != "device": continue
if ext["name"] in UNEXPOSED_EXTENSIONS:
continue f.write(" \"{0}\",\n".format(ext["name"])) f.write("};\n\n")
@@ -2685,6 +2696,8 @@ class VkGenerator(object): for ext in self.registry.extensions: if ext["type"] != "instance": continue
if ext["name"] in UNEXPOSED_EXTENSIONS:
continue f.write(" \"{0}\",\n".format(ext["name"])) f.write("};\n\n")
@@ -2746,6 +2759,8 @@ class VkGenerator(object): for vk_func in self.registry.funcs.values(): if not vk_func.is_required(): continue
if not vk_func.needs_exposed():
continue if vk_func.loader_thunk_type == ThunkType.NONE: continue
@@ -2767,6 +2782,8 @@ class VkGenerator(object): continue if vk_func.needs_thunk() and not vk_func.needs_private_thunk(): continue
if not vk_func.needs_exposed():
continue if vk_func.is_core_func(): f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix=prefix)))
@@ -2874,6 +2891,8 @@ class VkGenerator(object): for vk_func in self.registry.funcs.values(): if not vk_func.is_required(): continue
if not vk_func.needs_exposed():
continue if vk_func.loader_thunk_type != ThunkType.PUBLIC: continue
@@ -2883,6 +2902,8 @@ class VkGenerator(object): for vk_func in self.registry.device_funcs: if not vk_func.is_required(): continue
if not vk_func.needs_exposed():
continue f.write(" {{\"{0}\", &{0}}},\n".format(vk_func.name)) f.write("};\n\n")
@@ -2891,6 +2912,8 @@ class VkGenerator(object): for vk_func in self.registry.phys_dev_funcs: if not vk_func.is_required(): continue
if not vk_func.needs_exposed():
continue f.write(" {{\"{0}\", &{0}}},\n".format(vk_func.name)) f.write("};\n\n")
@@ -2899,6 +2922,8 @@ class VkGenerator(object): for vk_func in self.registry.instance_funcs: if not vk_func.is_required(): continue
if not vk_func.needs_exposed():
continue f.write(" {{\"{0}\", &{0}}},\n".format(vk_func.name)) f.write("};\n\n")
@@ -2956,6 +2981,8 @@ class VkGenerator(object): for vk_func in self.registry.funcs.values(): if not vk_func.is_required(): continue
if not vk_func.needs_exposed():
continue if vk_func.loader_thunk_type == ThunkType.NONE: continue
On 5/18/21 3:24 AM, Liam Middlebrook wrote:
On 5/17/21 1:00 PM, Derek Lesho wrote:
Signed-off-by: Derek Lesho dlesho@codeweavers.com
This patch is dead code, being used later for VK_KHR_external_memory_fd. I was informed that commits like this are normal for winevulkan, since exposing an extension w/ stubs can break applications.
I don't agree with the wording here, so let me re-iterate what I said when you asked me earlier today:
I personally think that submitting known broken code (which has potential to break apps in unexpected ways) is significantly worse than submitting code is used on a later change in a patchset.
there’s a difference between submitting something for the unknown future and submitting something where it’s used at the end of the same patchset.
But you should be asking these questions on #winehackers not in VKx discord
I personally don't consider this dead code. Typically when I think of dead code, it's something that was once used but is no longer. That said, unused code with the future promise of use isn't very useful, but as I quoted from myself above, I think that scaffolding is appropriate given that you have a later patch in the series which makes use of it.
👌
dlls/winevulkan/make_vulkan | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 7f76d328fc8..7e1d7c0f043 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -120,6 +120,9 @@ UNSUPPORTED_EXTENSIONS = [ "VK_NV_external_memory_win32", ] +# Extensions which aren't present on the win32 platform, but which winevulkan may use. +UNEXPOSED_EXTENSIONS = []
nit: Could we call this something like WINEVULKAN_INTERNAL_EXTENSIONS? These extensions are for use only by winevulkan internally. Really the name is fine either way just a matter of personal preference. I just picture this in my head as "extensions for use internal to winevulkan" rather than "extensions that winevulkan must not: expose".
👌
# The Vulkan loader provides entry-points for core functionality and important # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51. CORE_EXTENSIONS = [ @@ -521,7 +524,7 @@ class VkEnumValue(object): class VkFunction(object): - def __init__(self, _type=None, name=None, params=[], extensions=[], alias=None): + def __init__(self, _type=None, name=None, params=[], alias=None): self.extensions = [] self.name = name self.type = _type @@ -665,6 +668,9 @@ class VkFunction(object): def needs_private_thunk(self): return self.thunk_type == ThunkType.PRIVATE + def needs_exposed(self): + return not any(x for x in self.extensions if x in UNEXPOSED_EXTENSIONS)
Is this syntax correct? I'm used to seeing list comprehensions use []'s to surround them, like so:
return not any([x for x in self.extensions if x in UNEXPOSED_EXTENSIONS])
I'm just going off what appears in the rest of winevulkan, I don't see any "any" statement with the brackets in make_vulkan.
Also this logic is a bit confusing to read as-is. Is the check for seeing if VkFunction.extensions intersects with UNEXPOSED_EXTENSIONS and if there is an intersection to not expose the extension?
Yep, that was the idea, but it seems wrong now. I just looked at the code around UNSUPPORTED_EXTENSIONS and it seems we instead only need to hide if all the extensions are unsupported or internal-only.
What happens in the case (although I'm not sure this can exist) where an extension is marked as "unexposed" and has a function that is shared by say, Vulkan x.y core?
From what I can see, we don't calculate which core version we support from the current list of unsupported extensions either. How is this any different (We just don't expose a core version if any of the required functions are either unsupported or internal-only).
But it's probably best to add a comment either way clarifying the right set logic here.
Sounds good.
Also python has a set() type if that's any easier to use here.
Yeah, it looks like that would have been ideal if the logic weren't wrong since I could just checked if the union/intersection of the two sets were empty. I guess I could still check if the intersection equals the functions full set (self.extensions | WINEVULKAN_INTERNAL_EXTENSIONS == self.extensions), but this seems a bit less clear than the any solution I would have instead (`return self.is_required and any(x for x in self.extensions if x not in UNEXPOSED_EXTENSIONS)`). Do you disagree?
Thanks,
Liam Middlebrook
def pfn(self, prefix="p", call_conv=None, conv=False): """ Create function pointer. """ @@ -2656,6 +2662,9 @@ class VkGenerator(object): if not vk_func.is_required(): continue + if not vk_func.needs_exposed(): + continue
if vk_func.is_global_func(): continue @@ -2676,6 +2685,8 @@ class VkGenerator(object): for ext in self.registry.extensions: if ext["type"] != "device": continue + if ext["name"] in UNEXPOSED_EXTENSIONS: + continue f.write(" "{0}",\n".format(ext["name"])) f.write("};\n\n") @@ -2685,6 +2696,8 @@ class VkGenerator(object): for ext in self.registry.extensions: if ext["type"] != "instance": continue + if ext["name"] in UNEXPOSED_EXTENSIONS: + continue f.write(" "{0}",\n".format(ext["name"])) f.write("};\n\n") @@ -2746,6 +2759,8 @@ class VkGenerator(object): for vk_func in self.registry.funcs.values(): if not vk_func.is_required(): continue + if not vk_func.needs_exposed(): + continue if vk_func.loader_thunk_type == ThunkType.NONE: continue @@ -2767,6 +2782,8 @@ class VkGenerator(object): continue if vk_func.needs_thunk() and not vk_func.needs_private_thunk(): continue + if not vk_func.needs_exposed(): + continue if vk_func.is_core_func(): f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix=prefix))) @@ -2874,6 +2891,8 @@ class VkGenerator(object): for vk_func in self.registry.funcs.values(): if not vk_func.is_required(): continue + if not vk_func.needs_exposed(): + continue if vk_func.loader_thunk_type != ThunkType.PUBLIC: continue @@ -2883,6 +2902,8 @@ class VkGenerator(object): for vk_func in self.registry.device_funcs: if not vk_func.is_required(): continue + if not vk_func.needs_exposed(): + continue f.write(" {{"{0}", &{0}}},\n".format(vk_func.name)) f.write("};\n\n") @@ -2891,6 +2912,8 @@ class VkGenerator(object): for vk_func in self.registry.phys_dev_funcs: if not vk_func.is_required(): continue + if not vk_func.needs_exposed(): + continue f.write(" {{"{0}", &{0}}},\n".format(vk_func.name)) f.write("};\n\n") @@ -2899,6 +2922,8 @@ class VkGenerator(object): for vk_func in self.registry.instance_funcs: if not vk_func.is_required(): continue + if not vk_func.needs_exposed(): + continue f.write(" {{"{0}", &{0}}},\n".format(vk_func.name)) f.write("};\n\n") @@ -2956,6 +2981,8 @@ class VkGenerator(object): for vk_func in self.registry.funcs.values(): if not vk_func.is_required(): continue + if not vk_func.needs_exposed(): + continue if vk_func.loader_thunk_type == ThunkType.NONE: continue
On 17.05.21 22:00, Derek Lesho wrote:
Signed-off-by: Derek Lesho dlesho@codeweavers.com
This patch is dead code, being used later for VK_KHR_external_memory_fd. I was informed that commits like this are normal for winevulkan, since exposing an extension w/ stubs can break applications.
dlls/winevulkan/make_vulkan | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 7f76d328fc8..7e1d7c0f043 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -120,6 +120,9 @@ UNSUPPORTED_EXTENSIONS = [ "VK_NV_external_memory_win32", ]
+# Extensions which aren't present on the win32 platform, but which winevulkan may use. +UNEXPOSED_EXTENSIONS = []
- # The Vulkan loader provides entry-points for core functionality and important # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51. CORE_EXTENSIONS = [
@@ -521,7 +524,7 @@ class VkEnumValue(object):
class VkFunction(object):
- def __init__(self, _type=None, name=None, params=[], extensions=[], alias=None):
- def __init__(self, _type=None, name=None, params=[], alias=None): self.extensions = [] self.name = name self.type = _type
@@ -665,6 +668,9 @@ class VkFunction(object): def needs_private_thunk(self): return self.thunk_type == ThunkType.PRIVATE
- def needs_exposed(self):
return not any(x for x in self.extensions if x in UNEXPOSED_EXTENSIONS)
Shouldn't this be all instead of any? If we support any extension the function should be exposed, even if it's also provided by another extension that we don't expose.
def pfn(self, prefix="p", call_conv=None, conv=False): """ Create function pointer. """
@@ -2656,6 +2662,9 @@ class VkGenerator(object): if not vk_func.is_required(): continue
if not vk_func.needs_exposed():
continue
if vk_func.is_global_func(): continue
@@ -2676,6 +2685,8 @@ class VkGenerator(object): for ext in self.registry.extensions: if ext["type"] != "device": continue
if ext["name"] in UNEXPOSED_EXTENSIONS:
continue f.write(" \"{0}\",\n".format(ext["name"])) f.write("};\n\n")
@@ -2685,6 +2696,8 @@ class VkGenerator(object): for ext in self.registry.extensions: if ext["type"] != "instance": continue
if ext["name"] in UNEXPOSED_EXTENSIONS:
continue f.write(" \"{0}\",\n".format(ext["name"])) f.write("};\n\n")
@@ -2746,6 +2759,8 @@ class VkGenerator(object): for vk_func in self.registry.funcs.values(): if not vk_func.is_required(): continue
if not vk_func.needs_exposed():
continue if vk_func.loader_thunk_type == ThunkType.NONE: continue
@@ -2767,6 +2782,8 @@ class VkGenerator(object): continue if vk_func.needs_thunk() and not vk_func.needs_private_thunk(): continue
if not vk_func.needs_exposed():
continue if vk_func.is_core_func(): f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix=prefix)))
@@ -2874,6 +2891,8 @@ class VkGenerator(object): for vk_func in self.registry.funcs.values(): if not vk_func.is_required(): continue
if not vk_func.needs_exposed():
continue if vk_func.loader_thunk_type != ThunkType.PUBLIC: continue
@@ -2883,6 +2902,8 @@ class VkGenerator(object): for vk_func in self.registry.device_funcs: if not vk_func.is_required(): continue
if not vk_func.needs_exposed():
continue f.write(" {{\"{0}\", &{0}}},\n".format(vk_func.name)) f.write("};\n\n")
@@ -2891,6 +2912,8 @@ class VkGenerator(object): for vk_func in self.registry.phys_dev_funcs: if not vk_func.is_required(): continue
if not vk_func.needs_exposed():
continue f.write(" {{\"{0}\", &{0}}},\n".format(vk_func.name)) f.write("};\n\n")
@@ -2899,6 +2922,8 @@ class VkGenerator(object): for vk_func in self.registry.instance_funcs: if not vk_func.is_required(): continue
if not vk_func.needs_exposed():
continue f.write(" {{\"{0}\", &{0}}},\n".format(vk_func.name)) f.write("};\n\n")
@@ -2956,6 +2981,8 @@ class VkGenerator(object): for vk_func in self.registry.funcs.values(): if not vk_func.is_required(): continue
if not vk_func.needs_exposed():
continue if vk_func.loader_thunk_type == ThunkType.NONE: continue
On 5/18/21 11:06 AM, Georg Lehmann wrote:
On 17.05.21 22:00, Derek Lesho wrote:
Signed-off-by: Derek Lesho dlesho@codeweavers.com
This patch is dead code, being used later for VK_KHR_external_memory_fd. I was informed that commits like this are normal for winevulkan, since exposing an extension w/ stubs can break applications.
dlls/winevulkan/make_vulkan | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 7f76d328fc8..7e1d7c0f043 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -120,6 +120,9 @@ UNSUPPORTED_EXTENSIONS = [ "VK_NV_external_memory_win32", ] +# Extensions which aren't present on the win32 platform, but which winevulkan may use. +UNEXPOSED_EXTENSIONS = []
# The Vulkan loader provides entry-points for core functionality and important # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51. CORE_EXTENSIONS = [ @@ -521,7 +524,7 @@ class VkEnumValue(object): class VkFunction(object): - def __init__(self, _type=None, name=None, params=[], extensions=[], alias=None): + def __init__(self, _type=None, name=None, params=[], alias=None): self.extensions = [] self.name = name self.type = _type @@ -665,6 +668,9 @@ class VkFunction(object): def needs_private_thunk(self): return self.thunk_type == ThunkType.PRIVATE + def needs_exposed(self): + return not any(x for x in self.extensions if x in UNEXPOSED_EXTENSIONS)
Shouldn't this be all instead of any? If we support any extension the function should be exposed, even if it's also provided by another extension that we don't expose.
Yep, I realized this while replying to Liam's mail.
def pfn(self, prefix="p", call_conv=None, conv=False): """ Create function pointer. """ @@ -2656,6 +2662,9 @@ class VkGenerator(object): if not vk_func.is_required(): continue + if not vk_func.needs_exposed(): + continue
if vk_func.is_global_func(): continue @@ -2676,6 +2685,8 @@ class VkGenerator(object): for ext in self.registry.extensions: if ext["type"] != "device": continue + if ext["name"] in UNEXPOSED_EXTENSIONS: + continue f.write(" "{0}",\n".format(ext["name"])) f.write("};\n\n") @@ -2685,6 +2696,8 @@ class VkGenerator(object): for ext in self.registry.extensions: if ext["type"] != "instance": continue + if ext["name"] in UNEXPOSED_EXTENSIONS: + continue f.write(" "{0}",\n".format(ext["name"])) f.write("};\n\n") @@ -2746,6 +2759,8 @@ class VkGenerator(object): for vk_func in self.registry.funcs.values(): if not vk_func.is_required(): continue + if not vk_func.needs_exposed(): + continue if vk_func.loader_thunk_type == ThunkType.NONE: continue @@ -2767,6 +2782,8 @@ class VkGenerator(object): continue if vk_func.needs_thunk() and not vk_func.needs_private_thunk(): continue + if not vk_func.needs_exposed(): + continue if vk_func.is_core_func(): f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix=prefix))) @@ -2874,6 +2891,8 @@ class VkGenerator(object): for vk_func in self.registry.funcs.values(): if not vk_func.is_required(): continue + if not vk_func.needs_exposed(): + continue if vk_func.loader_thunk_type != ThunkType.PUBLIC: continue @@ -2883,6 +2902,8 @@ class VkGenerator(object): for vk_func in self.registry.device_funcs: if not vk_func.is_required(): continue + if not vk_func.needs_exposed(): + continue f.write(" {{"{0}", &{0}}},\n".format(vk_func.name)) f.write("};\n\n") @@ -2891,6 +2912,8 @@ class VkGenerator(object): for vk_func in self.registry.phys_dev_funcs: if not vk_func.is_required(): continue + if not vk_func.needs_exposed(): + continue f.write(" {{"{0}", &{0}}},\n".format(vk_func.name)) f.write("};\n\n") @@ -2899,6 +2922,8 @@ class VkGenerator(object): for vk_func in self.registry.instance_funcs: if not vk_func.is_required(): continue + if not vk_func.needs_exposed(): + continue f.write(" {{"{0}", &{0}}},\n".format(vk_func.name)) f.write("};\n\n") @@ -2956,6 +2981,8 @@ class VkGenerator(object): for vk_func in self.registry.funcs.values(): if not vk_func.is_required(): continue + if not vk_func.needs_exposed(): + continue if vk_func.loader_thunk_type == ThunkType.NONE: continue
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- v2: Addressed comments from mailing list and discord. --- dlls/vulkan-1/tests/vulkan.c | 216 ++++++++++++++++ dlls/winevulkan/make_vulkan | 26 +- dlls/winevulkan/vulkan.c | 406 +++++++++++++++++++++++++++++-- dlls/winevulkan/vulkan_private.h | 24 ++ 4 files changed, 645 insertions(+), 27 deletions(-)
diff --git a/dlls/vulkan-1/tests/vulkan.c b/dlls/vulkan-1/tests/vulkan.c index 1d23c4112cf..718937e2222 100644 --- a/dlls/vulkan-1/tests/vulkan.c +++ b/dlls/vulkan-1/tests/vulkan.c @@ -546,6 +546,221 @@ static void test_null_hwnd(VkInstance vk_instance, VkPhysicalDevice vk_physical_ vkDestroySurfaceKHR(vk_instance, surface, NULL); }
+uint32_t find_memory_type(VkPhysicalDevice vk_physical_device, VkMemoryPropertyFlagBits flags) +{ + VkPhysicalDeviceMemoryProperties properties = {0}; + unsigned int i; + + vkGetPhysicalDeviceMemoryProperties(vk_physical_device, &properties); + + for(i = 0; i < properties.memoryTypeCount; i++) + { + if (properties.memoryTypes[i].propertyFlags & flags) + return i; + } + return -1; +} + +static const char *test_external_memory_extensions[] = +{ + "VK_KHR_external_memory_capabilities", +}; + +static void test_external_memory(VkInstance vk_instance, VkPhysicalDevice vk_physical_device) +{ + PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR; + PFN_vkGetMemoryWin32HandleKHR pfn_vkGetMemoryWin32HandleKHR; + VkPhysicalDeviceExternalBufferInfoKHR external_buffer_info; + VkExternalBufferPropertiesKHR external_buffer_properties; + VkMemoryDedicatedAllocateInfoKHR dedicated_alloc_info; + VkExportMemoryWin32HandleInfoKHR export_handle_info; + VkImportMemoryWin32HandleInfoKHR import_handle_info; + VkExportMemoryAllocateInfoKHR export_memory_info; + VkMemoryGetWin32HandleInfoKHR get_handle_info; + VkBufferCreateInfo buffer_create_info; + VkMemoryAllocateInfo alloc_info; + uint32_t queue_family_index; + HANDLE nt_handle, kmt_handle; + VkDeviceMemory vk_memory, vk_memory_import; + VkBuffer vk_buffer; + VkDevice vk_device; + VkResult vr; + + static const char *extensions[] = + { + "VK_KHR_dedicated_allocation", + "VK_KHR_external_memory", + "VK_KHR_external_memory_win32", + }; + + pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR = + (void*) vkGetInstanceProcAddr(vk_instance, "vkGetPhysicalDeviceExternalBufferPropertiesKHR"); + + if ((vr = create_device(vk_physical_device, ARRAY_SIZE(extensions), extensions, NULL, &vk_device))) + { + skip("Failed to create device with external memory extensions, VkResult %d.\n", vr); + return; + } + + pfn_vkGetMemoryWin32HandleKHR = (void *) vkGetDeviceProcAddr(vk_device, "vkGetMemoryWin32HandleKHR"); + + find_queue_family(vk_physical_device, VK_QUEUE_GRAPHICS_BIT, &queue_family_index); + + /* Most implementations only support exporting dedicated allocations */ + + buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_create_info.pNext = NULL; + buffer_create_info.flags = 0; + buffer_create_info.size = 1; + buffer_create_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + buffer_create_info.sharingMode = VK_SHARING_MODE_CONCURRENT; + buffer_create_info.queueFamilyIndexCount = 1; + buffer_create_info.pQueueFamilyIndices = &queue_family_index; + if ((vr = vkCreateBuffer(vk_device, &buffer_create_info, NULL, &vk_buffer))) + { + skip("Failed to create generic buffer, VkResult %d.\n", vr); + vkDestroyDevice(vk_device, NULL); + return; + } + + dedicated_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR; + dedicated_alloc_info.pNext = NULL; + dedicated_alloc_info.image = VK_NULL_HANDLE; + dedicated_alloc_info.buffer = vk_buffer; + + external_buffer_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR; + external_buffer_info.pNext = NULL; + external_buffer_info.flags = 0; + external_buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + external_buffer_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR; + + memset(&external_buffer_properties, 0, sizeof(external_buffer_properties)); + external_buffer_properties.sType = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR; + + pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR(vk_physical_device, &external_buffer_info, &external_buffer_properties); + + if (!(external_buffer_properties.externalMemoryProperties.externalMemoryFeatures & + (VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR|VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR))) + skip("With desired parameters, buffers are not exportable to and importable from an NT handle.\n"); + else + { + ok(external_buffer_properties.externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR, + "Unexpected compatibleHandleTypes %#x.\n", external_buffer_properties.externalMemoryProperties.compatibleHandleTypes); + + export_memory_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR; + export_memory_info.pNext = &dedicated_alloc_info; + export_memory_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR; + + export_handle_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR; + export_handle_info.pNext = &export_memory_info; + export_handle_info.name = L"wine_test_buffer_export_name"; + export_handle_info.dwAccess = GENERIC_ALL; + export_handle_info.pAttributes = NULL; + + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.pNext = &export_handle_info; + alloc_info.allocationSize = 1; + alloc_info.memoryTypeIndex = find_memory_type(vk_physical_device, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + ok(alloc_info.memoryTypeIndex != -1, "Device local memory type index was not found.\n"); + + vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory); + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr); + + get_handle_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR; + get_handle_info.pNext = NULL; + get_handle_info.memory = vk_memory; + get_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR; + + vr = pfn_vkGetMemoryWin32HandleKHR(vk_device, &get_handle_info, &nt_handle); + ok(vr == VK_SUCCESS, "vkGetMemoryWin32HandleKHR failed, VkResult %d.\n", vr); + + import_handle_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR; + import_handle_info.pNext = &dedicated_alloc_info; + import_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR; + import_handle_info.handle = nt_handle; + import_handle_info.name = NULL; + + alloc_info.pNext = &import_handle_info; + + vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import); + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr); + ok(vk_memory_import != vk_memory, "Expected new memory object.\n"); + + vkFreeMemory(vk_device, vk_memory_import, NULL); + + import_handle_info.handle = NULL; + import_handle_info.name = L"wine_test_buffer_export_name"; + + vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import); + todo_wine + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr); + if (vr == VK_SUCCESS) + { + ok(vk_memory_import != vk_memory, "Expected new memory object.\n"); + vkFreeMemory(vk_device, vk_memory_import, NULL); + } + vkFreeMemory(vk_device, vk_memory, NULL); + CloseHandle(nt_handle); + } + + external_buffer_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR; + + memset(&external_buffer_properties, 0, sizeof(external_buffer_properties)); + external_buffer_properties.sType = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR; + + pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR(vk_physical_device, &external_buffer_info, &external_buffer_properties); + + if (!(external_buffer_properties.externalMemoryProperties.externalMemoryFeatures & + (VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR|VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR))) + skip("With desired parameters, buffers are not exportable to and importable from a KMT handle.\n"); + else + { + ok(external_buffer_properties.externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR, + "Unexpected compatibleHandleTypes %#x.\n", external_buffer_properties.externalMemoryProperties.compatibleHandleTypes); + + export_memory_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR; + export_memory_info.pNext = &dedicated_alloc_info; + export_memory_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR; + + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.pNext = &export_memory_info; + alloc_info.allocationSize = 1; + alloc_info.memoryTypeIndex = find_memory_type(vk_physical_device, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + ok(alloc_info.memoryTypeIndex != -1, "Device local memory type index was not found.\n"); + + vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory); + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr); + + get_handle_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR; + get_handle_info.pNext = NULL; + get_handle_info.memory = vk_memory; + get_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR; + + vr = pfn_vkGetMemoryWin32HandleKHR(vk_device, &get_handle_info, &kmt_handle); + ok(vr == VK_SUCCESS, "vkGetMemoryWin32HandleKHR failed, VkResult %d.\n", vr); + + import_handle_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR; + import_handle_info.pNext = &dedicated_alloc_info; + import_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR; + import_handle_info.handle = kmt_handle; + import_handle_info.name = NULL; + + alloc_info.pNext = &import_handle_info; + + vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import); + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr); + ok(vk_memory_import != vk_memory, "Expected new memory object.\n"); + + vkFreeMemory(vk_device, vk_memory_import, NULL); + vkFreeMemory(vk_device, vk_memory, NULL); + } + + vkDestroyBuffer(vk_device, vk_buffer, NULL); + vkDestroyDevice(vk_device, NULL); +} + static void for_each_device_instance(uint32_t extension_count, const char * const *enabled_extensions, void (*test_func_instance)(VkInstance, VkPhysicalDevice), void (*test_func)(VkPhysicalDevice)) { @@ -602,4 +817,5 @@ START_TEST(vulkan) for_each_device(test_unsupported_device_extensions); for_each_device(test_private_data); for_each_device_instance(ARRAY_SIZE(test_null_hwnd_extensions), test_null_hwnd_extensions, test_null_hwnd, NULL); + for_each_device_instance(ARRAY_SIZE(test_external_memory_extensions), test_external_memory_extensions, test_external_memory, NULL); } diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 7e1d7c0f043..b36275ba75f 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -99,7 +99,6 @@ UNSUPPORTED_EXTENSIONS = [ "VK_EXT_pipeline_creation_feedback", "VK_GOOGLE_display_timing", "VK_KHR_external_fence_win32", - "VK_KHR_external_memory_win32", "VK_KHR_external_semaphore_win32", # Relates to external_semaphore and needs type conversions in bitflags. "VK_KHR_shared_presentable_image", # Needs WSI work. @@ -109,7 +108,6 @@ UNSUPPORTED_EXTENSIONS = [ "VK_EXT_external_memory_dma_buf", "VK_EXT_image_drm_format_modifier", "VK_KHR_external_fence_fd", - "VK_KHR_external_memory_fd", "VK_KHR_external_semaphore_fd",
# Extensions which require callback handling @@ -121,7 +119,9 @@ UNSUPPORTED_EXTENSIONS = [ ]
# Extensions which aren't present on the win32 platform, but which winevulkan may use. -UNEXPOSED_EXTENSIONS = [] +UNEXPOSED_EXTENSIONS = [ + "VK_KHR_external_memory_fd", +]
# The Vulkan loader provides entry-points for core functionality and important # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51. @@ -179,7 +179,7 @@ FUNCTION_OVERRIDES = { "vkEnumerateDeviceLayerProperties": {"dispatch": True, "driver": False, "thunk": ThunkType.NONE}, "vkEnumeratePhysicalDeviceGroups" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, - "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, + "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, @@ -188,10 +188,14 @@ FUNCTION_OVERRIDES = {
# Device functions "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkAllocateMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkCreateBuffer" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkCreateImage" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkFreeMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE}, "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetDeviceQueue2" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, @@ -221,7 +225,7 @@ FUNCTION_OVERRIDES = { "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
# VK_KHR_external_memory_capabilities - "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, + "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
# VK_KHR_external_semaphore_capabilities @@ -257,12 +261,22 @@ FUNCTION_OVERRIDES = { # VK_EXT_debug_marker "vkDebugMarkerSetObjectNameEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkDebugMarkerSetObjectTagEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE}, + + # VK_KHR_external_memory_win32 + "vkGetMemoryWin32HandleKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkGetMemoryWin32HandlePropertiesKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, }
STRUCT_CHAIN_CONVERSIONS = { # Ignore to not confuse host loader. "VkDeviceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO"], "VkInstanceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO"], + + # Structs which require pNext chain modification + "VkBufferCreateInfo": [], + "VkImageCreateInfo": [], + "VkMemoryAllocateInfo": ["VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR", "VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR"], + "VkPhysicalDeviceImageFormatInfo2": [], }
@@ -1052,6 +1066,8 @@ class VkHandle(object): return "wine_debug_report_callback_from_handle({0})->debug_callback".format(name) if self.name == "VkSurfaceKHR": return "wine_surface_from_handle({0})->surface".format(name) + if self.name == "VkDeviceMemory": + return "wine_dev_mem_from_handle({0})->dev_mem".format(name)
native_handle_name = None
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 9f181d92bc5..c2069b77ef2 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -25,6 +25,7 @@ #include <time.h> #include <stdarg.h> #include <stdlib.h> +#include <unistd.h>
#include "ntstatus.h" #define WIN32_NO_STATUS @@ -34,6 +35,8 @@ #include "winuser.h" #include "winternl.h"
+#include "wine/server.h" + #include "vulkan_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(vulkan); @@ -263,6 +266,15 @@ static struct VkPhysicalDevice_T *wine_vk_physical_device_alloc(struct VkInstanc */ for (i = 0; i < num_host_properties; i++) { + if (!strcmp(host_properties[i].extensionName, "VK_KHR_external_memory_fd")) + { + TRACE("Substituting VK_KHR_external_memory_fd for VK_KHR_external_memory_win32\n"); + + snprintf(host_properties[i].extensionName, sizeof(host_properties[i].extensionName), + VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME); + host_properties[i].specVersion = VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION; + } + if (wine_vk_device_extension_supported(host_properties[i].extensionName)) { TRACE("Enabling extension '%s' for physical device %p\n", host_properties[i].extensionName, object); @@ -361,11 +373,15 @@ static void wine_vk_device_get_queues(struct VkDevice_T *device, static void wine_vk_device_free_create_info(VkDeviceCreateInfo *create_info) { free_VkDeviceCreateInfo_struct_chain(create_info); + + if (create_info->enabledExtensionCount) + free((void *)create_info->ppEnabledExtensionNames); }
static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src, VkDeviceCreateInfo *dst) { + const char **enabled_extensions; unsigned int i; VkResult res;
@@ -389,11 +405,34 @@ static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src if (!wine_vk_device_extension_supported(extension_name)) { WARN("Extension %s is not supported.\n", debugstr_a(extension_name)); - wine_vk_device_free_create_info(dst); + free_VkDeviceCreateInfo_struct_chain(dst); return VK_ERROR_EXTENSION_NOT_PRESENT; } }
+ if (src->enabledExtensionCount > 0) + { + enabled_extensions = calloc(src->enabledExtensionCount, sizeof(*src->ppEnabledExtensionNames)); + if (!enabled_extensions) + { + free_VkDeviceCreateInfo_struct_chain(dst); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + for (i = 0; i < src->enabledExtensionCount; i++) + { + if (!strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_memory_win32")) + { + enabled_extensions[i] = "VK_KHR_external_memory_fd"; + } + else + { + enabled_extensions[i] = src->ppEnabledExtensionNames[i]; + } + } + dst->ppEnabledExtensionNames = enabled_extensions; + } + return VK_SUCCESS; }
@@ -1190,57 +1229,100 @@ void WINAPI wine_vkGetPhysicalDeviceExternalFencePropertiesKHR(VkPhysicalDevice void WINAPI wine_vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice phys_dev, const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties) { + VkPhysicalDeviceExternalBufferInfo buffer_info_dup = *buffer_info; + TRACE("%p, %p, %p\n", phys_dev, buffer_info, properties); - memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties)); + + if (buffer_info_dup.handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + buffer_info_dup.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + + thunk_vkGetPhysicalDeviceExternalBufferProperties(phys_dev, &buffer_info_dup, properties); + + if (properties->externalMemoryProperties.exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) + properties->externalMemoryProperties.exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + if (properties->externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) + properties->externalMemoryProperties.compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; }
void WINAPI wine_vkGetPhysicalDeviceExternalBufferPropertiesKHR(VkPhysicalDevice phys_dev, const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties) { + VkPhysicalDeviceExternalBufferInfo buffer_info_dup = *buffer_info; + TRACE("%p, %p, %p\n", phys_dev, buffer_info, properties); - memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties)); + + if (buffer_info_dup.handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + buffer_info_dup.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + + thunk_vkGetPhysicalDeviceExternalBufferPropertiesKHR(phys_dev, &buffer_info_dup, properties); + + if (properties->externalMemoryProperties.exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) + properties->externalMemoryProperties.exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + if (properties->externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) + properties->externalMemoryProperties.compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; }
-VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev, +static VkResult wine_vk_get_physical_device_image_format_properties_2(VkPhysicalDevice phys_dev, + VkResult (*p_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice, const VkPhysicalDeviceImageFormatInfo2 *, VkImageFormatProperties2 *), const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties) { + VkPhysicalDeviceExternalImageFormatInfo *external_image_info_dup = NULL; + const VkPhysicalDeviceExternalImageFormatInfo *external_image_info; + VkPhysicalDeviceImageFormatInfo2 format_info_host = *format_info; VkExternalImageFormatProperties *external_image_properties; VkResult res;
- TRACE("%p, %p, %p\n", phys_dev, format_info, properties); + if ((external_image_info = wine_vk_find_struct(format_info, PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO))) + { + if (external_image_info->handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + { + if ((res = convert_VkPhysicalDeviceImageFormatInfo2_struct_chain(format_info->pNext, &format_info_host)) < 0) + { + WARN("Failed to convert VkPhysicalDeviceImageFormatInfo2 pNext chain, res=%d.\n", res); + return res; + }
- res = thunk_vkGetPhysicalDeviceImageFormatProperties2(phys_dev, format_info, properties); + external_image_info_dup = wine_vk_find_struct(&format_info_host, PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO); + external_image_info_dup->handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + } + if (external_image_info->handleType &~ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + { + WARN("Unsupported handle type %#x.\n", external_image_info->handleType); + return VK_ERROR_FORMAT_NOT_SUPPORTED; + } + } + + res = p_vkGetPhysicalDeviceImageFormatProperties2(phys_dev, &format_info_host, properties); + + if (external_image_info_dup) + free_VkPhysicalDeviceImageFormatInfo2_struct_chain(&format_info_host);
if ((external_image_properties = wine_vk_find_struct(properties, EXTERNAL_IMAGE_FORMAT_PROPERTIES))) { VkExternalMemoryProperties *p = &external_image_properties->externalMemoryProperties; - p->externalMemoryFeatures = 0; - p->exportFromImportedHandleTypes = 0; - p->compatibleHandleTypes = 0; + if (p->exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) + p->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + if (p->compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) + p->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; }
return res; }
-VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice phys_dev, +VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev, const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties) { - VkExternalImageFormatProperties *external_image_properties; - VkResult res; - TRACE("%p, %p, %p\n", phys_dev, format_info, properties);
- res = thunk_vkGetPhysicalDeviceImageFormatProperties2KHR(phys_dev, format_info, properties); + return wine_vk_get_physical_device_image_format_properties_2(phys_dev, thunk_vkGetPhysicalDeviceImageFormatProperties2, format_info, properties); +}
- if ((external_image_properties = wine_vk_find_struct(properties, EXTERNAL_IMAGE_FORMAT_PROPERTIES))) - { - VkExternalMemoryProperties *p = &external_image_properties->externalMemoryProperties; - p->externalMemoryFeatures = 0; - p->exportFromImportedHandleTypes = 0; - p->compatibleHandleTypes = 0; - } +VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice phys_dev, + const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties) +{ + TRACE("%p, %p, %p\n", phys_dev, format_info, properties);
- return res; + return wine_vk_get_physical_device_image_format_properties_2(phys_dev, thunk_vkGetPhysicalDeviceImageFormatProperties2KHR, format_info, properties); }
/* From ntdll/unix/sync.c */ @@ -1720,3 +1802,283 @@ VkResult WINAPI wine_vkDebugMarkerSetObjectNameEXT(VkDevice device, const VkDebu
return thunk_vkDebugMarkerSetObjectNameEXT(device, &wine_name_info); } + +static HANDLE create_gpu_resource(int fd, LPCWSTR name) +{ + HANDLE ret = INVALID_HANDLE_VALUE; + + if (name) + FIXME("Naming gpu resources not supported.\n"); + + wine_server_fd_to_handle(fd, GENERIC_ALL, 0, &ret); + + return ret; +} + +VkResult WINAPI wine_vkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *allocate_info, + const VkAllocationCallbacks *allocator, VkDeviceMemory *memory) +{ + const VkImportMemoryWin32HandleInfoKHR *handle_import_info; + const VkExportMemoryWin32HandleInfoKHR *handle_export_info; + VkMemoryAllocateInfo allocate_info_dup = *allocate_info; + VkExportMemoryAllocateInfo *export_info; + VkImportMemoryFdInfoKHR fd_import_info; + struct wine_dev_mem *object; + VkResult res; + int fd; + +#if defined(USE_STRUCT_CONVERSION) + VkMemoryAllocateInfo_host allocate_info_host; + VkMemoryGetFdInfoKHR_host get_fd_info; +#else + VkMemoryAllocateInfo allocate_info_host; + VkMemoryGetFdInfoKHR get_fd_info; +#endif + + TRACE("%p %p %p %p\n", device, allocate_info, allocator, memory); + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + if ((res = convert_VkMemoryAllocateInfo_struct_chain(allocate_info->pNext, &allocate_info_dup)) < 0) + { + WARN("Failed to convert VkMemoryAllocateInfo pNext chain, res=%d.\n", res); + return res; + } + + if (!(object = calloc(1, sizeof(*object)))) + { + free_VkMemoryAllocateInfo_struct_chain(&allocate_info_dup); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + object->dev_mem = VK_NULL_HANDLE; + object->handle = INVALID_HANDLE_VALUE; + fd_import_info.fd = -1; + fd_import_info.pNext = NULL; + + /* find and process handle import/export info and grab it */ + handle_import_info = wine_vk_find_struct(allocate_info, IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR); + handle_export_info = wine_vk_find_struct(allocate_info, EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR); + if (handle_export_info && handle_export_info->pAttributes && handle_export_info->pAttributes->lpSecurityDescriptor) + FIXME("Support for custom security descriptor not implemented.\n"); + + if ((export_info = wine_vk_find_struct(&allocate_info_dup, EXPORT_MEMORY_ALLOCATE_INFO))) + { + object->handle_types = export_info->handleTypes; + if (object->handle_types &~ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto done; + } + if (object->handle_types) + export_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + } + + /* Vulkan consumes imported FDs, but not imported HANDLEs */ + if (handle_import_info) + { + fd_import_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; + fd_import_info.pNext = allocate_info_dup.pNext; + fd_import_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + + switch (handle_import_info->handleType) + { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT: + if (handle_import_info->handle) + NtDuplicateObject( NtCurrentProcess(), handle_import_info->handle, NtCurrentProcess(), &object->handle, 0, 0, DUPLICATE_SAME_ACCESS ); + else if (handle_import_info->name) + FIXME("Importing device memory by resource name not supported.\n"); + break; + default: + WARN("Invalid handle type %08x passed in.\n", handle_import_info->handleType); + res = VK_ERROR_INVALID_EXTERNAL_HANDLE; + goto done; + } + + if (object->handle != INVALID_HANDLE_VALUE) + wine_server_handle_to_fd(object->handle, FILE_READ_DATA, &fd_import_info.fd, NULL); + + if (fd_import_info.fd == -1) + { + TRACE("Couldn't access resource handle or name. type=%08x handle=%p name=%s\n", handle_import_info->handleType, handle_import_info->handle, + handle_import_info->name ? debugstr_w(handle_import_info->name) : ""); + res = VK_ERROR_INVALID_EXTERNAL_HANDLE; + goto done; + } + } + + allocate_info_host.sType = allocate_info_dup.sType; + allocate_info_host.pNext = fd_import_info.fd == -1 ? allocate_info_dup.pNext : &fd_import_info; + allocate_info_host.allocationSize = allocate_info_dup.allocationSize; + allocate_info_host.memoryTypeIndex = allocate_info_dup.memoryTypeIndex; + + if ((res = device->funcs.p_vkAllocateMemory(device->device, &allocate_info_host, NULL, &object->dev_mem)) == VK_SUCCESS) + { + if (object->handle == INVALID_HANDLE_VALUE && export_info && export_info->handleTypes) + { + get_fd_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR; + get_fd_info.pNext = NULL; + get_fd_info.memory = object->dev_mem; + get_fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + + if (device->funcs.p_vkGetMemoryFdKHR(device->device, &get_fd_info, &fd) == VK_SUCCESS) + { + object->handle = create_gpu_resource(fd, handle_export_info ? handle_export_info->name : NULL); + object->access = handle_export_info ? handle_export_info->dwAccess : GENERIC_ALL; + if (handle_export_info && handle_export_info->pAttributes) + object->inherit = handle_export_info->pAttributes->bInheritHandle; + else + object->inherit = FALSE; + close(fd); + } + + if (object->handle == INVALID_HANDLE_VALUE) + { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto done; + } + } + + WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(device->phys_dev->instance, object, object->dev_mem); + *memory = wine_dev_mem_to_handle(object); + } + + done: + + if (res != VK_SUCCESS) + { + device->funcs.p_vkFreeMemory(device->device, object->dev_mem, NULL); + if (fd_import_info.fd != -1) + close(fd_import_info.fd); + if (object->handle != INVALID_HANDLE_VALUE) + NtClose(object->handle); + free(object); + } + + free_VkMemoryAllocateInfo_struct_chain(&allocate_info_dup); + + return res; +} + +VkResult WINAPI wine_vkGetMemoryWin32HandleKHR(VkDevice device, + const VkMemoryGetWin32HandleInfoKHR *handle_info, HANDLE *handle) +{ + struct wine_dev_mem *dev_mem = wine_dev_mem_from_handle(handle_info->memory); + const VkBaseInStructure *chain; + + TRACE("%p, %p %p\n", device, handle_info, handle); + + if (!(dev_mem->handle_types & handle_info->handleType)) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + if ((chain = handle_info->pNext)) + FIXME("Ignoring a linked structure of type %u.\n", chain->sType); + + switch(handle_info->handleType) + { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT: + return !NtDuplicateObject( NtCurrentProcess(), dev_mem->handle, NtCurrentProcess(), handle, dev_mem->access, dev_mem->inherit ? OBJ_INHERIT : 0, 0) ? + VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY; + default: + return VK_ERROR_UNKNOWN; + } +} + +void WINAPI wine_vkFreeMemory(VkDevice device, VkDeviceMemory handle, const VkAllocationCallbacks *allocator) +{ + struct wine_dev_mem *dev_mem = wine_dev_mem_from_handle(handle); + + TRACE("%p 0x%s, %p\n", device, wine_dbgstr_longlong(handle), allocator); + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + if (!handle) + return; + + WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, dev_mem); + device->funcs.p_vkFreeMemory(device->device, dev_mem->dev_mem, NULL); + if (dev_mem->handle != INVALID_HANDLE_VALUE) + NtClose(dev_mem->handle); + free(dev_mem); +} + +VkResult WINAPI wine_vkGetMemoryWin32HandlePropertiesKHR(VkDevice device, + VkExternalMemoryHandleTypeFlagBits type, HANDLE handle, VkMemoryWin32HandlePropertiesKHR *properties) +{ + TRACE("%p %u %p %p\n", device, type, handle, properties); + + /* VUID-vkGetMemoryWin32HandlePropertiesKHR-handleType-00666 + handleType must not be one of the handle types defined as opaque */ + return VK_ERROR_INVALID_EXTERNAL_HANDLE; +} + +VkResult WINAPI wine_vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *create_info, + const VkAllocationCallbacks *allocator, VkBuffer *buffer) +{ + VkExternalMemoryBufferCreateInfo *external_memory_info; + VkBufferCreateInfo create_info_dup; + VkResult res; + +#if defined(USE_STRUCT_CONVERSION) + VkBufferCreateInfo_host create_info_host; +#else + VkBufferCreateInfo create_info_host; +#endif + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + if ((res = convert_VkBufferCreateInfo_struct_chain(create_info->pNext, &create_info_dup))) + { + WARN("Failed to convert VkBufferCreateInfo pNext chain, res=%d.\n", res); + return res; + } + + if ((external_memory_info = wine_vk_find_struct(&create_info_dup, EXTERNAL_MEMORY_BUFFER_CREATE_INFO)) && + external_memory_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR) + external_memory_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; + + create_info_host.pNext = create_info_dup.pNext; + create_info_host.sType = create_info->sType; + create_info_host.flags = create_info->flags; + create_info_host.size = create_info->size; + create_info_host.usage = create_info->usage; + create_info_host.sharingMode = create_info->sharingMode; + create_info_host.queueFamilyIndexCount = create_info->queueFamilyIndexCount; + create_info_host.pQueueFamilyIndices = create_info->pQueueFamilyIndices; + + res = device->funcs.p_vkCreateBuffer(device->device, &create_info_host, NULL, buffer); + + free_VkBufferCreateInfo_struct_chain(&create_info_dup); + + return res; +} + +VkResult WINAPI wine_vkCreateImage(VkDevice device, const VkImageCreateInfo *create_info, + const VkAllocationCallbacks *allocator, VkBuffer *image) +{ + VkExternalMemoryImageCreateInfo *external_memory_info; + VkImageCreateInfo create_info_host; + VkResult res; + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + if ((res = convert_VkImageCreateInfo_struct_chain(create_info->pNext, &create_info_host))) + { + WARN("Failed to convert VkImageCreateInfo pNext chain, res=%d.\n", res); + return res; + } + + if ((external_memory_info = wine_vk_find_struct(&create_info_host, EXTERNAL_MEMORY_BUFFER_CREATE_INFO)) && + external_memory_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR) + external_memory_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; + + res = device->funcs.p_vkCreateImage(device->device, &create_info_host, NULL, image); + + free_VkImageCreateInfo_struct_chain(&create_info_host); + + return res; +} diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 83dc90ca15e..4a20702d43b 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -204,6 +204,30 @@ static inline VkSurfaceKHR wine_surface_to_handle(struct wine_surface *surface) return (VkSurfaceKHR)(uintptr_t)surface; }
+struct wine_dev_mem +{ + VkDeviceMemory dev_mem; + + VkExternalMemoryHandleTypeFlagBits handle_types; + + BOOL inherit; + DWORD access; + + HANDLE handle; + + struct wine_vk_mapping mapping; +}; + +static inline struct wine_dev_mem *wine_dev_mem_from_handle(VkDeviceMemory handle) +{ + return (struct wine_dev_mem *)(uintptr_t)handle; +} + +static inline VkDeviceMemory wine_dev_mem_to_handle(struct wine_dev_mem *dev_mem) +{ + return (VkDeviceMemory)(uintptr_t)dev_mem; +} + BOOL wine_vk_device_extension_supported(const char *name) DECLSPEC_HIDDEN; BOOL wine_vk_instance_extension_supported(const char *name) DECLSPEC_HIDDEN;
On 5/17/21 1:01 PM, Derek Lesho wrote:
Signed-off-by: Derek Lesho dlesho@codeweavers.com
v2: Addressed comments from mailing list and discord.
You should be encouraging people giving feedback on Discord to reply to your patches here on wine-devel.
dlls/vulkan-1/tests/vulkan.c | 216 ++++++++++++++++
This patch is very large. Would it make sense to split off the test to a separate commit to make review easier? (although I guess there's no overlap between the test code and the winevulkan code)
dlls/winevulkan/make_vulkan | 26 +- dlls/winevulkan/vulkan.c | 406 +++++++++++++++++++++++++++++--
From skimming through this patch I think you could split off the code that handles buffer/image/memory creation/allocation into a separate patch that goes before support for VK_EXT_external_memory_win32. Having more granular commits here would make it easier to review, and also lower the surface area for regressions in each commit, making it easier to fix/revert if/when bugs do sneak in.
I haven't reviewed the changes below in-detail yet and have no comments for them at this time, sorry I'll see if I have more time to look at this (or a later revision) later in the week.
Thanks,
Liam Middlebrook
dlls/winevulkan/vulkan_private.h | 24 ++ 4 files changed, 645 insertions(+), 27 deletions(-)
diff --git a/dlls/vulkan-1/tests/vulkan.c b/dlls/vulkan-1/tests/vulkan.c index 1d23c4112cf..718937e2222 100644 --- a/dlls/vulkan-1/tests/vulkan.c +++ b/dlls/vulkan-1/tests/vulkan.c @@ -546,6 +546,221 @@ static void test_null_hwnd(VkInstance vk_instance, VkPhysicalDevice vk_physical_ vkDestroySurfaceKHR(vk_instance, surface, NULL); }
+uint32_t find_memory_type(VkPhysicalDevice vk_physical_device, VkMemoryPropertyFlagBits flags) +{
- VkPhysicalDeviceMemoryProperties properties = {0};
- unsigned int i;
- vkGetPhysicalDeviceMemoryProperties(vk_physical_device, &properties);
- for(i = 0; i < properties.memoryTypeCount; i++)
- {
if (properties.memoryTypes[i].propertyFlags & flags)
return i;
- }
- return -1;
+}
+static const char *test_external_memory_extensions[] = +{
- "VK_KHR_external_memory_capabilities",
+};
+static void test_external_memory(VkInstance vk_instance, VkPhysicalDevice vk_physical_device) +{
- PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR;
- PFN_vkGetMemoryWin32HandleKHR pfn_vkGetMemoryWin32HandleKHR;
- VkPhysicalDeviceExternalBufferInfoKHR external_buffer_info;
- VkExternalBufferPropertiesKHR external_buffer_properties;
- VkMemoryDedicatedAllocateInfoKHR dedicated_alloc_info;
- VkExportMemoryWin32HandleInfoKHR export_handle_info;
- VkImportMemoryWin32HandleInfoKHR import_handle_info;
- VkExportMemoryAllocateInfoKHR export_memory_info;
- VkMemoryGetWin32HandleInfoKHR get_handle_info;
- VkBufferCreateInfo buffer_create_info;
- VkMemoryAllocateInfo alloc_info;
- uint32_t queue_family_index;
- HANDLE nt_handle, kmt_handle;
- VkDeviceMemory vk_memory, vk_memory_import;
- VkBuffer vk_buffer;
- VkDevice vk_device;
- VkResult vr;
- static const char *extensions[] =
- {
"VK_KHR_dedicated_allocation",
"VK_KHR_external_memory",
"VK_KHR_external_memory_win32",
- };
- pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR =
(void*) vkGetInstanceProcAddr(vk_instance, "vkGetPhysicalDeviceExternalBufferPropertiesKHR");
- if ((vr = create_device(vk_physical_device, ARRAY_SIZE(extensions), extensions, NULL, &vk_device)))
- {
skip("Failed to create device with external memory extensions, VkResult %d.\n", vr);
return;
- }
- pfn_vkGetMemoryWin32HandleKHR = (void *) vkGetDeviceProcAddr(vk_device, "vkGetMemoryWin32HandleKHR");
- find_queue_family(vk_physical_device, VK_QUEUE_GRAPHICS_BIT, &queue_family_index);
- /* Most implementations only support exporting dedicated allocations */
- buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
- buffer_create_info.pNext = NULL;
- buffer_create_info.flags = 0;
- buffer_create_info.size = 1;
- buffer_create_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
- buffer_create_info.sharingMode = VK_SHARING_MODE_CONCURRENT;
- buffer_create_info.queueFamilyIndexCount = 1;
- buffer_create_info.pQueueFamilyIndices = &queue_family_index;
- if ((vr = vkCreateBuffer(vk_device, &buffer_create_info, NULL, &vk_buffer)))
- {
skip("Failed to create generic buffer, VkResult %d.\n", vr);
vkDestroyDevice(vk_device, NULL);
return;
- }
- dedicated_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR;
- dedicated_alloc_info.pNext = NULL;
- dedicated_alloc_info.image = VK_NULL_HANDLE;
- dedicated_alloc_info.buffer = vk_buffer;
- external_buffer_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR;
- external_buffer_info.pNext = NULL;
- external_buffer_info.flags = 0;
- external_buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
- external_buffer_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
- memset(&external_buffer_properties, 0, sizeof(external_buffer_properties));
- external_buffer_properties.sType = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR;
- pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR(vk_physical_device, &external_buffer_info, &external_buffer_properties);
- if (!(external_buffer_properties.externalMemoryProperties.externalMemoryFeatures &
(VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR|VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR)))
skip("With desired parameters, buffers are not exportable to and importable from an NT handle.\n");
- else
- {
ok(external_buffer_properties.externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR,
"Unexpected compatibleHandleTypes %#x.\n", external_buffer_properties.externalMemoryProperties.compatibleHandleTypes);
export_memory_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;
export_memory_info.pNext = &dedicated_alloc_info;
export_memory_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
export_handle_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR;
export_handle_info.pNext = &export_memory_info;
export_handle_info.name = L"wine_test_buffer_export_name";
export_handle_info.dwAccess = GENERIC_ALL;
export_handle_info.pAttributes = NULL;
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.pNext = &export_handle_info;
alloc_info.allocationSize = 1;
alloc_info.memoryTypeIndex = find_memory_type(vk_physical_device, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
ok(alloc_info.memoryTypeIndex != -1, "Device local memory type index was not found.\n");
vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory);
ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
get_handle_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR;
get_handle_info.pNext = NULL;
get_handle_info.memory = vk_memory;
get_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
vr = pfn_vkGetMemoryWin32HandleKHR(vk_device, &get_handle_info, &nt_handle);
ok(vr == VK_SUCCESS, "vkGetMemoryWin32HandleKHR failed, VkResult %d.\n", vr);
import_handle_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR;
import_handle_info.pNext = &dedicated_alloc_info;
import_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
import_handle_info.handle = nt_handle;
import_handle_info.name = NULL;
alloc_info.pNext = &import_handle_info;
vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import);
ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
ok(vk_memory_import != vk_memory, "Expected new memory object.\n");
vkFreeMemory(vk_device, vk_memory_import, NULL);
import_handle_info.handle = NULL;
import_handle_info.name = L"wine_test_buffer_export_name";
vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import);
- todo_wine
ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
if (vr == VK_SUCCESS)
{
ok(vk_memory_import != vk_memory, "Expected new memory object.\n");
vkFreeMemory(vk_device, vk_memory_import, NULL);
}
vkFreeMemory(vk_device, vk_memory, NULL);
CloseHandle(nt_handle);
- }
- external_buffer_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
- memset(&external_buffer_properties, 0, sizeof(external_buffer_properties));
- external_buffer_properties.sType = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR;
- pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR(vk_physical_device, &external_buffer_info, &external_buffer_properties);
- if (!(external_buffer_properties.externalMemoryProperties.externalMemoryFeatures &
(VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR|VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR)))
skip("With desired parameters, buffers are not exportable to and importable from a KMT handle.\n");
- else
- {
ok(external_buffer_properties.externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR,
"Unexpected compatibleHandleTypes %#x.\n", external_buffer_properties.externalMemoryProperties.compatibleHandleTypes);
export_memory_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;
export_memory_info.pNext = &dedicated_alloc_info;
export_memory_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.pNext = &export_memory_info;
alloc_info.allocationSize = 1;
alloc_info.memoryTypeIndex = find_memory_type(vk_physical_device, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
ok(alloc_info.memoryTypeIndex != -1, "Device local memory type index was not found.\n");
vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory);
ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
get_handle_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR;
get_handle_info.pNext = NULL;
get_handle_info.memory = vk_memory;
get_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
vr = pfn_vkGetMemoryWin32HandleKHR(vk_device, &get_handle_info, &kmt_handle);
ok(vr == VK_SUCCESS, "vkGetMemoryWin32HandleKHR failed, VkResult %d.\n", vr);
import_handle_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR;
import_handle_info.pNext = &dedicated_alloc_info;
import_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
import_handle_info.handle = kmt_handle;
import_handle_info.name = NULL;
alloc_info.pNext = &import_handle_info;
vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import);
ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
ok(vk_memory_import != vk_memory, "Expected new memory object.\n");
vkFreeMemory(vk_device, vk_memory_import, NULL);
vkFreeMemory(vk_device, vk_memory, NULL);
- }
- vkDestroyBuffer(vk_device, vk_buffer, NULL);
- vkDestroyDevice(vk_device, NULL);
+}
- static void for_each_device_instance(uint32_t extension_count, const char * const *enabled_extensions, void (*test_func_instance)(VkInstance, VkPhysicalDevice), void (*test_func)(VkPhysicalDevice)) {
@@ -602,4 +817,5 @@ START_TEST(vulkan) for_each_device(test_unsupported_device_extensions); for_each_device(test_private_data); for_each_device_instance(ARRAY_SIZE(test_null_hwnd_extensions), test_null_hwnd_extensions, test_null_hwnd, NULL);
- for_each_device_instance(ARRAY_SIZE(test_external_memory_extensions), test_external_memory_extensions, test_external_memory, NULL); }
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 7e1d7c0f043..b36275ba75f 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -99,7 +99,6 @@ UNSUPPORTED_EXTENSIONS = [ "VK_EXT_pipeline_creation_feedback", "VK_GOOGLE_display_timing", "VK_KHR_external_fence_win32",
- "VK_KHR_external_memory_win32", "VK_KHR_external_semaphore_win32", # Relates to external_semaphore and needs type conversions in bitflags. "VK_KHR_shared_presentable_image", # Needs WSI work.
@@ -109,7 +108,6 @@ UNSUPPORTED_EXTENSIONS = [ "VK_EXT_external_memory_dma_buf", "VK_EXT_image_drm_format_modifier", "VK_KHR_external_fence_fd",
"VK_KHR_external_memory_fd", "VK_KHR_external_semaphore_fd",
# Extensions which require callback handling
@@ -121,7 +119,9 @@ UNSUPPORTED_EXTENSIONS = [ ]
# Extensions which aren't present on the win32 platform, but which winevulkan may use. -UNEXPOSED_EXTENSIONS = [] +UNEXPOSED_EXTENSIONS = [
- "VK_KHR_external_memory_fd",
+]
# The Vulkan loader provides entry-points for core functionality and important # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51. @@ -179,7 +179,7 @@ FUNCTION_OVERRIDES = { "vkEnumerateDeviceLayerProperties": {"dispatch": True, "driver": False, "thunk": ThunkType.NONE}, "vkEnumeratePhysicalDeviceGroups" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
- "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
- "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
@@ -188,10 +188,14 @@ FUNCTION_OVERRIDES = {
# Device functions "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
- "vkAllocateMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
- "vkCreateBuffer" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
- "vkCreateImage" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
- "vkFreeMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE}, "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetDeviceQueue2" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
@@ -221,7 +225,7 @@ FUNCTION_OVERRIDES = { "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
# VK_KHR_external_memory_capabilities
- "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
"vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
# VK_KHR_external_semaphore_capabilities
@@ -257,12 +261,22 @@ FUNCTION_OVERRIDES = { # VK_EXT_debug_marker "vkDebugMarkerSetObjectNameEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkDebugMarkerSetObjectTagEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
# VK_KHR_external_memory_win32
"vkGetMemoryWin32HandleKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
"vkGetMemoryWin32HandlePropertiesKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, }
STRUCT_CHAIN_CONVERSIONS = { # Ignore to not confuse host loader. "VkDeviceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO"], "VkInstanceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO"],
# Structs which require pNext chain modification
"VkBufferCreateInfo": [],
"VkImageCreateInfo": [],
"VkMemoryAllocateInfo": ["VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR", "VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR"],
"VkPhysicalDeviceImageFormatInfo2": [], }
@@ -1052,6 +1066,8 @@ class VkHandle(object): return "wine_debug_report_callback_from_handle({0})->debug_callback".format(name) if self.name == "VkSurfaceKHR": return "wine_surface_from_handle({0})->surface".format(name)
if self.name == "VkDeviceMemory":
return "wine_dev_mem_from_handle({0})->dev_mem".format(name) native_handle_name = None
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 9f181d92bc5..c2069b77ef2 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -25,6 +25,7 @@ #include <time.h> #include <stdarg.h> #include <stdlib.h> +#include <unistd.h>
#include "ntstatus.h" #define WIN32_NO_STATUS @@ -34,6 +35,8 @@ #include "winuser.h" #include "winternl.h"
+#include "wine/server.h"
#include "vulkan_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
@@ -263,6 +266,15 @@ static struct VkPhysicalDevice_T *wine_vk_physical_device_alloc(struct VkInstanc */ for (i = 0; i < num_host_properties; i++) {
if (!strcmp(host_properties[i].extensionName, "VK_KHR_external_memory_fd"))
{
TRACE("Substituting VK_KHR_external_memory_fd for VK_KHR_external_memory_win32\n");
snprintf(host_properties[i].extensionName, sizeof(host_properties[i].extensionName),
VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME);
host_properties[i].specVersion = VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION;
}
if (wine_vk_device_extension_supported(host_properties[i].extensionName)) { TRACE("Enabling extension '%s' for physical device %p\n", host_properties[i].extensionName, object);
@@ -361,11 +373,15 @@ static void wine_vk_device_get_queues(struct VkDevice_T *device, static void wine_vk_device_free_create_info(VkDeviceCreateInfo *create_info) { free_VkDeviceCreateInfo_struct_chain(create_info);
if (create_info->enabledExtensionCount)
free((void *)create_info->ppEnabledExtensionNames);
}
static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src, VkDeviceCreateInfo *dst) {
const char **enabled_extensions; unsigned int i; VkResult res;
@@ -389,11 +405,34 @@ static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src if (!wine_vk_device_extension_supported(extension_name)) { WARN("Extension %s is not supported.\n", debugstr_a(extension_name));
wine_vk_device_free_create_info(dst);
free_VkDeviceCreateInfo_struct_chain(dst); return VK_ERROR_EXTENSION_NOT_PRESENT; } }
if (src->enabledExtensionCount > 0)
{
enabled_extensions = calloc(src->enabledExtensionCount, sizeof(*src->ppEnabledExtensionNames));
if (!enabled_extensions)
{
free_VkDeviceCreateInfo_struct_chain(dst);
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
for (i = 0; i < src->enabledExtensionCount; i++)
{
if (!strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_memory_win32"))
{
enabled_extensions[i] = "VK_KHR_external_memory_fd";
}
else
{
enabled_extensions[i] = src->ppEnabledExtensionNames[i];
}
}
dst->ppEnabledExtensionNames = enabled_extensions;
}
return VK_SUCCESS;
}
@@ -1190,57 +1229,100 @@ void WINAPI wine_vkGetPhysicalDeviceExternalFencePropertiesKHR(VkPhysicalDevice void WINAPI wine_vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice phys_dev, const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties) {
- VkPhysicalDeviceExternalBufferInfo buffer_info_dup = *buffer_info;
TRACE("%p, %p, %p\n", phys_dev, buffer_info, properties);
- memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties));
if (buffer_info_dup.handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)
buffer_info_dup.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
thunk_vkGetPhysicalDeviceExternalBufferProperties(phys_dev, &buffer_info_dup, properties);
if (properties->externalMemoryProperties.exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
properties->externalMemoryProperties.exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
if (properties->externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
properties->externalMemoryProperties.compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
}
void WINAPI wine_vkGetPhysicalDeviceExternalBufferPropertiesKHR(VkPhysicalDevice phys_dev, const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties) {
VkPhysicalDeviceExternalBufferInfo buffer_info_dup = *buffer_info;
TRACE("%p, %p, %p\n", phys_dev, buffer_info, properties);
- memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties));
- if (buffer_info_dup.handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)
buffer_info_dup.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
- thunk_vkGetPhysicalDeviceExternalBufferPropertiesKHR(phys_dev, &buffer_info_dup, properties);
- if (properties->externalMemoryProperties.exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
properties->externalMemoryProperties.exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
- if (properties->externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
}properties->externalMemoryProperties.compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
-VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev, +static VkResult wine_vk_get_physical_device_image_format_properties_2(VkPhysicalDevice phys_dev,
{VkResult (*p_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice, const VkPhysicalDeviceImageFormatInfo2 *, VkImageFormatProperties2 *), const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties)
- VkPhysicalDeviceExternalImageFormatInfo *external_image_info_dup = NULL;
- const VkPhysicalDeviceExternalImageFormatInfo *external_image_info;
- VkPhysicalDeviceImageFormatInfo2 format_info_host = *format_info; VkExternalImageFormatProperties *external_image_properties; VkResult res;
- TRACE("%p, %p, %p\n", phys_dev, format_info, properties);
- if ((external_image_info = wine_vk_find_struct(format_info, PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO)))
- {
if (external_image_info->handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)
{
if ((res = convert_VkPhysicalDeviceImageFormatInfo2_struct_chain(format_info->pNext, &format_info_host)) < 0)
{
WARN("Failed to convert VkPhysicalDeviceImageFormatInfo2 pNext chain, res=%d.\n", res);
return res;
}
- res = thunk_vkGetPhysicalDeviceImageFormatProperties2(phys_dev, format_info, properties);
external_image_info_dup = wine_vk_find_struct(&format_info_host, PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO);
external_image_info_dup->handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
}
if (external_image_info->handleType &~ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)
{
WARN("Unsupported handle type %#x.\n", external_image_info->handleType);
return VK_ERROR_FORMAT_NOT_SUPPORTED;
}
}
res = p_vkGetPhysicalDeviceImageFormatProperties2(phys_dev, &format_info_host, properties);
if (external_image_info_dup)
free_VkPhysicalDeviceImageFormatInfo2_struct_chain(&format_info_host); if ((external_image_properties = wine_vk_find_struct(properties, EXTERNAL_IMAGE_FORMAT_PROPERTIES))) { VkExternalMemoryProperties *p = &external_image_properties->externalMemoryProperties;
p->externalMemoryFeatures = 0;
p->exportFromImportedHandleTypes = 0;
p->compatibleHandleTypes = 0;
if (p->exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
p->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
if (p->compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
p->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; } return res;
}
-VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice phys_dev, +VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev, const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties) {
VkExternalImageFormatProperties *external_image_properties;
VkResult res;
TRACE("%p, %p, %p\n", phys_dev, format_info, properties);
res = thunk_vkGetPhysicalDeviceImageFormatProperties2KHR(phys_dev, format_info, properties);
- return wine_vk_get_physical_device_image_format_properties_2(phys_dev, thunk_vkGetPhysicalDeviceImageFormatProperties2, format_info, properties);
+}
- if ((external_image_properties = wine_vk_find_struct(properties, EXTERNAL_IMAGE_FORMAT_PROPERTIES)))
- {
VkExternalMemoryProperties *p = &external_image_properties->externalMemoryProperties;
p->externalMemoryFeatures = 0;
p->exportFromImportedHandleTypes = 0;
p->compatibleHandleTypes = 0;
- }
+VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice phys_dev,
const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties)
+{
- TRACE("%p, %p, %p\n", phys_dev, format_info, properties);
- return res;
return wine_vk_get_physical_device_image_format_properties_2(phys_dev, thunk_vkGetPhysicalDeviceImageFormatProperties2KHR, format_info, properties); }
/* From ntdll/unix/sync.c */
@@ -1720,3 +1802,283 @@ VkResult WINAPI wine_vkDebugMarkerSetObjectNameEXT(VkDevice device, const VkDebu
return thunk_vkDebugMarkerSetObjectNameEXT(device, &wine_name_info);
}
+static HANDLE create_gpu_resource(int fd, LPCWSTR name) +{
- HANDLE ret = INVALID_HANDLE_VALUE;
- if (name)
FIXME("Naming gpu resources not supported.\n");
- wine_server_fd_to_handle(fd, GENERIC_ALL, 0, &ret);
- return ret;
+}
+VkResult WINAPI wine_vkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *allocate_info,
- const VkAllocationCallbacks *allocator, VkDeviceMemory *memory)
+{
- const VkImportMemoryWin32HandleInfoKHR *handle_import_info;
- const VkExportMemoryWin32HandleInfoKHR *handle_export_info;
- VkMemoryAllocateInfo allocate_info_dup = *allocate_info;
- VkExportMemoryAllocateInfo *export_info;
- VkImportMemoryFdInfoKHR fd_import_info;
- struct wine_dev_mem *object;
- VkResult res;
- int fd;
+#if defined(USE_STRUCT_CONVERSION)
VkMemoryAllocateInfo_host allocate_info_host;
VkMemoryGetFdInfoKHR_host get_fd_info;
+#else
VkMemoryAllocateInfo allocate_info_host;
VkMemoryGetFdInfoKHR get_fd_info;
+#endif
- TRACE("%p %p %p %p\n", device, allocate_info, allocator, memory);
- if (allocator)
FIXME("Support for allocation callbacks not implemented yet\n");
- if ((res = convert_VkMemoryAllocateInfo_struct_chain(allocate_info->pNext, &allocate_info_dup)) < 0)
- {
WARN("Failed to convert VkMemoryAllocateInfo pNext chain, res=%d.\n", res);
return res;
- }
- if (!(object = calloc(1, sizeof(*object))))
- {
free_VkMemoryAllocateInfo_struct_chain(&allocate_info_dup);
return VK_ERROR_OUT_OF_HOST_MEMORY;
- }
- object->dev_mem = VK_NULL_HANDLE;
- object->handle = INVALID_HANDLE_VALUE;
- fd_import_info.fd = -1;
- fd_import_info.pNext = NULL;
- /* find and process handle import/export info and grab it */
- handle_import_info = wine_vk_find_struct(allocate_info, IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR);
- handle_export_info = wine_vk_find_struct(allocate_info, EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR);
- if (handle_export_info && handle_export_info->pAttributes && handle_export_info->pAttributes->lpSecurityDescriptor)
FIXME("Support for custom security descriptor not implemented.\n");
- if ((export_info = wine_vk_find_struct(&allocate_info_dup, EXPORT_MEMORY_ALLOCATE_INFO)))
- {
object->handle_types = export_info->handleTypes;
if (object->handle_types &~ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)
{
res = VK_ERROR_OUT_OF_HOST_MEMORY;
goto done;
}
if (object->handle_types)
export_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
- }
- /* Vulkan consumes imported FDs, but not imported HANDLEs */
- if (handle_import_info)
- {
fd_import_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
fd_import_info.pNext = allocate_info_dup.pNext;
fd_import_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
switch (handle_import_info->handleType)
{
case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT:
if (handle_import_info->handle)
NtDuplicateObject( NtCurrentProcess(), handle_import_info->handle, NtCurrentProcess(), &object->handle, 0, 0, DUPLICATE_SAME_ACCESS );
else if (handle_import_info->name)
FIXME("Importing device memory by resource name not supported.\n");
break;
default:
WARN("Invalid handle type %08x passed in.\n", handle_import_info->handleType);
res = VK_ERROR_INVALID_EXTERNAL_HANDLE;
goto done;
}
if (object->handle != INVALID_HANDLE_VALUE)
wine_server_handle_to_fd(object->handle, FILE_READ_DATA, &fd_import_info.fd, NULL);
if (fd_import_info.fd == -1)
{
TRACE("Couldn't access resource handle or name. type=%08x handle=%p name=%s\n", handle_import_info->handleType, handle_import_info->handle,
handle_import_info->name ? debugstr_w(handle_import_info->name) : "");
res = VK_ERROR_INVALID_EXTERNAL_HANDLE;
goto done;
}
- }
- allocate_info_host.sType = allocate_info_dup.sType;
- allocate_info_host.pNext = fd_import_info.fd == -1 ? allocate_info_dup.pNext : &fd_import_info;
- allocate_info_host.allocationSize = allocate_info_dup.allocationSize;
- allocate_info_host.memoryTypeIndex = allocate_info_dup.memoryTypeIndex;
- if ((res = device->funcs.p_vkAllocateMemory(device->device, &allocate_info_host, NULL, &object->dev_mem)) == VK_SUCCESS)
- {
if (object->handle == INVALID_HANDLE_VALUE && export_info && export_info->handleTypes)
{
get_fd_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR;
get_fd_info.pNext = NULL;
get_fd_info.memory = object->dev_mem;
get_fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
if (device->funcs.p_vkGetMemoryFdKHR(device->device, &get_fd_info, &fd) == VK_SUCCESS)
{
object->handle = create_gpu_resource(fd, handle_export_info ? handle_export_info->name : NULL);
object->access = handle_export_info ? handle_export_info->dwAccess : GENERIC_ALL;
if (handle_export_info && handle_export_info->pAttributes)
object->inherit = handle_export_info->pAttributes->bInheritHandle;
else
object->inherit = FALSE;
close(fd);
}
if (object->handle == INVALID_HANDLE_VALUE)
{
res = VK_ERROR_OUT_OF_HOST_MEMORY;
goto done;
}
}
WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(device->phys_dev->instance, object, object->dev_mem);
*memory = wine_dev_mem_to_handle(object);
- }
- done:
- if (res != VK_SUCCESS)
- {
device->funcs.p_vkFreeMemory(device->device, object->dev_mem, NULL);
if (fd_import_info.fd != -1)
close(fd_import_info.fd);
if (object->handle != INVALID_HANDLE_VALUE)
NtClose(object->handle);
free(object);
- }
- free_VkMemoryAllocateInfo_struct_chain(&allocate_info_dup);
- return res;
+}
+VkResult WINAPI wine_vkGetMemoryWin32HandleKHR(VkDevice device,
- const VkMemoryGetWin32HandleInfoKHR *handle_info, HANDLE *handle)
+{
- struct wine_dev_mem *dev_mem = wine_dev_mem_from_handle(handle_info->memory);
- const VkBaseInStructure *chain;
- TRACE("%p, %p %p\n", device, handle_info, handle);
- if (!(dev_mem->handle_types & handle_info->handleType))
return VK_ERROR_OUT_OF_HOST_MEMORY;
- if ((chain = handle_info->pNext))
FIXME("Ignoring a linked structure of type %u.\n", chain->sType);
- switch(handle_info->handleType)
- {
case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT:
return !NtDuplicateObject( NtCurrentProcess(), dev_mem->handle, NtCurrentProcess(), handle, dev_mem->access, dev_mem->inherit ? OBJ_INHERIT : 0, 0) ?
VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY;
default:
return VK_ERROR_UNKNOWN;
- }
+}
+void WINAPI wine_vkFreeMemory(VkDevice device, VkDeviceMemory handle, const VkAllocationCallbacks *allocator) +{
- struct wine_dev_mem *dev_mem = wine_dev_mem_from_handle(handle);
- TRACE("%p 0x%s, %p\n", device, wine_dbgstr_longlong(handle), allocator);
- if (allocator)
FIXME("Support for allocation callbacks not implemented yet\n");
- if (!handle)
return;
- WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, dev_mem);
- device->funcs.p_vkFreeMemory(device->device, dev_mem->dev_mem, NULL);
- if (dev_mem->handle != INVALID_HANDLE_VALUE)
NtClose(dev_mem->handle);
- free(dev_mem);
+}
+VkResult WINAPI wine_vkGetMemoryWin32HandlePropertiesKHR(VkDevice device,
VkExternalMemoryHandleTypeFlagBits type, HANDLE handle, VkMemoryWin32HandlePropertiesKHR *properties)
+{
- TRACE("%p %u %p %p\n", device, type, handle, properties);
- /* VUID-vkGetMemoryWin32HandlePropertiesKHR-handleType-00666
handleType must not be one of the handle types defined as opaque */
- return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+}
+VkResult WINAPI wine_vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *create_info,
- const VkAllocationCallbacks *allocator, VkBuffer *buffer)
+{
- VkExternalMemoryBufferCreateInfo *external_memory_info;
- VkBufferCreateInfo create_info_dup;
- VkResult res;
+#if defined(USE_STRUCT_CONVERSION)
- VkBufferCreateInfo_host create_info_host;
+#else
- VkBufferCreateInfo create_info_host;
+#endif
- if (allocator)
FIXME("Support for allocation callbacks not implemented yet\n");
- if ((res = convert_VkBufferCreateInfo_struct_chain(create_info->pNext, &create_info_dup)))
- {
WARN("Failed to convert VkBufferCreateInfo pNext chain, res=%d.\n", res);
return res;
- }
- if ((external_memory_info = wine_vk_find_struct(&create_info_dup, EXTERNAL_MEMORY_BUFFER_CREATE_INFO)) &&
external_memory_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR)
external_memory_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
- create_info_host.pNext = create_info_dup.pNext;
- create_info_host.sType = create_info->sType;
- create_info_host.flags = create_info->flags;
- create_info_host.size = create_info->size;
- create_info_host.usage = create_info->usage;
- create_info_host.sharingMode = create_info->sharingMode;
- create_info_host.queueFamilyIndexCount = create_info->queueFamilyIndexCount;
- create_info_host.pQueueFamilyIndices = create_info->pQueueFamilyIndices;
- res = device->funcs.p_vkCreateBuffer(device->device, &create_info_host, NULL, buffer);
- free_VkBufferCreateInfo_struct_chain(&create_info_dup);
- return res;
+}
+VkResult WINAPI wine_vkCreateImage(VkDevice device, const VkImageCreateInfo *create_info,
- const VkAllocationCallbacks *allocator, VkBuffer *image)
+{
- VkExternalMemoryImageCreateInfo *external_memory_info;
- VkImageCreateInfo create_info_host;
- VkResult res;
- if (allocator)
FIXME("Support for allocation callbacks not implemented yet\n");
- if ((res = convert_VkImageCreateInfo_struct_chain(create_info->pNext, &create_info_host)))
- {
WARN("Failed to convert VkImageCreateInfo pNext chain, res=%d.\n", res);
return res;
- }
- if ((external_memory_info = wine_vk_find_struct(&create_info_host, EXTERNAL_MEMORY_BUFFER_CREATE_INFO)) &&
external_memory_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR)
external_memory_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
- res = device->funcs.p_vkCreateImage(device->device, &create_info_host, NULL, image);
- free_VkImageCreateInfo_struct_chain(&create_info_host);
- return res;
+} diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 83dc90ca15e..4a20702d43b 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -204,6 +204,30 @@ static inline VkSurfaceKHR wine_surface_to_handle(struct wine_surface *surface) return (VkSurfaceKHR)(uintptr_t)surface; }
+struct wine_dev_mem +{
- VkDeviceMemory dev_mem;
- VkExternalMemoryHandleTypeFlagBits handle_types;
- BOOL inherit;
- DWORD access;
- HANDLE handle;
- struct wine_vk_mapping mapping;
+};
+static inline struct wine_dev_mem *wine_dev_mem_from_handle(VkDeviceMemory handle) +{
- return (struct wine_dev_mem *)(uintptr_t)handle;
+}
+static inline VkDeviceMemory wine_dev_mem_to_handle(struct wine_dev_mem *dev_mem) +{
- return (VkDeviceMemory)(uintptr_t)dev_mem;
+}
- BOOL wine_vk_device_extension_supported(const char *name) DECLSPEC_HIDDEN; BOOL wine_vk_instance_extension_supported(const char *name) DECLSPEC_HIDDEN;
On 5/18/21 3:35 AM, Liam Middlebrook wrote:
On 5/17/21 1:01 PM, Derek Lesho wrote:
Signed-off-by: Derek Lesho dlesho@codeweavers.com
v2: Addressed comments from mailing list and discord.
You should be encouraging people giving feedback on Discord to reply to your patches here on wine-devel.
dlls/vulkan-1/tests/vulkan.c | 216 ++++++++++++++++
This patch is very large. Would it make sense to split off the test to a separate commit to make review easier? (although I guess there's no overlap between the test code and the winevulkan code)
The VK_KHR_external_memory_win32 extension has to leave UNSUPPORTED_EXTENSIONS for the tests to compile, as otherwise the necessary definitions aren't present in vulkan.h. Doing this would cause the situation that you indicated you want to avoid, where a extension would be exposed but the functions would all have to be stubs. Alternatively, we could add VK_KHR_external_memory_win32 to WINEVULKAN_INTERNAL_EXTENSIONS in the test commit, to allow the tests to compile and run on windows, then remove in the commit where we actually support it. If we do that, maybe it'd even make more sense to group the tests commit together with the internal extension commit so we don't have dead/unused code, although it might be a bit confusing if we add a new list with the name WINEVULKAN_INTERNAL_EXTENSIONS and have the first extension we add to that be an extension not supported on the host.
dlls/winevulkan/make_vulkan | 26 +- dlls/winevulkan/vulkan.c | 406 +++++++++++++++++++++++++++++--
From skimming through this patch I think you could split off the code that handles buffer/image/memory creation/allocation into a separate patch that goes before support for VK_EXT_external_memory_win32. Having more granular commits here would make it easier to review, and also lower the surface area for regressions in each commit, making it easier to fix/revert if/when bugs do sneak in.
Sounds good, although these will be more "unused helper code" commits in that case.
I haven't reviewed the changes below in-detail yet and have no comments for them at this time, sorry I'll see if I have more time to look at this (or a later revision) later in the week.
Thanks,
Liam Middlebrook
dlls/winevulkan/vulkan_private.h | 24 ++ 4 files changed, 645 insertions(+), 27 deletions(-)
diff --git a/dlls/vulkan-1/tests/vulkan.c b/dlls/vulkan-1/tests/vulkan.c index 1d23c4112cf..718937e2222 100644 --- a/dlls/vulkan-1/tests/vulkan.c +++ b/dlls/vulkan-1/tests/vulkan.c @@ -546,6 +546,221 @@ static void test_null_hwnd(VkInstance vk_instance, VkPhysicalDevice vk_physical_ vkDestroySurfaceKHR(vk_instance, surface, NULL); } +uint32_t find_memory_type(VkPhysicalDevice vk_physical_device, VkMemoryPropertyFlagBits flags) +{ + VkPhysicalDeviceMemoryProperties properties = {0}; + unsigned int i;
+ vkGetPhysicalDeviceMemoryProperties(vk_physical_device, &properties);
+ for(i = 0; i < properties.memoryTypeCount; i++) + { + if (properties.memoryTypes[i].propertyFlags & flags) + return i; + } + return -1; +}
+static const char *test_external_memory_extensions[] = +{ + "VK_KHR_external_memory_capabilities", +};
+static void test_external_memory(VkInstance vk_instance, VkPhysicalDevice vk_physical_device) +{ + PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR; + PFN_vkGetMemoryWin32HandleKHR pfn_vkGetMemoryWin32HandleKHR; + VkPhysicalDeviceExternalBufferInfoKHR external_buffer_info; + VkExternalBufferPropertiesKHR external_buffer_properties; + VkMemoryDedicatedAllocateInfoKHR dedicated_alloc_info; + VkExportMemoryWin32HandleInfoKHR export_handle_info; + VkImportMemoryWin32HandleInfoKHR import_handle_info; + VkExportMemoryAllocateInfoKHR export_memory_info; + VkMemoryGetWin32HandleInfoKHR get_handle_info; + VkBufferCreateInfo buffer_create_info; + VkMemoryAllocateInfo alloc_info; + uint32_t queue_family_index; + HANDLE nt_handle, kmt_handle; + VkDeviceMemory vk_memory, vk_memory_import; + VkBuffer vk_buffer; + VkDevice vk_device; + VkResult vr;
+ static const char *extensions[] = + { + "VK_KHR_dedicated_allocation", + "VK_KHR_external_memory", + "VK_KHR_external_memory_win32", + };
+ pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR = + (void*) vkGetInstanceProcAddr(vk_instance, "vkGetPhysicalDeviceExternalBufferPropertiesKHR");
+ if ((vr = create_device(vk_physical_device, ARRAY_SIZE(extensions), extensions, NULL, &vk_device))) + { + skip("Failed to create device with external memory extensions, VkResult %d.\n", vr); + return; + }
+ pfn_vkGetMemoryWin32HandleKHR = (void *) vkGetDeviceProcAddr(vk_device, "vkGetMemoryWin32HandleKHR");
+ find_queue_family(vk_physical_device, VK_QUEUE_GRAPHICS_BIT, &queue_family_index);
+ /* Most implementations only support exporting dedicated allocations */
+ buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_create_info.pNext = NULL; + buffer_create_info.flags = 0; + buffer_create_info.size = 1; + buffer_create_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + buffer_create_info.sharingMode = VK_SHARING_MODE_CONCURRENT; + buffer_create_info.queueFamilyIndexCount = 1; + buffer_create_info.pQueueFamilyIndices = &queue_family_index; + if ((vr = vkCreateBuffer(vk_device, &buffer_create_info, NULL, &vk_buffer))) + { + skip("Failed to create generic buffer, VkResult %d.\n", vr); + vkDestroyDevice(vk_device, NULL); + return; + }
+ dedicated_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR; + dedicated_alloc_info.pNext = NULL; + dedicated_alloc_info.image = VK_NULL_HANDLE; + dedicated_alloc_info.buffer = vk_buffer;
+ external_buffer_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR; + external_buffer_info.pNext = NULL; + external_buffer_info.flags = 0; + external_buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + external_buffer_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
+ memset(&external_buffer_properties, 0, sizeof(external_buffer_properties)); + external_buffer_properties.sType = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR;
pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR(vk_physical_device, &external_buffer_info, &external_buffer_properties);
+ if (!(external_buffer_properties.externalMemoryProperties.externalMemoryFeatures &
(VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR|VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR))) + skip("With desired parameters, buffers are not exportable to and importable from an NT handle.\n"); + else + {
ok(external_buffer_properties.externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR, + "Unexpected compatibleHandleTypes %#x.\n", external_buffer_properties.externalMemoryProperties.compatibleHandleTypes);
+ export_memory_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR; + export_memory_info.pNext = &dedicated_alloc_info; + export_memory_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
+ export_handle_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR; + export_handle_info.pNext = &export_memory_info; + export_handle_info.name = L"wine_test_buffer_export_name"; + export_handle_info.dwAccess = GENERIC_ALL; + export_handle_info.pAttributes = NULL;
+ alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.pNext = &export_handle_info; + alloc_info.allocationSize = 1; + alloc_info.memoryTypeIndex = find_memory_type(vk_physical_device, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ ok(alloc_info.memoryTypeIndex != -1, "Device local memory type index was not found.\n");
+ vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory); + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
+ get_handle_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR; + get_handle_info.pNext = NULL; + get_handle_info.memory = vk_memory; + get_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
+ vr = pfn_vkGetMemoryWin32HandleKHR(vk_device, &get_handle_info, &nt_handle); + ok(vr == VK_SUCCESS, "vkGetMemoryWin32HandleKHR failed, VkResult %d.\n", vr);
+ import_handle_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR; + import_handle_info.pNext = &dedicated_alloc_info; + import_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR; + import_handle_info.handle = nt_handle; + import_handle_info.name = NULL;
+ alloc_info.pNext = &import_handle_info;
+ vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import); + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr); + ok(vk_memory_import != vk_memory, "Expected new memory object.\n");
+ vkFreeMemory(vk_device, vk_memory_import, NULL);
+ import_handle_info.handle = NULL; + import_handle_info.name = L"wine_test_buffer_export_name";
+ vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import); + todo_wine + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr); + if (vr == VK_SUCCESS) + { + ok(vk_memory_import != vk_memory, "Expected new memory object.\n"); + vkFreeMemory(vk_device, vk_memory_import, NULL); + } + vkFreeMemory(vk_device, vk_memory, NULL); + CloseHandle(nt_handle); + }
+ external_buffer_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
+ memset(&external_buffer_properties, 0, sizeof(external_buffer_properties)); + external_buffer_properties.sType = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR;
pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR(vk_physical_device, &external_buffer_info, &external_buffer_properties);
+ if (!(external_buffer_properties.externalMemoryProperties.externalMemoryFeatures &
(VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR|VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR))) + skip("With desired parameters, buffers are not exportable to and importable from a KMT handle.\n"); + else + {
ok(external_buffer_properties.externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR, + "Unexpected compatibleHandleTypes %#x.\n", external_buffer_properties.externalMemoryProperties.compatibleHandleTypes);
+ export_memory_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR; + export_memory_info.pNext = &dedicated_alloc_info; + export_memory_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
+ alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.pNext = &export_memory_info; + alloc_info.allocationSize = 1; + alloc_info.memoryTypeIndex = find_memory_type(vk_physical_device, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ ok(alloc_info.memoryTypeIndex != -1, "Device local memory type index was not found.\n");
+ vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory); + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
+ get_handle_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR; + get_handle_info.pNext = NULL; + get_handle_info.memory = vk_memory; + get_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
+ vr = pfn_vkGetMemoryWin32HandleKHR(vk_device, &get_handle_info, &kmt_handle); + ok(vr == VK_SUCCESS, "vkGetMemoryWin32HandleKHR failed, VkResult %d.\n", vr);
+ import_handle_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR; + import_handle_info.pNext = &dedicated_alloc_info; + import_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR; + import_handle_info.handle = kmt_handle; + import_handle_info.name = NULL;
+ alloc_info.pNext = &import_handle_info;
+ vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import); + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr); + ok(vk_memory_import != vk_memory, "Expected new memory object.\n");
+ vkFreeMemory(vk_device, vk_memory_import, NULL); + vkFreeMemory(vk_device, vk_memory, NULL); + }
+ vkDestroyBuffer(vk_device, vk_buffer, NULL); + vkDestroyDevice(vk_device, NULL); +}
static void for_each_device_instance(uint32_t extension_count, const char * const *enabled_extensions, void (*test_func_instance)(VkInstance, VkPhysicalDevice), void (*test_func)(VkPhysicalDevice)) { @@ -602,4 +817,5 @@ START_TEST(vulkan) for_each_device(test_unsupported_device_extensions); for_each_device(test_private_data); for_each_device_instance(ARRAY_SIZE(test_null_hwnd_extensions), test_null_hwnd_extensions, test_null_hwnd, NULL);
for_each_device_instance(ARRAY_SIZE(test_external_memory_extensions), test_external_memory_extensions, test_external_memory, NULL); } diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 7e1d7c0f043..b36275ba75f 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -99,7 +99,6 @@ UNSUPPORTED_EXTENSIONS = [ "VK_EXT_pipeline_creation_feedback", "VK_GOOGLE_display_timing", "VK_KHR_external_fence_win32", - "VK_KHR_external_memory_win32", "VK_KHR_external_semaphore_win32", # Relates to external_semaphore and needs type conversions in bitflags. "VK_KHR_shared_presentable_image", # Needs WSI work. @@ -109,7 +108,6 @@ UNSUPPORTED_EXTENSIONS = [ "VK_EXT_external_memory_dma_buf", "VK_EXT_image_drm_format_modifier", "VK_KHR_external_fence_fd", - "VK_KHR_external_memory_fd", "VK_KHR_external_semaphore_fd", # Extensions which require callback handling @@ -121,7 +119,9 @@ UNSUPPORTED_EXTENSIONS = [ ] # Extensions which aren't present on the win32 platform, but which winevulkan may use. -UNEXPOSED_EXTENSIONS = [] +UNEXPOSED_EXTENSIONS = [ + "VK_KHR_external_memory_fd", +] # The Vulkan loader provides entry-points for core functionality and important # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51. @@ -179,7 +179,7 @@ FUNCTION_OVERRIDES = { "vkEnumerateDeviceLayerProperties": {"dispatch": True, "driver": False, "thunk": ThunkType.NONE}, "vkEnumeratePhysicalDeviceGroups" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, - "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, + "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, @@ -188,10 +188,14 @@ FUNCTION_OVERRIDES = { # Device functions "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkAllocateMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkCreateBuffer" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkCreateImage" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkFreeMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE}, "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetDeviceQueue2" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, @@ -221,7 +225,7 @@ FUNCTION_OVERRIDES = { "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, # VK_KHR_external_memory_capabilities - "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, + "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, # VK_KHR_external_semaphore_capabilities @@ -257,12 +261,22 @@ FUNCTION_OVERRIDES = { # VK_EXT_debug_marker "vkDebugMarkerSetObjectNameEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkDebugMarkerSetObjectTagEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
+ # VK_KHR_external_memory_win32 + "vkGetMemoryWin32HandleKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkGetMemoryWin32HandlePropertiesKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, } STRUCT_CHAIN_CONVERSIONS = { # Ignore to not confuse host loader. "VkDeviceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO"], "VkInstanceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO"],
+ # Structs which require pNext chain modification + "VkBufferCreateInfo": [], + "VkImageCreateInfo": [], + "VkMemoryAllocateInfo": ["VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR", "VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR"], + "VkPhysicalDeviceImageFormatInfo2": [], } @@ -1052,6 +1066,8 @@ class VkHandle(object): return "wine_debug_report_callback_from_handle({0})->debug_callback".format(name) if self.name == "VkSurfaceKHR": return "wine_surface_from_handle({0})->surface".format(name) + if self.name == "VkDeviceMemory": + return "wine_dev_mem_from_handle({0})->dev_mem".format(name) native_handle_name = None diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 9f181d92bc5..c2069b77ef2 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -25,6 +25,7 @@ #include <time.h> #include <stdarg.h> #include <stdlib.h> +#include <unistd.h> #include "ntstatus.h" #define WIN32_NO_STATUS @@ -34,6 +35,8 @@ #include "winuser.h" #include "winternl.h" +#include "wine/server.h"
#include "vulkan_private.h" WINE_DEFAULT_DEBUG_CHANNEL(vulkan); @@ -263,6 +266,15 @@ static struct VkPhysicalDevice_T *wine_vk_physical_device_alloc(struct VkInstanc */ for (i = 0; i < num_host_properties; i++) { + if (!strcmp(host_properties[i].extensionName, "VK_KHR_external_memory_fd")) + { + TRACE("Substituting VK_KHR_external_memory_fd for VK_KHR_external_memory_win32\n");
+ snprintf(host_properties[i].extensionName, sizeof(host_properties[i].extensionName),
- VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME);
+ host_properties[i].specVersion = VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION; + }
if (wine_vk_device_extension_supported(host_properties[i].extensionName)) { TRACE("Enabling extension '%s' for physical device %p\n", host_properties[i].extensionName, object); @@ -361,11 +373,15 @@ static void wine_vk_device_get_queues(struct VkDevice_T *device, static void wine_vk_device_free_create_info(VkDeviceCreateInfo *create_info) { free_VkDeviceCreateInfo_struct_chain(create_info);
+ if (create_info->enabledExtensionCount) + free((void *)create_info->ppEnabledExtensionNames); } static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src, VkDeviceCreateInfo *dst) { + const char **enabled_extensions; unsigned int i; VkResult res; @@ -389,11 +405,34 @@ static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src if (!wine_vk_device_extension_supported(extension_name)) { WARN("Extension %s is not supported.\n", debugstr_a(extension_name)); - wine_vk_device_free_create_info(dst); + free_VkDeviceCreateInfo_struct_chain(dst); return VK_ERROR_EXTENSION_NOT_PRESENT; } } + if (src->enabledExtensionCount > 0) + { + enabled_extensions = calloc(src->enabledExtensionCount, sizeof(*src->ppEnabledExtensionNames)); + if (!enabled_extensions) + { + free_VkDeviceCreateInfo_struct_chain(dst); + return VK_ERROR_OUT_OF_HOST_MEMORY; + }
+ for (i = 0; i < src->enabledExtensionCount; i++) + { + if (!strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_memory_win32")) + { + enabled_extensions[i] = "VK_KHR_external_memory_fd"; + } + else + { + enabled_extensions[i] = src->ppEnabledExtensionNames[i]; + } + } + dst->ppEnabledExtensionNames = enabled_extensions; + }
return VK_SUCCESS; } @@ -1190,57 +1229,100 @@ void WINAPI wine_vkGetPhysicalDeviceExternalFencePropertiesKHR(VkPhysicalDevice void WINAPI wine_vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice phys_dev, const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties) { + VkPhysicalDeviceExternalBufferInfo buffer_info_dup = *buffer_info;
TRACE("%p, %p, %p\n", phys_dev, buffer_info, properties); - memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties));
+ if (buffer_info_dup.handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + buffer_info_dup.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
+ thunk_vkGetPhysicalDeviceExternalBufferProperties(phys_dev, &buffer_info_dup, properties);
+ if (properties->externalMemoryProperties.exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
- properties->externalMemoryProperties.exportFromImportedHandleTypes
= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + if (properties->externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
- properties->externalMemoryProperties.compatibleHandleTypes =
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; } void WINAPI wine_vkGetPhysicalDeviceExternalBufferPropertiesKHR(VkPhysicalDevice phys_dev, const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties) { + VkPhysicalDeviceExternalBufferInfo buffer_info_dup = *buffer_info;
TRACE("%p, %p, %p\n", phys_dev, buffer_info, properties); - memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties));
+ if (buffer_info_dup.handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + buffer_info_dup.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
- thunk_vkGetPhysicalDeviceExternalBufferPropertiesKHR(phys_dev,
&buffer_info_dup, properties);
+ if (properties->externalMemoryProperties.exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
- properties->externalMemoryProperties.exportFromImportedHandleTypes
= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + if (properties->externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
- properties->externalMemoryProperties.compatibleHandleTypes =
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; } -VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev, +static VkResult wine_vk_get_physical_device_image_format_properties_2(VkPhysicalDevice phys_dev, + VkResult (*p_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice, const VkPhysicalDeviceImageFormatInfo2 *, VkImageFormatProperties2 *), const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties) { + VkPhysicalDeviceExternalImageFormatInfo *external_image_info_dup = NULL; + const VkPhysicalDeviceExternalImageFormatInfo *external_image_info; + VkPhysicalDeviceImageFormatInfo2 format_info_host = *format_info; VkExternalImageFormatProperties *external_image_properties; VkResult res; - TRACE("%p, %p, %p\n", phys_dev, format_info, properties); + if ((external_image_info = wine_vk_find_struct(format_info, PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO))) + { + if (external_image_info->handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + { + if ((res = convert_VkPhysicalDeviceImageFormatInfo2_struct_chain(format_info->pNext, &format_info_host)) < 0) + { + WARN("Failed to convert VkPhysicalDeviceImageFormatInfo2 pNext chain, res=%d.\n", res); + return res; + } - res = thunk_vkGetPhysicalDeviceImageFormatProperties2(phys_dev, format_info, properties); + external_image_info_dup = wine_vk_find_struct(&format_info_host, PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO); + external_image_info_dup->handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + } + if (external_image_info->handleType &~ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + { + WARN("Unsupported handle type %#x.\n", external_image_info->handleType); + return VK_ERROR_FORMAT_NOT_SUPPORTED; + } + }
+ res = p_vkGetPhysicalDeviceImageFormatProperties2(phys_dev, &format_info_host, properties);
+ if (external_image_info_dup)
- free_VkPhysicalDeviceImageFormatInfo2_struct_chain(&format_info_host);
if ((external_image_properties = wine_vk_find_struct(properties, EXTERNAL_IMAGE_FORMAT_PROPERTIES))) { VkExternalMemoryProperties *p = &external_image_properties->externalMemoryProperties; - p->externalMemoryFeatures = 0; - p->exportFromImportedHandleTypes = 0; - p->compatibleHandleTypes = 0; + if (p->exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) + p->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + if (p->compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) + p->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; } return res; } -VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice phys_dev, +VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev, const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties) { - VkExternalImageFormatProperties *external_image_properties; - VkResult res;
TRACE("%p, %p, %p\n", phys_dev, format_info, properties); - res = thunk_vkGetPhysicalDeviceImageFormatProperties2KHR(phys_dev, format_info, properties); + return wine_vk_get_physical_device_image_format_properties_2(phys_dev, thunk_vkGetPhysicalDeviceImageFormatProperties2, format_info, properties); +} - if ((external_image_properties = wine_vk_find_struct(properties, EXTERNAL_IMAGE_FORMAT_PROPERTIES))) - { - VkExternalMemoryProperties *p = &external_image_properties->externalMemoryProperties; - p->externalMemoryFeatures = 0; - p->exportFromImportedHandleTypes = 0; - p->compatibleHandleTypes = 0; - } +VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice phys_dev, + const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties) +{ + TRACE("%p, %p, %p\n", phys_dev, format_info, properties); - return res; + return wine_vk_get_physical_device_image_format_properties_2(phys_dev, thunk_vkGetPhysicalDeviceImageFormatProperties2KHR, format_info, properties); } /* From ntdll/unix/sync.c */ @@ -1720,3 +1802,283 @@ VkResult WINAPI wine_vkDebugMarkerSetObjectNameEXT(VkDevice device, const VkDebu return thunk_vkDebugMarkerSetObjectNameEXT(device, &wine_name_info); }
+static HANDLE create_gpu_resource(int fd, LPCWSTR name) +{ + HANDLE ret = INVALID_HANDLE_VALUE;
+ if (name) + FIXME("Naming gpu resources not supported.\n");
+ wine_server_fd_to_handle(fd, GENERIC_ALL, 0, &ret);
+ return ret; +}
+VkResult WINAPI wine_vkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *allocate_info, + const VkAllocationCallbacks *allocator, VkDeviceMemory *memory) +{ + const VkImportMemoryWin32HandleInfoKHR *handle_import_info; + const VkExportMemoryWin32HandleInfoKHR *handle_export_info; + VkMemoryAllocateInfo allocate_info_dup = *allocate_info; + VkExportMemoryAllocateInfo *export_info; + VkImportMemoryFdInfoKHR fd_import_info; + struct wine_dev_mem *object; + VkResult res; + int fd;
+#if defined(USE_STRUCT_CONVERSION) + VkMemoryAllocateInfo_host allocate_info_host; + VkMemoryGetFdInfoKHR_host get_fd_info; +#else + VkMemoryAllocateInfo allocate_info_host; + VkMemoryGetFdInfoKHR get_fd_info; +#endif
+ TRACE("%p %p %p %p\n", device, allocate_info, allocator, memory);
+ if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n");
+ if ((res = convert_VkMemoryAllocateInfo_struct_chain(allocate_info->pNext, &allocate_info_dup)) < 0) + { + WARN("Failed to convert VkMemoryAllocateInfo pNext chain, res=%d.\n", res); + return res; + }
+ if (!(object = calloc(1, sizeof(*object)))) + {
- free_VkMemoryAllocateInfo_struct_chain(&allocate_info_dup);
+ return VK_ERROR_OUT_OF_HOST_MEMORY; + }
+ object->dev_mem = VK_NULL_HANDLE; + object->handle = INVALID_HANDLE_VALUE; + fd_import_info.fd = -1; + fd_import_info.pNext = NULL;
+ /* find and process handle import/export info and grab it */ + handle_import_info = wine_vk_find_struct(allocate_info, IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR); + handle_export_info = wine_vk_find_struct(allocate_info, EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR); + if (handle_export_info && handle_export_info->pAttributes && handle_export_info->pAttributes->lpSecurityDescriptor) + FIXME("Support for custom security descriptor not implemented.\n");
+ if ((export_info = wine_vk_find_struct(&allocate_info_dup, EXPORT_MEMORY_ALLOCATE_INFO))) + { + object->handle_types = export_info->handleTypes; + if (object->handle_types &~ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto done; + } + if (object->handle_types) + export_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + }
+ /* Vulkan consumes imported FDs, but not imported HANDLEs */ + if (handle_import_info) + { + fd_import_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; + fd_import_info.pNext = allocate_info_dup.pNext; + fd_import_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
+ switch (handle_import_info->handleType) + { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT: + if (handle_import_info->handle) + NtDuplicateObject( NtCurrentProcess(), handle_import_info->handle, NtCurrentProcess(), &object->handle, 0, 0, DUPLICATE_SAME_ACCESS ); + else if (handle_import_info->name) + FIXME("Importing device memory by resource name not supported.\n"); + break; + default: + WARN("Invalid handle type %08x passed in.\n", handle_import_info->handleType); + res = VK_ERROR_INVALID_EXTERNAL_HANDLE; + goto done; + }
+ if (object->handle != INVALID_HANDLE_VALUE) + wine_server_handle_to_fd(object->handle, FILE_READ_DATA, &fd_import_info.fd, NULL);
+ if (fd_import_info.fd == -1) + { + TRACE("Couldn't access resource handle or name. type=%08x handle=%p name=%s\n", handle_import_info->handleType, handle_import_info->handle, + handle_import_info->name ? debugstr_w(handle_import_info->name) : ""); + res = VK_ERROR_INVALID_EXTERNAL_HANDLE; + goto done; + } + }
+ allocate_info_host.sType = allocate_info_dup.sType; + allocate_info_host.pNext = fd_import_info.fd == -1 ? allocate_info_dup.pNext : &fd_import_info; + allocate_info_host.allocationSize = allocate_info_dup.allocationSize; + allocate_info_host.memoryTypeIndex = allocate_info_dup.memoryTypeIndex;
+ if ((res = device->funcs.p_vkAllocateMemory(device->device, &allocate_info_host, NULL, &object->dev_mem)) == VK_SUCCESS) + { + if (object->handle == INVALID_HANDLE_VALUE && export_info && export_info->handleTypes) + { + get_fd_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR; + get_fd_info.pNext = NULL; + get_fd_info.memory = object->dev_mem; + get_fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
+ if (device->funcs.p_vkGetMemoryFdKHR(device->device, &get_fd_info, &fd) == VK_SUCCESS) + { + object->handle = create_gpu_resource(fd, handle_export_info ? handle_export_info->name : NULL); + object->access = handle_export_info ? handle_export_info->dwAccess : GENERIC_ALL; + if (handle_export_info && handle_export_info->pAttributes) + object->inherit = handle_export_info->pAttributes->bInheritHandle; + else + object->inherit = FALSE; + close(fd); + }
+ if (object->handle == INVALID_HANDLE_VALUE) + { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto done; + } + }
- WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(device->phys_dev->instance,
object, object->dev_mem); + *memory = wine_dev_mem_to_handle(object); + }
+ done:
+ if (res != VK_SUCCESS) + { + device->funcs.p_vkFreeMemory(device->device, object->dev_mem, NULL); + if (fd_import_info.fd != -1) + close(fd_import_info.fd); + if (object->handle != INVALID_HANDLE_VALUE) + NtClose(object->handle); + free(object); + }
- free_VkMemoryAllocateInfo_struct_chain(&allocate_info_dup);
+ return res; +}
+VkResult WINAPI wine_vkGetMemoryWin32HandleKHR(VkDevice device, + const VkMemoryGetWin32HandleInfoKHR *handle_info, HANDLE *handle) +{ + struct wine_dev_mem *dev_mem = wine_dev_mem_from_handle(handle_info->memory); + const VkBaseInStructure *chain;
+ TRACE("%p, %p %p\n", device, handle_info, handle);
+ if (!(dev_mem->handle_types & handle_info->handleType)) + return VK_ERROR_OUT_OF_HOST_MEMORY;
+ if ((chain = handle_info->pNext)) + FIXME("Ignoring a linked structure of type %u.\n", chain->sType);
+ switch(handle_info->handleType) + { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT: + return !NtDuplicateObject( NtCurrentProcess(), dev_mem->handle, NtCurrentProcess(), handle, dev_mem->access, dev_mem->inherit ? OBJ_INHERIT : 0, 0) ? + VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY; + default: + return VK_ERROR_UNKNOWN; + } +}
+void WINAPI wine_vkFreeMemory(VkDevice device, VkDeviceMemory handle, const VkAllocationCallbacks *allocator) +{ + struct wine_dev_mem *dev_mem = wine_dev_mem_from_handle(handle);
+ TRACE("%p 0x%s, %p\n", device, wine_dbgstr_longlong(handle), allocator);
+ if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n");
+ if (!handle) + return;
- WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, dev_mem);
+ device->funcs.p_vkFreeMemory(device->device, dev_mem->dev_mem, NULL); + if (dev_mem->handle != INVALID_HANDLE_VALUE) + NtClose(dev_mem->handle); + free(dev_mem); +}
+VkResult WINAPI wine_vkGetMemoryWin32HandlePropertiesKHR(VkDevice device, + VkExternalMemoryHandleTypeFlagBits type, HANDLE handle, VkMemoryWin32HandlePropertiesKHR *properties) +{ + TRACE("%p %u %p %p\n", device, type, handle, properties);
+ /* VUID-vkGetMemoryWin32HandlePropertiesKHR-handleType-00666 + handleType must not be one of the handle types defined as opaque */ + return VK_ERROR_INVALID_EXTERNAL_HANDLE; +}
+VkResult WINAPI wine_vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *create_info, + const VkAllocationCallbacks *allocator, VkBuffer *buffer) +{ + VkExternalMemoryBufferCreateInfo *external_memory_info; + VkBufferCreateInfo create_info_dup; + VkResult res;
+#if defined(USE_STRUCT_CONVERSION) + VkBufferCreateInfo_host create_info_host; +#else + VkBufferCreateInfo create_info_host; +#endif
+ if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n");
+ if ((res = convert_VkBufferCreateInfo_struct_chain(create_info->pNext, &create_info_dup))) + { + WARN("Failed to convert VkBufferCreateInfo pNext chain, res=%d.\n", res); + return res; + }
+ if ((external_memory_info = wine_vk_find_struct(&create_info_dup, EXTERNAL_MEMORY_BUFFER_CREATE_INFO)) && + external_memory_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR) + external_memory_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+ create_info_host.pNext = create_info_dup.pNext; + create_info_host.sType = create_info->sType; + create_info_host.flags = create_info->flags; + create_info_host.size = create_info->size; + create_info_host.usage = create_info->usage; + create_info_host.sharingMode = create_info->sharingMode; + create_info_host.queueFamilyIndexCount = create_info->queueFamilyIndexCount; + create_info_host.pQueueFamilyIndices = create_info->pQueueFamilyIndices;
+ res = device->funcs.p_vkCreateBuffer(device->device, &create_info_host, NULL, buffer);
+ free_VkBufferCreateInfo_struct_chain(&create_info_dup);
+ return res; +}
+VkResult WINAPI wine_vkCreateImage(VkDevice device, const VkImageCreateInfo *create_info, + const VkAllocationCallbacks *allocator, VkBuffer *image) +{ + VkExternalMemoryImageCreateInfo *external_memory_info; + VkImageCreateInfo create_info_host; + VkResult res;
+ if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n");
+ if ((res = convert_VkImageCreateInfo_struct_chain(create_info->pNext, &create_info_host))) + { + WARN("Failed to convert VkImageCreateInfo pNext chain, res=%d.\n", res); + return res; + }
+ if ((external_memory_info = wine_vk_find_struct(&create_info_host, EXTERNAL_MEMORY_BUFFER_CREATE_INFO)) && + external_memory_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR) + external_memory_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+ res = device->funcs.p_vkCreateImage(device->device, &create_info_host, NULL, image);
+ free_VkImageCreateInfo_struct_chain(&create_info_host);
+ return res; +} diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 83dc90ca15e..4a20702d43b 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -204,6 +204,30 @@ static inline VkSurfaceKHR wine_surface_to_handle(struct wine_surface *surface) return (VkSurfaceKHR)(uintptr_t)surface; } +struct wine_dev_mem +{ + VkDeviceMemory dev_mem;
+ VkExternalMemoryHandleTypeFlagBits handle_types;
+ BOOL inherit; + DWORD access;
+ HANDLE handle;
+ struct wine_vk_mapping mapping; +};
+static inline struct wine_dev_mem *wine_dev_mem_from_handle(VkDeviceMemory handle) +{ + return (struct wine_dev_mem *)(uintptr_t)handle; +}
+static inline VkDeviceMemory wine_dev_mem_to_handle(struct wine_dev_mem *dev_mem) +{ + return (VkDeviceMemory)(uintptr_t)dev_mem; +}
BOOL wine_vk_device_extension_supported(const char *name) DECLSPEC_HIDDEN; BOOL wine_vk_instance_extension_supported(const char *name) DECLSPEC_HIDDEN;
On 5/18/21 7:11 AM, Derek Lesho wrote:
On 5/18/21 3:35 AM, Liam Middlebrook wrote:
On 5/17/21 1:01 PM, Derek Lesho wrote:
Signed-off-by: Derek Lesho dlesho@codeweavers.com
v2: Addressed comments from mailing list and discord.
You should be encouraging people giving feedback on Discord to reply to your patches here on wine-devel.
dlls/vulkan-1/tests/vulkan.c | 216 ++++++++++++++++
This patch is very large. Would it make sense to split off the test to a separate commit to make review easier? (although I guess there's no overlap between the test code and the winevulkan code)
The VK_KHR_external_memory_win32 extension has to leave UNSUPPORTED_EXTENSIONS for the tests to compile, as otherwise the necessary definitions aren't present in vulkan.h. Doing this would cause the situation that you indicated you want to avoid, where a extension would be exposed but the functions would all have to be stubs. Alternatively, we could add VK_KHR_external_memory_win32 to WINEVULKAN_INTERNAL_EXTENSIONS in the test commit, to allow the tests to compile and run on windows, then remove in the commit where we actually support it. If we do that, maybe it'd even make more sense to group the tests commit together with the internal extension commit so we don't have dead/unused code, although it might be a bit confusing if we add a new list with the name WINEVULKAN_INTERNAL_EXTENSIONS and have the first extension we add to that be an extension not supported on the host.
I'm more confused by your description than I was before. Given that the tests stuff is in a separate file/"module" I think it's fine to just leave it in the same commit, nevermind on my feedback on it from before.
dlls/winevulkan/make_vulkan | 26 +- dlls/winevulkan/vulkan.c | 406 +++++++++++++++++++++++++++++--
From skimming through this patch I think you could split off the code that handles buffer/image/memory creation/allocation into a separate patch that goes before support for VK_EXT_external_memory_win32. Having more granular commits here would make it easier to review, and also lower the surface area for regressions in each commit, making it easier to fix/revert if/when bugs do sneak in.
Sounds good, although these will be more "unused helper code" commits in that case.
Will they be? It looks to me like they replace the auto-generated thunks? There's a difference between changes you expect to be a no-op and changes which introduce unused code. As far as I can tell the changes for buffer/image/memory creation/allocation would be used, but are expected to be a no-op.
Thanks,
Liam Middlebrook
I haven't reviewed the changes below in-detail yet and have no comments for them at this time, sorry I'll see if I have more time to look at this (or a later revision) later in the week.
Thanks,
Liam Middlebrook
dlls/winevulkan/vulkan_private.h | 24 ++ 4 files changed, 645 insertions(+), 27 deletions(-)
diff --git a/dlls/vulkan-1/tests/vulkan.c b/dlls/vulkan-1/tests/vulkan.c index 1d23c4112cf..718937e2222 100644 --- a/dlls/vulkan-1/tests/vulkan.c +++ b/dlls/vulkan-1/tests/vulkan.c @@ -546,6 +546,221 @@ static void test_null_hwnd(VkInstance vk_instance, VkPhysicalDevice vk_physical_ vkDestroySurfaceKHR(vk_instance, surface, NULL); } +uint32_t find_memory_type(VkPhysicalDevice vk_physical_device, VkMemoryPropertyFlagBits flags) +{ + VkPhysicalDeviceMemoryProperties properties = {0}; + unsigned int i;
+ vkGetPhysicalDeviceMemoryProperties(vk_physical_device, &properties);
+ for(i = 0; i < properties.memoryTypeCount; i++) + { + if (properties.memoryTypes[i].propertyFlags & flags) + return i; + } + return -1; +}
+static const char *test_external_memory_extensions[] = +{ + "VK_KHR_external_memory_capabilities", +};
+static void test_external_memory(VkInstance vk_instance, VkPhysicalDevice vk_physical_device) +{ + PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR; + PFN_vkGetMemoryWin32HandleKHR pfn_vkGetMemoryWin32HandleKHR; + VkPhysicalDeviceExternalBufferInfoKHR external_buffer_info; + VkExternalBufferPropertiesKHR external_buffer_properties; + VkMemoryDedicatedAllocateInfoKHR dedicated_alloc_info; + VkExportMemoryWin32HandleInfoKHR export_handle_info; + VkImportMemoryWin32HandleInfoKHR import_handle_info; + VkExportMemoryAllocateInfoKHR export_memory_info; + VkMemoryGetWin32HandleInfoKHR get_handle_info; + VkBufferCreateInfo buffer_create_info; + VkMemoryAllocateInfo alloc_info; + uint32_t queue_family_index; + HANDLE nt_handle, kmt_handle; + VkDeviceMemory vk_memory, vk_memory_import; + VkBuffer vk_buffer; + VkDevice vk_device; + VkResult vr;
+ static const char *extensions[] = + { + "VK_KHR_dedicated_allocation", + "VK_KHR_external_memory", + "VK_KHR_external_memory_win32", + };
+ pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR = + (void*) vkGetInstanceProcAddr(vk_instance, "vkGetPhysicalDeviceExternalBufferPropertiesKHR");
+ if ((vr = create_device(vk_physical_device, ARRAY_SIZE(extensions), extensions, NULL, &vk_device))) + { + skip("Failed to create device with external memory extensions, VkResult %d.\n", vr); + return; + }
+ pfn_vkGetMemoryWin32HandleKHR = (void *) vkGetDeviceProcAddr(vk_device, "vkGetMemoryWin32HandleKHR");
+ find_queue_family(vk_physical_device, VK_QUEUE_GRAPHICS_BIT, &queue_family_index);
+ /* Most implementations only support exporting dedicated allocations */
+ buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_create_info.pNext = NULL; + buffer_create_info.flags = 0; + buffer_create_info.size = 1; + buffer_create_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + buffer_create_info.sharingMode = VK_SHARING_MODE_CONCURRENT; + buffer_create_info.queueFamilyIndexCount = 1; + buffer_create_info.pQueueFamilyIndices = &queue_family_index; + if ((vr = vkCreateBuffer(vk_device, &buffer_create_info, NULL, &vk_buffer))) + { + skip("Failed to create generic buffer, VkResult %d.\n", vr); + vkDestroyDevice(vk_device, NULL); + return; + }
+ dedicated_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR; + dedicated_alloc_info.pNext = NULL; + dedicated_alloc_info.image = VK_NULL_HANDLE; + dedicated_alloc_info.buffer = vk_buffer;
+ external_buffer_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR; + external_buffer_info.pNext = NULL; + external_buffer_info.flags = 0; + external_buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + external_buffer_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
+ memset(&external_buffer_properties, 0, sizeof(external_buffer_properties)); + external_buffer_properties.sType = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR;
pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR(vk_physical_device, &external_buffer_info, &external_buffer_properties);
+ if (!(external_buffer_properties.externalMemoryProperties.externalMemoryFeatures &
(VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR|VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR)))
+ skip("With desired parameters, buffers are not exportable to and importable from an NT handle.\n"); + else + {
ok(external_buffer_properties.externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR, + "Unexpected compatibleHandleTypes %#x.\n", external_buffer_properties.externalMemoryProperties.compatibleHandleTypes);
+ export_memory_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR; + export_memory_info.pNext = &dedicated_alloc_info; + export_memory_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
+ export_handle_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR; + export_handle_info.pNext = &export_memory_info; + export_handle_info.name = L"wine_test_buffer_export_name"; + export_handle_info.dwAccess = GENERIC_ALL; + export_handle_info.pAttributes = NULL;
+ alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.pNext = &export_handle_info; + alloc_info.allocationSize = 1; + alloc_info.memoryTypeIndex = find_memory_type(vk_physical_device, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ ok(alloc_info.memoryTypeIndex != -1, "Device local memory type index was not found.\n");
+ vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory); + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
+ get_handle_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR; + get_handle_info.pNext = NULL; + get_handle_info.memory = vk_memory; + get_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
+ vr = pfn_vkGetMemoryWin32HandleKHR(vk_device, &get_handle_info, &nt_handle); + ok(vr == VK_SUCCESS, "vkGetMemoryWin32HandleKHR failed, VkResult %d.\n", vr);
+ import_handle_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR; + import_handle_info.pNext = &dedicated_alloc_info; + import_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR; + import_handle_info.handle = nt_handle; + import_handle_info.name = NULL;
+ alloc_info.pNext = &import_handle_info;
+ vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import); + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr); + ok(vk_memory_import != vk_memory, "Expected new memory object.\n");
+ vkFreeMemory(vk_device, vk_memory_import, NULL);
+ import_handle_info.handle = NULL; + import_handle_info.name = L"wine_test_buffer_export_name";
+ vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import); + todo_wine + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr); + if (vr == VK_SUCCESS) + { + ok(vk_memory_import != vk_memory, "Expected new memory object.\n"); + vkFreeMemory(vk_device, vk_memory_import, NULL); + } + vkFreeMemory(vk_device, vk_memory, NULL); + CloseHandle(nt_handle); + }
+ external_buffer_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
+ memset(&external_buffer_properties, 0, sizeof(external_buffer_properties)); + external_buffer_properties.sType = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR;
pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR(vk_physical_device, &external_buffer_info, &external_buffer_properties);
+ if (!(external_buffer_properties.externalMemoryProperties.externalMemoryFeatures &
(VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR|VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR)))
+ skip("With desired parameters, buffers are not exportable to and importable from a KMT handle.\n"); + else + {
ok(external_buffer_properties.externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR, + "Unexpected compatibleHandleTypes %#x.\n", external_buffer_properties.externalMemoryProperties.compatibleHandleTypes);
+ export_memory_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR; + export_memory_info.pNext = &dedicated_alloc_info; + export_memory_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
+ alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.pNext = &export_memory_info; + alloc_info.allocationSize = 1; + alloc_info.memoryTypeIndex = find_memory_type(vk_physical_device, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ ok(alloc_info.memoryTypeIndex != -1, "Device local memory type index was not found.\n");
+ vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory); + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
+ get_handle_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR; + get_handle_info.pNext = NULL; + get_handle_info.memory = vk_memory; + get_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
+ vr = pfn_vkGetMemoryWin32HandleKHR(vk_device, &get_handle_info, &kmt_handle); + ok(vr == VK_SUCCESS, "vkGetMemoryWin32HandleKHR failed, VkResult %d.\n", vr);
+ import_handle_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR; + import_handle_info.pNext = &dedicated_alloc_info; + import_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR; + import_handle_info.handle = kmt_handle; + import_handle_info.name = NULL;
+ alloc_info.pNext = &import_handle_info;
+ vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import); + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr); + ok(vk_memory_import != vk_memory, "Expected new memory object.\n");
+ vkFreeMemory(vk_device, vk_memory_import, NULL); + vkFreeMemory(vk_device, vk_memory, NULL); + }
+ vkDestroyBuffer(vk_device, vk_buffer, NULL); + vkDestroyDevice(vk_device, NULL); +}
static void for_each_device_instance(uint32_t extension_count, const char * const *enabled_extensions, void (*test_func_instance)(VkInstance, VkPhysicalDevice), void (*test_func)(VkPhysicalDevice)) { @@ -602,4 +817,5 @@ START_TEST(vulkan) for_each_device(test_unsupported_device_extensions); for_each_device(test_private_data); for_each_device_instance(ARRAY_SIZE(test_null_hwnd_extensions), test_null_hwnd_extensions, test_null_hwnd, NULL);
for_each_device_instance(ARRAY_SIZE(test_external_memory_extensions), test_external_memory_extensions, test_external_memory, NULL); } diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 7e1d7c0f043..b36275ba75f 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -99,7 +99,6 @@ UNSUPPORTED_EXTENSIONS = [ "VK_EXT_pipeline_creation_feedback", "VK_GOOGLE_display_timing", "VK_KHR_external_fence_win32", - "VK_KHR_external_memory_win32", "VK_KHR_external_semaphore_win32", # Relates to external_semaphore and needs type conversions in bitflags. "VK_KHR_shared_presentable_image", # Needs WSI work. @@ -109,7 +108,6 @@ UNSUPPORTED_EXTENSIONS = [ "VK_EXT_external_memory_dma_buf", "VK_EXT_image_drm_format_modifier", "VK_KHR_external_fence_fd", - "VK_KHR_external_memory_fd", "VK_KHR_external_semaphore_fd", # Extensions which require callback handling @@ -121,7 +119,9 @@ UNSUPPORTED_EXTENSIONS = [ ] # Extensions which aren't present on the win32 platform, but which winevulkan may use. -UNEXPOSED_EXTENSIONS = [] +UNEXPOSED_EXTENSIONS = [ + "VK_KHR_external_memory_fd", +] # The Vulkan loader provides entry-points for core functionality and important # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51. @@ -179,7 +179,7 @@ FUNCTION_OVERRIDES = { "vkEnumerateDeviceLayerProperties": {"dispatch": True, "driver": False, "thunk": ThunkType.NONE}, "vkEnumeratePhysicalDeviceGroups" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, - "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, + "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, @@ -188,10 +188,14 @@ FUNCTION_OVERRIDES = { # Device functions "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkAllocateMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkCreateBuffer" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkCreateImage" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkFreeMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE}, "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetDeviceQueue2" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, @@ -221,7 +225,7 @@ FUNCTION_OVERRIDES = { "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, # VK_KHR_external_memory_capabilities - "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, + "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, # VK_KHR_external_semaphore_capabilities @@ -257,12 +261,22 @@ FUNCTION_OVERRIDES = { # VK_EXT_debug_marker "vkDebugMarkerSetObjectNameEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkDebugMarkerSetObjectTagEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
+ # VK_KHR_external_memory_win32 + "vkGetMemoryWin32HandleKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkGetMemoryWin32HandlePropertiesKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, } STRUCT_CHAIN_CONVERSIONS = { # Ignore to not confuse host loader. "VkDeviceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO"], "VkInstanceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO"],
+ # Structs which require pNext chain modification + "VkBufferCreateInfo": [], + "VkImageCreateInfo": [], + "VkMemoryAllocateInfo": ["VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR", "VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR"], + "VkPhysicalDeviceImageFormatInfo2": [], } @@ -1052,6 +1066,8 @@ class VkHandle(object): return "wine_debug_report_callback_from_handle({0})->debug_callback".format(name)
if self.name == "VkSurfaceKHR": return "wine_surface_from_handle({0})->surface".format(name) + if self.name == "VkDeviceMemory": + return "wine_dev_mem_from_handle({0})->dev_mem".format(name) native_handle_name = None diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 9f181d92bc5..c2069b77ef2 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -25,6 +25,7 @@ #include <time.h> #include <stdarg.h> #include <stdlib.h> +#include <unistd.h> #include "ntstatus.h" #define WIN32_NO_STATUS @@ -34,6 +35,8 @@ #include "winuser.h" #include "winternl.h" +#include "wine/server.h"
#include "vulkan_private.h" WINE_DEFAULT_DEBUG_CHANNEL(vulkan); @@ -263,6 +266,15 @@ static struct VkPhysicalDevice_T *wine_vk_physical_device_alloc(struct VkInstanc */ for (i = 0; i < num_host_properties; i++) { + if (!strcmp(host_properties[i].extensionName, "VK_KHR_external_memory_fd")) + { + TRACE("Substituting VK_KHR_external_memory_fd for VK_KHR_external_memory_win32\n");
+ snprintf(host_properties[i].extensionName, sizeof(host_properties[i].extensionName),
- VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME);
+ host_properties[i].specVersion = VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION; + }
if (wine_vk_device_extension_supported(host_properties[i].extensionName)) { TRACE("Enabling extension '%s' for physical device %p\n", host_properties[i].extensionName, object); @@ -361,11 +373,15 @@ static void wine_vk_device_get_queues(struct VkDevice_T *device, static void wine_vk_device_free_create_info(VkDeviceCreateInfo *create_info) { free_VkDeviceCreateInfo_struct_chain(create_info);
+ if (create_info->enabledExtensionCount) + free((void *)create_info->ppEnabledExtensionNames); } static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src, VkDeviceCreateInfo *dst) { + const char **enabled_extensions; unsigned int i; VkResult res; @@ -389,11 +405,34 @@ static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src if (!wine_vk_device_extension_supported(extension_name)) { WARN("Extension %s is not supported.\n", debugstr_a(extension_name)); - wine_vk_device_free_create_info(dst); + free_VkDeviceCreateInfo_struct_chain(dst); return VK_ERROR_EXTENSION_NOT_PRESENT; } } + if (src->enabledExtensionCount > 0) + { + enabled_extensions = calloc(src->enabledExtensionCount, sizeof(*src->ppEnabledExtensionNames)); + if (!enabled_extensions) + { + free_VkDeviceCreateInfo_struct_chain(dst); + return VK_ERROR_OUT_OF_HOST_MEMORY; + }
+ for (i = 0; i < src->enabledExtensionCount; i++) + { + if (!strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_memory_win32")) + { + enabled_extensions[i] = "VK_KHR_external_memory_fd"; + } + else + { + enabled_extensions[i] = src->ppEnabledExtensionNames[i]; + } + } + dst->ppEnabledExtensionNames = enabled_extensions; + }
return VK_SUCCESS; } @@ -1190,57 +1229,100 @@ void WINAPI wine_vkGetPhysicalDeviceExternalFencePropertiesKHR(VkPhysicalDevice void WINAPI wine_vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice phys_dev, const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties) { + VkPhysicalDeviceExternalBufferInfo buffer_info_dup = *buffer_info;
TRACE("%p, %p, %p\n", phys_dev, buffer_info, properties); - memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties));
+ if (buffer_info_dup.handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + buffer_info_dup.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
+ thunk_vkGetPhysicalDeviceExternalBufferProperties(phys_dev, &buffer_info_dup, properties);
+ if (properties->externalMemoryProperties.exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
- properties->externalMemoryProperties.exportFromImportedHandleTypes
= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + if (properties->externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
- properties->externalMemoryProperties.compatibleHandleTypes =
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; } void WINAPI wine_vkGetPhysicalDeviceExternalBufferPropertiesKHR(VkPhysicalDevice phys_dev, const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties) { + VkPhysicalDeviceExternalBufferInfo buffer_info_dup = *buffer_info;
TRACE("%p, %p, %p\n", phys_dev, buffer_info, properties); - memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties));
+ if (buffer_info_dup.handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + buffer_info_dup.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
- thunk_vkGetPhysicalDeviceExternalBufferPropertiesKHR(phys_dev,
&buffer_info_dup, properties);
+ if (properties->externalMemoryProperties.exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
- properties->externalMemoryProperties.exportFromImportedHandleTypes
= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + if (properties->externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
- properties->externalMemoryProperties.compatibleHandleTypes =
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; } -VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev, +static VkResult wine_vk_get_physical_device_image_format_properties_2(VkPhysicalDevice phys_dev,
+ VkResult (*p_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice, const VkPhysicalDeviceImageFormatInfo2 *, VkImageFormatProperties2 *), const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties) { + VkPhysicalDeviceExternalImageFormatInfo *external_image_info_dup = NULL; + const VkPhysicalDeviceExternalImageFormatInfo *external_image_info; + VkPhysicalDeviceImageFormatInfo2 format_info_host = *format_info; VkExternalImageFormatProperties *external_image_properties; VkResult res; - TRACE("%p, %p, %p\n", phys_dev, format_info, properties); + if ((external_image_info = wine_vk_find_struct(format_info, PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO))) + { + if (external_image_info->handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + { + if ((res = convert_VkPhysicalDeviceImageFormatInfo2_struct_chain(format_info->pNext, &format_info_host)) < 0) + { + WARN("Failed to convert VkPhysicalDeviceImageFormatInfo2 pNext chain, res=%d.\n", res); + return res; + } - res = thunk_vkGetPhysicalDeviceImageFormatProperties2(phys_dev, format_info, properties); + external_image_info_dup = wine_vk_find_struct(&format_info_host, PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO); + external_image_info_dup->handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + } + if (external_image_info->handleType &~ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + { + WARN("Unsupported handle type %#x.\n", external_image_info->handleType); + return VK_ERROR_FORMAT_NOT_SUPPORTED; + } + }
+ res = p_vkGetPhysicalDeviceImageFormatProperties2(phys_dev, &format_info_host, properties);
+ if (external_image_info_dup)
- free_VkPhysicalDeviceImageFormatInfo2_struct_chain(&format_info_host);
if ((external_image_properties = wine_vk_find_struct(properties, EXTERNAL_IMAGE_FORMAT_PROPERTIES))) { VkExternalMemoryProperties *p = &external_image_properties->externalMemoryProperties; - p->externalMemoryFeatures = 0; - p->exportFromImportedHandleTypes = 0; - p->compatibleHandleTypes = 0; + if (p->exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) + p->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + if (p->compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) + p->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; } return res; } -VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice phys_dev, +VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev, const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties) { - VkExternalImageFormatProperties *external_image_properties; - VkResult res;
TRACE("%p, %p, %p\n", phys_dev, format_info, properties); - res = thunk_vkGetPhysicalDeviceImageFormatProperties2KHR(phys_dev, format_info, properties); + return wine_vk_get_physical_device_image_format_properties_2(phys_dev, thunk_vkGetPhysicalDeviceImageFormatProperties2, format_info, properties); +} - if ((external_image_properties = wine_vk_find_struct(properties, EXTERNAL_IMAGE_FORMAT_PROPERTIES))) - { - VkExternalMemoryProperties *p = &external_image_properties->externalMemoryProperties; - p->externalMemoryFeatures = 0; - p->exportFromImportedHandleTypes = 0; - p->compatibleHandleTypes = 0; - } +VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice phys_dev, + const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties) +{ + TRACE("%p, %p, %p\n", phys_dev, format_info, properties); - return res; + return wine_vk_get_physical_device_image_format_properties_2(phys_dev, thunk_vkGetPhysicalDeviceImageFormatProperties2KHR, format_info, properties); } /* From ntdll/unix/sync.c */ @@ -1720,3 +1802,283 @@ VkResult WINAPI wine_vkDebugMarkerSetObjectNameEXT(VkDevice device, const VkDebu return thunk_vkDebugMarkerSetObjectNameEXT(device, &wine_name_info); }
+static HANDLE create_gpu_resource(int fd, LPCWSTR name) +{ + HANDLE ret = INVALID_HANDLE_VALUE;
+ if (name) + FIXME("Naming gpu resources not supported.\n");
+ wine_server_fd_to_handle(fd, GENERIC_ALL, 0, &ret);
+ return ret; +}
+VkResult WINAPI wine_vkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *allocate_info, + const VkAllocationCallbacks *allocator, VkDeviceMemory *memory) +{ + const VkImportMemoryWin32HandleInfoKHR *handle_import_info; + const VkExportMemoryWin32HandleInfoKHR *handle_export_info; + VkMemoryAllocateInfo allocate_info_dup = *allocate_info; + VkExportMemoryAllocateInfo *export_info; + VkImportMemoryFdInfoKHR fd_import_info; + struct wine_dev_mem *object; + VkResult res; + int fd;
+#if defined(USE_STRUCT_CONVERSION) + VkMemoryAllocateInfo_host allocate_info_host; + VkMemoryGetFdInfoKHR_host get_fd_info; +#else + VkMemoryAllocateInfo allocate_info_host; + VkMemoryGetFdInfoKHR get_fd_info; +#endif
+ TRACE("%p %p %p %p\n", device, allocate_info, allocator, memory);
+ if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n");
+ if ((res = convert_VkMemoryAllocateInfo_struct_chain(allocate_info->pNext, &allocate_info_dup)) < 0) + { + WARN("Failed to convert VkMemoryAllocateInfo pNext chain, res=%d.\n", res); + return res; + }
+ if (!(object = calloc(1, sizeof(*object)))) + {
- free_VkMemoryAllocateInfo_struct_chain(&allocate_info_dup);
+ return VK_ERROR_OUT_OF_HOST_MEMORY; + }
+ object->dev_mem = VK_NULL_HANDLE; + object->handle = INVALID_HANDLE_VALUE; + fd_import_info.fd = -1; + fd_import_info.pNext = NULL;
+ /* find and process handle import/export info and grab it */ + handle_import_info = wine_vk_find_struct(allocate_info, IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR); + handle_export_info = wine_vk_find_struct(allocate_info, EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR); + if (handle_export_info && handle_export_info->pAttributes && handle_export_info->pAttributes->lpSecurityDescriptor) + FIXME("Support for custom security descriptor not implemented.\n");
+ if ((export_info = wine_vk_find_struct(&allocate_info_dup, EXPORT_MEMORY_ALLOCATE_INFO))) + { + object->handle_types = export_info->handleTypes; + if (object->handle_types &~ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto done; + } + if (object->handle_types) + export_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + }
+ /* Vulkan consumes imported FDs, but not imported HANDLEs */ + if (handle_import_info) + { + fd_import_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; + fd_import_info.pNext = allocate_info_dup.pNext; + fd_import_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
+ switch (handle_import_info->handleType) + { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT: + if (handle_import_info->handle) + NtDuplicateObject( NtCurrentProcess(), handle_import_info->handle, NtCurrentProcess(), &object->handle, 0, 0, DUPLICATE_SAME_ACCESS ); + else if (handle_import_info->name) + FIXME("Importing device memory by resource name not supported.\n"); + break; + default: + WARN("Invalid handle type %08x passed in.\n", handle_import_info->handleType); + res = VK_ERROR_INVALID_EXTERNAL_HANDLE; + goto done; + }
+ if (object->handle != INVALID_HANDLE_VALUE) + wine_server_handle_to_fd(object->handle, FILE_READ_DATA, &fd_import_info.fd, NULL);
+ if (fd_import_info.fd == -1) + { + TRACE("Couldn't access resource handle or name. type=%08x handle=%p name=%s\n", handle_import_info->handleType, handle_import_info->handle, + handle_import_info->name ? debugstr_w(handle_import_info->name) : ""); + res = VK_ERROR_INVALID_EXTERNAL_HANDLE; + goto done; + } + }
+ allocate_info_host.sType = allocate_info_dup.sType; + allocate_info_host.pNext = fd_import_info.fd == -1 ? allocate_info_dup.pNext : &fd_import_info; + allocate_info_host.allocationSize = allocate_info_dup.allocationSize; + allocate_info_host.memoryTypeIndex = allocate_info_dup.memoryTypeIndex;
+ if ((res = device->funcs.p_vkAllocateMemory(device->device, &allocate_info_host, NULL, &object->dev_mem)) == VK_SUCCESS) + { + if (object->handle == INVALID_HANDLE_VALUE && export_info && export_info->handleTypes) + { + get_fd_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR; + get_fd_info.pNext = NULL; + get_fd_info.memory = object->dev_mem; + get_fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
+ if (device->funcs.p_vkGetMemoryFdKHR(device->device, &get_fd_info, &fd) == VK_SUCCESS) + { + object->handle = create_gpu_resource(fd, handle_export_info ? handle_export_info->name : NULL); + object->access = handle_export_info ? handle_export_info->dwAccess : GENERIC_ALL; + if (handle_export_info && handle_export_info->pAttributes) + object->inherit = handle_export_info->pAttributes->bInheritHandle; + else + object->inherit = FALSE; + close(fd); + }
+ if (object->handle == INVALID_HANDLE_VALUE) + { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto done; + } + }
- WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(device->phys_dev->instance,
object, object->dev_mem); + *memory = wine_dev_mem_to_handle(object); + }
+ done:
+ if (res != VK_SUCCESS) + { + device->funcs.p_vkFreeMemory(device->device, object->dev_mem, NULL); + if (fd_import_info.fd != -1) + close(fd_import_info.fd); + if (object->handle != INVALID_HANDLE_VALUE) + NtClose(object->handle); + free(object); + }
- free_VkMemoryAllocateInfo_struct_chain(&allocate_info_dup);
+ return res; +}
+VkResult WINAPI wine_vkGetMemoryWin32HandleKHR(VkDevice device, + const VkMemoryGetWin32HandleInfoKHR *handle_info, HANDLE *handle) +{ + struct wine_dev_mem *dev_mem = wine_dev_mem_from_handle(handle_info->memory); + const VkBaseInStructure *chain;
+ TRACE("%p, %p %p\n", device, handle_info, handle);
+ if (!(dev_mem->handle_types & handle_info->handleType)) + return VK_ERROR_OUT_OF_HOST_MEMORY;
+ if ((chain = handle_info->pNext)) + FIXME("Ignoring a linked structure of type %u.\n", chain->sType);
+ switch(handle_info->handleType) + { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT: + return !NtDuplicateObject( NtCurrentProcess(), dev_mem->handle, NtCurrentProcess(), handle, dev_mem->access, dev_mem->inherit ? OBJ_INHERIT : 0, 0) ? + VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY; + default: + return VK_ERROR_UNKNOWN; + } +}
+void WINAPI wine_vkFreeMemory(VkDevice device, VkDeviceMemory handle, const VkAllocationCallbacks *allocator) +{ + struct wine_dev_mem *dev_mem = wine_dev_mem_from_handle(handle);
+ TRACE("%p 0x%s, %p\n", device, wine_dbgstr_longlong(handle), allocator);
+ if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n");
+ if (!handle) + return;
- WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, dev_mem);
+ device->funcs.p_vkFreeMemory(device->device, dev_mem->dev_mem, NULL); + if (dev_mem->handle != INVALID_HANDLE_VALUE) + NtClose(dev_mem->handle); + free(dev_mem); +}
+VkResult WINAPI wine_vkGetMemoryWin32HandlePropertiesKHR(VkDevice device, + VkExternalMemoryHandleTypeFlagBits type, HANDLE handle, VkMemoryWin32HandlePropertiesKHR *properties) +{ + TRACE("%p %u %p %p\n", device, type, handle, properties);
+ /* VUID-vkGetMemoryWin32HandlePropertiesKHR-handleType-00666 + handleType must not be one of the handle types defined as opaque */ + return VK_ERROR_INVALID_EXTERNAL_HANDLE; +}
+VkResult WINAPI wine_vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *create_info, + const VkAllocationCallbacks *allocator, VkBuffer *buffer) +{ + VkExternalMemoryBufferCreateInfo *external_memory_info; + VkBufferCreateInfo create_info_dup; + VkResult res;
+#if defined(USE_STRUCT_CONVERSION) + VkBufferCreateInfo_host create_info_host; +#else + VkBufferCreateInfo create_info_host; +#endif
+ if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n");
+ if ((res = convert_VkBufferCreateInfo_struct_chain(create_info->pNext, &create_info_dup))) + { + WARN("Failed to convert VkBufferCreateInfo pNext chain, res=%d.\n", res); + return res; + }
+ if ((external_memory_info = wine_vk_find_struct(&create_info_dup, EXTERNAL_MEMORY_BUFFER_CREATE_INFO)) && + external_memory_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR) + external_memory_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+ create_info_host.pNext = create_info_dup.pNext; + create_info_host.sType = create_info->sType; + create_info_host.flags = create_info->flags; + create_info_host.size = create_info->size; + create_info_host.usage = create_info->usage; + create_info_host.sharingMode = create_info->sharingMode; + create_info_host.queueFamilyIndexCount = create_info->queueFamilyIndexCount; + create_info_host.pQueueFamilyIndices = create_info->pQueueFamilyIndices;
+ res = device->funcs.p_vkCreateBuffer(device->device, &create_info_host, NULL, buffer);
+ free_VkBufferCreateInfo_struct_chain(&create_info_dup);
+ return res; +}
+VkResult WINAPI wine_vkCreateImage(VkDevice device, const VkImageCreateInfo *create_info, + const VkAllocationCallbacks *allocator, VkBuffer *image) +{ + VkExternalMemoryImageCreateInfo *external_memory_info; + VkImageCreateInfo create_info_host; + VkResult res;
+ if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n");
+ if ((res = convert_VkImageCreateInfo_struct_chain(create_info->pNext, &create_info_host))) + { + WARN("Failed to convert VkImageCreateInfo pNext chain, res=%d.\n", res); + return res; + }
+ if ((external_memory_info = wine_vk_find_struct(&create_info_host, EXTERNAL_MEMORY_BUFFER_CREATE_INFO)) && + external_memory_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR) + external_memory_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+ res = device->funcs.p_vkCreateImage(device->device, &create_info_host, NULL, image);
+ free_VkImageCreateInfo_struct_chain(&create_info_host);
+ return res; +} diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 83dc90ca15e..4a20702d43b 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -204,6 +204,30 @@ static inline VkSurfaceKHR wine_surface_to_handle(struct wine_surface *surface) return (VkSurfaceKHR)(uintptr_t)surface; } +struct wine_dev_mem +{ + VkDeviceMemory dev_mem;
+ VkExternalMemoryHandleTypeFlagBits handle_types;
+ BOOL inherit; + DWORD access;
+ HANDLE handle;
+ struct wine_vk_mapping mapping; +};
+static inline struct wine_dev_mem *wine_dev_mem_from_handle(VkDeviceMemory handle) +{ + return (struct wine_dev_mem *)(uintptr_t)handle; +}
+static inline VkDeviceMemory wine_dev_mem_to_handle(struct wine_dev_mem *dev_mem) +{ + return (VkDeviceMemory)(uintptr_t)dev_mem; +}
BOOL wine_vk_device_extension_supported(const char *name) DECLSPEC_HIDDEN; BOOL wine_vk_instance_extension_supported(const char *name) DECLSPEC_HIDDEN;
On 18.05.21 09:35, Liam Middlebrook wrote:
On 5/17/21 1:01 PM, Derek Lesho wrote:
Signed-off-by: Derek Lesho dlesho@codeweavers.com
v2: Addressed comments from mailing list and discord.
You should be encouraging people giving feedback on Discord to reply to your patches here on wine-devel.
Not sure who's meant here, but if it's me, I already give most of my feedback here on wine-devel.
On 17.05.21 22:01, Derek Lesho wrote:
Signed-off-by: Derek Lesho dlesho@codeweavers.com
v2: Addressed comments from mailing list and discord.
dlls/vulkan-1/tests/vulkan.c | 216 ++++++++++++++++
I think putting the test into a prior patch using the unexposed extension mechanism is a good idea.
dlls/winevulkan/make_vulkan | 26 +- dlls/winevulkan/vulkan.c | 406 +++++++++++++++++++++++++++++-- dlls/winevulkan/vulkan_private.h | 24 ++ 4 files changed, 645 insertions(+), 27 deletions(-)
diff --git a/dlls/vulkan-1/tests/vulkan.c b/dlls/vulkan-1/tests/vulkan.c index 1d23c4112cf..718937e2222 100644 --- a/dlls/vulkan-1/tests/vulkan.c +++ b/dlls/vulkan-1/tests/vulkan.c @@ -546,6 +546,221 @@ static void test_null_hwnd(VkInstance vk_instance, VkPhysicalDevice vk_physical_ vkDestroySurfaceKHR(vk_instance, surface, NULL); }
+uint32_t find_memory_type(VkPhysicalDevice vk_physical_device, VkMemoryPropertyFlagBits flags) +{
- VkPhysicalDeviceMemoryProperties properties = {0};
- unsigned int i;
- vkGetPhysicalDeviceMemoryProperties(vk_physical_device, &properties);
- for(i = 0; i < properties.memoryTypeCount; i++)
- {
if (properties.memoryTypes[i].propertyFlags & flags)
return i;
- }
- return -1;
+}
+static const char *test_external_memory_extensions[] = +{
- "VK_KHR_external_memory_capabilities",
+};
+static void test_external_memory(VkInstance vk_instance, VkPhysicalDevice vk_physical_device) +{
- PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR;
- PFN_vkGetMemoryWin32HandleKHR pfn_vkGetMemoryWin32HandleKHR;
- VkPhysicalDeviceExternalBufferInfoKHR external_buffer_info;
- VkExternalBufferPropertiesKHR external_buffer_properties;
- VkMemoryDedicatedAllocateInfoKHR dedicated_alloc_info;
- VkExportMemoryWin32HandleInfoKHR export_handle_info;
- VkImportMemoryWin32HandleInfoKHR import_handle_info;
- VkExportMemoryAllocateInfoKHR export_memory_info;
- VkMemoryGetWin32HandleInfoKHR get_handle_info;
- VkBufferCreateInfo buffer_create_info;
- VkMemoryAllocateInfo alloc_info;
- uint32_t queue_family_index;
- HANDLE nt_handle, kmt_handle;
- VkDeviceMemory vk_memory, vk_memory_import;
- VkBuffer vk_buffer;
- VkDevice vk_device;
- VkResult vr;
- static const char *extensions[] =
- {
"VK_KHR_dedicated_allocation",
"VK_KHR_external_memory",
"VK_KHR_external_memory_win32",
- };
- pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR =
(void*) vkGetInstanceProcAddr(vk_instance, "vkGetPhysicalDeviceExternalBufferPropertiesKHR");
- if ((vr = create_device(vk_physical_device, ARRAY_SIZE(extensions), extensions, NULL, &vk_device)))
- {
skip("Failed to create device with external memory extensions, VkResult %d.\n", vr);
return;
- }
- pfn_vkGetMemoryWin32HandleKHR = (void *) vkGetDeviceProcAddr(vk_device, "vkGetMemoryWin32HandleKHR");
- find_queue_family(vk_physical_device, VK_QUEUE_GRAPHICS_BIT, &queue_family_index);
- /* Most implementations only support exporting dedicated allocations */
- buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
- buffer_create_info.pNext = NULL;
- buffer_create_info.flags = 0;
- buffer_create_info.size = 1;
- buffer_create_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
- buffer_create_info.sharingMode = VK_SHARING_MODE_CONCURRENT;
- buffer_create_info.queueFamilyIndexCount = 1;
- buffer_create_info.pQueueFamilyIndices = &queue_family_index;
- if ((vr = vkCreateBuffer(vk_device, &buffer_create_info, NULL, &vk_buffer)))
- {
skip("Failed to create generic buffer, VkResult %d.\n", vr);
vkDestroyDevice(vk_device, NULL);
return;
- }
- dedicated_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR;
- dedicated_alloc_info.pNext = NULL;
- dedicated_alloc_info.image = VK_NULL_HANDLE;
- dedicated_alloc_info.buffer = vk_buffer;
- external_buffer_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR;
- external_buffer_info.pNext = NULL;
- external_buffer_info.flags = 0;
- external_buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
- external_buffer_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
- memset(&external_buffer_properties, 0, sizeof(external_buffer_properties));
- external_buffer_properties.sType = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR;
- pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR(vk_physical_device, &external_buffer_info, &external_buffer_properties);
- if (!(external_buffer_properties.externalMemoryProperties.externalMemoryFeatures &
(VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR|VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR)))
skip("With desired parameters, buffers are not exportable to and importable from an NT handle.\n");
- else
- {
ok(external_buffer_properties.externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR,
"Unexpected compatibleHandleTypes %#x.\n", external_buffer_properties.externalMemoryProperties.compatibleHandleTypes);
export_memory_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;
export_memory_info.pNext = &dedicated_alloc_info;
export_memory_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
export_handle_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR;
export_handle_info.pNext = &export_memory_info;
export_handle_info.name = L"wine_test_buffer_export_name";
export_handle_info.dwAccess = GENERIC_ALL;
export_handle_info.pAttributes = NULL;
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.pNext = &export_handle_info;
alloc_info.allocationSize = 1;
alloc_info.memoryTypeIndex = find_memory_type(vk_physical_device, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
You should filter out types which are not in the mask returned by vkGetBufferMemoryRequirements.
ok(alloc_info.memoryTypeIndex != -1, "Device local memory type index was not found.\n");
vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory);
ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
get_handle_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR;
get_handle_info.pNext = NULL;
get_handle_info.memory = vk_memory;
get_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
vr = pfn_vkGetMemoryWin32HandleKHR(vk_device, &get_handle_info, &nt_handle);
ok(vr == VK_SUCCESS, "vkGetMemoryWin32HandleKHR failed, VkResult %d.\n", vr);
import_handle_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR;
import_handle_info.pNext = &dedicated_alloc_info;
import_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
import_handle_info.handle = nt_handle;
import_handle_info.name = NULL;
alloc_info.pNext = &import_handle_info;
vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import);
ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
ok(vk_memory_import != vk_memory, "Expected new memory object.\n");
vkFreeMemory(vk_device, vk_memory_import, NULL);
import_handle_info.handle = NULL;
import_handle_info.name = L"wine_test_buffer_export_name";
vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import);
- todo_wine
ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
if (vr == VK_SUCCESS)
{
ok(vk_memory_import != vk_memory, "Expected new memory object.\n");
vkFreeMemory(vk_device, vk_memory_import, NULL);
}
vkFreeMemory(vk_device, vk_memory, NULL);
CloseHandle(nt_handle);
- }
- external_buffer_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
- memset(&external_buffer_properties, 0, sizeof(external_buffer_properties));
- external_buffer_properties.sType = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR;
- pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR(vk_physical_device, &external_buffer_info, &external_buffer_properties);
- if (!(external_buffer_properties.externalMemoryProperties.externalMemoryFeatures &
(VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR|VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR)))
skip("With desired parameters, buffers are not exportable to and importable from a KMT handle.\n");
- else
- {
ok(external_buffer_properties.externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR,
"Unexpected compatibleHandleTypes %#x.\n", external_buffer_properties.externalMemoryProperties.compatibleHandleTypes);
export_memory_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;
export_memory_info.pNext = &dedicated_alloc_info;
export_memory_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.pNext = &export_memory_info;
alloc_info.allocationSize = 1;
alloc_info.memoryTypeIndex = find_memory_type(vk_physical_device, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
again, filter out the types.
ok(alloc_info.memoryTypeIndex != -1, "Device local memory type index was not found.\n");
vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory);
ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
get_handle_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR;
get_handle_info.pNext = NULL;
get_handle_info.memory = vk_memory;
get_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
vr = pfn_vkGetMemoryWin32HandleKHR(vk_device, &get_handle_info, &kmt_handle);
ok(vr == VK_SUCCESS, "vkGetMemoryWin32HandleKHR failed, VkResult %d.\n", vr);
import_handle_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR;
import_handle_info.pNext = &dedicated_alloc_info;
import_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
import_handle_info.handle = kmt_handle;
import_handle_info.name = NULL;
alloc_info.pNext = &import_handle_info;
vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import);
ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
ok(vk_memory_import != vk_memory, "Expected new memory object.\n");
vkFreeMemory(vk_device, vk_memory_import, NULL);
vkFreeMemory(vk_device, vk_memory, NULL);
- }
- vkDestroyBuffer(vk_device, vk_buffer, NULL);
- vkDestroyDevice(vk_device, NULL);
+}
- static void for_each_device_instance(uint32_t extension_count, const char * const *enabled_extensions, void (*test_func_instance)(VkInstance, VkPhysicalDevice), void (*test_func)(VkPhysicalDevice)) {
@@ -602,4 +817,5 @@ START_TEST(vulkan) for_each_device(test_unsupported_device_extensions); for_each_device(test_private_data); for_each_device_instance(ARRAY_SIZE(test_null_hwnd_extensions), test_null_hwnd_extensions, test_null_hwnd, NULL);
- for_each_device_instance(ARRAY_SIZE(test_external_memory_extensions), test_external_memory_extensions, test_external_memory, NULL); }
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 7e1d7c0f043..b36275ba75f 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -99,7 +99,6 @@ UNSUPPORTED_EXTENSIONS = [ "VK_EXT_pipeline_creation_feedback", "VK_GOOGLE_display_timing", "VK_KHR_external_fence_win32",
- "VK_KHR_external_memory_win32", "VK_KHR_external_semaphore_win32", # Relates to external_semaphore and needs type conversions in bitflags. "VK_KHR_shared_presentable_image", # Needs WSI work.
@@ -109,7 +108,6 @@ UNSUPPORTED_EXTENSIONS = [ "VK_EXT_external_memory_dma_buf", "VK_EXT_image_drm_format_modifier", "VK_KHR_external_fence_fd",
"VK_KHR_external_memory_fd", "VK_KHR_external_semaphore_fd",
# Extensions which require callback handling
@@ -121,7 +119,9 @@ UNSUPPORTED_EXTENSIONS = [ ]
# Extensions which aren't present on the win32 platform, but which winevulkan may use. -UNEXPOSED_EXTENSIONS = [] +UNEXPOSED_EXTENSIONS = [
- "VK_KHR_external_memory_fd",
+]
# The Vulkan loader provides entry-points for core functionality and important # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51. @@ -179,7 +179,7 @@ FUNCTION_OVERRIDES = { "vkEnumerateDeviceLayerProperties": {"dispatch": True, "driver": False, "thunk": ThunkType.NONE}, "vkEnumeratePhysicalDeviceGroups" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
- "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
- "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
Why do you need a private thunk, it's just a function call that you can do directly.
"vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
@@ -188,10 +188,14 @@ FUNCTION_OVERRIDES = {
# Device functions "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
- "vkAllocateMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
- "vkCreateBuffer" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
- "vkCreateImage" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
- "vkFreeMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE}, "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetDeviceQueue2" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
@@ -221,7 +225,7 @@ FUNCTION_OVERRIDES = { "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
# VK_KHR_external_memory_capabilities
- "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
- "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
Again, why do you need a private thunk?
"vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, # VK_KHR_external_semaphore_capabilities
@@ -257,12 +261,22 @@ FUNCTION_OVERRIDES = { # VK_EXT_debug_marker "vkDebugMarkerSetObjectNameEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkDebugMarkerSetObjectTagEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
# VK_KHR_external_memory_win32
"vkGetMemoryWin32HandleKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
"vkGetMemoryWin32HandlePropertiesKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, }
STRUCT_CHAIN_CONVERSIONS = { # Ignore to not confuse host loader. "VkDeviceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO"], "VkInstanceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO"],
# Structs which require pNext chain modification
"VkBufferCreateInfo": [],
"VkImageCreateInfo": [],
"VkMemoryAllocateInfo": ["VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR", "VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR"],
"VkPhysicalDeviceImageFormatInfo2": [], }
@@ -1052,6 +1066,8 @@ class VkHandle(object): return "wine_debug_report_callback_from_handle({0})->debug_callback".format(name) if self.name == "VkSurfaceKHR": return "wine_surface_from_handle({0})->surface".format(name)
if self.name == "VkDeviceMemory":
return "wine_dev_mem_from_handle({0})->dev_mem".format(name) native_handle_name = None
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 9f181d92bc5..c2069b77ef2 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -25,6 +25,7 @@ #include <time.h> #include <stdarg.h> #include <stdlib.h> +#include <unistd.h>
#include "ntstatus.h" #define WIN32_NO_STATUS @@ -34,6 +35,8 @@ #include "winuser.h" #include "winternl.h"
+#include "wine/server.h"
#include "vulkan_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
@@ -263,6 +266,15 @@ static struct VkPhysicalDevice_T *wine_vk_physical_device_alloc(struct VkInstanc */ for (i = 0; i < num_host_properties; i++) {
if (!strcmp(host_properties[i].extensionName, "VK_KHR_external_memory_fd"))
{
TRACE("Substituting VK_KHR_external_memory_fd for VK_KHR_external_memory_win32\n");
snprintf(host_properties[i].extensionName, sizeof(host_properties[i].extensionName),
VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME);
host_properties[i].specVersion = VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION;
}
if (wine_vk_device_extension_supported(host_properties[i].extensionName)) { TRACE("Enabling extension '%s' for physical device %p\n", host_properties[i].extensionName, object);
@@ -361,11 +373,15 @@ static void wine_vk_device_get_queues(struct VkDevice_T *device, static void wine_vk_device_free_create_info(VkDeviceCreateInfo *create_info) { free_VkDeviceCreateInfo_struct_chain(create_info);
if (create_info->enabledExtensionCount)
free((void *)create_info->ppEnabledExtensionNames);
}
static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src, VkDeviceCreateInfo *dst) {
const char **enabled_extensions; unsigned int i; VkResult res;
@@ -389,11 +405,34 @@ static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src if (!wine_vk_device_extension_supported(extension_name)) { WARN("Extension %s is not supported.\n", debugstr_a(extension_name));
wine_vk_device_free_create_info(dst);
free_VkDeviceCreateInfo_struct_chain(dst); return VK_ERROR_EXTENSION_NOT_PRESENT; } }
if (src->enabledExtensionCount > 0)
{
enabled_extensions = calloc(src->enabledExtensionCount, sizeof(*src->ppEnabledExtensionNames));
if (!enabled_extensions)
{
free_VkDeviceCreateInfo_struct_chain(dst);
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
for (i = 0; i < src->enabledExtensionCount; i++)
{
if (!strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_memory_win32"))
{
enabled_extensions[i] = "VK_KHR_external_memory_fd";
}
else
{
enabled_extensions[i] = src->ppEnabledExtensionNames[i];
}
}
dst->ppEnabledExtensionNames = enabled_extensions;
}
return VK_SUCCESS;
}
@@ -1190,57 +1229,100 @@ void WINAPI wine_vkGetPhysicalDeviceExternalFencePropertiesKHR(VkPhysicalDevice void WINAPI wine_vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice phys_dev, const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties) {
- VkPhysicalDeviceExternalBufferInfo buffer_info_dup = *buffer_info;
TRACE("%p, %p, %p\n", phys_dev, buffer_info, properties);
- memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties));
- if (buffer_info_dup.handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)
This is not a bit mask, it's a single bit. So you should use == here.
buffer_info_dup.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
thunk_vkGetPhysicalDeviceExternalBufferProperties(phys_dev, &buffer_info_dup, properties);
if (properties->externalMemoryProperties.exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
properties->externalMemoryProperties.exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
if (properties->externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
properties->externalMemoryProperties.compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
}
void WINAPI wine_vkGetPhysicalDeviceExternalBufferPropertiesKHR(VkPhysicalDevice phys_dev, const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties)
This is an alias of vkGetPhysicalDeviceExternalBufferProperties, unify them in the same way as you did with vkGetPhysicalDeviceImageFormatProperties2.
{
- VkPhysicalDeviceExternalBufferInfo buffer_info_dup = *buffer_info;
TRACE("%p, %p, %p\n", phys_dev, buffer_info, properties);
- memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties));
- if (buffer_info_dup.handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)
buffer_info_dup.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
- thunk_vkGetPhysicalDeviceExternalBufferPropertiesKHR(phys_dev, &buffer_info_dup, properties);
- if (properties->externalMemoryProperties.exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
properties->externalMemoryProperties.exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
- if (properties->externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
}properties->externalMemoryProperties.compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
-VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev, +static VkResult wine_vk_get_physical_device_image_format_properties_2(VkPhysicalDevice phys_dev,
{VkResult (*p_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice, const VkPhysicalDeviceImageFormatInfo2 *, VkImageFormatProperties2 *), const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties)
- VkPhysicalDeviceExternalImageFormatInfo *external_image_info_dup = NULL;
- const VkPhysicalDeviceExternalImageFormatInfo *external_image_info;
- VkPhysicalDeviceImageFormatInfo2 format_info_host = *format_info; VkExternalImageFormatProperties *external_image_properties; VkResult res;
- TRACE("%p, %p, %p\n", phys_dev, format_info, properties);
- if ((external_image_info = wine_vk_find_struct(format_info, PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO)))
- {
if (external_image_info->handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)
This is not a bit mask, it's a single bit.
{
if ((res = convert_VkPhysicalDeviceImageFormatInfo2_struct_chain(format_info->pNext, &format_info_host)) < 0)
{
WARN("Failed to convert VkPhysicalDeviceImageFormatInfo2 pNext chain, res=%d.\n", res);
return res;
}
- res = thunk_vkGetPhysicalDeviceImageFormatProperties2(phys_dev, format_info, properties);
external_image_info_dup = wine_vk_find_struct(&format_info_host, PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO);
external_image_info_dup->handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
}
if (external_image_info->handleType &~ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)
{
WARN("Unsupported handle type %#x.\n", external_image_info->handleType);
return VK_ERROR_FORMAT_NOT_SUPPORTED;
}
}
res = p_vkGetPhysicalDeviceImageFormatProperties2(phys_dev, &format_info_host, properties);
if (external_image_info_dup)
free_VkPhysicalDeviceImageFormatInfo2_struct_chain(&format_info_host); if ((external_image_properties = wine_vk_find_struct(properties, EXTERNAL_IMAGE_FORMAT_PROPERTIES))) { VkExternalMemoryProperties *p = &external_image_properties->externalMemoryProperties;
p->externalMemoryFeatures = 0;
p->exportFromImportedHandleTypes = 0;
p->compatibleHandleTypes = 0;
if (p->exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
p->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
if (p->compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
p->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; } return res;
}
-VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice phys_dev, +VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev, const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties) {
VkExternalImageFormatProperties *external_image_properties;
VkResult res;
TRACE("%p, %p, %p\n", phys_dev, format_info, properties);
res = thunk_vkGetPhysicalDeviceImageFormatProperties2KHR(phys_dev, format_info, properties);
- return wine_vk_get_physical_device_image_format_properties_2(phys_dev, thunk_vkGetPhysicalDeviceImageFormatProperties2, format_info, properties);
+}
- if ((external_image_properties = wine_vk_find_struct(properties, EXTERNAL_IMAGE_FORMAT_PROPERTIES)))
- {
VkExternalMemoryProperties *p = &external_image_properties->externalMemoryProperties;
p->externalMemoryFeatures = 0;
p->exportFromImportedHandleTypes = 0;
p->compatibleHandleTypes = 0;
- }
+VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice phys_dev,
const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties)
+{
- TRACE("%p, %p, %p\n", phys_dev, format_info, properties);
- return res;
return wine_vk_get_physical_device_image_format_properties_2(phys_dev, thunk_vkGetPhysicalDeviceImageFormatProperties2KHR, format_info, properties); }
/* From ntdll/unix/sync.c */
@@ -1720,3 +1802,283 @@ VkResult WINAPI wine_vkDebugMarkerSetObjectNameEXT(VkDevice device, const VkDebu
return thunk_vkDebugMarkerSetObjectNameEXT(device, &wine_name_info);
}
+static HANDLE create_gpu_resource(int fd, LPCWSTR name) +{
- HANDLE ret = INVALID_HANDLE_VALUE;
- if (name)
FIXME("Naming gpu resources not supported.\n");
- wine_server_fd_to_handle(fd, GENERIC_ALL, 0, &ret);
- return ret;
+}
+VkResult WINAPI wine_vkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *allocate_info,
- const VkAllocationCallbacks *allocator, VkDeviceMemory *memory)
+{
- const VkImportMemoryWin32HandleInfoKHR *handle_import_info;
- const VkExportMemoryWin32HandleInfoKHR *handle_export_info;
- VkMemoryAllocateInfo allocate_info_dup = *allocate_info;
- VkExportMemoryAllocateInfo *export_info;
- VkImportMemoryFdInfoKHR fd_import_info;
- struct wine_dev_mem *object;
- VkResult res;
- int fd;
+#if defined(USE_STRUCT_CONVERSION)
VkMemoryAllocateInfo_host allocate_info_host;
VkMemoryGetFdInfoKHR_host get_fd_info;
+#else
VkMemoryAllocateInfo allocate_info_host;
VkMemoryGetFdInfoKHR get_fd_info;
+#endif
This indention is wrong.
- TRACE("%p %p %p %p\n", device, allocate_info, allocator, memory);
- if (allocator)
FIXME("Support for allocation callbacks not implemented yet\n");
- if ((res = convert_VkMemoryAllocateInfo_struct_chain(allocate_info->pNext, &allocate_info_dup)) < 0)
- {
WARN("Failed to convert VkMemoryAllocateInfo pNext chain, res=%d.\n", res);
return res;
- }
- if (!(object = calloc(1, sizeof(*object))))
- {
free_VkMemoryAllocateInfo_struct_chain(&allocate_info_dup);
return VK_ERROR_OUT_OF_HOST_MEMORY;
- }
- object->dev_mem = VK_NULL_HANDLE;
- object->handle = INVALID_HANDLE_VALUE;
- fd_import_info.fd = -1;
- fd_import_info.pNext = NULL;
- /* find and process handle import/export info and grab it */
- handle_import_info = wine_vk_find_struct(allocate_info, IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR);
- handle_export_info = wine_vk_find_struct(allocate_info, EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR);
- if (handle_export_info && handle_export_info->pAttributes && handle_export_info->pAttributes->lpSecurityDescriptor)
FIXME("Support for custom security descriptor not implemented.\n");
- if ((export_info = wine_vk_find_struct(&allocate_info_dup, EXPORT_MEMORY_ALLOCATE_INFO)))
- {
object->handle_types = export_info->handleTypes;
if (object->handle_types &~ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)
{
res = VK_ERROR_OUT_OF_HOST_MEMORY;
VK_ERROR_UNKNOWN sounds like a better idea.
goto done;
}
if (object->handle_types)
export_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
- }
- /* Vulkan consumes imported FDs, but not imported HANDLEs */
- if (handle_import_info)
- {
fd_import_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
fd_import_info.pNext = allocate_info_dup.pNext;
fd_import_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
switch (handle_import_info->handleType)
{
case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT:
if (handle_import_info->handle)
NtDuplicateObject( NtCurrentProcess(), handle_import_info->handle, NtCurrentProcess(), &object->handle, 0, 0, DUPLICATE_SAME_ACCESS );
else if (handle_import_info->name)
FIXME("Importing device memory by resource name not supported.\n");
break;
default:
WARN("Invalid handle type %08x passed in.\n", handle_import_info->handleType);
res = VK_ERROR_INVALID_EXTERNAL_HANDLE;
goto done;
}
if (object->handle != INVALID_HANDLE_VALUE)
wine_server_handle_to_fd(object->handle, FILE_READ_DATA, &fd_import_info.fd, NULL);
if (fd_import_info.fd == -1)
{
TRACE("Couldn't access resource handle or name. type=%08x handle=%p name=%s\n", handle_import_info->handleType, handle_import_info->handle,
handle_import_info->name ? debugstr_w(handle_import_info->name) : "");
res = VK_ERROR_INVALID_EXTERNAL_HANDLE;
goto done;
}
- }
- allocate_info_host.sType = allocate_info_dup.sType;
- allocate_info_host.pNext = fd_import_info.fd == -1 ? allocate_info_dup.pNext : &fd_import_info;
- allocate_info_host.allocationSize = allocate_info_dup.allocationSize;
- allocate_info_host.memoryTypeIndex = allocate_info_dup.memoryTypeIndex;
- if ((res = device->funcs.p_vkAllocateMemory(device->device, &allocate_info_host, NULL, &object->dev_mem)) == VK_SUCCESS)
- {
if (object->handle == INVALID_HANDLE_VALUE && export_info && export_info->handleTypes)
{
get_fd_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR;
get_fd_info.pNext = NULL;
get_fd_info.memory = object->dev_mem;
get_fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
if (device->funcs.p_vkGetMemoryFdKHR(device->device, &get_fd_info, &fd) == VK_SUCCESS)
{
object->handle = create_gpu_resource(fd, handle_export_info ? handle_export_info->name : NULL);
object->access = handle_export_info ? handle_export_info->dwAccess : GENERIC_ALL;
if (handle_export_info && handle_export_info->pAttributes)
object->inherit = handle_export_info->pAttributes->bInheritHandle;
else
object->inherit = FALSE;
close(fd);
}
if (object->handle == INVALID_HANDLE_VALUE)
{
res = VK_ERROR_OUT_OF_HOST_MEMORY;
goto done;
}
}
WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(device->phys_dev->instance, object, object->dev_mem);
*memory = wine_dev_mem_to_handle(object);
- }
- done:
- if (res != VK_SUCCESS)
- {
device->funcs.p_vkFreeMemory(device->device, object->dev_mem, NULL);
if (fd_import_info.fd != -1)
close(fd_import_info.fd);
if (object->handle != INVALID_HANDLE_VALUE)
NtClose(object->handle);
free(object);
- }
- free_VkMemoryAllocateInfo_struct_chain(&allocate_info_dup);
- return res;
+}
+VkResult WINAPI wine_vkGetMemoryWin32HandleKHR(VkDevice device,
- const VkMemoryGetWin32HandleInfoKHR *handle_info, HANDLE *handle)
+{
- struct wine_dev_mem *dev_mem = wine_dev_mem_from_handle(handle_info->memory);
- const VkBaseInStructure *chain;
- TRACE("%p, %p %p\n", device, handle_info, handle);
- if (!(dev_mem->handle_types & handle_info->handleType))
return VK_ERROR_OUT_OF_HOST_MEMORY;
VK_ERROR_UNKNOWN is probably better here as well.
- if ((chain = handle_info->pNext))
FIXME("Ignoring a linked structure of type %u.\n", chain->sType);
- switch(handle_info->handleType)
- {
case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT:
return !NtDuplicateObject( NtCurrentProcess(), dev_mem->handle, NtCurrentProcess(), handle, dev_mem->access, dev_mem->inherit ? OBJ_INHERIT : 0, 0) ?
VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY;
default:
return VK_ERROR_UNKNOWN;
- }
+}
+void WINAPI wine_vkFreeMemory(VkDevice device, VkDeviceMemory handle, const VkAllocationCallbacks *allocator) +{
- struct wine_dev_mem *dev_mem = wine_dev_mem_from_handle(handle);
- TRACE("%p 0x%s, %p\n", device, wine_dbgstr_longlong(handle), allocator);
- if (allocator)
FIXME("Support for allocation callbacks not implemented yet\n");
- if (!handle)
return;
- WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, dev_mem);
- device->funcs.p_vkFreeMemory(device->device, dev_mem->dev_mem, NULL);
- if (dev_mem->handle != INVALID_HANDLE_VALUE)
NtClose(dev_mem->handle);
- free(dev_mem);
+}
+VkResult WINAPI wine_vkGetMemoryWin32HandlePropertiesKHR(VkDevice device,
VkExternalMemoryHandleTypeFlagBits type, HANDLE handle, VkMemoryWin32HandlePropertiesKHR *properties)
+{
- TRACE("%p %u %p %p\n", device, type, handle, properties);
- /* VUID-vkGetMemoryWin32HandlePropertiesKHR-handleType-00666
handleType must not be one of the handle types defined as opaque */
- return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+}
+VkResult WINAPI wine_vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *create_info,
- const VkAllocationCallbacks *allocator, VkBuffer *buffer)
+{
- VkExternalMemoryBufferCreateInfo *external_memory_info;
- VkBufferCreateInfo create_info_dup;
Why do we need this? Couldn't you just call convert_VkBufferCreateInfo_struct_chain on create_info_host directly?
- VkResult res;
+#if defined(USE_STRUCT_CONVERSION)
- VkBufferCreateInfo_host create_info_host;
+#else
- VkBufferCreateInfo create_info_host;
+#endif
- if (allocator)
FIXME("Support for allocation callbacks not implemented yet\n");
- if ((res = convert_VkBufferCreateInfo_struct_chain(create_info->pNext, &create_info_dup)))
- {
WARN("Failed to convert VkBufferCreateInfo pNext chain, res=%d.\n", res);
return res;
- }
- if ((external_memory_info = wine_vk_find_struct(&create_info_dup, EXTERNAL_MEMORY_BUFFER_CREATE_INFO)) &&
external_memory_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR)
external_memory_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
- create_info_host.pNext = create_info_dup.pNext;
- create_info_host.sType = create_info->sType;
- create_info_host.flags = create_info->flags;
- create_info_host.size = create_info->size;
- create_info_host.usage = create_info->usage;
- create_info_host.sharingMode = create_info->sharingMode;
- create_info_host.queueFamilyIndexCount = create_info->queueFamilyIndexCount;
- create_info_host.pQueueFamilyIndices = create_info->pQueueFamilyIndices;
- res = device->funcs.p_vkCreateBuffer(device->device, &create_info_host, NULL, buffer);
- free_VkBufferCreateInfo_struct_chain(&create_info_dup);
- return res;
+}
+VkResult WINAPI wine_vkCreateImage(VkDevice device, const VkImageCreateInfo *create_info,
- const VkAllocationCallbacks *allocator, VkBuffer *image)
+{
- VkExternalMemoryImageCreateInfo *external_memory_info;
- VkImageCreateInfo create_info_host;
This is never initialized.
- VkResult res;
- if (allocator)
FIXME("Support for allocation callbacks not implemented yet\n");
- if ((res = convert_VkImageCreateInfo_struct_chain(create_info->pNext, &create_info_host)))
- {
WARN("Failed to convert VkImageCreateInfo pNext chain, res=%d.\n", res);
return res;
- }
- if ((external_memory_info = wine_vk_find_struct(&create_info_host, EXTERNAL_MEMORY_BUFFER_CREATE_INFO)) &&
wrong sType
external_memory_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR)
external_memory_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
- res = device->funcs.p_vkCreateImage(device->device, &create_info_host, NULL, image);
- free_VkImageCreateInfo_struct_chain(&create_info_host);
- return res;
+} diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 83dc90ca15e..4a20702d43b 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -204,6 +204,30 @@ static inline VkSurfaceKHR wine_surface_to_handle(struct wine_surface *surface) return (VkSurfaceKHR)(uintptr_t)surface; }
+struct wine_dev_mem +{
- VkDeviceMemory dev_mem;
- VkExternalMemoryHandleTypeFlagBits handle_types;
- BOOL inherit;
- DWORD access;
- HANDLE handle;
- struct wine_vk_mapping mapping;
+};
+static inline struct wine_dev_mem *wine_dev_mem_from_handle(VkDeviceMemory handle) +{
- return (struct wine_dev_mem *)(uintptr_t)handle;
+}
+static inline VkDeviceMemory wine_dev_mem_to_handle(struct wine_dev_mem *dev_mem) +{
- return (VkDeviceMemory)(uintptr_t)dev_mem;
+}
- BOOL wine_vk_device_extension_supported(const char *name) DECLSPEC_HIDDEN; BOOL wine_vk_instance_extension_supported(const char *name) DECLSPEC_HIDDEN;
On 5/18/21 12:21 PM, Georg Lehmann wrote:+VkResult WINAPI wine_vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *create_info,
+ const VkAllocationCallbacks *allocator, VkBuffer *buffer) +{ + VkExternalMemoryBufferCreateInfo *external_memory_info; + VkBufferCreateInfo create_info_dup;
Why do we need this? Couldn't you just call convert_VkBufferCreateInfo_struct_chain on create_info_host directly?
No, convert_<type>_struct_chain doesn't accept _host output structs.
On 18.05.21 22:28, Derek Lesho wrote:
On 5/18/21 12:21 PM, Georg Lehmann wrote:+VkResult WINAPI wine_vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *create_info,
+ const VkAllocationCallbacks *allocator, VkBuffer *buffer) +{ + VkExternalMemoryBufferCreateInfo *external_memory_info; + VkBufferCreateInfo create_info_dup;
Why do we need this? Couldn't you just call convert_VkBufferCreateInfo_struct_chain on create_info_host directly?
No, convert_<type>_struct_chain doesn't accept _host output structs.
But they doesn't use anything but sType and pNext. So you might es well just reinterpret cast. Not that this would be pretty, but having a separate struct just to make the types match seems a bit silly imo.
Signed-off-by: Liam Middlebrook lmiddlebrook@nvidia.com
On 5/17/21 1:00 PM, Derek Lesho wrote:
Signed-off-by: Derek Lesho dlesho@codeweavers.com
dlls/winevulkan/make_vulkan | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index cc79b0a58cd..7f76d328fc8 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -256,10 +256,11 @@ FUNCTION_OVERRIDES = { "vkDebugMarkerSetObjectTagEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE}, }
-STRUCT_CHAIN_CONVERSIONS = [
- "VkDeviceCreateInfo",
- "VkInstanceCreateInfo",
-] +STRUCT_CHAIN_CONVERSIONS = {
- # Ignore to not confuse host loader.
- "VkDeviceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO"],
- "VkInstanceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO"],
+}
class Direction(Enum): @@ -2417,9 +2418,10 @@ class FreeFunction(object):
class StructChainConversionFunction(object):
- def __init__(self, direction, struct):
def __init__(self, direction, struct, ignores): self.direction = direction self.struct = struct
self.ignores = ignores self.type = struct.name self.name = "convert_{0}_struct_chain".format(self.type)
@@ -2444,9 +2446,8 @@ class StructChainConversionFunction(object): body += " switch (in_header->sType)\n" body += " {\n"
# Ignore to not confuse host loader.
body += " case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO:\n"
body += " case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO:\n"
for i in self.ignores:
body += " case {0}:\n".format(i) body += " break;\n\n" for e in self.struct.struct_extensions:
@@ -2455,6 +2456,9 @@ class StructChainConversionFunction(object):
stype = next(x for x in e.members if x.name == "sType")
if stype.values in self.ignores:
continue
body += " case {0}:\n".format(stype.values) body += " {\n"
@@ -2604,7 +2608,7 @@ class VkGenerator(object):
for struct in self.registry.structs: if struct.name in STRUCT_CHAIN_CONVERSIONS:
self.struct_chain_conversions.append(StructChainConversionFunction(Direction.INPUT, struct))
self.struct_chain_conversions.append(StructChainConversionFunction(Direction.INPUT, struct, STRUCT_CHAIN_CONVERSIONS[struct.name])) self.struct_chain_conversions.append(FreeStructChainFunction(struct)) # Once we decide to support pNext chains conversion everywhere, move this under get_conversions for e in struct.struct_extensions: