vrclient: Classify struct compatibility over SDK versions.

CW-Bug-Id: #22729
This commit is contained in:
Rémi Bernon 2023-09-29 09:58:52 +02:00 committed by Arkadiusz Hiler
parent fb25831f68
commit cafc3fb8e7

View File

@ -121,6 +121,8 @@ EXEMPT_STRUCTS = {
"HmdVector3_t",
"HmdVector3d_t",
"HmdVector4_t",
"IntersectionMaskCircle_t",
"IntersectionMaskRectangle_t",
}
# structs for which the size is important, either because of arrays or size parameters
@ -213,6 +215,7 @@ all_records = {}
all_structs = {}
all_sources = {}
all_versions = {}
unique_structs = []
MANUAL_METHODS = {
@ -271,8 +274,24 @@ class BasicType:
def __init__(self, type, abi):
self._type = type.get_canonical()
self._abi = abi
self._decl_order = 0
self._conv_cache = {}
self.size = self._type.get_size()
self.id = self._type.spelling
@property
def order(self):
return self._decl_order
def set_used(self, order=-1):
if self._decl_order <= order:
return
self._decl_order = order
def needs_conversion(self, other):
if self._type.kind == TypeKind.POINTER and self._type.get_pointee().kind == TypeKind.FUNCTIONPROTO:
return self._abi != other._abi
return False
@ -282,6 +301,7 @@ class Struct:
self._sdkver = sdkver
self._abi = abi
self._fields = None
self._decl_order = 0
self._conv_cache = {}
self.name = canonical_typename(self._cursor)
@ -291,6 +311,19 @@ class Struct:
self.align = self.type.get_align()
self.id = f'{abi}_{self.name}_{sdkver}'
if self._cursor.spelling in EXEMPT_STRUCTS:
self._fields = [Padding(0, self.size)]
@property
def order(self):
return self._decl_order
def set_used(self, order=-1):
if self._decl_order <= order:
return
self._decl_order = order
[f._type.set_used(order - 1) for f in self.fields]
@property
def padded_fields(self):
if self._fields: return self._fields
@ -391,6 +424,7 @@ class Class:
self._sdkver = sdkver
self._abi = abi
self._methods = None
self._decl_order = 0
self.name = cursor.spelling
self.filename = SDK_CLASSES.get(self.name, None)
@ -398,6 +432,7 @@ class Class:
self.version = versions.get(self.name, "")
self.type = self._cursor.type.get_canonical()
self.id = f'{abi}_{self.name}_{sdkver}'
@property
def methods(self):
@ -425,9 +460,21 @@ class Class:
return self.name
return f'{self.name}_{self.version}'
@property
def order(self):
return self._decl_order
def set_used(self, order=-1):
if self._decl_order <= order:
return
self._decl_order = order
def needs_conversion(self, other):
return self._abi[0] != other._abi[0]
def __eq__(self, other):
return self._abi[0] == other._abi[0]
def write_definition(self, out, prefix):
out(f'struct {prefix}{self.full_name}\n')
out(u'{\n')
@ -543,6 +590,11 @@ def declspec(decl, name, prefix):
if decl.kind == TypeKind.ENUM:
return f'uint{decl.get_size() * 8}_t{name}'
type_name = decl.spelling.removeprefix("const ")
type_name = decl.spelling.removeprefix("vr::")
if type_name.startswith(('IVR', 'ID3D')):
return f'{const}void /*{type_name}*/{name}'
real_name = canonical_typename(decl)
real_name = real_name.removeprefix("const ")
real_name = real_name.removeprefix("vr::")
@ -1492,6 +1544,43 @@ def load(sdkver):
return versions, sources
def classify_struct(name):
if name in EXEMPT_STRUCTS:
return None
structs = all_structs[name]
prev = []
versions = {}
unique = True
for sdkver in filter(lambda v: v in structs, reversed(SDK_VERSIONS)):
abis = [structs[sdkver][a] for a in ABIS]
if any(abis[0].needs_conversion(a) for a in abis[1:]):
unique = False
def is_always_compatible(other):
for a, b in zip(abis, other):
if a.needs_conversion(b):
return False
return True
compat = next((k for k, v in prev if is_always_compatible(v)), None)
if compat:
versions[sdkver] = versions[compat]
else:
[abi.set_used() for abi in abis] # make sure order is computed
versions[sdkver] = f"{name}_{display_sdkver(sdkver)}"
prev += [(sdkver, abis)]
if unique:
unique_structs.append(name)
if len(set(versions.values())) == 1:
versions = {sdkver: name for sdkver in versions.keys()}
return versions
def generate(sdkver, structs):
print(f'generating SDK version {sdkver}...')
for child in structs['u32'].values():
@ -1553,6 +1642,31 @@ for i, sdkver in enumerate(reversed(SDK_VERSIONS)):
print('parsing SDKs... 100%')
tmp_structs = {}
for i, name in enumerate(all_structs.keys()):
print(f'classifying structs... {i * 100 // len(all_structs.keys())}%', end='\r')
versions = classify_struct(name)
for sdkver in SDK_VERSIONS:
if not versions or sdkver not in versions: continue
all_versions[sdkver][name] = versions[sdkver]
def struct_order(tuple):
name, structs = tuple
order = (struct.order for abis in structs.values()
for struct in abis.values())
return (min(order), name)
for name, structs in sorted(all_structs.items(), key=struct_order):
tmp_structs[name] = {}
for sdkver in filter(lambda v: v in structs, SDK_VERSIONS):
tmp_structs[name][sdkver] = {a: structs[sdkver][a] for a in ABIS}
all_structs = tmp_structs
print('classifying structs... 100%')
for klass in all_classes.values():
with open(f"vrclient_x64/win{klass.name}.c", "w") as file:
out = file.write