--- 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}, "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},
# 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. + """ + + 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") + 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 "" + 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) + + 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 + 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" + 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) + + 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" + + 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) + 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) + else: + body += "#if defined(USE_STRUCT_CONVERSION)\n {0}#else\n {1}#endif /* USE_STRUCT_CONVERSION */\n".format(convert, unwrap) 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) + else: + body += "#if defined(USE_STRUCT_CONVERSION)\n {0}#else\n {1}#endif /* USE_STRUCT_CONVERSION */\n".format(convert, unwrap) + + 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)
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) + else: + body += "#if defined(USE_STRUCT_CONVERSION)\n {0}#else\n {1}#endif /* USE_STRUCT_CONVERSION */\n".format(convert, unwrap) + + 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);
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);