/* Calculate appropriate pitch for a pixmap and allocate a BO that can hold it. */ struct amdgpu_buffer *amdgpu_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width, int height, int depth, int usage_hint, int bitsPerPixel, int *new_pitch) { AMDGPUInfoPtr info = AMDGPUPTR(pScrn); struct amdgpu_buffer *pixmap_buffer; if (info->gbm) { uint32_t bo_use = GBM_BO_USE_RENDERING; uint32_t gbm_format; switch (depth) { #ifdef GBM_FORMAT_R8 case 8: gbm_format = GBM_FORMAT_R8; break; #endif case 16: gbm_format = GBM_FORMAT_RGB565; break; case 32: gbm_format = GBM_FORMAT_ARGB8888; break; case 24: if (bitsPerPixel == 32) { gbm_format = GBM_FORMAT_XRGB8888; break; } /* fall through */ default: ErrorF("%s: Unsupported depth/bpp %d/%d\n", __func__, depth, bitsPerPixel); return NULL; } pixmap_buffer = (struct amdgpu_buffer *)calloc(1, sizeof(struct amdgpu_buffer)); if (!pixmap_buffer) { return NULL; } pixmap_buffer->ref_count = 1; if ( bitsPerPixel == pScrn->bitsPerPixel) bo_use |= GBM_BO_USE_SCANOUT; #ifdef CREATE_PIXMAP_USAGE_SHARED if (usage_hint == CREATE_PIXMAP_USAGE_SHARED) { /* XXX: Need to tell GBM to disable tiling in this case */ } #endif if (usage_hint & AMDGPU_CREATE_PIXMAP_LINEAR) { bo_use |= GBM_BO_USE_LINEAR; } pixmap_buffer->bo.gbm = gbm_bo_create(info->gbm, width, height, gbm_format, bo_use); if (!pixmap_buffer->bo.gbm) { free(pixmap_buffer); return NULL; } pixmap_buffer->flags |= AMDGPU_BO_FLAGS_GBM; if (new_pitch) *new_pitch = gbm_bo_get_stride(pixmap_buffer->bo.gbm); } else { AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); unsigned cpp = (bitsPerPixel + 7) / 8; unsigned pitch = cpp * AMDGPU_ALIGN(width, drmmode_get_pitch_align(pScrn, cpp)); pixmap_buffer = amdgpu_bo_open(pAMDGPUEnt->pDev, pitch * height, 4096, AMDGPU_GEM_DOMAIN_VRAM); if (new_pitch) *new_pitch = pitch; } return pixmap_buffer; }
/* 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; }