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