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 40static struct radeon_bo *radeon_vbo_get_bo(ScrnInfoPtr pScrn); 41 42void radeon_vbo_put(ScrnInfoPtr pScrn, struct radeon_vbo_object *vbo) 43{ 44 45 if (vbo->vb_bo) { 46 radeon_bo_unmap(vbo->vb_bo); 47 radeon_bo_unref(vbo->vb_bo); 48 vbo->vb_bo = NULL; 49 vbo->vb_total = 0; 50 } 51 52 vbo->vb_offset = 0; 53} 54 55void radeon_vbo_get(ScrnInfoPtr pScrn, struct radeon_vbo_object *vbo) 56{ 57 int ret; 58 59 vbo->vb_bo = radeon_vbo_get_bo(pScrn); 60 if (vbo->vb_bo) { 61 radeon_bo_ref(vbo->vb_bo); 62 ret = radeon_bo_map(vbo->vb_bo, 1); 63 if (ret) 64 FatalError("Failed to map vb %d\n", ret); 65 } 66 67 vbo->vb_total = VBO_SIZE; 68 vbo->vb_offset = 0; 69 vbo->vb_start_op = vbo->vb_offset; 70} 71 72/* these functions could migrate to libdrm and 73 be shared with the radeon 3D driver */ 74static int radeon_bo_is_idle(struct radeon_bo *bo) 75{ 76 uint32_t domain; 77 int ret = radeon_bo_is_busy(bo, &domain); 78 return ret != -EBUSY; 79} 80 81void radeon_vbo_init_lists(ScrnInfoPtr pScrn) 82{ 83 RADEONInfoPtr info = RADEONPTR(pScrn); 84 struct radeon_accel_state *accel_state = info->accel_state; 85 86 accel_state->use_vbos = TRUE; 87 make_empty_list(&accel_state->bo_free); 88 make_empty_list(&accel_state->bo_wait); 89 make_empty_list(&accel_state->bo_reserved); 90} 91 92void radeon_vbo_free_lists(ScrnInfoPtr pScrn) 93{ 94 RADEONInfoPtr info = RADEONPTR(pScrn); 95 struct radeon_accel_state *accel_state = info->accel_state; 96 struct radeon_dma_bo *dma_bo, *temp; 97 98 foreach_s(dma_bo, temp, &accel_state->bo_free) { 99 remove_from_list(dma_bo); 100 radeon_bo_unref(dma_bo->bo); 101 free(dma_bo); 102 } 103 104 foreach_s(dma_bo, temp, &accel_state->bo_wait) { 105 remove_from_list(dma_bo); 106 radeon_bo_unref(dma_bo->bo); 107 free(dma_bo); 108 } 109 110 foreach_s(dma_bo, temp, &accel_state->bo_reserved) { 111 remove_from_list(dma_bo); 112 radeon_bo_unref(dma_bo->bo); 113 free(dma_bo); 114 } 115} 116 117void radeon_vbo_flush_bos(ScrnInfoPtr pScrn) 118{ 119 RADEONInfoPtr info = RADEONPTR(pScrn); 120 struct radeon_accel_state *accel_state = info->accel_state; 121 struct radeon_dma_bo *dma_bo, *temp; 122 const int expire_at = ++accel_state->bo_free.expire_counter + DMA_BO_FREE_TIME; 123 const int time = accel_state->bo_free.expire_counter; 124 125 foreach_s(dma_bo, temp, &accel_state->bo_wait) { 126 if (dma_bo->expire_counter == time) { 127 ErrorF("leaking dma buffer\n"); 128 while ((dma_bo->bo = radeon_bo_unref(dma_bo->bo))) {} 129 remove_from_list(dma_bo); 130 free(dma_bo); 131 continue; 132 } 133 134 if (!radeon_bo_is_idle(dma_bo->bo)) 135 continue; 136 137 if (dma_bo->bo->ptr) { 138 ErrorF("bo with pointer on wait list!\n"); 139 continue; 140 } 141 142 remove_from_list(dma_bo); 143 dma_bo->expire_counter = expire_at; 144 insert_at_tail(&accel_state->bo_free, dma_bo); 145 } 146 147 /* move reserved to wait list */ 148 foreach_s(dma_bo, temp, &accel_state->bo_reserved) { 149 remove_from_list(dma_bo); 150 dma_bo->expire_counter = expire_at; 151 insert_at_tail(&accel_state->bo_wait, dma_bo); 152 } 153 154 /* free bos that have been unused */ 155 foreach_s(dma_bo, temp, &accel_state->bo_free) { 156 if (dma_bo->expire_counter != time) 157 break; 158 /* always keep one hanging around at end */ 159 if (at_end(&accel_state->bo_free, dma_bo)) { 160 dma_bo->expire_counter = time + DMA_BO_FREE_TIME; 161 break; 162 } 163 164 remove_from_list(dma_bo); 165 radeon_bo_unref(dma_bo->bo); 166 free(dma_bo); 167 } 168} 169 170static struct radeon_bo *radeon_vbo_get_bo(ScrnInfoPtr pScrn) 171{ 172 RADEONInfoPtr info = RADEONPTR(pScrn); 173 struct radeon_accel_state *accel_state = info->accel_state; 174 struct radeon_dma_bo *dma_bo = NULL; 175 struct radeon_bo *bo; 176 177 if (is_empty_list(&accel_state->bo_free)) { 178 dma_bo = calloc(1, sizeof(struct radeon_dma_bo)); 179 if (!dma_bo) 180 return NULL; 181 182again_alloc: 183 dma_bo->bo = radeon_bo_open(info->bufmgr, 0, VBO_SIZE, 184 0, RADEON_GEM_DOMAIN_GTT, 0); 185 186 if (!dma_bo->bo) { 187 ErrorF("failure to allocate DMA BO\n"); 188 free(dma_bo); 189 return NULL; 190 } 191 insert_at_head(&accel_state->bo_reserved, dma_bo); 192 } else { 193 dma_bo = last_elem(&accel_state->bo_free); 194 remove_from_list(dma_bo); 195 insert_at_head(&accel_state->bo_reserved, dma_bo); 196 } 197 198 if (is_empty_list(&accel_state->bo_reserved)) 199 goto again_alloc; 200 201 bo = first_elem(&accel_state->bo_reserved)->bo; 202 203 /* need a space check */ 204 if (radeon_cs_space_check_with_bo(info->cs, 205 bo, 206 RADEON_GEM_DOMAIN_GTT, 0)) 207 ErrorF("failed to revalidate\n"); 208 209 return bo; 210} 211 212