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