Merge branch 'lp-offset-twoside'
[mesa.git] / src / mesa / drivers / dri / radeon / radeon_bo_legacy.c
1 /*
2 * Copyright © 2008 Nicolai Haehnle
3 * Copyright © 2008 Dave Airlie
4 * Copyright © 2008 Jérôme Glisse
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
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 COPYRIGHT HOLDERS, AUTHORS AND/OR ITS 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 * The above copyright notice and this permission notice (including the
24 * next paragraph) shall be included in all copies or substantial portions
25 * of the Software.
26 */
27 /*
28 * Authors:
29 * Aapo Tahkola <aet@rasterburn.org>
30 * Nicolai Haehnle <prefect_@gmx.net>
31 * Dave Airlie
32 * Jérôme Glisse <glisse@freedesktop.org>
33 */
34 #include <stdio.h>
35 #include <stddef.h>
36 #include <stdint.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <unistd.h>
41 #include <sys/mman.h>
42 #include <sys/ioctl.h>
43 #include "xf86drm.h"
44 #include "texmem.h"
45 #include "main/simple_list.h"
46
47 #include "drm.h"
48 #include "radeon_drm.h"
49 #include "radeon_common.h"
50 #include "radeon_bocs_wrapper.h"
51 #include "radeon_macros.h"
52
53 #ifdef HAVE_LIBDRM_RADEON
54 #include "radeon_bo_int.h"
55 #else
56 #include "radeon_bo_int_drm.h"
57 #endif
58
59 /* no seriously texmem.c is this screwed up */
60 struct bo_legacy_texture_object {
61 driTextureObject base;
62 struct bo_legacy *parent;
63 };
64
65 struct bo_legacy {
66 struct radeon_bo_int base;
67 int map_count;
68 uint32_t pending;
69 int is_pending;
70 int static_bo;
71 uint32_t offset;
72 struct bo_legacy_texture_object *tobj;
73 int validated;
74 int dirty;
75 void *ptr;
76 struct bo_legacy *next, *prev;
77 struct bo_legacy *pnext, *pprev;
78 };
79
80 struct bo_manager_legacy {
81 struct radeon_bo_manager base;
82 unsigned nhandle;
83 unsigned nfree_handles;
84 unsigned cfree_handles;
85 uint32_t current_age;
86 struct bo_legacy bos;
87 struct bo_legacy pending_bos;
88 uint32_t fb_location;
89 uint32_t texture_offset;
90 unsigned dma_alloc_size;
91 uint32_t dma_buf_count;
92 unsigned cpendings;
93 driTextureObject texture_swapped;
94 driTexHeap *texture_heap;
95 struct radeon_screen *screen;
96 unsigned *free_handles;
97 };
98
99 static void bo_legacy_tobj_destroy(void *data, driTextureObject *t)
100 {
101 struct bo_legacy_texture_object *tobj = (struct bo_legacy_texture_object *)t;
102
103 if (tobj->parent) {
104 tobj->parent->tobj = NULL;
105 tobj->parent->validated = 0;
106 }
107 }
108
109 static void inline clean_handles(struct bo_manager_legacy *bom)
110 {
111 while (bom->cfree_handles > 0 &&
112 !bom->free_handles[bom->cfree_handles - 1])
113 bom->cfree_handles--;
114
115 }
116 static int legacy_new_handle(struct bo_manager_legacy *bom, uint32_t *handle)
117 {
118 uint32_t tmp;
119
120 *handle = 0;
121 if (bom->nhandle == 0xFFFFFFFF) {
122 return -EINVAL;
123 }
124 if (bom->cfree_handles > 0) {
125 tmp = bom->free_handles[--bom->cfree_handles];
126 clean_handles(bom);
127 } else {
128 bom->cfree_handles = 0;
129 tmp = bom->nhandle++;
130 }
131 assert(tmp);
132 *handle = tmp;
133 return 0;
134 }
135
136 static int legacy_free_handle(struct bo_manager_legacy *bom, uint32_t handle)
137 {
138 uint32_t *handles;
139
140 if (!handle) {
141 return 0;
142 }
143 if (handle == (bom->nhandle - 1)) {
144 int i;
145
146 bom->nhandle--;
147 for (i = bom->cfree_handles - 1; i >= 0; i--) {
148 if (bom->free_handles[i] == (bom->nhandle - 1)) {
149 bom->nhandle--;
150 bom->free_handles[i] = 0;
151 }
152 }
153 clean_handles(bom);
154 return 0;
155 }
156 if (bom->cfree_handles < bom->nfree_handles) {
157 bom->free_handles[bom->cfree_handles++] = handle;
158 return 0;
159 }
160 bom->nfree_handles += 0x100;
161 handles = (uint32_t*)realloc(bom->free_handles, bom->nfree_handles * 4);
162 if (handles == NULL) {
163 bom->nfree_handles -= 0x100;
164 return -ENOMEM;
165 }
166 bom->free_handles = handles;
167 bom->free_handles[bom->cfree_handles++] = handle;
168 return 0;
169 }
170
171 static void legacy_get_current_age(struct bo_manager_legacy *boml)
172 {
173 drm_radeon_getparam_t gp;
174 unsigned char *RADEONMMIO = NULL;
175 int r;
176
177 if ( IS_R300_CLASS(boml->screen)
178 || IS_R600_CLASS(boml->screen) )
179 {
180 gp.param = RADEON_PARAM_LAST_CLEAR;
181 gp.value = (int *)&boml->current_age;
182 r = drmCommandWriteRead(boml->base.fd, DRM_RADEON_GETPARAM,
183 &gp, sizeof(gp));
184 if (r) {
185 fprintf(stderr, "%s: drmRadeonGetParam: %d\n", __FUNCTION__, r);
186 exit(1);
187 }
188 }
189 else {
190 RADEONMMIO = boml->screen->mmio.map;
191 boml->current_age = boml->screen->scratch[3];
192 boml->current_age = INREG(RADEON_GUI_SCRATCH_REG3);
193 }
194 }
195
196 static int legacy_is_pending(struct radeon_bo_int *boi)
197 {
198 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)boi->bom;
199 struct bo_legacy *bo_legacy = (struct bo_legacy*)boi;
200
201 if (bo_legacy->is_pending <= 0) {
202 bo_legacy->is_pending = 0;
203 return 0;
204 }
205 if (boml->current_age >= bo_legacy->pending) {
206 if (boml->pending_bos.pprev == bo_legacy) {
207 boml->pending_bos.pprev = bo_legacy->pprev;
208 }
209 bo_legacy->pprev->pnext = bo_legacy->pnext;
210 if (bo_legacy->pnext) {
211 bo_legacy->pnext->pprev = bo_legacy->pprev;
212 }
213 assert(bo_legacy->is_pending <= boi->cref);
214 while (bo_legacy->is_pending--) {
215 boi = (struct radeon_bo_int *)radeon_bo_unref((struct radeon_bo *)boi);
216 if (!boi)
217 break;
218 }
219 if (boi)
220 bo_legacy->is_pending = 0;
221 boml->cpendings--;
222 return 0;
223 }
224 return 1;
225 }
226
227 static int legacy_wait_pending(struct radeon_bo_int *bo)
228 {
229 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bo->bom;
230 struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
231
232 if (!bo_legacy->is_pending) {
233 return 0;
234 }
235 /* FIXME: lockup and userspace busy looping that's all the folks */
236 legacy_get_current_age(boml);
237 while (legacy_is_pending(bo)) {
238 usleep(10);
239 legacy_get_current_age(boml);
240 }
241 return 0;
242 }
243
244 void legacy_track_pending(struct radeon_bo_manager *bom, int debug)
245 {
246 struct bo_manager_legacy *boml = (struct bo_manager_legacy*) bom;
247 struct bo_legacy *bo_legacy;
248 struct bo_legacy *next;
249
250 legacy_get_current_age(boml);
251 bo_legacy = boml->pending_bos.pnext;
252 while (bo_legacy) {
253 if (debug)
254 fprintf(stderr,"pending %p %d %d %d\n", bo_legacy, bo_legacy->base.size,
255 boml->current_age, bo_legacy->pending);
256 next = bo_legacy->pnext;
257 if (legacy_is_pending(&(bo_legacy->base))) {
258 }
259 bo_legacy = next;
260 }
261 }
262
263 static int legacy_wait_any_pending(struct bo_manager_legacy *boml)
264 {
265 struct bo_legacy *bo_legacy;
266
267 legacy_get_current_age(boml);
268 bo_legacy = boml->pending_bos.pnext;
269 if (!bo_legacy)
270 return -1;
271 legacy_wait_pending(&bo_legacy->base);
272 return 0;
273 }
274
275 static void legacy_kick_all_buffers(struct bo_manager_legacy *boml)
276 {
277 struct bo_legacy *legacy;
278
279 legacy = boml->bos.next;
280 while (legacy != &boml->bos) {
281 if (legacy->tobj) {
282 if (legacy->validated) {
283 driDestroyTextureObject(&legacy->tobj->base);
284 legacy->tobj = 0;
285 legacy->validated = 0;
286 }
287 }
288 legacy = legacy->next;
289 }
290 }
291
292 static struct bo_legacy *bo_allocate(struct bo_manager_legacy *boml,
293 uint32_t size,
294 uint32_t alignment,
295 uint32_t domains,
296 uint32_t flags)
297 {
298 struct bo_legacy *bo_legacy;
299 static int pgsize;
300
301 if (pgsize == 0)
302 pgsize = getpagesize() - 1;
303
304 size = (size + pgsize) & ~pgsize;
305
306 bo_legacy = (struct bo_legacy*)calloc(1, sizeof(struct bo_legacy));
307 if (bo_legacy == NULL) {
308 return NULL;
309 }
310 bo_legacy->base.bom = (struct radeon_bo_manager*)boml;
311 bo_legacy->base.handle = 0;
312 bo_legacy->base.size = size;
313 bo_legacy->base.alignment = alignment;
314 bo_legacy->base.domains = domains;
315 bo_legacy->base.flags = flags;
316 bo_legacy->base.ptr = NULL;
317 bo_legacy->map_count = 0;
318 bo_legacy->next = NULL;
319 bo_legacy->prev = NULL;
320 bo_legacy->pnext = NULL;
321 bo_legacy->pprev = NULL;
322 bo_legacy->next = boml->bos.next;
323 bo_legacy->prev = &boml->bos;
324 boml->bos.next = bo_legacy;
325 if (bo_legacy->next) {
326 bo_legacy->next->prev = bo_legacy;
327 }
328
329 return bo_legacy;
330 }
331
332 static int bo_dma_alloc(struct radeon_bo_int *bo)
333 {
334 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bo->bom;
335 struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
336 drm_radeon_mem_alloc_t alloc;
337 unsigned size;
338 int base_offset;
339 int r;
340
341 /* align size on 4Kb */
342 size = (((4 * 1024) - 1) + bo_legacy->base.size) & ~((4 * 1024) - 1);
343 alloc.region = RADEON_MEM_REGION_GART;
344 alloc.alignment = bo_legacy->base.alignment;
345 alloc.size = size;
346 alloc.region_offset = &base_offset;
347 r = drmCommandWriteRead(bo->bom->fd,
348 DRM_RADEON_ALLOC,
349 &alloc,
350 sizeof(alloc));
351 if (r) {
352 /* ptr is set to NULL if dma allocation failed */
353 bo_legacy->ptr = NULL;
354 return r;
355 }
356 bo_legacy->ptr = boml->screen->gartTextures.map + base_offset;
357 bo_legacy->offset = boml->screen->gart_texture_offset + base_offset;
358 bo->size = size;
359 boml->dma_alloc_size += size;
360 boml->dma_buf_count++;
361 return 0;
362 }
363
364 static int bo_dma_free(struct radeon_bo_int *bo)
365 {
366 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bo->bom;
367 struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
368 drm_radeon_mem_free_t memfree;
369 int r;
370
371 if (bo_legacy->ptr == NULL) {
372 /* ptr is set to NULL if dma allocation failed */
373 return 0;
374 }
375 legacy_get_current_age(boml);
376 memfree.region = RADEON_MEM_REGION_GART;
377 memfree.region_offset = bo_legacy->offset;
378 memfree.region_offset -= boml->screen->gart_texture_offset;
379 r = drmCommandWrite(boml->base.fd,
380 DRM_RADEON_FREE,
381 &memfree,
382 sizeof(memfree));
383 if (r) {
384 fprintf(stderr, "Failed to free bo[%p] at %08x\n",
385 &bo_legacy->base, memfree.region_offset);
386 fprintf(stderr, "ret = %s\n", strerror(-r));
387 return r;
388 }
389 boml->dma_alloc_size -= bo_legacy->base.size;
390 boml->dma_buf_count--;
391 return 0;
392 }
393
394 static void bo_free(struct bo_legacy *bo_legacy)
395 {
396 struct bo_manager_legacy *boml;
397
398 if (bo_legacy == NULL) {
399 return;
400 }
401 boml = (struct bo_manager_legacy *)bo_legacy->base.bom;
402 bo_legacy->prev->next = bo_legacy->next;
403 if (bo_legacy->next) {
404 bo_legacy->next->prev = bo_legacy->prev;
405 }
406 if (!bo_legacy->static_bo) {
407 legacy_free_handle(boml, bo_legacy->base.handle);
408 if (bo_legacy->base.domains & RADEON_GEM_DOMAIN_GTT) {
409 /* dma buffers */
410 bo_dma_free(&bo_legacy->base);
411 } else {
412 driDestroyTextureObject(&bo_legacy->tobj->base);
413 bo_legacy->tobj = NULL;
414 /* free backing store */
415 free(bo_legacy->ptr);
416 }
417 }
418 memset(bo_legacy, 0 , sizeof(struct bo_legacy));
419 free(bo_legacy);
420 }
421
422 static struct radeon_bo *bo_open(struct radeon_bo_manager *bom,
423 uint32_t handle,
424 uint32_t size,
425 uint32_t alignment,
426 uint32_t domains,
427 uint32_t flags)
428 {
429 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bom;
430 struct bo_legacy *bo_legacy;
431 int r;
432
433 if (handle) {
434 bo_legacy = boml->bos.next;
435 while (bo_legacy) {
436 if (bo_legacy->base.handle == handle) {
437 radeon_bo_ref((struct radeon_bo *)&(bo_legacy->base));
438 return (struct radeon_bo*)bo_legacy;
439 }
440 bo_legacy = bo_legacy->next;
441 }
442 return NULL;
443 }
444 bo_legacy = bo_allocate(boml, size, alignment, domains, flags);
445 bo_legacy->static_bo = 0;
446 r = legacy_new_handle(boml, &bo_legacy->base.handle);
447 if (r) {
448 bo_free(bo_legacy);
449 return NULL;
450 }
451 if (bo_legacy->base.domains & RADEON_GEM_DOMAIN_GTT)
452 {
453 retry:
454 legacy_track_pending(&boml->base, 0);
455 /* dma buffers */
456
457 r = bo_dma_alloc(&(bo_legacy->base));
458 if (r)
459 {
460 if (legacy_wait_any_pending(boml) == -1)
461 {
462 bo_free(bo_legacy);
463 return NULL;
464 }
465 goto retry;
466 return NULL;
467 }
468 }
469 else
470 {
471 bo_legacy->ptr = malloc(bo_legacy->base.size);
472 if (bo_legacy->ptr == NULL) {
473 bo_free(bo_legacy);
474 return NULL;
475 }
476 }
477 radeon_bo_ref((struct radeon_bo *)&(bo_legacy->base));
478
479 return (struct radeon_bo*)bo_legacy;
480 }
481
482 static void bo_ref(struct radeon_bo_int *bo)
483 {
484 }
485
486 static struct radeon_bo *bo_unref(struct radeon_bo_int *boi)
487 {
488 struct bo_legacy *bo_legacy = (struct bo_legacy*)boi;
489
490 if (boi->cref <= 0) {
491 bo_legacy->prev->next = bo_legacy->next;
492 if (bo_legacy->next) {
493 bo_legacy->next->prev = bo_legacy->prev;
494 }
495 if (!bo_legacy->is_pending) {
496 bo_free(bo_legacy);
497 }
498 return NULL;
499 }
500 return (struct radeon_bo *)boi;
501 }
502
503 static int bo_map(struct radeon_bo_int *bo, int write)
504 {
505 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bo->bom;
506 struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
507
508 legacy_wait_pending(bo);
509 bo_legacy->validated = 0;
510 bo_legacy->dirty = 1;
511 bo_legacy->map_count++;
512 bo->ptr = bo_legacy->ptr;
513 /* Read the first pixel in the frame buffer. This should
514 * be a noop, right? In fact without this conform fails as reading
515 * from the framebuffer sometimes produces old results -- the
516 * on-card read cache gets mixed up and doesn't notice that the
517 * framebuffer has been updated.
518 *
519 * Note that we should probably be reading some otherwise unused
520 * region of VRAM, otherwise we might get incorrect results when
521 * reading pixels from the top left of the screen.
522 *
523 * I found this problem on an R420 with glean's texCube test.
524 * Note that the R200 span code also *writes* the first pixel in the
525 * framebuffer, but I've found this to be unnecessary.
526 * -- Nicolai Hähnle, June 2008
527 */
528 if (!(bo->domains & RADEON_GEM_DOMAIN_GTT)) {
529 int p;
530 volatile int *buf = (int*)boml->screen->driScreen->pFB;
531 p = *buf;
532 }
533
534 return 0;
535 }
536
537 static int bo_unmap(struct radeon_bo_int *bo)
538 {
539 struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
540
541 if (--bo_legacy->map_count > 0)
542 {
543 return 0;
544 }
545
546 bo->ptr = NULL;
547
548 return 0;
549 }
550
551 static int bo_is_busy(struct radeon_bo_int *bo, uint32_t *domain)
552 {
553 *domain = 0;
554 if (bo->domains & RADEON_GEM_DOMAIN_GTT)
555 *domain = RADEON_GEM_DOMAIN_GTT;
556 else
557 *domain = RADEON_GEM_DOMAIN_CPU;
558 if (legacy_is_pending(bo))
559 return -EBUSY;
560 else
561 return 0;
562 }
563
564 static int bo_is_static(struct radeon_bo_int *bo)
565 {
566 struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
567 return bo_legacy->static_bo;
568 }
569
570 static struct radeon_bo_funcs bo_legacy_funcs = {
571 bo_open,
572 bo_ref,
573 bo_unref,
574 bo_map,
575 bo_unmap,
576 NULL,
577 bo_is_static,
578 NULL,
579 NULL,
580 bo_is_busy
581 };
582
583 static int bo_vram_validate(struct radeon_bo_int *bo,
584 uint32_t *soffset,
585 uint32_t *eoffset)
586 {
587 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bo->bom;
588 struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
589 int r;
590 int retry_count = 0, pending_retry = 0;
591
592 if (!bo_legacy->tobj) {
593 bo_legacy->tobj = CALLOC(sizeof(struct bo_legacy_texture_object));
594 bo_legacy->tobj->parent = bo_legacy;
595 make_empty_list(&bo_legacy->tobj->base);
596 bo_legacy->tobj->base.totalSize = bo->size;
597 retry:
598 r = driAllocateTexture(&boml->texture_heap, 1,
599 &bo_legacy->tobj->base);
600 if (r) {
601 pending_retry = 0;
602 while(boml->cpendings && pending_retry++ < 10000) {
603 legacy_track_pending(&boml->base, 0);
604 retry_count++;
605 if (retry_count > 2) {
606 free(bo_legacy->tobj);
607 bo_legacy->tobj = NULL;
608 fprintf(stderr, "Ouch! vram_validate failed %d\n", r);
609 return -1;
610 }
611 goto retry;
612 }
613 }
614 bo_legacy->offset = boml->texture_offset +
615 bo_legacy->tobj->base.memBlock->ofs;
616 bo_legacy->dirty = 1;
617 }
618
619 assert(bo_legacy->tobj->base.memBlock);
620
621 driUpdateTextureLRU(&bo_legacy->tobj->base);
622
623 if (bo_legacy->dirty || bo_legacy->tobj->base.dirty_images[0]) {
624 if (IS_R600_CLASS(boml->screen)) {
625 drm_radeon_texture_t tex;
626 drm_radeon_tex_image_t tmp;
627 int ret;
628
629 tex.offset = bo_legacy->offset;
630 tex.image = &tmp;
631 assert(!(tex.offset & 1023));
632
633 tmp.x = 0;
634 tmp.y = 0;
635 tmp.width = bo->size;
636 tmp.height = 1;
637 tmp.data = bo_legacy->ptr;
638 tex.format = RADEON_TXFORMAT_ARGB8888;
639 tex.width = tmp.width;
640 tex.height = tmp.height;
641 tex.pitch = bo->size;
642 do {
643 ret = drmCommandWriteRead(bo->bom->fd,
644 DRM_RADEON_TEXTURE,
645 &tex,
646 sizeof(drm_radeon_texture_t));
647 if (ret) {
648 if (RADEON_DEBUG & RADEON_IOCTL)
649 fprintf(stderr, "DRM_RADEON_TEXTURE: again!\n");
650 usleep(1);
651 }
652 } while (ret == -EAGAIN);
653 } else {
654 /* Copy to VRAM using a blit.
655 * All memory is 4K aligned. We're using 1024 pixels wide blits.
656 */
657 drm_radeon_texture_t tex;
658 drm_radeon_tex_image_t tmp;
659 int ret;
660
661 tex.offset = bo_legacy->offset;
662 tex.image = &tmp;
663 assert(!(tex.offset & 1023));
664
665 tmp.x = 0;
666 tmp.y = 0;
667 if (bo->size < 4096) {
668 tmp.width = (bo->size + 3) / 4;
669 tmp.height = 1;
670 } else {
671 tmp.width = 1024;
672 tmp.height = (bo->size + 4095) / 4096;
673 }
674 tmp.data = bo_legacy->ptr;
675 tex.format = RADEON_TXFORMAT_ARGB8888;
676 tex.width = tmp.width;
677 tex.height = tmp.height;
678 tex.pitch = MAX2(tmp.width / 16, 1);
679 do {
680 ret = drmCommandWriteRead(bo->bom->fd,
681 DRM_RADEON_TEXTURE,
682 &tex,
683 sizeof(drm_radeon_texture_t));
684 if (ret) {
685 if (RADEON_DEBUG & RADEON_IOCTL)
686 fprintf(stderr, "DRM_RADEON_TEXTURE: again!\n");
687 usleep(1);
688 }
689 } while (ret == -EAGAIN);
690 }
691 bo_legacy->dirty = 0;
692 bo_legacy->tobj->base.dirty_images[0] = 0;
693 }
694 return 0;
695 }
696
697 /*
698 * radeon_bo_legacy_validate -
699 * returns:
700 * 0 - all good
701 * -EINVAL - mapped buffer can't be validated
702 * -EAGAIN - restart validation we've kicked all the buffers out
703 */
704 int radeon_bo_legacy_validate(struct radeon_bo *bo,
705 uint32_t *soffset,
706 uint32_t *eoffset)
707 {
708 struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
709 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)boi->bom;
710 struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
711 int r;
712 int retries = 0;
713
714 if (bo_legacy->map_count) {
715 fprintf(stderr, "bo(%p, %d) is mapped (%d) can't valide it.\n",
716 bo, boi->size, bo_legacy->map_count);
717 return -EINVAL;
718 }
719 if(boi->size == 0) {
720 fprintf(stderr, "bo(%p) has size 0.\n", bo);
721 return -EINVAL;
722 }
723 if (bo_legacy->static_bo || bo_legacy->validated) {
724 *soffset = bo_legacy->offset;
725 *eoffset = bo_legacy->offset + boi->size;
726
727 return 0;
728 }
729 if (!(boi->domains & RADEON_GEM_DOMAIN_GTT)) {
730
731 r = bo_vram_validate(boi, soffset, eoffset);
732 if (r) {
733 legacy_track_pending(&boml->base, 0);
734 legacy_kick_all_buffers(boml);
735 retries++;
736 if (retries == 2) {
737 fprintf(stderr,"legacy bo: failed to get relocations into aperture\n");
738 assert(0);
739 exit(-1);
740 }
741 return -EAGAIN;
742 }
743 }
744 *soffset = bo_legacy->offset;
745 *eoffset = bo_legacy->offset + boi->size;
746 bo_legacy->validated = 1;
747
748 return 0;
749 }
750
751 void radeon_bo_legacy_pending(struct radeon_bo *bo, uint32_t pending)
752 {
753 struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
754 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)boi->bom;
755 struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
756
757 bo_legacy->pending = pending;
758 bo_legacy->is_pending++;
759 /* add to pending list */
760 radeon_bo_ref(bo);
761 if (bo_legacy->is_pending > 1) {
762 return;
763 }
764 bo_legacy->pprev = boml->pending_bos.pprev;
765 bo_legacy->pnext = NULL;
766 bo_legacy->pprev->pnext = bo_legacy;
767 boml->pending_bos.pprev = bo_legacy;
768 boml->cpendings++;
769 }
770
771 void radeon_bo_manager_legacy_dtor(struct radeon_bo_manager *bom)
772 {
773 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bom;
774 struct bo_legacy *bo_legacy;
775
776 if (bom == NULL) {
777 return;
778 }
779 bo_legacy = boml->bos.next;
780 while (bo_legacy) {
781 struct bo_legacy *next;
782
783 next = bo_legacy->next;
784 bo_free(bo_legacy);
785 bo_legacy = next;
786 }
787 driDestroyTextureHeap(boml->texture_heap);
788 free(boml->free_handles);
789 free(boml);
790 }
791
792 static struct bo_legacy *radeon_legacy_bo_alloc_static(struct bo_manager_legacy *bom,
793 int size,
794 uint32_t offset)
795 {
796 struct bo_legacy *bo;
797
798 bo = bo_allocate(bom, size, 0, RADEON_GEM_DOMAIN_VRAM, 0);
799
800 if (bo == NULL)
801 return NULL;
802 bo->static_bo = 1;
803 bo->offset = offset + bom->fb_location;
804 bo->base.handle = bo->offset;
805 bo->ptr = bom->screen->driScreen->pFB + offset;
806 if (bo->base.handle > bom->nhandle) {
807 bom->nhandle = bo->base.handle + 1;
808 }
809 radeon_bo_ref((struct radeon_bo *)&(bo->base));
810 return bo;
811 }
812
813 struct radeon_bo_manager *radeon_bo_manager_legacy_ctor(struct radeon_screen *scrn)
814 {
815 struct bo_manager_legacy *bom;
816 struct bo_legacy *bo;
817 unsigned size;
818
819 bom = (struct bo_manager_legacy*)
820 calloc(1, sizeof(struct bo_manager_legacy));
821 if (bom == NULL) {
822 return NULL;
823 }
824
825 make_empty_list(&bom->texture_swapped);
826
827 bom->texture_heap = driCreateTextureHeap(0,
828 bom,
829 scrn->texSize[0],
830 12,
831 RADEON_NR_TEX_REGIONS,
832 (drmTextureRegionPtr)scrn->sarea->tex_list[0],
833 &scrn->sarea->tex_age[0],
834 &bom->texture_swapped,
835 sizeof(struct bo_legacy_texture_object),
836 &bo_legacy_tobj_destroy);
837 bom->texture_offset = scrn->texOffset[0];
838
839 bom->base.funcs = &bo_legacy_funcs;
840 bom->base.fd = scrn->driScreen->fd;
841 bom->bos.next = NULL;
842 bom->bos.prev = NULL;
843 bom->pending_bos.pprev = &bom->pending_bos;
844 bom->pending_bos.pnext = NULL;
845 bom->screen = scrn;
846 bom->fb_location = scrn->fbLocation;
847 bom->nhandle = 1;
848 bom->cfree_handles = 0;
849 bom->nfree_handles = 0x400;
850 bom->free_handles = (uint32_t*)malloc(bom->nfree_handles * 4);
851 if (bom->free_handles == NULL) {
852 radeon_bo_manager_legacy_dtor((struct radeon_bo_manager*)bom);
853 return NULL;
854 }
855
856 /* biggest framebuffer size */
857 size = 4096*4096*4;
858
859 /* allocate front */
860 bo = radeon_legacy_bo_alloc_static(bom, size, bom->screen->frontOffset);
861
862 if (!bo) {
863 radeon_bo_manager_legacy_dtor((struct radeon_bo_manager*)bom);
864 return NULL;
865 }
866 if (scrn->sarea->tiling_enabled) {
867 bo->base.flags = RADEON_BO_FLAGS_MACRO_TILE;
868 }
869
870 /* allocate back */
871 bo = radeon_legacy_bo_alloc_static(bom, size, bom->screen->backOffset);
872
873 if (!bo) {
874 radeon_bo_manager_legacy_dtor((struct radeon_bo_manager*)bom);
875 return NULL;
876 }
877 if (scrn->sarea->tiling_enabled) {
878 bo->base.flags = RADEON_BO_FLAGS_MACRO_TILE;
879 }
880
881 /* allocate depth */
882 bo = radeon_legacy_bo_alloc_static(bom, size, bom->screen->depthOffset);
883
884 if (!bo) {
885 radeon_bo_manager_legacy_dtor((struct radeon_bo_manager*)bom);
886 return NULL;
887 }
888 bo->base.flags = 0;
889 if (scrn->sarea->tiling_enabled) {
890 bo->base.flags |= RADEON_BO_FLAGS_MACRO_TILE;
891 bo->base.flags |= RADEON_BO_FLAGS_MICRO_TILE;
892 }
893 return (struct radeon_bo_manager*)bom;
894 }
895
896 void radeon_bo_legacy_texture_age(struct radeon_bo_manager *bom)
897 {
898 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bom;
899 DRI_AGE_TEXTURES(boml->texture_heap);
900 }
901
902 unsigned radeon_bo_legacy_relocs_size(struct radeon_bo *bo)
903 {
904 struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
905 struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
906
907 if (bo_legacy->static_bo || (boi->domains & RADEON_GEM_DOMAIN_GTT)) {
908 return 0;
909 }
910 return boi->size;
911 }
912
913 /*
914 * Fake up a bo for things like texture image_override.
915 * bo->offset already includes fb_location
916 */
917 struct radeon_bo *radeon_legacy_bo_alloc_fake(struct radeon_bo_manager *bom,
918 int size,
919 uint32_t offset)
920 {
921 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bom;
922 struct bo_legacy *bo;
923
924 bo = bo_allocate(boml, size, 0, RADEON_GEM_DOMAIN_VRAM, 0);
925
926 if (bo == NULL)
927 return NULL;
928 bo->static_bo = 1;
929 bo->offset = offset;
930 bo->base.handle = bo->offset;
931 bo->ptr = boml->screen->driScreen->pFB + (offset - boml->fb_location);
932 if (bo->base.handle > boml->nhandle) {
933 boml->nhandle = bo->base.handle + 1;
934 }
935 radeon_bo_ref((struct radeon_bo *)&(bo->base));
936 return (struct radeon_bo *)&(bo->base);
937 }
938