radeon: plug memory leak running gears
[mesa.git] / src / mesa / drivers / dri / radeon / radeon_cs_legacy.c
1 /*
2 * Copyright © 2008 Nicolai Haehnle
3 * Copyright © 2008 Jérôme Glisse
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
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 NON-INFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
24 * of the Software.
25 */
26 /*
27 * Authors:
28 * Aapo Tahkola <aet@rasterburn.org>
29 * Nicolai Haehnle <prefect_@gmx.net>
30 * Jérôme Glisse <glisse@freedesktop.org>
31 */
32 #include <errno.h>
33
34
35 #include "common_context.h"
36 #include "radeon_cs.h"
37 #include "radeon_cs_legacy.h"
38 #include "radeon_bo_legacy.h"
39
40
41 struct cs_manager_legacy {
42 struct radeon_cs_manager base;
43 struct radeon_context *ctx;
44 /* hack for scratch stuff */
45 uint32_t pending_age;
46 uint32_t pending_count;
47 };
48
49 struct cs_reloc_legacy {
50 struct radeon_cs_reloc base;
51 uint32_t cindices;
52 uint32_t *indices;
53 };
54
55
56 static struct radeon_cs *cs_create(struct radeon_cs_manager *csm,
57 uint32_t ndw)
58 {
59 struct radeon_cs *cs;
60
61 cs = (struct radeon_cs*)calloc(1, sizeof(struct radeon_cs));
62 if (cs == NULL) {
63 return NULL;
64 }
65 cs->csm = csm;
66 cs->ndw = (ndw + 0x3FF) & (~0x3FF);
67 cs->packets = (uint32_t*)malloc(4*cs->ndw);
68 if (cs->packets == NULL) {
69 free(cs);
70 return NULL;
71 }
72 cs->relocs_total_size = 0;
73 return cs;
74 }
75
76 int cs_write_dword(struct radeon_cs *cs, uint32_t dword)
77 {
78 if (cs->cdw >= cs->ndw) {
79 uint32_t tmp, *ptr;
80 tmp = (cs->cdw + 1 + 0x3FF) & (~0x3FF);
81 ptr = (uint32_t*)realloc(cs->packets, 4 * tmp);
82 if (ptr == NULL) {
83 return -ENOMEM;
84 }
85 cs->packets = ptr;
86 cs->ndw = tmp;
87 }
88 cs->packets[cs->cdw++] = dword;
89 if (cs->section) {
90 cs->section_cdw++;
91 }
92 return 0;
93 }
94
95 static int cs_write_reloc(struct radeon_cs *cs,
96 struct radeon_bo *bo,
97 uint32_t read_domain,
98 uint32_t write_domain,
99 uint32_t flags)
100 {
101 struct cs_reloc_legacy *relocs;
102 int i;
103
104 relocs = (struct cs_reloc_legacy *)cs->relocs;
105 /* check domains */
106 if ((read_domain && write_domain) || (!read_domain && !write_domain)) {
107 /* in one CS a bo can only be in read or write domain but not
108 * in read & write domain at the same sime
109 */
110 return -EINVAL;
111 }
112 if (read_domain == RADEON_GEM_DOMAIN_CPU) {
113 return -EINVAL;
114 }
115 if (write_domain == RADEON_GEM_DOMAIN_CPU) {
116 return -EINVAL;
117 }
118 /* check if bo is already referenced */
119 for(i = 0; i < cs->crelocs; i++) {
120 uint32_t *indices;
121
122 if (relocs[i].base.bo->handle == bo->handle) {
123 /* Check domains must be in read or write. As we check already
124 * checked that in argument one of the read or write domain was
125 * set we only need to check that if previous reloc as the read
126 * domain set then the read_domain should also be set for this
127 * new relocation.
128 */
129 if (relocs[i].base.read_domain && !read_domain) {
130 return -EINVAL;
131 }
132 if (relocs[i].base.write_domain && !write_domain) {
133 return -EINVAL;
134 }
135 relocs[i].base.read_domain |= read_domain;
136 relocs[i].base.write_domain |= write_domain;
137 /* save indice */
138 relocs[i].cindices++;
139 indices = (uint32_t*)realloc(relocs[i].indices,
140 relocs[i].cindices * 4);
141 if (indices == NULL) {
142 relocs[i].cindices -= 1;
143 return -ENOMEM;
144 }
145 relocs[i].indices = indices;
146 relocs[i].indices[relocs[i].cindices - 1] = cs->cdw - 1;
147 return 0;
148 }
149 }
150 /* add bo to reloc */
151 relocs = (struct cs_reloc_legacy*)
152 realloc(cs->relocs,
153 sizeof(struct cs_reloc_legacy) * (cs->crelocs + 1));
154 if (relocs == NULL) {
155 return -ENOMEM;
156 }
157 cs->relocs = relocs;
158 relocs[cs->crelocs].base.bo = bo;
159 relocs[cs->crelocs].base.read_domain = read_domain;
160 relocs[cs->crelocs].base.write_domain = write_domain;
161 relocs[cs->crelocs].base.flags = flags;
162 relocs[cs->crelocs].indices = (uint32_t*)malloc(4);
163 if (relocs[cs->crelocs].indices == NULL) {
164 return -ENOMEM;
165 }
166 relocs[cs->crelocs].indices[0] = cs->cdw - 1;
167 relocs[cs->crelocs].cindices = 1;
168 cs->relocs_total_size += radeon_bo_legacy_relocs_size(bo);
169 cs->crelocs++;
170 radeon_bo_ref(bo);
171 return 0;
172 }
173
174 static int cs_begin(struct radeon_cs *cs,
175 uint32_t ndw,
176 const char *file,
177 const char *func,
178 int line)
179 {
180 if (cs->section) {
181 fprintf(stderr, "CS already in a section(%s,%s,%d)\n",
182 cs->section_file, cs->section_func, cs->section_line);
183 fprintf(stderr, "CS can't start section(%s,%s,%d)\n",
184 file, func, line);
185 return -EPIPE;
186 }
187 cs->section = 1;
188 cs->section_ndw = ndw;
189 cs->section_cdw = 0;
190 cs->section_file = file;
191 cs->section_func = func;
192 cs->section_line = line;
193 return 0;
194 }
195
196 static int cs_end(struct radeon_cs *cs,
197 const char *file,
198 const char *func,
199 int line)
200
201 {
202 if (!cs->section) {
203 fprintf(stderr, "CS no section to end at (%s,%s,%d)\n",
204 file, func, line);
205 return -EPIPE;
206 }
207 cs->section = 0;
208 if (cs->section_ndw != cs->section_cdw) {
209 fprintf(stderr, "CS section size missmatch start at (%s,%s,%d) %d vs %d\n",
210 cs->section_file, cs->section_func, cs->section_line, cs->section_ndw, cs->section_cdw);
211 fprintf(stderr, "CS section end at (%s,%s,%d)\n",
212 file, func, line);
213 return -EPIPE;
214 }
215 return 0;
216 }
217
218 static int cs_process_relocs(struct radeon_cs *cs)
219 {
220 struct cs_manager_legacy *csm = (struct cs_manager_legacy*)cs->csm;
221 struct cs_reloc_legacy *relocs;
222 int i, j, r;
223
224 csm = (struct cs_manager_legacy*)cs->csm;
225 relocs = (struct cs_reloc_legacy *)cs->relocs;
226 for (i = 0; i < cs->crelocs; i++) {
227 for (j = 0; j < relocs[i].cindices; j++) {
228 uint32_t soffset, eoffset;
229
230 r = radeon_bo_legacy_validate(relocs[i].base.bo,
231 &soffset, &eoffset);
232 if (r) {
233 fprintf(stderr, "validated %p [0x%08X, 0x%08X]\n",
234 relocs[i].base.bo, soffset, eoffset);
235 return r;
236 }
237 cs->packets[relocs[i].indices[j]] += soffset;
238 if (cs->packets[relocs[i].indices[j]] >= eoffset) {
239 radeon_bo_debug(relocs[i].base.bo, 12);
240 fprintf(stderr, "validated %p [0x%08X, 0x%08X]\n",
241 relocs[i].base.bo, soffset, eoffset);
242 fprintf(stderr, "above end: %p 0x%08X 0x%08X\n",
243 relocs[i].base.bo,
244 cs->packets[relocs[i].indices[j]],
245 eoffset);
246 exit(0);
247 return -EINVAL;
248 }
249 }
250 }
251 return 0;
252 }
253
254 static int cs_set_age(struct radeon_cs *cs)
255 {
256 struct cs_manager_legacy *csm = (struct cs_manager_legacy*)cs->csm;
257 struct cs_reloc_legacy *relocs;
258 int i;
259
260 relocs = (struct cs_reloc_legacy *)cs->relocs;
261 for (i = 0; i < cs->crelocs; i++) {
262 radeon_bo_legacy_pending(relocs[i].base.bo, csm->pending_age);
263 radeon_bo_unref(relocs[i].base.bo);
264 }
265 return 0;
266 }
267
268 static void dump_cmdbuf(struct radeon_cs *cs)
269 {
270 int i;
271 for (i = 0; i < cs->cdw; i++){
272 fprintf(stderr,"%x: %08x\n", i, cs->packets[i]);
273 }
274
275 }
276 static int cs_emit(struct radeon_cs *cs)
277 {
278 struct cs_manager_legacy *csm = (struct cs_manager_legacy*)cs->csm;
279 drm_radeon_cmd_buffer_t cmd;
280 drm_r300_cmd_header_t age;
281 uint64_t ull;
282 int r;
283
284 csm->ctx->vtbl.emit_cs_header(cs, csm->ctx);
285
286
287 /* append buffer age */
288 if (IS_R300_CLASS(csm->ctx->radeonScreen)) {
289 age.scratch.cmd_type = R300_CMD_SCRATCH;
290 /* Scratch register 2 corresponds to what radeonGetAge polls */
291 csm->pending_age = 0;
292 csm->pending_count = 1;
293 ull = (uint64_t) (intptr_t) &csm->pending_age;
294 age.scratch.reg = 2;
295 age.scratch.n_bufs = 1;
296 age.scratch.flags = 0;
297 radeon_cs_write_dword(cs, age.u);
298 radeon_cs_write_dword(cs, ull & 0xffffffff);
299 radeon_cs_write_dword(cs, ull >> 32);
300 radeon_cs_write_dword(cs, 0);
301 }
302
303 r = cs_process_relocs(cs);
304 if (r) {
305 return 0;
306 }
307
308 cmd.buf = (char *)cs->packets;
309 cmd.bufsz = cs->cdw * 4;
310 if (csm->ctx->state.scissor.enabled) {
311 cmd.nbox = csm->ctx->state.scissor.numClipRects;
312 cmd.boxes = (drm_clip_rect_t *) csm->ctx->state.scissor.pClipRects;
313 } else {
314 cmd.nbox = csm->ctx->numClipRects;
315 cmd.boxes = (drm_clip_rect_t *) csm->ctx->pClipRects;
316 }
317
318 // dump_cmdbuf(cs);
319
320 r = drmCommandWrite(cs->csm->fd, DRM_RADEON_CMDBUF, &cmd, sizeof(cmd));
321 if (r) {
322 return r;
323 }
324 if (!IS_R300_CLASS(csm->ctx->radeonScreen)) {
325 drm_radeon_irq_emit_t emit_cmd;
326 emit_cmd.irq_seq = &csm->pending_age;
327 r = drmCommandWrite(cs->csm->fd, DRM_RADEON_IRQ_EMIT, &emit_cmd, sizeof(emit_cmd));
328 if (r) {
329 return r;
330 }
331 }
332 cs_set_age(cs);
333 return 0;
334 }
335
336 static void inline cs_free_reloc(void *relocs_p, int crelocs)
337 {
338 struct cs_reloc_legacy *relocs = relocs_p;
339 int i;
340 if (!relocs_p)
341 return;
342 for (i = 0; i < crelocs; i++)
343 free(relocs[i].indices);
344 }
345
346 static int cs_destroy(struct radeon_cs *cs)
347 {
348 cs_free_reloc(cs->relocs, cs->crelocs);
349 free(cs->relocs);
350 free(cs->packets);
351 free(cs);
352 return 0;
353 }
354
355 static int cs_erase(struct radeon_cs *cs)
356 {
357 cs_free_reloc(cs->relocs, cs->crelocs);
358 free(cs->relocs);
359 cs->relocs_total_size = 0;
360 cs->relocs = NULL;
361 cs->crelocs = 0;
362 cs->cdw = 0;
363 cs->section = 0;
364 return 0;
365 }
366
367 static int cs_need_flush(struct radeon_cs *cs)
368 {
369 /* FIXME: we should get the texture heap size */
370 return (cs->relocs_total_size > (7*1024*1024));
371 }
372
373 static void cs_print(struct radeon_cs *cs, FILE *file)
374 {
375 }
376
377 static struct radeon_cs_funcs radeon_cs_legacy_funcs = {
378 cs_create,
379 cs_write_dword,
380 cs_write_reloc,
381 cs_begin,
382 cs_end,
383 cs_emit,
384 cs_destroy,
385 cs_erase,
386 cs_need_flush,
387 cs_print
388 };
389
390 struct radeon_cs_manager *radeon_cs_manager_legacy_ctor(struct radeon_context *ctx)
391 {
392 struct cs_manager_legacy *csm;
393
394 csm = (struct cs_manager_legacy*)
395 calloc(1, sizeof(struct cs_manager_legacy));
396 if (csm == NULL) {
397 return NULL;
398 }
399 csm->base.funcs = &radeon_cs_legacy_funcs;
400 csm->base.fd = ctx->dri.fd;
401 csm->ctx = ctx;
402 csm->pending_age = 1;
403 return (struct radeon_cs_manager*)csm;
404 }
405
406 void radeon_cs_manager_legacy_dtor(struct radeon_cs_manager *csm)
407 {
408 free(csm);
409 }