lima: fix bo submit memory leak
[mesa.git] / src / gallium / drivers / lima / lima_submit.c
1 /*
2 * Copyright (C) 2017-2019 Lima Project
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 shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 */
23
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "xf86drm.h"
28 #include "libsync.h"
29 #include "drm-uapi/lima_drm.h"
30
31 #include "util/ralloc.h"
32 #include "util/u_dynarray.h"
33 #include "util/os_time.h"
34
35 #include "lima_screen.h"
36 #include "lima_context.h"
37 #include "lima_submit.h"
38 #include "lima_bo.h"
39 #include "lima_util.h"
40
41 struct lima_submit {
42 struct lima_screen *screen;
43 uint32_t pipe;
44 uint32_t ctx;
45
46 int in_sync_fd;
47 uint32_t in_sync;
48 uint32_t out_sync;
49
50 struct util_dynarray gem_bos;
51 struct util_dynarray bos;
52 };
53
54
55 #define VOID2U64(x) ((uint64_t)(unsigned long)(x))
56
57 struct lima_submit *lima_submit_create(struct lima_context *ctx, uint32_t pipe)
58 {
59 struct lima_submit *s;
60
61 s = rzalloc(ctx, struct lima_submit);
62 if (!s)
63 return NULL;
64
65 s->screen = lima_screen(ctx->base.screen);
66 s->pipe = pipe;
67 s->ctx = ctx->id;
68 s->in_sync_fd = -1;
69
70 int err = drmSyncobjCreate(s->screen->fd, DRM_SYNCOBJ_CREATE_SIGNALED,
71 &s->out_sync);
72 if (err)
73 goto err_out0;
74
75 err = drmSyncobjCreate(s->screen->fd, DRM_SYNCOBJ_CREATE_SIGNALED,
76 &s->in_sync);
77 if (err)
78 goto err_out1;
79
80 util_dynarray_init(&s->gem_bos, s);
81 util_dynarray_init(&s->bos, s);
82
83 return s;
84
85 err_out1:
86 drmSyncobjDestroy(s->screen->fd, s->out_sync);
87 err_out0:
88 ralloc_free(s);
89 return NULL;
90 }
91
92 void lima_submit_free(struct lima_submit *submit)
93 {
94 if (submit->in_sync_fd >= 0)
95 close(submit->in_sync_fd);
96 drmSyncobjDestroy(submit->screen->fd, submit->in_sync);
97 drmSyncobjDestroy(submit->screen->fd, submit->out_sync);
98 }
99
100 bool lima_submit_add_bo(struct lima_submit *submit, struct lima_bo *bo, uint32_t flags)
101 {
102 util_dynarray_foreach(&submit->gem_bos, struct drm_lima_gem_submit_bo, gem_bo) {
103 if (bo->handle == gem_bo->handle) {
104 gem_bo->flags |= flags;
105 return true;
106 }
107 }
108
109 struct drm_lima_gem_submit_bo *submit_bo =
110 util_dynarray_grow(&submit->gem_bos, struct drm_lima_gem_submit_bo, 1);
111 submit_bo->handle = bo->handle;
112 submit_bo->flags = flags;
113
114 struct lima_bo **jbo = util_dynarray_grow(&submit->bos, struct lima_bo *, 1);
115 *jbo = bo;
116
117 /* prevent bo from being freed when submit start */
118 lima_bo_reference(bo);
119
120 return true;
121 }
122
123 bool lima_submit_start(struct lima_submit *submit, void *frame, uint32_t size)
124 {
125 struct drm_lima_gem_submit req = {
126 .ctx = submit->ctx,
127 .pipe = submit->pipe,
128 .nr_bos = submit->gem_bos.size / sizeof(struct drm_lima_gem_submit_bo),
129 .bos = VOID2U64(util_dynarray_begin(&submit->gem_bos)),
130 .frame = VOID2U64(frame),
131 .frame_size = size,
132 .out_sync = submit->out_sync,
133 };
134
135 if (submit->in_sync_fd >= 0) {
136 int err = drmSyncobjImportSyncFile(submit->screen->fd, submit->in_sync,
137 submit->in_sync_fd);
138 if (err)
139 return false;
140
141 req.in_sync[0] = submit->in_sync;
142 close(submit->in_sync_fd);
143 submit->in_sync_fd = -1;
144 }
145
146 bool ret = drmIoctl(submit->screen->fd, DRM_IOCTL_LIMA_GEM_SUBMIT, &req) == 0;
147
148 util_dynarray_foreach(&submit->bos, struct lima_bo *, bo) {
149 lima_bo_unreference(*bo);
150 }
151
152 util_dynarray_clear(&submit->gem_bos);
153 util_dynarray_clear(&submit->bos);
154 return ret;
155 }
156
157 bool lima_submit_wait(struct lima_submit *submit, uint64_t timeout_ns)
158 {
159 int64_t abs_timeout = os_time_get_absolute_timeout(timeout_ns);
160 if (abs_timeout == OS_TIMEOUT_INFINITE)
161 abs_timeout = INT64_MAX;
162
163 return !drmSyncobjWait(submit->screen->fd, &submit->out_sync, 1, abs_timeout, 0, NULL);
164 }
165
166 bool lima_submit_has_bo(struct lima_submit *submit, struct lima_bo *bo, bool all)
167 {
168 util_dynarray_foreach(&submit->gem_bos, struct drm_lima_gem_submit_bo, gem_bo) {
169 if (bo->handle == gem_bo->handle) {
170 if (all)
171 return true;
172 else
173 return gem_bo->flags & LIMA_SUBMIT_BO_WRITE;
174 }
175 }
176
177 return false;
178 }
179
180 bool lima_submit_add_in_sync(struct lima_submit *submit, int fd)
181 {
182 return !sync_accumulate("lima", &submit->in_sync_fd, fd);
183 }
184
185 bool lima_submit_get_out_sync(struct lima_submit *submit, int *fd)
186 {
187 return !drmSyncobjExportSyncFile(submit->screen->fd, submit->out_sync, fd);
188 }