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