radeon_bo_helper.c revision 0d16fef4
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#include "radeon_glamor.h" 29 30#ifdef RADEON_PIXMAP_SHARING 31#include "radeon_bo_gem.h" 32#endif 33 34static const unsigned MicroBlockTable[5][3][2] = { 35 /*linear tiled square-tiled */ 36 {{32, 1}, {8, 4}, {0, 0}}, /* 8 bits per pixel */ 37 {{16, 1}, {8, 2}, {4, 4}}, /* 16 bits per pixel */ 38 {{ 8, 1}, {4, 2}, {0, 0}}, /* 32 bits per pixel */ 39 {{ 4, 1}, {0, 0}, {2, 2}}, /* 64 bits per pixel */ 40 {{ 2, 1}, {0, 0}, {0, 0}} /* 128 bits per pixel */ 41}; 42 43/* Return true if macrotiling can be enabled */ 44static Bool RADEONMacroSwitch(int width, int height, int bpp, 45 uint32_t flags, Bool rv350_mode) 46{ 47 unsigned tilew, tileh, microtiled, logbpp; 48 49 logbpp = RADEONLog2(bpp / 8); 50 if (logbpp > 4) 51 return 0; 52 53 microtiled = !!(flags & RADEON_TILING_MICRO); 54 tilew = MicroBlockTable[logbpp][microtiled][0] * 8; 55 tileh = MicroBlockTable[logbpp][microtiled][1] * 8; 56 57 /* See TX_FILTER1_n.MACRO_SWITCH. */ 58 if (rv350_mode) { 59 return width >= tilew && height >= tileh; 60 } else { 61 return width > tilew && height > tileh; 62 } 63} 64 65/* Calculate appropriate tiling and pitch for a pixmap and allocate a BO that 66 * can hold it. 67 */ 68struct radeon_bo* 69radeon_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width, int height, int depth, 70 int usage_hint, int bitsPerPixel, int *new_pitch, 71 struct radeon_surface *new_surface, uint32_t *new_tiling) 72{ 73 RADEONInfoPtr info = RADEONPTR(pScrn); 74 int pitch, base_align; 75 uint32_t size, heighta; 76 int cpp = bitsPerPixel / 8; 77 uint32_t tiling = 0, flags = 0; 78 struct radeon_surface surface; 79 struct radeon_bo *bo; 80 int domain = RADEON_GEM_DOMAIN_VRAM; 81 if (usage_hint) { 82 if (info->allowColorTiling) { 83 if (usage_hint & RADEON_CREATE_PIXMAP_TILING_MACRO) 84 tiling |= RADEON_TILING_MACRO; 85 if (usage_hint & RADEON_CREATE_PIXMAP_TILING_MICRO) 86 tiling |= RADEON_TILING_MICRO; 87 } 88 if (usage_hint & RADEON_CREATE_PIXMAP_DEPTH) 89 tiling |= RADEON_TILING_MACRO | RADEON_TILING_MICRO; 90 91 if ((usage_hint == CREATE_PIXMAP_USAGE_BACKING_PIXMAP && 92 info->shadow_primary) 93#ifdef CREATE_PIXMAP_USAGE_SHARED 94 || (usage_hint & 0xffff) == CREATE_PIXMAP_USAGE_SHARED 95#endif 96 ) { 97 tiling = 0; 98 domain = RADEON_GEM_DOMAIN_GTT; 99 } 100 } 101 102 /* Small pixmaps must not be macrotiled on R300, hw cannot sample them 103 * correctly because samplers automatically switch to macrolinear. */ 104 if (info->ChipFamily >= CHIP_FAMILY_R300 && 105 info->ChipFamily <= CHIP_FAMILY_RS740 && 106 (tiling & RADEON_TILING_MACRO) && 107 !RADEONMacroSwitch(width, height, bitsPerPixel, tiling, 108 info->ChipFamily >= CHIP_FAMILY_RV350)) { 109 tiling &= ~RADEON_TILING_MACRO; 110 } 111 112 heighta = RADEON_ALIGN(height, drmmode_get_height_align(pScrn, tiling)); 113 pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, cpp, tiling)) * cpp; 114 base_align = drmmode_get_base_align(pScrn, cpp, tiling); 115 size = RADEON_ALIGN(heighta * pitch, RADEON_GPU_PAGE_SIZE); 116 memset(&surface, 0, sizeof(struct radeon_surface)); 117 118 if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) { 119 if (width) { 120 surface.npix_x = width; 121 /* need to align height to 8 for old kernel */ 122 surface.npix_y = RADEON_ALIGN(height, 8); 123 surface.npix_z = 1; 124 surface.blk_w = 1; 125 surface.blk_h = 1; 126 surface.blk_d = 1; 127 surface.array_size = 1; 128 surface.last_level = 0; 129 surface.bpe = cpp; 130 surface.nsamples = 1; 131 if (height < 128) { 132 /* disable 2d tiling for small surface to work around 133 * the fact that ddx align height to 8 pixel for old 134 * obscure reason i can't remember 135 */ 136 tiling &= ~RADEON_TILING_MACRO; 137 } 138 surface.flags = RADEON_SURF_SCANOUT; 139 /* we are requiring a recent enough libdrm version */ 140 surface.flags |= RADEON_SURF_HAS_TILE_MODE_INDEX; 141 surface.flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE); 142 surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR, MODE); 143 if ((tiling & RADEON_TILING_MICRO)) { 144 surface.flags = RADEON_SURF_CLR(surface.flags, MODE); 145 surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE); 146 } 147 if ((tiling & RADEON_TILING_MACRO)) { 148 surface.flags = RADEON_SURF_CLR(surface.flags, MODE); 149 surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE); 150 } 151 if (usage_hint & RADEON_CREATE_PIXMAP_SZBUFFER) { 152 surface.flags |= RADEON_SURF_ZBUFFER; 153 surface.flags |= RADEON_SURF_SBUFFER; 154 } 155 if (radeon_surface_best(info->surf_man, &surface)) { 156 return NULL; 157 } 158 if (radeon_surface_init(info->surf_man, &surface)) { 159 return NULL; 160 } 161 size = surface.bo_size; 162 base_align = surface.bo_alignment; 163 pitch = surface.level[0].pitch_bytes; 164 tiling = 0; 165 switch (surface.level[0].mode) { 166 case RADEON_SURF_MODE_2D: 167 tiling |= RADEON_TILING_MACRO; 168 tiling |= surface.bankw << RADEON_TILING_EG_BANKW_SHIFT; 169 tiling |= surface.bankh << RADEON_TILING_EG_BANKH_SHIFT; 170 tiling |= surface.mtilea << RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT; 171 if (surface.tile_split) 172 tiling |= eg_tile_split(surface.tile_split) << RADEON_TILING_EG_TILE_SPLIT_SHIFT; 173 tiling |= eg_tile_split(surface.stencil_tile_split) << RADEON_TILING_EG_STENCIL_TILE_SPLIT_SHIFT; 174 break; 175 case RADEON_SURF_MODE_1D: 176 tiling |= RADEON_TILING_MICRO; 177 break; 178 default: 179 break; 180 } 181 } 182 } 183 184 if (tiling) 185 flags |= RADEON_GEM_NO_CPU_ACCESS; 186 187 bo = radeon_bo_open(info->bufmgr, 0, size, base_align, 188 domain, flags); 189 190 if (bo && tiling && radeon_bo_set_tiling(bo, tiling, pitch) == 0) 191 *new_tiling = tiling; 192 193 *new_surface = surface; 194 *new_pitch = pitch; 195 return bo; 196} 197 198/* Get GEM handle for the pixmap */ 199Bool radeon_get_pixmap_handle(PixmapPtr pixmap, uint32_t *handle) 200{ 201 struct radeon_bo *bo = radeon_get_pixmap_bo(pixmap); 202#ifdef USE_GLAMOR 203 ScreenPtr screen = pixmap->drawable.pScreen; 204 RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(screen)); 205#endif 206 207 if (bo) { 208 *handle = bo->handle; 209 return TRUE; 210 } 211 212#ifdef USE_GLAMOR 213 if (info->use_glamor) { 214 struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); 215 CARD16 stride; 216 CARD32 size; 217 int fd, r; 218 219 if (!priv) { 220 priv = calloc(1, sizeof(*priv)); 221 radeon_set_pixmap_private(pixmap, priv); 222 } 223 224 if (priv->handle_valid) { 225 *handle = priv->handle; 226 return TRUE; 227 } 228 229 fd = glamor_fd_from_pixmap(screen, pixmap, &stride, &size); 230 if (fd < 0) 231 return FALSE; 232 233 r = drmPrimeFDToHandle(info->dri2.drm_fd, fd, &priv->handle); 234 close(fd); 235 if (r == 0) { 236 struct drm_radeon_gem_set_tiling args = { .handle = priv->handle }; 237 238 priv->handle_valid = TRUE; 239 *handle = priv->handle; 240 241 if (drmCommandWriteRead(info->dri2.drm_fd, 242 DRM_RADEON_GEM_GET_TILING, &args, 243 sizeof(args)) == 0) 244 priv->tiling_flags = args.tiling_flags; 245 246 return TRUE; 247 } 248 } 249#endif 250 251 return FALSE; 252} 253 254uint32_t radeon_get_pixmap_tiling_flags(PixmapPtr pPix) 255{ 256#ifdef USE_GLAMOR 257 RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(pPix->drawable.pScreen)); 258 259 if (info->use_glamor) { 260 struct radeon_pixmap *priv = radeon_get_pixmap_private(pPix); 261 262 if (!priv || (!priv->bo && !priv->handle_valid)) { 263 uint32_t handle; 264 265 radeon_get_pixmap_handle(pPix, &handle); 266 priv = radeon_get_pixmap_private(pPix); 267 } 268 269 return priv ? priv->tiling_flags : 0; 270 } else 271#endif 272 { 273 struct radeon_exa_pixmap_priv *driver_priv; 274 driver_priv = exaGetPixmapDriverPrivate(pPix); 275 return driver_priv ? driver_priv->tiling_flags : 0; 276 } 277} 278 279#ifdef RADEON_PIXMAP_SHARING 280 281Bool radeon_share_pixmap_backing(struct radeon_bo *bo, void **handle_p) 282{ 283 int handle; 284 285 if (radeon_gem_prime_share_bo(bo, &handle) != 0) 286 return FALSE; 287 288 *handle_p = (void *)(long)handle; 289 return TRUE; 290} 291 292static unsigned eg_tile_split_opp(unsigned tile_split) 293{ 294 switch (tile_split) { 295 case 0: tile_split = 64; break; 296 case 1: tile_split = 128; break; 297 case 2: tile_split = 256; break; 298 case 3: tile_split = 512; break; 299 default: 300 case 4: tile_split = 1024; break; 301 case 5: tile_split = 2048; break; 302 case 6: tile_split = 4096; break; 303 } 304 return tile_split; 305} 306 307Bool radeon_set_shared_pixmap_backing(PixmapPtr ppix, void *fd_handle, 308 struct radeon_surface *surface) 309{ 310 ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen); 311 RADEONInfoPtr info = RADEONPTR(pScrn); 312 struct radeon_bo *bo; 313 int ihandle = (int)(long)fd_handle; 314 uint32_t size = ppix->devKind * ppix->drawable.height; 315 316 bo = radeon_gem_bo_open_prime(info->bufmgr, ihandle, size); 317 if (!bo) 318 return FALSE; 319 320 memset(surface, 0, sizeof(struct radeon_surface)); 321 322 radeon_set_pixmap_bo(ppix, bo); 323 324 if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) { 325 uint32_t tiling_flags; 326 327#ifdef USE_GLAMOR 328 if (info->use_glamor) { 329 tiling_flags = radeon_get_pixmap_private(ppix)->tiling_flags; 330 } else 331#endif 332 { 333 struct radeon_exa_pixmap_priv *driver_priv; 334 335 driver_priv = exaGetPixmapDriverPrivate(ppix); 336 tiling_flags = driver_priv->tiling_flags; 337 } 338 339 surface->npix_x = ppix->drawable.width; 340 surface->npix_y = ppix->drawable.height; 341 surface->npix_z = 1; 342 surface->blk_w = 1; 343 surface->blk_h = 1; 344 surface->blk_d = 1; 345 surface->array_size = 1; 346 surface->bpe = ppix->drawable.bitsPerPixel / 8; 347 surface->nsamples = 1; 348 /* we are requiring a recent enough libdrm version */ 349 surface->flags |= RADEON_SURF_HAS_TILE_MODE_INDEX; 350 surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE); 351 if (tiling_flags & RADEON_TILING_MACRO) 352 surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE); 353 else if (tiling_flags & RADEON_TILING_MICRO) 354 surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE); 355 else 356 surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR_ALIGNED, MODE); 357 surface->bankw = (tiling_flags >> RADEON_TILING_EG_BANKW_SHIFT) & RADEON_TILING_EG_BANKW_MASK; 358 surface->bankh = (tiling_flags >> RADEON_TILING_EG_BANKH_SHIFT) & RADEON_TILING_EG_BANKH_MASK; 359 surface->tile_split = eg_tile_split_opp((tiling_flags >> RADEON_TILING_EG_TILE_SPLIT_SHIFT) & RADEON_TILING_EG_TILE_SPLIT_MASK); 360 surface->stencil_tile_split = (tiling_flags >> RADEON_TILING_EG_STENCIL_TILE_SPLIT_SHIFT) & RADEON_TILING_EG_STENCIL_TILE_SPLIT_MASK; 361 surface->mtilea = (tiling_flags >> RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT) & RADEON_TILING_EG_MACRO_TILE_ASPECT_MASK; 362 if (radeon_surface_best(info->surf_man, surface)) { 363 return FALSE; 364 } 365 if (radeon_surface_init(info->surf_man, surface)) { 366 return FALSE; 367 } 368 /* we have to post hack the surface to reflect the actual size 369 of the shared pixmap */ 370 surface->level[0].pitch_bytes = ppix->devKind; 371 surface->level[0].nblk_x = ppix->devKind / surface->bpe; 372 } 373 374 close(ihandle); 375 /* we have a reference from the alloc and one from set pixmap bo, 376 drop one */ 377 radeon_bo_unref(bo); 378 return TRUE; 379} 380 381#endif /* RADEON_PIXMAP_SHARING */ 382