1 /*
2  * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  *
23  * Authors:
24  *    Rob Clark <robclark@freedesktop.org>
25  */
26 
27 #include "util/os_file.h"
28 #include "util/u_inlines.h"
29 
30 #include "freedreno_fence.h"
31 #include "freedreno_context.h"
32 #include "freedreno_util.h"
33 /* TODO: Use the interface drm/freedreno_drmif.h instead of calling directly */
34 #include <xf86drm.h>
35 
36 struct pipe_fence_handle {
37 	struct pipe_reference reference;
38 	/* fence holds a weak reference to the batch until the batch is flushed,
39 	 * at which point fd_fence_populate() is called and timestamp and possibly
40 	 * fence_fd become valid and the week reference is dropped.
41 	 */
42 	struct fd_batch *batch;
43 	struct fd_pipe *pipe;
44 	struct fd_screen *screen;
45 	int fence_fd;
46 	uint32_t timestamp;
47 	uint32_t syncobj;
48 };
49 
fence_flush(struct pipe_fence_handle * fence)50 static void fence_flush(struct pipe_fence_handle *fence)
51 {
52 	if (fence->batch)
53 		fd_batch_flush(fence->batch);
54 	debug_assert(!fence->batch);
55 }
56 
fd_fence_populate(struct pipe_fence_handle * fence,uint32_t timestamp,int fence_fd)57 void fd_fence_populate(struct pipe_fence_handle *fence,
58 		uint32_t timestamp, int fence_fd)
59 {
60 	if (!fence->batch)
61 		return;
62 	fence->timestamp = timestamp;
63 	fence->fence_fd = fence_fd;
64 	fence->batch = NULL;
65 }
66 
fd_fence_destroy(struct pipe_fence_handle * fence)67 static void fd_fence_destroy(struct pipe_fence_handle *fence)
68 {
69 	if (fence->fence_fd != -1)
70 		close(fence->fence_fd);
71 	if (fence->syncobj)
72 		drmSyncobjDestroy(fd_device_fd(fence->screen->dev), fence->syncobj);
73 	fd_pipe_del(fence->pipe);
74 	FREE(fence);
75 }
76 
fd_fence_ref(struct pipe_fence_handle ** ptr,struct pipe_fence_handle * pfence)77 void fd_fence_ref(struct pipe_fence_handle **ptr,
78 		struct pipe_fence_handle *pfence)
79 {
80 	if (pipe_reference(&(*ptr)->reference, &pfence->reference))
81 		fd_fence_destroy(*ptr);
82 
83 	*ptr = pfence;
84 }
85 
fd_fence_finish(struct pipe_screen * pscreen,struct pipe_context * ctx,struct pipe_fence_handle * fence,uint64_t timeout)86 bool fd_fence_finish(struct pipe_screen *pscreen,
87 		struct pipe_context *ctx,
88 		struct pipe_fence_handle *fence,
89 		uint64_t timeout)
90 {
91 	fence_flush(fence);
92 
93 	if (fence->fence_fd != -1) {
94 		int ret = sync_wait(fence->fence_fd, timeout / 1000000);
95 		return ret == 0;
96 	}
97 
98 	if (fd_pipe_wait_timeout(fence->pipe, fence->timestamp, timeout))
99 		return false;
100 
101 	return true;
102 }
103 
fence_create(struct fd_context * ctx,struct fd_batch * batch,uint32_t timestamp,int fence_fd,int syncobj)104 static struct pipe_fence_handle * fence_create(struct fd_context *ctx,
105 		struct fd_batch *batch, uint32_t timestamp, int fence_fd, int syncobj)
106 {
107 	struct pipe_fence_handle *fence;
108 
109 	fence = CALLOC_STRUCT(pipe_fence_handle);
110 	if (!fence)
111 		return NULL;
112 
113 	pipe_reference_init(&fence->reference, 1);
114 
115 	fence->batch = batch;
116 	fence->pipe = fd_pipe_ref(ctx->pipe);
117 	fence->screen = ctx->screen;
118 	fence->timestamp = timestamp;
119 	fence->fence_fd = fence_fd;
120 	fence->syncobj = syncobj;
121 
122 	return fence;
123 }
124 
fd_create_fence_fd(struct pipe_context * pctx,struct pipe_fence_handle ** pfence,int fd,enum pipe_fd_type type)125 void fd_create_fence_fd(struct pipe_context *pctx,
126 		struct pipe_fence_handle **pfence, int fd,
127 		enum pipe_fd_type type)
128 {
129 	struct fd_context *ctx = fd_context(pctx);
130 
131 	switch (type) {
132 	case PIPE_FD_TYPE_NATIVE_SYNC:
133 		*pfence = fence_create(fd_context(pctx), NULL, 0, os_dupfd_cloexec(fd), 0);
134 		break;
135 	case PIPE_FD_TYPE_SYNCOBJ: {
136 		int ret;
137 		uint32_t syncobj;
138 
139 		assert(ctx->screen->has_syncobj);
140 		ret = drmSyncobjFDToHandle(fd_device_fd(ctx->screen->dev), fd, &syncobj);
141 		if (!ret)
142 			close(fd);
143 
144 		*pfence = fence_create(fd_context(pctx), NULL, 0, -1, syncobj);
145 		break;
146 	}
147 	default:
148 		unreachable("Unhandled fence type");
149 	}
150 }
151 
fd_fence_server_sync(struct pipe_context * pctx,struct pipe_fence_handle * fence)152 void fd_fence_server_sync(struct pipe_context *pctx,
153 		struct pipe_fence_handle *fence)
154 {
155 	struct fd_context *ctx = fd_context(pctx);
156 
157 	fence_flush(fence);
158 
159 	/* if not an external fence, then nothing more to do without preemption: */
160 	if (fence->fence_fd == -1)
161 		return;
162 
163 	if (sync_accumulate("freedreno", &ctx->in_fence_fd, fence->fence_fd)) {
164 		/* error */
165 	}
166 }
167 
fd_fence_server_signal(struct pipe_context * pctx,struct pipe_fence_handle * fence)168 void fd_fence_server_signal(struct pipe_context *pctx,
169 		struct pipe_fence_handle *fence)
170 {
171 	struct fd_context *ctx = fd_context(pctx);
172 
173 	if (fence->syncobj) {
174 		drmSyncobjSignal(fd_device_fd(ctx->screen->dev), &fence->syncobj, 1);
175 	}
176 }
177 
fd_fence_get_fd(struct pipe_screen * pscreen,struct pipe_fence_handle * fence)178 int fd_fence_get_fd(struct pipe_screen *pscreen,
179 		struct pipe_fence_handle *fence)
180 {
181 	fence_flush(fence);
182 	return os_dupfd_cloexec(fence->fence_fd);
183 }
184 
fd_fence_is_fd(struct pipe_fence_handle * fence)185 bool fd_fence_is_fd(struct pipe_fence_handle *fence)
186 {
187 	return fence->fence_fd != -1;
188 }
189 
fd_fence_create(struct fd_batch * batch)190 struct pipe_fence_handle * fd_fence_create(struct fd_batch *batch)
191 {
192 	return fence_create(batch->ctx, batch, 0, -1, 0);
193 }
194