panfrost: Prepare panfrost_fence for batch pipelining

The panfrost_fence logic currently waits on the last submitted batch,
but the batch serialization that was enforced in
panfrost_batch_submit() is about to go away, allowing for several
batches to be pipelined, and the last submitted one is not necessarily
the one that will finish last.

We need to make sure the fence logic waits on all flushed batches, not
only the last one.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
This commit is contained in:
Boris Brezillon
2019-09-15 18:23:10 +02:00
parent 2dad9fde50
commit b5d8f9bbbf
5 changed files with 57 additions and 56 deletions

View File

@@ -1343,14 +1343,30 @@ panfrost_flush(
{ {
struct panfrost_context *ctx = pan_context(pipe); struct panfrost_context *ctx = pan_context(pipe);
struct panfrost_batch *batch = panfrost_get_batch_for_fbo(ctx); struct panfrost_batch *batch = panfrost_get_batch_for_fbo(ctx);
struct util_dynarray fences;
/* We must collect the fences before the flush is done, otherwise we'll
* lose track of them.
*/
if (fence) {
util_dynarray_init(&fences, NULL);
panfrost_batch_fence_reference(batch->out_sync);
util_dynarray_append(&fences, struct panfrost_batch_fence *,
batch->out_sync);
}
/* Submit the frame itself */ /* Submit the frame itself */
panfrost_batch_submit(batch); panfrost_batch_submit(batch);
if (fence) { if (fence) {
struct panfrost_fence *f = panfrost_fence_create(ctx); struct panfrost_fence *f = panfrost_fence_create(ctx, &fences);
pipe->screen->fence_reference(pipe->screen, fence, NULL); pipe->screen->fence_reference(pipe->screen, fence, NULL);
*fence = (struct pipe_fence_handle *)f; *fence = (struct pipe_fence_handle *)f;
util_dynarray_foreach(&fences, struct panfrost_batch_fence *, fence)
panfrost_batch_fence_unreference(*fence);
util_dynarray_fini(&fences);
} }
} }

View File

@@ -94,7 +94,7 @@ struct panfrost_query {
struct panfrost_fence { struct panfrost_fence {
struct pipe_reference reference; struct pipe_reference reference;
int fd; struct util_dynarray syncfds;
}; };
struct panfrost_streamout { struct panfrost_streamout {
@@ -193,9 +193,6 @@ struct panfrost_context {
/* True for t6XX, false for t8xx. */ /* True for t6XX, false for t8xx. */
bool is_t6xx; bool is_t6xx;
/* The out sync fence of the last submitted batch. */
struct panfrost_batch_fence *last_out_sync;
}; };
/* Corresponds to the CSO */ /* Corresponds to the CSO */

View File

@@ -819,13 +819,6 @@ panfrost_batch_submit_ioctl(struct panfrost_batch *batch,
free(bo_handles); free(bo_handles);
free(in_syncs); free(in_syncs);
/* Release the last batch fence if any, and retain the new one */
if (ctx->last_out_sync)
panfrost_batch_fence_unreference(ctx->last_out_sync);
panfrost_batch_fence_reference(batch->out_sync);
ctx->last_out_sync = batch->out_sync;
if (ret) { if (ret) {
fprintf(stderr, "Error submitting: %m\n"); fprintf(stderr, "Error submitting: %m\n");
return errno; return errno;
@@ -884,15 +877,6 @@ panfrost_batch_submit(struct panfrost_batch *batch)
* to wait on it. * to wait on it.
*/ */
batch->out_sync->signaled = true; batch->out_sync->signaled = true;
/* Release the last batch fence if any, and set ->last_out_sync
* to NULL
*/
if (ctx->last_out_sync) {
panfrost_batch_fence_unreference(ctx->last_out_sync);
ctx->last_out_sync = NULL;
}
goto out; goto out;
} }

View File

@@ -575,7 +575,9 @@ panfrost_fence_reference(struct pipe_screen *pscreen,
struct panfrost_fence *old = *p; struct panfrost_fence *old = *p;
if (pipe_reference(&(*p)->reference, &f->reference)) { if (pipe_reference(&(*p)->reference, &f->reference)) {
close(old->fd); util_dynarray_foreach(&old->syncfds, int, fd)
close(*fd);
util_dynarray_fini(&old->syncfds);
free(old); free(old);
} }
*p = f; *p = f;
@@ -589,66 +591,67 @@ panfrost_fence_finish(struct pipe_screen *pscreen,
{ {
struct panfrost_screen *screen = pan_screen(pscreen); struct panfrost_screen *screen = pan_screen(pscreen);
struct panfrost_fence *f = (struct panfrost_fence *)fence; struct panfrost_fence *f = (struct panfrost_fence *)fence;
struct util_dynarray syncobjs;
int ret; int ret;
unsigned syncobj;
/* The fence was already signaled */ /* All fences were already signaled */
if (f->fd == -1) if (!util_dynarray_num_elements(&f->syncfds, int))
return true; return true;
ret = drmSyncobjCreate(screen->fd, 0, &syncobj); util_dynarray_init(&syncobjs, NULL);
if (ret) { util_dynarray_foreach(&f->syncfds, int, fd) {
fprintf(stderr, "Failed to create syncobj to wait on: %m\n"); uint32_t syncobj;
return false;
}
ret = drmSyncobjImportSyncFile(screen->fd, syncobj, f->fd); ret = drmSyncobjCreate(screen->fd, 0, &syncobj);
if (ret) { assert(!ret);
fprintf(stderr, "Failed to import fence to syncobj: %m\n");
return false; ret = drmSyncobjImportSyncFile(screen->fd, syncobj, *fd);
assert(!ret);
util_dynarray_append(&syncobjs, uint32_t, syncobj);
} }
uint64_t abs_timeout = os_time_get_absolute_timeout(timeout); uint64_t abs_timeout = os_time_get_absolute_timeout(timeout);
if (abs_timeout == OS_TIMEOUT_INFINITE) if (abs_timeout == OS_TIMEOUT_INFINITE)
abs_timeout = INT64_MAX; abs_timeout = INT64_MAX;
ret = drmSyncobjWait(screen->fd, &syncobj, 1, abs_timeout, 0, NULL); ret = drmSyncobjWait(screen->fd, util_dynarray_begin(&syncobjs),
util_dynarray_num_elements(&syncobjs, uint32_t),
abs_timeout, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL,
NULL);
drmSyncobjDestroy(screen->fd, syncobj); util_dynarray_foreach(&syncobjs, uint32_t, syncobj)
drmSyncobjDestroy(screen->fd, *syncobj);
return ret >= 0; return ret >= 0;
} }
struct panfrost_fence * struct panfrost_fence *
panfrost_fence_create(struct panfrost_context *ctx) panfrost_fence_create(struct panfrost_context *ctx,
struct util_dynarray *fences)
{ {
struct panfrost_screen *screen = pan_screen(ctx->base.screen); struct panfrost_screen *screen = pan_screen(ctx->base.screen);
struct panfrost_fence *f = calloc(1, sizeof(*f)); struct panfrost_fence *f = calloc(1, sizeof(*f));
if (!f) if (!f)
return NULL; return NULL;
f->fd = -1; util_dynarray_init(&f->syncfds, NULL);
/* There was no job flushed yet or the batch fence was already /* Export fences from all pending batches. */
* signaled, let's return a dummy fence object that returns true util_dynarray_foreach(fences, struct panfrost_batch_fence *, fence) {
* directly when ->fence_finish() is called. int fd = -1;
*/
if (!ctx->last_out_sync || ctx->last_out_sync->signaled)
goto out;
/* Snapshot the last Panfrost's rendering's out fence. We'd rather have /* The fence is already signaled, no need to export it. */
* another syncobj instead of a sync file, but this is all we get. if ((*fence)->signaled)
* (HandleToFD/FDToHandle just gives you another syncobj ID for the continue;
* same syncobj).
*/ drmSyncobjExportSyncFile(screen->fd, (*fence)->syncobj, &fd);
drmSyncobjExportSyncFile(screen->fd, ctx->last_out_sync->syncobj, &f->fd); if (fd == -1)
if (f->fd == -1) { fprintf(stderr, "export failed: %m\n");
fprintf(stderr, "export failed: %m\n");
free(f); assert(fd != -1);
return NULL; util_dynarray_append(&f->syncfds, int, fd);
} }
out:
pipe_reference_init(&f->reference, 1); pipe_reference_init(&f->reference, 1);
return f; return f;

View File

@@ -101,6 +101,7 @@ pan_screen(struct pipe_screen *p)
} }
struct panfrost_fence * struct panfrost_fence *
panfrost_fence_create(struct panfrost_context *ctx); panfrost_fence_create(struct panfrost_context *ctx,
struct util_dynarray *fences);
#endif /* PAN_SCREEN_H */ #endif /* PAN_SCREEN_H */