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