• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from .common.codegen import CodeGen, VulkanWrapperGenerator, VulkanAPIWrapper
2from .common.vulkantypes import \
3    VulkanAPI, makeVulkanTypeSimple, iterateVulkanType, DISPATCHABLE_HANDLE_TYPES, NON_DISPATCHABLE_HANDLE_TYPES
4
5from .reservedmarshaling import VulkanReservedMarshalingCodegen
6from .transform import TransformCodegen, genTransformsForVulkanType
7
8from .wrapperdefs import API_PREFIX_MARSHAL
9from .wrapperdefs import API_PREFIX_UNMARSHAL, API_PREFIX_RESERVEDUNMARSHAL
10from .wrapperdefs import ROOT_TYPE_DEFAULT_VALUE
11from .wrapperdefs import VULKAN_STREAM_TYPE
12
13from copy import copy
14
15decoder_decl_preamble = """
16"""
17
18decoder_impl_preamble = """
19"""
20
21READ_STREAM = "readStream"
22WRITE_STREAM = "vkStream"
23
24# Driver workarounds for APIs that don't work well multithreaded
25driver_workarounds_global_lock_apis = [
26    "vkCreatePipelineLayout",
27    "vkDestroyPipelineLayout",
28]
29
30MAX_STACK_ITEMS = "16"
31
32
33def emit_param_decl_for_reading(param, cgen):
34    if param.staticArrExpr:
35        cgen.stmt(
36            cgen.makeRichCTypeDecl(param.getForNonConstAccess()))
37    else:
38        cgen.stmt(
39            cgen.makeRichCTypeDecl(param))
40
41    if param.pointerIndirectionLevels > 0:
42        lenAccess = cgen.generalLengthAccess(param)
43        if not lenAccess:
44            lenAccess = "1"
45        arrSize = "1" if "1" == lenAccess else "MAX_STACK_ITEMS"
46
47        typeHere = "uint8_t*" if "void" == param.typeName else param.typeName
48        cgen.stmt("%s%s stack_%s[%s]" % (
49            typeHere, "*" * (param.pointerIndirectionLevels - 1), param.paramName, arrSize))
50
51
52def emit_unmarshal(typeInfo, param, cgen, output=False, destroy=False, noUnbox=False):
53    if destroy:
54        iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen(
55            cgen,
56            READ_STREAM,
57            ROOT_TYPE_DEFAULT_VALUE,
58            param.paramName,
59            "readStreamPtrPtr",
60            API_PREFIX_RESERVEDUNMARSHAL,
61            "",
62            direction="read",
63            dynAlloc=True))
64        lenAccess = cgen.generalLengthAccess(param)
65        lenAccessGuard = cgen.generalLengthAccessGuard(param)
66        if None == lenAccess or "1" == lenAccess:
67            cgen.stmt("boxed_%s_preserve = %s" %
68                      (param.paramName, param.paramName))
69            cgen.stmt("%s = unbox_%s(%s)" %
70                      (param.paramName, param.typeName, param.paramName))
71        else:
72            if lenAccessGuard is not None:
73                self.cgen.beginIf(lenAccessGuard)
74            cgen.beginFor("uint32_t i = 0", "i < %s" % lenAccess, "++i")
75            cgen.stmt("boxed_%s_preserve[i] = %s[i]" %
76                      (param.paramName, param.paramName))
77            cgen.stmt("((%s*)(%s))[i] = unbox_%s(%s[i])" % (param.typeName,
78                                                            param.paramName, param.typeName, param.paramName))
79            cgen.endFor()
80            if lenAccessGuard is not None:
81                self.cgen.endIf()
82    else:
83        if noUnbox:
84            cgen.line("// No unbox for %s" % (param.paramName))
85
86        lenAccess = cgen.generalLengthAccess(param)
87        if not lenAccess:
88            lenAccess = "1"
89        arrSize = "1" if "1" == lenAccess else "MAX_STACK_ITEMS"
90
91        iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen(
92            cgen,
93            READ_STREAM,
94            ROOT_TYPE_DEFAULT_VALUE,
95            param.paramName,
96            "readStreamPtrPtr",
97            API_PREFIX_RESERVEDUNMARSHAL,
98            "" if (output or noUnbox) else "unbox_",
99            direction="read",
100            dynAlloc=True,
101            stackVar="stack_%s" % param.paramName,
102            stackArrSize=arrSize))
103
104
105def emit_dispatch_unmarshal(typeInfo, param, cgen, globalWrapped):
106    if globalWrapped:
107        cgen.stmt(
108            "// Begin global wrapped dispatchable handle unboxing for %s" % param.paramName)
109        iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen(
110            cgen,
111            READ_STREAM,
112            ROOT_TYPE_DEFAULT_VALUE,
113            param.paramName,
114            "readStreamPtrPtr",
115            API_PREFIX_RESERVEDUNMARSHAL,
116            "",
117            direction="read",
118            dynAlloc=True))
119    else:
120        cgen.stmt(
121            "// Begin non wrapped dispatchable handle unboxing for %s" % param.paramName)
122        # cgen.stmt("%s->unsetHandleMapping()" % READ_STREAM)
123        iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen(
124            cgen,
125            READ_STREAM,
126            ROOT_TYPE_DEFAULT_VALUE,
127            param.paramName,
128            "readStreamPtrPtr",
129            API_PREFIX_RESERVEDUNMARSHAL,
130            "",
131            direction="read",
132            dynAlloc=True))
133        cgen.stmt("auto unboxed_%s = unbox_%s(%s)" %
134                  (param.paramName, param.typeName, param.paramName))
135        cgen.stmt("auto vk = dispatch_%s(%s)" %
136                  (param.typeName, param.paramName))
137        cgen.stmt("// End manual dispatchable handle unboxing for %s" %
138                  param.paramName)
139
140
141def emit_transform(typeInfo, param, cgen, variant="tohost"):
142    res = \
143        iterateVulkanType(typeInfo, param, TransformCodegen(
144            cgen, param.paramName, "globalstate", "transform_%s_" % variant, variant))
145    if not res:
146        cgen.stmt("(void)%s" % param.paramName)
147
148# Everything here elides the initial arg
149
150
151class DecodingParameters(object):
152    def __init__(self, api):
153        self.params = []
154        self.toRead = []
155        self.toWrite = []
156
157        i = 0
158
159        for param in api.parameters[1:]:
160            param.nonDispatchableHandleCreate = False
161            param.nonDispatchableHandleDestroy = False
162            param.dispatchHandle = False
163            param.dispatchableHandleCreate = False
164            param.dispatchableHandleDestroy = False
165
166            if i == 0 and param.isDispatchableHandleType():
167                param.dispatchHandle = True
168
169            if param.isNonDispatchableHandleType() and param.isCreatedBy(api):
170                param.nonDispatchableHandleCreate = True
171
172            if param.isNonDispatchableHandleType() and param.isDestroyedBy(api):
173                param.nonDispatchableHandleDestroy = True
174
175            if param.isDispatchableHandleType() and param.isCreatedBy(api):
176                param.dispatchableHandleCreate = True
177
178            if param.isDispatchableHandleType() and param.isDestroyedBy(api):
179                param.dispatchableHandleDestroy = True
180
181            self.toRead.append(param)
182
183            if param.possiblyOutput():
184                self.toWrite.append(param)
185
186            self.params.append(param)
187
188            i += 1
189
190
191def emit_call_log(api, cgen):
192    decodingParams = DecodingParameters(api)
193    paramsToRead = decodingParams.toRead
194
195    # cgen.beginIf("m_logCalls")
196    paramLogFormat = "%p"
197    paramLogArgs = ["(void*)boxed_dispatchHandle"]
198
199    for p in paramsToRead:
200        paramLogFormat += "0x%llx "
201    for p in paramsToRead:
202        paramLogArgs.append("(unsigned long long)%s" % (p.paramName))
203    # cgen.stmt("fprintf(stderr, \"substream %%p: call %s %s\\n\", readStream, %s)" % (api.name, paramLogFormat, ", ".join(paramLogArgs)))
204    # cgen.endIf()
205
206
207def emit_decode_parameters(typeInfo, api, cgen, globalWrapped=False):
208
209    decodingParams = DecodingParameters(api)
210
211    paramsToRead = decodingParams.toRead
212
213    for p in paramsToRead:
214        emit_param_decl_for_reading(p, cgen)
215
216    i = 0
217    for p in paramsToRead:
218        lenAccess = cgen.generalLengthAccess(p)
219
220        if p.dispatchHandle:
221            emit_dispatch_unmarshal(typeInfo, p, cgen, globalWrapped)
222        else:
223            destroy = p.nonDispatchableHandleDestroy or p.dispatchableHandleDestroy
224            noUnbox = False
225
226            if p.nonDispatchableHandleDestroy or p.dispatchableHandleDestroy:
227                destroy = True
228                cgen.stmt(
229                    "// Begin manual non dispatchable handle destroy unboxing for %s" % p.paramName)
230                if None == lenAccess or "1" == lenAccess:
231                    cgen.stmt("%s boxed_%s_preserve" %
232                              (p.typeName, p.paramName))
233                else:
234                    cgen.stmt("%s* boxed_%s_preserve; %s->alloc((void**)&boxed_%s_preserve, %s * sizeof(%s))" %
235                              (p.typeName, p.paramName, READ_STREAM, p.paramName, lenAccess, p.typeName))
236
237            if p.possiblyOutput():
238                cgen.stmt(
239                    "// Begin manual dispatchable handle unboxing for %s" % p.paramName)
240                cgen.stmt("%s->unsetHandleMapping()" % READ_STREAM)
241
242            emit_unmarshal(typeInfo, p, cgen, output=p.possiblyOutput(
243            ), destroy=destroy, noUnbox=noUnbox)
244        i += 1
245
246    for p in paramsToRead:
247        emit_transform(typeInfo, p, cgen, variant="tohost")
248
249    emit_call_log(api, cgen)
250
251
252def emit_dispatch_call(api, cgen):
253
254    decodingParams = DecodingParameters(api)
255
256    customParams = ["(VkCommandBuffer)dispatchHandle"]
257
258    for (i, p) in enumerate(api.parameters[1:]):
259        customParam = p.paramName
260        if decodingParams.params[i].dispatchHandle:
261            customParam = "unboxed_%s" % p.paramName
262        customParams.append(customParam)
263
264    if api.name in driver_workarounds_global_lock_apis:
265        cgen.stmt("lock()")
266
267    cgen.vkApiCall(api, customPrefix="vk->", customParameters=customParams)
268
269    if api.name in driver_workarounds_global_lock_apis:
270        cgen.stmt("unlock()")
271
272
273def emit_global_state_wrapped_call(api, cgen):
274    customParams = ["pool", "(VkCommandBuffer)(boxed_dispatchHandle)"] + \
275        list(map(lambda p: p.paramName, api.parameters[1:]))
276    cgen.vkApiCall(api, customPrefix="this->on_",
277                   customParameters=customParams)
278
279
280def emit_default_decoding(typeInfo, api, cgen):
281    emit_decode_parameters(typeInfo, api, cgen)
282    emit_dispatch_call(api, cgen)
283
284
285def emit_global_state_wrapped_decoding(typeInfo, api, cgen):
286    emit_decode_parameters(typeInfo, api, cgen, globalWrapped=True)
287    emit_global_state_wrapped_call(api, cgen)
288
289
290custom_decodes = {
291    "vkCmdCopyBufferToImage": emit_global_state_wrapped_decoding,
292    "vkCmdCopyImage": emit_global_state_wrapped_decoding,
293    "vkCmdCopyImageToBuffer": emit_global_state_wrapped_decoding,
294    "vkCmdExecuteCommands": emit_global_state_wrapped_decoding,
295    "vkBeginCommandBuffer": emit_global_state_wrapped_decoding,
296    "vkResetCommandBuffer": emit_global_state_wrapped_decoding,
297    "vkCmdPipelineBarrier": emit_global_state_wrapped_decoding,
298    "vkCmdBindPipeline": emit_global_state_wrapped_decoding,
299    "vkCmdBindDescriptorSets": emit_global_state_wrapped_decoding,
300    "vkBeginCommandBufferAsyncGOOGLE": emit_global_state_wrapped_decoding,
301    "vkEndCommandBufferAsyncGOOGLE": emit_global_state_wrapped_decoding,
302    "vkResetCommandBufferAsyncGOOGLE": emit_global_state_wrapped_decoding,
303    "vkCommandBufferHostSyncGOOGLE": emit_global_state_wrapped_decoding,
304}
305
306
307class VulkanSubDecoder(VulkanWrapperGenerator):
308    def __init__(self, module, typeInfo):
309        VulkanWrapperGenerator.__init__(self, module, typeInfo)
310        self.typeInfo = typeInfo
311        self.cgen = CodeGen()
312
313    def onBegin(self,):
314        self.module.appendImpl(
315            "#define MAX_STACK_ITEMS %s\n" % MAX_STACK_ITEMS)
316
317        self.module.appendImpl(
318            "size_t subDecode(VulkanMemReadingStream* readStream, VulkanDispatch* vk, void* boxed_dispatchHandle, void* dispatchHandle, VkDeviceSize dataSize, const void* pData)\n")
319
320        self.cgen.beginBlock()  # function body
321
322        self.cgen.stmt("uint32_t count = 0")
323        self.cgen.stmt("unsigned char *buf = (unsigned char *)pData")
324        self.cgen.stmt("android::base::BumpPool* pool = readStream->pool()")
325        self.cgen.stmt("unsigned char *ptr = (unsigned char *)pData")
326        self.cgen.stmt(
327            "const unsigned char* const end = (const unsigned char*)buf + dataSize")
328        self.cgen.stmt(
329            "VkDecoderGlobalState* globalstate = VkDecoderGlobalState::get()")
330
331        self.cgen.line("while (end - ptr >= 8)")
332        self.cgen.beginBlock()  # while loop
333
334        self.cgen.stmt("uint32_t opcode = *(uint32_t *)ptr")
335        self.cgen.stmt("int32_t packetLen = *(int32_t *)(ptr + 4)")
336        self.cgen.stmt(
337            "if (end - ptr < packetLen) return ptr - (unsigned char*)buf")
338
339        self.cgen.stmt("%s->setBuf((uint8_t*)(ptr + 8))" % READ_STREAM)
340        self.cgen.stmt(
341            "uint8_t* readStreamPtr = %s->getBuf(); uint8_t** readStreamPtrPtr = &readStreamPtr" % READ_STREAM)
342        self.cgen.line("switch (opcode)")
343        self.cgen.beginBlock()  # switch stmt
344
345        self.module.appendImpl(self.cgen.swapCode())
346
347    def onGenCmd(self, cmdinfo, name, alias):
348        typeInfo = self.typeInfo
349        cgen = self.cgen
350        api = typeInfo.apis[name]
351
352        if "commandBuffer" != api.parameters[0].paramName:
353            return
354
355        cgen.line("case OP_%s:" % name)
356        cgen.beginBlock()
357        cgen.stmt("android::base::beginTrace(\"%s subdecode\")" % name)
358
359        if api.name in custom_decodes.keys():
360            custom_decodes[api.name](typeInfo, api, cgen)
361        else:
362            emit_default_decoding(typeInfo, api, cgen)
363
364        cgen.stmt("android::base::endTrace()")
365        cgen.stmt("break")
366        cgen.endBlock()
367        self.module.appendImpl(self.cgen.swapCode())
368
369    def onEnd(self,):
370        self.cgen.line("default:")
371        self.cgen.beginBlock()
372        self.cgen.stmt(
373            "fprintf(stderr, \"Fatal, unrecognized opcode %u\\n\", opcode)")
374        self.cgen.stmt("abort()")
375        self.cgen.stmt("return ptr - (unsigned char *)buf")
376        self.cgen.endBlock()
377
378        self.cgen.endBlock()  # switch stmt
379
380        self.cgen.stmt("++count; if (count % 1000 == 0) { pool->freeAll(); }")
381        self.cgen.stmt("ptr += packetLen")
382        self.cgen.endBlock()  # while loop
383
384        self.cgen.stmt("pool->freeAll()")
385        self.cgen.stmt("return ptr - (unsigned char*)buf;")
386        self.cgen.endBlock()  # function body
387        self.module.appendImpl(self.cgen.swapCode())
388