• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from .common.codegen import CodeGen, VulkanWrapperGenerator
2from .common.vulkantypes import VulkanAPI, makeVulkanTypeSimple, iterateVulkanType, VulkanTypeInfo,\
3    VulkanType
4
5from .marshaling import VulkanMarshalingCodegen
6from .reservedmarshaling import VulkanReservedMarshalingCodegen
7from .transform import TransformCodegen
8
9from .wrapperdefs import API_PREFIX_MARSHAL
10from .wrapperdefs import API_PREFIX_RESERVEDUNMARSHAL
11from .wrapperdefs import MAX_PACKET_LENGTH
12from .wrapperdefs import VULKAN_STREAM_TYPE
13from .wrapperdefs import ROOT_TYPE_DEFAULT_VALUE
14from .wrapperdefs import RELAXED_APIS
15
16
17SKIPPED_DECODER_DELETES = [
18    "vkFreeDescriptorSets",
19]
20
21DELAYED_DECODER_DELETES = [
22    "vkDestroyPipelineLayout",
23]
24
25global_state_prefix = "m_state->on_"
26
27decoder_decl_preamble = """
28
29namespace gfxstream {
30class IOStream;
31}  // namespace gfxstream
32
33namespace gfxstream {
34namespace vk {
35
36class VkDecoder {
37public:
38    VkDecoder();
39    ~VkDecoder();
40    void setForSnapshotLoad(bool forSnapshotLoad);
41    size_t decode(void* buf, size_t bufsize, IOStream* stream,
42                  const ProcessResources* processResources, const VkDecoderContext&);
43private:
44    class Impl;
45    std::unique_ptr<Impl> mImpl;
46};
47
48}  // namespace vk
49}  // namespace gfxstream
50
51"""
52
53decoder_impl_preamble ="""
54namespace gfxstream {
55namespace vk {
56
57using android::base::MetricEventBadPacketLength;
58using android::base::MetricEventDuplicateSequenceNum;
59
60class VkDecoder::Impl {
61public:
62    Impl() : m_logCalls(android::base::getEnvironmentVariable("ANDROID_EMU_VK_LOG_CALLS") == "1"),
63             m_vk(vkDispatch()),
64             m_state(VkDecoderGlobalState::get()),
65             m_boxedHandleUnwrapMapping(m_state),
66             m_boxedHandleCreateMapping(m_state),
67             m_boxedHandleDestroyMapping(m_state),
68             m_boxedHandleUnwrapAndDeleteMapping(m_state),
69             m_boxedHandleUnwrapAndDeletePreserveBoxedMapping(m_state),
70             m_prevSeqno(std::nullopt) {}
71    %s* stream() { return &m_vkStream; }
72    VulkanMemReadingStream* readStream() { return &m_vkMemReadingStream; }
73
74    void setForSnapshotLoad(bool forSnapshotLoad) {
75        m_forSnapshotLoad = forSnapshotLoad;
76    }
77
78    size_t decode(void* buf, size_t bufsize, IOStream* stream,
79                  const ProcessResources* processResources, const VkDecoderContext&);
80
81private:
82    bool m_logCalls;
83    bool m_forSnapshotLoad = false;
84    VulkanDispatch* m_vk;
85    VkDecoderGlobalState* m_state;
86    %s m_vkStream { nullptr };
87    VulkanMemReadingStream m_vkMemReadingStream { nullptr };
88    BoxedHandleUnwrapMapping m_boxedHandleUnwrapMapping;
89    BoxedHandleCreateMapping m_boxedHandleCreateMapping;
90    BoxedHandleDestroyMapping m_boxedHandleDestroyMapping;
91    BoxedHandleUnwrapAndDeleteMapping m_boxedHandleUnwrapAndDeleteMapping;
92    android::base::BumpPool m_pool;
93    BoxedHandleUnwrapAndDeletePreserveBoxedMapping m_boxedHandleUnwrapAndDeletePreserveBoxedMapping;
94    std::optional<uint32_t> m_prevSeqno;
95};
96
97VkDecoder::VkDecoder() :
98    mImpl(new VkDecoder::Impl()) { }
99
100VkDecoder::~VkDecoder() = default;
101
102void VkDecoder::setForSnapshotLoad(bool forSnapshotLoad) {
103    mImpl->setForSnapshotLoad(forSnapshotLoad);
104}
105
106size_t VkDecoder::decode(void* buf, size_t bufsize, IOStream* stream,
107                         const ProcessResources* processResources,
108                         const VkDecoderContext& context) {
109    return mImpl->decode(buf, bufsize, stream, processResources, context);
110}
111
112// VkDecoder::Impl::decode to follow
113""" % (VULKAN_STREAM_TYPE, VULKAN_STREAM_TYPE)
114
115decoder_impl_postamble = """
116
117}  // namespace vk
118}  // namespace gfxstream
119
120"""
121
122READ_STREAM = "vkReadStream"
123WRITE_STREAM = "vkStream"
124
125# Driver workarounds for APIs that don't work well multithreaded
126driver_workarounds_global_lock_apis = [ \
127    "vkCreatePipelineLayout",
128    "vkDestroyPipelineLayout",
129]
130
131def emit_param_decl_for_reading(param, cgen):
132    if param.staticArrExpr:
133        cgen.stmt(
134            cgen.makeRichCTypeDecl(param.getForNonConstAccess()))
135    else:
136        cgen.stmt(
137            cgen.makeRichCTypeDecl(param))
138
139def emit_unmarshal(typeInfo, param, cgen, output = False, destroy = False, noUnbox = False):
140    if destroy:
141        iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen(
142            cgen,
143            "host",
144            READ_STREAM,
145            ROOT_TYPE_DEFAULT_VALUE,
146            param.paramName,
147            "readStreamPtrPtr",
148            API_PREFIX_RESERVEDUNMARSHAL,
149            "",
150            direction="read",
151            dynAlloc=True))
152        lenAccess = cgen.generalLengthAccess(param)
153        lenAccessGuard = cgen.generalLengthAccessGuard(param)
154        if None == lenAccess or "1" == lenAccess:
155            cgen.stmt("boxed_%s_preserve = %s" % (param.paramName, param.paramName))
156            cgen.stmt("%s = unbox_%s(%s)" % (param.paramName, param.typeName, param.paramName))
157        else:
158            if lenAccessGuard is not None:
159                cgen.beginIf(lenAccessGuard)
160            cgen.beginFor("uint32_t i = 0", "i < %s" % lenAccess, "++i")
161            cgen.stmt("boxed_%s_preserve[i] = %s[i]" % (param.paramName, param.paramName))
162            cgen.stmt("((%s*)(%s))[i] = unbox_%s(%s[i])" % (param.typeName, param.paramName, param.typeName, param.paramName))
163            cgen.endFor()
164            if lenAccessGuard is not None:
165                cgen.endIf()
166    else:
167        if noUnbox:
168            cgen.line("// No unbox for %s" % (param.paramName))
169        iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen(
170            cgen,
171            "host",
172            READ_STREAM,
173            ROOT_TYPE_DEFAULT_VALUE,
174            param.paramName,
175            "readStreamPtrPtr",
176            API_PREFIX_RESERVEDUNMARSHAL,
177            "" if (output or noUnbox) else "unbox_",
178            direction="read",
179            dynAlloc=True))
180
181
182def emit_dispatch_unmarshal(typeInfo: VulkanTypeInfo, param: VulkanType, cgen, globalWrapped):
183    cgen.stmt("// Begin {} wrapped dispatchable handle unboxing for {}".format(
184        "global" if globalWrapped else "non",
185        param.paramName))
186
187    iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen(
188        cgen,
189        "host",
190        READ_STREAM,
191        ROOT_TYPE_DEFAULT_VALUE,
192        param.paramName,
193        "readStreamPtrPtr",
194        API_PREFIX_RESERVEDUNMARSHAL,
195        "",
196        direction="read",
197        dynAlloc=True))
198
199    if not globalWrapped:
200        cgen.stmt("auto unboxed_%s = unbox_%s(%s)" %
201                  (param.paramName, param.typeName, param.paramName))
202        cgen.stmt("auto vk = dispatch_%s(%s)" %
203                  (param.typeName, param.paramName))
204        cgen.stmt("// End manual dispatchable handle unboxing for %s" % param.paramName)
205
206
207def emit_transform(typeInfo, param, cgen, variant="tohost"):
208    res = iterateVulkanType(typeInfo, param, TransformCodegen(
209        cgen, param.paramName, "m_state", "transform_%s_" % variant, variant))
210    if not res:
211        cgen.stmt("(void)%s" % param.paramName)
212
213
214def emit_marshal(typeInfo, param, cgen, handleMapOverwrites=False):
215    iterateVulkanType(typeInfo, param, VulkanMarshalingCodegen(
216        cgen,
217        WRITE_STREAM,
218        ROOT_TYPE_DEFAULT_VALUE,
219        param.paramName,
220        API_PREFIX_MARSHAL,
221        direction="write",
222        handleMapOverwrites=handleMapOverwrites))
223
224
225class DecodingParameters(object):
226    def __init__(self, api: VulkanAPI):
227        self.params: list[VulkanType] = []
228        self.toRead: list[VulkanType] = []
229        self.toWrite: list[VulkanType] = []
230
231        for i, param in enumerate(api.parameters):
232            if i == 0 and param.isDispatchableHandleType():
233                param.dispatchHandle = True
234
235            if param.isNonDispatchableHandleType() and param.isCreatedBy(api):
236                param.nonDispatchableHandleCreate = True
237
238            if param.isNonDispatchableHandleType() and param.isDestroyedBy(api):
239                param.nonDispatchableHandleDestroy = True
240
241            if param.isDispatchableHandleType() and param.isCreatedBy(api):
242                param.dispatchableHandleCreate = True
243
244            if param.isDispatchableHandleType() and param.isDestroyedBy(api):
245                param.dispatchableHandleDestroy = True
246
247            self.toRead.append(param)
248
249            if param.possiblyOutput():
250                self.toWrite.append(param)
251
252            self.params.append(param)
253
254
255def emit_call_log(api, cgen):
256    decodingParams = DecodingParameters(api)
257    paramsToRead = decodingParams.toRead
258
259    cgen.beginIf("m_logCalls")
260    paramLogFormat = ""
261    paramLogArgs = []
262    for p in paramsToRead:
263        paramLogFormat += "0x%llx "
264    for p in paramsToRead:
265        paramLogArgs.append("(unsigned long long)%s" % (p.paramName))
266    cgen.stmt("fprintf(stderr, \"stream %%p: call %s %s\\n\", ioStream, %s)" % (api.name, paramLogFormat, ", ".join(paramLogArgs)))
267    cgen.endIf()
268
269def emit_decode_parameters(typeInfo: VulkanTypeInfo, api: VulkanAPI, cgen, globalWrapped=False):
270    decodingParams = DecodingParameters(api)
271
272    paramsToRead = decodingParams.toRead
273
274    for p in paramsToRead:
275        emit_param_decl_for_reading(p, cgen)
276
277    for i, p in enumerate(paramsToRead):
278        lenAccess = cgen.generalLengthAccess(p)
279
280        if p.dispatchHandle:
281            emit_dispatch_unmarshal(typeInfo, p, cgen, globalWrapped)
282        else:
283            destroy = p.nonDispatchableHandleDestroy or p.dispatchableHandleDestroy
284            noUnbox = api.name in ["vkQueueFlushCommandsGOOGLE", "vkQueueFlushCommandsFromAuxMemoryGOOGLE"] and p.paramName == "commandBuffer"
285
286            if p.nonDispatchableHandleDestroy or p.dispatchableHandleDestroy:
287                destroy = True
288                cgen.stmt("// Begin manual non dispatchable handle destroy unboxing for %s" % p.paramName)
289                if None == lenAccess or "1" == lenAccess:
290                    cgen.stmt("%s boxed_%s_preserve" % (p.typeName, p.paramName))
291                else:
292                    cgen.stmt("%s* boxed_%s_preserve; %s->alloc((void**)&boxed_%s_preserve, %s * sizeof(%s))" % (p.typeName, p.paramName, READ_STREAM, p.paramName, lenAccess, p.typeName))
293
294            if p.possiblyOutput():
295                cgen.stmt("// Begin manual dispatchable handle unboxing for %s" % p.paramName)
296                cgen.stmt("%s->unsetHandleMapping()" % READ_STREAM)
297
298            emit_unmarshal(typeInfo, p, cgen, output = p.possiblyOutput(), destroy = destroy, noUnbox = noUnbox)
299
300    for p in paramsToRead:
301        emit_transform(typeInfo, p, cgen, variant="tohost")
302
303    emit_call_log(api, cgen)
304
305def emit_dispatch_call(api, cgen):
306
307    decodingParams = DecodingParameters(api)
308
309    customParams = []
310
311    delay = api.name in DELAYED_DECODER_DELETES
312
313    for i, p in enumerate(api.parameters):
314        customParam = p.paramName
315        if decodingParams.params[i].dispatchHandle:
316            customParam = "unboxed_%s" % p.paramName
317        customParams.append(customParam)
318
319    if delay:
320        cgen.line("std::function<void()> delayed_remove_callback = [vk, %s]() {" % ", ".join(customParams))
321
322    if api.name in driver_workarounds_global_lock_apis:
323        if delay:
324            cgen.stmt("auto state = VkDecoderGlobalState::get()")
325            cgen.stmt("// state already locked")
326        else:
327            cgen.stmt("m_state->lock()")
328
329    cgen.vkApiCall(api, customPrefix="vk->", customParameters=customParams, \
330        globalStatePrefix=global_state_prefix, checkForDeviceLost=True,
331        checkForOutOfMemory=True)
332
333    if api.name in driver_workarounds_global_lock_apis:
334        if not delay:
335            cgen.stmt("m_state->unlock()")
336        # for delayed remove, state is already locked, so we do not need to
337        # unlock
338
339    if delay:
340        cgen.line("};")
341
342def emit_global_state_wrapped_call(api, cgen, context):
343    if api.name in DELAYED_DECODER_DELETES:
344        print("Error: Cannot generate a global state wrapped call that is also a delayed delete (yet)");
345        raise
346
347    customParams = ["&m_pool"] + list(map(lambda p: p.paramName, api.parameters))
348    if context:
349        customParams += ["context"]
350    cgen.vkApiCall(api, customPrefix=global_state_prefix, \
351        customParameters=customParams, globalStatePrefix=global_state_prefix, \
352        checkForDeviceLost=True, checkForOutOfMemory=True)
353
354def emit_decode_parameters_writeback(typeInfo, api, cgen, autobox=True):
355    decodingParams = DecodingParameters(api)
356
357    paramsToWrite = decodingParams.toWrite
358
359    cgen.stmt("%s->unsetHandleMapping()" % WRITE_STREAM)
360
361    handleMapOverwrites = False
362
363    for p in paramsToWrite:
364        emit_transform(typeInfo, p, cgen, variant="fromhost")
365
366        handleMapOverwrites = False
367
368        if p.nonDispatchableHandleCreate or p.dispatchableHandleCreate:
369            handleMapOverwrites = True
370
371        if autobox and p.nonDispatchableHandleCreate:
372            cgen.stmt("// Begin auto non dispatchable handle create for %s" % p.paramName)
373            cgen.stmt("if (%s == VK_SUCCESS) %s->setHandleMapping(&m_boxedHandleCreateMapping)" % \
374                      (api.getRetVarExpr(), WRITE_STREAM))
375
376        if (not autobox) and p.nonDispatchableHandleCreate:
377            cgen.stmt("// Begin manual non dispatchable handle create for %s" % p.paramName)
378            cgen.stmt("%s->unsetHandleMapping()" % WRITE_STREAM)
379
380        emit_marshal(typeInfo, p, cgen, handleMapOverwrites=handleMapOverwrites)
381
382        if autobox and p.nonDispatchableHandleCreate:
383            cgen.stmt("// Begin auto non dispatchable handle create for %s" % p.paramName)
384            cgen.stmt("%s->setHandleMapping(&m_boxedHandleUnwrapMapping)" % WRITE_STREAM)
385
386        if (not autobox) and p.nonDispatchableHandleCreate:
387            cgen.stmt("// Begin manual non dispatchable handle create for %s" % p.paramName)
388            cgen.stmt("%s->setHandleMapping(&m_boxedHandleUnwrapMapping)" % WRITE_STREAM)
389
390def emit_decode_return_writeback(api, cgen):
391    retTypeName = api.getRetTypeExpr()
392    if retTypeName != "void":
393        retVar = api.getRetVarExpr()
394        cgen.stmt("%s->write(&%s, %s)" %
395            (WRITE_STREAM, retVar, cgen.sizeofExpr(api.retType)))
396
397def emit_decode_finish(api, cgen):
398    decodingParams = DecodingParameters(api)
399    retTypeName = api.getRetTypeExpr()
400    paramsToWrite = decodingParams.toWrite
401
402    if retTypeName != "void" or len(paramsToWrite) != 0:
403        cgen.stmt("%s->commitWrite()" % WRITE_STREAM)
404
405def emit_destroyed_handle_cleanup(api, cgen):
406    decodingParams = DecodingParameters(api)
407    paramsToRead = decodingParams.toRead
408
409    skipDelete = api.name in SKIPPED_DECODER_DELETES
410
411    if skipDelete:
412        cgen.line("// Skipping handle cleanup for %s" % api.name)
413        return
414
415    for p in paramsToRead:
416        if p.dispatchHandle:
417            pass
418        else:
419            lenAccess = cgen.generalLengthAccess(p)
420            lenAccessGuard = cgen.generalLengthAccess(p)
421            destroy = p.nonDispatchableHandleDestroy or p.dispatchableHandleDestroy
422            if destroy:
423                if None == lenAccess or "1" == lenAccess:
424                    if api.name in DELAYED_DECODER_DELETES:
425                        cgen.stmt("delayed_delete_%s(boxed_%s_preserve, unboxed_device, delayed_remove_callback)" % (p.typeName, p.paramName))
426                    else:
427                        cgen.stmt("delete_%s(boxed_%s_preserve)" % (p.typeName, p.paramName))
428                else:
429                    if lenAccessGuard is not None:
430                        cgen.beginIf(lenAccessGuard)
431                    cgen.beginFor("uint32_t i = 0", "i < %s" % lenAccess, "++i")
432                    if api.name in DELAYED_DECODER_DELETES:
433                        cgen.stmt("delayed_delete_%s(boxed_%s_preserve[i], unboxed_device, delayed_remove_callback)" % (p.typeName, p.paramName))
434                    else:
435                        cgen.stmt("delete_%s(boxed_%s_preserve[i])" % (p.typeName, p.paramName))
436                    cgen.endFor()
437                    if lenAccessGuard is not None:
438                        cgen.endIf()
439
440def emit_pool_free(cgen):
441    cgen.stmt("%s->clearPool()" % READ_STREAM)
442
443def emit_seqno_incr(api, cgen):
444    cgen.stmt("if (queueSubmitWithCommandsEnabled) seqnoPtr->fetch_add(1, std::memory_order_seq_cst)")
445
446def emit_snapshot(typeInfo, api, cgen):
447
448    cgen.stmt("%s->setReadPos((uintptr_t)(*readStreamPtrPtr) - (uintptr_t)snapshotTraceBegin)" % READ_STREAM)
449    cgen.stmt("size_t snapshotTraceBytes = %s->endTrace()" % READ_STREAM)
450
451    additionalParams = [ \
452        makeVulkanTypeSimple(True, "uint8_t", 1, "snapshotTraceBegin"),
453        makeVulkanTypeSimple(False, "size_t", 0, "snapshotTraceBytes"),
454        makeVulkanTypeSimple(False, "android::base::BumpPool", 1, "&m_pool"),
455    ]
456
457    retTypeName = api.getRetTypeExpr()
458    if retTypeName != "void":
459        retVar = api.getRetVarExpr()
460        additionalParams.append(makeVulkanTypeSimple(False, retTypeName, 0, retVar))
461
462    paramsForSnapshot = []
463
464    decodingParams = DecodingParameters(api)
465
466    for p in decodingParams.toRead:
467        if p.nonDispatchableHandleDestroy or (not p.dispatchHandle and p.dispatchableHandleDestroy):
468            paramsForSnapshot.append(p.withModifiedName("boxed_%s_preserve" % p.paramName))
469        else:
470            paramsForSnapshot.append(p)
471
472    customParams = additionalParams + paramsForSnapshot
473
474    apiForSnapshot = \
475        api.withCustomReturnType(makeVulkanTypeSimple(False, "void", 0, "void")). \
476            withCustomParameters(customParams)
477
478    cgen.beginIf("m_state->snapshotsEnabled()")
479    cgen.vkApiCall(apiForSnapshot, customPrefix="m_state->snapshot()->")
480    cgen.endIf()
481
482def emit_decoding(typeInfo, api, cgen, globalWrapped=False, context=False):
483    isAcquire = api.name in RELAXED_APIS
484    emit_decode_parameters(typeInfo, api, cgen, globalWrapped)
485
486    if isAcquire:
487        emit_seqno_incr(api, cgen)
488
489    if globalWrapped:
490        emit_global_state_wrapped_call(api, cgen, context)
491    else:
492        emit_dispatch_call(api, cgen)
493
494    emit_decode_parameters_writeback(typeInfo, api, cgen, autobox=not globalWrapped)
495    emit_decode_return_writeback(api, cgen)
496    emit_decode_finish(api, cgen)
497    emit_snapshot(typeInfo, api, cgen)
498    emit_destroyed_handle_cleanup(api, cgen)
499    emit_pool_free(cgen)
500
501    if not isAcquire:
502        emit_seqno_incr(api, cgen)
503
504def emit_default_decoding(typeInfo, api, cgen):
505    emit_decoding(typeInfo, api, cgen)
506
507def emit_global_state_wrapped_decoding(typeInfo, api, cgen):
508    emit_decoding(typeInfo, api, cgen, globalWrapped=True)
509
510def emit_global_state_wrapped_decoding_with_context(typeInfo, api, cgen):
511    emit_decoding(typeInfo, api, cgen, globalWrapped=True, context=True)
512
513## Custom decoding definitions##################################################
514def decode_vkFlushMappedMemoryRanges(typeInfo: VulkanTypeInfo, api, cgen):
515    emit_decode_parameters(typeInfo, api, cgen)
516
517    cgen.beginIf("!m_state->usingDirectMapping()")
518    cgen.stmt("// This is to deal with a deficiency in the encoder,");
519    cgen.stmt("// where usingDirectMapping fails to set the proper packet size,");
520    cgen.stmt("// meaning we can read off the end of the packet.");
521    cgen.stmt("uint64_t sizeLeft = end - *readStreamPtrPtr")
522    cgen.beginFor("uint32_t i = 0", "i < memoryRangeCount", "++i")
523    cgen.beginIf("sizeLeft < sizeof(uint64_t)")
524    cgen.beginIf("m_prevSeqno")
525    cgen.stmt("m_prevSeqno = m_prevSeqno.value() - 1")
526    cgen.endIf()
527    cgen.stmt("return ptr - (unsigned char*)buf;")
528    cgen.endIf()
529    cgen.stmt("auto range = pMemoryRanges[i]")
530    cgen.stmt("auto memory = pMemoryRanges[i].memory")
531    cgen.stmt("auto size = pMemoryRanges[i].size")
532    cgen.stmt("auto offset = pMemoryRanges[i].offset")
533    cgen.stmt("uint64_t readStream = 0")
534    cgen.stmt("memcpy(&readStream, *readStreamPtrPtr, sizeof(uint64_t)); *readStreamPtrPtr += sizeof(uint64_t)")
535    cgen.stmt("sizeLeft -= sizeof(uint64_t)")
536    cgen.stmt("auto hostPtr = m_state->getMappedHostPointer(memory)")
537    cgen.stmt("if (!hostPtr && readStream > 0) GFXSTREAM_ABORT(::emugl::FatalError(::emugl::ABORT_REASON_OTHER))")
538    cgen.stmt("if (!hostPtr) continue")
539    cgen.beginIf("sizeLeft < readStream")
540    cgen.beginIf("m_prevSeqno")
541    cgen.stmt("m_prevSeqno = m_prevSeqno.value() - 1")
542    cgen.endIf()
543    cgen.stmt("return ptr - (unsigned char*)buf;")
544    cgen.endIf()
545    cgen.stmt("sizeLeft -= readStream")
546    cgen.stmt("uint8_t* targetRange = hostPtr + offset")
547    cgen.stmt("memcpy(targetRange, *readStreamPtrPtr, readStream); *readStreamPtrPtr += readStream")
548    cgen.stmt("packetLen += 8 + readStream")
549    cgen.endFor()
550    cgen.endIf()
551
552    emit_dispatch_call(api, cgen)
553    emit_decode_parameters_writeback(typeInfo, api, cgen)
554    emit_decode_return_writeback(api, cgen)
555    emit_decode_finish(api, cgen)
556    emit_snapshot(typeInfo, api, cgen);
557    emit_pool_free(cgen)
558    emit_seqno_incr(api, cgen)
559
560def decode_vkInvalidateMappedMemoryRanges(typeInfo, api, cgen):
561    emit_decode_parameters(typeInfo, api, cgen)
562    emit_dispatch_call(api, cgen)
563    emit_decode_parameters_writeback(typeInfo, api, cgen)
564    emit_decode_return_writeback(api, cgen)
565
566    cgen.beginIf("!m_state->usingDirectMapping()")
567    cgen.beginFor("uint32_t i = 0", "i < memoryRangeCount", "++i")
568    cgen.stmt("auto range = pMemoryRanges[i]")
569    cgen.stmt("auto memory = range.memory")
570    cgen.stmt("auto size = range.size")
571    cgen.stmt("auto offset = range.offset")
572    cgen.stmt("auto hostPtr = m_state->getMappedHostPointer(memory)")
573    cgen.stmt("auto actualSize = size == VK_WHOLE_SIZE ? m_state->getDeviceMemorySize(memory) : size")
574    cgen.stmt("uint64_t writeStream = 0")
575    cgen.stmt("if (!hostPtr) { %s->write(&writeStream, sizeof(uint64_t)); continue; }" % WRITE_STREAM)
576    cgen.stmt("uint8_t* targetRange = hostPtr + offset")
577    cgen.stmt("writeStream = actualSize")
578    cgen.stmt("%s->write(&writeStream, sizeof(uint64_t))" % WRITE_STREAM)
579    cgen.stmt("%s->write(targetRange, actualSize)" % WRITE_STREAM)
580    cgen.endFor()
581    cgen.endIf()
582
583    emit_decode_finish(api, cgen)
584    emit_snapshot(typeInfo, api, cgen);
585    emit_pool_free(cgen)
586    emit_seqno_incr(api, cgen)
587
588def decode_unsupported_api(typeInfo, api, cgen):
589    cgen.line(f"// Decoding {api.name} is not supported. This should not run.")
590    cgen.stmt(f"fprintf(stderr, \"stream %p: fatal: decoding unsupported API {api.name}\\n\", ioStream)");
591    cgen.stmt("__builtin_trap()")
592
593custom_decodes = {
594    "vkEnumerateInstanceVersion" : emit_global_state_wrapped_decoding,
595    "vkCreateInstance" : emit_global_state_wrapped_decoding,
596    "vkDestroyInstance" : emit_global_state_wrapped_decoding,
597    "vkEnumeratePhysicalDevices" : emit_global_state_wrapped_decoding,
598
599    "vkGetPhysicalDeviceFeatures" : emit_global_state_wrapped_decoding,
600    "vkGetPhysicalDeviceFeatures2" : emit_global_state_wrapped_decoding,
601    "vkGetPhysicalDeviceFeatures2KHR" : emit_global_state_wrapped_decoding,
602    "vkGetPhysicalDeviceFormatProperties" : emit_global_state_wrapped_decoding,
603    "vkGetPhysicalDeviceFormatProperties2" : emit_global_state_wrapped_decoding,
604    "vkGetPhysicalDeviceFormatProperties2KHR" : emit_global_state_wrapped_decoding,
605    "vkGetPhysicalDeviceImageFormatProperties" : emit_global_state_wrapped_decoding,
606    "vkGetPhysicalDeviceImageFormatProperties2" : emit_global_state_wrapped_decoding,
607    "vkGetPhysicalDeviceImageFormatProperties2KHR" : emit_global_state_wrapped_decoding,
608    "vkGetPhysicalDeviceProperties" : emit_global_state_wrapped_decoding,
609    "vkGetPhysicalDeviceProperties2" : emit_global_state_wrapped_decoding,
610    "vkGetPhysicalDeviceProperties2KHR" : emit_global_state_wrapped_decoding,
611
612    "vkGetPhysicalDeviceMemoryProperties" : emit_global_state_wrapped_decoding,
613    "vkGetPhysicalDeviceMemoryProperties2" : emit_global_state_wrapped_decoding,
614    "vkGetPhysicalDeviceMemoryProperties2KHR" : emit_global_state_wrapped_decoding,
615
616    "vkGetPhysicalDeviceExternalSemaphoreProperties" : emit_global_state_wrapped_decoding,
617    "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR" : emit_global_state_wrapped_decoding,
618
619    "vkEnumerateDeviceExtensionProperties" : emit_global_state_wrapped_decoding,
620
621    "vkCreateBuffer" : emit_global_state_wrapped_decoding,
622    "vkDestroyBuffer" : emit_global_state_wrapped_decoding,
623
624    "vkBindBufferMemory" : emit_global_state_wrapped_decoding,
625    "vkBindBufferMemory2" : emit_global_state_wrapped_decoding,
626    "vkBindBufferMemory2KHR" : emit_global_state_wrapped_decoding,
627
628    "vkCreateDevice" : emit_global_state_wrapped_decoding,
629    "vkGetDeviceQueue" : emit_global_state_wrapped_decoding,
630    "vkDestroyDevice" : emit_global_state_wrapped_decoding,
631
632    "vkGetDeviceQueue2" : emit_global_state_wrapped_decoding,
633
634    "vkBindImageMemory" : emit_global_state_wrapped_decoding,
635    "vkBindImageMemory2" : emit_global_state_wrapped_decoding,
636    "vkBindImageMemory2KHR" : emit_global_state_wrapped_decoding,
637
638    "vkCreateImage" : emit_global_state_wrapped_decoding,
639    "vkCreateImageView" : emit_global_state_wrapped_decoding,
640    "vkCreateSampler" : emit_global_state_wrapped_decoding,
641    "vkDestroyImage" : emit_global_state_wrapped_decoding,
642    "vkDestroyImageView" : emit_global_state_wrapped_decoding,
643    "vkDestroySampler" : emit_global_state_wrapped_decoding,
644    "vkCmdCopyBufferToImage" : emit_global_state_wrapped_decoding_with_context,
645    "vkCmdCopyImage" : emit_global_state_wrapped_decoding,
646    "vkCmdCopyImageToBuffer" : emit_global_state_wrapped_decoding,
647    "vkCmdCopyBufferToImage2" : emit_global_state_wrapped_decoding_with_context,
648    "vkCmdCopyImage2" : emit_global_state_wrapped_decoding,
649    "vkCmdCopyImageToBuffer2" : emit_global_state_wrapped_decoding,
650    "vkGetImageMemoryRequirements" : emit_global_state_wrapped_decoding,
651    "vkGetImageMemoryRequirements2" : emit_global_state_wrapped_decoding,
652    "vkGetImageMemoryRequirements2KHR" : emit_global_state_wrapped_decoding,
653    "vkGetBufferMemoryRequirements" : emit_global_state_wrapped_decoding,
654    "vkGetBufferMemoryRequirements2": emit_global_state_wrapped_decoding,
655    "vkGetBufferMemoryRequirements2KHR": emit_global_state_wrapped_decoding,
656
657    "vkCreateDescriptorSetLayout" : emit_global_state_wrapped_decoding,
658    "vkDestroyDescriptorSetLayout" : emit_global_state_wrapped_decoding,
659    "vkCreateDescriptorPool" : emit_global_state_wrapped_decoding,
660    "vkDestroyDescriptorPool" : emit_global_state_wrapped_decoding,
661    "vkResetDescriptorPool" : emit_global_state_wrapped_decoding,
662    "vkAllocateDescriptorSets" : emit_global_state_wrapped_decoding,
663    "vkFreeDescriptorSets" : emit_global_state_wrapped_decoding,
664
665    "vkUpdateDescriptorSets" : emit_global_state_wrapped_decoding,
666
667    "vkCreateShaderModule": emit_global_state_wrapped_decoding,
668    "vkDestroyShaderModule": emit_global_state_wrapped_decoding,
669    "vkCreatePipelineCache": emit_global_state_wrapped_decoding,
670    "vkDestroyPipelineCache": emit_global_state_wrapped_decoding,
671    "vkCreateGraphicsPipelines": emit_global_state_wrapped_decoding,
672    "vkDestroyPipeline": emit_global_state_wrapped_decoding,
673
674    "vkAllocateMemory" : emit_global_state_wrapped_decoding,
675    "vkFreeMemory" : emit_global_state_wrapped_decoding,
676    "vkMapMemory" : emit_global_state_wrapped_decoding,
677    "vkUnmapMemory" : emit_global_state_wrapped_decoding,
678    "vkFlushMappedMemoryRanges" : decode_vkFlushMappedMemoryRanges,
679    "vkInvalidateMappedMemoryRanges" : decode_vkInvalidateMappedMemoryRanges,
680
681    "vkAllocateCommandBuffers" : emit_global_state_wrapped_decoding,
682    "vkCmdExecuteCommands" : emit_global_state_wrapped_decoding,
683    "vkQueueSubmit" : emit_global_state_wrapped_decoding,
684    "vkQueueSubmit2" : emit_global_state_wrapped_decoding,
685    "vkQueueWaitIdle" : emit_global_state_wrapped_decoding,
686    "vkBeginCommandBuffer" : emit_global_state_wrapped_decoding_with_context,
687    "vkEndCommandBuffer" : emit_global_state_wrapped_decoding_with_context,
688    "vkResetCommandBuffer" : emit_global_state_wrapped_decoding,
689    "vkFreeCommandBuffers" : emit_global_state_wrapped_decoding,
690    "vkCreateCommandPool" : emit_global_state_wrapped_decoding,
691    "vkDestroyCommandPool" : emit_global_state_wrapped_decoding,
692    "vkResetCommandPool" : emit_global_state_wrapped_decoding,
693    "vkCmdPipelineBarrier" : emit_global_state_wrapped_decoding,
694    "vkCmdBindPipeline" : emit_global_state_wrapped_decoding,
695    "vkCmdBindDescriptorSets" : emit_global_state_wrapped_decoding,
696
697    "vkCreateRenderPass" : emit_global_state_wrapped_decoding,
698    "vkCreateRenderPass2" : emit_global_state_wrapped_decoding,
699    "vkCreateRenderPass2KHR" : emit_global_state_wrapped_decoding,
700    "vkDestroyRenderPass" : emit_global_state_wrapped_decoding,
701    "vkCreateFramebuffer" : emit_global_state_wrapped_decoding,
702    "vkDestroyFramebuffer" : emit_global_state_wrapped_decoding,
703
704    "vkCreateSamplerYcbcrConversion": emit_global_state_wrapped_decoding,
705    "vkDestroySamplerYcbcrConversion": emit_global_state_wrapped_decoding,
706
707    # VK_ANDROID_native_buffer
708    "vkGetSwapchainGrallocUsageANDROID" : emit_global_state_wrapped_decoding,
709    "vkGetSwapchainGrallocUsage2ANDROID" : emit_global_state_wrapped_decoding,
710    "vkAcquireImageANDROID" : emit_global_state_wrapped_decoding,
711    "vkQueueSignalReleaseImageANDROID" : emit_global_state_wrapped_decoding,
712
713    "vkCreateSemaphore" : emit_global_state_wrapped_decoding,
714    "vkGetSemaphoreFdKHR" : emit_global_state_wrapped_decoding,
715    "vkImportSemaphoreFdKHR" : emit_global_state_wrapped_decoding,
716    "vkDestroySemaphore" : emit_global_state_wrapped_decoding,
717
718    "vkCreateFence" : emit_global_state_wrapped_decoding,
719    "vkResetFences" : emit_global_state_wrapped_decoding,
720    "vkDestroyFence" : emit_global_state_wrapped_decoding,
721
722    # VK_GOOGLE_gfxstream
723    "vkFreeMemorySyncGOOGLE" : emit_global_state_wrapped_decoding,
724    "vkMapMemoryIntoAddressSpaceGOOGLE" : emit_global_state_wrapped_decoding,
725    "vkGetMemoryHostAddressInfoGOOGLE" : emit_global_state_wrapped_decoding,
726    "vkGetBlobGOOGLE" : emit_global_state_wrapped_decoding,
727
728    # Descriptor update templates
729    "vkCreateDescriptorUpdateTemplate" : emit_global_state_wrapped_decoding,
730    "vkCreateDescriptorUpdateTemplateKHR" : emit_global_state_wrapped_decoding,
731    "vkDestroyDescriptorUpdateTemplate" : emit_global_state_wrapped_decoding,
732    "vkDestroyDescriptorUpdateTemplateKHR" : emit_global_state_wrapped_decoding,
733    "vkUpdateDescriptorSetWithTemplateSizedGOOGLE" : emit_global_state_wrapped_decoding,
734    "vkUpdateDescriptorSetWithTemplateSized2GOOGLE" : emit_global_state_wrapped_decoding,
735
736    # VK_GOOGLE_gfxstream
737    "vkBeginCommandBufferAsyncGOOGLE" : emit_global_state_wrapped_decoding_with_context,
738    "vkEndCommandBufferAsyncGOOGLE" : emit_global_state_wrapped_decoding_with_context,
739    "vkResetCommandBufferAsyncGOOGLE" : emit_global_state_wrapped_decoding,
740    "vkCommandBufferHostSyncGOOGLE" : emit_global_state_wrapped_decoding,
741    "vkCreateImageWithRequirementsGOOGLE" : emit_global_state_wrapped_decoding,
742    "vkCreateBufferWithRequirementsGOOGLE" : emit_global_state_wrapped_decoding,
743    "vkQueueHostSyncGOOGLE" : emit_global_state_wrapped_decoding,
744    "vkQueueSubmitAsyncGOOGLE" : emit_global_state_wrapped_decoding,
745    "vkQueueSubmitAsync2GOOGLE" : emit_global_state_wrapped_decoding,
746    "vkQueueWaitIdleAsyncGOOGLE" : emit_global_state_wrapped_decoding,
747    "vkQueueBindSparseAsyncGOOGLE" : emit_global_state_wrapped_decoding,
748    "vkGetLinearImageLayoutGOOGLE" : emit_global_state_wrapped_decoding,
749    "vkGetLinearImageLayout2GOOGLE" : emit_global_state_wrapped_decoding,
750    "vkQueueFlushCommandsGOOGLE" : emit_global_state_wrapped_decoding_with_context,
751    "vkQueueFlushCommandsFromAuxMemoryGOOGLE" : emit_global_state_wrapped_decoding_with_context,
752    "vkQueueCommitDescriptorSetUpdatesGOOGLE" : emit_global_state_wrapped_decoding,
753    "vkCollectDescriptorPoolIdsGOOGLE" : emit_global_state_wrapped_decoding,
754    "vkQueueSignalReleaseImageANDROIDAsyncGOOGLE" : emit_global_state_wrapped_decoding,
755
756    "vkQueueBindSparse" : emit_global_state_wrapped_decoding,
757
758    # VK_KHR_xcb_surface
759    "vkCreateXcbSurfaceKHR": decode_unsupported_api,
760    "vkGetPhysicalDeviceXcbPresentationSupportKHR": decode_unsupported_api,
761
762    # VK_EXT_metal_surface
763    "vkCreateMetalSurfaceEXT": decode_unsupported_api,
764
765    # VK_KHR_sampler_ycbcr_conversion
766    "vkCreateSamplerYcbcrConversionKHR": emit_global_state_wrapped_decoding,
767    "vkDestroySamplerYcbcrConversionKHR": emit_global_state_wrapped_decoding,
768
769    #VK_KHR_copy_commands2
770    "vkCmdCopyBufferToImage2KHR" : emit_global_state_wrapped_decoding_with_context,
771    "vkCmdCopyImage2KHR" : emit_global_state_wrapped_decoding,
772    "vkCmdCopyImageToBuffer2KHR" : emit_global_state_wrapped_decoding,
773}
774
775class VulkanDecoder(VulkanWrapperGenerator):
776    def __init__(self, module, typeInfo):
777        VulkanWrapperGenerator.__init__(self, module, typeInfo)
778        self.typeInfo: VulkanTypeInfo = typeInfo
779        self.cgen = CodeGen()
780
781    def onBegin(self,):
782        self.module.appendImpl(
783            "#define MAX_PACKET_LENGTH %s\n" % MAX_PACKET_LENGTH)
784        self.module.appendHeader(decoder_decl_preamble)
785        self.module.appendImpl(decoder_impl_preamble)
786
787        self.module.appendImpl(
788            """
789size_t VkDecoder::Impl::decode(void* buf, size_t len, IOStream* ioStream,
790                               const ProcessResources* processResources,
791                               const VkDecoderContext& context)
792""")
793
794        self.cgen.beginBlock() # function body
795
796        self.cgen.stmt("const char* processName = context.processName")
797        self.cgen.stmt("auto& gfx_logger = *context.gfxApiLogger")
798        self.cgen.stmt("auto* healthMonitor = context.healthMonitor")
799        self.cgen.stmt("auto& metricsLogger = *context.metricsLogger")
800        self.cgen.stmt("if (len < 8) return 0")
801        self.cgen.stmt("bool queueSubmitWithCommandsEnabled = feature_is_enabled(kFeature_VulkanQueueSubmitWithCommands)")
802        self.cgen.stmt("unsigned char *ptr = (unsigned char *)buf")
803        self.cgen.stmt("const unsigned char* const end = (const unsigned char*)buf + len")
804
805        self.cgen.beginIf("m_forSnapshotLoad")
806        self.cgen.stmt("ptr += m_state->setCreatedHandlesForSnapshotLoad(ptr)");
807        self.cgen.endIf()
808        self.cgen.line("while (end - ptr >= 8)")
809        self.cgen.beginBlock() # while loop
810
811        self.cgen.stmt("uint32_t opcode = *(uint32_t *)ptr")
812        self.cgen.stmt("uint32_t packetLen = *(uint32_t *)(ptr + 4)")
813        self.cgen.line("""
814        // packetLen should be at least 8 (op code and packet length) and should not be excessively large
815        if (packetLen < 8 || packetLen > MAX_PACKET_LENGTH) {
816            WARN("Bad packet length %d detected, decode may fail", packetLen);
817            metricsLogger.logMetricEvent(MetricEventBadPacketLength{ .len = packetLen });
818        }
819        """)
820        self.cgen.stmt("if (end - ptr < packetLen) return ptr - (unsigned char*)buf")
821        self.cgen.stmt("gfx_logger.record(ptr, std::min(size_t(packetLen + 8), size_t(end - ptr)))")
822
823        self.cgen.stmt("stream()->setStream(ioStream)")
824        self.cgen.stmt("VulkanStream* %s = stream()" % WRITE_STREAM)
825        self.cgen.stmt("VulkanMemReadingStream* %s = readStream()" % READ_STREAM)
826        self.cgen.stmt("%s->setBuf((uint8_t*)(ptr + 8))" % READ_STREAM)
827        self.cgen.stmt("uint8_t* readStreamPtr = %s->getBuf(); uint8_t** readStreamPtrPtr = &readStreamPtr" % READ_STREAM)
828        self.cgen.stmt("uint8_t* snapshotTraceBegin = %s->beginTrace()" % READ_STREAM)
829        self.cgen.stmt("%s->setHandleMapping(&m_boxedHandleUnwrapMapping)" % READ_STREAM)
830        self.cgen.line("""
831        std::unique_ptr<EventHangMetadata::HangAnnotations> executionData =
832            std::make_unique<EventHangMetadata::HangAnnotations>();
833        if (healthMonitor) {
834            executionData->insert(
835                 {{"packet_length", std::to_string(packetLen)},
836                 {"opcode", std::to_string(opcode)}});
837            if (processName) {
838                executionData->insert(
839                    {{"renderthread_guest_process", std::string(processName)}});
840            }
841            if (m_prevSeqno) {
842                executionData->insert({{"previous_seqno", std::to_string(m_prevSeqno.value())}});
843            }
844        }
845
846        std::atomic<uint32_t>* seqnoPtr = processResources ?
847                processResources->getSequenceNumberPtr() : nullptr;
848
849        if (queueSubmitWithCommandsEnabled && ((opcode >= OP_vkFirst && opcode < OP_vkLast) || (opcode >= OP_vkFirst_old && opcode < OP_vkLast_old))) {
850            uint32_t seqno;
851            memcpy(&seqno, *readStreamPtrPtr, sizeof(uint32_t)); *readStreamPtrPtr += sizeof(uint32_t);
852            if (healthMonitor) executionData->insert({{"seqno", std::to_string(seqno)}});
853            if (m_prevSeqno  && seqno == m_prevSeqno.value()) {
854                WARN(
855                    "Seqno %d is the same as previously processed on thread %d. It might be a "
856                    "duplicate command.",
857                    seqno, getCurrentThreadId());
858                metricsLogger.logMetricEvent(MetricEventDuplicateSequenceNum{ .opcode = opcode });
859            }
860            if (seqnoPtr && !m_forSnapshotLoad) {
861                {
862                    auto seqnoWatchdog =
863                        WATCHDOG_BUILDER(healthMonitor,
864                                         "RenderThread seqno loop")
865                            .setHangType(EventHangMetadata::HangType::kRenderThread)
866                            .setAnnotations(std::make_unique<EventHangMetadata::HangAnnotations>(*executionData))
867                            /* Data gathered if this hangs*/
868                            .setOnHangCallback([=]() {
869                                auto annotations = std::make_unique<EventHangMetadata::HangAnnotations>();
870                                annotations->insert({{"seqnoPtr", std::to_string(seqnoPtr->load(std::memory_order_seq_cst))}});
871                                return annotations;
872                            })
873                            .build();
874                    while ((seqno - seqnoPtr->load(std::memory_order_seq_cst) != 1)) {
875                        #if (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)))
876                        _mm_pause();
877                        #elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
878                        __asm__ __volatile__("pause;");
879                        #endif
880                    }
881                    m_prevSeqno = seqno;
882                }
883            }
884        }
885        """)
886
887        self.cgen.line("""
888        gfx_logger.recordCommandExecution();
889        """)
890
891        self.cgen.line("""
892        auto executionWatchdog =
893            WATCHDOG_BUILDER(healthMonitor, "RenderThread VkDecoder command execution")
894                .setHangType(EventHangMetadata::HangType::kRenderThread)
895                .setAnnotations(std::move(executionData))
896                .build();
897        """)
898
899        self.cgen.stmt("auto vk = m_vk")
900
901        self.cgen.line("switch (opcode)")
902        self.cgen.beginBlock()  # switch stmt
903
904        self.module.appendImpl(self.cgen.swapCode())
905
906    def onGenCmd(self, cmdinfo, name, alias):
907        typeInfo = self.typeInfo
908        cgen = self.cgen
909        api: VulkanAPI = typeInfo.apis[name]
910
911        cgen.line("case OP_%s:" % name)
912        cgen.beginBlock()
913        cgen.stmt("android::base::beginTrace(\"%s decode\")" % name)
914
915        if api.name in custom_decodes.keys():
916            custom_decodes[api.name](typeInfo, api, cgen)
917        else:
918            emit_default_decoding(typeInfo, api, cgen)
919
920        cgen.stmt("android::base::endTrace()")
921        cgen.stmt("break")
922        cgen.endBlock()
923        self.module.appendImpl(self.cgen.swapCode())
924
925    def onEnd(self,):
926        self.cgen.line("default:")
927        self.cgen.beginBlock()
928        self.cgen.stmt("m_pool.freeAll()")
929        self.cgen.stmt("return ptr - (unsigned char *)buf")
930        self.cgen.endBlock()
931
932        self.cgen.endBlock() # switch stmt
933
934        self.cgen.stmt("ptr += packetLen")
935        self.cgen.endBlock() # while loop
936
937        self.cgen.beginIf("m_forSnapshotLoad")
938        self.cgen.stmt("m_state->clearCreatedHandlesForSnapshotLoad()");
939        self.cgen.endIf()
940
941        self.cgen.stmt("m_pool.freeAll()")
942        self.cgen.stmt("return ptr - (unsigned char*)buf;")
943        self.cgen.endBlock() # function body
944        self.module.appendImpl(self.cgen.swapCode())
945        self.module.appendImpl(decoder_impl_postamble)
946