• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2018 Google LLC
2# SPDX-License-Identifier: MIT
3
4from .common.codegen import CodeGen, VulkanWrapperGenerator, VulkanAPIWrapper
5from .common.vulkantypes import \
6        VulkanAPI, makeVulkanTypeSimple, iterateVulkanType, DISPATCHABLE_HANDLE_TYPES, NON_DISPATCHABLE_HANDLE_TYPES
7
8from .transform import TransformCodegen, genTransformsForVulkanType
9
10from .wrapperdefs import API_PREFIX_MARSHAL
11from .wrapperdefs import API_PREFIX_UNMARSHAL
12from .wrapperdefs import VULKAN_STREAM_TYPE
13
14from copy import copy
15from dataclasses import dataclass
16
17decoder_snapshot_decl_preamble = """
18
19namespace android {
20namespace base {
21class BumpPool;
22class Stream;
23} // namespace base {
24} // namespace android {
25
26namespace gfxstream {
27namespace vk {
28
29class VkDecoderSnapshot {
30  public:
31    VkDecoderSnapshot();
32    ~VkDecoderSnapshot();
33
34    void clear();
35
36    void saveReplayBuffers(android::base::Stream* stream);
37    static void loadReplayBuffers(android::base::Stream* stream, std::vector<uint64_t>* outHandleBuffer, std::vector<uint8_t>* outDecoderBuffer);
38
39    VkSnapshotApiCallInfo* createApiCallInfo();
40    void destroyApiCallInfoIfUnused(VkSnapshotApiCallInfo* info);
41"""
42
43decoder_snapshot_decl_postamble = """
44  private:
45    class Impl;
46    std::unique_ptr<Impl> mImpl;
47
48};
49
50}  // namespace vk
51}  // namespace gfxstream
52"""
53
54decoder_snapshot_impl_preamble ="""
55
56using emugl::GfxApiLogger;
57using emugl::HealthMonitor;
58
59namespace gfxstream {
60namespace vk {
61
62class VkDecoderSnapshot::Impl {
63  public:
64    Impl() { }
65
66    void clear() {
67        std::lock_guard<std::mutex> lock(mReconstructionMutex);
68        mReconstruction.clear();
69    }
70
71    void saveReplayBuffers(android::base::Stream* stream) {
72        std::lock_guard<std::mutex> lock(mReconstructionMutex);
73        mReconstruction.saveReplayBuffers(stream);
74    }
75
76    static void loadReplayBuffers(android::base::Stream* stream, std::vector<uint64_t>* outHandleBuffer, std::vector<uint8_t>* outDecoderBuffer) {
77        VkReconstruction::loadReplayBuffers(stream, outHandleBuffer, outDecoderBuffer);
78    }
79
80    VkSnapshotApiCallInfo* createApiCallInfo() {
81        std::lock_guard<std::mutex> lock(mReconstructionMutex);
82        return mReconstruction.createApiCallInfo();
83    }
84
85    void destroyApiCallInfoIfUnused(VkSnapshotApiCallInfo* info) {
86        std::lock_guard<std::mutex> lock(mReconstructionMutex);
87        return mReconstruction.destroyApiCallInfoIfUnused(info);
88    }
89"""
90
91decoder_snapshot_impl_postamble = """
92  private:
93    std::mutex mReconstructionMutex;
94    VkReconstruction mReconstruction GUARDED_BY(mReconstructionMutex);
95};
96
97VkDecoderSnapshot::VkDecoderSnapshot() :
98    mImpl(new VkDecoderSnapshot::Impl()) { }
99
100void VkDecoderSnapshot::clear() {
101    mImpl->clear();
102}
103
104void VkDecoderSnapshot::saveReplayBuffers(android::base::Stream* stream) {
105    mImpl->saveReplayBuffers(stream);
106}
107
108/*static*/
109void VkDecoderSnapshot::loadReplayBuffers(android::base::Stream* stream, std::vector<uint64_t>* outHandleBuffer, std::vector<uint8_t>* outDecoderBuffer) {
110    VkDecoderSnapshot::Impl::loadReplayBuffers(stream, outHandleBuffer, outDecoderBuffer);
111}
112
113VkSnapshotApiCallInfo* VkDecoderSnapshot::createApiCallInfo() {
114    return mImpl->createApiCallInfo();
115}
116
117void VkDecoderSnapshot::destroyApiCallInfoIfUnused(VkSnapshotApiCallInfo* info) {
118    mImpl->destroyApiCallInfoIfUnused(info);
119}
120
121VkDecoderSnapshot::~VkDecoderSnapshot() = default;
122"""
123
124decoder_snapshot_namespace_postamble = """
125
126}  // namespace vk
127}  // namespace gfxstream
128
129"""
130
131
132AUXILIARY_SNAPSHOT_API_BASE_PARAM_COUNT = 3
133
134AUXILIARY_SNAPSHOT_API_PARAM_NAMES = [
135    "input_result",
136]
137
138# Vulkan handle dependencies.
139# (a, b): a depends on b
140SNAPSHOT_HANDLE_DEPENDENCIES = [
141    # Dispatchable handle types
142    ("VkCommandBuffer", "VkCommandPool"),
143    ("VkCommandPool", "VkDevice"),
144    ("VkQueue", "VkDevice"),
145    ("VkDevice", "VkPhysicalDevice"),
146    ("VkPhysicalDevice", "VkInstance")] + \
147    list(map(lambda handleType : (handleType, "VkDevice"), NON_DISPATCHABLE_HANDLE_TYPES))
148
149handleDependenciesDict = dict(SNAPSHOT_HANDLE_DEPENDENCIES)
150
151def extract_deps_vkAllocateMemory(param, access, lenExpr, api, cgen):
152    cgen.stmt("const VkMemoryDedicatedAllocateInfo* dedicatedAllocateInfo = vk_find_struct<VkMemoryDedicatedAllocateInfo>(pAllocateInfo)");
153    cgen.beginIf("dedicatedAllocateInfo");
154    cgen.beginIf("dedicatedAllocateInfo->image")
155    cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)%s, %s, (uint64_t)(uintptr_t)%s)" % \
156              (access, lenExpr, "unboxed_to_boxed_non_dispatchable_VkImage(dedicatedAllocateInfo->image)"))
157    cgen.endIf()
158    cgen.beginIf("dedicatedAllocateInfo->buffer")
159    cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)%s, %s, (uint64_t)(uintptr_t)%s)" % \
160              (access, lenExpr, "unboxed_to_boxed_non_dispatchable_VkBuffer(dedicatedAllocateInfo->buffer)"))
161    cgen.endIf()
162    cgen.endIf()
163
164def extract_deps_vkAllocateCommandBuffers(param, access, lenExpr, api, cgen):
165    cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)%s, %s, (uint64_t)(uintptr_t)%s)" % \
166              (access, lenExpr, "unboxed_to_boxed_non_dispatchable_VkCommandPool(pAllocateInfo->commandPool)"))
167
168def extract_deps_vkAllocateDescriptorSets(param, access, lenExpr, api, cgen):
169    cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)%s, %s, (uint64_t)(uintptr_t)%s)" % \
170              (access, lenExpr, "unboxed_to_boxed_non_dispatchable_VkDescriptorPool(pAllocateInfo->descriptorPool)"))
171
172def extract_deps_vkUpdateDescriptorSets(param, access, lenExpr, api, cgen):
173    cgen.beginFor("uint32_t i = 0", "i < descriptorWriteCount", "++i")
174    cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)(&handle), 1, (uint64_t)(uintptr_t)unboxed_to_boxed_non_dispatchable_VkDescriptorSet( pDescriptorWrites[i].dstSet))")
175    cgen.beginFor("uint32_t j = 0", "j < pDescriptorWrites[i].descriptorCount", "++j")
176    cgen.beginIf("(pDescriptorWrites[i].pImageInfo)")
177    cgen.beginIf("pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER")
178    cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)(&handle), 1, (uint64_t)(uintptr_t)unboxed_to_boxed_non_dispatchable_VkSampler( pDescriptorWrites[i].pImageInfo[j].sampler))")
179    cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)(&handle), 1, (uint64_t)(uintptr_t)unboxed_to_boxed_non_dispatchable_VkImageView( pDescriptorWrites[i].pImageInfo[j].imageView))")
180    cgen.endIf()
181    cgen.beginIf("pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER")
182    cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)(&handle), 1, (uint64_t)(uintptr_t)unboxed_to_boxed_non_dispatchable_VkSampler( pDescriptorWrites[i].pImageInfo[j].sampler))")
183    cgen.endIf()
184    cgen.endIf()
185    cgen.beginIf("pDescriptorWrites[i].pBufferInfo");
186    cgen.beginIf("pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER");
187    cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)(&handle), 1, (uint64_t)(uintptr_t)unboxed_to_boxed_non_dispatchable_VkBuffer( pDescriptorWrites[i].pBufferInfo[j].buffer))")
188    cgen.endIf()
189    cgen.endIf()
190    cgen.endFor()
191    cgen.endFor()
192
193def extract_deps_vkCreateImageView(param, access, lenExpr, api, cgen):
194    cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)%s, %s, (uint64_t)(uintptr_t)%s, VkReconstruction::CREATED, VkReconstruction::BOUND_MEMORY)" % \
195              (access, lenExpr, "unboxed_to_boxed_non_dispatchable_VkImage(pCreateInfo->image)"))
196
197def extract_deps_vkCreateGraphicsPipelines(param, access, lenExpr, api, cgen):
198    cgen.beginFor("uint32_t i = 0", "i < createInfoCount", "++i")
199    cgen.beginFor("uint32_t j = 0", "j < pCreateInfos[i].stageCount", "++j")
200    cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)(%s + i), %s, (uint64_t)(uintptr_t)%s)" % \
201              (access, 1, "unboxed_to_boxed_non_dispatchable_VkShaderModule(pCreateInfos[i].pStages[j].module)"))
202    cgen.endFor()
203    cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)(%s + i), %s, (uint64_t)(uintptr_t)%s)" % \
204              (access, 1, "unboxed_to_boxed_non_dispatchable_VkRenderPass(pCreateInfos[i].renderPass)"))
205    cgen.endFor()
206
207def extract_deps_vkCreateFramebuffer(param, access, lenExpr, api, cgen):
208    cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)%s, %s, (uint64_t)(uintptr_t)%s)" % \
209              (access, lenExpr, "unboxed_to_boxed_non_dispatchable_VkRenderPass(pCreateInfo->renderPass)"))
210    cgen.beginFor("uint32_t i = 0", "i < pCreateInfo->attachmentCount" , "++i")
211    cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)%s, %s, (uint64_t)(uintptr_t)%s)" % \
212              (access, lenExpr, "unboxed_to_boxed_non_dispatchable_VkImageView(pCreateInfo->pAttachments[i])"))
213    cgen.endFor()
214
215def extract_deps_vkBindImageMemory(param, access, lenExpr, api, cgen):
216    cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)%s, %s, (uint64_t)(uintptr_t)%s, VkReconstruction::BOUND_MEMORY)" % \
217              (access, lenExpr, "unboxed_to_boxed_non_dispatchable_VkDeviceMemory(memory)"))
218    cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)%s, %s, (uint64_t)(uintptr_t)((%s)[0]), VkReconstruction::BOUND_MEMORY)" % \
219              (access, lenExpr, access))
220
221def extract_deps_vkBindBufferMemory(param, access, lenExpr, api, cgen):
222    cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)%s, %s, (uint64_t)(uintptr_t)%s, VkReconstruction::BOUND_MEMORY)" % \
223              (access, lenExpr, "unboxed_to_boxed_non_dispatchable_VkDeviceMemory(memory)"))
224    cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)%s, %s, (uint64_t)(uintptr_t)((%s)[0]), VkReconstruction::BOUND_MEMORY)" % \
225              (access, lenExpr, access))
226
227specialCaseDependencyExtractors = {
228    "vkAllocateCommandBuffers" : extract_deps_vkAllocateCommandBuffers,
229    "vkAllocateDescriptorSets" : extract_deps_vkAllocateDescriptorSets,
230    "vkAllocateMemory" : extract_deps_vkAllocateMemory,
231    "vkCreateImageView" : extract_deps_vkCreateImageView,
232    "vkCreateGraphicsPipelines" : extract_deps_vkCreateGraphicsPipelines,
233    "vkCreateFramebuffer" : extract_deps_vkCreateFramebuffer,
234    "vkBindImageMemory": extract_deps_vkBindImageMemory,
235    "vkBindBufferMemory": extract_deps_vkBindBufferMemory,
236    "vkUpdateDescriptorSets" : extract_deps_vkUpdateDescriptorSets,
237}
238
239apiSequences = {
240    "vkAllocateMemory" : ["vkAllocateMemory", "vkMapMemoryIntoAddressSpaceGOOGLE"]
241}
242
243@dataclass(frozen=True)
244class VkObjectState:
245    vk_object : str
246    state : str = "VkReconstruction::CREATED"
247
248# TODO: add vkBindImageMemory2 and vkBindBufferMemory2 into this list
249apiChangeState = {
250    "vkBindImageMemory": VkObjectState("image", "VkReconstruction::BOUND_MEMORY"),
251    "vkBindBufferMemory": VkObjectState("buffer", "VkReconstruction::BOUND_MEMORY"),
252}
253
254def api_special_implementation_vkBindImageMemory2(api, cgen):
255    childType = "VkImage"
256    parentType = "VkDeviceMemory"
257    childObj = "boxed_%s" % childType
258    parentObj = "boxed_%s" % parentType
259    cgen.stmt("std::lock_guard<std::mutex> lock(mReconstructionMutex)")
260    cgen.beginFor("uint32_t i = 0", "i < bindInfoCount", "++i")
261    cgen.stmt("%s boxed_%s = unboxed_to_boxed_non_dispatchable_%s(pBindInfos[i].image)"
262              % (childType, childType, childType))
263    cgen.stmt("%s boxed_%s = unboxed_to_boxed_non_dispatchable_%s(pBindInfos[i].memory)"
264              % (parentType, parentType, parentType))
265    cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)&%s, %s, (uint64_t)(uintptr_t)%s, VkReconstruction::BOUND_MEMORY)" % \
266              (childObj, "1", parentObj))
267    cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)&%s, %s, (uint64_t)(uintptr_t)%s, VkReconstruction::BOUND_MEMORY)" % \
268              (childObj, "1", childObj))
269    cgen.endFor()
270
271    cgen.stmt("auto apiCallHandle = apiCallInfo->handle")
272    cgen.stmt("mReconstruction.setApiTrace(apiCallInfo, apiCallPacket, apiCallPacketSize)")
273    cgen.line("// Note: the implementation does not work with bindInfoCount > 1");
274    cgen.beginFor("uint32_t i = 0", "i < bindInfoCount", "++i")
275    cgen.stmt("%s boxed_%s = unboxed_to_boxed_non_dispatchable_%s(pBindInfos[i].image)"
276              % (childType, childType, childType))
277    cgen.stmt(f"mReconstruction.forEachHandleAddApi((const uint64_t*)&{childObj}, {1}, apiCallHandle, VkReconstruction::BOUND_MEMORY)")
278    cgen.endFor()
279
280apiSpecialImplementation = {
281    "vkBindImageMemory2": api_special_implementation_vkBindImageMemory2,
282    "vkBindImageMemory2KHR": api_special_implementation_vkBindImageMemory2,
283}
284
285apiModifies = {
286    "vkMapMemoryIntoAddressSpaceGOOGLE" : ["memory"],
287    "vkGetBlobGOOGLE" : ["memory"],
288    "vkBeginCommandBuffer" : ["commandBuffer"],
289    "vkEndCommandBuffer" : ["commandBuffer"],
290}
291
292apiActions = {
293    "vkUpdateDescriptorSets" : ["pDescriptorWrites"],
294}
295
296apiClearModifiers = {
297    "vkResetCommandBuffer" : ["commandBuffer"],
298}
299
300delayedDestroys = [
301    "vkDestroyShaderModule",
302]
303
304# The following types are created and cached by other commands.
305# Thus we should not snapshot their "create" commands.
306skipCreatorSnapshotTypes = [
307    "VkQueue", # created by vkCreateDevice
308]
309
310def is_state_change_operation(api, param):
311    if param.isCreatedBy(api) and param.typeName not in skipCreatorSnapshotTypes:
312        return True
313    if api.name in apiChangeState:
314        if param.paramName == apiChangeState[api.name].vk_object:
315            return True
316    return False
317
318def get_target_state(api, param):
319    if param.isCreatedBy(api):
320        return "VkReconstruction::CREATED"
321    if api.name in apiActions:
322        return "VkReconstruction::CREATED"
323    if api.name in apiChangeState:
324        if param.paramName == apiChangeState[api.name].vk_object:
325            return apiChangeState[api.name].state
326    return None
327
328def is_action_operation(api, param):
329    if api.name in apiActions:
330        if param.paramName in apiActions[api.name]:
331            return True
332    return False
333
334def is_modify_operation(api, param):
335    if api.name in apiModifies:
336        if param.paramName in apiModifies[api.name]:
337            return True
338    if api.name.startswith('vkCmd') and param.paramName == 'commandBuffer':
339        return True
340    return False
341
342def is_clear_modifier_operation(api, param):
343    if api.name in apiClearModifiers:
344        if param.paramName in apiClearModifiers[api.name]:
345            return True
346
347
348def emit_impl(typeInfo, api, cgen):
349    if api.name in apiSpecialImplementation:
350        apiSpecialImplementation[api.name](api, cgen)
351    for p in api.parameters:
352        if not (p.isHandleType):
353            continue
354
355        lenExpr = cgen.generalLengthAccess(p)
356        lenAccessGuard = cgen.generalLengthAccessGuard(p)
357
358        if lenExpr is None:
359            lenExpr = "1"
360
361        # Note that in vkCreate*, the last parameter (the output) is boxed. But all input parameters are unboxed.
362
363        if p.pointerIndirectionLevels > 0:
364            access = p.paramName
365        else:
366            access = "(&%s)" % p.paramName
367
368        if is_state_change_operation(api, p):
369            if p.isCreatedBy(api):
370                boxed_access = access
371            else:
372                cgen.stmt("%s boxed_%s = unboxed_to_boxed_non_dispatchable_%s(%s[0])" % (p.typeName, p.typeName, p.typeName, access))
373                boxed_access = "&boxed_%s" % p.typeName
374            if p.pointerIndirectionLevels > 0:
375                cgen.stmt("if (!%s) return" % access)
376
377            cgen.stmt("std::lock_guard<std::mutex> lock(mReconstructionMutex)")
378            cgen.line("// %s create" % p.paramName)
379            if p.isCreatedBy(api):
380                cgen.stmt("mReconstruction.addHandles((const uint64_t*)%s, %s)" % (boxed_access, lenExpr));
381
382            if p.isCreatedBy(api) and p.typeName in handleDependenciesDict:
383                dependsOnType = handleDependenciesDict[p.typeName];
384                for p2 in api.parameters:
385                    if p2.typeName == dependsOnType:
386                        cgen.stmt("mReconstruction.addHandleDependency((const uint64_t*)%s, %s, (uint64_t)(uintptr_t)%s)" % (boxed_access, lenExpr, p2.paramName))
387            if api.name in specialCaseDependencyExtractors:
388                specialCaseDependencyExtractors[api.name](p, boxed_access, lenExpr, api, cgen)
389
390            cgen.stmt("auto apiCallHandle = apiCallInfo->handle")
391            cgen.stmt("mReconstruction.setApiTrace(apiCallInfo, apiCallPacket, apiCallPacketSize)")
392            if lenAccessGuard is not None:
393                cgen.beginIf(lenAccessGuard)
394            cgen.stmt(f"mReconstruction.forEachHandleAddApi((const uint64_t*){boxed_access}, {lenExpr}, apiCallHandle, {get_target_state(api, p)})")
395            if p.isCreatedBy(api):
396                cgen.stmt("mReconstruction.setCreatedHandlesForApi(apiCallHandle, (const uint64_t*)%s, %s)" % (boxed_access, lenExpr))
397            if lenAccessGuard is not None:
398                cgen.endIf()
399
400        if p.isDestroyedBy(api):
401            cgen.stmt("std::lock_guard<std::mutex> lock(mReconstructionMutex)")
402            cgen.line("// %s destroy" % p.paramName)
403            if lenAccessGuard is not None:
404                cgen.beginIf(lenAccessGuard)
405            shouldRecursiveDestroy = "false" if api.name in delayedDestroys else "true"
406            cgen.stmt("mReconstruction.removeHandles((const uint64_t*)%s, %s, %s)" % (access, lenExpr, shouldRecursiveDestroy));
407            if lenAccessGuard is not None:
408                cgen.endIf()
409
410        if is_action_operation(api, p):
411            cgen.stmt("std::lock_guard<std::mutex> lock(mReconstructionMutex)")
412            cgen.line("// %s action" % p.paramName)
413            cgen.stmt("VkDecoderGlobalState* m_state = VkDecoderGlobalState::get()")
414            cgen.beginIf("m_state->batchedDescriptorSetUpdateEnabled()")
415            cgen.stmt("return")
416            cgen.endIf();
417            cgen.stmt("uint64_t handle = m_state->newGlobalVkGenericHandle()")
418            cgen.stmt("mReconstruction.addHandles((const uint64_t*)(&handle), 1)");
419            cgen.stmt("auto apiCallHandle = apiCallInfo->handle")
420            cgen.stmt("mReconstruction.setApiTrace(apiCallInfo, apiCallPacket, apiCallPacketSize)")
421            if api.name in specialCaseDependencyExtractors:
422                specialCaseDependencyExtractors[api.name](p, None, None, api, cgen)
423            cgen.stmt(f"mReconstruction.forEachHandleAddApi((const uint64_t*)(&handle), 1, apiCallHandle, {get_target_state(api, p)})")
424            cgen.stmt("mReconstruction.setCreatedHandlesForApi(apiCallHandle, (const uint64_t*)(&handle), 1)")
425
426        elif is_modify_operation(api, p) or is_clear_modifier_operation(api, p):
427            cgen.stmt("std::lock_guard<std::mutex> lock(mReconstructionMutex)")
428            cgen.line("// %s modify" % p.paramName)
429            cgen.stmt("auto apiCallHandle = apiCallInfo->handle")
430            cgen.stmt("mReconstruction.setApiTrace(apiCallInfo, apiCallPacket, apiCallPacketSize)")
431            if lenAccessGuard is not None:
432                cgen.beginIf(lenAccessGuard)
433            cgen.beginFor("uint32_t i = 0", "i < %s" % lenExpr, "++i")
434            if p.isNonDispatchableHandleType():
435                cgen.stmt("%s boxed = unboxed_to_boxed_non_dispatchable_%s(%s[i])" % (p.typeName, p.typeName, access))
436            else:
437                cgen.line("// %s is already boxed, no need to box again" % p.paramName)
438                cgen.stmt("%s boxed = %s(%s[i])" % (p.typeName, p.typeName, access))
439            if is_modify_operation(api, p):
440                cgen.stmt("mReconstruction.forEachHandleAddModifyApi((const uint64_t*)(&boxed), 1, apiCallHandle)")
441            else: # is clear modifier operation
442                cgen.stmt("mReconstruction.forEachHandleClearModifyApi((const uint64_t*)(&boxed), 1)")
443            cgen.endFor()
444            if lenAccessGuard is not None:
445                cgen.endIf()
446
447def emit_passthrough_to_impl(typeInfo, api, cgen):
448    cgen.vkApiCall(api, customPrefix = "mImpl->")
449
450class VulkanDecoderSnapshot(VulkanWrapperGenerator):
451    def __init__(self, module, typeInfo):
452        VulkanWrapperGenerator.__init__(self, module, typeInfo)
453
454        self.typeInfo = typeInfo
455
456        self.cgenHeader = CodeGen()
457        self.cgenHeader.incrIndent()
458
459        self.cgenImpl = CodeGen()
460
461        self.currentFeature = None
462
463        self.feature_apis = []
464
465    def onBegin(self,):
466        self.module.appendHeader(decoder_snapshot_decl_preamble)
467        self.module.appendImpl(decoder_snapshot_impl_preamble)
468
469    def onBeginFeature(self, featureName, featureType):
470        VulkanWrapperGenerator.onBeginFeature(self, featureName, featureType)
471        self.currentFeature = featureName
472
473    def onGenCmd(self, cmdinfo, name, alias):
474        VulkanWrapperGenerator.onGenCmd(self, cmdinfo, name, alias)
475
476        api = self.typeInfo.apis[name]
477
478        additionalParams = [ \
479            makeVulkanTypeSimple(False, "android::base::BumpPool", 1, "pool"),
480            makeVulkanTypeSimple(False, "VkSnapshotApiCallInfo", 1, "apiCallInfo"),
481            makeVulkanTypeSimple(True, "uint8_t", 1, "apiCallPacket"),
482            makeVulkanTypeSimple(False, "size_t", 0, "apiCallPacketSize"),
483        ]
484
485        if api.retType.typeName != "void":
486            additionalParams.append( \
487                makeVulkanTypeSimple(False, api.retType.typeName, 0, "input_result"))
488
489        apiForSnapshot = \
490            api.withCustomParameters( \
491                additionalParams + \
492                api.parameters).withCustomReturnType( \
493                    makeVulkanTypeSimple(False, "void", 0, "void"))
494
495        self.feature_apis.append((self.currentFeature, apiForSnapshot))
496
497        self.cgenHeader.stmt(self.cgenHeader.makeFuncProto(apiForSnapshot))
498        self.module.appendHeader(self.cgenHeader.swapCode())
499
500        self.cgenImpl.emitFuncImpl( \
501            apiForSnapshot, lambda cgen: emit_impl(self.typeInfo, apiForSnapshot, cgen))
502        self.module.appendImpl(self.cgenImpl.swapCode())
503
504    def onEnd(self,):
505        self.module.appendHeader(decoder_snapshot_decl_postamble)
506        self.module.appendImpl(decoder_snapshot_impl_postamble)
507        self.cgenHeader.decrIndent()
508
509        for feature, api in self.feature_apis:
510            if feature is not None:
511                self.cgenImpl.line("#ifdef %s" % feature)
512
513            apiImplShell = \
514                api.withModifiedName("VkDecoderSnapshot::" + api.name)
515
516            self.cgenImpl.emitFuncImpl( \
517                apiImplShell, lambda cgen: emit_passthrough_to_impl(self.typeInfo, api, cgen))
518
519            if feature is not None:
520                self.cgenImpl.line("#endif")
521
522        self.module.appendImpl(self.cgenImpl.swapCode())
523        self.module.appendImpl(decoder_snapshot_namespace_postamble)
524