• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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