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