[Mesa-dev] [PATCH 09/17] mesa/st: add support for waiting for semaphore objects
Andres Rodriguez
andresx7 at gmail.com
Fri Nov 3 17:36:46 UTC 2017
On 2017-11-03 05:17 AM, Nicolai Hähnle wrote:
> On 02.11.2017 04:57, Andres Rodriguez wrote:
>> Bits to implement ServerWaitSemaphoreObject/ServerSignalSemaphoreObject
>>
>> Signed-off-by: Andres Rodriguez <andresx7 at gmail.com>
>> ---
>> src/mesa/state_tracker/st_cb_semaphoreobjects.c | 28
>> +++++++++++++++++++++++++
>> 1 file changed, 28 insertions(+)
>>
>> diff --git a/src/mesa/state_tracker/st_cb_semaphoreobjects.c
>> b/src/mesa/state_tracker/st_cb_semaphoreobjects.c
>> index 47ece47..4cff3fd 100644
>> --- a/src/mesa/state_tracker/st_cb_semaphoreobjects.c
>> +++ b/src/mesa/state_tracker/st_cb_semaphoreobjects.c
>> @@ -1,5 +1,7 @@
>> +
>> #include "main/imports.h"
>> #include "main/mtypes.h"
>> +#include "main/context.h"
>> #include "main/externalobjects.h"
>> @@ -47,10 +49,36 @@ st_import_semaphoreobj_fd(struct gl_context *ctx,
>> #endif
>> }
>> +static void
>> +st_server_wait_semaphore(struct gl_context *ctx,
>> + struct gl_semaphore_object *semObj)
>> +{
>> + struct st_semaphore_object *st_obj = st_semaphore_object(semObj);
>> + struct st_context *st = st_context(ctx);
>> + struct pipe_context *pipe = st->pipe;
>> +
>> + _mesa_flush(ctx);
>
> What's the justification of this flush?
Thanks for all the review feedback :)
Technically according to the spec we shouldn't need to flush here. But
the flush is required due to how amdgpu handles syncobjs.
For amdgpu, the wait and signal operations happens on a submission
boundary. I.e, we can say "wait for this syncobj before executing this
submission", or "signal this syncobj after this submission completes".
But we can't really introduce a wait/signal in the middle of a
commandstream as the spec requires us to do.
This flush (and the one in st_server_signal_semaphore) exist to adjust
the submission boundaries. If we align the submission boundary with the
semaphore operation boundary we can accurately emulate the timing of the
semaphore operations.
In this case, when st_server_wait_semaphore() is called, the user
expects that any work queued up until this point will not wait for the
semaphore. Any work submitted after the wait call returns should wait
for the semaphore to signal. Hence, we call flush so that the amdgpu
winsys will submit all the current work. Then we queue up the syncobj
for future submissions to wait on.
In the signal case, we flush so that the syncobj will signal when the
current work finishes (instead of at "current work + N"). That way we
don't have any unnecessary latency.
However, I'm not 100% certain my approach here is the best solution. My
main concern is that an amdgpu specific detail is surfaced in what
should be a pipe agnostic layer. If you have any recommendations on how
to move this code into the pipe layer, or achieve the same results with
a different strategy I'd love to take the advice.
From the performance point of view, I'm not as concerned. Wait/signal
tend to be aligned at frame boundaries so flushing there shouldn't be a
big deal. But I do think that improving the code structure from my
current iteration would have value.
>
>
>> + pipe->semobj_wait(pipe, st_obj->semaphore);
>> +}
>> +
>> +static void
>> +st_server_signal_semaphore(struct gl_context *ctx,
>> + struct gl_semaphore_object *semObj)
>> +{
>> + struct st_semaphore_object *st_obj = st_semaphore_object(semObj);
>> + struct st_context *st = st_context(ctx);
>> + struct pipe_context *pipe = st->pipe;
>> +
>
> You have to flush state-tracker internal state here. This means
> FLUSH_VERTICES, st_flush_bitmap, possibly others. I don't think we have
> this factored out well yet, but see below.
Thanks for pointing this out, this actually gives me an idea for getting
rid of the full flushes, see below.
>
>
>> + pipe->semobj_signal(pipe, st_obj->semaphore);
>> + _mesa_flush(ctx);
>
> What's the justification of this flush? Does EXT_external_objects
> contain any language to guarantee that SignalSemaphoreEXT will "finish
> in finite time"? If no, the flush should probably not be there. If yes,
> please add a spec quote.
See above for the flush reasoning.
>
> Furthermore, this whole code section is a strong hint that merging
> fences and semaphores at the Gallium level is indeed a good idea.
> Basically, the idea is that you'd end up calling
>
> pipe->flush(pipe, &st_obj->semaphore, flags);
>
> where flags is PIPE_FLUSH_DEFERRED | PIPE_FLUSH_REUSE_FENCE or
> PIPE_FLUSH_ASYNC | PIPE_FLUSH_REUSE_FENCE, depending on how the previous
> paragraph is resolved. In one of my recent series that includes deferred
> fences for threaded contexts, I'm already doing the equivalent of adding
> a "PIPE_FLUSH_REUSE_FENCE". We could formalize this as a more broadly
> applicable feature in the Gallium interface.
>
Thanks for pointing out PIPE_FLUSH_REUSE_FENCE, I wasn't aware of this flag.
My reasoning for keeping semaphore operations separate is that a
different pipe implementation might be able to emit a wait/signal packet
into the middle of the commandstream, with no flushing required.
However, that argument has a giant hole in it. I have a _mesa_flush()
which completely negates any benefits of a "pipe agnostic"
implementation. So in this case, as you suggested, I think merging
semaphores with re-usable fences would be a good idea.
I do have one alternative proposal try to keep the option of
mid-commandstream semaphores open. How about something like:
flush_state_tracker_internal_state() {
flush_vertices();
flush_bitmaps();
}
st_server_wait_semaphore() {
flush_state_tracker_internal_state();
pipe->semobj_wait(pipe, st_obj->semaphore);
// The amdgpu semobj_wait() implementation would
// then be responsible for adjusting the submission
// windows internally, i.e. calling flush()
}
st_server_signal_semaphore() {
flush_state_tracker_internal_state();
pipe->semobj_signal(pipe, st_obj->semaphore);
// The amdgpu semobj_signal() implementation would
// then be responsible for adjusting the submission
// windows internally, i.e. calling flush()
}
Let me know what you think of this slightly more agnostic implementation.
Sorry for the long reply!
Regards,
Andres
> Cheers,
> Nicolai
>
>
>> +}
>> +
>> void
>> st_init_semaphoreobject_functions(struct dd_function_table *functions)
>> {
>> functions->NewSemaphoreObject = st_semaphoreobj_alloc;
>> functions->DeleteSemaphoreObject = st_semaphoreobj_free;
>> functions->ImportSemaphoreFd = st_import_semaphoreobj_fd;
>> + functions->ServerWaitSemaphoreObject = st_server_wait_semaphore;
>> + functions->ServerSignalSemaphoreObject = st_server_signal_semaphore;
>> }
>>
>
>
More information about the mesa-dev
mailing list