diff options
| author | Tobin Ehlis <tobine@google.com> | 2016-02-10 15:32:46 -0700 |
|---|---|---|
| committer | Tobin Ehlis <tobine@google.com> | 2016-02-11 16:31:56 -0700 |
| commit | 5e29489f855a8c6fba84c1e608bfaa5dd58066d1 (patch) | |
| tree | 1aa4730a1b71a7a03392ba7dbd79bc1062517f61 | |
| parent | 2f18c59a5c36bfbac1dd99ee35b58027b433156a (diff) | |
| download | usermoji-5e29489f855a8c6fba84c1e608bfaa5dd58066d1.tar.xz | |
layers: Update vk_helper to generate safe_struct wrappers
Create vk_safe_struct.h/cpp files that contain wrapped versions of vk structs.
The idea is to wrap structs that contain non-dispatchable objects so that
the non-dispatchable objects are no longer contained within or below "const" decls.
The safe struct wrappers are intended to exactly match the original structures
in how they appear, but they also contain some utility functions to contruct and
desctruct themselves so that ptr chains are automatically replicated.
For unique_objects, the idea is to use the safe_struct wrappers as follows:
foreach struct that contains non-dispatchable objects
declare local safe_struct version of struct
initialize struct to exactly match original
unwrap non-dispatchable objects in place in the safe_struct
| -rwxr-xr-x | vk_helper.py | 183 |
1 files changed, 176 insertions, 7 deletions
diff --git a/vk_helper.py b/vk_helper.py index dcff2f68..75441931 100755 --- a/vk_helper.py +++ b/vk_helper.py @@ -76,6 +76,11 @@ enum_type_dict = {} # |->['dyn_array'] = bool indicating if member is a dynamically sized array # '->['array_size'] = For dyn_array, member name used to size array, else int size for static array struct_dict = {} +struct_order_list = [] # struct names in order they're declared +# Store struct names that require #ifdef guards +# dict stores struct and enum definitions that are guarded by ifdef as the key +# and the txt of the ifdef is the value +ifdef_dict = {} # typedef_fwd_dict stores mapping from orig_type_name -> new_type_name typedef_fwd_dict = {} # typedef_rev_dict stores mapping from new_type_name -> orig_type_name @@ -129,9 +134,17 @@ class HeaderFileParser: # TODO : Comment parsing is very fragile but handles 2 known files block_comment = False prev_count_name = '' + ifdef_txt = '' + ifdef_active = 0 exclude_struct_list = ['VkPlatformHandleXcbKHR', 'VkPlatformHandleX11KHR'] with open(self.header_file) as f: for line in f: + if True in [ifd_txt in line for ifd_txt in ['#ifdef ', '#ifndef ']]: + ifdef_txt = line.split()[1] + ifdef_active = ifdef_active + 1 + continue + if ifdef_active != 0 and '#endif' in line: + ifdef_active = ifdef_active - 1 if block_comment: if '*/' in line: block_comment = False @@ -189,6 +202,7 @@ class HeaderFileParser: #print("Found Actual Struct type %s" % base_type) self.struct_dict[base_type] = self.struct_dict['tmp_struct'] self.struct_dict.pop('tmp_struct', 0) + struct_order_list.append(base_type) self.types_dict[base_type] = 'struct' self.types_dict.pop('tmp_struct', 0) elif 'tmp_enum' == base_type: @@ -203,6 +217,8 @@ class HeaderFileParser: self.enum_type_dict.pop('tmp_enum', 0) self.types_dict[base_type] = 'enum' self.types_dict.pop('tmp_enum', 0) + if ifdef_active: + ifdef_dict[base_type] = ifdef_txt self.typedef_fwd_dict[base_type] = targ_type.strip(';') self.typedef_rev_dict[targ_type.strip(';')] = base_type #print("fwd_dict: %s = %s" % (base_type, targ_type)) @@ -259,6 +275,9 @@ class HeaderFileParser: # 3a. Name of dynam array must end in 's' char OR # 3b. Name of count var minus 'count' must be contained in name of dynamic array def _is_dynamic_array(self, full_type, name): + exceptions = ['pEnabledFeatures', 'pWaitDstStageMask', 'pSampleMask'] + if name in exceptions: + return False if '' != self.last_struct_count_name: if 'const' in full_type and '*' in full_type: if name.endswith('s') or self.last_struct_count_name.lower().replace('count', '') in name.lower(): @@ -309,13 +328,13 @@ class HeaderFileParser: self.struct_dict[struct_type][num]['type'] = member_type if '[' in member_name: (member_name, array_size) = member_name.split('[', 1) - if 'char' in member_type: - self.struct_dict[struct_type][num]['array'] = False - self.struct_dict[struct_type][num]['array_size'] = 0 - self.struct_dict[struct_type][num]['ptr'] = True - else: - self.struct_dict[struct_type][num]['array'] = True - self.struct_dict[struct_type][num]['array_size'] = array_size.strip(']') + #if 'char' in member_type: + # self.struct_dict[struct_type][num]['array'] = False + # self.struct_dict[struct_type][num]['array_size'] = 0 + # self.struct_dict[struct_type][num]['ptr'] = True + #else: + self.struct_dict[struct_type][num]['array'] = True + self.struct_dict[struct_type][num]['array_size'] = array_size.strip(']') elif self._is_dynamic_array(self.struct_dict[struct_type][num]['full_type'], member_name): #print("Found dynamic array %s of size %s" % (member_name, self.last_struct_count_name)) self.struct_dict[struct_type][num]['array'] = True @@ -431,12 +450,17 @@ class StructWrapperGen: self.api_prefix = prefix self.header_filename = os.path.join(out_dir, self.api_prefix+"_struct_wrappers.h") self.class_filename = os.path.join(out_dir, self.api_prefix+"_struct_wrappers.cpp") + self.safe_struct_header_filename = os.path.join(out_dir, self.api_prefix+"_safe_struct.h") + self.safe_struct_source_filename = os.path.join(out_dir, self.api_prefix+"_safe_struct.cpp") self.string_helper_filename = os.path.join(out_dir, self.api_prefix+"_struct_string_helper.h") self.string_helper_no_addr_filename = os.path.join(out_dir, self.api_prefix+"_struct_string_helper_no_addr.h") self.string_helper_cpp_filename = os.path.join(out_dir, self.api_prefix+"_struct_string_helper_cpp.h") self.string_helper_no_addr_cpp_filename = os.path.join(out_dir, self.api_prefix+"_struct_string_helper_no_addr_cpp.h") self.validate_helper_filename = os.path.join(out_dir, self.api_prefix+"_struct_validate_helper.h") self.no_addr = False + # Safe Struct (ss) header and source files + self.ssh = CommonFileGen(self.safe_struct_header_filename) + self.sss = CommonFileGen(self.safe_struct_source_filename) self.hfg = CommonFileGen(self.header_filename) self.cfg = CommonFileGen(self.class_filename) self.shg = CommonFileGen(self.string_helper_filename) @@ -486,6 +510,20 @@ class StructWrapperGen: self.cfg.setFooter(self._generateFooter()) self.cfg.generate() + # Safe Structs are versions of vulkan structs with non-const safe ptrs + # that make shadowing structures and clean-up of shadowed structures very simple + def generateSafeStructHeader(self): + self.ssh.setCopyright(self._generateCopyright()) + self.ssh.setHeader(self._generateSafeStructHeader()) + self.ssh.setBody(self._generateSafeStructDecls()) + self.ssh.generate() + + def generateSafeStructs(self): + self.sss.setCopyright(self._generateCopyright()) + self.sss.setHeader(self._generateSafeStructSourceHeader()) + self.sss.setBody(self._generateSafeStructSource()) + self.sss.generate() + # Generate c-style .h file that contains functions for printing structs def generateStringHelper(self): print("Generating struct string helper") @@ -1507,6 +1545,135 @@ class StructWrapperGen: def _generateFooter(self): return "\n//any footer info for class\n" + def _getSafeStructName(self, struct): + return "safe_%s" % (struct) + + # If struct has sType or ptr members, generate safe type + def _hasSafeStruct(self, s): + exceptions = ['VkPhysicalDeviceFeatures', 'VkPipelineColorBlendStateCreateInfo'] + if s in exceptions: + return False + if 'sType' == self.struct_dict[s][0]['name']: + return True + for m in self.struct_dict[s]: + if self.struct_dict[s][m]['ptr']: + return True + return False + + def _generateSafeStructHeader(self): + header = [] + header.append("//#includes, #defines, globals and such...\n") + header.append('#include "vulkan/vulkan.h"') + return "".join(header) + + # If given ty is in obj list, or is a struct that contains anything in obj list, return True + def _typeHasObject(self, ty, obj): + if ty in obj: + return True + if is_type(ty, 'struct'): + for m in self.struct_dict[ty]: + if self.struct_dict[ty][m]['type'] in obj: + return True + return False + + def _generateSafeStructDecls(self): + ss_decls = [] + for s in struct_order_list: + if not self._hasSafeStruct(s): + continue + if s in ifdef_dict: + ss_decls.append('#ifdef %s' % ifdef_dict[s]) + ss_name = self._getSafeStructName(s) + ss_decls.append("\nstruct %s {" % (ss_name)) + for m in sorted(self.struct_dict[s]): + m_type = self.struct_dict[s][m]['type'] + if is_type(m_type, 'struct') and self._hasSafeStruct(m_type): + m_type = self._getSafeStructName(m_type) + if self.struct_dict[s][m]['array_size'] != 0 and not self.struct_dict[s][m]['dyn_array']: + ss_decls.append(" %s %s[%s];" % (m_type, self.struct_dict[s][m]['name'], self.struct_dict[s][m]['array_size'])) + elif self.struct_dict[s][m]['ptr'] and 'safe_' not in m_type and not self._typeHasObject(m_type, vulkan.object_non_dispatch_list):#m_type in ['char', 'float', 'uint32_t', 'void', 'VkPhysicalDeviceFeatures']: # We'll never overwrite char* so it can remain const + ss_decls.append(" %s %s;" % (self.struct_dict[s][m]['full_type'], self.struct_dict[s][m]['name'])) + elif self.struct_dict[s][m]['array']: + ss_decls.append(" %s* %s;" % (m_type, self.struct_dict[s][m]['name'])) + elif self.struct_dict[s][m]['ptr']: + ss_decls.append(" %s* %s;" % (m_type, self.struct_dict[s][m]['name'])) + else: + ss_decls.append(" %s %s;" % (m_type, self.struct_dict[s][m]['name'])) + ss_decls.append(" %s(const %s* pInStruct);" % (ss_name, s)) + ss_decls.append(" %s();" % (ss_name)) + ss_decls.append(" ~%s();" % (ss_name)) + ss_decls.append(" void initialize(const %s* pInStruct);" % (s)) + ss_decls.append("};") + if s in ifdef_dict: + ss_decls.append('#endif') + return "\n".join(ss_decls) + + def _generateSafeStructSourceHeader(self): + header = [] + header.append("//#includes, #defines, globals and such...\n") + header.append('#include "vk_safe_struct.h"') + return "".join(header) + + def _generateSafeStructSource(self): + ss_src = [] + for s in struct_order_list: + if not self._hasSafeStruct(s): + continue + if s in ifdef_dict: + ss_src.append('#ifdef %s' % ifdef_dict[s]) + ss_name = self._getSafeStructName(s) + init_list = '' # list of members in struct constructor initializer + init_func_txt = '' # Txt for initialize() function that takes struct ptr and inits members + construct_txt = '' + destruct_txt = '' + for m in self.struct_dict[s]: + m_name = self.struct_dict[s][m]['name'] + m_type = self.struct_dict[s][m]['type'] + if is_type(m_type, 'struct') and self._hasSafeStruct(m_type): + m_type = self._getSafeStructName(m_type) + if self.struct_dict[s][m]['ptr'] and 'safe_' not in m_type and not self._typeHasObject(m_type, vulkan.object_non_dispatch_list):# in ['char', 'float', 'uint32_t', 'void', 'VkPhysicalDeviceFeatures']) or 'pp' == self.struct_dict[s][m]['name'][0:1]: + init_list += '\n\t%s(pInStruct->%s),' % (m_name, m_name) + init_func_txt += ' %s = pInStruct->%s;\n' % (m_name, m_name) + elif self.struct_dict[s][m]['array']: + array_element = 'pInStruct->%s[i]' % (m_name) + if is_type(self.struct_dict[s][m]['type'], 'struct') and self._hasSafeStruct(self.struct_dict[s][m]['type']): + array_element = '%s(&pInStruct->%s[i])' % (self._getSafeStructName(self.struct_dict[s][m]['type']), m_name) + construct_txt += ' if (%s && pInStruct->%s) {\n' % (self.struct_dict[s][m]['array_size'], m_name) + construct_txt += ' %s = new %s[%s];\n' % (m_name, m_type, self.struct_dict[s][m]['array_size']) + destruct_txt += ' if (%s)\n' % (m_name) + destruct_txt += ' delete[] %s;\n' % (m_name) + construct_txt += ' for (uint32_t i=0; i<%s; ++i) {\n' % (self.struct_dict[s][m]['array_size']) + if 'safe_' in m_type: + construct_txt += ' %s[i].initialize(&pInStruct->%s[i]);\n' % (m_name, m_name) + else: + construct_txt += ' %s[i] = %s;\n' % (m_name, array_element) + construct_txt += ' }\n' + construct_txt += ' } else {\n' + construct_txt += ' %s = NULL;\n' % (m_name) + construct_txt += ' }\n' + elif self.struct_dict[s][m]['ptr']: + construct_txt += ' if (pInStruct->%s)\n' % (m_name) + construct_txt += ' %s = new %s(pInStruct->%s);\n' % (m_name, m_type, m_name) + construct_txt += ' else\n' + construct_txt += ' %s = NULL;\n' % (m_name) + destruct_txt += ' if (%s)\n' % (m_name) + destruct_txt += ' delete %s;\n' % (m_name) + elif 'safe_' in m_type: # inline struct, need to pass in reference for constructor + init_list += '\n\t%s(&pInStruct->%s),' % (m_name, m_name) + init_func_txt += ' %s.initialize(&pInStruct->%s);\n' % (m_name, m_name) + else: + init_list += '\n\t%s(pInStruct->%s),' % (m_name, m_name) + init_func_txt += ' %s = pInStruct->%s;\n' % (m_name, m_name) + if '' != init_list: + init_list = init_list[:-1] # hack off final comma + ss_src.append("\n%s::%s(const %s* pInStruct) : %s\n{\n%s}" % (ss_name, ss_name, s, init_list, construct_txt)) + ss_src.append("\n%s::%s() {}" % (ss_name, ss_name)) + ss_src.append("\n%s::~%s()\n{\n%s}" % (ss_name, ss_name, destruct_txt)) + ss_src.append("\nvoid %s::initialize(const %s* pInStruct)\n{\n%s%s}" % (ss_name, s, init_func_txt, construct_txt)) + if s in ifdef_dict: + ss_src.append('#endif') + return "\n".join(ss_src) + class EnumCodeGen: def __init__(self, enum_type_dict=None, enum_val_dict=None, typedef_fwd_dict=None, in_file=None, out_sh_file=None, out_vh_file=None): self.et_dict = enum_type_dict @@ -1938,6 +2105,8 @@ def main(argv=None): sw.set_include_headers(["stdio.h", "stdlib.h", input_header]) sw.generateSizeHelper() sw.generateSizeHelperC() + sw.generateSafeStructHeader() + sw.generateSafeStructs() if opts.gen_struct_sizes: st = StructWrapperGen(struct_dict, os.path.basename(opts.input_file).strip(".h"), os.path.dirname(enum_sh_filename)) st.set_include_headers(["stdio.h", "stdlib.h", input_header]) |
