Can I check if a semaphore has signaled already?

TL;DR
Is there anyway I can let GPU check and do not wait if pWaitSemaphores have signaled already? Can VK_SEMAPHORE_TYPE_TIMELINE do this?

Details
In my case, I have a submission B, which waits on a signal which is sent by submission A. The problem is that for performance reason, I didn’t submit A and B at once, in which case A has signaled already while B was not submitted, so is there any way I can check if the semaphore has already signaled?

I tried to add an extra fence, but I’m afraid of the case that

  1. I checked fence with vkGetFenceStatus , and it is not ready (not signaled)
  2. I am submitting a command buffer, meanwhile the pWaitSemaphores of this CB signaled.
  3. This CB will wait forever.

Will this happen?

And of-cause I can wait on that fence, but I guess if I can find a way that let the GPU check the signal, it will perform way better than using a fence (because submitting commands take times too, wait the fence than submit will waste some time).

I looked up the timeline semaphore, but didn’t find clues that this kind of semaphore can do what I want.

I found that timeline semophore can do exactly what I want, from this tutorial, the only thing is that what my problem involving Vulkan window system, but it currently works not well with timeline semaphore.

Why do you think this will matter? Do you think the GPU is incapable of checking to see if a semaphore has already signaled before blocking on it?

Just let the implementation do its job.

That’s not necessarily true. Just because you submit a batch doesn’t mean that batch has finished (and therefore has signaled its semaphores). The semaphore is only signaled when the batch has completed execution.

In fact, you are not allowed to submit a batch that waits on a binary semaphore before you have submitted the batch that signals that semaphore. That is, you cannot submit B before A.

I think you are misunderstanding, I know that submission success does not equal to execution finished, in my case, I submit A, and wait for 10ms, then submit B, If A already executed, the signal will send, but B could not submit yet, and B hangs for waiting semaphore when it is submitted.

Do you suggest that what I met is impossible (so I must make other mistakes)? Does the implementation guaranteed that command buffers will not wait on a signaled semaphore (not like semaphore we use on CPU coding)?

How do you know that it hangs?

No, but I trust that implementers have a vested interest in making their queues execute quickly. So the GPU probably isn’t going to ignore the possibility that a semaphore is already signaled when a batch begins execution.

How do you know that it hangs?

Sorry, I don’t know, it’s just that my buffer does not get updated, while after I tried using timeline semaphore, it works… I may use validate layers later to prove.

I asked because I usually not dare to depend on something that is not guaranteed…

Have you ever come across situations like I mentioned (two submissions in an interval)? As you experience, do you just rely on semaphores, no matter the previous submission executed or not?

Yea, timeline semaphores provide vkGetSemaphoreCounterValueKHR. Sounds like extremely paranoid optimization though. Possibly would hurt matters.

This is not a good way to write code in Vulkan. Trying stuff and seeing what “works” isn’t how you learn Vulkan.

Vulkan is not a safe API; there are a myriad of ways to fall into undefined behavior that may “work” on some hardware, or on some driver revision on the same hardware. But unless it is guaranteed by the specification, reliance on it is not a viable path.

This is why validation layers exist. They help ensure that you’re correctly writing Vulkan code. They help ensure that you have the memory barriers, dependencies, and so forth that the API requires, even if some code just so happens to “work” on your local hardware.

You should never assume that your code is correct just because it appears to “work”. If you don’t know that its correct, if you can’t prove that it’s following the specification, then it should be assumed not to be.

It should also be noted that binary semaphores cannot be reset from the CPU. If you submit a batch that signals a semaphore, but nothing waits on it, that semaphore will remain signaled. Forever. The only thing you can do to it is delete it; you can’t reuse a signaled semaphore.

So if you signal a binary semaphore, you should always wait on it.

I’m a little confused of the behaviors of binary semaphore here, it seems that the semaphore I understand is totally wrong.

It should also be noted that binary semaphores cannot be reset from the CPU. If you submit a batch that signals a semaphore, but nothing waits on it, that semaphore will remain signaled. Forever. The only thing you can do to it is delete it; you can’t reuse a signaled semaphore.

Do you suggest that binary semaphore is just a “boolean”, the state is only signaled or not, and only be reset by command buffers which wait on it? Cause all example I got use same semaphores frame to frame, not re-creating new ones, so there must be somewhere, that the semaphores are get reset, right?

Yes: they get reset by waiting on them. That is, when the batch that waits on a semaphore sees that it is signaled, the batch resets the semaphore to unsignaled.

This is the only way a binary semaphore becomes unsignaled. That’s why I said:

If you submit a batch that signals a semaphore, but nothing waits on it, that semaphore will remain signaled.

1 Like

I seem to know what I am wrong about my code, I did misunderstand how semaphore works.

May I ask how do you know these details? All the tutorials didn’t talk much about semaphores, let alone these details, even the doc of VkSemaphore doesn’t mention that. I totally misunderstand them like it signals to all waits.

And thanks for your advice, I am indeed not using validate layer very much, this is a bad habit.

The Vulkan specification.

1 Like