radeon_bo_helper.c revision de2362d3
1/* 2 * Copyright 2012 Advanced Micro Devices, 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 shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 */ 22 23#ifdef HAVE_CONFIG_H 24# include "config.h" 25#endif 26 27#include "radeon.h" 28 29#ifdef RADEON_PIXMAP_SHARING 30#include "radeon_bo_gem.h" 31#endif 32 33static const unsigned MicroBlockTable[5][3][2] = { 34 /*linear tiled square-tiled */ 35 {{32, 1}, {8, 4}, {0, 0}}, /* 8 bits per pixel */ 36 {{16, 1}, {8, 2}, {4, 4}}, /* 16 bits per pixel */ 37 {{ 8, 1}, {4, 2}, {0, 0}}, /* 32 bits per pixel */ 38 {{ 4, 1}, {0, 0}, {2, 2}}, /* 64 bits per pixel */ 39 {{ 2, 1}, {0, 0}, {0, 0}} /* 128 bits per pixel */ 40}; 41 42/* Return true if macrotiling can be enabled */ 43static Bool RADEONMacroSwitch(int width, int height, int bpp, 44 uint32_t flags, Bool rv350_mode) 45{ 46 unsigned tilew, tileh, microtiled, logbpp; 47 48 logbpp = RADEONLog2(bpp / 8); 49 if (logbpp > 4) 50 return 0; 51 52 microtiled = !!(flags & RADEON_TILING_MICRO); 53 tilew = MicroBlockTable[logbpp][microtiled][0] * 8; 54 tileh = MicroBlockTable[logbpp][microtiled][1] * 8; 55 56 /* See TX_FILTER1_n.MACRO_SWITCH. */ 57 if (rv350_mode) { 58 return width >= tilew && height >= tileh; 59 } else { 60 return width > tilew && height > tileh; 61 } 62} 63 64/* Calculate appropriate tiling and pitch for a pixmap and allocate a BO that 65 * can hold it. 66 */ 67struct radeon_bo* 68radeon_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width, int height, int depth, 69 int usage_hint, int bitsPerPixel, int *new_pitch, 70 struct radeon_surface *new_surface, uint32_t *new_tiling) 71{ 72 RADEONInfoPtr info = RADEONPTR(pScrn); 73 int pitch, base_align; 74 uint32_t size, heighta; 75 int cpp = bitsPerPixel / 8; 76 uint32_t tiling = 0; 77 struct radeon_surface surface; 78 struct radeon_bo *bo; 79 int domain = RADEON_GEM_DOMAIN_VRAM; 80 if (usage_hint) { 81 if (info->allowColorTiling) { 82 if (usage_hint & RADEON_CREATE_PIXMAP_TILING_MACRO) 83 tiling |= RADEON_TILING_MACRO; 84 if (usage_hint & RADEON_CREATE_PIXMAP_TILING_MICRO) 85 tiling |= RADEON_TILING_MICRO; 86 } 87 if (usage_hint & RADEON_CREATE_PIXMAP_DEPTH) 88 tiling |= RADEON_TILING_MACRO | RADEON_TILING_MICRO; 89 90#ifdef CREATE_PIXMAP_USAGE_SHARED 91 if ((usage_hint & 0xffff) == CREATE_PIXMAP_USAGE_SHARED) { 92 tiling = 0; 93 domain = RADEON_GEM_DOMAIN_GTT; 94 } 95#endif 96 } 97 98 /* Small pixmaps must not be macrotiled on R300, hw cannot sample them 99 * correctly because samplers automatically switch to macrolinear. */ 100 if (info->ChipFamily >= CHIP_FAMILY_R300 && 101 info->ChipFamily <= CHIP_FAMILY_RS740 && 102 (tiling & RADEON_TILING_MACRO) && 103 !RADEONMacroSwitch(width, height, bitsPerPixel, tiling, 104 info->ChipFamily >= CHIP_FAMILY_RV350)) { 105 tiling &= ~RADEON_TILING_MACRO; 106 } 107 108 heighta = RADEON_ALIGN(height, drmmode_get_height_align(pScrn, tiling)); 109 pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, cpp, tiling)) * cpp; 110 base_align = drmmode_get_base_align(pScrn, cpp, tiling); 111 size = RADEON_ALIGN(heighta * pitch, RADEON_GPU_PAGE_SIZE); 112 memset(&surface, 0, sizeof(struct radeon_surface)); 113 114 if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) { 115 if (width) { 116 surface.npix_x = width; 117 /* need to align height to 8 for old kernel */ 118 surface.npix_y = RADEON_ALIGN(height, 8); 119 surface.npix_z = 1; 120 surface.blk_w = 1; 121 surface.blk_h = 1; 122 surface.blk_d = 1; 123 surface.array_size = 1; 124 surface.last_level = 0; 125 surface.bpe = cpp; 126 surface.nsamples = 1; 127 if (height < 128) { 128 /* disable 2d tiling for small surface to work around 129 * the fact that ddx align height to 8 pixel for old 130 * obscure reason i can't remember 131 */ 132 tiling &= ~RADEON_TILING_MACRO; 133 } 134 surface.flags = RADEON_SURF_SCANOUT; 135 /* we are requiring a recent enough libdrm version */ 136 surface.flags |= RADEON_SURF_HAS_TILE_MODE_INDEX; 137 surface.flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE); 138 surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR, MODE); 139 if ((tiling & RADEON_TILING_MICRO)) { 140 surface.flags = RADEON_SURF_CLR(surface.flags, MODE); 141 surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE); 142 } 143 if ((tiling & RADEON_TILING_MACRO)) { 144 surface.flags = RADEON_SURF_CLR(surface.flags, MODE); 145 surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE); 146 } 147 if (usage_hint & RADEON_CREATE_PIXMAP_SZBUFFER) { 148 surface.flags |= RADEON_SURF_ZBUFFER; 149 surface.flags |= RADEON_SURF_SBUFFER; 150 } 151 if (radeon_surface_best(info->surf_man, &surface)) { 152 return NULL; 153 } 154 if (radeon_surface_init(info->surf_man, &surface)) { 155 return NULL; 156 } 157 size = surface.bo_size; 158 base_align = surface.bo_alignment; 159 pitch = surface.level[0].pitch_bytes; 160 tiling = 0; 161 switch (surface.level[0].mode) { 162 case RADEON_SURF_MODE_2D: 163 tiling |= RADEON_TILING_MACRO; 164 tiling |= surface.bankw << RADEON_TILING_EG_BANKW_SHIFT; 165 tiling |= surface.bankh << RADEON_TILING_EG_BANKH_SHIFT; 166 tiling |= surface.mtilea << RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT; 167 tiling |= eg_tile_split(surface.tile_split) << RADEON_TILING_EG_TILE_SPLIT_SHIFT; 168 tiling |= eg_tile_split(surface.stencil_tile_split) << RADEON_TILING_EG_STENCIL_TILE_SPLIT_SHIFT; 169 break; 170 case RADEON_SURF_MODE_1D: 171 tiling |= RADEON_TILING_MICRO; 172 break; 173 default: 174 break; 175 } 176 } 177 } 178 179 bo = radeon_bo_open(info->bufmgr, 0, size, base_align, 180 domain, 0); 181 182 if (bo && tiling && radeon_bo_set_tiling(bo, tiling, pitch) == 0) 183 *new_tiling = tiling; 184 185 *new_surface = surface; 186 *new_pitch = pitch; 187 return bo; 188} 189 190#ifdef RADEON_PIXMAP_SHARING 191 192Bool radeon_share_pixmap_backing(struct radeon_bo *bo, void **handle_p) 193{ 194 int handle; 195 196 if (radeon_gem_prime_share_bo(bo, &handle) != 0) 197 return FALSE; 198 199 *handle_p = (void *)(long)handle; 200 return TRUE; 201} 202 203Bool radeon_set_shared_pixmap_backing(PixmapPtr ppix, void *fd_handle, 204 struct radeon_surface *surface) 205{ 206 ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen); 207 RADEONInfoPtr info = RADEONPTR(pScrn); 208 struct radeon_bo *bo; 209 int ihandle = (int)(long)fd_handle; 210 uint32_t size = ppix->devKind * ppix->drawable.height; 211 212 bo = radeon_gem_bo_open_prime(info->bufmgr, ihandle, size); 213 if (!bo) 214 return FALSE; 215 216 memset(surface, 0, sizeof(struct radeon_surface)); 217 218 if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) { 219 220 surface->npix_x = ppix->drawable.width; 221 surface->npix_y = ppix->drawable.height; 222 surface->npix_z = 1; 223 surface->blk_w = 1; 224 surface->blk_h = 1; 225 surface->blk_d = 1; 226 surface->array_size = 1; 227 surface->bpe = ppix->drawable.bitsPerPixel / 8; 228 surface->nsamples = 1; 229 /* we are requiring a recent enough libdrm version */ 230 surface->flags |= RADEON_SURF_HAS_TILE_MODE_INDEX; 231 surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE); 232 surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR, MODE); 233 if (radeon_surface_best(info->surf_man, surface)) { 234 return FALSE; 235 } 236 if (radeon_surface_init(info->surf_man, surface)) { 237 return FALSE; 238 } 239 /* we have to post hack the surface to reflect the actual size 240 of the shared pixmap */ 241 surface->level[0].pitch_bytes = ppix->devKind; 242 surface->level[0].nblk_x = ppix->devKind / surface->bpe; 243 } 244 radeon_set_pixmap_bo(ppix, bo); 245 246 close(ihandle); 247 /* we have a reference from the alloc and one from set pixmap bo, 248 drop one */ 249 radeon_bo_unref(bo); 250 return TRUE; 251} 252 253#endif /* RADEON_PIXMAP_SHARING */ 254