• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either expresso or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "vulkan/VkDecoderSnapshotUtils.h"
16 
17 #include "VkCommonOperations.h"
18 
19 namespace gfxstream {
20 namespace vk {
21 
22 namespace {
23 
GetMemoryType(const PhysicalDeviceInfo & physicalDevice,const VkMemoryRequirements & memoryRequirements,VkMemoryPropertyFlags memoryProperties)24 uint32_t GetMemoryType(const PhysicalDeviceInfo& physicalDevice,
25                        const VkMemoryRequirements& memoryRequirements,
26                        VkMemoryPropertyFlags memoryProperties) {
27     const auto& props = physicalDevice.memoryPropertiesHelper->getHostMemoryProperties();
28     for (uint32_t i = 0; i < props.memoryTypeCount; i++) {
29         if (!(memoryRequirements.memoryTypeBits & (1 << i))) {
30             continue;
31         }
32         if ((props.memoryTypes[i].propertyFlags & memoryProperties) != memoryProperties) {
33             continue;
34         }
35         return i;
36     }
37     GFXSTREAM_ABORT(emugl::FatalError(emugl::ABORT_REASON_OTHER))
38         << "Cannot find memory type for snapshot save " << __func__ << " (" << __FILE__ << ":"
39         << __LINE__ << ")";
40 }
41 
bytes_per_pixel(VkFormat format)42 uint32_t bytes_per_pixel(VkFormat format) {
43     switch (format) {
44         case VK_FORMAT_R8_UNORM:
45         case VK_FORMAT_R8_SNORM:
46         case VK_FORMAT_R8_USCALED:
47         case VK_FORMAT_R8_SSCALED:
48         case VK_FORMAT_R8_UINT:
49         case VK_FORMAT_R8_SINT:
50         case VK_FORMAT_R8_SRGB:
51         case VK_FORMAT_S8_UINT:
52             return 1;
53         case VK_FORMAT_R8G8_UNORM:
54         case VK_FORMAT_R8G8_SNORM:
55         case VK_FORMAT_R8G8_USCALED:
56         case VK_FORMAT_R8G8_SSCALED:
57         case VK_FORMAT_R8G8_UINT:
58         case VK_FORMAT_R8G8_SINT:
59         case VK_FORMAT_R8G8_SRGB:
60             return 2;
61         case VK_FORMAT_R8G8B8_UNORM:
62         case VK_FORMAT_R8G8B8_SNORM:
63         case VK_FORMAT_R8G8B8_USCALED:
64         case VK_FORMAT_R8G8B8_SSCALED:
65         case VK_FORMAT_R8G8B8_UINT:
66         case VK_FORMAT_R8G8B8_SINT:
67         case VK_FORMAT_R8G8B8_SRGB:
68         case VK_FORMAT_B8G8R8_UNORM:
69         case VK_FORMAT_B8G8R8_SNORM:
70         case VK_FORMAT_B8G8R8_USCALED:
71         case VK_FORMAT_B8G8R8_SSCALED:
72         case VK_FORMAT_B8G8R8_UINT:
73         case VK_FORMAT_B8G8R8_SINT:
74         case VK_FORMAT_B8G8R8_SRGB:
75         case VK_FORMAT_D16_UNORM_S8_UINT:
76             return 3;
77         case VK_FORMAT_R8G8B8A8_UNORM:
78         case VK_FORMAT_R8G8B8A8_SNORM:
79         case VK_FORMAT_R8G8B8A8_USCALED:
80         case VK_FORMAT_R8G8B8A8_SSCALED:
81         case VK_FORMAT_R8G8B8A8_UINT:
82         case VK_FORMAT_R8G8B8A8_SINT:
83         case VK_FORMAT_R8G8B8A8_SRGB:
84         case VK_FORMAT_B8G8R8A8_UNORM:
85         case VK_FORMAT_B8G8R8A8_SNORM:
86         case VK_FORMAT_B8G8R8A8_USCALED:
87         case VK_FORMAT_B8G8R8A8_SSCALED:
88         case VK_FORMAT_B8G8R8A8_UINT:
89         case VK_FORMAT_B8G8R8A8_SINT:
90         case VK_FORMAT_B8G8R8A8_SRGB:
91         case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
92         case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
93         case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
94         case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
95         case VK_FORMAT_A8B8G8R8_UINT_PACK32:
96         case VK_FORMAT_A8B8G8R8_SINT_PACK32:
97         case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
98         case VK_FORMAT_D24_UNORM_S8_UINT:
99             return 4;
100         default:
101             GFXSTREAM_ABORT(emugl::FatalError(emugl::ABORT_REASON_OTHER))
102                 << "Unsupported VkFormat on snapshot save " << format << " " << __func__ << " ("
103                 << __FILE__ << ":" << __LINE__ << ")";
104     }
105 }
106 
getMipmapExtent(VkExtent3D baseExtent,uint32_t mipLevel)107 VkExtent3D getMipmapExtent(VkExtent3D baseExtent, uint32_t mipLevel) {
108     return VkExtent3D{
109         .width = (baseExtent.width + (1 << mipLevel) - 1) >> mipLevel,
110         .height = (baseExtent.height + (1 << mipLevel) - 1) >> mipLevel,
111         .depth = baseExtent.depth,
112     };
113 }
114 
115 }  // namespace
116 
117 #define _RUN_AND_CHECK(command)                                                             \
118     {                                                                                       \
119         if (command)                                                                        \
120             GFXSTREAM_ABORT(emugl::FatalError(emugl::ABORT_REASON_OTHER))                   \
121                 << "Vulkan snapshot save failed at " << __func__ << " (" << __FILE__ << ":" \
122                 << __LINE__ << ")";                                                         \
123     }
124 
saveImageContent(android::base::Stream * stream,StateBlock * stateBlock,VkImage image,const ImageInfo * imageInfo)125 void saveImageContent(android::base::Stream* stream, StateBlock* stateBlock, VkImage image,
126                       const ImageInfo* imageInfo) {
127     if (imageInfo->layout == VK_IMAGE_LAYOUT_UNDEFINED) {
128         return;
129     }
130     // TODO(b/333936705): snapshot multi-sample images
131     if (imageInfo->imageCreateInfoShallow.samples != VK_SAMPLE_COUNT_1_BIT) {
132         return;
133     }
134     VulkanDispatch* dispatch = stateBlock->deviceDispatch;
135     const VkImageCreateInfo& imageCreateInfo = imageInfo->imageCreateInfoShallow;
136     VkCommandBufferAllocateInfo allocInfo{
137         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
138         .commandPool = stateBlock->commandPool,
139         .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
140         .commandBufferCount = 1,
141     };
142     VkCommandBuffer commandBuffer;
143     _RUN_AND_CHECK(dispatch->vkAllocateCommandBuffers(stateBlock->device, &allocInfo,
144                                                       &commandBuffer) != VK_SUCCESS);
145     VkFenceCreateInfo fenceCreateInfo{
146         .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
147     };
148     VkFence fence;
149     _RUN_AND_CHECK(dispatch->vkCreateFence(stateBlock->device, &fenceCreateInfo, nullptr, &fence));
150     VkBufferCreateInfo bufferCreateInfo = {
151         .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
152         .size = static_cast<VkDeviceSize>(
153             imageCreateInfo.extent.width * imageCreateInfo.extent.height *
154             imageCreateInfo.extent.depth * bytes_per_pixel(imageCreateInfo.format)),
155         .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT,
156         .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
157     };
158     VkBuffer readbackBuffer;
159     _RUN_AND_CHECK(
160         dispatch->vkCreateBuffer(stateBlock->device, &bufferCreateInfo, nullptr, &readbackBuffer));
161 
162     VkMemoryRequirements readbackBufferMemoryRequirements{};
163     dispatch->vkGetBufferMemoryRequirements(stateBlock->device, readbackBuffer,
164                                             &readbackBufferMemoryRequirements);
165 
166     const auto readbackBufferMemoryType =
167         GetMemoryType(*stateBlock->physicalDeviceInfo, readbackBufferMemoryRequirements,
168                       VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
169     // Staging memory
170     // TODO(b/323064243): reuse staging memory
171     VkMemoryAllocateInfo readbackBufferMemoryAllocateInfo = {
172         .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
173         .allocationSize = readbackBufferMemoryRequirements.size,
174         .memoryTypeIndex = readbackBufferMemoryType,
175     };
176     VkDeviceMemory readbackMemory;
177     _RUN_AND_CHECK(dispatch->vkAllocateMemory(stateBlock->device, &readbackBufferMemoryAllocateInfo,
178                                               nullptr, &readbackMemory));
179     _RUN_AND_CHECK(
180         dispatch->vkBindBufferMemory(stateBlock->device, readbackBuffer, readbackMemory, 0));
181 
182     void* mapped = nullptr;
183     _RUN_AND_CHECK(dispatch->vkMapMemory(stateBlock->device, readbackMemory, 0, VK_WHOLE_SIZE,
184                                          VkMemoryMapFlags{}, &mapped));
185 
186     for (uint32_t mipLevel = 0; mipLevel < imageInfo->imageCreateInfoShallow.mipLevels;
187          mipLevel++) {
188         for (uint32_t arrayLayer = 0; arrayLayer < imageInfo->imageCreateInfoShallow.arrayLayers;
189              arrayLayer++) {
190             // TODO(b/323064243): reuse command buffers
191             VkCommandBufferBeginInfo beginInfo{
192                 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
193             };
194             if (dispatch->vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) {
195                 GFXSTREAM_ABORT(emugl::FatalError(emugl::ABORT_REASON_OTHER))
196                     << "Failed to start command buffer on snapshot save";
197             }
198 
199             // TODO(b/323059453): separate stencil and depth images properly
200             VkExtent3D mipmapExtent = getMipmapExtent(imageCreateInfo.extent, mipLevel);
201             VkImageAspectFlags aspects =
202                 imageCreateInfo.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
203                     ? VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT
204                     : VK_IMAGE_ASPECT_COLOR_BIT;
205             VkImageLayout layoutBeforeSave = imageInfo->layout;
206             VkImageMemoryBarrier imgMemoryBarrier = {
207                 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
208                 .pNext = nullptr,
209                 .srcAccessMask = static_cast<VkAccessFlags>(~VK_ACCESS_NONE_KHR),
210                 .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
211                 .oldLayout = layoutBeforeSave,
212                 .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
213                 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
214                 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
215                 .image = image,
216                 .subresourceRange = VkImageSubresourceRange{.aspectMask = aspects,
217                                                             .baseMipLevel = mipLevel,
218                                                             .levelCount = 1,
219                                                             .baseArrayLayer = arrayLayer,
220                                                             .layerCount = 1}};
221 
222             dispatch->vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
223                                            VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0,
224                                            nullptr, 1, &imgMemoryBarrier);
225             VkBufferImageCopy region{
226                 .bufferOffset = 0,
227                 .bufferRowLength = 0,
228                 .bufferImageHeight = 0,
229                 .imageSubresource = VkImageSubresourceLayers{.aspectMask = aspects,
230                                                              .mipLevel = mipLevel,
231                                                              .baseArrayLayer = arrayLayer,
232                                                              .layerCount = 1},
233                 .imageOffset =
234                     VkOffset3D{
235                         .x = 0,
236                         .y = 0,
237                         .z = 0,
238                     },
239                 .imageExtent = mipmapExtent,
240             };
241             dispatch->vkCmdCopyImageToBuffer(commandBuffer, image,
242                                              VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, readbackBuffer,
243                                              1, &region);
244 
245             // Cannot really translate it back to VK_IMAGE_LAYOUT_PREINITIALIZED
246             if (layoutBeforeSave != VK_IMAGE_LAYOUT_PREINITIALIZED) {
247                 imgMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
248                 imgMemoryBarrier.newLayout = layoutBeforeSave;
249                 imgMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
250                 imgMemoryBarrier.dstAccessMask = ~VK_ACCESS_NONE_KHR;
251                 dispatch->vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
252                                                VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0,
253                                                nullptr, 1, &imgMemoryBarrier);
254             }
255             _RUN_AND_CHECK(dispatch->vkEndCommandBuffer(commandBuffer));
256 
257             // Execute the command to copy image
258             VkSubmitInfo submitInfo = {
259                 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
260                 .commandBufferCount = 1,
261                 .pCommandBuffers = &commandBuffer,
262             };
263             _RUN_AND_CHECK(dispatch->vkQueueSubmit(stateBlock->queue, 1, &submitInfo, fence));
264             _RUN_AND_CHECK(
265                 dispatch->vkWaitForFences(stateBlock->device, 1, &fence, VK_TRUE, 3000000000L));
266             _RUN_AND_CHECK(dispatch->vkResetFences(stateBlock->device, 1, &fence));
267             size_t bytes = mipmapExtent.width * mipmapExtent.height * mipmapExtent.depth *
268                            bytes_per_pixel(imageCreateInfo.format);
269             stream->putBe64(bytes);
270             stream->write(mapped, bytes);
271         }
272     }
273     dispatch->vkDestroyFence(stateBlock->device, fence, nullptr);
274     dispatch->vkUnmapMemory(stateBlock->device, readbackMemory);
275     dispatch->vkDestroyBuffer(stateBlock->device, readbackBuffer, nullptr);
276     dispatch->vkFreeMemory(stateBlock->device, readbackMemory, nullptr);
277     dispatch->vkFreeCommandBuffers(stateBlock->device, stateBlock->commandPool, 1, &commandBuffer);
278 }
279 
loadImageContent(android::base::Stream * stream,StateBlock * stateBlock,VkImage image,const ImageInfo * imageInfo)280 void loadImageContent(android::base::Stream* stream, StateBlock* stateBlock, VkImage image,
281                       const ImageInfo* imageInfo) {
282     if (imageInfo->layout == VK_IMAGE_LAYOUT_UNDEFINED) {
283         return;
284     }
285     VulkanDispatch* dispatch = stateBlock->deviceDispatch;
286     const VkImageCreateInfo& imageCreateInfo = imageInfo->imageCreateInfoShallow;
287     VkCommandBufferAllocateInfo allocInfo{
288         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
289         .commandPool = stateBlock->commandPool,
290         .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
291         .commandBufferCount = 1,
292     };
293     VkCommandBuffer commandBuffer;
294     _RUN_AND_CHECK(dispatch->vkAllocateCommandBuffers(stateBlock->device, &allocInfo,
295                                                       &commandBuffer) != VK_SUCCESS);
296     VkFenceCreateInfo fenceCreateInfo{
297         .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
298     };
299     VkFence fence;
300     _RUN_AND_CHECK(dispatch->vkCreateFence(stateBlock->device, &fenceCreateInfo, nullptr, &fence));
301     if (imageInfo->imageCreateInfoShallow.samples != VK_SAMPLE_COUNT_1_BIT) {
302         // Set the layout and quit
303         // TODO: resolve and save image content
304         VkImageAspectFlags aspects =
305             imageCreateInfo.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
306                 ? VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT
307                 : VK_IMAGE_ASPECT_COLOR_BIT;
308         VkImageMemoryBarrier imgMemoryBarrier = {
309             .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
310             .pNext = nullptr,
311             .srcAccessMask = static_cast<VkAccessFlags>(~VK_ACCESS_NONE_KHR),
312             .dstAccessMask = static_cast<VkAccessFlags>(~VK_ACCESS_NONE_KHR),
313             .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
314             .newLayout = imageInfo->layout,
315             .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
316             .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
317             .image = image,
318             .subresourceRange = VkImageSubresourceRange{.aspectMask = aspects,
319                                                         .baseMipLevel = 0,
320                                                         .levelCount = VK_REMAINING_MIP_LEVELS,
321                                                         .baseArrayLayer = 0,
322                                                         .layerCount = VK_REMAINING_ARRAY_LAYERS}};
323         VkCommandBufferBeginInfo beginInfo{
324             .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
325         };
326         _RUN_AND_CHECK(dispatch->vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS);
327 
328         dispatch->vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
329                                        VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0,
330                                        nullptr, 1, &imgMemoryBarrier);
331 
332         _RUN_AND_CHECK(dispatch->vkEndCommandBuffer(commandBuffer));
333 
334         // Execute the command to copy image
335         VkSubmitInfo submitInfo = {
336             .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
337             .commandBufferCount = 1,
338             .pCommandBuffers = &commandBuffer,
339         };
340         _RUN_AND_CHECK(dispatch->vkQueueSubmit(stateBlock->queue, 1, &submitInfo, fence));
341         _RUN_AND_CHECK(
342             dispatch->vkWaitForFences(stateBlock->device, 1, &fence, VK_TRUE, 3000000000L));
343         dispatch->vkDestroyFence(stateBlock->device, fence, nullptr);
344         dispatch->vkFreeCommandBuffers(stateBlock->device, stateBlock->commandPool, 1,
345                                        &commandBuffer);
346         return;
347     }
348     VkBufferCreateInfo bufferCreateInfo = {
349         .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
350         .size = static_cast<VkDeviceSize>(
351             imageCreateInfo.extent.width * imageCreateInfo.extent.height *
352             imageCreateInfo.extent.depth * bytes_per_pixel(imageCreateInfo.format)),
353         .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
354         .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
355     };
356     VkBuffer stagingBuffer;
357     _RUN_AND_CHECK(
358         dispatch->vkCreateBuffer(stateBlock->device, &bufferCreateInfo, nullptr, &stagingBuffer));
359 
360     VkMemoryRequirements stagingBufferMemoryRequirements{};
361     dispatch->vkGetBufferMemoryRequirements(stateBlock->device, stagingBuffer,
362                                             &stagingBufferMemoryRequirements);
363 
364     const auto stagingBufferMemoryType =
365         GetMemoryType(*stateBlock->physicalDeviceInfo, stagingBufferMemoryRequirements,
366                       VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
367 
368     // Staging memory
369     // TODO(b/323064243): reuse staging memory
370     VkMemoryAllocateInfo stagingBufferMemoryAllocateInfo = {
371         .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
372         .allocationSize = stagingBufferMemoryRequirements.size,
373         .memoryTypeIndex = stagingBufferMemoryType,
374     };
375     VkDeviceMemory stagingMemory;
376     _RUN_AND_CHECK(dispatch->vkAllocateMemory(stateBlock->device, &stagingBufferMemoryAllocateInfo,
377                                               nullptr, &stagingMemory));
378     _RUN_AND_CHECK(
379         dispatch->vkBindBufferMemory(stateBlock->device, stagingBuffer, stagingMemory, 0));
380 
381     void* mapped = nullptr;
382     _RUN_AND_CHECK(dispatch->vkMapMemory(stateBlock->device, stagingMemory, 0, VK_WHOLE_SIZE,
383                                          VkMemoryMapFlags{}, &mapped));
384 
385     for (uint32_t mipLevel = 0; mipLevel < imageInfo->imageCreateInfoShallow.mipLevels;
386          mipLevel++) {
387         for (uint32_t arrayLayer = 0; arrayLayer < imageInfo->imageCreateInfoShallow.arrayLayers;
388              arrayLayer++) {
389             // TODO(b/323064243): reuse command buffers
390             VkCommandBufferBeginInfo beginInfo{
391                 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
392             };
393             if (dispatch->vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) {
394                 GFXSTREAM_ABORT(emugl::FatalError(emugl::ABORT_REASON_OTHER))
395                     << "Failed to start command buffer on snapshot save";
396             }
397 
398             VkExtent3D mipmapExtent = getMipmapExtent(imageCreateInfo.extent, mipLevel);
399             size_t bytes = stream->getBe64();
400             stream->read(mapped, bytes);
401 
402             VkImageAspectFlags aspects =
403                 imageCreateInfo.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
404                     ? VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT
405                     : VK_IMAGE_ASPECT_COLOR_BIT;
406             VkImageMemoryBarrier imgMemoryBarrier = {
407                 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
408                 .pNext = nullptr,
409                 .srcAccessMask = static_cast<VkAccessFlags>(~VK_ACCESS_NONE_KHR),
410                 .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
411                 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
412                 .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
413                 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
414                 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
415                 .image = image,
416                 .subresourceRange = VkImageSubresourceRange{.aspectMask = aspects,
417                                                             .baseMipLevel = mipLevel,
418                                                             .levelCount = 1,
419                                                             .baseArrayLayer = arrayLayer,
420                                                             .layerCount = 1}};
421 
422             dispatch->vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
423                                            VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0,
424                                            nullptr, 1, &imgMemoryBarrier);
425 
426             VkBufferImageCopy region{
427                 .bufferOffset = 0,
428                 .bufferRowLength = 0,
429                 .bufferImageHeight = 0,
430                 .imageSubresource = VkImageSubresourceLayers{.aspectMask = aspects,
431                                                              .mipLevel = mipLevel,
432                                                              .baseArrayLayer = arrayLayer,
433                                                              .layerCount = 1},
434                 .imageOffset =
435                     VkOffset3D{
436                         .x = 0,
437                         .y = 0,
438                         .z = 0,
439                     },
440                 .imageExtent = mipmapExtent,
441             };
442             dispatch->vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, image,
443                                              VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
444 
445             // Cannot really translate it back to VK_IMAGE_LAYOUT_PREINITIALIZED
446             if (imageInfo->layout != VK_IMAGE_LAYOUT_PREINITIALIZED) {
447                 imgMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
448                 imgMemoryBarrier.newLayout = imageInfo->layout;
449                 imgMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
450                 imgMemoryBarrier.dstAccessMask = ~VK_ACCESS_NONE_KHR;
451                 dispatch->vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
452                                                VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0,
453                                                nullptr, 1, &imgMemoryBarrier);
454             }
455             _RUN_AND_CHECK(dispatch->vkEndCommandBuffer(commandBuffer));
456 
457             // Execute the command to copy image
458             VkSubmitInfo submitInfo = {
459                 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
460                 .commandBufferCount = 1,
461                 .pCommandBuffers = &commandBuffer,
462             };
463             _RUN_AND_CHECK(dispatch->vkQueueSubmit(stateBlock->queue, 1, &submitInfo, fence));
464             _RUN_AND_CHECK(
465                 dispatch->vkWaitForFences(stateBlock->device, 1, &fence, VK_TRUE, 3000000000L));
466             _RUN_AND_CHECK(dispatch->vkResetFences(stateBlock->device, 1, &fence));
467         }
468     }
469     dispatch->vkDestroyFence(stateBlock->device, fence, nullptr);
470     dispatch->vkUnmapMemory(stateBlock->device, stagingMemory);
471     dispatch->vkDestroyBuffer(stateBlock->device, stagingBuffer, nullptr);
472     dispatch->vkFreeMemory(stateBlock->device, stagingMemory, nullptr);
473     dispatch->vkFreeCommandBuffers(stateBlock->device, stateBlock->commandPool, 1, &commandBuffer);
474 }
475 
saveBufferContent(android::base::Stream * stream,StateBlock * stateBlock,VkBuffer buffer,const BufferInfo * bufferInfo)476 void saveBufferContent(android::base::Stream* stream, StateBlock* stateBlock, VkBuffer buffer,
477                        const BufferInfo* bufferInfo) {
478     VkBufferUsageFlags requiredUsages =
479         VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
480     if ((bufferInfo->usage & requiredUsages) != requiredUsages) {
481         return;
482     }
483     VulkanDispatch* dispatch = stateBlock->deviceDispatch;
484     VkCommandBufferAllocateInfo allocInfo{
485         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
486         .commandPool = stateBlock->commandPool,
487         .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
488         .commandBufferCount = 1,
489     };
490     VkCommandBuffer commandBuffer;
491     _RUN_AND_CHECK(dispatch->vkAllocateCommandBuffers(stateBlock->device, &allocInfo,
492                                                       &commandBuffer) != VK_SUCCESS);
493     VkFenceCreateInfo fenceCreateInfo{
494         .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
495     };
496     VkFence fence;
497     _RUN_AND_CHECK(dispatch->vkCreateFence(stateBlock->device, &fenceCreateInfo, nullptr, &fence));
498     VkBufferCreateInfo bufferCreateInfo = {
499         .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
500         .size = static_cast<VkDeviceSize>(bufferInfo->size),
501         .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT,
502         .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
503     };
504     VkBuffer readbackBuffer;
505     _RUN_AND_CHECK(
506         dispatch->vkCreateBuffer(stateBlock->device, &bufferCreateInfo, nullptr, &readbackBuffer));
507 
508     VkMemoryRequirements readbackBufferMemoryRequirements{};
509     dispatch->vkGetBufferMemoryRequirements(stateBlock->device, readbackBuffer,
510                                             &readbackBufferMemoryRequirements);
511 
512     const auto readbackBufferMemoryType =
513         GetMemoryType(*stateBlock->physicalDeviceInfo, readbackBufferMemoryRequirements,
514                       VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
515     // Staging memory
516     // TODO(b/323064243): reuse staging memory
517     VkMemoryAllocateInfo readbackBufferMemoryAllocateInfo = {
518         .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
519         .allocationSize = readbackBufferMemoryRequirements.size,
520         .memoryTypeIndex = readbackBufferMemoryType,
521     };
522     VkDeviceMemory readbackMemory;
523     _RUN_AND_CHECK(dispatch->vkAllocateMemory(stateBlock->device, &readbackBufferMemoryAllocateInfo,
524                                               nullptr, &readbackMemory));
525     _RUN_AND_CHECK(
526         dispatch->vkBindBufferMemory(stateBlock->device, readbackBuffer, readbackMemory, 0));
527 
528     void* mapped = nullptr;
529     _RUN_AND_CHECK(dispatch->vkMapMemory(stateBlock->device, readbackMemory, 0, VK_WHOLE_SIZE,
530                                          VkMemoryMapFlags{}, &mapped));
531 
532     VkBufferCopy bufferCopy = {
533         .srcOffset = 0,
534         .dstOffset = 0,
535         .size = bufferInfo->size,
536     };
537 
538     VkCommandBufferBeginInfo beginInfo{
539         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
540     };
541     if (dispatch->vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) {
542         GFXSTREAM_ABORT(emugl::FatalError(emugl::ABORT_REASON_OTHER))
543             << "Failed to start command buffer on snapshot save";
544     }
545     dispatch->vkCmdCopyBuffer(commandBuffer, buffer, readbackBuffer, 1, &bufferCopy);
546     VkBufferMemoryBarrier barrier{.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
547                                   .pNext = nullptr,
548                                   .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
549                                   .dstAccessMask = VK_ACCESS_HOST_READ_BIT,
550                                   .srcQueueFamilyIndex = 0xFFFFFFFF,
551                                   .dstQueueFamilyIndex = 0xFFFFFFFF,
552                                   .buffer = readbackBuffer,
553                                   .offset = 0,
554                                   .size = bufferInfo->size};
555     dispatch->vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
556                                    VK_PIPELINE_STAGE_HOST_BIT, 0, 0, nullptr, 1, &barrier, 0,
557                                    nullptr);
558 
559     // Execute the command to copy buffer
560     VkSubmitInfo submitInfo = {
561         .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
562         .commandBufferCount = 1,
563         .pCommandBuffers = &commandBuffer,
564     };
565     _RUN_AND_CHECK(dispatch->vkEndCommandBuffer(commandBuffer));
566     _RUN_AND_CHECK(dispatch->vkQueueSubmit(stateBlock->queue, 1, &submitInfo, fence));
567     _RUN_AND_CHECK(dispatch->vkWaitForFences(stateBlock->device, 1, &fence, VK_TRUE, 3000000000L));
568     _RUN_AND_CHECK(dispatch->vkResetFences(stateBlock->device, 1, &fence));
569     stream->putBe64(bufferInfo->size);
570     stream->write(mapped, bufferInfo->size);
571 
572     dispatch->vkDestroyFence(stateBlock->device, fence, nullptr);
573     dispatch->vkUnmapMemory(stateBlock->device, readbackMemory);
574     dispatch->vkDestroyBuffer(stateBlock->device, readbackBuffer, nullptr);
575     dispatch->vkFreeMemory(stateBlock->device, readbackMemory, nullptr);
576     dispatch->vkFreeCommandBuffers(stateBlock->device, stateBlock->commandPool, 1, &commandBuffer);
577 }
578 
loadBufferContent(android::base::Stream * stream,StateBlock * stateBlock,VkBuffer buffer,const BufferInfo * bufferInfo)579 void loadBufferContent(android::base::Stream* stream, StateBlock* stateBlock, VkBuffer buffer,
580                        const BufferInfo* bufferInfo) {
581     VkBufferUsageFlags requiredUsages =
582         VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
583     if ((bufferInfo->usage & requiredUsages) != requiredUsages) {
584         return;
585     }
586     VulkanDispatch* dispatch = stateBlock->deviceDispatch;
587     VkCommandBufferAllocateInfo allocInfo{
588         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
589         .commandPool = stateBlock->commandPool,
590         .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
591         .commandBufferCount = 1,
592     };
593     VkCommandBuffer commandBuffer;
594     _RUN_AND_CHECK(dispatch->vkAllocateCommandBuffers(stateBlock->device, &allocInfo,
595                                                       &commandBuffer) != VK_SUCCESS);
596     VkFenceCreateInfo fenceCreateInfo{
597         .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
598     };
599     VkFence fence;
600     _RUN_AND_CHECK(dispatch->vkCreateFence(stateBlock->device, &fenceCreateInfo, nullptr, &fence));
601     VkBufferCreateInfo bufferCreateInfo = {
602         .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
603         .size = static_cast<VkDeviceSize>(bufferInfo->size),
604         .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
605         .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
606     };
607     VkBuffer stagingBuffer;
608     _RUN_AND_CHECK(
609         dispatch->vkCreateBuffer(stateBlock->device, &bufferCreateInfo, nullptr, &stagingBuffer));
610 
611     VkMemoryRequirements stagingBufferMemoryRequirements{};
612     dispatch->vkGetBufferMemoryRequirements(stateBlock->device, stagingBuffer,
613                                             &stagingBufferMemoryRequirements);
614 
615     const auto stagingBufferMemoryType =
616         GetMemoryType(*stateBlock->physicalDeviceInfo, stagingBufferMemoryRequirements,
617                       VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
618     // Staging memory
619     // TODO(b/323064243): reuse staging memory
620     VkMemoryAllocateInfo stagingBufferMemoryAllocateInfo = {
621         .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
622         .allocationSize = stagingBufferMemoryRequirements.size,
623         .memoryTypeIndex = stagingBufferMemoryType,
624     };
625     VkDeviceMemory stagingMemory;
626     _RUN_AND_CHECK(dispatch->vkAllocateMemory(stateBlock->device, &stagingBufferMemoryAllocateInfo,
627                                               nullptr, &stagingMemory));
628     _RUN_AND_CHECK(
629         dispatch->vkBindBufferMemory(stateBlock->device, stagingBuffer, stagingMemory, 0));
630 
631     void* mapped = nullptr;
632     _RUN_AND_CHECK(dispatch->vkMapMemory(stateBlock->device, stagingMemory, 0, VK_WHOLE_SIZE,
633                                          VkMemoryMapFlags{}, &mapped));
634     size_t bufferSize = stream->getBe64();
635     assert(bufferSize == bufferInfo->size);
636     stream->read(mapped, bufferInfo->size);
637 
638     VkBufferCopy bufferCopy = {
639         .srcOffset = 0,
640         .dstOffset = 0,
641         .size = bufferInfo->size,
642     };
643 
644     VkCommandBufferBeginInfo beginInfo{
645         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
646     };
647     if (dispatch->vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) {
648         GFXSTREAM_ABORT(emugl::FatalError(emugl::ABORT_REASON_OTHER))
649             << "Failed to start command buffer on snapshot save";
650     }
651     dispatch->vkCmdCopyBuffer(commandBuffer, stagingBuffer, buffer, 1, &bufferCopy);
652     VkBufferMemoryBarrier barrier{.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
653                                   .pNext = nullptr,
654                                   .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
655                                   .dstAccessMask = static_cast<VkAccessFlags>(~VK_ACCESS_NONE_KHR),
656                                   .srcQueueFamilyIndex = 0xFFFFFFFF,
657                                   .dstQueueFamilyIndex = 0xFFFFFFFF,
658                                   .buffer = buffer,
659                                   .offset = 0,
660                                   .size = bufferInfo->size};
661     dispatch->vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
662                                    VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 1, &barrier,
663                                    0, nullptr);
664 
665     // Execute the command to copy buffer
666     VkSubmitInfo submitInfo = {
667         .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
668         .commandBufferCount = 1,
669         .pCommandBuffers = &commandBuffer,
670     };
671     _RUN_AND_CHECK(dispatch->vkEndCommandBuffer(commandBuffer));
672     _RUN_AND_CHECK(dispatch->vkQueueSubmit(stateBlock->queue, 1, &submitInfo, fence));
673     _RUN_AND_CHECK(dispatch->vkWaitForFences(stateBlock->device, 1, &fence, VK_TRUE, 3000000000L));
674     _RUN_AND_CHECK(dispatch->vkResetFences(stateBlock->device, 1, &fence));
675 
676     dispatch->vkDestroyFence(stateBlock->device, fence, nullptr);
677     dispatch->vkUnmapMemory(stateBlock->device, stagingMemory);
678     dispatch->vkDestroyBuffer(stateBlock->device, stagingBuffer, nullptr);
679     dispatch->vkFreeMemory(stateBlock->device, stagingMemory, nullptr);
680     dispatch->vkFreeCommandBuffers(stateBlock->device, stateBlock->commandPool, 1, &commandBuffer);
681 }
682 
683 }  // namespace vk
684 }  // namespace gfxstream