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