[PATCH v2] winevulkan: Add support for unwrapping handles in thunks.

Georg Lehmann dadschoorse at gmail.com
Thu May 13 04:49:30 CDT 2021



On 12.05.21 18:00, Derek Lesho wrote:
> ---
> v2:
>    - Addressed comments
>    - Explicitely named conv parameters for `VkMember.copy` and `VkMember.free` methods
> ---
>   dlls/winevulkan/make_vulkan | 568 +++++++++++++++++++++++++++---------
>   dlls/winevulkan/vulkan.c    | 142 +--------
>   2 files changed, 433 insertions(+), 277 deletions(-)
> 
> diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan
> index d5cc62d2097..02a0e4bfac7 100755
> --- a/dlls/winevulkan/make_vulkan
> +++ b/dlls/winevulkan/make_vulkan
> @@ -185,7 +185,6 @@ FUNCTION_OVERRIDES = {
>   
>       # Device functions
>       "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
> -    "vkCmdExecuteCommands" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},

Put this in a separate commit.

>       "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
>       "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
>       "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
> @@ -193,7 +192,6 @@ FUNCTION_OVERRIDES = {
>       "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},
> -    "vkQueueSubmit" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},

Another separate commit for this.

>   
>       # VK_KHR_surface
>       "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE},
> @@ -204,14 +202,14 @@ FUNCTION_OVERRIDES = {
>   
>       # VK_KHR_get_surface_capabilities2
>       "vkGetPhysicalDeviceSurfaceCapabilities2KHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PRIVATE},
> -    "vkGetPhysicalDeviceSurfaceFormats2KHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PRIVATE},
> +    "vkGetPhysicalDeviceSurfaceFormats2KHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
>   
>       # VK_KHR_win32_surface
>       "vkCreateWin32SurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE},
>       "vkGetPhysicalDeviceWin32PresentationSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
>   
>       # VK_KHR_swapchain
> -    "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PRIVATE},
> +    "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
>       "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
>       "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
>       "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC},
> @@ -645,6 +643,18 @@ class VkFunction(object):
>   
>           return False
>   
> +    def needs_unwrapping(self):
> +        """ Check if the function needs any input/output type unwrapping.
> +        Functions need input/output unwrapping if struct parameters have
> +        wrapped dispatchable handles. > +        """

Not just dispatchable handles, non-dispatchable ones as well, e.g. 
VkSurfaceKHR. Please change it to just wrapped handles in all comments.

> +
> +        for p in self.params:
> +            if p.needs_unwrapping():
> +                return True
> +
> +        return False
> +
>       def needs_dispatch(self):
>           return self.dispatch
>   
> @@ -739,7 +749,7 @@ class VkFunction(object):
>   
>           return body
>   
> -    def body_conversion(self):
> +    def body_conversion(self, conv):
>           body = ""
>   
>           # Declare a variable to hold the result for non-void functions.
> @@ -748,27 +758,28 @@ class VkFunction(object):
>   
>           # Declare any tmp parameters for conversion.
>           for p in self.params:
> -            if not p.needs_conversion():
> -                continue
> -
> -            if p.is_dynamic_array():
> -                body += "    {0}_host *{1}_host;\n".format(p.type, p.name)
> -            else:
> -                body += "    {0}_host {1}_host;\n".format(p.type, p.name)
> +            if p.needs_conversion() and conv:
> +                if p.is_dynamic_array():
> +                    body += "    {0}_host *{1}_host;\n".format(p.type, p.name)
> +                else:
> +                    body += "    {0}_host {1}_host;\n".format(p.type, p.name)
> +            elif p.needs_unwrapping():
> +                if p.is_dynamic_array():
> +                    body += "    {0} *{1}_host;\n".format(p.type, p.name)
> +                else:
> +                    body += "    {0} {1}_host;\n".format(p.type, p.name)
>   
>           if not self.needs_private_thunk():
>               body += "    {0}\n".format(self.trace())
>   
>           # Call any win_to_host conversion calls.
>           for p in self.params:
> -            if not p.needs_input_conversion():
> -                continue
> -
> -            body += p.copy(Direction.INPUT)
> +            if p.needs_input_conversion() and (p.needs_unwrapping() or conv):
> +                body += p.copy(Direction.INPUT)
>   
>           # Build list of parameters containing converted and non-converted parameters.
>           # The param itself knows if conversion is needed and applies it when we set conv=True.
> -        params = ", ".join([p.variable(conv=True) for p in self.params])
> +        params = ", ".join([p.variable(conv=conv) for p in self.params])
>   
>           # Call the native Vulkan function.
>           if self.type == "void":
> @@ -787,10 +798,8 @@ class VkFunction(object):
>   
>           # Perform any required cleanups. Most of these are for array functions.
>           for p in self.params:
> -            if not p.needs_free():
> -                continue
> -
> -            body += p.free()
> +            if p.needs_free() and (p.needs_unwrapping() or conv):
> +                body += p.free()
>   
>           # Finally return the result.
>           if self.type != "void":
> @@ -840,10 +849,15 @@ class VkFunction(object):
>   
>           if self.needs_conversion():
>               thunk += "#if defined(USE_STRUCT_CONVERSION)\n"
> -            thunk += self.body_conversion()
> +            thunk += self.body_conversion(conv=True)
>               thunk += "#else\n"
> -            thunk += self.body()
> +            if self.needs_unwrapping():
> +                thunk += self.body_conversion(conv=False)
> +            else:
> +                thunk += self.body()
>               thunk += "#endif\n"
> +        elif self.needs_unwrapping():
> +            thunk += self.body_conversion(conv=False)
>           else:
>               thunk += self.body()
>   
> @@ -1063,6 +1077,12 @@ class VkHandle(object):
>       def is_wrapped(self):
>           return self.native_handle("test") is not None
>   
> +    def needs_conversion(self):
> +        return False
> +
> +    def needs_unwrapping(self):
> +        return self.is_wrapped()
> +
>   class VkMember(object):
>       def __init__(self, const=False, struct_fwd_decl=False,_type=None, pointer=None, name=None, array_len=None,
>               dyn_array_len=None, optional=False, values=None):
> @@ -1148,10 +1168,11 @@ class VkMember(object):
>           return VkMember(const=const, struct_fwd_decl=struct_fwd_decl, _type=member_type, pointer=pointer, name=name_elem.text,
>                   array_len=array_len, dyn_array_len=dyn_array_len, optional=optional, values=values)
>   
> -    def copy(self, input, output, direction):
> -        """ Helper method for use by conversion logic to generate a C-code statement to copy this member. """
> +    def copy(self, input, output, direction, conv):
> +        """ Helper method for use by conversion logic to generate a C-code statement to copy this member.
> +            - `conv` indicates whether the statement is in a struct alignment conversion path. """
>   
> -        if self.needs_conversion():
> +        if (conv and self.needs_conversion()) or self.needs_unwrapping():
>               if self.is_dynamic_array():
>                   if direction == Direction.OUTPUT:
>                       LOGGER.warn("TODO: implement copying of returnedonly dynamic array for {0}.{1}".format(self.type, self.name))
> @@ -1167,6 +1188,12 @@ class VkMember(object):
>                   else:
>                       # Nothing needed this yet.
>                       LOGGER.warn("TODO: implement copying of static array for {0}.{1}".format(self.type, self.name))
> +            elif self.is_handle() and self.needs_unwrapping():
> +                if direction == Direction.OUTPUT:
> +                    LOGGER.err("Only INPUT parameters can be unwrapped")

Log the handle name here.

> +                else:
> +                    handle = self.type_info["data"]
> +                    return "{0}{1} = {2};\n".format(output, self.name, handle.driver_handle("{0}{1}".format(input, self.name)))
>               else:
>                   if direction == Direction.OUTPUT:
>                       return "convert_{0}_host_to_win(&{2}{1}, &{3}{1});\n".format(self.type, self.name, input, output)
> @@ -1178,6 +1205,27 @@ class VkMember(object):
>           else:
>               return "{0}{1} = {2}{1};\n".format(output, self.name, input)
>   
> +    def free(self, location, conv):
> +        """ Helper method for use by conversion logic to generate a C-code statement to free this member. """
> +
> +        if not self.needs_unwrapping() and not conv:
> +            return ""
> +
> +        cast = ("(" + self.type + ("_host" if conv and self.needs_conversion() else "") + " *)") if self.is_const() else ""

This is not readable at all nor is it understandable.

> +        if self.is_dynamic_array():
> +            count = self.dyn_array_len if isinstance(self.dyn_array_len, int) else "{0}{1}".format(location, self.dyn_array_len)
> +            if self.is_struct() and self.type_info["data"].returnedonly:
> +                # For returnedonly, counts is stored in a pointer.
> +                return "free_{0}_array({1}{2}{3}, *{4});\n".format(self.type, cast, location, self.name, count)
> +            else:
> +                return "free_{0}_array({1}{2}{3}, {4});\n".format(self.type, cast, location, self.name, count)
> +        else:
> +            # We are operating on a single structure. Some structs (very rare) contain dynamic members,
> +            # which would need freeing.
> +            if self.needs_free():
> +                return "free_{0}({1}&{2}{3});\n".format(self.type, cast, location, self.name)
> +        return ""
> +
>       def definition(self, align=False, conv=False):
>           """ Generate prototype for given function.
>   
> @@ -1216,31 +1264,34 @@ class VkMember(object):
>   
>           # Check if we need conversion either for this member itself or for any child members
>           # in case member represents a struct.
> -        if not self.needs_conversion():
> +        if not self.needs_conversion() and not self.needs_unwrapping():
>               return None
>   
>           conversions = []
>   
>           # Collect any conversion for any member structs.
> -        struct = self.type_info["data"]
> -        for m in struct:
> -            m.needs_struct_extensions_conversion()
> -            if m.needs_conversion():
> -                conversions.extend(m.get_conversions())
> +        if self.is_struct():
> +            struct = self.type_info["data"]
> +            for m in struct:
> +                m.needs_struct_extensions_conversion()
> +                if m.needs_conversion() or m.needs_unwrapping():
> +                    conversions.extend(m.get_conversions())
>   
> -        struct.needs_struct_extensions_conversion()
> +            struct.needs_struct_extensions_conversion()
> +            direction = Direction.OUTPUT if struct.returnedonly else Direction.INPUT
> +        elif self.is_handle():
> +            direction = Direction.INPUT
>   
> -        struct = self.type_info["data"]
> -        direction = Direction.OUTPUT if struct.returnedonly else Direction.INPUT
> +        operand = self.type_info["data"]
>           if self.is_dynamic_array():
> -            conversions.append(ConversionFunction(False, True, direction, struct))
> +            conversions.append(ConversionFunction(False, True, direction, operand))
>           elif self.is_static_array():
> -            conversions.append(ConversionFunction(True, False, direction, struct))
> +            conversions.append(ConversionFunction(True, False, direction, operand))
>           else:
> -            conversions.append(ConversionFunction(False, False, direction, struct))
> +            conversions.append(ConversionFunction(False, False, direction, operand))
>   
>           if self.needs_free():
> -            conversions.append(FreeFunction(self.is_dynamic_array(), struct))
> +            conversions.append(FreeFunction(self.is_dynamic_array(), operand))
>   
>           return conversions
>   
> @@ -1307,8 +1358,21 @@ class VkMember(object):
>           struct = self.type_info["data"]
>           return struct.needs_conversion()
>   
> +    def needs_unwrapping(self):
> +        """ Structures with wrapped dispatchable handles, need unwrapping. """
> +
> +        if self.is_struct():
> +            struct = self.type_info["data"]
> +            return struct.needs_unwrapping()
> +
> +        if self.is_handle():
> +            handle = self.type_info["data"]
> +            return handle.is_wrapped()
> +
> +        return False
> +
>       def needs_free(self):
> -        if not self.needs_conversion():
> +        if not self.needs_conversion() and not self.needs_unwrapping():
>               return False
>   
>           if self.is_dynamic_array():
> @@ -1392,21 +1456,23 @@ class VkParam(object):
>           self.free_func = None
>           self.input_conv = None
>           self.output_conv = None
> -        if not self.needs_conversion():
> +        if not self.needs_conversion() and not self.needs_unwrapping():
>               return
>   
> +        operand = self.struct if self.is_struct() else self.handle
> +
>           # Input functions require win to host conversion.
>           if self._direction in [Direction.INPUT, Direction.INPUT_OUTPUT]:
> -            self.input_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.INPUT, self.struct)
> +            self.input_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.INPUT, operand)
>   
>           # Output functions require host to win conversion.
>           if self._direction in [Direction.INPUT_OUTPUT, Direction.OUTPUT]:
> -            self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, self.struct)
> +            self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, operand)
>   
>           # Dynamic arrays, but also some normal structs (e.g. VkCommandBufferBeginInfo) need memory
>           # allocation and thus some cleanup.
>           if self.is_dynamic_array() or self.struct.needs_free():
> -            self.free_func = FreeFunction(self.is_dynamic_array(), self.struct)
> +            self.free_func = FreeFunction(self.is_dynamic_array(), operand)
>   
>       def _set_direction(self):
>           """ Internal helper function to set parameter direction (input/output/input_output). """
> @@ -1544,7 +1610,7 @@ class VkParam(object):
>   
>       def free(self):
>           if self.is_dynamic_array():
> -            if self.struct.returnedonly:
> +            if self.is_struct() and self.struct.returnedonly:
>                   # For returnedonly, counts is stored in a pointer.
>                   return "    free_{0}_array({1}_host, *{2});\n".format(self.type, self.name, self.dyn_array_len)
>               else:
> @@ -1552,7 +1618,7 @@ class VkParam(object):
>           else:
>               # We are operating on a single structure. Some structs (very rare) contain dynamic members,
>               # which would need freeing.
> -            if self.struct.needs_free():
> +            if self.is_struct() and self.struct.needs_free():
>                   return "    free_{0}(&{1}_host);\n".format(self.type, self.name)
>           return ""
>   
> @@ -1563,14 +1629,14 @@ class VkParam(object):
>           required.
>           """
>   
> -        if not self.is_struct():
> +        if self.is_struct():
> +            self.struct.needs_struct_extensions_conversion()
> +            for m in self.struct:
> +                m.needs_struct_extensions_conversion()
> +        elif not self.is_handle():
>               return None
>   
> -        self.struct.needs_struct_extensions_conversion()
> -        for m in self.struct:
> -            m.needs_struct_extensions_conversion()
> -
> -        if not self.needs_conversion():
> +        if not self.needs_conversion() and not self.needs_unwrapping():
>               return None
>   
>           conversions = []
> @@ -1578,14 +1644,15 @@ class VkParam(object):
>           # Collect any member conversions first, so we can guarantee
>           # those functions will be defined prior to usage by the
>           # 'parent' param requiring conversion.
> -        for m in self.struct:
> -            if not m.is_struct():
> -                continue
> +        if self.is_struct():
> +            for m in self.struct:
> +                if not m.is_struct():
> +                    continue
>   
> -            if not m.needs_conversion():
> -                continue
> +                if not m.needs_conversion() and not m.needs_unwrapping():
> +                    continue
>   
> -            conversions.extend(m.get_conversions())
> +                conversions.extend(m.get_conversions())
>   
>           # Conversion requirements for the 'parent' parameter.
>           if self.input_conv is not None:
> @@ -1641,6 +1708,18 @@ class VkParam(object):
>   
>           return False
>   
> +    def needs_unwrapping(self):
> +        """ Returns if parameter needs unwrapping of dispatchable handle. """
> +
> +        # Wrapped handle parameters are handled seperately, only look for wrapped handles in structs
> +        if self.is_struct():
> +            return self.struct.needs_unwrapping()
> +
> +        if self.is_handle() and self.is_dynamic_array():
> +            return self.handle.needs_unwrapping()
> +
> +        return False
> +
>       def needs_free(self):
>           return self.free_func is not None
>   
> @@ -1691,7 +1770,7 @@ class VkParam(object):
>               LOGGER.debug("TODO: setting NULL VkAllocationCallbacks for {0}".format(self.name))
>               return "NULL"
>   
> -        if conv and self.needs_conversion():
> +        if self.needs_unwrapping() or (conv and self.needs_conversion()):
>               if self.is_dynamic_array():
>                   return "{0}_host".format(self.name)
>               else:
> @@ -1880,6 +1959,14 @@ class VkStruct(Sequence):
>                   return True
>           return False
>   
> +    def needs_unwrapping(self):
> +        """ Returns if struct members need unwrapping of a dispatchable handle. """
> +
> +        for m in self.members:
> +            if m.needs_unwrapping():
> +                return True
> +        return False
> +
>       def needs_free(self):
>           """ Check if any struct member needs some memory freeing."""
>   
> @@ -1897,7 +1984,10 @@ class VkStruct(Sequence):
>   
>           for e in self.struct_extensions:
>               if e.required and e.needs_conversion():
> -                LOGGER.error("Unhandled pNext chain conversion for {0}".format(e.name))
> +                LOGGER.error("Unhandled pNext chain alignment conversion for {0}".format(e.name))
> +                ret = True
> +            if e.required and e.needs_unwrapping():
> +                LOGGER.error("Unhandled pNext chain unwrapping conversion for {0}".format(e.name))
>                   ret = True
>   
>           return ret
> @@ -1913,12 +2003,12 @@ class VkStruct(Sequence):
>   
>   
>   class ConversionFunction(object):
> -    def __init__(self, array, dyn_array, direction, struct):
> +    def __init__(self, array, dyn_array, direction, operand):
>           self.array = array
>           self.direction = direction
>           self.dyn_array = dyn_array
> -        self.struct = struct
> -        self.type = struct.name
> +        self.operand = operand
> +        self.type = operand.name
>   
>           self._set_name()
>   
> @@ -1926,21 +2016,44 @@ class ConversionFunction(object):
>           return self.name == other.name
>   
>       def _generate_array_conversion_func(self):
> -        """ Helper function for generating a conversion function for array structs. """
> +        """ Helper function for generating a conversion function for array operands. """
> +
> +        body = ""
> +
> +        if self.operand.needs_conversion():
> +            body += "#if defined(USE_STRUCT_CONVERSION)\n"
> +
> +            if self.direction == Direction.OUTPUT:
> +                params = ["const {0}_host *in".format(self.type), "uint32_t count"]
> +                return_type = self.type
> +            else:
> +                params = ["const {0} *in".format(self.type), "uint32_t count"]
> +                return_type = "{0}_host".format(self.type)
> +
> +            # Generate function prototype.
> +            body += "static inline {0} *{1}(".format(return_type, self.name)
> +            body += ", ".join(p for p in params)
> +            body += ")\n{\n"
> +
> +            body += "    {0} *out;\n".format(return_type)
> +
> +        if self.operand.needs_unwrapping():
> +            if self.operand.needs_conversion():
> +                body += "#else\n"
>   
> -        if self.direction == Direction.OUTPUT:
> -            params = ["const {0}_host *in".format(self.type), "uint32_t count"]
> -            return_type = self.type
> -        else:
>               params = ["const {0} *in".format(self.type), "uint32_t count"]
> -            return_type = "{0}_host".format(self.type)
> +            return_type = "{0}".format(self.type)
>   
> -        # Generate function prototype.
> -        body = "static inline {0} *{1}(".format(return_type, self.name)
> -        body += ", ".join(p for p in params)
> -        body += ")\n{\n"
> +            # Generate function prototype.
> +            body += "static inline {0} *{1}(".format(return_type, self.name)
> +            body += ", ".join(p for p in params)
> +            body += ")\n{\n"
> +
> +            body += "    {0} *out;\n".format(return_type)
> +
> +            if self.operand.needs_conversion():
> +                body += "#endif /* USE_STRUCT_CONVERSION */\n"
>   
> -        body += "    {0} *out;\n".format(return_type)
>           body += "    unsigned int i;\n\n"
>           body += "    if (!in) return NULL;\n\n"
>   
> @@ -1949,33 +2062,74 @@ class ConversionFunction(object):
>           body += "    for (i = 0; i < count; i++)\n"
>           body += "    {\n"
>   
> -        for m in self.struct:
> -            # TODO: support copying of pNext extension structures!
> -            # Luckily though no extension struct at this point needs conversion.
> -            body += "        " + m.copy("in[i].", "out[i].", self.direction)
> +        if isinstance(self.operand, VkStruct):
> +            for m in self.operand:
> +                # TODO: support copying of pNext extension structures!
> +                # Luckily though no extension struct at this point needs conversion.
> +                convert = m.copy("in[i].", "out[i].", self.direction, conv=True)
> +                if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
> +                    body += "        " + convert
> +                else:
> +                    unwrap = m.copy("in[i].", "out[i].", self.direction, conv=False)
> +                    if unwrap == convert:
> +                        body += "        " + unwrap
> +                    else:
> +                        body += "#if defined(USE_STRUCT_CONVERSION)\n        {0}#else\n        {1}#endif /* USE_STRUCT_CONVERSION */\n".format(convert, unwrap)
> +
Split this into 5 lines.


> +        elif isinstance(self.operand, VkHandle) and self.direction == Direction.INPUT:
> +            body += "        out[i] = " + self.operand.driver_handle("in[i]") + ";\n"
> +        else:
> +            LOGGER.warn("Unhandled conversion operand type")
> +            body += "        out[i] = in[i];\n"
>   
>           body += "    }\n\n"
>           body += "    return out;\n"
>           body += "}\n\n"
> +        # endif is appended by FreeFunction

Not sure if this is a good thing, why not end it here and open a new #if 
for the free function?

> +
>           return body
>   
>       def _generate_conversion_func(self):
> -        """ Helper function for generating a conversion function for non-array structs. """
> +        """ Helper function for generating a conversion function for non-array operands. """
>   
> -        if self.direction == Direction.OUTPUT:
> -            params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type)]
> -        else:
> -            params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
> +        # It doesn't make sense to generate conversion functions for non-struct variables
> +        # which aren't in arrays, as this should be handled by the copy() function
> +        if not isinstance(self.operand, VkStruct):
> +            return ""
>   
> -        body = "static inline void {0}(".format(self.name)
> +        body = ""
>   
> -        # Generate parameter list
> -        body += ", ".join(p for p in params)
> -        body += ")\n{\n"
> +        if self.operand.needs_conversion():
> +            body += "#if defined (USE_STRUCT_CONVERSION)\n"

Drop the space between defined and (

> +            body += "static inline void {0}(".format(self.name)
>   
> -        body += "    if (!in) return;\n\n"
> +            if self.direction == Direction.OUTPUT:
> +                params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type)]
> +            else:
> +                params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
> +
> +            # Generate parameter list
> +            body += ", ".join(p for p in params)
> +            body += ")\n"
> +
> +        if self.operand.needs_unwrapping():
> +            if self.operand.needs_conversion():
> +                body += "#else\n"
> +
> +            body += "static inline void {0}(".format(self.name)
>   
> -        if self.direction == Direction.INPUT and "pNext" in self.struct and self.struct.returnedonly:
> +            params = ["const {0} *in".format(self.type), "{0} *out".format(self.type)]
> +
> +            # Generate parameter list
> +            body += ", ".join(p for p in params)
> +            body += ")\n"
> +
> +            if self.operand.needs_conversion():
> +                body += "#endif /* USE_STRUCT_CONVERSION */\n"
> +
> +        body += "{\n    if (!in) return;\n\n"
> +
> +        if self.direction == Direction.INPUT and "pNext" in self.operand and self.operand.returnedonly:
>               # We are dealing with an input_output parameter. For these we only need to copy
>               # pNext and sType as the other fields are filled in by the host. We do potentially
>               # have to iterate over pNext and perform conversions based on switch(sType)!
> @@ -1984,36 +2138,88 @@ class ConversionFunction(object):
>               body += "    out->pNext = in->pNext;\n"
>               body += "    out->sType = in->sType;\n"
>           else:
> -            for m in self.struct:
> +            for m in self.operand:
>                   # TODO: support copying of pNext extension structures!
> -                body += "    " + m.copy("in->", "out->", self.direction)
> +                convert = m.copy("in->", "out->", self.direction, conv=True)
> +                if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
> +                    body += "    " + convert
> +                else:
> +                    unwrap = m.copy("in->", "out->", self.direction, conv=False)
> +                    if unwrap == convert:
> +                        body += "    " + unwrap
> +                    else:
> +                        body += "#if defined(USE_STRUCT_CONVERSION)\n   {0}#else\n    {1}#endif /* USE_STRUCT_CONVERSION */\n".format(convert, unwrap)
> +

5 lines

> +        body += "}\n"
> +
> +        if not self.operand.needs_unwrapping() and not self.operand.needs_free():
> +            body += "#endif /* USE_STRUCT_CONVERSION */\n"
> +
> +        body += "\n"
>   
> -        body += "}\n\n"
>           return body
>   
>       def _generate_static_array_conversion_func(self):
> -        """ Helper function for generating a conversion function for array structs. """
> +        """ Helper function for generating a conversion function for array operands. """
>   
> -        if self.direction == Direction.OUTPUT:
> -            params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
> -        else:
> -            params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
> +        body = ""
>   
> -        # Generate function prototype.
> -        body = "static inline void {0}(".format(self.name)
> -        body += ", ".join(p for p in params)
> -        body += ")\n{\n"
> +        if self.operand.needs_conversion():
> +            body += "#if defined (USE_STRUCT_CONVERSION)\n"

Another weird space.

> +
> +            if self.direction == Direction.OUTPUT:
> +                params = ["const {0}_host *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
> +            else:
> +                params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
> +
> +            # Generate function prototype.
> +            body += "static inline void {0}(".format(self.name)
> +            body += ", ".join(p for p in params)
> +            body += ")\n"
> +
> +        if self.operand.needs_unwrapping():
> +            if self.operand.needs_conversion():
> +                body += "#else\n"
> +
> +            params = ["const {0} *in".format(self.type), "{0} *out".format(self.type), "uint32_t count"]
> +
> +            # Generate function prototype.
> +            body += "static inline void {0}(".format(self.name)
> +            body += ", ".join(p for p in params)
> +            body += ")\n"
> +
> +        body += "{\n"
>           body += "    unsigned int i;\n\n"
>           body += "    if (!in) return;\n\n"
>           body += "    for (i = 0; i < count; i++)\n"
>           body += "    {\n"
>   
> -        for m in self.struct:
> -            # TODO: support copying of pNext extension structures!
> -            body += "        " + m.copy("in[i].", "out[i].", self.direction)
> +        if isinstance(self.operand, VkStruct):
> +            for m in self.operand:
> +                # TODO: support copying of pNext extension structures!
> +                convert = m.copy("in[i].", "out[i].", self.direction, conv=True)
> +                if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
> +                    body += "        " + convert
> +                else:
> +                    unwrap = m.copy("in[i].", "out[i].", self.direction, conv=False)
> +                    if unwrap == convert:
> +                        body += "        " + unwrap
> +                    else:
> +                        body += "#if defined(USE_STRUCT_CONVERSION)\n   {0}#else\n    {1}#endif /* USE_STRUCT_CONVERSION */\n".format(convert, unwrap)

5 lines

> +        elif isinstance(self.operand, VkHandle) and self.direction == Direction.INPUT:
> +            body += "        out[i] = " + self.operand.driver_handle("in[i]") + ";\n" > +        else:
> +            LOGGER.warn("Unhandled conversion operand type")
> +            body += "        out[i] = in[i];\n"
>   
>           body += "    }\n"
> -        body += "}\n\n"
> +        body += "}\n"
> +
> +        if not self.operand.needs_unwrapping():
> +            body += "#endif /* USE_STRUCT_CONVERSION) */\n"
> +
> +        body += "\n"
> +
>           return body
>   
>       def _set_name(self):
> @@ -2044,10 +2250,10 @@ class ConversionFunction(object):
>   
>   
>   class FreeFunction(object):
> -    def __init__(self, dyn_array, struct):
> +    def __init__(self, dyn_array, operand):
>           self.dyn_array = dyn_array
> -        self.struct = struct
> -        self.type = struct.name
> +        self.operand = operand
> +        self.type = operand.name
>   
>           if dyn_array:
>               self.name = "free_{0}_array".format(self.type)
> @@ -2060,52 +2266,94 @@ class FreeFunction(object):
>       def _generate_array_free_func(self):
>           """ Helper function for cleaning up temporary buffers required for array conversions. """
>   
> -        # Generate function prototype.
> -        body = "static inline void {0}({1}_host *in, uint32_t count)\n{{\n".format(self.name, self.type)
> +        body = ""
> +
> +        if self.operand.needs_conversion():
> +            if self.operand.needs_unwrapping():
> +                body += "#if defined(USE_STRUCT_CONVERSION)\n"
> +
> +            # Generate function prototype.
> +            body += "static inline void {0}({1}_host *in, uint32_t count)\n".format(self.name, self.type)
> +
> +        if self.operand.needs_unwrapping():
> +            if self.operand.needs_conversion():
> +                body += "#else\n"
> +
> +            # Generate function prototype.
> +            body += "static inline void {0}({1} *in, uint32_t count)\n".format(self.name, self.type)
> +
> +            if self.operand.needs_conversion():
> +                body += "#endif /* USE_STRUCT_CONVERSION */\n"
> +
> +        body += "{\n"
>   
>           # E.g. VkGraphicsPipelineCreateInfo_host needs freeing for pStages.
> -        if self.struct.needs_free():
> +        if isinstance(self.operand, VkStruct) and self.operand.needs_free():
>               body += "    unsigned int i;\n\n"
>               body += "    if (!in) return;\n\n"
>               body += "    for (i = 0; i < count; i++)\n"
>               body += "    {\n"
>   
> -            for m in self.struct:
> -                if m.needs_conversion() and m.is_dynamic_array():
> -                    if m.is_const():
> -                        # Add a cast to ignore const on conversion structs we allocated ourselves.
> -                        body += "        free_{0}_array(({0}_host *)in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
> +            for m in self.operand:
> +                if m.needs_free():
> +                    convert = m.free("in[i].", conv=True)
> +                    if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
> +                        body += "        " + convert
>                       else:
> -                        body += "        free_{0}_array(in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
> -                elif m.needs_conversion():
> -                    LOGGER.error("Unhandled conversion for {0}".format(m.name))
> +                        unwrap = m.free("in[i].", conv=False)
> +                        if convert == unwrap:
> +                            body += "        " + unwrap
> +                        elif unwrap == "":
> +                            body += "#if defined(USE_STRUCT_CONVERSION)\n        {0}#endif /* USE_STRUCT_CONVERSION */\n".format(convert)

3 lines

> +                        else:
> +                            body += "#if defined(USE_STRUCT_CONVERSION)\n        {0}#else\n        {1}#endif /* USE_STRUCT_CONVERSION */\n".format(convert, unwrap)

5 lines

>               body += "    }\n"
>           else:
>               body += "    if (!in) return;\n\n" >
>           body += "    free(in);\n"
>   
> -        body += "}\n\n"
> +        body += "}\n"
> +
> +        if not self.operand.needs_unwrapping():
> +            body += "#endif /* USE_STRUCT_CONVERSION */\n"
> +
> +        body += "\n"
> +
>           return body
>   
>       def _generate_free_func(self):
>           # E.g. VkCommandBufferBeginInfo.pInheritanceInfo needs freeing.
> -        if not self.struct.needs_free():
> +        if not self.operand.needs_free():
> +            return ""
> +
> +        if not isinstance(self.operand, VkStruct):
>               return ""
>   
>           # Generate function prototype.
>           body = "static inline void {0}({1}_host *in)\n{{\n".format(self.name, self.type)
>   
> -        for m in self.struct:
> -            if m.needs_conversion() and m.is_dynamic_array():
> -                count = m.dyn_array_len if isinstance(m.dyn_array_len, int) else "in->{0}".format(m.dyn_array_len)
> -                if m.is_const():
> -                    # Add a cast to ignore const on conversion structs we allocated ourselves.
> -                    body += "    free_{0}_array(({0}_host *)in->{1}, {2});\n".format(m.type, m.name, count)
> +        for m in self.operand:
> +            if m.needs_free():
> +                convert = m.free("in->", conv=True)
> +                if self.operand.needs_conversion() and not self.operand.needs_unwrapping():
> +                    body += "    " + convert
>                   else:
> -                    body += "    free_{0}_array(in->{1}, {2});\n".format(m.type, m.name, count)
> +                    unwrap = m.free("in->", conv=False)
> +                    if convert == unwrap:
> +                        body += "    " + unwrap
> +                    elif unwrap == "":
> +                        body += "#if defined(USE_STRUCT_CONVERSION)\n    {0}#endif /* USE_STRUCT_CONVERSION */\n".format(convert)

3 lines

> +                    else:
> +                        body += "#if defined(USE_STRUCT_CONVERSION)\n    {0}#else\n    {1}#endif /* USE_STRUCT_CONVERSION */\n".format(convert, unwrap)

5 lines

> +
> +        body += "}\n"
> +
> +        if not self.operand.needs_unwrapping(): > +            body += "#endif /* USE_STRUCT_CONVERSION */\n"
> +
> +        body += "\n"
>   
> -        body += "}\n\n"
>           return body
>   
>       def definition(self):
> @@ -2168,7 +2416,12 @@ class StructChainConversionFunction(object):
>                   if m.name == "pNext":
>                       body += "            out->pNext = NULL;\n"
>                   else:
> -                    body += "            " + m.copy("in->", "out->", self.direction)
> +                    convert = m.copy("in->", "out->", self.direction, conv=True)
> +                    unwrap = m.copy("in->", "out->", self.direction, conv=False)
> +                    if unwrap == convert:
> +                        body += "            " + unwrap
> +                    else:
> +                        body += "#if defined(USE_STRUCT_CONVERSION)\n            {0}#else\n            {1}#endif /* USE_STRUCT_CONVERSION */\n".format(convert, unwrap)

5 lines

>   
>               body += "\n            out_header->pNext = (VkBaseOutStructure *)out;\n"
>               body += "            out_header = out_header->pNext;\n"
> @@ -2212,7 +2465,41 @@ class FreeStructChainFunction(object):
>   
>           body += "    while (header)\n"
>           body += "    {\n"
> -        body += "        void *prev = header;\n"
> +        body += "        void *prev = header;\n\n"
> +        body += "        switch (header->sType)\n"
> +        body += "        {\n"
> +
> +        for e in self.struct.struct_extensions:
> +            if not e.required:
> +                continue
> +
> +            if not any(m.needs_free() for m in e):
> +                continue
> +
> +            stype = next(x for x in e.members if x.name == "sType")
> +
> +            body += "            case {0}:\n".format(stype.values)
> +            body += "            {\n"
> +            body += "                {0} *structure = ({0} *) header;\n".format(e.name)
> +
> +            for m in e:
> +                if m.needs_free():
> +                    convert = m.free("structure->", conv=True)
> +                    unwrap = m.free("structure->", conv=False)
> +                    if convert == unwrap:
> +                        body += "                " + unwrap
> +                    elif unwrap == "":
> +                        body += "#if defined(USE_STRUCT_CONVERSION)\n                {0}#endif /* USE_STRUCT_CONVERSION */\n".format(convert)

3 lines

> +                    else:
> +                        body += "#if defined(USE_STRUCT_CONVERSION)\n                {0}#else\n                {1}#endif /* USE_STRUCT_CONVERSION */\n".format(convert, unwrap)

5 lines

> +
> +            body += "                break;\n"
> +            body += "            }\n" > +
> +        body += "            default:\n"
> +        body += "                break;\n"
> +        body += "        }\n"
> +
>           body += "        header = header->pNext;\n"
>           body += "        free(prev);\n"
>           body += "    }\n\n"
> @@ -2235,7 +2522,7 @@ class VkGenerator(object):
>               if not func.is_required():
>                   continue
>   
> -            if not func.needs_conversion():
> +            if not func.needs_conversion() and not func.needs_unwrapping():
>                   continue
>   
>               conversions = func.get_conversions()
> @@ -2246,15 +2533,26 @@ class VkGenerator(object):
>                       if not any(c == conv for c in self.conversions):
>                           self.conversions.append(conv)
>   
> +                if not isinstance(conv.operand, VkStruct):
> +                    continue
> +
>                   # Structs can be used in different ways by different conversions
>                   # e.g. array vs non-array. Just make sure we pull in each struct once.
> -                if not any(s.name == conv.struct.name for s in self.host_structs):
> -                    self.host_structs.append(conv.struct)
> +                if not any(s.name == conv.operand.name for s in self.host_structs):
> +                    self.host_structs.append(conv.operand)
>   
>           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(FreeStructChainFunction(struct))
> +                # Once we decide to support pNext chains conversion everywhere, move this under get_conversions
> +                for e in struct.struct_extensions:
> +                    for m in e:
> +                        if m.needs_conversion() or m.needs_unwrapping():
> +                            conversions = m.get_conversions()
> +                            for conv in conversions:
> +                                if not any(c == conv for c in self.conversions):
> +                                    self.conversions.append(conv)
>   
>       def _generate_copyright(self, f, spec_file=False):
>           f.write("# " if spec_file else "/* ")
> @@ -2281,10 +2579,8 @@ class VkGenerator(object):
>           f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
>   
>           # Generate any conversion helper functions.
> -        f.write("#if defined(USE_STRUCT_CONVERSION)\n")
>           for conv in self.conversions:
>               f.write(conv.definition())
> -        f.write("#endif /* USE_STRUCT_CONVERSION */\n\n")
>   
>           for conv in self.struct_chain_conversions:
>               f.write(conv.definition())
> diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c
> index 45eda78e997..9f181d92bc5 100644
> --- a/dlls/winevulkan/vulkan.c
> +++ b/dlls/winevulkan/vulkan.c
> @@ -360,20 +360,12 @@ static void wine_vk_device_get_queues(struct VkDevice_T *device,
>   
>   static void wine_vk_device_free_create_info(VkDeviceCreateInfo *create_info)
>   {
> -    VkDeviceGroupDeviceCreateInfo *group_info;
> -
> -    if ((group_info = wine_vk_find_struct(create_info, DEVICE_GROUP_DEVICE_CREATE_INFO)))
> -    {
> -        free((void *)group_info->pPhysicalDevices);
> -    }
> -
>       free_VkDeviceCreateInfo_struct_chain(create_info);
>   }
>   
>   static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src,
>           VkDeviceCreateInfo *dst)
>   {
> -    VkDeviceGroupDeviceCreateInfo *group_info;
>       unsigned int i;
>       VkResult res;
>   
> @@ -385,23 +377,6 @@ static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src
>           return res;
>       }
>   
> -    /* FIXME: convert_VkDeviceCreateInfo_struct_chain() should unwrap handles for us. */
> -    if ((group_info = wine_vk_find_struct(dst, DEVICE_GROUP_DEVICE_CREATE_INFO)))
> -    {
> -        VkPhysicalDevice *physical_devices;
> -
> -        if (!(physical_devices = calloc(group_info->physicalDeviceCount, sizeof(*physical_devices))))
> -        {
> -            free_VkDeviceCreateInfo_struct_chain(dst);
> -            return VK_ERROR_OUT_OF_HOST_MEMORY;
> -        }
> -        for (i = 0; i < group_info->physicalDeviceCount; ++i)
> -        {
> -            physical_devices[i] = group_info->pPhysicalDevices[i]->phys_dev;
> -        }
> -        group_info->pPhysicalDevices = physical_devices;
> -    }
> -
>       /* Should be filtered out by loader as ICDs don't support layers. */
>       dst->enabledLayerCount = 0;
>       dst->ppEnabledLayerNames = NULL;
> @@ -709,36 +684,6 @@ VkResult WINAPI wine_vkAllocateCommandBuffers(VkDevice device,
>       return res;
>   }
>   
> -void WINAPI wine_vkCmdExecuteCommands(VkCommandBuffer buffer, uint32_t count,
> -        const VkCommandBuffer *buffers)
> -{
> -    VkCommandBuffer *tmp_buffers;
> -    unsigned int i;
> -
> -    TRACE("%p %u %p\n", buffer, count, buffers);
> -
> -    if (!buffers || !count)
> -        return;
> -
> -    /* Unfortunately we need a temporary buffer as our command buffers are wrapped.
> -     * This call is called often and if a performance concern, we may want to use
> -     * alloca as we shouldn't need much memory and it needs to be cleaned up after
> -     * the call anyway.
> -     */
> -    if (!(tmp_buffers = malloc(count * sizeof(*tmp_buffers))))
> -    {
> -        ERR("Failed to allocate memory for temporary command buffers\n");
> -        return;
> -    }
> -
> -    for (i = 0; i < count; i++)
> -        tmp_buffers[i] = buffers[i]->command_buffer;
> -
> -    buffer->device->funcs.p_vkCmdExecuteCommands(buffer->command_buffer, count, tmp_buffers);
> -
> -    free(tmp_buffers);
> -}
> -
>   VkResult WINAPI wine_vkCreateDevice(VkPhysicalDevice phys_dev,
>           const VkDeviceCreateInfo *create_info,
>           const VkAllocationCallbacks *allocator, VkDevice *device)
> @@ -1122,61 +1067,6 @@ void WINAPI wine_vkGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2 *in
>       *queue = wine_vk_device_find_queue(device, info);
>   }
>   
> -VkResult WINAPI wine_vkQueueSubmit(VkQueue queue, uint32_t count,
> -        const VkSubmitInfo *submits, VkFence fence)
> -{
> -    VkSubmitInfo *submits_host;
> -    VkResult res;
> -    VkCommandBuffer *command_buffers;
> -    unsigned int i, j, num_command_buffers;
> -
> -    TRACE("%p %u %p 0x%s\n", queue, count, submits, wine_dbgstr_longlong(fence));
> -
> -    if (count == 0)
> -    {
> -        return queue->device->funcs.p_vkQueueSubmit(queue->queue, 0, NULL, fence);
> -    }
> -
> -    submits_host = calloc(count, sizeof(*submits_host));
> -    if (!submits_host)
> -    {
> -        ERR("Unable to allocate memory for submit buffers!\n");
> -        return VK_ERROR_OUT_OF_HOST_MEMORY;
> -    }
> -
> -    for (i = 0; i < count; i++)
> -    {
> -        memcpy(&submits_host[i], &submits[i], sizeof(*submits_host));
> -
> -        num_command_buffers = submits[i].commandBufferCount;
> -        command_buffers = calloc(num_command_buffers, sizeof(*command_buffers));
> -        if (!command_buffers)
> -        {
> -            ERR("Unable to allocate memory for command buffers!\n");
> -            res = VK_ERROR_OUT_OF_HOST_MEMORY;
> -            goto done;
> -        }
> -
> -        for (j = 0; j < num_command_buffers; j++)
> -        {
> -            command_buffers[j] = submits[i].pCommandBuffers[j]->command_buffer;
> -        }
> -        submits_host[i].pCommandBuffers = command_buffers;
> -    }
> -
> -    res = queue->device->funcs.p_vkQueueSubmit(queue->queue, count, submits_host, fence);
> -
> -done:
> -    for (i = 0; i < count; i++)
> -    {
> -        free((void *)submits_host[i].pCommandBuffers);
> -    }
> -    free(submits_host);
> -
> -    TRACE("Returning %d\n", res);
> -    return res;
> -}
> -
>   VkResult WINAPI wine_vkCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *info,
>           const VkAllocationCallbacks *allocator, VkCommandPool *command_pool)
>   {
> @@ -1540,19 +1430,6 @@ void WINAPI wine_vkGetPrivateDataEXT(VkDevice device, VkObjectType object_type,
>       device->funcs.p_vkGetPrivateDataEXT(device->device, object_type, object_handle, private_data_slot, data);
>   }
>   
> -VkResult WINAPI wine_vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *create_info,
> -        const VkAllocationCallbacks *allocator, VkSwapchainKHR *swapchain)
> -{
> -    VkSwapchainCreateInfoKHR native_info;
> -
> -    TRACE("%p, %p, %p, %p\n", device, create_info, allocator, swapchain);
> -
> -    native_info = *create_info;
> -    native_info.surface = wine_surface_from_handle(create_info->surface)->driver_surface;
> -
> -    return thunk_vkCreateSwapchainKHR(device, &native_info, allocator, swapchain);
> -}
> -
>   VkResult WINAPI wine_vkCreateWin32SurfaceKHR(VkInstance instance,
>           const VkWin32SurfaceCreateInfoKHR *createInfo, const VkAllocationCallbacks *allocator, VkSurfaceKHR *surface)
>   {
> @@ -1601,19 +1478,6 @@ void WINAPI wine_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface,
>       free(object);
>   }
>   
> -VkResult WINAPI wine_vkGetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice phys_dev,
> -        const VkPhysicalDeviceSurfaceInfo2KHR *surface_info, uint32_t *formats_count, VkSurfaceFormat2KHR *formats)
> -{
> -    VkPhysicalDeviceSurfaceInfo2KHR native_info;
> -
> -    TRACE("%p, %p, %p, %p\n", phys_dev, surface_info, formats_count, formats);
> -
> -    native_info = *surface_info;
> -    native_info.surface = wine_surface_from_handle(surface_info->surface)->driver_surface;
> -
> -    return thunk_vkGetPhysicalDeviceSurfaceFormats2KHR(phys_dev, &native_info, formats_count, formats);
> -}
> -
>   static inline void adjust_max_image_count(VkPhysicalDevice phys_dev, VkSurfaceCapabilitiesKHR* capabilities)
>   {
>       /* Many Windows games, for example Strange Brigade, No Man's Sky, Path of Exile
> @@ -1647,15 +1511,11 @@ VkResult WINAPI wine_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice
>   VkResult WINAPI wine_vkGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice phys_dev,
>           const VkPhysicalDeviceSurfaceInfo2KHR *surface_info, VkSurfaceCapabilities2KHR *capabilities)
>   {
> -    VkPhysicalDeviceSurfaceInfo2KHR native_info;
>       VkResult res;
>   
>       TRACE("%p, %p, %p\n", phys_dev, surface_info, capabilities);
>   
> -    native_info = *surface_info;
> -    native_info.surface = wine_surface_from_handle(surface_info->surface)->driver_surface;
> -
> -    res = thunk_vkGetPhysicalDeviceSurfaceCapabilities2KHR(phys_dev, &native_info, capabilities);
> +    res = thunk_vkGetPhysicalDeviceSurfaceCapabilities2KHR(phys_dev, surface_info, capabilities);
>   
>       if (res == VK_SUCCESS)
>           adjust_max_image_count(phys_dev, &capabilities->surfaceCapabilities);
> 



More information about the wine-devel mailing list