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