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