scripts: Add pNext-chain extension helper function
Unique-objects layer did not handle extension structs or chains of
extension structs. Automated generation and handling of unwrapped
struct chains.
Change-Id: I8cc813c9bf7290bbcec257245848e54e1ce8a0f7
diff --git a/scripts/unique_objects_generator.py b/scripts/unique_objects_generator.py
index 855292e..1a0b0ec 100644
--- a/scripts/unique_objects_generator.py
+++ b/scripts/unique_objects_generator.py
@@ -163,15 +163,21 @@
self.headerVersion = None
# Internal state - accumulators for different inner block text
self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
+
self.cmdMembers = []
self.cmd_feature_protect = [] # Save ifdef's for each command
- self.cmd_info_data = [] # Save the cmdinfo data for wrapping the handles when processing is complete
- self.structMembers = [] # List of StructMemberData records for all Vulkan structs
+ self.cmd_info_data = [] # Save the cmdinfo data for wrapping the handles when processing is complete
+ self.structMembers = [] # List of StructMemberData records for all Vulkan structs
+ self.extension_structs = [] # List of all structs or sister-structs containing handles
+ # A sister-struct may contain no handles but shares <validextensionstructs> with one that does
+ self.structTypes = dict() # Map of Vulkan struct typename to required VkStructureType
# Named tuples to store struct and command data
+ self.StructType = namedtuple('StructType', ['name', 'value'])
self.CmdMemberData = namedtuple('CmdMemberData', ['name', 'members'])
self.CmdInfoData = namedtuple('CmdInfoData', ['name', 'cmdinfo'])
self.CmdExtraProtect = namedtuple('CmdExtraProtect', ['name', 'extra_protect'])
- self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'ispointer', 'isconst', 'iscount', 'len', 'extstructs', 'cdecl', 'islocal', 'iscreate', 'isdestroy'])
+
+ self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'ispointer', 'isconst', 'iscount', 'len', 'extstructs', 'cdecl', 'islocal', 'iscreate', 'isdestroy', 'feature_protect'])
self.StructMemberData = namedtuple('StructMemberData', ['name', 'members'])
#
def incIndent(self, indent):
@@ -208,6 +214,12 @@
# Write out wrapping/unwrapping functions
self.WrapCommands()
+ # Build and write out pNext processing function
+ extension_proc = self.build_extension_processing_func()
+ self.newline()
+ write('// Unique Objects pNext extension handling function', file=self.outFile)
+ write('%s' % extension_proc, file=self.outFile)
+
# Actually write the interface to the output file.
if (self.emit):
self.newline()
@@ -378,19 +390,24 @@
value = result.group(0)
else:
value = self.genVkStructureType(typeName)
+ # Store the required type value
+ self.structTypes[typeName] = self.StructType(name=name, value=value)
# Store pointer/array/string info
+ extstructs = member.attrib.get('validextensionstructs') if name == 'pNext' else None
membersInfo.append(self.CommandParam(type=type,
name=name,
ispointer=self.paramIsPointer(member),
isconst=True if 'const' in cdecl else False,
iscount=True if name in lens else False,
len=self.getLen(member),
- extstructs=member.attrib.get('validextensionstructs') if name == 'pNext' else None,
+ extstructs=extstructs,
cdecl=cdecl,
islocal=False,
iscreate=False,
- isdestroy=False))
+ isdestroy=False,
+ feature_protect=self.featureExtraProtect))
self.structMembers.append(self.StructMemberData(name=typeName, members=membersInfo))
+
#
# Insert a lock_guard line
def lock_guard(self, indent):
@@ -433,6 +450,76 @@
ndo_list.add(item)
return ndo_list
#
+ # Generate pNext handling function
+ def build_extension_processing_func(self):
+
+ # Construct list of extension structs containing handles, or extension structs that share a <validextensionstructs>
+ # tag WITH an extension struct containing handles. All extension structs in any pNext chain will have to be copied.
+ for struct in self.structMembers:
+ if (len(struct.members) > 1) and struct.members[1].extstructs is not None:
+ found = False;
+ for item in struct.members[1].extstructs.split(','):
+ if item != '' and self.struct_contains_ndo(item) == True:
+ found = True
+ if found == True:
+ for item in struct.members[1].extstructs.split(','):
+ if item != '' and item not in self.extension_structs:
+ self.extension_structs.append(item)
+ # Construct helper functions to build and free pNext extension chains
+ pnext_proc = ''
+ pnext_proc += 'void *CreateUnwrappedExtensionStructs(layer_data *dev_data, const void *pNext) {\n'
+ pnext_proc += ' void *cur_pnext = const_cast<void *>(pNext);\n'
+ pnext_proc += ' void *head_pnext = NULL;\n'
+ pnext_proc += ' void *prev_ext_struct = NULL;\n'
+ pnext_proc += ' void *cur_ext_struct = NULL;\n\n'
+ pnext_proc += ' while (cur_pnext != NULL) {\n'
+ pnext_proc += ' GenericHeader *header = reinterpret_cast<GenericHeader *>(cur_pnext);\n\n'
+ pnext_proc += ' switch (header->sType) {\n'
+ for item in self.extension_structs:
+ struct_member_dict = dict(self.structMembers)
+ struct_info = struct_member_dict[item]
+ if struct_info[0].feature_protect is not None:
+ pnext_proc += '#ifdef %s \n' % struct_info[0].feature_protect
+ pnext_proc += ' case %s: {\n' % self.structTypes[item].value
+ pnext_proc += ' safe_%s *safe_struct = reinterpret_cast<safe_%s *>(new safe_%s);\n' % (item, item, item)
+ pnext_proc += ' safe_struct->initialize(reinterpret_cast<const %s *>(cur_pnext));\n' % item
+ # Generate code to unwrap the handles
+ indent = ' '
+ (tmp_decl, tmp_pre, tmp_post) = self.uniquify_members(struct_info, indent, 'safe_struct->', 0, False, False, False, False)
+ pnext_proc += tmp_pre
+ pnext_proc += ' cur_ext_struct = reinterpret_cast<void *>(safe_struct);\n'
+ pnext_proc += ' } break;\n'
+ if struct_info[0].feature_protect is not None:
+ pnext_proc += '#endif // %s \n' % struct_info[0].feature_protect
+ pnext_proc += '\n'
+ pnext_proc += ' default:\n'
+ pnext_proc += ' break;\n'
+ pnext_proc += ' }\n\n'
+ pnext_proc += ' // Save pointer to the first structure in the pNext chain\n'
+ pnext_proc += ' head_pnext = (head_pnext ? head_pnext : cur_ext_struct);\n\n'
+ pnext_proc += ' // For any extension structure but the first, link the last struct\'s pNext to the current ext struct\n'
+ pnext_proc += ' if (prev_ext_struct) {\n'
+ pnext_proc += ' (reinterpret_cast<GenericHeader *>(prev_ext_struct))->pNext = cur_ext_struct;\n'
+ pnext_proc += ' }\n'
+ pnext_proc += ' prev_ext_struct = cur_ext_struct;\n\n'
+ pnext_proc += ' // Process the next structure in the chain\n'
+ pnext_proc += ' cur_pnext = const_cast<void *>(header->pNext);\n'
+ pnext_proc += ' }\n'
+ pnext_proc += ' return head_pnext;\n'
+ pnext_proc += '}\n\n'
+ pnext_proc += '// Free a pNext extension chain\n'
+ pnext_proc += 'void FreeUnwrappedExtensionStructs(void *head) {\n'
+ pnext_proc += ' void * curr_ptr = head;\n'
+ pnext_proc += ' while (curr_ptr) {\n'
+ pnext_proc += ' GenericHeader *header = reinterpret_cast<GenericHeader *>(curr_ptr);\n'
+ pnext_proc += ' void *temp = curr_ptr;\n'
+ pnext_proc += ' curr_ptr = header->pNext;\n'
+ pnext_proc += ' free(temp);\n'
+ pnext_proc += ' }\n'
+ pnext_proc += '}\n'
+ return pnext_proc
+
+ #
# Generate source for creating a non-dispatchable object
def generate_create_ndo_code(self, indent, proto, params, cmd_info):
create_ndo_code = ''
@@ -716,7 +803,8 @@
cdecl=cdecl,
islocal=islocal,
iscreate=iscreate,
- isdestroy=isdestroy))
+ isdestroy=isdestroy,
+ feature_protect=self.featureExtraProtect))
self.cmdMembers.append(self.CmdMemberData(name=cmdname, members=membersInfo))
self.cmd_info_data.append(self.CmdInfoData(name=cmdname, cmdinfo=cmdinfo))
self.cmd_feature_protect.append(self.CmdExtraProtect(name=cmdname, extra_protect=self.featureExtraProtect))