[PATCH 1/9] winevulkan: Generate conversion function for VkInstanceCreateInfo structure extensions.

Józef Kucia jkucia at codeweavers.com
Wed Apr 10 04:59:49 CDT 2019


Signed-off-by: Józef Kucia <jkucia at codeweavers.com>
---
 dlls/winevulkan/make_vulkan     | 145 +++++++++++++++++++++++++++++---
 dlls/winevulkan/vulkan.c        |  31 ++-----
 dlls/winevulkan/vulkan_thunks.c |  37 ++++++++
 dlls/winevulkan/vulkan_thunks.h |   3 +
 4 files changed, 177 insertions(+), 39 deletions(-)

diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan
index 20643fa1e34c..eb68a7be598f 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 f86064c4b661..259d7d18e7c1 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 e1df2aa72eae..2f0cc6218e22 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 6d0ed45e3c3d..3b8a93176abd 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
 {
-- 
2.21.0




More information about the wine-devel mailing list