xref: /aosp_15_r20/external/mesa3d/src/gfxstream/codegen/scripts/cereal/encoder.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1# Copyright 2018 Google LLC
2# SPDX-License-Identifier: MIT
3import copy
4
5from .common.codegen import CodeGen, VulkanWrapperGenerator
6from .common.vulkantypes import \
7        VulkanAPI, makeVulkanTypeSimple, iterateVulkanType
8
9from .marshaling import VulkanMarshalingCodegen
10from .reservedmarshaling import VulkanReservedMarshalingCodegen
11from .counting import VulkanCountingCodegen
12from .handlemap import HandleMapCodegen
13from .deepcopy import DeepcopyCodegen
14from .transform import TransformCodegen, genTransformsForVulkanType
15
16from .wrapperdefs import API_PREFIX_RESERVEDMARSHAL
17from .wrapperdefs import API_PREFIX_MARSHAL
18from .wrapperdefs import API_PREFIX_UNMARSHAL
19from .wrapperdefs import ROOT_TYPE_DEFAULT_VALUE
20from .wrapperdefs import VULKAN_STREAM_TYPE_GUEST
21
22encoder_decl_preamble = """
23
24class VkEncoder {
25public:
26    VkEncoder(gfxstream::guest::IOStream* stream);
27    ~VkEncoder();
28
29#include "VkEncoder.h.inl"
30"""
31
32encoder_decl_postamble = """
33private:
34    class Impl;
35    std::unique_ptr<Impl> mImpl;
36};
37"""
38
39encoder_impl_preamble ="""
40
41using namespace gfxstream::vk;
42
43using gfxstream::aemu::BumpPool;
44
45#include "VkEncoder.cpp.inl"
46
47#define VALIDATE_RET(retType, success, validate) \\
48    retType goldfish_vk_validateResult = validate; \\
49    if (goldfish_vk_validateResult != success) return goldfish_vk_validateResult; \\
50
51#define VALIDATE_VOID(validate) \\
52    VkResult goldfish_vk_validateResult = validate; \\
53    if (goldfish_vk_validateResult != VK_SUCCESS) return; \\
54
55"""
56
57STREAM = "stream"
58RESOURCES = "sResourceTracker"
59POOL = "pool"
60
61ENCODER_PREVALIDATED_APIS = [
62    "vkFlushMappedMemoryRanges",
63    "vkInvalidateMappedMemoryRanges",
64]
65
66ENCODER_CUSTOM_RESOURCE_PREPROCESS = [
67    "vkMapMemoryIntoAddressSpaceGOOGLE",
68    "vkDestroyDevice",
69]
70
71ENCODER_CUSTOM_RESOURCE_POSTPROCESS = [
72    "vkCreateInstance",
73    "vkCreateDevice",
74    "vkMapMemoryIntoAddressSpaceGOOGLE",
75    "vkGetPhysicalDeviceFeatures2",
76    "vkGetPhysicalDeviceFeatures2KHR",
77    "vkGetPhysicalDeviceProperties",
78    "vkGetPhysicalDeviceProperties2",
79    "vkGetPhysicalDeviceProperties2KHR",
80    "vkCreateDescriptorUpdateTemplate",
81    "vkCreateDescriptorUpdateTemplateKHR",
82    "vkGetPhysicalDeviceExternalSemaphoreProperties",
83    "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR",
84    "vkGetDeviceQueue",
85    "vkGetDeviceQueue2",
86]
87
88ENCODER_EXPLICIT_FLUSHED_APIS = [
89    "vkEndCommandBufferAsyncGOOGLE",
90    "vkQueueSubmitAsyncGOOGLE",
91    "vkQueueBindSparseAsyncGOOGLE",
92    "vkQueueWaitIdleAsyncGOOGLE",
93    "vkQueueSignalReleaseImageANDROID",
94    "vkDestroyDevice",
95]
96
97SUCCESS_RET_TYPES = {
98    "VkResult" : "VK_SUCCESS",
99    "void" : None,
100    # TODO: Put up success results for other return types here.
101}
102
103ENCODER_THIS_PARAM = makeVulkanTypeSimple(False, "VkEncoder", 1, "this")
104
105# Common components of encoding a Vulkan API call
106def make_event_handler_call(
107    handler_access,
108    api,
109    context_param,
110    input_result_param,
111    cgen,
112    suffix=""):
113    extraParams = [context_param.paramName]
114    if input_result_param:
115        extraParams.append(input_result_param)
116    return cgen.makeCallExpr( \
117               "%s->on_%s%s" % (handler_access, api.name, suffix),
118               extraParams + \
119                       [p.paramName for p in api.parameters[:-1]])
120
121def emit_custom_pre_validate(typeInfo, api, cgen):
122    if api.name in ENCODER_PREVALIDATED_APIS:
123        callExpr = \
124            make_event_handler_call( \
125                "mImpl->validation()", api,
126                ENCODER_THIS_PARAM,
127                SUCCESS_RET_TYPES[api.getRetTypeExpr()],
128                cgen)
129
130        if api.getRetTypeExpr() == "void":
131            cgen.stmt("VALIDATE_VOID(%s)" % callExpr)
132        else:
133            cgen.stmt("VALIDATE_RET(%s, %s, %s)" % \
134                (api.getRetTypeExpr(),
135                 SUCCESS_RET_TYPES[api.getRetTypeExpr()],
136                 callExpr))
137
138def emit_custom_resource_preprocess(typeInfo, api, cgen):
139    if api.name in ENCODER_CUSTOM_RESOURCE_PREPROCESS:
140        cgen.stmt( \
141            make_event_handler_call( \
142                "sResourceTracker", api,
143                ENCODER_THIS_PARAM,
144                SUCCESS_RET_TYPES[api.getRetTypeExpr()],
145                cgen, suffix="_pre"))
146
147def emit_custom_resource_postprocess(typeInfo, api, cgen):
148    if api.name in ENCODER_CUSTOM_RESOURCE_POSTPROCESS:
149        cgen.stmt(make_event_handler_call( \
150            "sResourceTracker",
151            api,
152            ENCODER_THIS_PARAM,
153            api.getRetVarExpr(),
154            cgen))
155
156def emit_count_marshal(typeInfo, param, cgen):
157    res = \
158        iterateVulkanType(
159            typeInfo, param,
160            VulkanCountingCodegen( \
161                cgen, "sFeatureBits", param.paramName, "countPtr", ROOT_TYPE_DEFAULT_VALUE,
162               "count_"))
163    if not res:
164        cgen.stmt("(void)%s" % param.paramName)
165
166def emit_marshal(typeInfo, param, cgen):
167    forOutput = param.isHandleType() and ("out" in param.inout)
168    if forOutput:
169        cgen.stmt("/* is handle, possibly out */")
170
171    res = \
172        iterateVulkanType(
173            typeInfo, param,
174            VulkanReservedMarshalingCodegen( \
175                cgen, "guest", STREAM, ROOT_TYPE_DEFAULT_VALUE, param.paramName, "streamPtrPtr",
176               API_PREFIX_RESERVEDMARSHAL,
177               "" if forOutput else "get_host_u64_",
178               direction="write"))
179    if not res:
180        cgen.stmt("(void)%s" % param.paramName)
181
182    if forOutput:
183        cgen.stmt("/* is handle, possibly out */")
184
185def emit_unmarshal(typeInfo, param, cgen):
186    iterateVulkanType(
187        typeInfo, param,
188        VulkanMarshalingCodegen( \
189            cgen, STREAM, ROOT_TYPE_DEFAULT_VALUE, param.paramName,
190           API_PREFIX_UNMARSHAL, direction="read"))
191
192def emit_deepcopy(typeInfo, param, cgen):
193    res = \
194        iterateVulkanType(typeInfo, param, DeepcopyCodegen(
195            cgen, [param.paramName, "local_" + param.paramName], "pool", ROOT_TYPE_DEFAULT_VALUE, "deepcopy_"))
196    if not res:
197        cgen.stmt("(void)%s" % param.paramName)
198
199def emit_transform(typeInfo, param, cgen, variant="tohost"):
200    res = \
201        iterateVulkanType(typeInfo, param, TransformCodegen( \
202            cgen, param.paramName, "sResourceTracker", "transform_%s_" % variant, variant))
203    if not res:
204        cgen.stmt("(void)%s" % param.paramName)
205
206def emit_handlemap_create(typeInfo, param, cgen):
207    iterateVulkanType(typeInfo, param, HandleMapCodegen(
208        cgen, None, "sResourceTracker", "handlemap_",
209        lambda vtype: typeInfo.isHandleType(vtype.typeName)
210    ))
211
212def custom_encoder_args(api):
213    params = ["this"]
214    if api.getRetVarExpr() is not None:
215        params.append(api.getRetVarExpr())
216    return params
217
218def emit_handlemap_destroy(typeInfo, param, cgen):
219    iterateVulkanType(typeInfo, param, HandleMapCodegen(
220        cgen, None, "sResourceTracker->destroyMapping()", "handlemap_",
221        lambda vtype: typeInfo.isHandleType(vtype.typeName)
222    ))
223
224class EncodingParameters(object):
225    def __init__(self, api):
226        self.localCopied = []
227        self.toWrite = []
228        self.toRead = []
229        self.toCreate = []
230        self.toDestroy = []
231
232        for param in api.parameters:
233            param.action = None
234            param.inout = "in"
235
236            if param.paramName == "doLock":
237                continue
238
239            if param.possiblyOutput():
240                param.inout += "out"
241                self.toWrite.append(param)
242                self.toRead.append(param)
243                if param.isCreatedBy(api):
244                    self.toCreate.append(param)
245                    param.action = "create"
246            else:
247
248                if param.paramName == "doLock":
249                    continue
250
251                if param.isDestroyedBy(api):
252                    self.toDestroy.append(param)
253                    param.action = "destroy"
254                localCopyParam = \
255                    param.getForNonConstAccess().withModifiedName( \
256                        "local_" + param.paramName)
257                self.localCopied.append((param, localCopyParam))
258                self.toWrite.append(localCopyParam)
259
260def emit_parameter_encode_preamble_write(typeInfo, api, cgen):
261    emit_custom_pre_validate(typeInfo, api, cgen);
262    emit_custom_resource_preprocess(typeInfo, api, cgen);
263
264    cgen.stmt("auto %s = mImpl->stream()" % STREAM)
265    cgen.stmt("auto %s = mImpl->pool()" % POOL)
266    # cgen.stmt("%s->setHandleMapping(%s->unwrapMapping())" % (STREAM, RESOURCES))
267
268    encodingParams = EncodingParameters(api)
269    for (_, localCopyParam) in encodingParams.localCopied:
270        cgen.stmt(cgen.makeRichCTypeDecl(localCopyParam))
271
272def emit_parameter_encode_copy_unwrap_count(typeInfo, api, cgen, customUnwrap=None):
273    encodingParams = EncodingParameters(api)
274
275    for (origParam, localCopyParam) in encodingParams.localCopied:
276        shouldCustomCopy = \
277            customUnwrap and \
278            origParam.paramName in customUnwrap and \
279            "copyOp" in customUnwrap[origParam.paramName]
280
281        shouldCustomMap = \
282            customUnwrap and \
283            origParam.paramName in customUnwrap and \
284            "mapOp" in customUnwrap[origParam.paramName]
285
286        if shouldCustomCopy:
287            customUnwrap[origParam.paramName]["copyOp"](cgen, origParam, localCopyParam)
288        else:
289            # if this is a pointer type and we don't do custom copy nor unwrap,
290            # and the transform doesn't end up doing anything,
291            # don't deepcopy, just cast it.
292
293            avoidDeepcopy = False
294
295            if origParam.pointerIndirectionLevels > 0:
296                testCgen = CodeGen()
297                genTransformsForVulkanType("sResourceTracker", origParam, lambda p: testCgen.generalAccess(p, parentVarName = None, asPtr = True), lambda p: testCgen.generalLengthAccess(p, parentVarName = None), testCgen)
298                emit_transform(typeInfo, origParam, testCgen, variant="tohost")
299                if "" == testCgen.swapCode():
300                    avoidDeepcopy = True
301            if avoidDeepcopy:
302                cgen.line("// Avoiding deepcopy for %s" % origParam.paramName)
303                cgen.stmt("%s = (%s%s)%s" % (localCopyParam.paramName, localCopyParam.typeName, "*" * origParam.pointerIndirectionLevels, origParam.paramName))
304            else:
305                emit_deepcopy(typeInfo, origParam, cgen)
306
307    for (origParam, localCopyParam) in encodingParams.localCopied:
308        shouldCustomMap = \
309            customUnwrap and \
310            origParam.paramName in customUnwrap and \
311            "mapOp" in customUnwrap[origParam.paramName]
312
313        if shouldCustomMap:
314            customUnwrap[origParam.paramName]["mapOp"](cgen, origParam, localCopyParam)
315        else:
316            if localCopyParam.typeName == "VkAllocationCallbacks":
317                cgen.stmt("%s = nullptr" % localCopyParam.paramName)
318
319    apiForTransform = \
320        api.withCustomParameters( \
321            map(lambda p: p[1], \
322                encodingParams.localCopied))
323
324    # Apply transforms if applicable.
325    # Apply transform to API itself:
326    genTransformsForVulkanType(
327        "sResourceTracker",
328        apiForTransform,
329        lambda p: cgen.generalAccess(p, parentVarName = None, asPtr = True),
330        lambda p: cgen.generalLengthAccess(p, parentVarName = None),
331        cgen)
332
333    # For all local copied parameters, run the transforms
334    for localParam in apiForTransform.parameters:
335        if "doLock" in localParam.paramName:
336            continue
337        emit_transform(typeInfo, localParam, cgen, variant="tohost")
338
339    cgen.stmt("size_t count = 0")
340    cgen.stmt("size_t* countPtr = &count")
341    cgen.beginBlock()
342
343    # Use counting stream to calculate the packet size.
344    for p in encodingParams.toWrite:
345        emit_count_marshal(typeInfo, p, cgen)
346
347    cgen.endBlock()
348
349def is_cmdbuf_dispatch(api):
350    return "VkCommandBuffer" == api.parameters[0].typeName
351
352def emit_parameter_encode_write_packet_info(typeInfo, api, cgen):
353    # Seqno and skipping dispatch serialize are for use with VULKAN_STREAM_FEATURE_QUEUE_SUBMIT_WITH_COMMANDS_BIT
354    doSeqno = True
355    doDispatchSerialize = True
356
357    if is_cmdbuf_dispatch(api):
358        doSeqno = False
359        doDispatchSerialize = False
360
361    if doSeqno:
362        cgen.stmt("uint32_t packetSize_%s = 4 + 4 + (queueSubmitWithCommandsEnabled ? 4 : 0) + count" % (api.name))
363    else:
364        cgen.stmt("uint32_t packetSize_%s = 4 + 4 + count" % (api.name))
365
366    if not doDispatchSerialize:
367        cgen.stmt("if (queueSubmitWithCommandsEnabled) packetSize_%s -= 8" % api.name)
368
369    cgen.stmt("uint8_t* streamPtr = %s->reserve(packetSize_%s)" % (STREAM, api.name))
370    cgen.stmt("uint8_t* packetBeginPtr = streamPtr")
371    cgen.stmt("uint8_t** streamPtrPtr = &streamPtr")
372    cgen.stmt("uint32_t opcode_%s = OP_%s" % (api.name, api.name))
373
374    if doSeqno:
375        cgen.stmt("uint32_t seqno; if (queueSubmitWithCommandsEnabled) seqno = ResourceTracker::nextSeqno()")
376
377    cgen.stmt("memcpy(streamPtr, &opcode_%s, sizeof(uint32_t)); streamPtr += sizeof(uint32_t)" % api.name)
378    cgen.stmt("memcpy(streamPtr, &packetSize_%s, sizeof(uint32_t)); streamPtr += sizeof(uint32_t)" % api.name)
379
380    if doSeqno:
381        cgen.line("if (queueSubmitWithCommandsEnabled) { memcpy(streamPtr, &seqno, sizeof(uint32_t)); streamPtr += sizeof(uint32_t); }")
382
383def emit_parameter_encode_do_parameter_write(typeInfo, api, cgen):
384    encodingParams = EncodingParameters(api)
385
386    dispatchDone = False
387
388    for p in encodingParams.toWrite:
389        if is_cmdbuf_dispatch(api) and not dispatchDone:
390            cgen.beginIf("!queueSubmitWithCommandsEnabled")
391            emit_marshal(typeInfo, p, cgen)
392            cgen.endIf()
393        else:
394            emit_marshal(typeInfo, p, cgen)
395
396        dispatchDone = True
397
398def emit_parameter_encode_read(typeInfo, api, cgen):
399    encodingParams = EncodingParameters(api)
400
401    for p in encodingParams.toRead:
402        if p.action == "create":
403            cgen.stmt(
404                "%s->setHandleMapping(%s->createMapping())" % \
405                (STREAM, RESOURCES))
406        emit_unmarshal(typeInfo, p, cgen)
407        if p.action == "create":
408            cgen.stmt(
409                "%s->unsetHandleMapping()" % STREAM)
410        emit_transform(typeInfo, p, cgen, variant="fromhost")
411
412def emit_post(typeInfo, api, cgen):
413    encodingParams = EncodingParameters(api)
414
415    emit_custom_resource_postprocess(typeInfo, api, cgen)
416
417    for p in encodingParams.toDestroy:
418        emit_handlemap_destroy(typeInfo, p, cgen)
419
420    doSeqno = True
421    if is_cmdbuf_dispatch(api):
422        doSeqno = False
423
424    retType = api.getRetTypeExpr()
425
426    if api.name in ENCODER_EXPLICIT_FLUSHED_APIS:
427        cgen.stmt("stream->flush()");
428        return
429
430    if doSeqno:
431        if retType == "void":
432            encodingParams = EncodingParameters(api)
433            if 0 == len(encodingParams.toRead):
434                cgen.stmt("stream->flush()");
435
436def emit_pool_free(cgen):
437    cgen.stmt("++encodeCount")
438    cgen.beginIf("0 == encodeCount % POOL_CLEAR_INTERVAL")
439    cgen.stmt("pool->freeAll()")
440    cgen.stmt("%s->clearPool()" % STREAM)
441    cgen.endIf()
442
443def emit_return_unmarshal(typeInfo, api, cgen):
444
445    retType = api.getRetTypeExpr()
446
447    if retType == "void":
448        return
449
450    retVar = api.getRetVarExpr()
451    cgen.stmt("%s %s = (%s)0" % (retType, retVar, retType))
452    cgen.stmt("%s->read(&%s, %s)" % \
453              (STREAM, retVar, cgen.sizeofExpr(api.retType)))
454
455def emit_return(typeInfo, api, cgen):
456    if api.getRetTypeExpr() == "void":
457        return
458
459    retVar = api.getRetVarExpr()
460    cgen.stmt("return %s" % retVar)
461
462def emit_lock(cgen):
463    cgen.stmt("(void)doLock");
464    cgen.stmt("bool queueSubmitWithCommandsEnabled = sFeatureBits & VULKAN_STREAM_FEATURE_QUEUE_SUBMIT_WITH_COMMANDS_BIT")
465    cgen.stmt("if (!queueSubmitWithCommandsEnabled && doLock) this->lock()")
466
467def emit_unlock(cgen):
468    cgen.stmt("if (!queueSubmitWithCommandsEnabled && doLock) this->unlock()")
469
470def emit_debug_log(typeInfo, api, cgen):
471    logFormat = []
472    logVargs = []
473    for param in api.parameters:
474        if param.paramName == "doLock":
475            continue
476
477        paramFormatSpecifier = param.getPrintFormatSpecifier()
478        if not paramFormatSpecifier:
479            continue
480
481        logFormat.append(param.paramName + ":" + paramFormatSpecifier)
482        logVargs.append(param.paramName)
483
484    logFormatStr = ", ".join(logFormat)
485    logVargsStr = ", ".join(logVargs)
486
487def emit_default_encoding(typeInfo, api, cgen):
488    emit_debug_log(typeInfo, api, cgen)
489    emit_lock(cgen)
490    emit_parameter_encode_preamble_write(typeInfo, api, cgen)
491    emit_parameter_encode_copy_unwrap_count(typeInfo, api, cgen)
492    emit_parameter_encode_write_packet_info(typeInfo, api, cgen)
493    emit_parameter_encode_do_parameter_write(typeInfo, api, cgen)
494    emit_parameter_encode_read(typeInfo, api, cgen)
495    emit_return_unmarshal(typeInfo, api, cgen)
496    emit_post(typeInfo, api, cgen)
497    emit_pool_free(cgen)
498    emit_unlock(cgen)
499    emit_return(typeInfo, api, cgen)
500
501## Custom encoding definitions##################################################
502
503def emit_only_goldfish_custom(typeInfo, api, cgen):
504    emit_lock(cgen)
505    cgen.vkApiCall( \
506        api,
507        customPrefix="sResourceTracker->on_",
508        customParameters=custom_encoder_args(api) + \
509                [p.paramName for p in api.parameters[:-1]])
510    emit_unlock(cgen)
511    emit_return(typeInfo, api, cgen)
512
513def emit_only_resource_event(typeInfo, api, cgen):
514    cgen.stmt("(void)doLock");
515    input_result = None
516    retExpr = api.getRetVarExpr()
517
518    if retExpr:
519        retType = api.getRetTypeExpr()
520        input_result = SUCCESS_RET_TYPES[retType]
521        cgen.stmt("%s %s = (%s)0" % (retType, retExpr, retType))
522
523    cgen.stmt(
524        (("%s = " % retExpr) if retExpr else "") +
525        make_event_handler_call(
526            "sResourceTracker",
527            api,
528            ENCODER_THIS_PARAM,
529            input_result, cgen))
530
531    if retExpr:
532        emit_return(typeInfo, api, cgen)
533
534def emit_with_custom_unwrap(custom):
535    def call(typeInfo, api, cgen):
536        emit_lock(cgen)
537        emit_parameter_encode_preamble_write(typeInfo, api, cgen)
538        emit_parameter_encode_copy_unwrap_count(
539            typeInfo, api, cgen, customUnwrap=custom)
540        emit_parameter_encode_write_packet_info(typeInfo, api, cgen)
541        emit_parameter_encode_do_parameter_write(typeInfo, api, cgen)
542        emit_parameter_encode_read(typeInfo, api, cgen)
543        emit_return_unmarshal(typeInfo, api, cgen)
544        emit_pool_free(cgen)
545        emit_unlock(cgen)
546        emit_return(typeInfo, api, cgen)
547    return call
548
549def encode_vkFlushMappedMemoryRanges(typeInfo, api, cgen):
550    emit_lock(cgen)
551    emit_parameter_encode_preamble_write(typeInfo, api, cgen)
552    emit_parameter_encode_copy_unwrap_count(typeInfo, api, cgen)
553
554    def emit_flush_ranges(streamVar):
555        cgen.beginIf("!sResourceTracker->usingDirectMapping()")
556        cgen.beginFor("uint32_t i = 0", "i < memoryRangeCount", "++i")
557        cgen.stmt("auto range = pMemoryRanges[i]")
558        cgen.stmt("auto memory = pMemoryRanges[i].memory")
559        cgen.stmt("auto size = pMemoryRanges[i].size")
560        cgen.stmt("auto offset = pMemoryRanges[i].offset")
561        cgen.stmt("uint64_t streamSize = 0")
562        cgen.stmt("if (!memory) { %s->write(&streamSize, sizeof(uint64_t)); continue; }" % streamVar)
563        cgen.stmt("auto hostPtr = sResourceTracker->getMappedPointer(memory)")
564        cgen.stmt("auto actualSize = size == VK_WHOLE_SIZE ? sResourceTracker->getMappedSize(memory) : size")
565        cgen.stmt("if (!hostPtr) { %s->write(&streamSize, sizeof(uint64_t)); continue; }" % streamVar)
566        cgen.stmt("streamSize = actualSize")
567        cgen.stmt("%s->write(&streamSize, sizeof(uint64_t))" % streamVar)
568        cgen.stmt("uint8_t* targetRange = hostPtr + offset")
569        cgen.stmt("%s->write(targetRange, actualSize)" % streamVar)
570        cgen.endFor()
571        cgen.endIf()
572
573    emit_parameter_encode_write_packet_info(typeInfo, api, cgen)
574    emit_parameter_encode_do_parameter_write(typeInfo, api, cgen)
575
576    emit_flush_ranges(STREAM)
577
578    emit_parameter_encode_read(typeInfo, api, cgen)
579    emit_return_unmarshal(typeInfo, api, cgen)
580    emit_pool_free(cgen)
581    emit_unlock(cgen)
582    emit_return(typeInfo, api, cgen)
583
584def encode_vkInvalidateMappedMemoryRanges(typeInfo, api, cgen):
585    emit_lock(cgen)
586    emit_parameter_encode_preamble_write(typeInfo, api, cgen)
587    emit_parameter_encode_copy_unwrap_count(typeInfo, api, cgen)
588    emit_parameter_encode_write_packet_info(typeInfo, api, cgen)
589    emit_parameter_encode_do_parameter_write(typeInfo, api, cgen)
590    emit_parameter_encode_read(typeInfo, api, cgen)
591    emit_return_unmarshal(typeInfo, api, cgen)
592
593    def emit_invalidate_ranges(streamVar):
594        cgen.beginIf("!sResourceTracker->usingDirectMapping()")
595        cgen.beginFor("uint32_t i = 0", "i < memoryRangeCount", "++i")
596        cgen.stmt("auto range = pMemoryRanges[i]")
597        cgen.stmt("auto memory = pMemoryRanges[i].memory")
598        cgen.stmt("auto size = pMemoryRanges[i].size")
599        cgen.stmt("auto offset = pMemoryRanges[i].offset")
600        cgen.stmt("uint64_t streamSize = 0")
601        cgen.stmt("if (!memory) { %s->read(&streamSize, sizeof(uint64_t)); continue; }" % streamVar)
602        cgen.stmt("auto hostPtr = sResourceTracker->getMappedPointer(memory)")
603        cgen.stmt("auto actualSize = size == VK_WHOLE_SIZE ? sResourceTracker->getMappedSize(memory) : size")
604        cgen.stmt("if (!hostPtr) { %s->read(&streamSize, sizeof(uint64_t)); continue; }" % streamVar)
605        cgen.stmt("streamSize = actualSize")
606        cgen.stmt("%s->read(&streamSize, sizeof(uint64_t))" % streamVar)
607        cgen.stmt("uint8_t* targetRange = hostPtr + offset")
608        cgen.stmt("%s->read(targetRange, actualSize)" % streamVar)
609        cgen.endFor()
610        cgen.endIf()
611
612    emit_invalidate_ranges(STREAM)
613    emit_pool_free(cgen)
614    emit_unlock(cgen)
615    emit_return(typeInfo, api, cgen)
616
617def emit_manual_inline(typeInfo, api, cgen):
618    cgen.line("#include \"%s_encode_impl.cpp.inl\"" % api.name)
619
620def unwrap_vkCreateImage_pCreateInfo():
621    def mapOp(cgen, orig, local):
622        cgen.stmt("sResourceTracker->unwrap_vkCreateImage_pCreateInfo(%s, %s)" %
623                  (orig.paramName, local.paramName))
624    return { "pCreateInfo" : { "mapOp" : mapOp } }
625
626def unwrap_vkBindImageMemory2_pBindInfos():
627    def mapOp(cgen, orig, local):
628        cgen.stmt("sResourceTracker->unwrap_VkBindImageMemory2_pBindInfos(bindInfoCount, %s, %s)" %
629                  (orig.paramName, local.paramName))
630    return { "pBindInfos" : { "mapOp" : mapOp } }
631
632def unwrap_vkAcquireImageANDROID_nativeFenceFd():
633    def mapOp(cgen, orig, local):
634        cgen.stmt("sResourceTracker->unwrap_vkAcquireImageANDROID_nativeFenceFd(%s, &%s)" %
635                  (orig.paramName, local.paramName))
636    return { "nativeFenceFd" : { "mapOp" : mapOp } }
637
638custom_encodes = {
639    "vkMapMemory" : emit_only_resource_event,
640    "vkUnmapMemory" : emit_only_resource_event,
641    "vkFlushMappedMemoryRanges" : encode_vkFlushMappedMemoryRanges,
642    "vkInvalidateMappedMemoryRanges" : encode_vkInvalidateMappedMemoryRanges,
643    "vkCreateImage" : emit_with_custom_unwrap(unwrap_vkCreateImage_pCreateInfo()),
644    "vkCreateImageWithRequirementsGOOGLE" : emit_with_custom_unwrap(unwrap_vkCreateImage_pCreateInfo()),
645    "vkBindImageMemory2": emit_with_custom_unwrap(unwrap_vkBindImageMemory2_pBindInfos()),
646    "vkAcquireImageANDROID" : emit_with_custom_unwrap(unwrap_vkAcquireImageANDROID_nativeFenceFd()),
647    "vkQueueFlushCommandsGOOGLE" : emit_manual_inline,
648}
649
650class VulkanEncoder(VulkanWrapperGenerator):
651    def __init__(self, module, typeInfo):
652        VulkanWrapperGenerator.__init__(self, module, typeInfo)
653
654        self.typeInfo = typeInfo
655
656        self.cgenHeader = CodeGen()
657        self.cgenHeader.incrIndent()
658
659        self.cgenImpl = CodeGen()
660
661    def onBegin(self,):
662        self.module.appendHeader(encoder_decl_preamble)
663        self.module.appendImpl(encoder_impl_preamble)
664
665    def onGenCmd(self, cmdinfo, name, alias):
666        VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
667
668        api = copy.deepcopy(self.typeInfo.apis[name])
669        api.parameters.append(makeVulkanTypeSimple(False, "uint32_t", 0, "doLock"))
670
671        self.cgenHeader.stmt(self.cgenHeader.makeFuncProto(api))
672        apiImpl = api.withModifiedName("VkEncoder::" + api.name)
673
674        self.module.appendHeader(self.cgenHeader.swapCode())
675
676        def emit_function_impl(cgen):
677            if api.name in custom_encodes.keys():
678                custom_encodes[api.name](self.typeInfo, api, cgen)
679            else:
680                emit_default_encoding(self.typeInfo, api, cgen)
681
682        self.module.appendImpl(self.cgenImpl.makeFuncImpl(apiImpl, emit_function_impl))
683
684    def onEnd(self,):
685        self.module.appendHeader(encoder_decl_postamble)
686        self.cgenHeader.decrIndent()
687