static void surf_winsys_to_drm(struct radeon_surface *surf_drm, const struct pipe_resource *tex, unsigned flags, unsigned bpe, enum radeon_surf_mode mode, const struct radeon_surf *surf_ws) { int i; memset(surf_drm, 0, sizeof(*surf_drm)); surf_drm->npix_x = tex->width0; surf_drm->npix_y = tex->height0; surf_drm->npix_z = tex->depth0; surf_drm->blk_w = util_format_get_blockwidth(tex->format); surf_drm->blk_h = util_format_get_blockheight(tex->format); surf_drm->blk_d = 1; surf_drm->array_size = 1; surf_drm->last_level = tex->last_level; surf_drm->bpe = bpe; surf_drm->nsamples = tex->nr_samples ? tex->nr_samples : 1; surf_drm->flags = flags; surf_drm->flags = RADEON_SURF_CLR(surf_drm->flags, TYPE); surf_drm->flags = RADEON_SURF_CLR(surf_drm->flags, MODE); surf_drm->flags |= RADEON_SURF_SET(mode, MODE) | RADEON_SURF_HAS_SBUFFER_MIPTREE | RADEON_SURF_HAS_TILE_MODE_INDEX; switch (tex->target) { case PIPE_TEXTURE_1D: surf_drm->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D, TYPE); break; case PIPE_TEXTURE_RECT: case PIPE_TEXTURE_2D: surf_drm->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE); break; case PIPE_TEXTURE_3D: surf_drm->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_3D, TYPE); break; case PIPE_TEXTURE_1D_ARRAY: surf_drm->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D_ARRAY, TYPE); surf_drm->array_size = tex->array_size; break; case PIPE_TEXTURE_CUBE_ARRAY: /* cube array layout like 2d array */ assert(tex->array_size % 6 == 0); /* fall through */ case PIPE_TEXTURE_2D_ARRAY: surf_drm->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D_ARRAY, TYPE); surf_drm->array_size = tex->array_size; break; case PIPE_TEXTURE_CUBE: surf_drm->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_CUBEMAP, TYPE); break; case PIPE_BUFFER: default: assert(0); } surf_drm->bo_size = surf_ws->surf_size; surf_drm->bo_alignment = surf_ws->surf_alignment; surf_drm->bankw = surf_ws->u.legacy.bankw; surf_drm->bankh = surf_ws->u.legacy.bankh; surf_drm->mtilea = surf_ws->u.legacy.mtilea; surf_drm->tile_split = surf_ws->u.legacy.tile_split; for (i = 0; i <= surf_drm->last_level; i++) { surf_level_winsys_to_drm(&surf_drm->level[i], &surf_ws->u.legacy.level[i], bpe * surf_drm->nsamples); surf_drm->tiling_index[i] = surf_ws->u.legacy.tiling_index[i]; } if (flags & RADEON_SURF_SBUFFER) { surf_drm->stencil_tile_split = surf_ws->u.legacy.stencil_tile_split; for (i = 0; i <= surf_drm->last_level; i++) { surf_level_winsys_to_drm(&surf_drm->stencil_level[i], &surf_ws->u.legacy.stencil_level[i], surf_drm->nsamples); surf_drm->stencil_tiling_index[i] = surf_ws->u.legacy.stencil_tiling_index[i]; } } }
/* The number of samples can be specified independently of the texture. */ void r600_texture_get_fmask_info(struct r600_common_screen *rscreen, struct r600_texture *rtex, unsigned nr_samples, struct r600_fmask_info *out) { /* FMASK is allocated like an ordinary texture. */ struct radeon_surf fmask = rtex->surface; memset(out, 0, sizeof(*out)); fmask.bo_alignment = 0; fmask.bo_size = 0; fmask.nsamples = 1; fmask.flags |= RADEON_SURF_FMASK; /* Force 2D tiling if it wasn't set. This may occur when creating * FMASK for MSAA resolve on R6xx. On R6xx, the single-sample * destination buffer must have an FMASK too. */ fmask.flags = RADEON_SURF_CLR(fmask.flags, MODE); fmask.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE); if (rscreen->chip_class >= SI) { fmask.flags |= RADEON_SURF_HAS_TILE_MODE_INDEX; } switch (nr_samples) { case 2: case 4: fmask.bpe = 1; if (rscreen->chip_class <= CAYMAN) { fmask.bankh = 4; } break; case 8: fmask.bpe = 4; break; default: R600_ERR("Invalid sample count for FMASK allocation.\n"); return; } /* Overallocate FMASK on R600-R700 to fix colorbuffer corruption. * This can be fixed by writing a separate FMASK allocator specifically * for R600-R700 asics. */ if (rscreen->chip_class <= R700) { fmask.bpe *= 2; } if (rscreen->ws->surface_init(rscreen->ws, &fmask)) { R600_ERR("Got error in surface_init while allocating FMASK.\n"); return; } assert(fmask.level[0].mode == RADEON_SURF_MODE_2D); out->slice_tile_max = (fmask.level[0].nblk_x * fmask.level[0].nblk_y) / 64; if (out->slice_tile_max) out->slice_tile_max -= 1; out->tile_mode_index = fmask.tiling_index[0]; out->pitch = fmask.level[0].nblk_x; out->bank_height = fmask.bankh; out->alignment = MAX2(256, fmask.bo_alignment); out->size = fmask.bo_size; }
/* Calculate appropriate tiling and pitch for a pixmap and allocate a BO that * can hold it. */ struct radeon_bo* radeon_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width, int height, int depth, int usage_hint, int bitsPerPixel, int *new_pitch, struct radeon_surface *new_surface, uint32_t *new_tiling) { RADEONInfoPtr info = RADEONPTR(pScrn); int pitch, base_align; uint32_t size, heighta; int cpp = bitsPerPixel / 8; uint32_t tiling = 0; struct radeon_surface surface; struct radeon_bo *bo; int domain = RADEON_GEM_DOMAIN_VRAM; if (usage_hint) { if (info->allowColorTiling) { if (usage_hint & RADEON_CREATE_PIXMAP_TILING_MACRO) tiling |= RADEON_TILING_MACRO; if (usage_hint & RADEON_CREATE_PIXMAP_TILING_MICRO) tiling |= RADEON_TILING_MICRO; } if (usage_hint & RADEON_CREATE_PIXMAP_DEPTH) tiling |= RADEON_TILING_MACRO | RADEON_TILING_MICRO; #ifdef CREATE_PIXMAP_USAGE_SHARED if ((usage_hint & 0xffff) == CREATE_PIXMAP_USAGE_SHARED) { tiling = 0; domain = RADEON_GEM_DOMAIN_GTT; } #endif } /* Small pixmaps must not be macrotiled on R300, hw cannot sample them * correctly because samplers automatically switch to macrolinear. */ if (info->ChipFamily >= CHIP_FAMILY_R300 && info->ChipFamily <= CHIP_FAMILY_RS740 && (tiling & RADEON_TILING_MACRO) && !RADEONMacroSwitch(width, height, bitsPerPixel, tiling, info->ChipFamily >= CHIP_FAMILY_RV350)) { tiling &= ~RADEON_TILING_MACRO; } heighta = RADEON_ALIGN(height, drmmode_get_height_align(pScrn, tiling)); pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, cpp, tiling)) * cpp; base_align = drmmode_get_base_align(pScrn, cpp, tiling); size = RADEON_ALIGN(heighta * pitch, RADEON_GPU_PAGE_SIZE); memset(&surface, 0, sizeof(struct radeon_surface)); if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) { if (width) { surface.npix_x = width; /* need to align height to 8 for old kernel */ surface.npix_y = RADEON_ALIGN(height, 8); surface.npix_z = 1; surface.blk_w = 1; surface.blk_h = 1; surface.blk_d = 1; surface.array_size = 1; surface.last_level = 0; surface.bpe = cpp; surface.nsamples = 1; if (height < 128) { /* disable 2d tiling for small surface to work around * the fact that ddx align height to 8 pixel for old * obscure reason i can't remember */ tiling &= ~RADEON_TILING_MACRO; } surface.flags = RADEON_SURF_SCANOUT; /* we are requiring a recent enough libdrm version */ surface.flags |= RADEON_SURF_HAS_TILE_MODE_INDEX; surface.flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE); surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR, MODE); if ((tiling & RADEON_TILING_MICRO)) { surface.flags = RADEON_SURF_CLR(surface.flags, MODE); surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE); } if ((tiling & RADEON_TILING_MACRO)) { surface.flags = RADEON_SURF_CLR(surface.flags, MODE); surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE); } if (usage_hint & RADEON_CREATE_PIXMAP_SZBUFFER) { surface.flags |= RADEON_SURF_ZBUFFER; surface.flags |= RADEON_SURF_SBUFFER; } if (radeon_surface_best(info->surf_man, &surface)) { return NULL; } if (radeon_surface_init(info->surf_man, &surface)) { return NULL; } size = surface.bo_size; base_align = surface.bo_alignment; pitch = surface.level[0].pitch_bytes; tiling = 0; switch (surface.level[0].mode) { case RADEON_SURF_MODE_2D: tiling |= RADEON_TILING_MACRO; tiling |= surface.bankw << RADEON_TILING_EG_BANKW_SHIFT; tiling |= surface.bankh << RADEON_TILING_EG_BANKH_SHIFT; tiling |= surface.mtilea << RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT; tiling |= eg_tile_split(surface.tile_split) << RADEON_TILING_EG_TILE_SPLIT_SHIFT; tiling |= eg_tile_split(surface.stencil_tile_split) << RADEON_TILING_EG_STENCIL_TILE_SPLIT_SHIFT; break; case RADEON_SURF_MODE_1D: tiling |= RADEON_TILING_MICRO; break; default: break; } } } bo = radeon_bo_open(info->bufmgr, 0, size, base_align, domain, 0); if (bo && tiling && radeon_bo_set_tiling(bo, tiling, pitch) == 0) *new_tiling = tiling; *new_surface = surface; *new_pitch = pitch; return bo; }