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