Merge branch 'mesa_7_5_branch' into mesa_7_6_branch
[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 void legacy_track_pending(struct radeon_bo_manager *bom, int debug)
239 {
240 struct bo_manager_legacy *boml = (struct bo_manager_legacy*) bom;
241 struct bo_legacy *bo_legacy;
242 struct bo_legacy *next;
243
244 legacy_get_current_age(boml);
245 bo_legacy = boml->pending_bos.pnext;
246 while (bo_legacy) {
247 if (debug)
248 fprintf(stderr,"pending %p %d %d %d\n", bo_legacy, bo_legacy->base.size,
249 boml->current_age, bo_legacy->pending);
250 next = bo_legacy->pnext;
251 if (legacy_is_pending(&(bo_legacy->base))) {
252 }
253 bo_legacy = next;
254 }
255 }
256
257 static int legacy_wait_any_pending(struct bo_manager_legacy *boml)
258 {
259 struct bo_legacy *bo_legacy;
260
261 legacy_get_current_age(boml);
262 bo_legacy = boml->pending_bos.pnext;
263 if (!bo_legacy)
264 return -1;
265 legacy_wait_pending(&bo_legacy->base);
266 return 0;
267 }
268
269 static void legacy_kick_all_buffers(struct bo_manager_legacy *boml)
270 {
271 struct bo_legacy *legacy;
272
273 legacy = boml->bos.next;
274 while (legacy != &boml->bos) {
275 if (legacy->tobj) {
276 if (legacy->validated) {
277 driDestroyTextureObject(&legacy->tobj->base);
278 legacy->tobj = 0;
279 legacy->validated = 0;
280 }
281 }
282 legacy = legacy->next;
283 }
284 }
285
286 static struct bo_legacy *bo_allocate(struct bo_manager_legacy *boml,
287 uint32_t size,
288 uint32_t alignment,
289 uint32_t domains,
290 uint32_t flags)
291 {
292 struct bo_legacy *bo_legacy;
293 static int pgsize;
294
295 if (pgsize == 0)
296 pgsize = getpagesize() - 1;
297
298 size = (size + pgsize) & ~pgsize;
299
300 bo_legacy = (struct bo_legacy*)calloc(1, sizeof(struct bo_legacy));
301 if (bo_legacy == NULL) {
302 return NULL;
303 }
304 bo_legacy->base.bom = (struct radeon_bo_manager*)boml;
305 bo_legacy->base.handle = 0;
306 bo_legacy->base.size = size;
307 bo_legacy->base.alignment = alignment;
308 bo_legacy->base.domains = domains;
309 bo_legacy->base.flags = flags;
310 bo_legacy->base.ptr = NULL;
311 bo_legacy->map_count = 0;
312 bo_legacy->next = NULL;
313 bo_legacy->prev = NULL;
314 bo_legacy->pnext = NULL;
315 bo_legacy->pprev = NULL;
316 bo_legacy->next = boml->bos.next;
317 bo_legacy->prev = &boml->bos;
318 boml->bos.next = bo_legacy;
319 if (bo_legacy->next) {
320 bo_legacy->next->prev = bo_legacy;
321 }
322
323 return bo_legacy;
324 }
325
326 static int bo_dma_alloc(struct radeon_bo *bo)
327 {
328 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bo->bom;
329 struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
330 drm_radeon_mem_alloc_t alloc;
331 unsigned size;
332 int base_offset;
333 int r;
334
335 /* align size on 4Kb */
336 size = (((4 * 1024) - 1) + bo->size) & ~((4 * 1024) - 1);
337 alloc.region = RADEON_MEM_REGION_GART;
338 alloc.alignment = bo_legacy->base.alignment;
339 alloc.size = size;
340 alloc.region_offset = &base_offset;
341 r = drmCommandWriteRead(bo->bom->fd,
342 DRM_RADEON_ALLOC,
343 &alloc,
344 sizeof(alloc));
345 if (r) {
346 /* ptr is set to NULL if dma allocation failed */
347 bo_legacy->ptr = NULL;
348 return r;
349 }
350 bo_legacy->ptr = boml->screen->gartTextures.map + base_offset;
351 bo_legacy->offset = boml->screen->gart_texture_offset + base_offset;
352 bo->size = size;
353 boml->dma_alloc_size += size;
354 boml->dma_buf_count++;
355 return 0;
356 }
357
358 static int bo_dma_free(struct radeon_bo *bo)
359 {
360 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bo->bom;
361 struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
362 drm_radeon_mem_free_t memfree;
363 int r;
364
365 if (bo_legacy->ptr == NULL) {
366 /* ptr is set to NULL if dma allocation failed */
367 return 0;
368 }
369 legacy_get_current_age(boml);
370 memfree.region = RADEON_MEM_REGION_GART;
371 memfree.region_offset = bo_legacy->offset;
372 memfree.region_offset -= boml->screen->gart_texture_offset;
373 r = drmCommandWrite(boml->base.fd,
374 DRM_RADEON_FREE,
375 &memfree,
376 sizeof(memfree));
377 if (r) {
378 fprintf(stderr, "Failed to free bo[%p] at %08x\n",
379 &bo_legacy->base, memfree.region_offset);
380 fprintf(stderr, "ret = %s\n", strerror(-r));
381 return r;
382 }
383 boml->dma_alloc_size -= bo_legacy->base.size;
384 boml->dma_buf_count--;
385 return 0;
386 }
387
388 static void bo_free(struct bo_legacy *bo_legacy)
389 {
390 struct bo_manager_legacy *boml;
391
392 if (bo_legacy == NULL) {
393 return;
394 }
395 boml = (struct bo_manager_legacy *)bo_legacy->base.bom;
396 bo_legacy->prev->next = bo_legacy->next;
397 if (bo_legacy->next) {
398 bo_legacy->next->prev = bo_legacy->prev;
399 }
400 if (!bo_legacy->static_bo) {
401 legacy_free_handle(boml, bo_legacy->base.handle);
402 if (bo_legacy->base.domains & RADEON_GEM_DOMAIN_GTT) {
403 /* dma buffers */
404 bo_dma_free(&bo_legacy->base);
405 } else {
406 driDestroyTextureObject(&bo_legacy->tobj->base);
407 bo_legacy->tobj = NULL;
408 /* free backing store */
409 free(bo_legacy->ptr);
410 }
411 }
412 memset(bo_legacy, 0 , sizeof(struct bo_legacy));
413 free(bo_legacy);
414 }
415
416 static struct radeon_bo *bo_open(struct radeon_bo_manager *bom,
417 uint32_t handle,
418 uint32_t size,
419 uint32_t alignment,
420 uint32_t domains,
421 uint32_t flags)
422 {
423 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bom;
424 struct bo_legacy *bo_legacy;
425 int r;
426
427 if (handle) {
428 bo_legacy = boml->bos.next;
429 while (bo_legacy) {
430 if (bo_legacy->base.handle == handle) {
431 radeon_bo_ref(&(bo_legacy->base));
432 return (struct radeon_bo*)bo_legacy;
433 }
434 bo_legacy = bo_legacy->next;
435 }
436 return NULL;
437 }
438 bo_legacy = bo_allocate(boml, size, alignment, domains, flags);
439 bo_legacy->static_bo = 0;
440 r = legacy_new_handle(boml, &bo_legacy->base.handle);
441 if (r) {
442 bo_free(bo_legacy);
443 return NULL;
444 }
445 if (bo_legacy->base.domains & RADEON_GEM_DOMAIN_GTT)
446 {
447 retry:
448 legacy_track_pending(&boml->base, 0);
449 /* dma buffers */
450
451 r = bo_dma_alloc(&(bo_legacy->base));
452 if (r)
453 {
454 if (legacy_wait_any_pending(boml) == -1)
455 {
456 bo_free(bo_legacy);
457 return NULL;
458 }
459 goto retry;
460 return NULL;
461 }
462 }
463 else
464 {
465 bo_legacy->ptr = malloc(bo_legacy->base.size);
466 if (bo_legacy->ptr == NULL) {
467 bo_free(bo_legacy);
468 return NULL;
469 }
470 }
471 radeon_bo_ref(&(bo_legacy->base));
472
473 return (struct radeon_bo*)bo_legacy;
474 }
475
476 static void bo_ref(struct radeon_bo *bo)
477 {
478 }
479
480 static struct radeon_bo *bo_unref(struct radeon_bo *bo)
481 {
482 struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
483
484 if (bo->cref <= 0) {
485 bo_legacy->prev->next = bo_legacy->next;
486 if (bo_legacy->next) {
487 bo_legacy->next->prev = bo_legacy->prev;
488 }
489 if (!bo_legacy->is_pending) {
490 bo_free(bo_legacy);
491 }
492 return NULL;
493 }
494 return bo;
495 }
496
497 static int bo_map(struct radeon_bo *bo, int write)
498 {
499 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bo->bom;
500 struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
501
502 legacy_wait_pending(bo);
503 bo_legacy->validated = 0;
504 bo_legacy->dirty = 1;
505 bo_legacy->map_count++;
506 bo->ptr = bo_legacy->ptr;
507 /* Read the first pixel in the frame buffer. This should
508 * be a noop, right? In fact without this conform fails as reading
509 * from the framebuffer sometimes produces old results -- the
510 * on-card read cache gets mixed up and doesn't notice that the
511 * framebuffer has been updated.
512 *
513 * Note that we should probably be reading some otherwise unused
514 * region of VRAM, otherwise we might get incorrect results when
515 * reading pixels from the top left of the screen.
516 *
517 * I found this problem on an R420 with glean's texCube test.
518 * Note that the R200 span code also *writes* the first pixel in the
519 * framebuffer, but I've found this to be unnecessary.
520 * -- Nicolai Hähnle, June 2008
521 */
522 if (!(bo->domains & RADEON_GEM_DOMAIN_GTT)) {
523 int p;
524 volatile int *buf = (int*)boml->screen->driScreen->pFB;
525 p = *buf;
526 }
527
528 return 0;
529 }
530
531 static int bo_unmap(struct radeon_bo *bo)
532 {
533 struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
534
535 if (--bo_legacy->map_count > 0)
536 {
537 return 0;
538 }
539
540 bo->ptr = NULL;
541
542 return 0;
543 }
544
545 static int bo_is_busy(struct radeon_bo *bo, uint32_t *domain)
546 {
547 *domain = 0;
548 if (bo->domains & RADEON_GEM_DOMAIN_GTT)
549 *domain = RADEON_GEM_DOMAIN_GTT;
550 else
551 *domain = RADEON_GEM_DOMAIN_CPU;
552 if (legacy_is_pending(bo))
553 return -EBUSY;
554 else
555 return 0;
556 }
557
558 static int bo_is_static(struct radeon_bo *bo)
559 {
560 struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
561 return bo_legacy->static_bo;
562 }
563
564 static struct radeon_bo_funcs bo_legacy_funcs = {
565 bo_open,
566 bo_ref,
567 bo_unref,
568 bo_map,
569 bo_unmap,
570 NULL,
571 bo_is_static,
572 NULL,
573 NULL,
574 bo_is_busy
575 };
576
577 static int bo_vram_validate(struct radeon_bo *bo,
578 uint32_t *soffset,
579 uint32_t *eoffset)
580 {
581 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bo->bom;
582 struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
583 int r;
584 int retry_count = 0, pending_retry = 0;
585
586 if (!bo_legacy->tobj) {
587 bo_legacy->tobj = CALLOC(sizeof(struct bo_legacy_texture_object));
588 bo_legacy->tobj->parent = bo_legacy;
589 make_empty_list(&bo_legacy->tobj->base);
590 bo_legacy->tobj->base.totalSize = bo->size;
591 retry:
592 r = driAllocateTexture(&boml->texture_heap, 1,
593 &bo_legacy->tobj->base);
594 if (r) {
595 pending_retry = 0;
596 while(boml->cpendings && pending_retry++ < 10000) {
597 legacy_track_pending(&boml->base, 0);
598 retry_count++;
599 if (retry_count > 2) {
600 free(bo_legacy->tobj);
601 bo_legacy->tobj = NULL;
602 fprintf(stderr, "Ouch! vram_validate failed %d\n", r);
603 return -1;
604 }
605 goto retry;
606 }
607 }
608 bo_legacy->offset = boml->texture_offset +
609 bo_legacy->tobj->base.memBlock->ofs;
610 bo_legacy->dirty = 1;
611 }
612
613 assert(bo_legacy->tobj->base.memBlock);
614
615 if (bo_legacy->tobj)
616 driUpdateTextureLRU(&bo_legacy->tobj->base);
617
618 if (bo_legacy->dirty || bo_legacy->tobj->base.dirty_images[0]) {
619 if (IS_R600_CLASS(boml->screen)) {
620 drm_radeon_texture_t tex;
621 drm_radeon_tex_image_t tmp;
622 int ret;
623
624 tex.offset = bo_legacy->offset;
625 tex.image = &tmp;
626 assert(!(tex.offset & 1023));
627
628 tmp.x = 0;
629 tmp.y = 0;
630 tmp.width = bo->size;
631 tmp.height = 1;
632 tmp.data = bo_legacy->ptr;
633 tex.format = RADEON_TXFORMAT_ARGB8888;
634 tex.width = tmp.width;
635 tex.height = tmp.height;
636 tex.pitch = bo->size;
637 do {
638 ret = drmCommandWriteRead(bo->bom->fd,
639 DRM_RADEON_TEXTURE,
640 &tex,
641 sizeof(drm_radeon_texture_t));
642 if (ret) {
643 if (RADEON_DEBUG & RADEON_IOCTL)
644 fprintf(stderr, "DRM_RADEON_TEXTURE: again!\n");
645 usleep(1);
646 }
647 } while (ret == -EAGAIN);
648 } else {
649 /* Copy to VRAM using a blit.
650 * All memory is 4K aligned. We're using 1024 pixels wide blits.
651 */
652 drm_radeon_texture_t tex;
653 drm_radeon_tex_image_t tmp;
654 int ret;
655
656 tex.offset = bo_legacy->offset;
657 tex.image = &tmp;
658 assert(!(tex.offset & 1023));
659
660 tmp.x = 0;
661 tmp.y = 0;
662 if (bo->size < 4096) {
663 tmp.width = (bo->size + 3) / 4;
664 tmp.height = 1;
665 } else {
666 tmp.width = 1024;
667 tmp.height = (bo->size + 4095) / 4096;
668 }
669 tmp.data = bo_legacy->ptr;
670 tex.format = RADEON_TXFORMAT_ARGB8888;
671 tex.width = tmp.width;
672 tex.height = tmp.height;
673 tex.pitch = MAX2(tmp.width / 16, 1);
674 do {
675 ret = drmCommandWriteRead(bo->bom->fd,
676 DRM_RADEON_TEXTURE,
677 &tex,
678 sizeof(drm_radeon_texture_t));
679 if (ret) {
680 if (RADEON_DEBUG & RADEON_IOCTL)
681 fprintf(stderr, "DRM_RADEON_TEXTURE: again!\n");
682 usleep(1);
683 }
684 } while (ret == -EAGAIN);
685 }
686 bo_legacy->dirty = 0;
687 bo_legacy->tobj->base.dirty_images[0] = 0;
688 }
689 return 0;
690 }
691
692 /*
693 * radeon_bo_legacy_validate -
694 * returns:
695 * 0 - all good
696 * -EINVAL - mapped buffer can't be validated
697 * -EAGAIN - restart validation we've kicked all the buffers out
698 */
699 int radeon_bo_legacy_validate(struct radeon_bo *bo,
700 uint32_t *soffset,
701 uint32_t *eoffset)
702 {
703 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bo->bom;
704 struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
705 int r;
706 int retries = 0;
707
708 if (bo_legacy->map_count) {
709 fprintf(stderr, "bo(%p, %d) is mapped (%d) can't valide it.\n",
710 bo, bo->size, bo_legacy->map_count);
711 return -EINVAL;
712 }
713 if (bo_legacy->static_bo || bo_legacy->validated) {
714 *soffset = bo_legacy->offset;
715 *eoffset = bo_legacy->offset + bo->size;
716
717 return 0;
718 }
719 if (!(bo->domains & RADEON_GEM_DOMAIN_GTT)) {
720
721 r = bo_vram_validate(bo, soffset, eoffset);
722 if (r) {
723 legacy_track_pending(&boml->base, 0);
724 legacy_kick_all_buffers(boml);
725 retries++;
726 if (retries == 2) {
727 fprintf(stderr,"legacy bo: failed to get relocations into aperture\n");
728 assert(0);
729 exit(-1);
730 }
731 return -EAGAIN;
732 }
733 }
734 *soffset = bo_legacy->offset;
735 *eoffset = bo_legacy->offset + bo->size;
736 bo_legacy->validated = 1;
737
738 return 0;
739 }
740
741 void radeon_bo_legacy_pending(struct radeon_bo *bo, uint32_t pending)
742 {
743 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bo->bom;
744 struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
745
746 bo_legacy->pending = pending;
747 bo_legacy->is_pending++;
748 /* add to pending list */
749 radeon_bo_ref(bo);
750 if (bo_legacy->is_pending > 1) {
751 return;
752 }
753 bo_legacy->pprev = boml->pending_bos.pprev;
754 bo_legacy->pnext = NULL;
755 bo_legacy->pprev->pnext = bo_legacy;
756 boml->pending_bos.pprev = bo_legacy;
757 boml->cpendings++;
758 }
759
760 void radeon_bo_manager_legacy_dtor(struct radeon_bo_manager *bom)
761 {
762 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bom;
763 struct bo_legacy *bo_legacy;
764
765 if (bom == NULL) {
766 return;
767 }
768 bo_legacy = boml->bos.next;
769 while (bo_legacy) {
770 struct bo_legacy *next;
771
772 next = bo_legacy->next;
773 bo_free(bo_legacy);
774 bo_legacy = next;
775 }
776 driDestroyTextureHeap(boml->texture_heap);
777 free(boml->free_handles);
778 free(boml);
779 }
780
781 static struct bo_legacy *radeon_legacy_bo_alloc_static(struct bo_manager_legacy *bom,
782 int size,
783 uint32_t offset)
784 {
785 struct bo_legacy *bo;
786
787 bo = bo_allocate(bom, size, 0, RADEON_GEM_DOMAIN_VRAM, 0);
788
789 if (bo == NULL)
790 return NULL;
791 bo->static_bo = 1;
792 bo->offset = offset + bom->fb_location;
793 bo->base.handle = bo->offset;
794 bo->ptr = bom->screen->driScreen->pFB + offset;
795 if (bo->base.handle > bom->nhandle) {
796 bom->nhandle = bo->base.handle + 1;
797 }
798 radeon_bo_ref(&(bo->base));
799 return bo;
800 }
801
802 struct radeon_bo_manager *radeon_bo_manager_legacy_ctor(struct radeon_screen *scrn)
803 {
804 struct bo_manager_legacy *bom;
805 struct bo_legacy *bo;
806 unsigned size;
807
808 bom = (struct bo_manager_legacy*)
809 calloc(1, sizeof(struct bo_manager_legacy));
810 if (bom == NULL) {
811 return NULL;
812 }
813
814 make_empty_list(&bom->texture_swapped);
815
816 bom->texture_heap = driCreateTextureHeap(0,
817 bom,
818 scrn->texSize[0],
819 12,
820 RADEON_NR_TEX_REGIONS,
821 (drmTextureRegionPtr)scrn->sarea->tex_list[0],
822 &scrn->sarea->tex_age[0],
823 &bom->texture_swapped,
824 sizeof(struct bo_legacy_texture_object),
825 &bo_legacy_tobj_destroy);
826 bom->texture_offset = scrn->texOffset[0];
827
828 bom->base.funcs = &bo_legacy_funcs;
829 bom->base.fd = scrn->driScreen->fd;
830 bom->bos.next = NULL;
831 bom->bos.prev = NULL;
832 bom->pending_bos.pprev = &bom->pending_bos;
833 bom->pending_bos.pnext = NULL;
834 bom->screen = scrn;
835 bom->fb_location = scrn->fbLocation;
836 bom->nhandle = 1;
837 bom->cfree_handles = 0;
838 bom->nfree_handles = 0x400;
839 bom->free_handles = (uint32_t*)malloc(bom->nfree_handles * 4);
840 if (bom->free_handles == NULL) {
841 radeon_bo_manager_legacy_dtor((struct radeon_bo_manager*)bom);
842 return NULL;
843 }
844
845 /* biggest framebuffer size */
846 size = 4096*4096*4;
847
848 /* allocate front */
849 bo = radeon_legacy_bo_alloc_static(bom, size, bom->screen->frontOffset);
850
851 if (!bo) {
852 radeon_bo_manager_legacy_dtor((struct radeon_bo_manager*)bom);
853 return NULL;
854 }
855 if (scrn->sarea->tiling_enabled) {
856 bo->base.flags = RADEON_BO_FLAGS_MACRO_TILE;
857 }
858
859 /* allocate back */
860 bo = radeon_legacy_bo_alloc_static(bom, size, bom->screen->backOffset);
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 depth */
871 bo = radeon_legacy_bo_alloc_static(bom, size, bom->screen->depthOffset);
872
873 if (!bo) {
874 radeon_bo_manager_legacy_dtor((struct radeon_bo_manager*)bom);
875 return NULL;
876 }
877 bo->base.flags = 0;
878 if (scrn->sarea->tiling_enabled) {
879 bo->base.flags |= RADEON_BO_FLAGS_MACRO_TILE;
880 bo->base.flags |= RADEON_BO_FLAGS_MICRO_TILE;
881 }
882 return (struct radeon_bo_manager*)bom;
883 }
884
885 void radeon_bo_legacy_texture_age(struct radeon_bo_manager *bom)
886 {
887 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bom;
888 DRI_AGE_TEXTURES(boml->texture_heap);
889 }
890
891 unsigned radeon_bo_legacy_relocs_size(struct radeon_bo *bo)
892 {
893 struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
894
895 if (bo_legacy->static_bo || (bo->domains & RADEON_GEM_DOMAIN_GTT)) {
896 return 0;
897 }
898 return bo->size;
899 }
900
901 /*
902 * Fake up a bo for things like texture image_override.
903 * bo->offset already includes fb_location
904 */
905 struct radeon_bo *radeon_legacy_bo_alloc_fake(struct radeon_bo_manager *bom,
906 int size,
907 uint32_t offset)
908 {
909 struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bom;
910 struct bo_legacy *bo;
911
912 bo = bo_allocate(boml, size, 0, RADEON_GEM_DOMAIN_VRAM, 0);
913
914 if (bo == NULL)
915 return NULL;
916 bo->static_bo = 1;
917 bo->offset = offset;
918 bo->base.handle = bo->offset;
919 bo->ptr = boml->screen->driScreen->pFB + (offset - boml->fb_location);
920 if (bo->base.handle > boml->nhandle) {
921 boml->nhandle = bo->base.handle + 1;
922 }
923 radeon_bo_ref(&(bo->base));
924 return &(bo->base);
925 }
926