radeon: free indices caught with valgrind
[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 += 1;
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 fprintf(stderr, "validated %p [0x%08X, 0x%08X]\n",
238 relocs[i].base.bo, soffset, eoffset);
239 cs->packets[relocs[i].indices[j]] += soffset;
240 if (cs->packets[relocs[i].indices[j]] >= eoffset) {
241 radeon_bo_debug(relocs[i].base.bo, 12);
242 fprintf(stderr, "validated %p [0x%08X, 0x%08X]\n",
243 relocs[i].base.bo, soffset, eoffset);
244 fprintf(stderr, "above end: %p 0x%08X 0x%08X\n",
245 relocs[i].base.bo,
246 cs->packets[relocs[i].indices[j]],
247 eoffset);
248 exit(0);
249 return -EINVAL;
250 }
251 }
252 }
253 return 0;
254 }
255
256 static int cs_set_age(struct radeon_cs *cs)
257 {
258 struct cs_manager_legacy *csm = (struct cs_manager_legacy*)cs->csm;
259 struct cs_reloc_legacy *relocs;
260 int i;
261
262 relocs = (struct cs_reloc_legacy *)cs->relocs;
263 for (i = 0; i < cs->crelocs; i++) {
264 radeon_bo_legacy_pending(relocs[i].base.bo, csm->pending_age);
265 radeon_bo_unref(relocs[i].base.bo);
266 }
267 return 0;
268 }
269
270 static void dump_cmdbuf(struct radeon_cs *cs)
271 {
272 int i;
273 for (i = 0; i < cs->cdw; i++){
274 fprintf(stderr,"%x: %08x\n", i, cs->packets[i]);
275 }
276
277 }
278 static int cs_emit(struct radeon_cs *cs)
279 {
280 struct cs_manager_legacy *csm = (struct cs_manager_legacy*)cs->csm;
281 drm_radeon_cmd_buffer_t cmd;
282 drm_r300_cmd_header_t age;
283 uint64_t ull;
284 int r;
285
286 csm->ctx->vtbl.emit_cs_header(cs, csm->ctx);
287
288
289 /* append buffer age */
290 if (IS_R300_CLASS(csm->ctx->radeonScreen)) {
291 age.scratch.cmd_type = R300_CMD_SCRATCH;
292 /* Scratch register 2 corresponds to what radeonGetAge polls */
293 csm->pending_age = 0;
294 csm->pending_count = 1;
295 ull = (uint64_t) (intptr_t) &csm->pending_age;
296 age.scratch.reg = 2;
297 age.scratch.n_bufs = 1;
298 age.scratch.flags = 0;
299 radeon_cs_write_dword(cs, age.u);
300 radeon_cs_write_dword(cs, ull & 0xffffffff);
301 radeon_cs_write_dword(cs, ull >> 32);
302 radeon_cs_write_dword(cs, 0);
303 }
304
305 r = cs_process_relocs(cs);
306 if (r) {
307 return 0;
308 }
309
310 cmd.buf = (char *)cs->packets;
311 cmd.bufsz = cs->cdw * 4;
312 if (csm->ctx->state.scissor.enabled) {
313 cmd.nbox = csm->ctx->state.scissor.numClipRects;
314 cmd.boxes = (drm_clip_rect_t *) csm->ctx->state.scissor.pClipRects;
315 } else {
316 cmd.nbox = csm->ctx->numClipRects;
317 cmd.boxes = (drm_clip_rect_t *) csm->ctx->pClipRects;
318 }
319
320 // dump_cmdbuf(cs);
321
322 r = drmCommandWrite(cs->csm->fd, DRM_RADEON_CMDBUF, &cmd, sizeof(cmd));
323 if (r) {
324 return r;
325 }
326 if (!IS_R300_CLASS(csm->ctx->radeonScreen)) {
327 drm_radeon_irq_emit_t emit_cmd;
328 emit_cmd.irq_seq = &csm->pending_age;
329 r = drmCommandWrite(cs->csm->fd, DRM_RADEON_IRQ_EMIT, &emit_cmd, sizeof(emit_cmd));
330 if (r) {
331 return r;
332 }
333 }
334 cs_set_age(cs);
335 return 0;
336 }
337
338 static int cs_destroy(struct radeon_cs *cs)
339 {
340 free(cs->relocs->indices);
341 free(cs->relocs);
342 free(cs->packets);
343 free(cs);
344 return 0;
345 }
346
347 static int cs_erase(struct radeon_cs *cs)
348 {
349 free(cs->relocs);
350 cs->relocs_total_size = 0;
351 cs->relocs = NULL;
352 cs->crelocs = 0;
353 cs->cdw = 0;
354 cs->section = 0;
355 return 0;
356 }
357
358 static int cs_need_flush(struct radeon_cs *cs)
359 {
360 /* FIXME: we should get the texture heap size */
361 return (cs->relocs_total_size > (7*1024*1024));
362 }
363
364 static void cs_print(struct radeon_cs *cs, FILE *file)
365 {
366 }
367
368 static struct radeon_cs_funcs radeon_cs_legacy_funcs = {
369 cs_create,
370 cs_write_dword,
371 cs_write_reloc,
372 cs_begin,
373 cs_end,
374 cs_emit,
375 cs_destroy,
376 cs_erase,
377 cs_need_flush,
378 cs_print
379 };
380
381 struct radeon_cs_manager *radeon_cs_manager_legacy_ctor(struct radeon_context *ctx)
382 {
383 struct cs_manager_legacy *csm;
384
385 csm = (struct cs_manager_legacy*)
386 calloc(1, sizeof(struct cs_manager_legacy));
387 if (csm == NULL) {
388 return NULL;
389 }
390 csm->base.funcs = &radeon_cs_legacy_funcs;
391 csm->base.fd = ctx->dri.fd;
392 csm->ctx = ctx;
393 csm->pending_age = 1;
394 return (struct radeon_cs_manager*)csm;
395 }
396
397 void radeon_cs_manager_legacy_dtor(struct radeon_cs_manager *csm)
398 {
399 free(csm);
400 }