1# Copyright (c) 2018 The Android Open Source Project 2# Copyright (c) 2018 Google Inc. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16from copy import copy 17import hashlib, sys 18 19from .common.codegen import CodeGen, VulkanAPIWrapper 20from .common.vulkantypes import \ 21 VulkanAPI, makeVulkanTypeSimple, iterateVulkanType, VulkanTypeIterator, Atom, FuncExpr, FuncExprVal, FuncLambda 22 23from .wrapperdefs import VulkanWrapperGenerator 24from .wrapperdefs import VULKAN_STREAM_VAR_NAME 25from .wrapperdefs import ROOT_TYPE_VAR_NAME, ROOT_TYPE_PARAM 26from .wrapperdefs import STREAM_RET_TYPE 27from .wrapperdefs import MARSHAL_INPUT_VAR_NAME 28from .wrapperdefs import UNMARSHAL_INPUT_VAR_NAME 29from .wrapperdefs import PARAMETERS_MARSHALING 30from .wrapperdefs import PARAMETERS_MARSHALING_GUEST 31from .wrapperdefs import STYPE_OVERRIDE 32from .wrapperdefs import STRUCT_EXTENSION_PARAM, STRUCT_EXTENSION_PARAM_FOR_WRITE, EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME 33from .wrapperdefs import API_PREFIX_MARSHAL 34from .wrapperdefs import API_PREFIX_UNMARSHAL 35 36from .marshalingdefs import KNOWN_FUNCTION_OPCODES, CUSTOM_MARSHAL_TYPES 37 38class VulkanMarshalingCodegen(VulkanTypeIterator): 39 40 def __init__(self, 41 cgen, 42 streamVarName, 43 rootTypeVarName, 44 inputVarName, 45 marshalPrefix, 46 direction = "write", 47 forApiOutput = False, 48 dynAlloc = False, 49 mapHandles = True, 50 handleMapOverwrites = False, 51 doFiltering = True): 52 self.cgen = cgen 53 self.direction = direction 54 self.processSimple = "write" if self.direction == "write" else "read" 55 self.forApiOutput = forApiOutput 56 57 self.checked = False 58 59 self.streamVarName = streamVarName 60 self.rootTypeVarName = rootTypeVarName 61 self.inputVarName = inputVarName 62 self.marshalPrefix = marshalPrefix 63 64 self.exprAccessor = lambda t: self.cgen.generalAccess(t, parentVarName = self.inputVarName, asPtr = True) 65 self.exprValueAccessor = lambda t: self.cgen.generalAccess(t, parentVarName = self.inputVarName, asPtr = False) 66 self.exprPrimitiveValueAccessor = lambda t: self.cgen.generalAccess(t, parentVarName = self.inputVarName, asPtr = False) 67 self.lenAccessor = lambda t: self.cgen.generalLengthAccess(t, parentVarName = self.inputVarName) 68 self.lenAccessorGuard = lambda t: self.cgen.generalLengthAccessGuard( 69 t, parentVarName=self.inputVarName) 70 self.filterVarAccessor = lambda t: self.cgen.filterVarAccess(t, parentVarName = self.inputVarName) 71 72 self.dynAlloc = dynAlloc 73 self.mapHandles = mapHandles 74 self.handleMapOverwrites = handleMapOverwrites 75 self.doFiltering = doFiltering 76 77 def getTypeForStreaming(self, vulkanType): 78 res = copy(vulkanType) 79 80 if not vulkanType.accessibleAsPointer(): 81 res = res.getForAddressAccess() 82 83 if vulkanType.staticArrExpr: 84 res = res.getForAddressAccess() 85 86 if self.direction == "write": 87 return res 88 else: 89 return res.getForNonConstAccess() 90 91 def makeCastExpr(self, vulkanType): 92 return "(%s)" % ( 93 self.cgen.makeCTypeDecl(vulkanType, useParamName=False)) 94 95 def genStreamCall(self, vulkanType, toStreamExpr, sizeExpr): 96 varname = self.streamVarName 97 func = self.processSimple 98 cast = self.makeCastExpr(self.getTypeForStreaming(vulkanType)) 99 100 self.cgen.stmt( 101 "%s->%s(%s%s, %s)" % (varname, func, cast, toStreamExpr, sizeExpr)) 102 103 def genPrimitiveStreamCall(self, vulkanType, access): 104 varname = self.streamVarName 105 106 self.cgen.streamPrimitive( 107 self.typeInfo, 108 varname, 109 access, 110 vulkanType, 111 direction=self.direction) 112 113 def genHandleMappingCall(self, vulkanType, access, lenAccess): 114 115 if lenAccess is None: 116 lenAccess = "1" 117 handle64Bytes = "8" 118 else: 119 handle64Bytes = "%s * 8" % lenAccess 120 121 handle64Var = self.cgen.var() 122 if lenAccess != "1": 123 self.cgen.beginIf(lenAccess) 124 self.cgen.stmt("uint64_t* %s" % handle64Var) 125 self.cgen.stmt( 126 "%s->alloc((void**)&%s, %s * 8)" % \ 127 (self.streamVarName, handle64Var, lenAccess)) 128 handle64VarAccess = handle64Var 129 handle64VarType = \ 130 makeVulkanTypeSimple(False, "uint64_t", 1, paramName=handle64Var) 131 else: 132 self.cgen.stmt("uint64_t %s" % handle64Var) 133 handle64VarAccess = "&%s" % handle64Var 134 handle64VarType = \ 135 makeVulkanTypeSimple(False, "uint64_t", 0, paramName=handle64Var) 136 137 if self.direction == "write": 138 if self.handleMapOverwrites: 139 self.cgen.stmt( 140 "static_assert(8 == sizeof(%s), \"handle map overwrite requires %s to be 8 bytes long\")" % \ 141 (vulkanType.typeName, vulkanType.typeName)) 142 self.cgen.stmt( 143 "%s->handleMapping()->mapHandles_%s((%s*)%s, %s)" % 144 (self.streamVarName, vulkanType.typeName, vulkanType.typeName, 145 access, lenAccess)) 146 self.genStreamCall(vulkanType, access, "8 * %s" % lenAccess) 147 else: 148 self.cgen.stmt( 149 "%s->handleMapping()->mapHandles_%s_u64(%s, %s, %s)" % 150 (self.streamVarName, vulkanType.typeName, 151 access, 152 handle64VarAccess, lenAccess)) 153 self.genStreamCall(handle64VarType, handle64VarAccess, handle64Bytes) 154 else: 155 self.genStreamCall(handle64VarType, handle64VarAccess, handle64Bytes) 156 self.cgen.stmt( 157 "%s->handleMapping()->mapHandles_u64_%s(%s, %s%s, %s)" % 158 (self.streamVarName, vulkanType.typeName, 159 handle64VarAccess, 160 self.makeCastExpr(vulkanType.getForNonConstAccess()), access, 161 lenAccess)) 162 163 if lenAccess != "1": 164 self.cgen.endIf() 165 166 def doAllocSpace(self, vulkanType): 167 if self.dynAlloc and self.direction == "read": 168 access = self.exprAccessor(vulkanType) 169 lenAccess = self.lenAccessor(vulkanType) 170 sizeof = self.cgen.sizeofExpr( \ 171 vulkanType.getForValueAccess()) 172 if lenAccess: 173 bytesExpr = "%s * %s" % (lenAccess, sizeof) 174 else: 175 bytesExpr = sizeof 176 177 self.cgen.stmt( \ 178 "%s->alloc((void**)&%s, %s)" % 179 (self.streamVarName, 180 access, bytesExpr)) 181 182 def getOptionalStringFeatureExpr(self, vulkanType): 183 if vulkanType.optionalStr is not None: 184 if vulkanType.optionalStr.startswith("streamFeature:"): 185 splitted = vulkanType.optionalStr.split(":") 186 featureExpr = "%s->getFeatureBits() & %s" % (self.streamVarName, splitted[1]) 187 return featureExpr 188 return None 189 190 def onCheck(self, vulkanType): 191 192 if self.forApiOutput: 193 return 194 195 featureExpr = self.getOptionalStringFeatureExpr(vulkanType); 196 197 self.checked = True 198 199 access = self.exprAccessor(vulkanType) 200 201 needConsistencyCheck = False 202 203 self.cgen.line("// WARNING PTR CHECK") 204 if (self.dynAlloc and self.direction == "read") or self.direction == "write": 205 checkAccess = self.exprAccessor(vulkanType) 206 addrExpr = "&" + checkAccess 207 sizeExpr = self.cgen.sizeofExpr(vulkanType) 208 else: 209 checkName = "check_%s" % vulkanType.paramName 210 self.cgen.stmt("%s %s" % ( 211 self.cgen.makeCTypeDecl(vulkanType, useParamName = False), checkName)) 212 checkAccess = checkName 213 addrExpr = "&" + checkAccess 214 sizeExpr = self.cgen.sizeofExpr(vulkanType) 215 needConsistencyCheck = True 216 217 if featureExpr is not None: 218 self.cgen.beginIf(featureExpr) 219 220 self.genPrimitiveStreamCall( 221 vulkanType, 222 checkAccess) 223 224 if featureExpr is not None: 225 self.cgen.endIf() 226 227 if featureExpr is not None: 228 self.cgen.beginIf("(!(%s) || %s)" % (featureExpr, access)) 229 else: 230 self.cgen.beginIf(access) 231 232 if needConsistencyCheck and featureExpr is None: 233 self.cgen.beginIf("!(%s)" % checkName) 234 self.cgen.stmt( 235 "fprintf(stderr, \"fatal: %s inconsistent between guest and host\\n\")" % (access)) 236 self.cgen.endIf() 237 238 239 def onCheckWithNullOptionalStringFeature(self, vulkanType): 240 self.cgen.beginIf("%s->getFeatureBits() & VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT" % self.streamVarName) 241 self.onCheck(vulkanType) 242 243 def endCheckWithNullOptionalStringFeature(self, vulkanType): 244 self.endCheck(vulkanType) 245 self.cgen.endIf() 246 self.cgen.beginElse() 247 248 def finalCheckWithNullOptionalStringFeature(self, vulkanType): 249 self.cgen.endElse() 250 251 def endCheck(self, vulkanType): 252 253 if self.checked: 254 self.cgen.endIf() 255 self.checked = False 256 257 def genFilterFunc(self, filterfunc, env): 258 259 def loop(expr, lambdaEnv={}): 260 def do_func(expr): 261 fnamestr = expr.name.name 262 if "not" == fnamestr: 263 return "!(%s)" % (loop(expr.args[0], lambdaEnv)) 264 if "eq" == fnamestr: 265 return "(%s == %s)" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv)) 266 if "and" == fnamestr: 267 return "(%s && %s)" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv)) 268 if "or" == fnamestr: 269 return "(%s || %s)" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv)) 270 if "bitwise_and" == fnamestr: 271 return "(%s & %s)" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv)) 272 if "getfield" == fnamestr: 273 ptrlevels = get_ptrlevels(expr.args[0].val.name) 274 if ptrlevels == 0: 275 return "%s.%s" % (loop(expr.args[0], lambdaEnv), expr.args[1].val) 276 else: 277 return "(%s(%s)).%s" % ("*" * ptrlevels, loop(expr.args[0], lambdaEnv), expr.args[1].val) 278 279 if "if" == fnamestr: 280 return "((%s) ? (%s) : (%s))" % (loop(expr.args[0], lambdaEnv), loop(expr.args[1], lambdaEnv), loop(expr.args[2], lambdaEnv)) 281 282 return "%s(%s)" % (fnamestr, ", ".join(map(lambda e: loop(e, lambdaEnv), expr.args))) 283 284 def do_expratom(atomname, lambdaEnv= {}): 285 if lambdaEnv.get(atomname, None) is not None: 286 return atomname 287 288 enventry = env.get(atomname, None) 289 if None != enventry: 290 return self.getEnvAccessExpr(atomname) 291 return atomname 292 293 def get_ptrlevels(atomname, lambdaEnv= {}): 294 if lambdaEnv.get(atomname, None) is not None: 295 return 0 296 297 enventry = env.get(atomname, None) 298 if None != enventry: 299 return self.getPointerIndirectionLevels(atomname) 300 301 return 0 302 303 def do_exprval(expr, lambdaEnv= {}): 304 expratom = expr.val 305 306 if Atom == type(expratom): 307 return do_expratom(expratom.name, lambdaEnv) 308 309 return "%s" % expratom 310 311 def do_lambda(expr, lambdaEnv= {}): 312 params = expr.vs 313 body = expr.body 314 newEnv = {} 315 316 for (k, v) in lambdaEnv.items(): 317 newEnv[k] = v 318 319 for p in params: 320 newEnv[p.name] = p.typ 321 322 return "[](%s) { return %s; }" % (", ".join(list(map(lambda p: "%s %s" % (p.typ, p.name), params))), loop(body, lambdaEnv=newEnv)) 323 324 if FuncExpr == type(expr): 325 return do_func(expr) 326 if FuncLambda == type(expr): 327 return do_lambda(expr) 328 elif FuncExprVal == type(expr): 329 return do_exprval(expr) 330 331 return loop(filterfunc) 332 333 def beginFilterGuard(self, vulkanType): 334 if vulkanType.filterVar == None: 335 return 336 337 if self.doFiltering == False: 338 return 339 340 filterVarAccess = self.getEnvAccessExpr(vulkanType.filterVar) 341 342 filterValsExpr = None 343 filterFuncExpr = None 344 filterExpr = None 345 346 filterFeature = "%s->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT" % self.streamVarName 347 348 if None != vulkanType.filterVals: 349 filterValsExpr = " || ".join(map(lambda filterval: "(%s == %s)" % (filterval, filterVarAccess), vulkanType.filterVals)) 350 351 if None != vulkanType.filterFunc: 352 filterFuncExpr = self.genFilterFunc(vulkanType.filterFunc, self.currentStructInfo.environment) 353 354 if None != filterValsExpr and None != filterFuncExpr: 355 filterExpr = "%s || %s" % (filterValsExpr, filterFuncExpr) 356 elif None == filterValsExpr and None == filterFuncExpr: 357 # Assume is bool 358 self.cgen.beginIf(filterVarAccess) 359 elif None != filterValsExpr: 360 self.cgen.beginIf("(!(%s) || (%s))" % (filterFeature, filterValsExpr)) 361 elif None != filterFuncExpr: 362 self.cgen.beginIf("(!(%s) || (%s))" % (filterFeature, filterFuncExpr)) 363 364 def endFilterGuard(self, vulkanType, cleanupExpr=None): 365 if vulkanType.filterVar == None: 366 return 367 368 if self.doFiltering == False: 369 return 370 371 if cleanupExpr == None: 372 self.cgen.endIf() 373 else: 374 self.cgen.endIf() 375 self.cgen.beginElse() 376 self.cgen.stmt(cleanupExpr) 377 self.cgen.endElse() 378 379 def getEnvAccessExpr(self, varName): 380 parentEnvEntry = self.currentStructInfo.environment.get(varName, None) 381 382 if parentEnvEntry != None: 383 isParentMember = parentEnvEntry["structmember"] 384 385 if isParentMember: 386 envAccess = self.exprValueAccessor(list(filter(lambda member: member.paramName == varName, self.currentStructInfo.members))[0]) 387 else: 388 envAccess = varName 389 return envAccess 390 391 return None 392 393 def getPointerIndirectionLevels(self, varName): 394 parentEnvEntry = self.currentStructInfo.environment.get(varName, None) 395 396 if parentEnvEntry != None: 397 isParentMember = parentEnvEntry["structmember"] 398 399 if isParentMember: 400 return list(filter(lambda member: member.paramName == varName, self.currentStructInfo.members))[0].pointerIndirectionLevels 401 else: 402 return 0 403 return 0 404 405 return 0 406 407 408 def onCompoundType(self, vulkanType): 409 410 access = self.exprAccessor(vulkanType) 411 lenAccess = self.lenAccessor(vulkanType) 412 lenAccessGuard = self.lenAccessorGuard(vulkanType) 413 414 self.beginFilterGuard(vulkanType) 415 416 if vulkanType.pointerIndirectionLevels > 0: 417 self.doAllocSpace(vulkanType) 418 419 if lenAccess is not None: 420 if lenAccessGuard is not None: 421 self.cgen.beginIf(lenAccessGuard) 422 loopVar = "i" 423 access = "%s + %s" % (access, loopVar) 424 forInit = "uint32_t %s = 0" % loopVar 425 forCond = "%s < (uint32_t)%s" % (loopVar, lenAccess) 426 forIncr = "++%s" % loopVar 427 self.cgen.beginFor(forInit, forCond, forIncr) 428 429 accessWithCast = "%s(%s)" % (self.makeCastExpr( 430 self.getTypeForStreaming(vulkanType)), access) 431 432 callParams = [self.streamVarName, self.rootTypeVarName, accessWithCast] 433 434 for (bindName, localName) in vulkanType.binds.items(): 435 callParams.append(self.getEnvAccessExpr(localName)) 436 437 self.cgen.funcCall(None, self.marshalPrefix + vulkanType.typeName, 438 callParams) 439 440 if lenAccess is not None: 441 self.cgen.endFor() 442 if lenAccessGuard is not None: 443 self.cgen.endIf() 444 445 if self.direction == "read": 446 self.endFilterGuard(vulkanType, "%s = 0" % self.exprAccessor(vulkanType)) 447 else: 448 self.endFilterGuard(vulkanType) 449 450 def onString(self, vulkanType): 451 452 access = self.exprAccessor(vulkanType) 453 454 if self.direction == "write": 455 self.cgen.stmt("%s->putString(%s)" % (self.streamVarName, access)) 456 else: 457 castExpr = \ 458 self.makeCastExpr( \ 459 self.getTypeForStreaming( \ 460 vulkanType.getForAddressAccess())) 461 462 self.cgen.stmt( \ 463 "%s->loadStringInPlace(%s&%s)" % (self.streamVarName, castExpr, access)) 464 465 def onStringArray(self, vulkanType): 466 467 access = self.exprAccessor(vulkanType) 468 lenAccess = self.lenAccessor(vulkanType) 469 470 if self.direction == "write": 471 self.cgen.stmt("saveStringArray(%s, %s, %s)" % (self.streamVarName, 472 access, lenAccess)) 473 else: 474 castExpr = \ 475 self.makeCastExpr( \ 476 self.getTypeForStreaming( \ 477 vulkanType.getForAddressAccess())) 478 479 self.cgen.stmt("%s->loadStringArrayInPlace(%s&%s)" % (self.streamVarName, castExpr, access)) 480 481 def onStaticArr(self, vulkanType): 482 access = self.exprValueAccessor(vulkanType) 483 lenAccess = self.lenAccessor(vulkanType) 484 finalLenExpr = "%s * %s" % (lenAccess, self.cgen.sizeofExpr(vulkanType)) 485 self.genStreamCall(vulkanType, access, finalLenExpr) 486 487 # Old version VkEncoder may have some sType values conflict with VkDecoder 488 # of new versions. For host decoder, it should not carry the incorrect old 489 # sType values to the |forUnmarshaling| struct. Instead it should overwrite 490 # the sType value. 491 def overwriteSType(self, vulkanType): 492 if self.direction == "read": 493 sTypeParam = copy(vulkanType) 494 sTypeParam.paramName = "sType" 495 sTypeAccess = self.exprAccessor(sTypeParam) 496 497 typeName = vulkanType.parent.typeName 498 if typeName in STYPE_OVERRIDE: 499 self.cgen.stmt("%s = %s" % 500 (sTypeAccess, STYPE_OVERRIDE[typeName])) 501 502 def onStructExtension(self, vulkanType): 503 self.overwriteSType(vulkanType) 504 505 sTypeParam = copy(vulkanType) 506 sTypeParam.paramName = "sType" 507 508 access = self.exprAccessor(vulkanType) 509 sizeVar = "%s_size" % vulkanType.paramName 510 511 if self.direction == "read": 512 castedAccessExpr = "(%s)(%s)" % ("void*", access) 513 else: 514 castedAccessExpr = access 515 516 sTypeAccess = self.exprAccessor(sTypeParam) 517 self.cgen.beginIf("%s == VK_STRUCTURE_TYPE_MAX_ENUM" % 518 self.rootTypeVarName) 519 self.cgen.stmt("%s = %s" % (self.rootTypeVarName, sTypeAccess)) 520 self.cgen.endIf() 521 522 if self.direction == "read" and self.dynAlloc: 523 self.cgen.stmt("size_t %s" % sizeVar) 524 self.cgen.stmt("%s = %s->getBe32()" % \ 525 (sizeVar, self.streamVarName)) 526 self.cgen.stmt("%s = nullptr" % access) 527 self.cgen.beginIf(sizeVar) 528 self.cgen.stmt( \ 529 "%s->alloc((void**)&%s, sizeof(VkStructureType))" % 530 (self.streamVarName, access)) 531 532 self.genStreamCall(vulkanType, access, "sizeof(VkStructureType)") 533 self.cgen.stmt("VkStructureType extType = *(VkStructureType*)(%s)" % access) 534 self.cgen.stmt( \ 535 "%s->alloc((void**)&%s, %s(%s->getFeatureBits(), %s, %s))" % 536 (self.streamVarName, access, EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME, self.streamVarName, self.rootTypeVarName, access)) 537 self.cgen.stmt("*(VkStructureType*)%s = extType" % access) 538 539 self.cgen.funcCall(None, self.marshalPrefix + "extension_struct", 540 [self.streamVarName, self.rootTypeVarName, castedAccessExpr]) 541 self.cgen.endIf() 542 else: 543 544 self.cgen.funcCall(None, self.marshalPrefix + "extension_struct", 545 [self.streamVarName, self.rootTypeVarName, castedAccessExpr]) 546 547 548 def onPointer(self, vulkanType): 549 access = self.exprAccessor(vulkanType) 550 551 lenAccess = self.lenAccessor(vulkanType) 552 lenAccessGuard = self.lenAccessorGuard(vulkanType) 553 554 self.beginFilterGuard(vulkanType) 555 self.doAllocSpace(vulkanType) 556 557 if vulkanType.filterVar != None: 558 print("onPointer Needs filter: %s filterVar %s" % (access, vulkanType.filterVar)) 559 560 if vulkanType.isHandleType() and self.mapHandles: 561 self.genHandleMappingCall(vulkanType, access, lenAccess) 562 else: 563 if self.typeInfo.isNonAbiPortableType(vulkanType.typeName): 564 if lenAccess is not None: 565 if lenAccessGuard is not None: 566 self.cgen.beginIf(lenAccessGuard) 567 self.cgen.beginFor("uint32_t i = 0", "i < (uint32_t)%s" % lenAccess, "++i") 568 self.genPrimitiveStreamCall(vulkanType.getForValueAccess(), "%s[i]" % access) 569 self.cgen.endFor() 570 if lenAccessGuard is not None: 571 self.cgen.endIf() 572 else: 573 self.genPrimitiveStreamCall(vulkanType.getForValueAccess(), "(*%s)" % access) 574 else: 575 if lenAccess is not None: 576 finalLenExpr = "%s * %s" % ( 577 lenAccess, self.cgen.sizeofExpr(vulkanType.getForValueAccess())) 578 else: 579 finalLenExpr = "%s" % ( 580 self.cgen.sizeofExpr(vulkanType.getForValueAccess())) 581 self.genStreamCall(vulkanType, access, finalLenExpr) 582 583 if self.direction == "read": 584 self.endFilterGuard(vulkanType, "%s = 0" % access) 585 else: 586 self.endFilterGuard(vulkanType) 587 588 def onValue(self, vulkanType): 589 self.beginFilterGuard(vulkanType) 590 591 if vulkanType.isHandleType() and self.mapHandles: 592 access = self.exprAccessor(vulkanType) 593 if vulkanType.filterVar != None: 594 print("onValue Needs filter: %s filterVar %s" % (access, vulkanType.filterVar)) 595 self.genHandleMappingCall( 596 vulkanType.getForAddressAccess(), access, "1") 597 elif self.typeInfo.isNonAbiPortableType(vulkanType.typeName): 598 access = self.exprPrimitiveValueAccessor(vulkanType) 599 self.genPrimitiveStreamCall(vulkanType, access) 600 else: 601 access = self.exprAccessor(vulkanType) 602 self.genStreamCall(vulkanType, access, self.cgen.sizeofExpr(vulkanType)) 603 604 self.endFilterGuard(vulkanType) 605 606 def streamLetParameter(self, structInfo, letParamInfo): 607 filterFeature = "%s->getFeatureBits() & VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT" % self.streamVarName 608 self.cgen.stmt("%s %s = 1" % (letParamInfo.typeName, letParamInfo.paramName)) 609 610 self.cgen.beginIf(filterFeature) 611 612 if self.direction == "write": 613 bodyExpr = self.currentStructInfo.environment[letParamInfo.paramName]["body"] 614 self.cgen.stmt("%s = %s" % (letParamInfo.paramName, self.genFilterFunc(bodyExpr, self.currentStructInfo.environment))) 615 616 self.genPrimitiveStreamCall(letParamInfo, letParamInfo.paramName) 617 618 self.cgen.endIf() 619 620 621class VulkanMarshaling(VulkanWrapperGenerator): 622 623 def __init__(self, module, typeInfo, variant="host"): 624 VulkanWrapperGenerator.__init__(self, module, typeInfo) 625 626 self.cgenHeader = CodeGen() 627 self.cgenImpl = CodeGen() 628 629 self.variant = variant 630 631 self.currentFeature = None 632 self.apiOpcodes = {} 633 self.dynAlloc = self.variant != "guest" 634 635 if self.variant == "guest": 636 self.marshalingParams = PARAMETERS_MARSHALING_GUEST 637 else: 638 self.marshalingParams = PARAMETERS_MARSHALING 639 640 self.writeCodegen = \ 641 VulkanMarshalingCodegen( 642 None, 643 VULKAN_STREAM_VAR_NAME, 644 ROOT_TYPE_VAR_NAME, 645 MARSHAL_INPUT_VAR_NAME, 646 API_PREFIX_MARSHAL, 647 direction = "write") 648 649 self.readCodegen = \ 650 VulkanMarshalingCodegen( 651 None, 652 VULKAN_STREAM_VAR_NAME, 653 ROOT_TYPE_VAR_NAME, 654 UNMARSHAL_INPUT_VAR_NAME, 655 API_PREFIX_UNMARSHAL, 656 direction = "read", 657 dynAlloc=self.dynAlloc) 658 659 self.knownDefs = {} 660 661 # Begin Vulkan API opcodes from something high 662 # that is not going to interfere with renderControl 663 # opcodes 664 self.beginOpcodeOld = 20000 665 self.endOpcodeOld = 30000 666 667 self.beginOpcode = 200000000 668 self.endOpcode = 300000000 669 self.knownOpcodes = set() 670 671 self.extensionMarshalPrototype = \ 672 VulkanAPI(API_PREFIX_MARSHAL + "extension_struct", 673 STREAM_RET_TYPE, 674 self.marshalingParams + 675 [STRUCT_EXTENSION_PARAM]) 676 677 self.extensionUnmarshalPrototype = \ 678 VulkanAPI(API_PREFIX_UNMARSHAL + "extension_struct", 679 STREAM_RET_TYPE, 680 self.marshalingParams + 681 [STRUCT_EXTENSION_PARAM_FOR_WRITE]) 682 683 def onBegin(self,): 684 VulkanWrapperGenerator.onBegin(self) 685 self.module.appendImpl(self.cgenImpl.makeFuncDecl(self.extensionMarshalPrototype)) 686 self.module.appendImpl(self.cgenImpl.makeFuncDecl(self.extensionUnmarshalPrototype)) 687 688 def onBeginFeature(self, featureName, featureType): 689 VulkanWrapperGenerator.onBeginFeature(self, featureName, featureType) 690 self.currentFeature = featureName 691 692 def onGenType(self, typeXml, name, alias): 693 VulkanWrapperGenerator.onGenType(self, typeXml, name, alias) 694 695 if name in self.knownDefs: 696 return 697 698 category = self.typeInfo.categoryOf(name) 699 700 if category in ["struct", "union"] and alias: 701 self.module.appendHeader( 702 self.cgenHeader.makeFuncAlias(API_PREFIX_MARSHAL + name, 703 API_PREFIX_MARSHAL + alias)) 704 self.module.appendHeader( 705 self.cgenHeader.makeFuncAlias(API_PREFIX_UNMARSHAL + name, 706 API_PREFIX_UNMARSHAL + alias)) 707 708 if category in ["struct", "union"] and not alias: 709 710 structInfo = self.typeInfo.structs[name] 711 712 marshalParams = self.marshalingParams + \ 713 [makeVulkanTypeSimple(True, name, 1, MARSHAL_INPUT_VAR_NAME)] 714 715 freeParams = [] 716 letParams = [] 717 718 for (envname, bindingInfo) in list(sorted(structInfo.environment.items(), key = lambda kv: kv[0])): 719 if None == bindingInfo["binding"]: 720 freeParams.append(makeVulkanTypeSimple(True, bindingInfo["type"], 0, envname)) 721 else: 722 if not bindingInfo["structmember"]: 723 letParams.append(makeVulkanTypeSimple(True, bindingInfo["type"], 0, envname)) 724 725 marshalPrototype = \ 726 VulkanAPI(API_PREFIX_MARSHAL + name, 727 STREAM_RET_TYPE, 728 marshalParams + freeParams) 729 730 marshalPrototypeNoFilter = \ 731 VulkanAPI(API_PREFIX_MARSHAL + name, 732 STREAM_RET_TYPE, 733 marshalParams) 734 735 def structMarshalingCustom(cgen): 736 self.writeCodegen.cgen = cgen 737 self.writeCodegen.currentStructInfo = structInfo 738 self.writeCodegen.cgen.stmt("(void)%s" % ROOT_TYPE_VAR_NAME) 739 740 marshalingCode = \ 741 CUSTOM_MARSHAL_TYPES[name]["common"] + \ 742 CUSTOM_MARSHAL_TYPES[name]["marshaling"].format( 743 streamVarName=self.writeCodegen.streamVarName, 744 rootTypeVarName=self.writeCodegen.rootTypeVarName, 745 inputVarName=self.writeCodegen.inputVarName, 746 newInputVarName=self.writeCodegen.inputVarName + "_new") 747 for line in marshalingCode.split('\n'): 748 cgen.line(line) 749 750 def structMarshalingDef(cgen): 751 self.writeCodegen.cgen = cgen 752 self.writeCodegen.currentStructInfo = structInfo 753 self.writeCodegen.cgen.stmt("(void)%s" % ROOT_TYPE_VAR_NAME) 754 755 if category == "struct": 756 # marshal 'let' parameters first 757 for letp in letParams: 758 self.writeCodegen.streamLetParameter(self.typeInfo, letp) 759 760 for member in structInfo.members: 761 iterateVulkanType(self.typeInfo, member, self.writeCodegen) 762 if category == "union": 763 iterateVulkanType(self.typeInfo, structInfo.members[0], self.writeCodegen) 764 765 def structMarshalingDefNoFilter(cgen): 766 self.writeCodegen.cgen = cgen 767 self.writeCodegen.currentStructInfo = structInfo 768 self.writeCodegen.doFiltering = False 769 self.writeCodegen.cgen.stmt("(void)%s" % ROOT_TYPE_VAR_NAME) 770 771 if category == "struct": 772 # marshal 'let' parameters first 773 for letp in letParams: 774 self.writeCodegen.streamLetParameter(self.typeInfo, letp) 775 776 for member in structInfo.members: 777 iterateVulkanType(self.typeInfo, member, self.writeCodegen) 778 if category == "union": 779 iterateVulkanType(self.typeInfo, structInfo.members[0], self.writeCodegen) 780 self.writeCodegen.doFiltering = True 781 782 self.module.appendHeader( 783 self.cgenHeader.makeFuncDecl(marshalPrototype)) 784 785 if name in CUSTOM_MARSHAL_TYPES: 786 self.module.appendImpl( 787 self.cgenImpl.makeFuncImpl( 788 marshalPrototype, structMarshalingCustom)) 789 else: 790 self.module.appendImpl( 791 self.cgenImpl.makeFuncImpl( 792 marshalPrototype, structMarshalingDef)) 793 794 if freeParams != []: 795 self.module.appendHeader( 796 self.cgenHeader.makeFuncDecl(marshalPrototypeNoFilter)) 797 self.module.appendImpl( 798 self.cgenImpl.makeFuncImpl( 799 marshalPrototypeNoFilter, structMarshalingDefNoFilter)) 800 801 unmarshalPrototype = \ 802 VulkanAPI(API_PREFIX_UNMARSHAL + name, 803 STREAM_RET_TYPE, 804 self.marshalingParams + [makeVulkanTypeSimple(False, name, 1, UNMARSHAL_INPUT_VAR_NAME)] + freeParams) 805 806 unmarshalPrototypeNoFilter = \ 807 VulkanAPI(API_PREFIX_UNMARSHAL + name, 808 STREAM_RET_TYPE, 809 self.marshalingParams + [makeVulkanTypeSimple(False, name, 1, UNMARSHAL_INPUT_VAR_NAME)]) 810 811 def structUnmarshalingCustom(cgen): 812 self.readCodegen.cgen = cgen 813 self.readCodegen.currentStructInfo = structInfo 814 self.writeCodegen.cgen.stmt("(void)%s" % ROOT_TYPE_VAR_NAME) 815 816 unmarshalingCode = \ 817 CUSTOM_MARSHAL_TYPES[name]["common"] + \ 818 CUSTOM_MARSHAL_TYPES[name]["unmarshaling"].format( 819 streamVarName=self.readCodegen.streamVarName, 820 rootTypeVarName=self.readCodegen.rootTypeVarName, 821 inputVarName=self.readCodegen.inputVarName, 822 newInputVarName=self.readCodegen.inputVarName + "_new") 823 for line in unmarshalingCode.split('\n'): 824 cgen.line(line) 825 826 def structUnmarshalingDef(cgen): 827 self.readCodegen.cgen = cgen 828 self.readCodegen.currentStructInfo = structInfo 829 self.writeCodegen.cgen.stmt("(void)%s" % ROOT_TYPE_VAR_NAME) 830 831 if category == "struct": 832 # unmarshal 'let' parameters first 833 for letp in letParams: 834 self.readCodegen.streamLetParameter(self.typeInfo, letp) 835 836 for member in structInfo.members: 837 iterateVulkanType(self.typeInfo, member, self.readCodegen) 838 if category == "union": 839 iterateVulkanType(self.typeInfo, structInfo.members[0], self.readCodegen) 840 841 def structUnmarshalingDefNoFilter(cgen): 842 self.readCodegen.cgen = cgen 843 self.readCodegen.currentStructInfo = structInfo 844 self.readCodegen.doFiltering = False 845 self.writeCodegen.cgen.stmt("(void)%s" % ROOT_TYPE_VAR_NAME) 846 847 if category == "struct": 848 # unmarshal 'let' parameters first 849 for letp in letParams: 850 iterateVulkanType(self.typeInfo, letp, self.readCodegen) 851 for member in structInfo.members: 852 iterateVulkanType(self.typeInfo, member, self.readCodegen) 853 if category == "union": 854 iterateVulkanType(self.typeInfo, structInfo.members[0], self.readCodegen) 855 self.readCodegen.doFiltering = True 856 857 self.module.appendHeader( 858 self.cgenHeader.makeFuncDecl(unmarshalPrototype)) 859 860 if name in CUSTOM_MARSHAL_TYPES: 861 self.module.appendImpl( 862 self.cgenImpl.makeFuncImpl( 863 unmarshalPrototype, structUnmarshalingCustom)) 864 else: 865 self.module.appendImpl( 866 self.cgenImpl.makeFuncImpl( 867 unmarshalPrototype, structUnmarshalingDef)) 868 869 if freeParams != []: 870 self.module.appendHeader( 871 self.cgenHeader.makeFuncDecl(unmarshalPrototypeNoFilter)) 872 self.module.appendImpl( 873 self.cgenImpl.makeFuncImpl( 874 unmarshalPrototypeNoFilter, structUnmarshalingDefNoFilter)) 875 876 def onGenCmd(self, cmdinfo, name, alias): 877 VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias) 878 if name in KNOWN_FUNCTION_OPCODES: 879 opcode = KNOWN_FUNCTION_OPCODES[name] 880 else: 881 hashCode = hashlib.sha256(name.encode()).hexdigest()[:8] 882 hashInt = int(hashCode, 16) 883 opcode = self.beginOpcode + hashInt % (self.endOpcode - self.beginOpcode) 884 hasHashCollision = False 885 while opcode in self.knownOpcodes: 886 hasHashCollision = True 887 opcode += 1 888 if hasHashCollision: 889 print("Hash collision occurred on function '{}'. " 890 "Please add the following line to marshalingdefs.py:".format(name), file=sys.stderr) 891 print("----------------------", file=sys.stderr) 892 print(" \"{}\": {},".format(name, opcode), file=sys.stderr) 893 print("----------------------", file=sys.stderr) 894 895 self.module.appendHeader( 896 "#define OP_%s %d\n" % (name, opcode)) 897 self.apiOpcodes[name] = (opcode, self.currentFeature) 898 self.knownOpcodes.add(opcode) 899 900 def doExtensionStructMarshalingCodegen(self, cgen, retType, extParam, forEach, funcproto, direction): 901 accessVar = "structAccess" 902 sizeVar = "currExtSize" 903 cgen.stmt("VkInstanceCreateInfo* %s = (VkInstanceCreateInfo*)(%s)" % (accessVar, extParam.paramName)) 904 cgen.stmt("size_t %s = %s(%s->getFeatureBits(), %s, %s)" % (sizeVar, 905 EXTENSION_SIZE_WITH_STREAM_FEATURES_API_NAME, VULKAN_STREAM_VAR_NAME, ROOT_TYPE_VAR_NAME, extParam.paramName)) 906 907 cgen.beginIf("!%s && %s" % (sizeVar, extParam.paramName)) 908 909 cgen.line("// unknown struct extension; skip and call on its pNext field"); 910 cgen.funcCall(None, funcproto.name, [ 911 "vkStream", ROOT_TYPE_VAR_NAME, "(void*)%s->pNext" % accessVar]) 912 cgen.stmt("return") 913 914 cgen.endIf() 915 cgen.beginElse() 916 917 cgen.line("// known or null extension struct") 918 919 if direction == "write": 920 cgen.stmt("vkStream->putBe32(%s)" % sizeVar) 921 elif not self.dynAlloc: 922 cgen.stmt("vkStream->getBe32()"); 923 924 cgen.beginIf("!%s" % (sizeVar)) 925 cgen.line("// exit if this was a null extension struct (size == 0 in this branch)") 926 cgen.stmt("return") 927 cgen.endIf() 928 929 cgen.endIf() 930 931 # Now we can do stream stuff 932 if direction == "write": 933 cgen.stmt("vkStream->write(%s, sizeof(VkStructureType))" % extParam.paramName) 934 elif not self.dynAlloc: 935 cgen.stmt("uint64_t pNext_placeholder") 936 placeholderAccess = "(&pNext_placeholder)" 937 cgen.stmt("vkStream->read((void*)(&pNext_placeholder), sizeof(VkStructureType))") 938 cgen.stmt("(void)pNext_placeholder") 939 940 def fatalDefault(cgen): 941 cgen.line("// fatal; the switch is only taken if the extension struct is known"); 942 cgen.stmt("abort()") 943 pass 944 945 self.emitForEachStructExtension( 946 cgen, 947 retType, 948 extParam, 949 forEach, 950 defaultEmit=fatalDefault, 951 rootTypeVar=ROOT_TYPE_PARAM) 952 953 def onEnd(self,): 954 VulkanWrapperGenerator.onEnd(self) 955 956 def forEachExtensionMarshal(ext, castedAccess, cgen): 957 cgen.funcCall(None, API_PREFIX_MARSHAL + ext.name, 958 [VULKAN_STREAM_VAR_NAME, ROOT_TYPE_VAR_NAME, castedAccess]) 959 960 def forEachExtensionUnmarshal(ext, castedAccess, cgen): 961 cgen.funcCall(None, API_PREFIX_UNMARSHAL + ext.name, 962 [VULKAN_STREAM_VAR_NAME, ROOT_TYPE_VAR_NAME, castedAccess]) 963 964 self.module.appendImpl( 965 self.cgenImpl.makeFuncImpl( 966 self.extensionMarshalPrototype, 967 lambda cgen: self.doExtensionStructMarshalingCodegen( 968 cgen, 969 STREAM_RET_TYPE, 970 STRUCT_EXTENSION_PARAM, 971 forEachExtensionMarshal, 972 self.extensionMarshalPrototype, 973 "write"))) 974 975 self.module.appendImpl( 976 self.cgenImpl.makeFuncImpl( 977 self.extensionUnmarshalPrototype, 978 lambda cgen: self.doExtensionStructMarshalingCodegen( 979 cgen, 980 STREAM_RET_TYPE, 981 STRUCT_EXTENSION_PARAM_FOR_WRITE, 982 forEachExtensionUnmarshal, 983 self.extensionUnmarshalPrototype, 984 "read"))) 985 986 opcode2stringPrototype = \ 987 VulkanAPI("api_opcode_to_string", 988 makeVulkanTypeSimple(True, "char", 1, "none"), 989 [ makeVulkanTypeSimple(True, "uint32_t", 0, "opcode") ]) 990 991 self.module.appendHeader( 992 self.cgenHeader.makeFuncDecl(opcode2stringPrototype)) 993 994 def emitOpcode2StringImpl(apiOpcodes, cgen): 995 cgen.line("switch(opcode)") 996 cgen.beginBlock() 997 998 currFeature = None 999 1000 for (name, (opcodeNum, feature)) in sorted(apiOpcodes.items(), key = lambda x : x[1][0]): 1001 if not currFeature: 1002 cgen.leftline("#ifdef %s" % feature) 1003 currFeature = feature 1004 1005 if currFeature and feature != currFeature: 1006 cgen.leftline("#endif") 1007 cgen.leftline("#ifdef %s" % feature) 1008 currFeature = feature 1009 1010 cgen.line("case OP_%s:" % name) 1011 cgen.beginBlock() 1012 cgen.stmt("return \"OP_%s\"" % name) 1013 cgen.endBlock() 1014 1015 if currFeature: 1016 cgen.leftline("#endif") 1017 1018 cgen.line("default:") 1019 cgen.beginBlock() 1020 cgen.stmt("return \"OP_UNKNOWN_API_CALL\"") 1021 cgen.endBlock() 1022 1023 cgen.endBlock() 1024 1025 self.module.appendImpl( 1026 self.cgenImpl.makeFuncImpl( 1027 opcode2stringPrototype, 1028 lambda cgen: emitOpcode2StringImpl(self.apiOpcodes, cgen))) 1029 1030 self.module.appendHeader( 1031 "#define OP_vkFirst_old %d\n" % (self.beginOpcodeOld)) 1032 self.module.appendHeader( 1033 "#define OP_vkLast_old %d\n" % (self.endOpcodeOld)) 1034 self.module.appendHeader( 1035 "#define OP_vkFirst %d\n" % (self.beginOpcode)) 1036 self.module.appendHeader( 1037 "#define OP_vkLast %d\n" % (self.endOpcode)) 1038