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