panfrost: Fix panfrost_bo_access memory leak
[mesa.git] / src / gallium / drivers / freedreno / freedreno_fence.c
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 <libsync.h>
28
29 #include "util/u_inlines.h"
30
31 #include "freedreno_fence.h"
32 #include "freedreno_context.h"
33 #include "freedreno_util.h"
34
35 struct pipe_fence_handle {
36 struct pipe_reference reference;
37 /* fence holds a weak reference to the batch until the batch is flushed,
38 * at which point fd_fence_populate() is called and timestamp and possibly
39 * fence_fd become valid and the week reference is dropped.
40 */
41 struct fd_batch *batch;
42 struct fd_pipe *pipe;
43 struct fd_screen *screen;
44 int fence_fd;
45 uint32_t timestamp;
46 };
47
48 static void fence_flush(struct pipe_fence_handle *fence)
49 {
50 if (fence->batch)
51 fd_batch_flush(fence->batch, true);
52 debug_assert(!fence->batch);
53 }
54
55 void fd_fence_populate(struct pipe_fence_handle *fence,
56 uint32_t timestamp, int fence_fd)
57 {
58 if (!fence->batch)
59 return;
60 fence->timestamp = timestamp;
61 fence->fence_fd = fence_fd;
62 fence->batch = NULL;
63 }
64
65 static void fd_fence_destroy(struct pipe_fence_handle *fence)
66 {
67 if (fence->fence_fd != -1)
68 close(fence->fence_fd);
69 fd_pipe_del(fence->pipe);
70 FREE(fence);
71 }
72
73 void fd_fence_ref(struct pipe_fence_handle **ptr,
74 struct pipe_fence_handle *pfence)
75 {
76 if (pipe_reference(&(*ptr)->reference, &pfence->reference))
77 fd_fence_destroy(*ptr);
78
79 *ptr = pfence;
80 }
81
82 bool fd_fence_finish(struct pipe_screen *pscreen,
83 struct pipe_context *ctx,
84 struct pipe_fence_handle *fence,
85 uint64_t timeout)
86 {
87 fence_flush(fence);
88
89 if (fence->fence_fd != -1) {
90 int ret = sync_wait(fence->fence_fd, timeout / 1000000);
91 return ret == 0;
92 }
93
94 if (fd_pipe_wait_timeout(fence->pipe, fence->timestamp, timeout))
95 return false;
96
97 return true;
98 }
99
100 static struct pipe_fence_handle * fence_create(struct fd_context *ctx,
101 struct fd_batch *batch, uint32_t timestamp, int fence_fd)
102 {
103 struct pipe_fence_handle *fence;
104
105 fence = CALLOC_STRUCT(pipe_fence_handle);
106 if (!fence)
107 return NULL;
108
109 pipe_reference_init(&fence->reference, 1);
110
111 fence->batch = batch;
112 fence->pipe = fd_pipe_ref(ctx->pipe);
113 fence->screen = ctx->screen;
114 fence->timestamp = timestamp;
115 fence->fence_fd = fence_fd;
116
117 return fence;
118 }
119
120 void fd_create_fence_fd(struct pipe_context *pctx,
121 struct pipe_fence_handle **pfence, int fd,
122 enum pipe_fd_type type)
123 {
124 assert(type == PIPE_FD_TYPE_NATIVE_SYNC);
125 *pfence = fence_create(fd_context(pctx), NULL, 0, dup(fd));
126 }
127
128 void fd_fence_server_sync(struct pipe_context *pctx,
129 struct pipe_fence_handle *fence)
130 {
131 struct fd_context *ctx = fd_context(pctx);
132 struct fd_batch *batch = fd_context_batch(ctx);
133
134 fence_flush(fence);
135
136 /* if not an external fence, then nothing more to do without preemption: */
137 if (fence->fence_fd == -1)
138 return;
139
140 if (sync_accumulate("freedreno", &batch->in_fence_fd, fence->fence_fd)) {
141 /* error */
142 }
143 }
144
145 int fd_fence_get_fd(struct pipe_screen *pscreen,
146 struct pipe_fence_handle *fence)
147 {
148 fence_flush(fence);
149 return dup(fence->fence_fd);
150 }
151
152 struct pipe_fence_handle * fd_fence_create(struct fd_batch *batch)
153 {
154 return fence_create(batch->ctx, batch, 0, -1);
155 }