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