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 vc4_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 <libsync.h>
3801e04c3fSmrg#include <fcntl.h>
3901e04c3fSmrg
407ec681f3Smrg#include "util/os_file.h"
4101e04c3fSmrg#include "util/u_inlines.h"
4201e04c3fSmrg
4301e04c3fSmrg#include "vc4_screen.h"
4401e04c3fSmrg#include "vc4_context.h"
4501e04c3fSmrg#include "vc4_bufmgr.h"
4601e04c3fSmrg
4701e04c3fSmrgstruct vc4_fence {
4801e04c3fSmrg        struct pipe_reference reference;
4901e04c3fSmrg        uint64_t seqno;
5001e04c3fSmrg        int fd;
5101e04c3fSmrg};
5201e04c3fSmrg
5301e04c3fSmrgstatic inline struct vc4_fence *
5401e04c3fSmrgvc4_fence(struct pipe_fence_handle *pfence)
5501e04c3fSmrg{
5601e04c3fSmrg        return (struct vc4_fence *)pfence;
5701e04c3fSmrg}
5801e04c3fSmrg
5901e04c3fSmrgstatic void
6001e04c3fSmrgvc4_fence_reference(struct pipe_screen *pscreen,
6101e04c3fSmrg                    struct pipe_fence_handle **pp,
6201e04c3fSmrg                    struct pipe_fence_handle *pf)
6301e04c3fSmrg{
6401e04c3fSmrg        struct vc4_fence **p = (struct vc4_fence **)pp;
6501e04c3fSmrg        struct vc4_fence *f = vc4_fence(pf);
6601e04c3fSmrg        struct vc4_fence *old = *p;
6701e04c3fSmrg
6801e04c3fSmrg        if (pipe_reference(&(*p)->reference, &f->reference)) {
6901e04c3fSmrg                if (old->fd >= 0)
7001e04c3fSmrg                        close(old->fd);
7101e04c3fSmrg                free(old);
7201e04c3fSmrg        }
7301e04c3fSmrg        *p = f;
7401e04c3fSmrg}
7501e04c3fSmrg
767ec681f3Smrgstatic bool
7701e04c3fSmrgvc4_fence_finish(struct pipe_screen *pscreen,
7801e04c3fSmrg		 struct pipe_context *ctx,
7901e04c3fSmrg                 struct pipe_fence_handle *pf,
8001e04c3fSmrg                 uint64_t timeout_ns)
8101e04c3fSmrg{
8201e04c3fSmrg        struct vc4_screen *screen = vc4_screen(pscreen);
8301e04c3fSmrg        struct vc4_fence *f = vc4_fence(pf);
8401e04c3fSmrg
8501e04c3fSmrg        if (f->fd >= 0)
8601e04c3fSmrg                return sync_wait(f->fd, timeout_ns / 1000000) == 0;
8701e04c3fSmrg
8801e04c3fSmrg        return vc4_wait_seqno(screen, f->seqno, timeout_ns, "fence wait");
8901e04c3fSmrg}
9001e04c3fSmrg
9101e04c3fSmrgstruct vc4_fence *
9201e04c3fSmrgvc4_fence_create(struct vc4_screen *screen, uint64_t seqno, int fd)
9301e04c3fSmrg{
9401e04c3fSmrg        struct vc4_fence *f = calloc(1, sizeof(*f));
9501e04c3fSmrg
9601e04c3fSmrg        if (!f)
9701e04c3fSmrg                return NULL;
9801e04c3fSmrg
9901e04c3fSmrg        pipe_reference_init(&f->reference, 1);
10001e04c3fSmrg        f->seqno = seqno;
10101e04c3fSmrg        f->fd = fd;
10201e04c3fSmrg
10301e04c3fSmrg        return f;
10401e04c3fSmrg}
10501e04c3fSmrg
10601e04c3fSmrgstatic void
10701e04c3fSmrgvc4_fence_create_fd(struct pipe_context *pctx, struct pipe_fence_handle **pf,
10801e04c3fSmrg                    int fd, enum pipe_fd_type type)
10901e04c3fSmrg{
11001e04c3fSmrg        struct vc4_context *vc4 = vc4_context(pctx);
11101e04c3fSmrg        struct vc4_fence **fence = (struct vc4_fence **)pf;
11201e04c3fSmrg
11301e04c3fSmrg        assert(type == PIPE_FD_TYPE_NATIVE_SYNC);
11401e04c3fSmrg        *fence = vc4_fence_create(vc4->screen, vc4->last_emit_seqno,
1157ec681f3Smrg                                  os_dupfd_cloexec(fd));
11601e04c3fSmrg}
11701e04c3fSmrg
11801e04c3fSmrgstatic void
11901e04c3fSmrgvc4_fence_server_sync(struct pipe_context *pctx,
12001e04c3fSmrg                      struct pipe_fence_handle *pfence)
12101e04c3fSmrg{
12201e04c3fSmrg        struct vc4_context *vc4 = vc4_context(pctx);
12301e04c3fSmrg        struct vc4_fence *fence = vc4_fence(pfence);
12401e04c3fSmrg
12501e04c3fSmrg        if (fence->fd >= 0)
12601e04c3fSmrg                sync_accumulate("vc4", &vc4->in_fence_fd, fence->fd);
12701e04c3fSmrg}
12801e04c3fSmrg
12901e04c3fSmrgstatic int
13001e04c3fSmrgvc4_fence_get_fd(struct pipe_screen *screen, struct pipe_fence_handle *pfence)
13101e04c3fSmrg{
13201e04c3fSmrg        struct vc4_fence *fence = vc4_fence(pfence);
13301e04c3fSmrg
1347ec681f3Smrg        return os_dupfd_cloexec(fence->fd);
13501e04c3fSmrg}
13601e04c3fSmrg
13701e04c3fSmrgint
13801e04c3fSmrgvc4_fence_context_init(struct vc4_context *vc4)
13901e04c3fSmrg{
14001e04c3fSmrg        vc4->base.create_fence_fd = vc4_fence_create_fd;
14101e04c3fSmrg        vc4->base.fence_server_sync = vc4_fence_server_sync;
14201e04c3fSmrg        vc4->in_fence_fd = -1;
14301e04c3fSmrg
14401e04c3fSmrg        /* Since we initialize the in_fence_fd to -1 (no wait necessary),
14501e04c3fSmrg         * we also need to initialize our in_syncobj as signaled.
14601e04c3fSmrg         */
14701e04c3fSmrg        if (vc4->screen->has_syncobj) {
14801e04c3fSmrg                return drmSyncobjCreate(vc4->fd, DRM_SYNCOBJ_CREATE_SIGNALED,
14901e04c3fSmrg                                        &vc4->in_syncobj);
15001e04c3fSmrg        } else {
15101e04c3fSmrg                return 0;
15201e04c3fSmrg        }
15301e04c3fSmrg}
15401e04c3fSmrg
15501e04c3fSmrgvoid
15601e04c3fSmrgvc4_fence_screen_init(struct vc4_screen *screen)
15701e04c3fSmrg{
15801e04c3fSmrg        screen->base.fence_reference = vc4_fence_reference;
15901e04c3fSmrg        screen->base.fence_finish = vc4_fence_finish;
16001e04c3fSmrg        screen->base.fence_get_fd = vc4_fence_get_fd;
16101e04c3fSmrg}
162