Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible invalid synchronization #276

Open
mtvec opened this issue Mar 7, 2022 · 6 comments
Open

Possible invalid synchronization #276

mtvec opened this issue Mar 7, 2022 · 6 comments

Comments

@mtvec
Copy link

mtvec commented Mar 7, 2022

It seems to me that the following sequence of events could happen in 15_hello_triangle.cpp:

Step CPU GPU GPU Queue
1 drawFrame(F1) []
2 wait(fence) []
3 acquire(signal=iaSem) []
4 T1 = submit(F1, wait=iaSem, signal=rfSem,fence) [T1]
5 T2 = present(F1, wait=rfSem) [T1, T2]
6 drawFrame(F2) [T1, T2]
7 wait(fence) [T1, T2]
8 (blocked) finish T1 (signal rfSem/fence) [T2]
9 acquire(signal=iaSem) [T2]
10 T3 = submit(F2, wait=iaSem, signal=rfSem,fence) [T2, T3]

In step10, vkQueueSubmit is called with renderFinishedSemaphore to signal which is already in the signaled state (signaled in step 8 and not yet unsignaled by the GPU). This seems illegal according to the spec:

Each binary semaphore element of the pSignalSemaphores member of any element of pSubmits must be unsignaled when the semaphore signal operation it defines is executed on the device

Is the some implicit synchronization mechanism that ensures that T2 already started (and hence waited on/unsignaled renderFinishedSemaphore) at this point or is it actually invalid?

@charles-lunarg
Copy link
Contributor

I do not believe this is a synchronization issue because the fence that is waited on in step 7 guarantees that the rfSem has signaled. The spec line quoted indicates that its fine to use a semaphore if it will be unsignaled by the time it is waited on.
Maybe my understanding of semaphore resetting is mistaken, where the vkQueuePresent has to 'finish' (and reset the semaphore) for the sync to be correct.

The issue is that there is no Vulkan 1.0 mechanism to query whether a swapchain image is finished being presented on except for getting the same swapchain image index again. Since this chapter is trying to introduce synchronization, I wanted it to be as simple as possible. Does the following chapter (where multiple frames in flight are introduced) have the same issue? If so that would be the place to fix it in my opinion.

@mtvec
Copy link
Author

mtvec commented Mar 8, 2022

I do not believe this is a synchronization issue because the fence that is waited on in step 7 guarantees that the rfSem has signaled. The spec line quoted indicates that its fine to use a semaphore if it will be unsignaled by the time it is waited on.

And is there a mechanism that ensures it will be unsignaled by that time? At the time of the call to vkQueueSubmit it could definitely still be signaled as per my example but maybe by the time the semaphore is waited in, the present task (T2) is guaranteed to have waited on/unsignaled rfSem? If so, does this still hold when separate queues are used for graphics and presentation?

Does the following chapter (where multiple frames in flight are introduced) have the same issue?

As far as I can tell, when setting MAX_FRAMES_IN_FLIGHT to 1, the code there is equivalent to the code in this chapter. So the same issue (if it is one) should still exist there. I might try to write-out an example with MAX_FRAMES_IN_FLIGHT == 2 later.

@charles-lunarg
Copy link
Contributor

From my understanding the reason why it works is because of the use of a single queue. Essentially the queue forward progress guarantees make this synchronization work. However I am not an expert on this subject and don't have a stronger answer for why it works.

@zeno-endemann-kdab
Copy link

I have only just now looked into this, so I may not understand this fully, but judging from this comment to fix this issue, you need to use swapChainImages.size() renderFinishedSemaphores (instead of MAX_FRAMES_IN_FLIGHT).

@charles-lunarg
Copy link
Contributor

charles-lunarg commented Oct 5, 2022

Yes, that is actually the provably more correct solution.

The core of the issue is that this is currently a 'underspecified' part of the spec, or at least without the VK_EXT_present_wait extension that has limited support. So while on most drivers this works just fine, it would be good to improve the text with that change. Not a very satisfactory answer, but WSI in vulkan is not a good API and the people who wrote it know that.

@zeno-endemann-kdab
Copy link

FYI, I have put up a modified version of the code that fixes this as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants