scripts: Make safe_structs call pnext handlers
Safe structs will now make deep copies of the attendant pnext chain.
Change-Id: I34d6dfed9ce8222c197b83448ad7ee420b55df8c
diff --git a/scripts/helper_file_generator.py b/scripts/helper_file_generator.py
index e3225a6..8a02bb2 100644
--- a/scripts/helper_file_generator.py
+++ b/scripts/helper_file_generator.py
@@ -454,6 +454,7 @@
safe_struct_helper_header += '#include <vulkan/vulkan.h>\n'
safe_struct_helper_header += '\n'
safe_struct_helper_header += 'void *SafePnextCopy(const void *pNext);\n'
+ safe_struct_helper_header += 'void FreePnextChain(const void *head);\n'
safe_struct_helper_header += 'void FreePnextChain(void *head);\n'
safe_struct_helper_header += '\n'
safe_struct_helper_header += self.GenerateSafeStructHeader()
@@ -891,58 +892,67 @@
build_pnext_proc = '\n\n'
build_pnext_proc += 'void *SafePnextCopy(const void *pNext) {\n'
build_pnext_proc += ' void *cur_pnext = const_cast<void *>(pNext);\n'
- build_pnext_proc += ' void *cur_ext_struct = NULL;\n\n'
- build_pnext_proc += ' if (cur_pnext == nullptr) {\n'
- build_pnext_proc += ' return nullptr;\n'
- build_pnext_proc += ' } else {\n'
- build_pnext_proc += ' VkBaseOutStructure *header = reinterpret_cast<VkBaseOutStructure *>(cur_pnext);\n\n'
- build_pnext_proc += ' switch (header->sType) {\n'
+ build_pnext_proc += ' void *cur_ext_struct = NULL;\n'
+ build_pnext_proc += ' bool unrecognized_stype = true;\n\n'
+ build_pnext_proc += ' while (unrecognized_stype) {\n'
+ build_pnext_proc += ' unrecognized_stype = false;\n'
+ build_pnext_proc += ' if (cur_pnext == nullptr) {\n'
+ build_pnext_proc += ' return nullptr;\n'
+ build_pnext_proc += ' } else {\n'
+ build_pnext_proc += ' VkBaseOutStructure *header = reinterpret_cast<VkBaseOutStructure *>(cur_pnext);\n\n'
+ build_pnext_proc += ' switch (header->sType) {\n'
free_pnext_proc = '\n\n'
+ free_pnext_proc += '// Free a const pNext extension chain\n'
+ free_pnext_proc += 'void FreePnextChain(const void *head) {\n'
+ free_pnext_proc += ' FreePnextChain(const_cast<void *>(head));\n'
+ free_pnext_proc += '}\n\n'
+
free_pnext_proc += '// Free a pNext extension chain\n'
free_pnext_proc += 'void FreePnextChain(void *head) {\n'
- free_pnext_proc += ' VkBaseOutStructure *curr_ptr = reinterpret_cast<VkBaseOutStructure *>(head);\n'
- free_pnext_proc += ' while (curr_ptr) {\n'
- free_pnext_proc += ' VkBaseOutStructure *header = curr_ptr;\n'
- free_pnext_proc += ' curr_ptr = reinterpret_cast<VkBaseOutStructure *>(header->pNext);\n\n'
- free_pnext_proc += ' switch (header->sType) {\n';
+ free_pnext_proc += ' if (nullptr == head) return;\n'
+ free_pnext_proc += ' VkBaseOutStructure *header = reinterpret_cast<VkBaseOutStructure *>(head);\n\n'
+ free_pnext_proc += ' switch (header->sType) {\n';
for item in self.structextends_list:
- member_index = next((i for i, v in enumerate(self.structMembers) if v[0] == item), None)
- if member_index is None:
+
+ struct = next((v for v in self.structMembers if v.name == item), None)
+ if struct is None:
continue
- struct_info = self.structMembers[member_index][1]
- feature_protect = self.structMembers[member_index][2]
+
+ if struct.ifdef_protect is not None:
+ build_pnext_proc += '#ifdef %s\n' % struct.ifdef_protect
+ free_pnext_proc += '#ifdef %s\n' % struct.ifdef_protect
+ build_pnext_proc += ' case %s: {\n' % self.structTypes[item].value
+ build_pnext_proc += ' safe_%s *safe_struct = new safe_%s;\n' % (item, item)
+ build_pnext_proc += ' safe_struct->initialize(reinterpret_cast<const %s *>(cur_pnext));\n' % item
+ build_pnext_proc += ' cur_ext_struct = reinterpret_cast<void *>(safe_struct);\n'
+ build_pnext_proc += ' } break;\n'
- if feature_protect is not None:
- build_pnext_proc += '#ifdef %s\n' % feature_protect
- free_pnext_proc += '#ifdef %s\n' % feature_protect
- build_pnext_proc += ' case %s: {\n' % self.structTypes[item].value
- build_pnext_proc += ' safe_%s *safe_struct = new safe_%s;\n' % (item, item)
- build_pnext_proc += ' safe_struct->initialize(reinterpret_cast<const %s *>(cur_pnext));\n' % item
- build_pnext_proc += ' cur_ext_struct = reinterpret_cast<void *>(safe_struct);\n'
- build_pnext_proc += ' } break;\n'
+ free_pnext_proc += ' case %s:\n' % self.structTypes[item].value
+ free_pnext_proc += ' delete reinterpret_cast<safe_%s *>(header);\n' % item
+ free_pnext_proc += ' break;\n'
- free_pnext_proc += ' case %s:\n' % self.structTypes[item].value
- free_pnext_proc += ' delete reinterpret_cast<safe_%s *>(header);\n' % item
- free_pnext_proc += ' break;\n'
-
- if feature_protect is not None:
- build_pnext_proc += '#endif // %s\n' % feature_protect
- free_pnext_proc += '#endif // %s\n' % feature_protect
+ if struct.ifdef_protect is not None:
+ build_pnext_proc += '#endif // %s\n' % struct.ifdef_protect
+ free_pnext_proc += '#endif // %s\n' % struct.ifdef_protect
build_pnext_proc += '\n'
free_pnext_proc += '\n'
- build_pnext_proc += ' default:\n'
- build_pnext_proc += ' break;\n'
+ build_pnext_proc += ' default:\n'
+ build_pnext_proc += ' // Encountered an unknown sType -- skip (do not copy) this entry in the chain\n'
+ build_pnext_proc += ' unrecognized_stype = true;\n'
+ build_pnext_proc += ' cur_pnext = header->pNext;\n'
+ build_pnext_proc += ' break;\n'
+ build_pnext_proc += ' }\n'
build_pnext_proc += ' }\n'
build_pnext_proc += ' }\n'
build_pnext_proc += ' return cur_ext_struct;\n'
build_pnext_proc += '}\n\n'
- free_pnext_proc += ' default:\n'
- free_pnext_proc += ' assert(0);\n'
- free_pnext_proc += ' }\n'
+ free_pnext_proc += ' default:\n'
+ free_pnext_proc += ' // Do nothing -- skip unrecognized sTypes\n'
+ free_pnext_proc += ' break;\n'
free_pnext_proc += ' }\n'
free_pnext_proc += '}\n'
@@ -1136,6 +1146,7 @@
custom_copy_txt = {
# VkGraphicsPipelineCreateInfo is special case because it has custom construct parameters
'VkGraphicsPipelineCreateInfo' :
+ ' pNext = SafePnextCopy(src.pNext);\n'
' if (stageCount && src.pStages) {\n'
' pStages = new safe_VkPipelineShaderStageCreateInfo[stageCount];\n'
' for (uint32_t i=0; i<stageCount; ++i) {\n'
@@ -1186,6 +1197,7 @@
' pDynamicState = NULL;\n',
# VkPipelineViewportStateCreateInfo is special case because it has custom construct parameters
'VkPipelineViewportStateCreateInfo' :
+ ' pNext = SafePnextCopy(src.pNext);\n'
' if (src.pViewports) {\n'
' pViewports = new VkViewport[src.viewportCount];\n'
' memcpy ((void *)pViewports, (void *)src.pViewports, sizeof(VkViewport)*src.viewportCount);\n'
@@ -1204,8 +1216,11 @@
' if (pCode)\n'
' delete[] reinterpret_cast<const uint8_t *>(pCode);\n' }
+ copy_pnext = ''
for member in item.members:
m_type = member.type
+ if member.name == 'pNext':
+ copy_pnext = ' pNext = SafePnextCopy(in_struct->pNext);\n'
if member.type in self.structNames:
member_index = next((i for i, v in enumerate(self.structMembers) if v[0] == member.type), None)
if member_index is not None and self.NeedSafeStruct(self.structMembers[member_index]) == True:
@@ -1213,9 +1228,10 @@
if member.ispointer and 'safe_' not in m_type and self.TypeContainsObjectHandle(member.type, False) == False:
# Ptr types w/o a safe_struct, for non-null case need to allocate new ptr and copy data in
if m_type in ['void', 'char']:
- # For these exceptions just copy initial value over for now
- init_list += '\n %s(in_struct->%s),' % (member.name, member.name)
- init_func_txt += ' %s = in_struct->%s;\n' % (member.name, member.name)
+ if member.name != 'pNext':
+ # For these exceptions just copy initial value over for now
+ init_list += '\n %s(in_struct->%s),' % (member.name, member.name)
+ init_func_txt += ' %s = in_struct->%s;\n' % (member.name, member.name)
else:
default_init_list += '\n %s(nullptr),' % (member.name)
init_list += '\n %s(nullptr),' % (member.name)
@@ -1223,20 +1239,19 @@
construct_txt += ' %s = in_struct->%s;\n' % (member.name, member.name)
else:
init_func_txt += ' %s = nullptr;\n' % (member.name)
- if 'pNext' != member.name and 'void' not in m_type:
- if not member.isstaticarray and (member.len is None or '/' in member.len):
- construct_txt += ' if (in_struct->%s) {\n' % member.name
- construct_txt += ' %s = new %s(*in_struct->%s);\n' % (member.name, m_type, member.name)
- construct_txt += ' }\n'
- destruct_txt += ' if (%s)\n' % member.name
- destruct_txt += ' delete %s;\n' % member.name
- else:
- construct_txt += ' if (in_struct->%s) {\n' % member.name
- construct_txt += ' %s = new %s[in_struct->%s];\n' % (member.name, m_type, member.len)
- construct_txt += ' memcpy ((void *)%s, (void *)in_struct->%s, sizeof(%s)*in_struct->%s);\n' % (member.name, member.name, m_type, member.len)
- construct_txt += ' }\n'
- destruct_txt += ' if (%s)\n' % member.name
- destruct_txt += ' delete[] %s;\n' % member.name
+ if not member.isstaticarray and (member.len is None or '/' in member.len):
+ construct_txt += ' if (in_struct->%s) {\n' % member.name
+ construct_txt += ' %s = new %s(*in_struct->%s);\n' % (member.name, m_type, member.name)
+ construct_txt += ' }\n'
+ destruct_txt += ' if (%s)\n' % member.name
+ destruct_txt += ' delete %s;\n' % member.name
+ else:
+ construct_txt += ' if (in_struct->%s) {\n' % member.name
+ construct_txt += ' %s = new %s[in_struct->%s];\n' % (member.name, m_type, member.len)
+ construct_txt += ' memcpy ((void *)%s, (void *)in_struct->%s, sizeof(%s)*in_struct->%s);\n' % (member.name, member.name, m_type, member.len)
+ construct_txt += ' }\n'
+ destruct_txt += ' if (%s)\n' % member.name
+ destruct_txt += ' delete[] %s;\n' % member.name
elif member.isstaticarray or member.len is not None:
if member.len is None:
# Extract length of static array by grabbing val between []
@@ -1280,19 +1295,29 @@
init_func_txt += ' %s = in_struct->%s;\n' % (member.name, member.name)
if '' != init_list:
init_list = init_list[:-1] # hack off final comma
+
+
if item.name in custom_construct_txt:
construct_txt = custom_construct_txt[item.name]
+
+ construct_txt = copy_pnext + construct_txt
+
if item.name in custom_destruct_txt:
destruct_txt = custom_destruct_txt[item.name]
+
+ if copy_pnext:
+ destruct_txt += ' if (pNext)\n FreePnextChain(pNext);\n'
+
safe_struct_body.append("\n%s::%s(const %s* in_struct%s) :%s\n{\n%s}" % (ss_name, ss_name, item.name, self.custom_construct_params.get(item.name, ''), init_list, construct_txt))
if '' != default_init_list:
default_init_list = " :%s" % (default_init_list[:-1])
safe_struct_body.append("\n%s::%s()%s\n{}" % (ss_name, ss_name, default_init_list))
# Create slight variation of init and construct txt for copy constructor that takes a src object reference vs. struct ptr
copy_construct_init = init_func_txt.replace('in_struct->', 'src.')
- copy_construct_txt = construct_txt.replace(' (in_struct->', ' (src.') # Exclude 'if' blocks from next line
- copy_construct_txt = copy_construct_txt.replace('(in_struct->', '(*src.') # Pass object to copy constructors
- copy_construct_txt = copy_construct_txt.replace('in_struct->', 'src.') # Modify remaining struct refs for src object
+ copy_construct_txt = construct_txt.replace(' (in_struct->', ' (src.') # Exclude 'if' blocks from next line
+ copy_construct_txt = construct_txt.replace(' (in_struct->', ' (src.') # Exclude 'if' blocks from next line
+ copy_construct_txt = re.sub('(new \\w+)\\(in_struct->', '\\1(*src.', construct_txt) # Pass object to copy constructors
+ copy_construct_txt = copy_construct_txt.replace('in_struct->', 'src.') # Modify remaining struct refs for src object
if item.name in custom_copy_txt:
copy_construct_txt = custom_copy_txt[item.name]
copy_assign_txt = ' if (&src == this) return *this;\n\n' + destruct_txt + '\n' + copy_construct_init + copy_construct_txt + '\n return *this;'