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 .common.codegen import CodeGen
17from .common.vulkantypes import \
18        VulkanAPI, makeVulkanTypeSimple, iterateVulkanType, VulkanTypeIterator
19
20from .wrapperdefs import VulkanWrapperGenerator
21from .wrapperdefs import STRUCT_EXTENSION_PARAM, STRUCT_EXTENSION_PARAM_FOR_WRITE
22
23class HandleMapCodegen(VulkanTypeIterator):
24    def __init__(self, cgen, inputVar, handlemapVarName, prefix, isHandleFunc):
25        self.cgen = cgen
26        self.inputVar = inputVar
27        self.prefix = prefix
28        self.handlemapVarName = handlemapVarName
29
30        def makeAccess(varName, asPtr = True):
31            return lambda t: self.cgen.generalAccess(t, parentVarName = varName, asPtr = asPtr)
32
33        def makeLengthAccess(varName):
34            return lambda t: self.cgen.generalLengthAccess(t, parentVarName = varName)
35
36        def makeLengthAccessGuard(varName):
37            return lambda t: self.cgen.generalLengthAccessGuard(t, parentVarName=varName)
38
39        self.exprAccessor = makeAccess(self.inputVar)
40        self.exprAccessorValue = makeAccess(self.inputVar, asPtr = False)
41        self.lenAccessor = makeLengthAccess(self.inputVar)
42        self.lenAccessorGuard = makeLengthAccessGuard(self.inputVar)
43
44        self.checked = False
45        self.isHandleFunc = isHandleFunc
46
47    def needSkip(self, vulkanType):
48        return False
49
50    def makeCastExpr(self, vulkanType):
51        return "(%s)" % (
52            self.cgen.makeCTypeDecl(vulkanType, useParamName=False))
53
54    def asNonConstCast(self, access, vulkanType):
55        if vulkanType.staticArrExpr:
56            casted = "%s(%s)" % (self.makeCastExpr(vulkanType.getForAddressAccess().getForNonConstAccess()), access)
57        elif vulkanType.accessibleAsPointer():
58            casted = "%s(%s)" % (self.makeCastExpr(vulkanType.getForNonConstAccess()), access)
59        else:
60            casted = "%s(%s)" % (self.makeCastExpr(vulkanType.getForAddressAccess().getForNonConstAccess()), access)
61        return casted
62
63    def onCheck(self, vulkanType):
64        pass
65
66    def endCheck(self, vulkanType):
67        pass
68
69    def onCompoundType(self, vulkanType):
70
71        if self.needSkip(vulkanType):
72            self.cgen.line("// TODO: Unsupported : %s" %
73                           self.cgen.makeCTypeDecl(vulkanType))
74            return
75        access = self.exprAccessor(vulkanType)
76        lenAccess = self.lenAccessor(vulkanType)
77        lenAccessGuard = self.lenAccessorGuard(vulkanType)
78
79        isPtr = vulkanType.pointerIndirectionLevels > 0
80
81        if lenAccessGuard is not None:
82            self.cgen.beginIf(lenAccessGuard)
83
84        if isPtr:
85            self.cgen.beginIf(access)
86
87        if lenAccess is not None:
88
89            loopVar = "i"
90            access = "%s + %s" % (access, loopVar)
91            forInit = "uint32_t %s = 0" % loopVar
92            forCond = "%s < (uint32_t)%s" % (loopVar, lenAccess)
93            forIncr = "++%s" % loopVar
94
95            self.cgen.beginFor(forInit, forCond, forIncr)
96
97        accessCasted = self.asNonConstCast(access, vulkanType)
98        self.cgen.funcCall(None, self.prefix + vulkanType.typeName,
99                           [self.handlemapVarName, accessCasted])
100
101        if lenAccess is not None:
102            self.cgen.endFor()
103
104        if isPtr:
105            self.cgen.endIf()
106
107        if lenAccessGuard is not None:
108            self.cgen.endIf()
109
110    def onString(self, vulkanType):
111        pass
112
113    def onStringArray(self, vulkanType):
114        pass
115
116    def onStaticArr(self, vulkanType):
117        if not self.isHandleFunc(vulkanType):
118            return
119
120        accessLhs = self.exprAccessor(vulkanType)
121        lenAccess = self.lenAccessor(vulkanType)
122
123        self.cgen.stmt("%s->mapHandles_%s(%s%s, %s)" % \
124            (self.handlemapVarName, vulkanType.typeName,
125             self.makeCastExpr(vulkanType.getForAddressAccess().getForNonConstAccess()),
126             accessLhs, lenAccess))
127
128    def onStructExtension(self, vulkanType):
129        access = self.exprAccessor(vulkanType)
130
131        castedAccessExpr = "(%s)(%s)" % ("void*", access)
132        self.cgen.beginIf(access)
133        self.cgen.funcCall(None, self.prefix + "extension_struct",
134                           [self.handlemapVarName, castedAccessExpr])
135        self.cgen.endIf()
136
137    def onPointer(self, vulkanType):
138        if self.needSkip(vulkanType):
139            return
140
141        if not self.isHandleFunc(vulkanType):
142            return
143
144        access = self.exprAccessor(vulkanType)
145        lenAccess = self.lenAccessor(vulkanType)
146        lenAccess = "1" if lenAccess is None else lenAccess
147
148        self.cgen.beginIf(access)
149
150        self.cgen.stmt( \
151            "%s->mapHandles_%s(%s%s, %s)" % \
152            (self.handlemapVarName,
153             vulkanType.typeName,
154             self.makeCastExpr(vulkanType.getForNonConstAccess()),
155             access,
156             lenAccess))
157
158        self.cgen.endIf()
159
160    def onValue(self, vulkanType):
161        if not self.isHandleFunc(vulkanType):
162            return
163        access = self.exprAccessor(vulkanType)
164        self.cgen.stmt(
165            "%s->mapHandles_%s(%s%s)" % \
166            (self.handlemapVarName, vulkanType.typeName,
167             self.makeCastExpr(vulkanType.getForAddressAccess().getForNonConstAccess()),
168             access))
169
170class VulkanHandleMap(VulkanWrapperGenerator):
171    def __init__(self, module, typeInfo):
172        VulkanWrapperGenerator.__init__(self, module, typeInfo)
173
174        self.codegen = CodeGen()
175
176        self.handlemapPrefix = "handlemap_"
177        self.toMapVar = "toMap"
178        self.handlemapVarName = "handlemap"
179        self.handlemapParam = \
180            makeVulkanTypeSimple(False, "VulkanHandleMapping", 1,
181                                 self.handlemapVarName)
182        self.voidType = makeVulkanTypeSimple(False, "void", 0)
183
184        self.handlemapCodegen = \
185            HandleMapCodegen(
186                None,
187                self.toMapVar,
188                self.handlemapVarName,
189                self.handlemapPrefix,
190                lambda vtype : typeInfo.isHandleType(vtype.typeName))
191
192        self.knownDefs = {}
193
194        self.extensionHandlemapPrototype = \
195            VulkanAPI(self.handlemapPrefix + "extension_struct",
196                      self.voidType,
197                      [self.handlemapParam, STRUCT_EXTENSION_PARAM_FOR_WRITE])
198
199    def onBegin(self,):
200        VulkanWrapperGenerator.onBegin(self)
201        self.module.appendImpl(self.codegen.makeFuncDecl(
202            self.extensionHandlemapPrototype))
203
204    def onGenType(self, typeXml, name, alias):
205        VulkanWrapperGenerator.onGenType(self, typeXml, name, alias)
206
207        if name in self.knownDefs:
208            return
209
210        category = self.typeInfo.categoryOf(name)
211
212        if category in ["struct", "union"] and alias:
213            self.module.appendHeader(
214                self.codegen.makeFuncAlias(self.handlemapPrefix + name,
215                                           self.handlemapPrefix + alias))
216
217        if category in ["struct", "union"] and not alias:
218
219            structInfo = self.typeInfo.structs[name]
220
221            typeFromName = \
222                lambda varname: \
223                    makeVulkanTypeSimple(varname == "from", name, 1, varname)
224
225            handlemapParams = \
226                [self.handlemapParam] + \
227                list(map(typeFromName, [self.toMapVar]))
228
229            handlemapPrototype = \
230                VulkanAPI(self.handlemapPrefix + name,
231                          self.voidType,
232                          handlemapParams)
233
234            def funcDefGenerator(cgen):
235                self.handlemapCodegen.cgen = cgen
236                for p in handlemapParams:
237                    cgen.stmt("(void)%s" % p.paramName)
238                for member in structInfo.members:
239                    iterateVulkanType(self.typeInfo, member,
240                                      self.handlemapCodegen)
241
242            self.module.appendHeader(
243                self.codegen.makeFuncDecl(handlemapPrototype))
244            self.module.appendImpl(
245                self.codegen.makeFuncImpl(handlemapPrototype, funcDefGenerator))
246
247    def onGenCmd(self, cmdinfo, name, alias):
248        VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
249
250    def onEnd(self,):
251        VulkanWrapperGenerator.onEnd(self)
252
253        def forEachExtensionHandlemap(ext, castedAccess, cgen):
254            cgen.funcCall(None, self.handlemapPrefix + ext.name,
255                          [self.handlemapVarName, castedAccess])
256
257        self.module.appendImpl(
258            self.codegen.makeFuncImpl(
259                self.extensionHandlemapPrototype,
260                lambda cgen: self.emitForEachStructExtension(
261                    cgen,
262                    self.voidType,
263                    STRUCT_EXTENSION_PARAM_FOR_WRITE,
264                    forEachExtensionHandlemap)))
265