r600g: fix memory/bo leak
[mesa.git] / src / gallium / winsys / r600 / drm / radeon_ctx.c
1 /*
2 * Copyright 2010 Jerome Glisse <glisse@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 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the 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 NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * Authors:
24 * Jerome Glisse
25 */
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include "radeon_priv.h"
30 #include "radeon_drm.h"
31 #include "bof.h"
32
33 static int radeon_ctx_set_bo_new(struct radeon_ctx *ctx, struct radeon_bo *bo)
34 {
35 if (ctx->nbo >= RADEON_CTX_MAX_PM4)
36 return -EBUSY;
37 ctx->bo[ctx->nbo] = bo;
38 ctx->nbo++;
39 return 0;
40 }
41
42 static struct radeon_bo *radeon_ctx_get_bo(struct radeon_ctx *ctx, unsigned reloc)
43 {
44 struct radeon_cs_reloc *greloc;
45 unsigned i;
46
47 greloc = (void *)(((u8 *)ctx->reloc) + reloc * 4);
48 for (i = 0; i < ctx->nbo; i++) {
49 if (ctx->bo[i]->handle == greloc->handle) {
50 return radeon_bo_incref(ctx->radeon, ctx->bo[i]);
51 }
52 }
53 fprintf(stderr, "%s no bo for reloc[%d 0x%08X] %d\n", __func__, reloc, greloc->handle, ctx->nbo);
54 return NULL;
55 }
56
57 static void radeon_ctx_get_placement(struct radeon_ctx *ctx, unsigned reloc, u32 *placement)
58 {
59 struct radeon_cs_reloc *greloc;
60 unsigned i;
61
62 placement[0] = 0;
63 placement[1] = 0;
64 greloc = (void *)(((u8 *)ctx->reloc) + reloc * 4);
65 for (i = 0; i < ctx->nbo; i++) {
66 if (ctx->bo[i]->handle == greloc->handle) {
67 placement[0] = greloc->read_domain | greloc->write_domain;
68 placement[1] = placement[0];
69 return;
70 }
71 }
72 }
73
74 void radeon_ctx_clear(struct radeon_ctx *ctx)
75 {
76 for (int i = 0; i < ctx->nbo; i++) {
77 ctx->bo[i] = radeon_bo_decref(ctx->radeon, ctx->bo[i]);
78 }
79 ctx->ndwords = RADEON_CTX_MAX_PM4;
80 ctx->cdwords = 0;
81 ctx->nreloc = 0;
82 ctx->nbo = 0;
83 }
84
85 int radeon_ctx_init(struct radeon_ctx *ctx, struct radeon *radeon)
86 {
87 if (radeon == NULL)
88 return -EINVAL;
89 memset(ctx, 0, sizeof(struct radeon_ctx));
90 ctx->radeon = radeon_incref(radeon);
91 radeon_ctx_clear(ctx);
92 ctx->pm4 = malloc(RADEON_CTX_MAX_PM4 * 4);
93 if (ctx->pm4 == NULL) {
94 radeon_ctx_fini(ctx);
95 return -ENOMEM;
96 }
97 ctx->reloc = malloc(sizeof(struct radeon_cs_reloc) * RADEON_CTX_MAX_PM4);
98 if (ctx->reloc == NULL) {
99 radeon_ctx_fini(ctx);
100 return -ENOMEM;
101 }
102 ctx->bo = malloc(sizeof(void *) * RADEON_CTX_MAX_PM4);
103 if (ctx->bo == NULL) {
104 radeon_ctx_fini(ctx);
105 return -ENOMEM;
106 }
107 return 0;
108 }
109
110 void radeon_ctx_fini(struct radeon_ctx *ctx)
111 {
112 unsigned i;
113
114 if (ctx == NULL)
115 return;
116
117 for (i = 0; i < ctx->nbo; i++) {
118 ctx->bo[i] = radeon_bo_decref(ctx->radeon, ctx->bo[i]);
119 }
120 ctx->radeon = radeon_decref(ctx->radeon);
121 free(ctx->bo);
122 free(ctx->pm4);
123 free(ctx->reloc);
124 memset(ctx, 0, sizeof(struct radeon_ctx));
125 }
126
127 static int radeon_ctx_state_bo(struct radeon_ctx *ctx, struct radeon_state *state)
128 {
129 unsigned i, j;
130 int r;
131
132 if (state == NULL)
133 return 0;
134 for (i = 0; i < state->nbo; i++) {
135 for (j = 0; j < ctx->nbo; j++) {
136 if (state->bo[i] == ctx->bo[j])
137 break;
138 }
139 if (j == ctx->nbo) {
140 radeon_bo_incref(ctx->radeon, state->bo[i]);
141 r = radeon_ctx_set_bo_new(ctx, state->bo[i]);
142 if (r)
143 return r;
144 }
145 }
146 return 0;
147 }
148
149
150 int radeon_ctx_submit(struct radeon_ctx *ctx)
151 {
152 struct drm_radeon_cs drmib;
153 struct drm_radeon_cs_chunk chunks[2];
154 uint64_t chunk_array[2];
155 int r = 0;
156
157 if (!ctx->cdwords)
158 return 0;
159 #if 0
160 for (r = 0; r < ctx->cdwords; r++) {
161 fprintf(stderr, "0x%08X\n", ctx->pm4[r]);
162 }
163 #endif
164 drmib.num_chunks = 2;
165 drmib.chunks = (uint64_t)(uintptr_t)chunk_array;
166 chunks[0].chunk_id = RADEON_CHUNK_ID_IB;
167 chunks[0].length_dw = ctx->cdwords;
168 chunks[0].chunk_data = (uint64_t)(uintptr_t)ctx->pm4;
169 chunks[1].chunk_id = RADEON_CHUNK_ID_RELOCS;
170 chunks[1].length_dw = ctx->nreloc * sizeof(struct radeon_cs_reloc) / 4;
171 chunks[1].chunk_data = (uint64_t)(uintptr_t)ctx->reloc;
172 chunk_array[0] = (uint64_t)(uintptr_t)&chunks[0];
173 chunk_array[1] = (uint64_t)(uintptr_t)&chunks[1];
174 #if 1
175 r = drmCommandWriteRead(ctx->radeon->fd, DRM_RADEON_CS, &drmib,
176 sizeof(struct drm_radeon_cs));
177 #endif
178 return r;
179 }
180
181 static int radeon_ctx_reloc(struct radeon_ctx *ctx, struct radeon_bo *bo,
182 unsigned id, unsigned *placement)
183 {
184 unsigned i;
185
186 for (i = 0; i < ctx->nreloc; i++) {
187 if (ctx->reloc[i].handle == bo->handle) {
188 ctx->pm4[id] = i * sizeof(struct radeon_cs_reloc) / 4;
189 return 0;
190 }
191 }
192 if (ctx->nreloc >= RADEON_CTX_MAX_PM4) {
193 return -EBUSY;
194 }
195 ctx->reloc[ctx->nreloc].handle = bo->handle;
196 ctx->reloc[ctx->nreloc].read_domain = placement[0] | placement [1];
197 ctx->reloc[ctx->nreloc].write_domain = placement[0] | placement [1];
198 ctx->reloc[ctx->nreloc].flags = 0;
199 ctx->pm4[id] = ctx->nreloc * sizeof(struct radeon_cs_reloc) / 4;
200 ctx->nreloc++;
201 return 0;
202 }
203
204 static int radeon_ctx_state_schedule(struct radeon_ctx *ctx, struct radeon_state *state)
205 {
206 unsigned i, rid, bid, cid;
207 int r;
208
209 if (state == NULL)
210 return 0;
211 if (state->cpm4 > ctx->ndwords) {
212 return -EBUSY;
213 }
214 memcpy(&ctx->pm4[ctx->cdwords], state->pm4, state->cpm4 * 4);
215 for (i = 0; i < state->nreloc; i++) {
216 rid = state->reloc_pm4_id[i];
217 bid = state->reloc_bo_id[i];
218 cid = ctx->cdwords + rid;
219 r = radeon_ctx_reloc(ctx, state->bo[bid], cid,
220 &state->placement[bid * 2]);
221 if (r) {
222 fprintf(stderr, "%s state %d failed to reloc\n", __func__, state->stype->stype);
223 return r;
224 }
225 }
226 ctx->cdwords += state->cpm4;
227 ctx->ndwords -= state->cpm4;
228 return 0;
229 }
230
231 int radeon_ctx_set_query_state(struct radeon_ctx *ctx, struct radeon_state *state)
232 {
233 int r = 0;
234
235 /* !!! ONLY ACCEPT QUERY STATE HERE !!! */
236 r = radeon_state_pm4(state);
237 if (r)
238 return r;
239 /* BEGIN/END query are balanced in the same cs so account for END
240 * END query when scheduling BEGIN query
241 */
242 switch (state->stype->stype) {
243 case R600_STATE_QUERY_BEGIN:
244 /* is there enough place for begin & end */
245 if ((state->cpm4 * 2) > ctx->ndwords)
246 return -EBUSY;
247 ctx->ndwords -= state->cpm4;
248 break;
249 case R600_STATE_QUERY_END:
250 ctx->ndwords += state->cpm4;
251 break;
252 default:
253 return -EINVAL;
254 }
255 return radeon_ctx_state_schedule(ctx, state);
256 }
257
258 int radeon_ctx_set_draw(struct radeon_ctx *ctx, struct radeon_draw *draw)
259 {
260 unsigned previous_cdwords;
261 int r = 0;
262
263 for (int i = 0; i < (ctx->radeon->nstate_per_shader * R600_SHADER_MAX); i++) {
264 r = radeon_ctx_state_bo(ctx, draw->state[i]);
265 if (r)
266 return r;
267 }
268 previous_cdwords = ctx->cdwords;
269 for (int i = 0, id = 0; i < ctx->radeon->nstate_per_shader; i++) {
270 for (int j = 0; j < R600_SHADER_MAX; j++) {
271 id = j * ctx->radeon->nstate_per_shader + i;
272 if (draw->state[id]) {
273 r = radeon_ctx_state_schedule(ctx, draw->state[id]);
274 if (r) {
275 ctx->cdwords = previous_cdwords;
276 return r;
277 }
278 }
279 }
280 }
281 return 0;
282 }
283
284 #if 0
285 int radeon_ctx_pm4(struct radeon_ctx *ctx)
286 {
287 unsigned i;
288 int r;
289
290 free(ctx->pm4);
291 ctx->cpm4 = 0;
292 ctx->pm4 = malloc(ctx->draw_cpm4 * 4);
293 if (ctx->pm4 == NULL)
294 return -EINVAL;
295 for (i = 0, ctx->id = 0; i < ctx->nstate; i++) {
296 }
297 if (ctx->id != ctx->draw_cpm4) {
298 fprintf(stderr, "%s miss predicted pm4 size %d for %d\n",
299 __func__, ctx->draw_cpm4, ctx->id);
300 return -EINVAL;
301 }
302 ctx->cpm4 = ctx->draw_cpm4;
303 return 0;
304 }
305 #endif
306
307 void radeon_ctx_dump_bof(struct radeon_ctx *ctx, const char *file)
308 {
309 bof_t *bcs, *blob, *array, *bo, *size, *handle, *device_id, *root;
310 unsigned i;
311
312 root = device_id = bcs = blob = array = bo = size = handle = NULL;
313 root = bof_object();
314 if (root == NULL)
315 goto out_err;
316 device_id = bof_int32(ctx->radeon->device);
317 if (device_id == NULL)
318 return;
319 if (bof_object_set(root, "device_id", device_id))
320 goto out_err;
321 bof_decref(device_id);
322 device_id = NULL;
323 /* dump relocs */
324 printf("%d relocs\n", ctx->nreloc);
325 blob = bof_blob(ctx->nreloc * 16, ctx->reloc);
326 if (blob == NULL)
327 goto out_err;
328 if (bof_object_set(root, "reloc", blob))
329 goto out_err;
330 bof_decref(blob);
331 blob = NULL;
332 /* dump cs */
333 printf("%d pm4\n", ctx->cdwords);
334 blob = bof_blob(ctx->cdwords * 4, ctx->pm4);
335 if (blob == NULL)
336 goto out_err;
337 if (bof_object_set(root, "pm4", blob))
338 goto out_err;
339 bof_decref(blob);
340 blob = NULL;
341 /* dump bo */
342 array = bof_array();
343 if (array == NULL)
344 goto out_err;
345 for (i = 0; i < ctx->nbo; i++) {
346 bo = bof_object();
347 if (bo == NULL)
348 goto out_err;
349 size = bof_int32(ctx->bo[i]->size);
350 if (size == NULL)
351 goto out_err;
352 if (bof_object_set(bo, "size", size))
353 goto out_err;
354 bof_decref(size);
355 size = NULL;
356 handle = bof_int32(ctx->bo[i]->handle);
357 if (handle == NULL)
358 goto out_err;
359 if (bof_object_set(bo, "handle", handle))
360 goto out_err;
361 bof_decref(handle);
362 handle = NULL;
363 radeon_bo_map(ctx->radeon, ctx->bo[i]);
364 blob = bof_blob(ctx->bo[i]->size, ctx->bo[i]->data);
365 radeon_bo_unmap(ctx->radeon, ctx->bo[i]);
366 if (blob == NULL)
367 goto out_err;
368 if (bof_object_set(bo, "data", blob))
369 goto out_err;
370 bof_decref(blob);
371 blob = NULL;
372 if (bof_array_append(array, bo))
373 goto out_err;
374 bof_decref(bo);
375 bo = NULL;
376 }
377 if (bof_object_set(root, "bo", array))
378 goto out_err;
379 bof_dump_file(root, file);
380 printf("done dump\n");
381 out_err:
382 bof_decref(blob);
383 bof_decref(array);
384 bof_decref(bo);
385 bof_decref(size);
386 bof_decref(handle);
387 bof_decref(device_id);
388 bof_decref(root);
389 }