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