graphicssynchronizationexternalvulkancross-process

What is the point to use copy of exported fence or semaphore in vulkan?


I am trying to synchronize access to external memory across 2 processes on android vulkan, my system is telling me that it is only supporting

VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT

which can be exported as as copy, not as a reference.

What I am doing is this in process A ( exporting fd )

CALL_VK(vkQueueSubmit(queue, 1, &submit_info, fence));

int fd;
VkFenceGetFdInfoKHR getFdInfo{};
getFdInfo.sType = VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR;
getFdInfo.handleType = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
getFdInfo.fence = fence;
CALL_VK(vkGetFenceFdKHR(device.device_, &getFdInfo, &fd));

and then this in process B ( importing copy of a payload from a fd)

VkImportFenceFdInfoKHR importFenceFdInfo{};
importFenceFdInfo.sType = VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR;
importFenceFdInfo.handleType = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
importFenceFdInfo.fd = fd;
importFenceFdInfo.fence = fence;
importFenceFdInfo.flags = VK_FENCE_IMPORT_TEMPORARY_BIT;

CALL_VK(vkImportFenceFdKHR(device.device_, &importFenceFdInfo));

The thing is if in the process B the fence I've got back is still unsignalled ( it was pending after vkQueueSubmit ) then since this is a copy and not a reference it will never be signalled and I will never know when my GPU runtime will have been finished. I am getting a freeze in the following call in my process B

VkResult result = vkWaitForFences(device, 1, &fence, VK_TRUE, -1);

Then what is the point in all this?

I am expecting that I shall be able to get the state of the fence updated in my process B once it is signalled by GPU.


Solution

  • When you perform a fence import operation, that operation has a "transference" associated with it. Reference transference means that the fence you imported into is able to directly see the state of the fence payload at all times. If it waits on the fence to be signaled, then it will be woken up when that happens.

    Copy transference means that it sees the state of the fence payload only at the moment the transfer happens. Any subsequent changes in the fence's payload are not available.

    If it is your intent to have some process wait until a fence in a different process has completed, it cannot do this by performing a copy transference only once. It basically has to poll the other process through importing the fence, with each import seeing the payload state at the time of the polling.

    And of course, you need to build in some system for the other process to know that the listening process has seen the signaling of the fence. Otherwise, the signaling process might reset the fence before the listening process has seen the signal.

    Note that if an implementation restricts you to temporary, reference importation only, that represents a hardware limitation. So polling (along with listener protection) is the best the system allows. So Vulkan forces you to do it manually.