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