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