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, ®ion);
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, ®ion);
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