winevulkan: Generate conversion function for VkInstanceCreateInfo structure extensions.

Signed-off-by: Józef Kucia <jkucia@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Józef Kucia 2019-04-10 11:59:49 +02:00 committed by Alexandre Julliard
parent cc2e8d7cda
commit a4b9460ad6
4 changed files with 177 additions and 39 deletions

View File

@ -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:

View File

@ -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);

View File

@ -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)

View File

@ -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
{