radeon: make more r100 work
[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 };
50
51 struct cs_reloc_legacy {
52 struct radeon_cs_reloc base;
53 uint32_t cindices;
54 uint32_t *indices;
55 };
56
57
58 static struct radeon_cs *cs_create(struct radeon_cs_manager *csm,
59 uint32_t ndw)
60 {
61 struct radeon_cs *cs;
62
63 cs = (struct radeon_cs*)calloc(1, sizeof(struct radeon_cs));
64 if (cs == NULL) {
65 return NULL;
66 }
67 cs->csm = csm;
68 cs->ndw = (ndw + 0x3FF) & (~0x3FF);
69 cs->packets = (uint32_t*)malloc(4*cs->ndw);
70 if (cs->packets == NULL) {
71 free(cs);
72 return NULL;
73 }
74 cs->relocs_total_size = 0;
75 return cs;
76 }
77
78 static int cs_write_reloc(struct radeon_cs *cs,
79 struct radeon_bo *bo,
80 uint32_t read_domain,
81 uint32_t write_domain,
82 uint32_t flags)
83 {
84 struct cs_reloc_legacy *relocs;
85 int i;
86
87 relocs = (struct cs_reloc_legacy *)cs->relocs;
88 /* check domains */
89 if ((read_domain && write_domain) || (!read_domain && !write_domain)) {
90 /* in one CS a bo can only be in read or write domain but not
91 * in read & write domain at the same sime
92 */
93 return -EINVAL;
94 }
95 if (read_domain == RADEON_GEM_DOMAIN_CPU) {
96 return -EINVAL;
97 }
98 if (write_domain == RADEON_GEM_DOMAIN_CPU) {
99 return -EINVAL;
100 }
101 /* check if bo is already referenced */
102 for(i = 0; i < cs->crelocs; i++) {
103 uint32_t *indices;
104
105 if (relocs[i].base.bo->handle == bo->handle) {
106 /* Check domains must be in read or write. As we check already
107 * checked that in argument one of the read or write domain was
108 * set we only need to check that if previous reloc as the read
109 * domain set then the read_domain should also be set for this
110 * new relocation.
111 */
112 if (relocs[i].base.read_domain && !read_domain) {
113 return -EINVAL;
114 }
115 if (relocs[i].base.write_domain && !write_domain) {
116 return -EINVAL;
117 }
118 relocs[i].base.read_domain |= read_domain;
119 relocs[i].base.write_domain |= write_domain;
120 /* save indice */
121 relocs[i].cindices++;
122 indices = (uint32_t*)realloc(relocs[i].indices,
123 relocs[i].cindices * 4);
124 if (indices == NULL) {
125 relocs[i].cindices -= 1;
126 return -ENOMEM;
127 }
128 relocs[i].indices = indices;
129 relocs[i].indices[relocs[i].cindices - 1] = cs->cdw - 1;
130 return 0;
131 }
132 }
133 /* add bo to reloc */
134 relocs = (struct cs_reloc_legacy*)
135 realloc(cs->relocs,
136 sizeof(struct cs_reloc_legacy) * (cs->crelocs + 1));
137 if (relocs == NULL) {
138 return -ENOMEM;
139 }
140 cs->relocs = relocs;
141 relocs[cs->crelocs].base.bo = bo;
142 relocs[cs->crelocs].base.read_domain = read_domain;
143 relocs[cs->crelocs].base.write_domain = write_domain;
144 relocs[cs->crelocs].base.flags = flags;
145 relocs[cs->crelocs].indices = (uint32_t*)malloc(4);
146 if (relocs[cs->crelocs].indices == NULL) {
147 return -ENOMEM;
148 }
149 relocs[cs->crelocs].indices[0] = cs->cdw - 1;
150 relocs[cs->crelocs].cindices = 1;
151 cs->relocs_total_size += radeon_bo_legacy_relocs_size(bo);
152 cs->crelocs++;
153 radeon_bo_ref(bo);
154 return 0;
155 }
156
157 static int cs_begin(struct radeon_cs *cs,
158 uint32_t ndw,
159 const char *file,
160 const char *func,
161 int line)
162 {
163 if (cs->section) {
164 fprintf(stderr, "CS already in a section(%s,%s,%d)\n",
165 cs->section_file, cs->section_func, cs->section_line);
166 fprintf(stderr, "CS can't start section(%s,%s,%d)\n",
167 file, func, line);
168 return -EPIPE;
169 }
170 cs->section = 1;
171 cs->section_ndw = ndw;
172 cs->section_cdw = 0;
173 cs->section_file = file;
174 cs->section_func = func;
175 cs->section_line = line;
176
177
178 if (cs->cdw + ndw > cs->ndw) {
179 uint32_t tmp, *ptr;
180 int num = (ndw > 0x3FF) ? ndw : 0x3FF;
181
182 tmp = (cs->cdw + 1 + num) & (~num);
183 ptr = (uint32_t*)realloc(cs->packets, 4 * tmp);
184 if (ptr == NULL) {
185 return -ENOMEM;
186 }
187 cs->packets = ptr;
188 cs->ndw = tmp;
189 }
190
191 return 0;
192 }
193
194 static int cs_end(struct radeon_cs *cs,
195 const char *file,
196 const char *func,
197 int line)
198
199 {
200 if (!cs->section) {
201 fprintf(stderr, "CS no section to end at (%s,%s,%d)\n",
202 file, func, line);
203 return -EPIPE;
204 }
205 cs->section = 0;
206 if (cs->section_ndw != cs->section_cdw) {
207 fprintf(stderr, "CS section size missmatch start at (%s,%s,%d) %d vs %d\n",
208 cs->section_file, cs->section_func, cs->section_line, cs->section_ndw, cs->section_cdw);
209 fprintf(stderr, "CS section end at (%s,%s,%d)\n",
210 file, func, line);
211 return -EPIPE;
212 }
213 return 0;
214 }
215
216 static int cs_process_relocs(struct radeon_cs *cs)
217 {
218 struct cs_manager_legacy *csm = (struct cs_manager_legacy*)cs->csm;
219 struct cs_reloc_legacy *relocs;
220 int i, j, r;
221
222 csm = (struct cs_manager_legacy*)cs->csm;
223 relocs = (struct cs_reloc_legacy *)cs->relocs;
224 for (i = 0; i < cs->crelocs; i++) {
225 for (j = 0; j < relocs[i].cindices; j++) {
226 uint32_t soffset, eoffset;
227
228 r = radeon_bo_legacy_validate(relocs[i].base.bo,
229 &soffset, &eoffset);
230 if (r) {
231 fprintf(stderr, "validated %p [0x%08X, 0x%08X]\n",
232 relocs[i].base.bo, soffset, eoffset);
233 return r;
234 }
235 cs->packets[relocs[i].indices[j]] += soffset;
236 if (cs->packets[relocs[i].indices[j]] >= eoffset) {
237 radeon_bo_debug(relocs[i].base.bo, 12);
238 fprintf(stderr, "validated %p [0x%08X, 0x%08X]\n",
239 relocs[i].base.bo, soffset, eoffset);
240 fprintf(stderr, "above end: %p 0x%08X 0x%08X\n",
241 relocs[i].base.bo,
242 cs->packets[relocs[i].indices[j]],
243 eoffset);
244 exit(0);
245 return -EINVAL;
246 }
247 }
248 }
249 return 0;
250 }
251
252 static int cs_set_age(struct radeon_cs *cs)
253 {
254 struct cs_manager_legacy *csm = (struct cs_manager_legacy*)cs->csm;
255 struct cs_reloc_legacy *relocs;
256 int i;
257
258 relocs = (struct cs_reloc_legacy *)cs->relocs;
259 for (i = 0; i < cs->crelocs; i++) {
260 radeon_bo_legacy_pending(relocs[i].base.bo, csm->pending_age);
261 radeon_bo_unref(relocs[i].base.bo);
262 }
263 return 0;
264 }
265
266 static void dump_cmdbuf(struct radeon_cs *cs)
267 {
268 int i;
269 for (i = 0; i < cs->cdw; i++){
270 fprintf(stderr,"%x: %08x\n", i, cs->packets[i]);
271 }
272
273 }
274 static int cs_emit(struct radeon_cs *cs)
275 {
276 struct cs_manager_legacy *csm = (struct cs_manager_legacy*)cs->csm;
277 drm_radeon_cmd_buffer_t cmd;
278 drm_r300_cmd_header_t age;
279 uint64_t ull;
280 int r;
281
282 csm->ctx->vtbl.emit_cs_header(cs, csm->ctx);
283
284
285 /* append buffer age */
286 if (IS_R300_CLASS(csm->ctx->radeonScreen)) {
287 age.scratch.cmd_type = R300_CMD_SCRATCH;
288 /* Scratch register 2 corresponds to what radeonGetAge polls */
289 csm->pending_age = 0;
290 csm->pending_count = 1;
291 ull = (uint64_t) (intptr_t) &csm->pending_age;
292 age.scratch.reg = 2;
293 age.scratch.n_bufs = 1;
294 age.scratch.flags = 0;
295 radeon_cs_write_dword(cs, age.u);
296 radeon_cs_write_dword(cs, ull & 0xffffffff);
297 radeon_cs_write_dword(cs, ull >> 32);
298 radeon_cs_write_dword(cs, 0);
299 }
300
301 r = cs_process_relocs(cs);
302 if (r) {
303 return 0;
304 }
305
306 cmd.buf = (char *)cs->packets;
307 cmd.bufsz = cs->cdw * 4;
308 if (csm->ctx->state.scissor.enabled) {
309 cmd.nbox = csm->ctx->state.scissor.numClipRects;
310 cmd.boxes = (drm_clip_rect_t *) csm->ctx->state.scissor.pClipRects;
311 } else {
312 cmd.nbox = csm->ctx->numClipRects;
313 cmd.boxes = (drm_clip_rect_t *) csm->ctx->pClipRects;
314 }
315
316 //dump_cmdbuf(cs);
317
318 r = drmCommandWrite(cs->csm->fd, DRM_RADEON_CMDBUF, &cmd, sizeof(cmd));
319 if (r) {
320 return r;
321 }
322 if (!IS_R300_CLASS(csm->ctx->radeonScreen)) {
323 drm_radeon_irq_emit_t emit_cmd;
324 emit_cmd.irq_seq = &csm->pending_age;
325 r = drmCommandWrite(cs->csm->fd, DRM_RADEON_IRQ_EMIT, &emit_cmd, sizeof(emit_cmd));
326 if (r) {
327 return r;
328 }
329 }
330 cs_set_age(cs);
331
332 cs->csm->read_used = 0;
333 cs->csm->vram_write_used = 0;
334 cs->csm->gart_write_used = 0;
335 return 0;
336 }
337
338 static void inline cs_free_reloc(void *relocs_p, int crelocs)
339 {
340 struct cs_reloc_legacy *relocs = relocs_p;
341 int i;
342 if (!relocs_p)
343 return;
344 for (i = 0; i < crelocs; i++)
345 free(relocs[i].indices);
346 }
347
348 static int cs_destroy(struct radeon_cs *cs)
349 {
350 cs_free_reloc(cs->relocs, cs->crelocs);
351 free(cs->relocs);
352 free(cs->packets);
353 free(cs);
354 return 0;
355 }
356
357 static int cs_erase(struct radeon_cs *cs)
358 {
359 cs_free_reloc(cs->relocs, cs->crelocs);
360 free(cs->relocs);
361 cs->relocs_total_size = 0;
362 cs->relocs = NULL;
363 cs->crelocs = 0;
364 cs->cdw = 0;
365 cs->section = 0;
366 return 0;
367 }
368
369 static int cs_need_flush(struct radeon_cs *cs)
370 {
371 /* FIXME: we should get the texture heap size */
372 return (cs->relocs_total_size > (7*1024*1024));
373 }
374
375 static void cs_print(struct radeon_cs *cs, FILE *file)
376 {
377 }
378
379 static int cs_check_space(struct radeon_cs *cs, struct radeon_cs_space_check *bos, int num_bo)
380 {
381 struct radeon_cs_manager *csm = cs->csm;
382 int this_op_read = 0, this_op_gart_write = 0, this_op_vram_write = 0;
383 uint32_t read_domains, write_domain;
384 int i;
385 struct radeon_bo *bo;
386
387 /* check the totals for this operation */
388
389 if (num_bo == 0)
390 return 0;
391
392 /* prepare */
393 for (i = 0; i < num_bo; i++) {
394 bo = bos[i].bo;
395
396 bos[i].new_accounted = 0;
397 read_domains = bos[i].read_domains;
398 write_domain = bos[i].write_domain;
399
400 /* pinned bos don't count */
401 if (radeon_legacy_bo_is_static(bo))
402 continue;
403
404 /* already accounted this bo */
405 if (write_domain && (write_domain == bo->space_accounted))
406 continue;
407
408 if (read_domains && ((read_domains << 16) == bo->space_accounted))
409 continue;
410
411 if (bo->space_accounted == 0) {
412 if (write_domain == RADEON_GEM_DOMAIN_VRAM)
413 this_op_vram_write += bo->size;
414 else if (write_domain == RADEON_GEM_DOMAIN_GTT)
415 this_op_gart_write += bo->size;
416 else
417 this_op_read += bo->size;
418 bos[i].new_accounted = (read_domains << 16) | write_domain;
419 } else {
420 uint16_t old_read, old_write;
421
422 old_read = bo->space_accounted >> 16;
423 old_write = bo->space_accounted & 0xffff;
424
425 if (write_domain && (old_read & write_domain)) {
426 bos[i].new_accounted = write_domain;
427 /* moving from read to a write domain */
428 if (write_domain == RADEON_GEM_DOMAIN_VRAM) {
429 this_op_read -= bo->size;
430 this_op_vram_write += bo->size;
431 } else if (write_domain == RADEON_GEM_DOMAIN_VRAM) {
432 this_op_read -= bo->size;
433 this_op_gart_write += bo->size;
434 }
435 } else if (read_domains & old_write) {
436 bos[i].new_accounted = bo->space_accounted & 0xffff;
437 } else {
438 /* rewrite the domains */
439 if (write_domain != old_write)
440 fprintf(stderr,"WRITE DOMAIN RELOC FAILURE 0x%x %d %d\n", bo->handle, write_domain, old_write);
441 if (read_domains != old_read)
442 fprintf(stderr,"READ DOMAIN RELOC FAILURE 0x%x %d %d\n", bo->handle, read_domains, old_read);
443 return RADEON_CS_SPACE_FLUSH;
444 }
445 }
446 }
447
448 if (this_op_read < 0)
449 this_op_read = 0;
450
451 /* check sizes - operation first */
452 if ((this_op_read + this_op_gart_write > csm->gart_limit) ||
453 (this_op_vram_write > csm->vram_limit)) {
454 return RADEON_CS_SPACE_OP_TO_BIG;
455 }
456
457 if (((csm->vram_write_used + this_op_vram_write) > csm->vram_limit) ||
458 ((csm->read_used + csm->gart_write_used + this_op_gart_write + this_op_read) > csm->gart_limit)) {
459 return RADEON_CS_SPACE_FLUSH;
460 }
461
462 csm->gart_write_used += this_op_gart_write;
463 csm->vram_write_used += this_op_vram_write;
464 csm->read_used += this_op_read;
465 /* commit */
466 for (i = 0; i < num_bo; i++) {
467 bo = bos[i].bo;
468 bo->space_accounted = bos[i].new_accounted;
469 }
470
471 return RADEON_CS_SPACE_OK;
472 }
473
474 static struct radeon_cs_funcs radeon_cs_legacy_funcs = {
475 cs_create,
476 cs_write_reloc,
477 cs_begin,
478 cs_end,
479 cs_emit,
480 cs_destroy,
481 cs_erase,
482 cs_need_flush,
483 cs_print,
484 cs_check_space
485 };
486
487 struct radeon_cs_manager *radeon_cs_manager_legacy_ctor(struct radeon_context *ctx)
488 {
489 struct cs_manager_legacy *csm;
490
491 csm = (struct cs_manager_legacy*)
492 calloc(1, sizeof(struct cs_manager_legacy));
493 if (csm == NULL) {
494 return NULL;
495 }
496 csm->base.funcs = &radeon_cs_legacy_funcs;
497 csm->base.fd = ctx->dri.fd;
498 csm->ctx = ctx;
499 csm->pending_age = 1;
500 return (struct radeon_cs_manager*)csm;
501 }
502
503 void radeon_cs_manager_legacy_dtor(struct radeon_cs_manager *csm)
504 {
505 free(csm);
506 }
507