radeon_vbo.c revision ad43ddac
1/*
2 * Copyright © 2009 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
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 NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 *    Dave Airlie <airlied@redhat.com>
25 *
26 */
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include <errno.h>
32#include "radeon.h"
33#include "radeon_bo.h"
34#include "radeon_cs.h"
35
36#define VBO_SIZE (16*1024)
37
38/* KMS vertex buffer support - for R600 only but could be used on previous gpus */
39
40#ifdef XF86DRM_MODE
41
42static struct radeon_bo *radeon_vbo_get_bo(ScrnInfoPtr pScrn);
43
44void radeon_vbo_put(ScrnInfoPtr pScrn)
45{
46    RADEONInfoPtr info = RADEONPTR(pScrn);
47    struct radeon_accel_state *accel_state = info->accel_state;
48
49    if (accel_state->vb_bo) {
50	radeon_bo_unmap(accel_state->vb_bo);
51	radeon_bo_unref(accel_state->vb_bo);
52	accel_state->vb_bo = NULL;
53	accel_state->vb_total = 0;
54    }
55
56    accel_state->vb_offset = 0;
57}
58
59void radeon_vbo_get(ScrnInfoPtr pScrn)
60{
61    RADEONInfoPtr info = RADEONPTR(pScrn);
62    struct radeon_accel_state *accel_state = info->accel_state;
63
64    accel_state->vb_bo = radeon_vbo_get_bo(pScrn);
65
66    accel_state->vb_total = VBO_SIZE;
67    accel_state->vb_offset = 0;
68    accel_state->vb_start_op = accel_state->vb_offset;
69}
70
71/* these functions could migrate to libdrm and
72   be shared with the radeon 3D driver */
73static int radeon_bo_is_idle(struct radeon_bo *bo)
74{
75    uint32_t domain;
76    int ret = radeon_bo_is_busy(bo, &domain);
77    return ret != -EBUSY;
78}
79
80void radeon_vbo_init_lists(ScrnInfoPtr pScrn)
81{
82    RADEONInfoPtr info = RADEONPTR(pScrn);
83    struct radeon_accel_state *accel_state = info->accel_state;
84
85    accel_state->use_vbos = TRUE;
86    make_empty_list(&accel_state->bo_free);
87    make_empty_list(&accel_state->bo_wait);
88    make_empty_list(&accel_state->bo_reserved);
89}
90
91void radeon_vbo_free_lists(ScrnInfoPtr pScrn)
92{
93    RADEONInfoPtr info = RADEONPTR(pScrn);
94    struct radeon_accel_state *accel_state = info->accel_state;
95    struct radeon_dma_bo *dma_bo, *temp;
96
97    foreach_s(dma_bo, temp, &accel_state->bo_free) {
98	remove_from_list(dma_bo);
99	radeon_bo_unref(dma_bo->bo);
100	xfree(dma_bo);
101    }
102
103    foreach_s(dma_bo, temp, &accel_state->bo_wait) {
104	remove_from_list(dma_bo);
105	radeon_bo_unref(dma_bo->bo);
106	xfree(dma_bo);
107    }
108
109    foreach_s(dma_bo, temp, &accel_state->bo_reserved) {
110	remove_from_list(dma_bo);
111	radeon_bo_unref(dma_bo->bo);
112	xfree(dma_bo);
113    }
114}
115
116void radeon_vbo_flush_bos(ScrnInfoPtr pScrn)
117{
118    RADEONInfoPtr info = RADEONPTR(pScrn);
119    struct radeon_accel_state *accel_state = info->accel_state;
120    struct radeon_dma_bo *dma_bo, *temp;
121    const int expire_at = ++accel_state->bo_free.expire_counter + DMA_BO_FREE_TIME;
122    const int time = accel_state->bo_free.expire_counter;
123
124    foreach_s(dma_bo, temp, &accel_state->bo_wait) {
125	if (dma_bo->expire_counter == time) {
126	    ErrorF("leaking dma buffer\n");
127	    while ((dma_bo->bo = radeon_bo_unref(dma_bo->bo))) {}
128	    remove_from_list(dma_bo);
129	    xfree(dma_bo);
130	    continue;
131	}
132
133	if (!radeon_bo_is_idle(dma_bo->bo))
134	    continue;
135
136	remove_from_list(dma_bo);
137	dma_bo->expire_counter = expire_at;
138	insert_at_tail(&accel_state->bo_free, dma_bo);
139    }
140
141    /* move reserved to wait list */
142    foreach_s(dma_bo, temp, &accel_state->bo_reserved) {
143	remove_from_list(dma_bo);
144	dma_bo->expire_counter = expire_at;
145	insert_at_tail(&accel_state->bo_wait, dma_bo);
146    }
147
148    /* free bos that have been unused */
149    foreach_s(dma_bo, temp, &accel_state->bo_free) {
150	if (dma_bo->expire_counter != time)
151	    break;
152	/* always keep one hanging around at end */
153	if (at_end(&accel_state->bo_free, dma_bo)) {
154	    dma_bo->expire_counter = time + DMA_BO_FREE_TIME;
155	    break;
156	}
157
158	remove_from_list(dma_bo);
159	radeon_bo_unref(dma_bo->bo);
160	xfree(dma_bo);
161    }
162}
163
164static struct radeon_bo *radeon_vbo_get_bo(ScrnInfoPtr pScrn)
165{
166    RADEONInfoPtr info = RADEONPTR(pScrn);
167    struct radeon_accel_state *accel_state = info->accel_state;
168    struct radeon_dma_bo *dma_bo = NULL;
169    struct radeon_bo *bo;
170
171    if (is_empty_list(&accel_state->bo_free)) {
172	dma_bo = xcalloc(1, sizeof(struct radeon_dma_bo));
173	if (!dma_bo)
174	    return NULL;
175
176again_alloc:
177	dma_bo->bo = radeon_bo_open(info->bufmgr, 0, VBO_SIZE,
178				    0, RADEON_GEM_DOMAIN_GTT, 0);
179
180	if (!dma_bo->bo) {
181	    ErrorF("failure to allocate DMA BO\n");
182	    return NULL;
183	}
184	insert_at_head(&accel_state->bo_reserved, dma_bo);
185    } else {
186	dma_bo = last_elem(&accel_state->bo_free);
187	remove_from_list(dma_bo);
188	insert_at_head(&accel_state->bo_reserved, dma_bo);
189    }
190
191    /* need a space check */
192    if (radeon_cs_space_check_with_bo(info->cs,
193				      first_elem(&accel_state->bo_reserved)->bo,
194				      RADEON_GEM_DOMAIN_GTT, 0))
195	fprintf(stderr,"failed to revalidated\n");
196
197    if (is_empty_list(&accel_state->bo_reserved)) {
198	goto again_alloc;
199    }
200
201    bo = first_elem(&accel_state->bo_reserved)->bo;
202    radeon_bo_ref(bo);
203    return bo;
204}
205
206#endif
207