101e04c3fSmrg/*
201e04c3fSmrg * Copyright © 2014 Broadcom
301e04c3fSmrg *
401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
501e04c3fSmrg * copy of this software and associated documentation files (the "Software"),
601e04c3fSmrg * to deal in the Software without restriction, including without limitation
701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the
901e04c3fSmrg * Software is furnished to do so, subject to the following conditions:
1001e04c3fSmrg *
1101e04c3fSmrg * The above copyright notice and this permission notice (including the next
1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the
1301e04c3fSmrg * Software.
1401e04c3fSmrg *
1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2101e04c3fSmrg * IN THE SOFTWARE.
2201e04c3fSmrg */
2301e04c3fSmrg
2401e04c3fSmrg/** @file v3d_fence.c
2501e04c3fSmrg *
2601e04c3fSmrg * Seqno-based fence management.
2701e04c3fSmrg *
2801e04c3fSmrg * We have two mechanisms for waiting in our kernel API: You can wait on a BO
2901e04c3fSmrg * to have all rendering to from any process to be completed, or wait on a
3001e04c3fSmrg * seqno for that particular seqno to be passed.  The fence API we're
3101e04c3fSmrg * implementing is based on waiting for all rendering in the context to have
3201e04c3fSmrg * completed (with no reference to what other processes might be doing with
3301e04c3fSmrg * the same BOs), so we can just use the seqno of the last rendering we'd
3401e04c3fSmrg * fired off as our fence marker.
3501e04c3fSmrg */
3601e04c3fSmrg
3701e04c3fSmrg#include "util/u_inlines.h"
3801e04c3fSmrg#include "util/os_time.h"
3901e04c3fSmrg
4001e04c3fSmrg#include "v3d_context.h"
4101e04c3fSmrg#include "v3d_bufmgr.h"
4201e04c3fSmrg
4301e04c3fSmrgstruct v3d_fence {
4401e04c3fSmrg        struct pipe_reference reference;
4501e04c3fSmrg        int fd;
4601e04c3fSmrg};
4701e04c3fSmrg
4801e04c3fSmrgstatic void
4901e04c3fSmrgv3d_fence_reference(struct pipe_screen *pscreen,
5001e04c3fSmrg                    struct pipe_fence_handle **pp,
5101e04c3fSmrg                    struct pipe_fence_handle *pf)
5201e04c3fSmrg{
5301e04c3fSmrg        struct v3d_fence **p = (struct v3d_fence **)pp;
5401e04c3fSmrg        struct v3d_fence *f = (struct v3d_fence *)pf;
5501e04c3fSmrg        struct v3d_fence *old = *p;
5601e04c3fSmrg
5701e04c3fSmrg        if (pipe_reference(&(*p)->reference, &f->reference)) {
5801e04c3fSmrg                close(old->fd);
5901e04c3fSmrg                free(old);
6001e04c3fSmrg        }
6101e04c3fSmrg        *p = f;
6201e04c3fSmrg}
6301e04c3fSmrg
647ec681f3Smrgvoid
657ec681f3Smrgv3d_fence_unreference(struct v3d_fence **fence)
6601e04c3fSmrg{
677ec681f3Smrg        assert(fence);
687ec681f3Smrg
697ec681f3Smrg        if (!*fence)
707ec681f3Smrg                return;
7101e04c3fSmrg
727ec681f3Smrg        v3d_fence_reference(NULL, (struct pipe_fence_handle **)fence, NULL);
737ec681f3Smrg}
747ec681f3Smrg
757ec681f3Smrgbool
767ec681f3Smrgv3d_fence_wait(struct v3d_screen *screen,
777ec681f3Smrg               struct v3d_fence *fence,
787ec681f3Smrg               uint64_t timeout_ns)
797ec681f3Smrg{
807ec681f3Smrg        int ret;
8101e04c3fSmrg        unsigned syncobj;
827ec681f3Smrg
8301e04c3fSmrg        ret = drmSyncobjCreate(screen->fd, 0, &syncobj);
8401e04c3fSmrg        if (ret) {
8501e04c3fSmrg                fprintf(stderr, "Failed to create syncobj to wait on: %d\n",
8601e04c3fSmrg                        ret);
8701e04c3fSmrg                return false;
8801e04c3fSmrg        }
8901e04c3fSmrg
907ec681f3Smrg        ret = drmSyncobjImportSyncFile(screen->fd, syncobj, fence->fd);
9101e04c3fSmrg        if (ret) {
9201e04c3fSmrg                fprintf(stderr, "Failed to import fence to syncobj: %d\n", ret);
9301e04c3fSmrg                return false;
9401e04c3fSmrg        }
9501e04c3fSmrg
9601e04c3fSmrg        uint64_t abs_timeout = os_time_get_absolute_timeout(timeout_ns);
9701e04c3fSmrg        if (abs_timeout == OS_TIMEOUT_INFINITE)
9801e04c3fSmrg                abs_timeout = INT64_MAX;
9901e04c3fSmrg
10001e04c3fSmrg        ret = drmSyncobjWait(screen->fd, &syncobj, 1, abs_timeout, 0, NULL);
10101e04c3fSmrg
10201e04c3fSmrg        drmSyncobjDestroy(screen->fd, syncobj);
10301e04c3fSmrg
10401e04c3fSmrg        return ret >= 0;
10501e04c3fSmrg}
10601e04c3fSmrg
1077ec681f3Smrgstatic bool
1087ec681f3Smrgv3d_fence_finish(struct pipe_screen *pscreen,
1097ec681f3Smrg		 struct pipe_context *ctx,
1107ec681f3Smrg                 struct pipe_fence_handle *pf,
1117ec681f3Smrg                 uint64_t timeout_ns)
1127ec681f3Smrg{
1137ec681f3Smrg        struct v3d_screen *screen = v3d_screen(pscreen);
1147ec681f3Smrg        struct v3d_fence *fence = (struct v3d_fence *)pf;
1157ec681f3Smrg
1167ec681f3Smrg        return v3d_fence_wait(screen, fence, timeout_ns);
1177ec681f3Smrg}
1187ec681f3Smrg
11901e04c3fSmrgstruct v3d_fence *
12001e04c3fSmrgv3d_fence_create(struct v3d_context *v3d)
12101e04c3fSmrg{
12201e04c3fSmrg        struct v3d_fence *f = calloc(1, sizeof(*f));
12301e04c3fSmrg        if (!f)
12401e04c3fSmrg                return NULL;
12501e04c3fSmrg
12601e04c3fSmrg        /* Snapshot the last V3D rendering's out fence.  We'd rather have
12701e04c3fSmrg         * another syncobj instead of a sync file, but this is all we get.
12801e04c3fSmrg         * (HandleToFD/FDToHandle just gives you another syncobj ID for the
12901e04c3fSmrg         * same syncobj).
13001e04c3fSmrg         */
13101e04c3fSmrg        drmSyncobjExportSyncFile(v3d->fd, v3d->out_sync, &f->fd);
13201e04c3fSmrg        if (f->fd == -1) {
13301e04c3fSmrg                fprintf(stderr, "export failed\n");
13401e04c3fSmrg                free(f);
13501e04c3fSmrg                return NULL;
13601e04c3fSmrg        }
13701e04c3fSmrg
13801e04c3fSmrg        pipe_reference_init(&f->reference, 1);
13901e04c3fSmrg
14001e04c3fSmrg        return f;
14101e04c3fSmrg}
14201e04c3fSmrg
14301e04c3fSmrgvoid
14401e04c3fSmrgv3d_fence_init(struct v3d_screen *screen)
14501e04c3fSmrg{
14601e04c3fSmrg        screen->base.fence_reference = v3d_fence_reference;
14701e04c3fSmrg        screen->base.fence_finish = v3d_fence_finish;
14801e04c3fSmrg}
149