diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 20643fa1e34..eb68a7be598 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -220,6 +220,10 @@ FUNCTION_OVERRIDES = { "vkGetPhysicalDevicePresentRectanglesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True}, } +STRUCT_CHAIN_CONVERSIONS = [ + "VkInstanceCreateInfo", +] + class Direction(Enum): """ Parameter direction: input, output, input_output. """ @@ -912,7 +916,7 @@ class VkHandle(object): 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): + dyn_array_len=None, optional=False, values=None): self.const = const self.struct_fwd_decl = struct_fwd_decl self.name = name @@ -922,6 +926,7 @@ class VkMember(object): self.array_len = array_len self.dyn_array_len = dyn_array_len self.optional = optional + self.values = values def __eq__(self, other): """ Compare member based on name against a string. @@ -930,10 +935,7 @@ class VkMember(object): if certain members exist. """ - if self.name == other: - return True - - return False + return self.name == other def __repr__(self): return "{0} {1} {2} {3} {4} {5} {6}".format(self.const, self.struct_fwd_decl, self.type, self.pointer, @@ -952,6 +954,8 @@ class VkMember(object): pointer = None array_len = None + values = member.get("values") + if member.text: if "const" in member.text: const = True @@ -993,7 +997,7 @@ class VkMember(object): array_len = name_elem.tail.strip("[]") 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) + 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. """ @@ -1739,10 +1743,7 @@ class ConversionFunction(object): self._set_name() def __eq__(self, other): - if self.name != other.name: - return False - - return True + return self.name == other.name def _generate_array_conversion_func(self): """ Helper function for generating a conversion function for array structs. """ @@ -1874,10 +1875,7 @@ class FreeFunction(object): self.name = "free_{0}".format(self.type) def __eq__(self, other): - if self.name == other.name: - return True - - return False + return self.name == other.name def _generate_array_free_func(self): """ Helper function for cleaning up temporary buffers required for array conversions. """ @@ -1939,12 +1937,119 @@ class FreeFunction(object): return self._generate_free_func() +class StructChainConversionFunction(object): + def __init__(self, direction, struct): + self.direction = direction + self.struct = struct + self.type = struct.name + + self.name = "convert_{0}_struct_chain".format(self.type) + + def __eq__(self, other): + return self.name == other.name + + def prototype(self, postfix=""): + return "VkResult {0}(const void *pNext, {1} *out_struct) {2}".format(self.name, self.type, postfix).strip() + + def definition(self): + body = self.prototype() + body += "\n{\n" + + body += " VkBaseOutStructure *out_header = (VkBaseOutStructure *)out_struct;\n"; + body += " const VkBaseInStructure *in_header;\n\n"; + + body += " out_header->pNext = NULL;\n\n" + + body += " for (in_header = pNext; in_header; in_header = in_header->pNext)\n" + body += " {\n" + body += " switch (in_header->sType)\n" + body += " {\n" + + # Ignore to not confuse host loader. + body += " case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO:\n" + body += " case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO:\n" + body += " break;\n\n" + + for e in self.struct.struct_extensions: + if not e.required: + continue + + stype = next(x for x in e.members if x.name == "sType") + + body += " case {0}:\n".format(stype.values) + body += " {\n" + + body += " const {0} *in = (const {0} *)in_header;\n".format(e.name) + body += " {0} *out;\n\n".format(e.name) + + body += " if (!(out = heap_alloc(sizeof(*out)))) goto out_of_memory;\n\n" + + for m in e: + if m.name == "pNext": + body += " out->pNext = NULL;\n" + else: + body += " " + m.copy("in->", "out->", self.direction) + + body += "\n out_header->pNext = (VkBaseOutStructure *)out;\n" + body += " out_header = out_header->pNext;\n" + body += " break;\n" + body += " }\n\n" + + body += " default:\n" + body += " FIXME(\"Application requested a linked structure of type %u.\\n\", in_header->sType);\n" + + body += " }\n" + body += " }\n\n" + + body += " return VK_SUCCESS;\n" + + if any(x for x in self.struct.struct_extensions if x.required): + body += "\nout_of_memory:\n" + body += " free_{0}_struct_chain(out_struct);\n".format(self.type) + body += " return VK_ERROR_OUT_OF_HOST_MEMORY;\n" + + body += "}\n\n" + return body + +class FreeStructChainFunction(object): + def __init__(self, struct): + self.struct = struct + self.type = struct.name + + self.name = "free_{0}_struct_chain".format(self.type) + + def __eq__(self, other): + return self.name == other.name + + def prototype(self, postfix=""): + return "void {0}({1} *s) {2}".format(self.name, self.type, postfix).strip() + + def definition(self): + body = self.prototype() + body += "\n{\n" + + body += " VkBaseOutStructure *header = (void *)s->pNext;\n\n"; + + body += " while (header)\n" + body += " {\n" + body += " void *prev = header;\n" + body += " header = header->pNext;\n" + body += " heap_free(prev);\n" + body += " }\n\n" + + body += " s->pNext = NULL;\n" + + body += "}\n\n" + return body + + class VkGenerator(object): def __init__(self, registry): self.registry = registry # Build a list conversion functions for struct conversion. self.conversions = [] + self.struct_chain_conversions = [] self.host_structs = [] for func in self.registry.funcs.values(): if not func.is_required(): @@ -1966,6 +2071,11 @@ class VkGenerator(object): if not any(s.name == conv.struct.name for s in self.host_structs): self.host_structs.append(conv.struct) + 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)) + def _generate_copyright(self, f, spec_file=False): f.write("# " if spec_file else "/* ") f.write("Automatically generated from Vulkan vk.xml; DO NOT EDIT!\n") @@ -1991,6 +2101,9 @@ class VkGenerator(object): f.write(conv.definition()) f.write("#endif /* USE_STRUCT_CONVERSION */\n\n") + for conv in self.struct_chain_conversions: + f.write(conv.definition()) + # Create thunks for instance and device functions. # Global functions don't go through the thunks. for vk_func in self.registry.funcs.values(): @@ -2128,6 +2241,10 @@ class VkGenerator(object): f.write(struct.definition(align=False, conv=True, postfix="_host")) f.write("\n") + for func in self.struct_chain_conversions: + f.write(func.prototype(postfix="DECLSPEC_HIDDEN") + ";\n") + f.write("\n") + f.write("/* For use by vkDevice and children */\n") f.write("struct vulkan_device_funcs\n{\n") for vk_func in self.registry.device_funcs: diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index f86064c4b66..259d7d18e7c 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -407,36 +407,15 @@ static VkResult wine_vk_instance_convert_create_info(const VkInstanceCreateInfo VkInstanceCreateInfo *dst) { unsigned int i; + VkResult res; *dst = *src; - /* Application and loader can pass in a chain of extensions through pNext. - * We can't blindly pass these through as often these contain callbacks or - * they can even be pass structures for loader / ICD internal use. For now - * we ignore everything in pNext chain, but we print FIXMEs. - */ - if (src->pNext) + if ((res = convert_VkInstanceCreateInfo_struct_chain(src->pNext, dst)) < 0) { - const VkBaseInStructure *header; - - for (header = src->pNext; header; header = header->pNext) - { - switch (header->sType) - { - case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO: - /* Can be used to register new dispatchable object types - * to the loader. We should ignore it as it will confuse the - * host its loader. - */ - break; - - default: - FIXME("Application requested a linked structure of type %u.\n", header->sType); - } - } + WARN("Failed to convert VkInstanceCreateInfo pNext chain, res=%d.\n", res); + return res; } - /* For now don't support anything. */ - dst->pNext = NULL; /* ICDs don't support any layers, so nothing to copy. Modern versions of the loader * filter this data out as well. @@ -452,6 +431,7 @@ static VkResult wine_vk_instance_convert_create_info(const VkInstanceCreateInfo if (!wine_vk_instance_extension_supported(extension_name)) { WARN("Extension %s is not supported.\n", debugstr_a(extension_name)); + free_VkInstanceCreateInfo_struct_chain(dst); return VK_ERROR_EXTENSION_NOT_PRESENT; } } @@ -771,6 +751,7 @@ VkResult WINAPI wine_vkCreateInstance(const VkInstanceCreateInfo *create_info, } res = vk_funcs->p_vkCreateInstance(&create_info_host, NULL /* allocator */, &object->instance); + free_VkInstanceCreateInfo_struct_chain(&create_info_host); if (res != VK_SUCCESS) { ERR("Failed to create instance, res=%d\n", res); diff --git a/dlls/winevulkan/vulkan_thunks.c b/dlls/winevulkan/vulkan_thunks.c index e1df2aa72ea..2f0cc6218e2 100644 --- a/dlls/winevulkan/vulkan_thunks.c +++ b/dlls/winevulkan/vulkan_thunks.c @@ -1343,6 +1343,43 @@ static inline void free_VkCopyDescriptorSet_array(VkCopyDescriptorSet_host *in, #endif /* USE_STRUCT_CONVERSION */ +VkResult convert_VkInstanceCreateInfo_struct_chain(const void *pNext, VkInstanceCreateInfo *out_struct) +{ + VkBaseOutStructure *out_header = (VkBaseOutStructure *)out_struct; + const VkBaseInStructure *in_header; + + out_header->pNext = NULL; + + for (in_header = pNext; in_header; in_header = in_header->pNext) + { + switch (in_header->sType) + { + case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO: + case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO: + break; + + default: + FIXME("Application requested a linked structure of type %u.\n", in_header->sType); + } + } + + return VK_SUCCESS; +} + +void free_VkInstanceCreateInfo_struct_chain(VkInstanceCreateInfo *s) +{ + VkBaseOutStructure *header = (void *)s->pNext; + + while (header) + { + void *prev = header; + header = header->pNext; + heap_free(prev); + } + + s->pNext = NULL; +} + VkResult WINAPI wine_vkAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR *pAcquireInfo, uint32_t *pImageIndex) { #if defined(USE_STRUCT_CONVERSION) diff --git a/dlls/winevulkan/vulkan_thunks.h b/dlls/winevulkan/vulkan_thunks.h index 6d0ed45e3c3..3b8a93176ab 100644 --- a/dlls/winevulkan/vulkan_thunks.h +++ b/dlls/winevulkan/vulkan_thunks.h @@ -765,6 +765,9 @@ typedef struct VkCopyDescriptorSet_host } VkCopyDescriptorSet_host; +VkResult convert_VkInstanceCreateInfo_struct_chain(const void *pNext, VkInstanceCreateInfo *out_struct) DECLSPEC_HIDDEN; +void free_VkInstanceCreateInfo_struct_chain(VkInstanceCreateInfo *s) DECLSPEC_HIDDEN; + /* For use by vkDevice and children */ struct vulkan_device_funcs {