1 // Copyright 2018 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 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either expresso or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 #include "VkAndroidNativeBuffer.h"
14
15 #include <string.h>
16
17 #include <future>
18
19 #include "GrallocDefs.h"
20 #include "SyncThread.h"
21 #include "VkCommonOperations.h"
22 #include "VulkanDispatch.h"
23 #include "cereal/common/goldfish_vk_deepcopy.h"
24 #include "cereal/common/goldfish_vk_extension_structs.h"
25
26 #include "goldfish_vk_private_defs.h"
27 #include "host-common/GfxstreamFatalError.h"
28 #include "FrameBuffer.h"
29 #include "vulkan/vk_enum_string_helper.h"
30
31 namespace gfxstream {
32 namespace vk {
33
34 #define VK_ANB_ERR(fmt, ...) fprintf(stderr, "%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__);
35
36 #define ENABLE_VK_ANB_DEBUG 0
37
38 #if ENABLE_VK_ANB_DEBUG
39 #define VK_ANB_DEBUG(fmt, ...) \
40 fprintf(stderr, "vk-anb-debug: %s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__);
41 #define VK_ANB_DEBUG_OBJ(obj, fmt, ...) \
42 fprintf(stderr, "vk-anb-debug: %s:%d:%p " fmt "\n", __func__, __LINE__, obj, ##__VA_ARGS__);
43 #else
44 #define VK_ANB_DEBUG(fmt, ...)
45 #define VK_ANB_DEBUG_OBJ(obj, fmt, ...)
46 #endif
47
48 using android::base::AutoLock;
49 using android::base::Lock;
50 using emugl::ABORT_REASON_OTHER;
51 using emugl::FatalError;
52
QsriWaitFencePool(VulkanDispatch * vk,VkDevice device)53 AndroidNativeBufferInfo::QsriWaitFencePool::QsriWaitFencePool(VulkanDispatch* vk, VkDevice device)
54 : mVk(vk), mDevice(device) {}
55
getFenceFromPool()56 VkFence AndroidNativeBufferInfo::QsriWaitFencePool::getFenceFromPool() {
57 VK_ANB_DEBUG("enter");
58 AutoLock lock(mLock);
59 VkFence fence = VK_NULL_HANDLE;
60 if (mAvailableFences.empty()) {
61 VkFenceCreateInfo fenceCreateInfo = {
62 VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
63 0,
64 0,
65 };
66 mVk->vkCreateFence(mDevice, &fenceCreateInfo, nullptr, &fence);
67 VK_ANB_DEBUG("no fences in pool, created %p", fence);
68 } else {
69 fence = mAvailableFences.back();
70 mAvailableFences.pop_back();
71 VkResult res = mVk->vkResetFences(mDevice, 1, &fence);
72 if (res != VK_SUCCESS) {
73 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
74 << "Fail to reset Qsri VkFence: " << res << "(" << string_VkResult(res) << ").";
75 }
76 VK_ANB_DEBUG("existing fence in pool: %p. also reset the fence", fence);
77 }
78 mUsedFences.emplace(fence);
79 VK_ANB_DEBUG("exit");
80 return fence;
81 }
82
~QsriWaitFencePool()83 AndroidNativeBufferInfo::QsriWaitFencePool::~QsriWaitFencePool() {
84 VK_ANB_DEBUG("enter");
85 // Nothing in the fence pool is unsignaled
86 if (!mUsedFences.empty()) {
87 VK_ANB_ERR("%zu VkFences are still being used when destroying the Qsri fence pool.",
88 mUsedFences.size());
89 }
90 for (auto fence : mAvailableFences) {
91 VK_ANB_DEBUG("destroy fence %p", fence);
92 mVk->vkDestroyFence(mDevice, fence, nullptr);
93 }
94 VK_ANB_DEBUG("exit");
95 }
96
returnFence(VkFence fence)97 void AndroidNativeBufferInfo::QsriWaitFencePool::returnFence(VkFence fence) {
98 AutoLock lock(mLock);
99 if (!mUsedFences.erase(fence)) {
100 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
101 << "Return an unmanaged Qsri VkFence back to the pool.";
102 return;
103 }
104 mAvailableFences.push_back(fence);
105 }
106
parseAndroidNativeBufferInfo(const VkImageCreateInfo * pCreateInfo,AndroidNativeBufferInfo * info_out)107 bool parseAndroidNativeBufferInfo(const VkImageCreateInfo* pCreateInfo,
108 AndroidNativeBufferInfo* info_out) {
109 // Look through the extension chain.
110 const void* curr_pNext = pCreateInfo->pNext;
111 if (!curr_pNext) return false;
112
113 uint32_t structType = goldfish_vk_struct_type(curr_pNext);
114
115 return structType == VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID;
116 }
117
prepareAndroidNativeBufferImage(VulkanDispatch * vk,VkDevice device,android::base::BumpPool & allocator,const VkImageCreateInfo * pCreateInfo,const VkNativeBufferANDROID * nativeBufferANDROID,const VkAllocationCallbacks * pAllocator,const VkPhysicalDeviceMemoryProperties * memProps,AndroidNativeBufferInfo * out)118 VkResult prepareAndroidNativeBufferImage(VulkanDispatch* vk, VkDevice device,
119 android::base::BumpPool& allocator,
120 const VkImageCreateInfo* pCreateInfo,
121 const VkNativeBufferANDROID* nativeBufferANDROID,
122 const VkAllocationCallbacks* pAllocator,
123 const VkPhysicalDeviceMemoryProperties* memProps,
124 AndroidNativeBufferInfo* out) {
125 bool colorBufferExportedToGl = false;
126 bool externalMemoryCompatible = false;
127
128 out->vk = vk;
129 out->device = device;
130 out->vkFormat = pCreateInfo->format;
131 out->extent = pCreateInfo->extent;
132 out->usage = pCreateInfo->usage;
133
134 for (uint32_t i = 0; i < pCreateInfo->queueFamilyIndexCount; ++i) {
135 out->queueFamilyIndices.push_back(pCreateInfo->pQueueFamilyIndices[i]);
136 }
137
138 out->format = nativeBufferANDROID->format;
139 out->stride = nativeBufferANDROID->stride;
140 out->colorBufferHandle = *static_cast<const uint32_t*>(nativeBufferANDROID->handle);
141
142 auto emu = getGlobalVkEmulation();
143
144 if (!getColorBufferShareInfo(out->colorBufferHandle, &colorBufferExportedToGl,
145 &externalMemoryCompatible)) {
146 VK_ANB_ERR("Failed to query if ColorBuffer:%d exported to GL.", out->colorBufferHandle);
147 return VK_ERROR_INITIALIZATION_FAILED;
148 }
149
150 if (externalMemoryCompatible) {
151 releaseColorBufferForGuestUse(out->colorBufferHandle);
152 out->externallyBacked = true;
153 }
154
155 out->useVulkanNativeImage =
156 (emu && emu->live && emu->guestUsesAngle) || colorBufferExportedToGl;
157
158 VkDeviceSize bindOffset = 0;
159 if (out->externallyBacked) {
160 VkImageCreateInfo createImageCi;
161 deepcopy_VkImageCreateInfo(&allocator, VK_STRUCTURE_TYPE_MAX_ENUM, pCreateInfo,
162 &createImageCi);
163 auto* nativeBufferAndroid = vk_find_struct<VkNativeBufferANDROID>(&createImageCi);
164 if (!nativeBufferAndroid) {
165 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
166 << "VkNativeBufferANDROID is required to be included in the pNext chain of the "
167 "VkImageCreateInfo when importing a gralloc buffer.";
168 }
169 vk_struct_chain_remove(nativeBufferAndroid, &createImageCi);
170
171 if (vk_find_struct<VkExternalMemoryImageCreateInfo>(&createImageCi)) {
172 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
173 << "Unhandled VkExternalMemoryImageCreateInfo in the pNext chain.";
174 }
175 // Create the image with extension structure about external backing.
176 VkExternalMemoryImageCreateInfo extImageCi = {
177 VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
178 0,
179 VK_EXT_MEMORY_HANDLE_TYPE_BIT,
180 };
181
182 vk_insert_struct(createImageCi, extImageCi);
183
184 VkResult createResult = vk->vkCreateImage(device, &createImageCi, pAllocator, &out->image);
185
186 if (createResult != VK_SUCCESS) return createResult;
187
188 // Now import the backing memory.
189 const auto& cbInfo = getColorBufferInfo(out->colorBufferHandle);
190 const auto& memInfo = cbInfo.memory;
191
192 vk->vkGetImageMemoryRequirements(device, out->image, &out->memReqs);
193
194 if (out->memReqs.size < memInfo.size) {
195 out->memReqs.size = memInfo.size;
196 }
197
198 if (memInfo.dedicatedAllocation) {
199 if (!importExternalMemoryDedicatedImage(vk, device, &memInfo, out->image,
200 &out->imageMemory)) {
201 VK_ANB_ERR(
202 "VK_ANDROID_native_buffer: Failed to import external memory (dedicated)");
203 return VK_ERROR_INITIALIZATION_FAILED;
204 }
205 } else {
206 if (!importExternalMemory(vk, device, &memInfo, &out->imageMemory)) {
207 VK_ANB_ERR("VK_ANDROID_native_buffer: Failed to import external memory");
208 return VK_ERROR_INITIALIZATION_FAILED;
209 }
210 }
211
212 bindOffset = memInfo.bindOffset;
213 } else {
214 // delete the info struct and pass to vkCreateImage, and also add
215 // transfer src capability to allow us to copy to CPU.
216 VkImageCreateInfo infoNoNative = *pCreateInfo;
217 infoNoNative.pNext = nullptr;
218 infoNoNative.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
219 VkResult createResult = vk->vkCreateImage(device, &infoNoNative, pAllocator, &out->image);
220
221 if (createResult != VK_SUCCESS) return createResult;
222
223 vk->vkGetImageMemoryRequirements(device, out->image, &out->memReqs);
224
225 uint32_t imageMemoryTypeIndex = 0;
226 bool imageMemoryTypeIndexFound = false;
227
228 for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i) {
229 bool supported = out->memReqs.memoryTypeBits & (1 << i);
230 if (supported) {
231 imageMemoryTypeIndex = i;
232 imageMemoryTypeIndexFound = true;
233 break;
234 }
235 }
236
237 if (!imageMemoryTypeIndexFound) {
238 VK_ANB_ERR(
239 "VK_ANDROID_native_buffer: could not obtain "
240 "image memory type index");
241 teardownAndroidNativeBufferImage(vk, out);
242 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
243 }
244
245 out->imageMemoryTypeIndex = imageMemoryTypeIndex;
246
247 VkMemoryAllocateInfo allocInfo = {
248 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
249 0,
250 out->memReqs.size,
251 out->imageMemoryTypeIndex,
252 };
253
254 if (VK_SUCCESS != vk->vkAllocateMemory(device, &allocInfo, nullptr, &out->imageMemory)) {
255 VK_ANB_ERR(
256 "VK_ANDROID_native_buffer: could not allocate "
257 "image memory. requested size: %zu",
258 (size_t)(out->memReqs.size));
259 teardownAndroidNativeBufferImage(vk, out);
260 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
261 }
262 }
263
264 if (VK_SUCCESS != vk->vkBindImageMemory(device, out->image, out->imageMemory, bindOffset)) {
265 VK_ANB_ERR(
266 "VK_ANDROID_native_buffer: could not bind "
267 "image memory.");
268 teardownAndroidNativeBufferImage(vk, out);
269 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
270 }
271
272 // Allocate a staging memory and set up the staging buffer.
273 // TODO: Make this shared as well if we can get that to
274 // work on Windows with NVIDIA.
275 {
276 VkBufferCreateInfo stagingBufferCreateInfo = {
277 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
278 0,
279 0,
280 out->memReqs.size,
281 VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
282 VK_SHARING_MODE_EXCLUSIVE,
283 0,
284 nullptr,
285 };
286 if (out->queueFamilyIndices.size() > 1) {
287 stagingBufferCreateInfo.sharingMode = VK_SHARING_MODE_CONCURRENT;
288 stagingBufferCreateInfo.queueFamilyIndexCount =
289 static_cast<uint32_t>(out->queueFamilyIndices.size());
290 stagingBufferCreateInfo.pQueueFamilyIndices = out->queueFamilyIndices.data();
291 }
292
293 if (VK_SUCCESS !=
294 vk->vkCreateBuffer(device, &stagingBufferCreateInfo, nullptr, &out->stagingBuffer)) {
295 VK_ANB_ERR(
296 "VK_ANDROID_native_buffer: could not create "
297 "staging buffer.");
298 teardownAndroidNativeBufferImage(vk, out);
299 return VK_ERROR_OUT_OF_HOST_MEMORY;
300 }
301
302 VkMemoryRequirements stagingMemReqs;
303 vk->vkGetBufferMemoryRequirements(device, out->stagingBuffer, &stagingMemReqs);
304 if (stagingMemReqs.size < out->memReqs.size) {
305 VK_ANB_ERR(
306 "VK_ANDROID_native_buffer: unexpected staging buffer size");
307 teardownAndroidNativeBufferImage(vk, out);
308 return VK_ERROR_OUT_OF_HOST_MEMORY;
309 }
310
311 bool stagingIndexRes =
312 getStagingMemoryTypeIndex(vk, device, memProps, &out->stagingMemoryTypeIndex);
313
314 if (!stagingIndexRes) {
315 VK_ANB_ERR(
316 "VK_ANDROID_native_buffer: could not obtain "
317 "staging memory type index");
318 teardownAndroidNativeBufferImage(vk, out);
319 return VK_ERROR_OUT_OF_HOST_MEMORY;
320 }
321
322 VkMemoryAllocateInfo allocInfo = {
323 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
324 0,
325 stagingMemReqs.size,
326 out->stagingMemoryTypeIndex,
327 };
328
329 VkResult res = vk->vkAllocateMemory(device, &allocInfo, nullptr, &out->stagingMemory);
330 if (VK_SUCCESS != res) {
331 VK_ANB_ERR(
332 "VK_ANDROID_native_buffer: could not allocate staging memory. "
333 "res = %d. requested size: %zu",
334 (int)res, (size_t)(out->memReqs.size));
335 teardownAndroidNativeBufferImage(vk, out);
336 return VK_ERROR_OUT_OF_HOST_MEMORY;
337 }
338
339 if (VK_SUCCESS !=
340 vk->vkBindBufferMemory(device, out->stagingBuffer, out->stagingMemory, 0)) {
341 VK_ANB_ERR(
342 "VK_ANDROID_native_buffer: could not bind "
343 "staging buffer to staging memory.");
344 teardownAndroidNativeBufferImage(vk, out);
345 return VK_ERROR_OUT_OF_HOST_MEMORY;
346 }
347
348 if (VK_SUCCESS != vk->vkMapMemory(device, out->stagingMemory, 0, out->memReqs.size, 0,
349 (void**)&out->mappedStagingPtr)) {
350 VK_ANB_ERR(
351 "VK_ANDROID_native_buffer: could not map "
352 "staging buffer.");
353 teardownAndroidNativeBufferImage(vk, out);
354 return VK_ERROR_OUT_OF_HOST_MEMORY;
355 }
356 }
357
358 out->qsriWaitFencePool =
359 std::make_unique<AndroidNativeBufferInfo::QsriWaitFencePool>(out->vk, out->device);
360 out->qsriTimeline = std::make_unique<VkQsriTimeline>();
361 return VK_SUCCESS;
362 }
363
teardownAndroidNativeBufferImage(VulkanDispatch * vk,AndroidNativeBufferInfo * anbInfo)364 void teardownAndroidNativeBufferImage(VulkanDispatch* vk, AndroidNativeBufferInfo* anbInfo) {
365 auto device = anbInfo->device;
366
367 auto image = anbInfo->image;
368 auto imageMemory = anbInfo->imageMemory;
369
370 auto stagingBuffer = anbInfo->stagingBuffer;
371 auto mappedPtr = anbInfo->mappedStagingPtr;
372 auto stagingMemory = anbInfo->stagingMemory;
373
374 if (image) vk->vkDestroyImage(device, image, nullptr);
375 if (imageMemory) vk->vkFreeMemory(device, imageMemory, nullptr);
376 if (stagingBuffer) vk->vkDestroyBuffer(device, stagingBuffer, nullptr);
377 if (mappedPtr) vk->vkUnmapMemory(device, stagingMemory);
378 if (stagingMemory) vk->vkFreeMemory(device, stagingMemory, nullptr);
379
380 for (auto queueState : anbInfo->queueStates) {
381 queueState.teardown(vk, device);
382 }
383
384 anbInfo->queueStates.clear();
385
386 anbInfo->acquireQueueState.teardown(vk, device);
387
388 anbInfo->vk = nullptr;
389 anbInfo->device = VK_NULL_HANDLE;
390 anbInfo->image = VK_NULL_HANDLE;
391 anbInfo->imageMemory = VK_NULL_HANDLE;
392 anbInfo->stagingBuffer = VK_NULL_HANDLE;
393 anbInfo->mappedStagingPtr = nullptr;
394 anbInfo->stagingMemory = VK_NULL_HANDLE;
395
396 anbInfo->qsriWaitFencePool = nullptr;
397 }
398
getGralloc0Usage(VkFormat format,VkImageUsageFlags imageUsage,int * usage_out)399 void getGralloc0Usage(VkFormat format, VkImageUsageFlags imageUsage, int* usage_out) {
400 // Pick some default flexible values for gralloc usage for now.
401 (void)format;
402 (void)imageUsage;
403 *usage_out = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
404 GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
405 }
406
407 // Taken from Android GrallocUsageConversion.h
getGralloc1Usage(VkFormat format,VkImageUsageFlags imageUsage,VkSwapchainImageUsageFlagsANDROID swapchainImageUsage,uint64_t * consumerUsage_out,uint64_t * producerUsage_out)408 void getGralloc1Usage(VkFormat format, VkImageUsageFlags imageUsage,
409 VkSwapchainImageUsageFlagsANDROID swapchainImageUsage,
410 uint64_t* consumerUsage_out, uint64_t* producerUsage_out) {
411 // Pick some default flexible values for gralloc usage for now.
412 (void)format;
413 (void)imageUsage;
414 (void)swapchainImageUsage;
415
416 constexpr int usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
417 GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
418
419 constexpr uint64_t PRODUCER_MASK =
420 GRALLOC1_PRODUCER_USAGE_CPU_READ |
421 /* GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN | */
422 GRALLOC1_PRODUCER_USAGE_CPU_WRITE |
423 /* GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN | */
424 GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET | GRALLOC1_PRODUCER_USAGE_PROTECTED |
425 GRALLOC1_PRODUCER_USAGE_CAMERA | GRALLOC1_PRODUCER_USAGE_VIDEO_DECODER |
426 GRALLOC1_PRODUCER_USAGE_SENSOR_DIRECT_DATA;
427 constexpr uint64_t CONSUMER_MASK =
428 GRALLOC1_CONSUMER_USAGE_CPU_READ |
429 /* GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN | */
430 GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE | GRALLOC1_CONSUMER_USAGE_HWCOMPOSER |
431 GRALLOC1_CONSUMER_USAGE_CLIENT_TARGET | GRALLOC1_CONSUMER_USAGE_CURSOR |
432 GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER | GRALLOC1_CONSUMER_USAGE_CAMERA |
433 GRALLOC1_CONSUMER_USAGE_RENDERSCRIPT | GRALLOC1_CONSUMER_USAGE_GPU_DATA_BUFFER;
434
435 *producerUsage_out = static_cast<uint64_t>(usage) & PRODUCER_MASK;
436 *consumerUsage_out = static_cast<uint64_t>(usage) & CONSUMER_MASK;
437
438 if ((static_cast<uint32_t>(usage) & GRALLOC_USAGE_SW_READ_OFTEN) ==
439 GRALLOC_USAGE_SW_READ_OFTEN) {
440 *producerUsage_out |= GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN;
441 *consumerUsage_out |= GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN;
442 }
443
444 if ((static_cast<uint32_t>(usage) & GRALLOC_USAGE_SW_WRITE_OFTEN) ==
445 GRALLOC_USAGE_SW_WRITE_OFTEN) {
446 *producerUsage_out |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN;
447 }
448 }
449
setup(VulkanDispatch * vk,VkDevice device,VkQueue queueIn,uint32_t queueFamilyIndexIn,android::base::Lock * queueLockIn)450 void AndroidNativeBufferInfo::QueueState::setup(VulkanDispatch* vk, VkDevice device,
451 VkQueue queueIn, uint32_t queueFamilyIndexIn,
452 android::base::Lock* queueLockIn) {
453 queue = queueIn;
454 queueFamilyIndex = queueFamilyIndexIn;
455 lock = queueLockIn;
456
457 VkCommandPoolCreateInfo poolCreateInfo = {
458 VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
459 0,
460 VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
461 queueFamilyIndex,
462 };
463
464 vk->vkCreateCommandPool(device, &poolCreateInfo, nullptr, &pool);
465
466 VkCommandBufferAllocateInfo cbAllocInfo = {
467 VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 0, pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1,
468 };
469
470 vk->vkAllocateCommandBuffers(device, &cbAllocInfo, &cb);
471
472 vk->vkAllocateCommandBuffers(device, &cbAllocInfo, &cb2);
473
474 VkFenceCreateInfo fenceCreateInfo = {
475 VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
476 0,
477 0,
478 };
479
480 vk->vkCreateFence(device, &fenceCreateInfo, nullptr, &fence);
481 }
482
teardown(VulkanDispatch * vk,VkDevice device)483 void AndroidNativeBufferInfo::QueueState::teardown(VulkanDispatch* vk, VkDevice device) {
484 if (queue) {
485 AutoLock qlock(*lock);
486 vk->vkQueueWaitIdle(queue);
487 }
488 if (cb) vk->vkFreeCommandBuffers(device, pool, 1, &cb);
489 if (pool) vk->vkDestroyCommandPool(device, pool, nullptr);
490 if (fence) vk->vkDestroyFence(device, fence, nullptr);
491
492 lock = nullptr;
493 queue = VK_NULL_HANDLE;
494 pool = VK_NULL_HANDLE;
495 cb = VK_NULL_HANDLE;
496 fence = VK_NULL_HANDLE;
497 queueFamilyIndex = 0;
498 }
499
setAndroidNativeImageSemaphoreSignaled(VulkanDispatch * vk,VkDevice device,VkQueue defaultQueue,uint32_t defaultQueueFamilyIndex,Lock * defaultQueueLock,VkSemaphore semaphore,VkFence fence,AndroidNativeBufferInfo * anbInfo)500 VkResult setAndroidNativeImageSemaphoreSignaled(VulkanDispatch* vk, VkDevice device,
501 VkQueue defaultQueue,
502 uint32_t defaultQueueFamilyIndex,
503 Lock* defaultQueueLock, VkSemaphore semaphore,
504 VkFence fence, AndroidNativeBufferInfo* anbInfo) {
505 auto fb = FrameBuffer::getFB();
506 auto emu = getGlobalVkEmulation();
507
508 bool firstTimeSetup = !anbInfo->everSynced && !anbInfo->everAcquired;
509
510 anbInfo->everAcquired = true;
511
512 if (firstTimeSetup) {
513 VkSubmitInfo submitInfo = {
514 VK_STRUCTURE_TYPE_SUBMIT_INFO,
515 0,
516 0,
517 nullptr,
518 nullptr,
519 0,
520 nullptr,
521 (uint32_t)(semaphore == VK_NULL_HANDLE ? 0 : 1),
522 semaphore == VK_NULL_HANDLE ? nullptr : &semaphore,
523 };
524 AutoLock qlock(*defaultQueueLock);
525 VK_CHECK(vk->vkQueueSubmit(defaultQueue, 1, &submitInfo, fence));
526 } else {
527 // Setup queue state for this queue family index.
528 auto queueFamilyIndex = anbInfo->lastUsedQueueFamilyIndex;
529 if (queueFamilyIndex >= anbInfo->queueStates.size()) {
530 anbInfo->queueStates.resize(queueFamilyIndex + 1);
531 }
532 AndroidNativeBufferInfo::QueueState& queueState =
533 anbInfo->queueStates[queueFamilyIndex];
534 if (!queueState.queue) {
535 queueState.setup(vk, anbInfo->device, defaultQueue, queueFamilyIndex, defaultQueueLock);
536 }
537
538 // If we used the Vulkan image without copying it back
539 // to the CPU, reset the layout to PRESENT.
540 if (anbInfo->useVulkanNativeImage) {
541 VkCommandBufferBeginInfo beginInfo = {
542 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
543 0,
544 VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
545 nullptr /* no inheritance info */,
546 };
547
548 vk->vkBeginCommandBuffer(queueState.cb2, &beginInfo);
549
550 emu->debugUtilsHelper.cmdBeginDebugLabel(queueState.cb2,
551 "vkAcquireImageANDROID(ColorBuffer:%d)",
552 anbInfo->colorBufferHandle);
553
554 VkImageMemoryBarrier queueTransferBarrier = {
555 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
556 .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
557 .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
558 .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
559 .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
560 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
561 .dstQueueFamilyIndex = anbInfo->lastUsedQueueFamilyIndex,
562 .image = anbInfo->image,
563 .subresourceRange =
564 {
565 VK_IMAGE_ASPECT_COLOR_BIT,
566 0,
567 1,
568 0,
569 1,
570 },
571 };
572 vk->vkCmdPipelineBarrier(queueState.cb2, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
573 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr,
574 1, &queueTransferBarrier);
575
576 emu->debugUtilsHelper.cmdEndDebugLabel(queueState.cb2);
577
578 vk->vkEndCommandBuffer(queueState.cb2);
579
580 VkSubmitInfo submitInfo = {
581 VK_STRUCTURE_TYPE_SUBMIT_INFO,
582 0,
583 0,
584 nullptr,
585 nullptr,
586 1,
587 &queueState.cb2,
588 (uint32_t)(semaphore == VK_NULL_HANDLE ? 0 : 1),
589 semaphore == VK_NULL_HANDLE ? nullptr : &semaphore,
590 };
591
592 AutoLock qlock(*queueState.lock);
593 // TODO(kaiyili): initiate ownership transfer from DisplayVk here
594 VK_CHECK(vk->vkQueueSubmit(queueState.queue, 1, &submitInfo, fence));
595 } else {
596 const AndroidNativeBufferInfo::QueueState& queueState =
597 anbInfo->queueStates[anbInfo->lastUsedQueueFamilyIndex];
598 VkSubmitInfo submitInfo = {
599 VK_STRUCTURE_TYPE_SUBMIT_INFO,
600 0,
601 0,
602 nullptr,
603 nullptr,
604 0,
605 nullptr,
606 (uint32_t)(semaphore == VK_NULL_HANDLE ? 0 : 1),
607 semaphore == VK_NULL_HANDLE ? nullptr : &semaphore,
608 };
609 AutoLock qlock(*queueState.lock);
610 VK_CHECK(vk->vkQueueSubmit(queueState.queue, 1, &submitInfo, fence));
611 }
612 }
613
614 return VK_SUCCESS;
615 }
616
617 static constexpr uint64_t kTimeoutNs = 3ULL * 1000000000ULL;
618
syncImageToColorBuffer(VulkanDispatch * vk,uint32_t queueFamilyIndex,VkQueue queue,Lock * queueLock,uint32_t waitSemaphoreCount,const VkSemaphore * pWaitSemaphores,int * pNativeFenceFd,std::shared_ptr<AndroidNativeBufferInfo> anbInfo)619 VkResult syncImageToColorBuffer(VulkanDispatch* vk, uint32_t queueFamilyIndex, VkQueue queue,
620 Lock* queueLock, uint32_t waitSemaphoreCount,
621 const VkSemaphore* pWaitSemaphores, int* pNativeFenceFd,
622 std::shared_ptr<AndroidNativeBufferInfo> anbInfo) {
623 auto anbInfoPtr = anbInfo.get();
624 auto fb = FrameBuffer::getFB();
625 fb->lock();
626
627 // Implicitly synchronized
628 *pNativeFenceFd = -1;
629
630 anbInfo->everSynced = true;
631 anbInfo->lastUsedQueueFamilyIndex = queueFamilyIndex;
632
633 // Setup queue state for this queue family index.
634 if (queueFamilyIndex >= anbInfo->queueStates.size()) {
635 anbInfo->queueStates.resize(queueFamilyIndex + 1);
636 }
637
638 auto& queueState = anbInfo->queueStates[queueFamilyIndex];
639
640 if (!queueState.queue) {
641 queueState.setup(vk, anbInfo->device, queue, queueFamilyIndex, queueLock);
642 }
643
644 auto emu = getGlobalVkEmulation();
645
646 // Record our synchronization commands.
647 VkCommandBufferBeginInfo beginInfo = {
648 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
649 0,
650 VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
651 nullptr /* no inheritance info */,
652 };
653
654 vk->vkBeginCommandBuffer(queueState.cb, &beginInfo);
655
656 emu->debugUtilsHelper.cmdBeginDebugLabel(queueState.cb,
657 "vkQueueSignalReleaseImageANDROID(ColorBuffer:%d)",
658 anbInfo->colorBufferHandle);
659
660 // If using the Vulkan image directly (rather than copying it back to
661 // the CPU), change its layout for that use.
662 if (anbInfo->useVulkanNativeImage) {
663 VkImageMemoryBarrier queueTransferBarrier = {
664 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
665 .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
666 .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
667 .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
668 .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
669 .srcQueueFamilyIndex = queueFamilyIndex,
670 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
671 .image = anbInfo->image,
672 .subresourceRange =
673 {
674 VK_IMAGE_ASPECT_COLOR_BIT,
675 0,
676 1,
677 0,
678 1,
679 },
680 };
681 vk->vkCmdPipelineBarrier(queueState.cb, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
682 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1,
683 &queueTransferBarrier);
684
685 } else {
686 // Not a GL texture. Read it back and put it back in present layout.
687
688 // From the spec: If an application does not need the contents of a resource
689 // to remain valid when transferring from one queue family to another, then
690 // the ownership transfer should be skipped.
691 // We definitely need to transition the image to
692 // VK_TRANSFER_SRC_OPTIMAL and back.
693 VkImageMemoryBarrier presentToTransferSrc = {
694 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
695 0,
696 0,
697 VK_ACCESS_TRANSFER_READ_BIT,
698 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
699 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
700 VK_QUEUE_FAMILY_IGNORED,
701 VK_QUEUE_FAMILY_IGNORED,
702 anbInfo->image,
703 {
704 VK_IMAGE_ASPECT_COLOR_BIT,
705 0,
706 1,
707 0,
708 1,
709 },
710 };
711
712 vk->vkCmdPipelineBarrier(queueState.cb, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
713 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1,
714 &presentToTransferSrc);
715
716 VkBufferImageCopy region = {
717 0 /* buffer offset */,
718 anbInfo->extent.width,
719 anbInfo->extent.height,
720 {
721 VK_IMAGE_ASPECT_COLOR_BIT,
722 0,
723 0,
724 1,
725 },
726 {0, 0, 0},
727 anbInfo->extent,
728 };
729
730 vk->vkCmdCopyImageToBuffer(queueState.cb, anbInfo->image,
731 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, anbInfo->stagingBuffer, 1,
732 ®ion);
733
734 // Transfer back to present src.
735 VkImageMemoryBarrier backToPresentSrc = {
736 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
737 0,
738 VK_ACCESS_TRANSFER_READ_BIT,
739 0,
740 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
741 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
742 VK_QUEUE_FAMILY_IGNORED,
743 VK_QUEUE_FAMILY_IGNORED,
744 anbInfo->image,
745 {
746 VK_IMAGE_ASPECT_COLOR_BIT,
747 0,
748 1,
749 0,
750 1,
751 },
752 };
753
754 vk->vkCmdPipelineBarrier(queueState.cb, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
755 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1,
756 &backToPresentSrc);
757 }
758
759 emu->debugUtilsHelper.cmdEndDebugLabel(queueState.cb);
760
761 vk->vkEndCommandBuffer(queueState.cb);
762
763 std::vector<VkPipelineStageFlags> pipelineStageFlags;
764 pipelineStageFlags.resize(waitSemaphoreCount, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
765
766 VkSubmitInfo submitInfo = {
767 VK_STRUCTURE_TYPE_SUBMIT_INFO,
768 0,
769 waitSemaphoreCount,
770 pWaitSemaphores,
771 pipelineStageFlags.data(),
772 1,
773 &queueState.cb,
774 0,
775 nullptr,
776 };
777
778 // TODO(kaiyili): initiate ownership transfer to DisplayVk here.
779 VkFence qsriFence = anbInfo->qsriWaitFencePool->getFenceFromPool();
780 AutoLock qLock(*queueLock);
781 VK_CHECK(vk->vkQueueSubmit(queueState.queue, 1, &submitInfo, qsriFence));
782 auto waitForQsriFenceTask = [anbInfoPtr, anbInfo, vk, device = anbInfo->device, qsriFence] {
783 (void)anbInfoPtr;
784 VK_ANB_DEBUG_OBJ(anbInfoPtr, "wait callback: enter");
785 VK_ANB_DEBUG_OBJ(anbInfoPtr, "wait callback: wait for fence %p...", qsriFence);
786 VkResult res = vk->vkWaitForFences(device, 1, &qsriFence, VK_FALSE, kTimeoutNs);
787 switch (res) {
788 case VK_SUCCESS:
789 break;
790 case VK_TIMEOUT:
791 VK_ANB_ERR("Timeout when waiting for the Qsri fence.");
792 break;
793 default:
794 ERR("Failed to wait for QSRI fence: %s\n", string_VkResult(res));
795 VK_CHECK(res);
796 }
797 VK_ANB_DEBUG_OBJ(anbInfoPtr, "wait callback: wait for fence %p...(done)", qsriFence);
798 anbInfo->qsriWaitFencePool->returnFence(qsriFence);
799 };
800 fb->unlock();
801
802 if (anbInfo->useVulkanNativeImage) {
803 VK_ANB_DEBUG_OBJ(anbInfoPtr, "using native image, so use sync thread to wait");
804 // Queue wait to sync thread with completion callback
805 // Pass anbInfo by value to get a ref
806 SyncThread::get()->triggerGeneral(
807 [waitForQsriFenceTask = std::move(waitForQsriFenceTask), anbInfo]() mutable {
808 waitForQsriFenceTask();
809 anbInfo->qsriTimeline->signalNextPresentAndPoll();
810 },
811 "wait for the guest Qsri VkFence signaled");
812 } else {
813 VK_ANB_DEBUG_OBJ(anbInfoPtr, "not using native image, so wait right away");
814 waitForQsriFenceTask();
815
816 VkMappedMemoryRange toInvalidate = {
817 VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, anbInfo->stagingMemory, 0, VK_WHOLE_SIZE,
818 };
819
820 vk->vkInvalidateMappedMemoryRanges(anbInfo->device, 1, &toInvalidate);
821
822 uint32_t colorBufferHandle = anbInfo->colorBufferHandle;
823
824 // Copy to from staging buffer to color buffer
825 uint32_t bpp = 4; /* format always rgba8...not */
826 switch (anbInfo->vkFormat) {
827 case VK_FORMAT_R5G6B5_UNORM_PACK16:
828 bpp = 2;
829 break;
830 case VK_FORMAT_R8G8B8_UNORM:
831 bpp = 3;
832 break;
833 default:
834 case VK_FORMAT_R8G8B8A8_UNORM:
835 case VK_FORMAT_B8G8R8A8_UNORM:
836 bpp = 4;
837 break;
838 }
839
840 FrameBuffer::getFB()->flushColorBufferFromVkBytes(
841 colorBufferHandle, anbInfo->mappedStagingPtr,
842 bpp * anbInfo->extent.width * anbInfo->extent.height);
843 anbInfo->qsriTimeline->signalNextPresentAndPoll();
844 }
845
846 return VK_SUCCESS;
847 }
848
849 } // namespace vk
850 } // namespace gfxstream
851