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