xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/panfrost/pan_fence.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright (c) 2022 Amazon.com, Inc. or its affiliates.
3  * Copyright (C) 2008 VMware, Inc.
4  * Copyright (C) 2014 Broadcom
5  * Copyright (C) 2018 Alyssa Rosenzweig
6  * Copyright (C) 2019 Collabora, Ltd.
7  * Copyright (C) 2012 Rob Clark <[email protected]>
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a
10  * copy of this software and associated documentation files (the "Software"),
11  * to deal in the Software without restriction, including without limitation
12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  * and/or sell copies of the Software, and to permit persons to whom the
14  * Software is furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice (including the next
17  * paragraph) shall be included in all copies or substantial portions of the
18  * Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26  * SOFTWARE.
27  */
28 
29 #include "pan_fence.h"
30 #include "pan_context.h"
31 #include "pan_screen.h"
32 
33 #include "util/os_time.h"
34 #include "util/u_inlines.h"
35 
36 void
panfrost_fence_reference(struct pipe_screen * pscreen,struct pipe_fence_handle ** ptr,struct pipe_fence_handle * fence)37 panfrost_fence_reference(struct pipe_screen *pscreen,
38                          struct pipe_fence_handle **ptr,
39                          struct pipe_fence_handle *fence)
40 {
41    struct panfrost_device *dev = pan_device(pscreen);
42    struct pipe_fence_handle *old = *ptr;
43 
44    if (pipe_reference(&old->reference, &fence->reference)) {
45       drmSyncobjDestroy(panfrost_device_fd(dev), old->syncobj);
46       free(old);
47    }
48 
49    *ptr = fence;
50 }
51 
52 bool
panfrost_fence_finish(struct pipe_screen * pscreen,struct pipe_context * ctx,struct pipe_fence_handle * fence,uint64_t timeout)53 panfrost_fence_finish(struct pipe_screen *pscreen, struct pipe_context *ctx,
54                       struct pipe_fence_handle *fence, uint64_t timeout)
55 {
56    struct panfrost_device *dev = pan_device(pscreen);
57    int ret;
58 
59    if (fence->signaled)
60       return true;
61 
62    uint64_t abs_timeout = os_time_get_absolute_timeout(timeout);
63    if (abs_timeout == OS_TIMEOUT_INFINITE)
64       abs_timeout = INT64_MAX;
65 
66    ret = drmSyncobjWait(panfrost_device_fd(dev), &fence->syncobj, 1,
67                         abs_timeout, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL, NULL);
68 
69    fence->signaled = (ret >= 0);
70    return fence->signaled;
71 }
72 
73 int
panfrost_fence_get_fd(struct pipe_screen * screen,struct pipe_fence_handle * f)74 panfrost_fence_get_fd(struct pipe_screen *screen, struct pipe_fence_handle *f)
75 {
76    struct panfrost_device *dev = pan_device(screen);
77    int fd = -1;
78 
79    drmSyncobjExportSyncFile(panfrost_device_fd(dev), f->syncobj, &fd);
80    return fd;
81 }
82 
83 struct pipe_fence_handle *
panfrost_fence_from_fd(struct panfrost_context * ctx,int fd,enum pipe_fd_type type)84 panfrost_fence_from_fd(struct panfrost_context *ctx, int fd,
85                        enum pipe_fd_type type)
86 {
87    struct panfrost_device *dev = pan_device(ctx->base.screen);
88    int ret;
89 
90    struct pipe_fence_handle *f = calloc(1, sizeof(*f));
91    if (!f)
92       return NULL;
93 
94    if (type == PIPE_FD_TYPE_NATIVE_SYNC) {
95       ret = drmSyncobjCreate(panfrost_device_fd(dev), 0, &f->syncobj);
96       if (ret) {
97          fprintf(stderr, "create syncobj failed\n");
98          goto err_free_fence;
99       }
100 
101       ret = drmSyncobjImportSyncFile(panfrost_device_fd(dev), f->syncobj, fd);
102       if (ret) {
103          fprintf(stderr, "import syncfile failed\n");
104          goto err_destroy_syncobj;
105       }
106    } else {
107       assert(type == PIPE_FD_TYPE_SYNCOBJ);
108       ret = drmSyncobjFDToHandle(panfrost_device_fd(dev), fd, &f->syncobj);
109       if (ret) {
110          fprintf(stderr, "import syncobj FD failed\n");
111          goto err_free_fence;
112       }
113    }
114 
115    pipe_reference_init(&f->reference, 1);
116 
117    return f;
118 
119 err_destroy_syncobj:
120    drmSyncobjDestroy(panfrost_device_fd(dev), f->syncobj);
121 err_free_fence:
122    free(f);
123    return NULL;
124 }
125 
126 struct pipe_fence_handle *
panfrost_fence_create(struct panfrost_context * ctx)127 panfrost_fence_create(struct panfrost_context *ctx)
128 {
129    struct panfrost_device *dev = pan_device(ctx->base.screen);
130    int fd = -1, ret;
131 
132    /* Snapshot the last rendering out fence. We'd rather have another
133     * syncobj instead of a sync file, but this is all we get.
134     * (HandleToFD/FDToHandle just gives you another syncobj ID for the
135     * same syncobj).
136     */
137    ret = drmSyncobjExportSyncFile(panfrost_device_fd(dev), ctx->syncobj, &fd);
138    if (ret || fd == -1) {
139       fprintf(stderr, "export failed\n");
140       return NULL;
141    }
142 
143    struct pipe_fence_handle *f =
144       panfrost_fence_from_fd(ctx, fd, PIPE_FD_TYPE_NATIVE_SYNC);
145 
146    close(fd);
147 
148    return f;
149 }
150