1ad43ddacSmrg/*
2ad43ddacSmrg * Copyright © 2009 Red Hat, Inc.
3ad43ddacSmrg *
4ad43ddacSmrg * Permission is hereby granted, free of charge, to any person obtaining a
5ad43ddacSmrg * copy of this software and associated documentation files (the "Software"),
6ad43ddacSmrg * to deal in the Software without restriction, including without limitation
7ad43ddacSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8ad43ddacSmrg * and/or sell copies of the Software, and to permit persons to whom the
9ad43ddacSmrg * Software is furnished to do so, subject to the following conditions:
10ad43ddacSmrg *
11ad43ddacSmrg * The above copyright notice and this permission notice (including the next
12ad43ddacSmrg * paragraph) shall be included in all copies or substantial portions of the
13ad43ddacSmrg * Software.
14ad43ddacSmrg *
15ad43ddacSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16ad43ddacSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17ad43ddacSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18ad43ddacSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19ad43ddacSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20ad43ddacSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21ad43ddacSmrg * SOFTWARE.
22ad43ddacSmrg *
23ad43ddacSmrg * Authors:
24ad43ddacSmrg *    Dave Airlie <airlied@redhat.com>
25ad43ddacSmrg *
26ad43ddacSmrg */
27ad43ddacSmrg#ifdef HAVE_CONFIG_H
28ad43ddacSmrg#include "config.h"
29ad43ddacSmrg#endif
30ad43ddacSmrg
31ad43ddacSmrg#include <errno.h>
32ad43ddacSmrg#include "radeon.h"
33ad43ddacSmrg#include "radeon_bo.h"
34ad43ddacSmrg#include "radeon_cs.h"
35ad43ddacSmrg
36ad43ddacSmrg#define VBO_SIZE (16*1024)
37ad43ddacSmrg
38ad43ddacSmrg/* KMS vertex buffer support - for R600 only but could be used on previous gpus */
39ad43ddacSmrg
4043df4709Smrg#ifdef XF86DRM_MODE
4143df4709Smrg
42ad43ddacSmrgstatic struct radeon_bo *radeon_vbo_get_bo(ScrnInfoPtr pScrn);
43ad43ddacSmrg
44921a55d8Smrgvoid radeon_vbo_put(ScrnInfoPtr pScrn, struct radeon_vbo_object *vbo)
45ad43ddacSmrg{
46921a55d8Smrg
47921a55d8Smrg    if (vbo->vb_bo) {
48921a55d8Smrg	radeon_bo_unmap(vbo->vb_bo);
49921a55d8Smrg	radeon_bo_unref(vbo->vb_bo);
50921a55d8Smrg	vbo->vb_bo = NULL;
51921a55d8Smrg	vbo->vb_total = 0;
52ad43ddacSmrg    }
53ad43ddacSmrg
54921a55d8Smrg    vbo->vb_offset = 0;
55ad43ddacSmrg}
56ad43ddacSmrg
57921a55d8Smrgvoid radeon_vbo_get(ScrnInfoPtr pScrn, struct radeon_vbo_object *vbo)
58ad43ddacSmrg{
59921a55d8Smrg    int ret;
60921a55d8Smrg
61921a55d8Smrg    vbo->vb_bo = radeon_vbo_get_bo(pScrn);
62921a55d8Smrg    if (vbo->vb_bo) {
63921a55d8Smrg	radeon_bo_ref(vbo->vb_bo);
64921a55d8Smrg	ret = radeon_bo_map(vbo->vb_bo, 1);
65921a55d8Smrg	if (ret)
66921a55d8Smrg	    FatalError("Failed to map vb %d\n", ret);
67921a55d8Smrg    }
68ad43ddacSmrg
69921a55d8Smrg    vbo->vb_total = VBO_SIZE;
70921a55d8Smrg    vbo->vb_offset = 0;
71921a55d8Smrg    vbo->vb_start_op = vbo->vb_offset;
72ad43ddacSmrg}
73ad43ddacSmrg
74ad43ddacSmrg/* these functions could migrate to libdrm and
75ad43ddacSmrg   be shared with the radeon 3D driver */
76ad43ddacSmrgstatic int radeon_bo_is_idle(struct radeon_bo *bo)
77ad43ddacSmrg{
78ad43ddacSmrg    uint32_t domain;
79ad43ddacSmrg    int ret = radeon_bo_is_busy(bo, &domain);
80ad43ddacSmrg    return ret != -EBUSY;
81ad43ddacSmrg}
82ad43ddacSmrg
83ad43ddacSmrgvoid radeon_vbo_init_lists(ScrnInfoPtr pScrn)
84ad43ddacSmrg{
85ad43ddacSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
86921a55d8Smrg    struct radeon_accel_state *accel_state = info->accel_state;
87ad43ddacSmrg
88ad43ddacSmrg    accel_state->use_vbos = TRUE;
89ad43ddacSmrg    make_empty_list(&accel_state->bo_free);
90ad43ddacSmrg    make_empty_list(&accel_state->bo_wait);
91ad43ddacSmrg    make_empty_list(&accel_state->bo_reserved);
92ad43ddacSmrg}
93ad43ddacSmrg
94ad43ddacSmrgvoid radeon_vbo_free_lists(ScrnInfoPtr pScrn)
95ad43ddacSmrg{
96ad43ddacSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
97921a55d8Smrg    struct radeon_accel_state *accel_state = info->accel_state;
98ad43ddacSmrg    struct radeon_dma_bo *dma_bo, *temp;
99ad43ddacSmrg
100ad43ddacSmrg    foreach_s(dma_bo, temp, &accel_state->bo_free) {
101ad43ddacSmrg	remove_from_list(dma_bo);
102ad43ddacSmrg	radeon_bo_unref(dma_bo->bo);
1032f39173dSmrg	free(dma_bo);
104ad43ddacSmrg    }
105ad43ddacSmrg
106ad43ddacSmrg    foreach_s(dma_bo, temp, &accel_state->bo_wait) {
107ad43ddacSmrg	remove_from_list(dma_bo);
108ad43ddacSmrg	radeon_bo_unref(dma_bo->bo);
1092f39173dSmrg	free(dma_bo);
110ad43ddacSmrg    }
111ad43ddacSmrg
112ad43ddacSmrg    foreach_s(dma_bo, temp, &accel_state->bo_reserved) {
113ad43ddacSmrg	remove_from_list(dma_bo);
114ad43ddacSmrg	radeon_bo_unref(dma_bo->bo);
1152f39173dSmrg	free(dma_bo);
116ad43ddacSmrg    }
117ad43ddacSmrg}
118ad43ddacSmrg
119ad43ddacSmrgvoid radeon_vbo_flush_bos(ScrnInfoPtr pScrn)
120ad43ddacSmrg{
121ad43ddacSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
122921a55d8Smrg    struct radeon_accel_state *accel_state = info->accel_state;
123ad43ddacSmrg    struct radeon_dma_bo *dma_bo, *temp;
124ad43ddacSmrg    const int expire_at = ++accel_state->bo_free.expire_counter + DMA_BO_FREE_TIME;
125ad43ddacSmrg    const int time = accel_state->bo_free.expire_counter;
126ad43ddacSmrg
127ad43ddacSmrg    foreach_s(dma_bo, temp, &accel_state->bo_wait) {
128ad43ddacSmrg	if (dma_bo->expire_counter == time) {
129ad43ddacSmrg	    ErrorF("leaking dma buffer\n");
130ad43ddacSmrg	    while ((dma_bo->bo = radeon_bo_unref(dma_bo->bo))) {}
131ad43ddacSmrg	    remove_from_list(dma_bo);
1322f39173dSmrg	    free(dma_bo);
133ad43ddacSmrg	    continue;
134ad43ddacSmrg	}
135ad43ddacSmrg
136ad43ddacSmrg	if (!radeon_bo_is_idle(dma_bo->bo))
137ad43ddacSmrg	    continue;
138ad43ddacSmrg
139921a55d8Smrg	if (dma_bo->bo->ptr) {
140921a55d8Smrg	    ErrorF("bo with pointer on wait list!\n");
141921a55d8Smrg	    continue;
142921a55d8Smrg	}
143921a55d8Smrg
144ad43ddacSmrg	remove_from_list(dma_bo);
145ad43ddacSmrg	dma_bo->expire_counter = expire_at;
146ad43ddacSmrg	insert_at_tail(&accel_state->bo_free, dma_bo);
147ad43ddacSmrg    }
148ad43ddacSmrg
149ad43ddacSmrg    /* move reserved to wait list */
150ad43ddacSmrg    foreach_s(dma_bo, temp, &accel_state->bo_reserved) {
151ad43ddacSmrg	remove_from_list(dma_bo);
152ad43ddacSmrg	dma_bo->expire_counter = expire_at;
153ad43ddacSmrg	insert_at_tail(&accel_state->bo_wait, dma_bo);
154ad43ddacSmrg    }
155ad43ddacSmrg
156ad43ddacSmrg    /* free bos that have been unused */
157ad43ddacSmrg    foreach_s(dma_bo, temp, &accel_state->bo_free) {
158ad43ddacSmrg	if (dma_bo->expire_counter != time)
159ad43ddacSmrg	    break;
160ad43ddacSmrg	/* always keep one hanging around at end */
161ad43ddacSmrg	if (at_end(&accel_state->bo_free, dma_bo)) {
162ad43ddacSmrg	    dma_bo->expire_counter = time + DMA_BO_FREE_TIME;
163ad43ddacSmrg	    break;
164ad43ddacSmrg	}
165ad43ddacSmrg
166ad43ddacSmrg	remove_from_list(dma_bo);
167ad43ddacSmrg	radeon_bo_unref(dma_bo->bo);
1682f39173dSmrg	free(dma_bo);
169ad43ddacSmrg    }
170ad43ddacSmrg}
171ad43ddacSmrg
172ad43ddacSmrgstatic struct radeon_bo *radeon_vbo_get_bo(ScrnInfoPtr pScrn)
173ad43ddacSmrg{
174ad43ddacSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
175921a55d8Smrg    struct radeon_accel_state *accel_state = info->accel_state;
176ad43ddacSmrg    struct radeon_dma_bo *dma_bo = NULL;
177ad43ddacSmrg    struct radeon_bo *bo;
178ad43ddacSmrg
179ad43ddacSmrg    if (is_empty_list(&accel_state->bo_free)) {
1802f39173dSmrg	dma_bo = calloc(1, sizeof(struct radeon_dma_bo));
181ad43ddacSmrg	if (!dma_bo)
182ad43ddacSmrg	    return NULL;
183ad43ddacSmrg
184ad43ddacSmrgagain_alloc:
185ad43ddacSmrg	dma_bo->bo = radeon_bo_open(info->bufmgr, 0, VBO_SIZE,
186ad43ddacSmrg				    0, RADEON_GEM_DOMAIN_GTT, 0);
187ad43ddacSmrg
188ad43ddacSmrg	if (!dma_bo->bo) {
189ad43ddacSmrg	    ErrorF("failure to allocate DMA BO\n");
190ad43ddacSmrg	    return NULL;
191ad43ddacSmrg	}
192ad43ddacSmrg	insert_at_head(&accel_state->bo_reserved, dma_bo);
193ad43ddacSmrg    } else {
194ad43ddacSmrg	dma_bo = last_elem(&accel_state->bo_free);
195ad43ddacSmrg	remove_from_list(dma_bo);
196ad43ddacSmrg	insert_at_head(&accel_state->bo_reserved, dma_bo);
197ad43ddacSmrg    }
198ad43ddacSmrg
199921a55d8Smrg    if (is_empty_list(&accel_state->bo_reserved))
200921a55d8Smrg	goto again_alloc;
201921a55d8Smrg
202921a55d8Smrg    bo = first_elem(&accel_state->bo_reserved)->bo;
203921a55d8Smrg
204ad43ddacSmrg    /* need a space check */
205ad43ddacSmrg    if (radeon_cs_space_check_with_bo(info->cs,
206921a55d8Smrg				      bo,
207ad43ddacSmrg				      RADEON_GEM_DOMAIN_GTT, 0))
208921a55d8Smrg	ErrorF("failed to revalidate\n");
209ad43ddacSmrg
210ad43ddacSmrg    return bo;
211ad43ddacSmrg}
212ad43ddacSmrg
21343df4709Smrg#endif
214