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