1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2014 Broadcom
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci/** @file v3d_fence.c
25bf215546Sopenharmony_ci *
26bf215546Sopenharmony_ci * Seqno-based fence management.
27bf215546Sopenharmony_ci *
28bf215546Sopenharmony_ci * We have two mechanisms for waiting in our kernel API: You can wait on a BO
29bf215546Sopenharmony_ci * to have all rendering to from any process to be completed, or wait on a
30bf215546Sopenharmony_ci * seqno for that particular seqno to be passed.  The fence API we're
31bf215546Sopenharmony_ci * implementing is based on waiting for all rendering in the context to have
32bf215546Sopenharmony_ci * completed (with no reference to what other processes might be doing with
33bf215546Sopenharmony_ci * the same BOs), so we can just use the seqno of the last rendering we'd
34bf215546Sopenharmony_ci * fired off as our fence marker.
35bf215546Sopenharmony_ci */
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_ci#include "util/u_inlines.h"
38bf215546Sopenharmony_ci#include "util/os_time.h"
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ci#include "v3d_context.h"
41bf215546Sopenharmony_ci#include "v3d_bufmgr.h"
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_cistruct v3d_fence {
44bf215546Sopenharmony_ci        struct pipe_reference reference;
45bf215546Sopenharmony_ci        int fd;
46bf215546Sopenharmony_ci};
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_cistatic void
49bf215546Sopenharmony_civ3d_fence_reference(struct pipe_screen *pscreen,
50bf215546Sopenharmony_ci                    struct pipe_fence_handle **pp,
51bf215546Sopenharmony_ci                    struct pipe_fence_handle *pf)
52bf215546Sopenharmony_ci{
53bf215546Sopenharmony_ci        struct v3d_fence **p = (struct v3d_fence **)pp;
54bf215546Sopenharmony_ci        struct v3d_fence *f = (struct v3d_fence *)pf;
55bf215546Sopenharmony_ci        struct v3d_fence *old = *p;
56bf215546Sopenharmony_ci
57bf215546Sopenharmony_ci        if (pipe_reference(&(*p)->reference, &f->reference)) {
58bf215546Sopenharmony_ci                close(old->fd);
59bf215546Sopenharmony_ci                free(old);
60bf215546Sopenharmony_ci        }
61bf215546Sopenharmony_ci        *p = f;
62bf215546Sopenharmony_ci}
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_civoid
65bf215546Sopenharmony_civ3d_fence_unreference(struct v3d_fence **fence)
66bf215546Sopenharmony_ci{
67bf215546Sopenharmony_ci        assert(fence);
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_ci        if (!*fence)
70bf215546Sopenharmony_ci                return;
71bf215546Sopenharmony_ci
72bf215546Sopenharmony_ci        v3d_fence_reference(NULL, (struct pipe_fence_handle **)fence, NULL);
73bf215546Sopenharmony_ci}
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_cibool
76bf215546Sopenharmony_civ3d_fence_wait(struct v3d_screen *screen,
77bf215546Sopenharmony_ci               struct v3d_fence *fence,
78bf215546Sopenharmony_ci               uint64_t timeout_ns)
79bf215546Sopenharmony_ci{
80bf215546Sopenharmony_ci        int ret;
81bf215546Sopenharmony_ci        unsigned syncobj;
82bf215546Sopenharmony_ci
83bf215546Sopenharmony_ci        ret = drmSyncobjCreate(screen->fd, 0, &syncobj);
84bf215546Sopenharmony_ci        if (ret) {
85bf215546Sopenharmony_ci                fprintf(stderr, "Failed to create syncobj to wait on: %d\n",
86bf215546Sopenharmony_ci                        ret);
87bf215546Sopenharmony_ci                return false;
88bf215546Sopenharmony_ci        }
89bf215546Sopenharmony_ci
90bf215546Sopenharmony_ci        ret = drmSyncobjImportSyncFile(screen->fd, syncobj, fence->fd);
91bf215546Sopenharmony_ci        if (ret) {
92bf215546Sopenharmony_ci                fprintf(stderr, "Failed to import fence to syncobj: %d\n", ret);
93bf215546Sopenharmony_ci                return false;
94bf215546Sopenharmony_ci        }
95bf215546Sopenharmony_ci
96bf215546Sopenharmony_ci        uint64_t abs_timeout = os_time_get_absolute_timeout(timeout_ns);
97bf215546Sopenharmony_ci        if (abs_timeout == OS_TIMEOUT_INFINITE)
98bf215546Sopenharmony_ci                abs_timeout = INT64_MAX;
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_ci        ret = drmSyncobjWait(screen->fd, &syncobj, 1, abs_timeout, 0, NULL);
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_ci        drmSyncobjDestroy(screen->fd, syncobj);
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ci        return ret >= 0;
105bf215546Sopenharmony_ci}
106bf215546Sopenharmony_ci
107bf215546Sopenharmony_cistatic bool
108bf215546Sopenharmony_civ3d_fence_finish(struct pipe_screen *pscreen,
109bf215546Sopenharmony_ci		 struct pipe_context *ctx,
110bf215546Sopenharmony_ci                 struct pipe_fence_handle *pf,
111bf215546Sopenharmony_ci                 uint64_t timeout_ns)
112bf215546Sopenharmony_ci{
113bf215546Sopenharmony_ci        struct v3d_screen *screen = v3d_screen(pscreen);
114bf215546Sopenharmony_ci        struct v3d_fence *fence = (struct v3d_fence *)pf;
115bf215546Sopenharmony_ci
116bf215546Sopenharmony_ci        return v3d_fence_wait(screen, fence, timeout_ns);
117bf215546Sopenharmony_ci}
118bf215546Sopenharmony_ci
119bf215546Sopenharmony_cistruct v3d_fence *
120bf215546Sopenharmony_civ3d_fence_create(struct v3d_context *v3d)
121bf215546Sopenharmony_ci{
122bf215546Sopenharmony_ci        struct v3d_fence *f = calloc(1, sizeof(*f));
123bf215546Sopenharmony_ci        if (!f)
124bf215546Sopenharmony_ci                return NULL;
125bf215546Sopenharmony_ci
126bf215546Sopenharmony_ci        /* Snapshot the last V3D rendering's out fence.  We'd rather have
127bf215546Sopenharmony_ci         * another syncobj instead of a sync file, but this is all we get.
128bf215546Sopenharmony_ci         * (HandleToFD/FDToHandle just gives you another syncobj ID for the
129bf215546Sopenharmony_ci         * same syncobj).
130bf215546Sopenharmony_ci         */
131bf215546Sopenharmony_ci        drmSyncobjExportSyncFile(v3d->fd, v3d->out_sync, &f->fd);
132bf215546Sopenharmony_ci        if (f->fd == -1) {
133bf215546Sopenharmony_ci                fprintf(stderr, "export failed\n");
134bf215546Sopenharmony_ci                free(f);
135bf215546Sopenharmony_ci                return NULL;
136bf215546Sopenharmony_ci        }
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_ci        pipe_reference_init(&f->reference, 1);
139bf215546Sopenharmony_ci
140bf215546Sopenharmony_ci        return f;
141bf215546Sopenharmony_ci}
142bf215546Sopenharmony_ci
143bf215546Sopenharmony_civoid
144bf215546Sopenharmony_civ3d_fence_init(struct v3d_screen *screen)
145bf215546Sopenharmony_ci{
146bf215546Sopenharmony_ci        screen->base.fence_reference = v3d_fence_reference;
147bf215546Sopenharmony_ci        screen->base.fence_finish = v3d_fence_finish;
148bf215546Sopenharmony_ci}
149