* Authors:
* Jérôme Glisse <jglisse@redhat.com>
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdbool.h>
+#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include "drm.h"
+#include "libdrm.h"
#include "xf86drm.h"
#include "radeon_drm.h"
#include "radeon_surface.h"
CHIP_TAHITI,
CHIP_PITCAIRN,
CHIP_VERDE,
+ CHIP_OLAND,
+ CHIP_HAINAN,
+ CHIP_BONAIRE,
+ CHIP_KAVERI,
+ CHIP_KABINI,
+ CHIP_HAWAII,
+ CHIP_MULLINS,
CHIP_LAST,
};
struct radeon_hw_info {
/* apply to r6, eg */
- uint32_t group_bytes;
- uint32_t num_banks;
- uint32_t num_pipes;
+ uint32_t group_bytes;
+ uint32_t num_banks;
+ uint32_t num_pipes;
/* apply to eg */
- uint32_t row_size;
- unsigned allow_2d;
+ uint32_t row_size;
+ unsigned allow_2d;
+ /* apply to si */
+ uint32_t tile_mode_array[32];
+ /* apply to cik */
+ uint32_t macrotile_mode_array[16];
};
struct radeon_surface_manager {
}
static void surf_minify(struct radeon_surface *surf,
- unsigned level,
+ struct radeon_surface_level *surflevel,
+ unsigned bpe, unsigned level,
uint32_t xalign, uint32_t yalign, uint32_t zalign,
unsigned offset)
{
- surf->level[level].npix_x = mip_minify(surf->npix_x, level);
- surf->level[level].npix_y = mip_minify(surf->npix_y, level);
- surf->level[level].npix_z = mip_minify(surf->npix_z, level);
- surf->level[level].nblk_x = (surf->level[level].npix_x + surf->blk_w - 1) / surf->blk_w;
- surf->level[level].nblk_y = (surf->level[level].npix_y + surf->blk_h - 1) / surf->blk_h;
- surf->level[level].nblk_z = (surf->level[level].npix_z + surf->blk_d - 1) / surf->blk_d;
- if (surf->level[level].mode == RADEON_SURF_MODE_2D) {
- if (surf->level[level].nblk_x < xalign || surf->level[level].nblk_y < yalign) {
- surf->level[level].mode = RADEON_SURF_MODE_1D;
+ surflevel->npix_x = mip_minify(surf->npix_x, level);
+ surflevel->npix_y = mip_minify(surf->npix_y, level);
+ surflevel->npix_z = mip_minify(surf->npix_z, level);
+ surflevel->nblk_x = (surflevel->npix_x + surf->blk_w - 1) / surf->blk_w;
+ surflevel->nblk_y = (surflevel->npix_y + surf->blk_h - 1) / surf->blk_h;
+ surflevel->nblk_z = (surflevel->npix_z + surf->blk_d - 1) / surf->blk_d;
+ if (surf->nsamples == 1 && surflevel->mode == RADEON_SURF_MODE_2D &&
+ !(surf->flags & RADEON_SURF_FMASK)) {
+ if (surflevel->nblk_x < xalign || surflevel->nblk_y < yalign) {
+ surflevel->mode = RADEON_SURF_MODE_1D;
return;
}
}
- surf->level[level].nblk_x = ALIGN(surf->level[level].nblk_x, xalign);
- surf->level[level].nblk_y = ALIGN(surf->level[level].nblk_y, yalign);
- surf->level[level].nblk_z = ALIGN(surf->level[level].nblk_z, zalign);
+ surflevel->nblk_x = ALIGN(surflevel->nblk_x, xalign);
+ surflevel->nblk_y = ALIGN(surflevel->nblk_y, yalign);
+ surflevel->nblk_z = ALIGN(surflevel->nblk_z, zalign);
- surf->level[level].offset = offset;
- surf->level[level].pitch_bytes = surf->level[level].nblk_x * surf->bpe;
- surf->level[level].slice_size = surf->level[level].pitch_bytes * surf->level[level].nblk_y;
+ surflevel->offset = offset;
+ surflevel->pitch_bytes = surflevel->nblk_x * bpe * surf->nsamples;
+ surflevel->slice_size = surflevel->pitch_bytes * surflevel->nblk_y;
- surf->bo_size = offset + surf->level[level].slice_size * surf->level[level].nblk_z * surf->array_size;
+ surf->bo_size = offset + surflevel->slice_size * surflevel->nblk_z * surf->array_size;
}
/* ===========================================================================
if (version && version->version_minor >= 14) {
surf_man->hw_info.allow_2d = 1;
}
+ drmFreeVersion(version);
switch ((tiling_config & 0xe) >> 1) {
case 0:
/* build mipmap tree */
for (i = start_level; i <= surf->last_level; i++) {
surf->level[i].mode = RADEON_SURF_MODE_LINEAR;
- surf_minify(surf, i, xalign, yalign, zalign, offset);
+ surf_minify(surf, surf->level+i, surf->bpe, i, xalign, yalign, zalign, offset);
/* level0 and first mipmap need to have alignment */
offset = surf->bo_size;
- if ((i == 0)) {
+ if (i == 0) {
offset = ALIGN(offset, surf->bo_alignment);
}
}
/* build mipmap tree */
for (i = start_level; i <= surf->last_level; i++) {
surf->level[i].mode = RADEON_SURF_MODE_LINEAR_ALIGNED;
- surf_minify(surf, i, xalign, yalign, zalign, offset);
+ surf_minify(surf, surf->level+i, surf->bpe, i, xalign, yalign, zalign, offset);
/* level0 and first mipmap need to have alignment */
offset = surf->bo_size;
- if ((i == 0)) {
+ if (i == 0) {
offset = ALIGN(offset, surf->bo_alignment);
}
}
/* build mipmap tree */
for (i = start_level; i <= surf->last_level; i++) {
surf->level[i].mode = RADEON_SURF_MODE_1D;
- surf_minify(surf, i, xalign, yalign, zalign, offset);
+ surf_minify(surf, surf->level+i, surf->bpe, i, xalign, yalign, zalign, offset);
/* level0 and first mipmap need to have alignment */
offset = surf->bo_size;
- if ((i == 0)) {
+ if (i == 0) {
offset = ALIGN(offset, surf->bo_alignment);
}
}
surf->bo_alignment =
MAX2(surf_man->hw_info.num_pipes *
surf_man->hw_info.num_banks *
- surf->bpe * 64,
+ surf->nsamples * surf->bpe * 64,
xalign * yalign * surf->nsamples * surf->bpe);
}
/* build mipmap tree */
for (i = start_level; i <= surf->last_level; i++) {
surf->level[i].mode = RADEON_SURF_MODE_2D;
- surf_minify(surf, i, xalign, yalign, zalign, offset);
+ surf_minify(surf, surf->level+i, surf->bpe, i, xalign, yalign, zalign, offset);
if (surf->level[i].mode == RADEON_SURF_MODE_1D) {
return r6_surface_init_1d(surf_man, surf, offset, i);
}
/* level0 and first mipmap need to have alignment */
offset = surf->bo_size;
- if ((i == 0)) {
+ if (i == 0) {
offset = ALIGN(offset, surf->bo_alignment);
}
}
unsigned mode;
int r;
+ /* MSAA surfaces support the 2D mode only. */
+ if (surf->nsamples > 1) {
+ surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
+ surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
+ }
+
/* tiling mode */
mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
- /* always enable z & stencil together */
- if (surf->flags & RADEON_SURF_ZBUFFER) {
- surf->flags |= RADEON_SURF_SBUFFER;
- }
- if (surf->flags & RADEON_SURF_SBUFFER) {
- surf->flags |= RADEON_SURF_ZBUFFER;
- }
- if (surf->flags & RADEON_SURF_ZBUFFER) {
+ if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
/* zbuffer only support 1D or 2D tiled surface */
switch (mode) {
case RADEON_SURF_MODE_1D:
/* force 1d on kernel that can't do 2d */
if (!surf_man->hw_info.allow_2d && mode > RADEON_SURF_MODE_1D) {
+ if (surf->nsamples > 1) {
+ fprintf(stderr, "radeon: Cannot use 2D tiling for an MSAA surface (%i).\n", __LINE__);
+ return -EFAULT;
+ }
mode = RADEON_SURF_MODE_1D;
surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
surf->flags |= RADEON_SURF_SET(mode, MODE);
if (version && version->version_minor >= 16) {
surf_man->hw_info.allow_2d = 1;
}
+ drmFreeVersion(version);
switch (tiling_config & 0xf) {
case 0:
}
static void eg_surf_minify(struct radeon_surface *surf,
+ struct radeon_surface_level *surflevel,
+ unsigned bpe,
unsigned level,
unsigned slice_pt,
unsigned mtilew,
{
unsigned mtile_pr, mtile_ps;
- surf->level[level].npix_x = mip_minify(surf->npix_x, level);
- surf->level[level].npix_y = mip_minify(surf->npix_y, level);
- surf->level[level].npix_z = mip_minify(surf->npix_z, level);
- surf->level[level].nblk_x = (surf->level[level].npix_x + surf->blk_w - 1) / surf->blk_w;
- surf->level[level].nblk_y = (surf->level[level].npix_y + surf->blk_h - 1) / surf->blk_h;
- surf->level[level].nblk_z = (surf->level[level].npix_z + surf->blk_d - 1) / surf->blk_d;
- if (surf->level[level].mode == RADEON_SURF_MODE_2D) {
- if (surf->level[level].nblk_x < mtilew || surf->level[level].nblk_y < mtileh) {
- surf->level[level].mode = RADEON_SURF_MODE_1D;
+ surflevel->npix_x = mip_minify(surf->npix_x, level);
+ surflevel->npix_y = mip_minify(surf->npix_y, level);
+ surflevel->npix_z = mip_minify(surf->npix_z, level);
+ surflevel->nblk_x = (surflevel->npix_x + surf->blk_w - 1) / surf->blk_w;
+ surflevel->nblk_y = (surflevel->npix_y + surf->blk_h - 1) / surf->blk_h;
+ surflevel->nblk_z = (surflevel->npix_z + surf->blk_d - 1) / surf->blk_d;
+ if (surf->nsamples == 1 && surflevel->mode == RADEON_SURF_MODE_2D &&
+ !(surf->flags & RADEON_SURF_FMASK)) {
+ if (surflevel->nblk_x < mtilew || surflevel->nblk_y < mtileh) {
+ surflevel->mode = RADEON_SURF_MODE_1D;
return;
}
}
- surf->level[level].nblk_x = ALIGN(surf->level[level].nblk_x, mtilew);
- surf->level[level].nblk_y = ALIGN(surf->level[level].nblk_y, mtileh);
- surf->level[level].nblk_z = ALIGN(surf->level[level].nblk_z, 1);
+ surflevel->nblk_x = ALIGN(surflevel->nblk_x, mtilew);
+ surflevel->nblk_y = ALIGN(surflevel->nblk_y, mtileh);
+ surflevel->nblk_z = ALIGN(surflevel->nblk_z, 1);
/* macro tile per row */
- mtile_pr = surf->level[level].nblk_x / mtilew;
+ mtile_pr = surflevel->nblk_x / mtilew;
/* macro tile per slice */
- mtile_ps = (mtile_pr * surf->level[level].nblk_y) / mtileh;
+ mtile_ps = (mtile_pr * surflevel->nblk_y) / mtileh;
- surf->level[level].offset = offset;
- surf->level[level].pitch_bytes = surf->level[level].nblk_x * surf->bpe * slice_pt;
- surf->level[level].slice_size = mtile_ps * mtileb * slice_pt;
+ surflevel->offset = offset;
+ surflevel->pitch_bytes = surflevel->nblk_x * bpe * slice_pt;
+ surflevel->slice_size = mtile_ps * mtileb * slice_pt;
- surf->bo_size = offset + surf->level[level].slice_size * surf->level[level].nblk_z * surf->array_size;
+ surf->bo_size = offset + surflevel->slice_size * surflevel->nblk_z * surf->array_size;
}
static int eg_surface_init_1d(struct radeon_surface_manager *surf_man,
struct radeon_surface *surf,
+ struct radeon_surface_level *level,
+ unsigned bpe,
uint64_t offset, unsigned start_level)
{
uint32_t xalign, yalign, zalign, tilew;
/* compute alignment */
tilew = 8;
- xalign = surf_man->hw_info.group_bytes / (tilew * surf->bpe * surf->nsamples);
- if (surf->flags & RADEON_SURF_SBUFFER) {
- xalign = surf_man->hw_info.group_bytes / (tilew * surf->nsamples);
- }
+ xalign = surf_man->hw_info.group_bytes / (tilew * bpe * surf->nsamples);
xalign = MAX2(tilew, xalign);
yalign = tilew;
zalign = 1;
if (surf->flags & RADEON_SURF_SCANOUT) {
- xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign);
+ xalign = MAX2((bpe == 1) ? 64 : 32, xalign);
}
+
if (!start_level) {
- surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
+ unsigned alignment = MAX2(256, surf_man->hw_info.group_bytes);
+ surf->bo_alignment = MAX2(surf->bo_alignment, alignment);
+
+ if (offset) {
+ offset = ALIGN(offset, alignment);
+ }
}
/* build mipmap tree */
for (i = start_level; i <= surf->last_level; i++) {
- surf->level[i].mode = RADEON_SURF_MODE_1D;
- surf_minify(surf, i, xalign, yalign, zalign, offset);
+ level[i].mode = RADEON_SURF_MODE_1D;
+ surf_minify(surf, level+i, bpe, i, xalign, yalign, zalign, offset);
/* level0 and first mipmap need to have alignment */
offset = surf->bo_size;
- if ((i == 0)) {
+ if (i == 0) {
offset = ALIGN(offset, surf->bo_alignment);
}
}
-
- if (surf->flags & RADEON_SURF_SBUFFER) {
- surf->stencil_offset = ALIGN(surf->bo_size, surf->bo_alignment);
- surf->bo_size = surf->stencil_offset + surf->bo_size / 4;
- }
-
return 0;
}
static int eg_surface_init_2d(struct radeon_surface_manager *surf_man,
struct radeon_surface *surf,
+ struct radeon_surface_level *level,
+ unsigned bpe, unsigned tile_split,
uint64_t offset, unsigned start_level)
{
unsigned tilew, tileh, tileb;
/* compute tile values */
tilew = 8;
tileh = 8;
- tileb = tilew * tileh * surf->bpe * surf->nsamples;
+ tileb = tilew * tileh * bpe * surf->nsamples;
/* slices per tile */
slice_pt = 1;
- if (tileb > surf->tile_split) {
- slice_pt = tileb / surf->tile_split;
+ if (tileb > tile_split && tile_split) {
+ slice_pt = tileb / tile_split;
}
tileb = tileb / slice_pt;
mtileb = (mtilew / tilew) * (mtileh / tileh) * tileb;
if (!start_level) {
- surf->bo_alignment = MAX2(256, mtileb);
+ unsigned alignment = MAX2(256, mtileb);
+ surf->bo_alignment = MAX2(surf->bo_alignment, alignment);
+
+ if (offset) {
+ offset = ALIGN(offset, alignment);
+ }
}
/* build mipmap tree */
for (i = start_level; i <= surf->last_level; i++) {
- surf->level[i].mode = RADEON_SURF_MODE_2D;
- eg_surf_minify(surf, i, slice_pt, mtilew, mtileh, mtileb, offset);
- if (surf->level[i].mode == RADEON_SURF_MODE_1D) {
- return eg_surface_init_1d(surf_man, surf, offset, i);
+ level[i].mode = RADEON_SURF_MODE_2D;
+ eg_surf_minify(surf, level+i, bpe, i, slice_pt, mtilew, mtileh, mtileb, offset);
+ if (level[i].mode == RADEON_SURF_MODE_1D) {
+ return eg_surface_init_1d(surf_man, surf, level, bpe, offset, i);
}
/* level0 and first mipmap need to have alignment */
offset = surf->bo_size;
- if ((i == 0)) {
+ if (i == 0) {
offset = ALIGN(offset, surf->bo_alignment);
}
}
-
- if (surf->flags & RADEON_SURF_SBUFFER) {
- surf->stencil_offset = ALIGN(surf->bo_size, surf->bo_alignment);
- surf->bo_size = surf->stencil_offset + surf->bo_size / 4;
- }
-
return 0;
}
/* force 1d on kernel that can't do 2d */
if (!surf_man->hw_info.allow_2d && mode > RADEON_SURF_MODE_1D) {
+ if (surf->nsamples > 1) {
+ fprintf(stderr, "radeon: Cannot use 2D tiling for an MSAA surface (%i).\n", __LINE__);
+ return -EFAULT;
+ }
mode = RADEON_SURF_MODE_1D;
surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
surf->flags |= RADEON_SURF_SET(mode, MODE);
return 0;
}
+static int eg_surface_init_1d_miptrees(struct radeon_surface_manager *surf_man,
+ struct radeon_surface *surf)
+{
+ unsigned zs_flags = RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER;
+ int r, is_depth_stencil = (surf->flags & zs_flags) == zs_flags;
+ /* Old libdrm headers didn't have stencil_level in it. This prevents crashes. */
+ struct radeon_surface_level tmp[RADEON_SURF_MAX_LEVEL];
+ struct radeon_surface_level *stencil_level =
+ (surf->flags & RADEON_SURF_HAS_SBUFFER_MIPTREE) ? surf->stencil_level : tmp;
+
+ r = eg_surface_init_1d(surf_man, surf, surf->level, surf->bpe, 0, 0);
+ if (r)
+ return r;
+
+ if (is_depth_stencil) {
+ r = eg_surface_init_1d(surf_man, surf, stencil_level, 1,
+ surf->bo_size, 0);
+ surf->stencil_offset = stencil_level[0].offset;
+ }
+ return r;
+}
+
+static int eg_surface_init_2d_miptrees(struct radeon_surface_manager *surf_man,
+ struct radeon_surface *surf)
+{
+ unsigned zs_flags = RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER;
+ int r, is_depth_stencil = (surf->flags & zs_flags) == zs_flags;
+ /* Old libdrm headers didn't have stencil_level in it. This prevents crashes. */
+ struct radeon_surface_level tmp[RADEON_SURF_MAX_LEVEL];
+ struct radeon_surface_level *stencil_level =
+ (surf->flags & RADEON_SURF_HAS_SBUFFER_MIPTREE) ? surf->stencil_level : tmp;
+
+ r = eg_surface_init_2d(surf_man, surf, surf->level, surf->bpe,
+ surf->tile_split, 0, 0);
+ if (r)
+ return r;
+
+ if (is_depth_stencil) {
+ r = eg_surface_init_2d(surf_man, surf, stencil_level, 1,
+ surf->stencil_tile_split, surf->bo_size, 0);
+ surf->stencil_offset = stencil_level[0].offset;
+ }
+ return r;
+}
+
static int eg_surface_init(struct radeon_surface_manager *surf_man,
struct radeon_surface *surf)
{
unsigned mode;
int r;
+ /* MSAA surfaces support the 2D mode only. */
+ if (surf->nsamples > 1) {
+ surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
+ surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
+ }
+
/* tiling mode */
mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
- /* for some reason eg need to have room for stencil right after depth */
- if (surf->flags & RADEON_SURF_ZBUFFER) {
- surf->flags |= RADEON_SURF_SBUFFER;
- }
- if (surf->flags & RADEON_SURF_SBUFFER) {
- surf->flags |= RADEON_SURF_ZBUFFER;
- }
- if (surf->flags & RADEON_SURF_ZBUFFER) {
+ if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
/* zbuffer only support 1D or 2D tiled surface */
switch (mode) {
case RADEON_SURF_MODE_1D:
}
surf->stencil_offset = 0;
- surf->stencil_tile_split = 0;
+ surf->bo_alignment = 0;
/* check tiling mode */
switch (mode) {
r = r6_surface_init_linear_aligned(surf_man, surf, 0, 0);
break;
case RADEON_SURF_MODE_1D:
- r = eg_surface_init_1d(surf_man, surf, 0, 0);
+ r = eg_surface_init_1d_miptrees(surf_man, surf);
break;
case RADEON_SURF_MODE_2D:
- r = eg_surface_init_2d(surf_man, surf, 0, 0);
+ r = eg_surface_init_2d_miptrees(surf_man, surf);
break;
default:
return -EINVAL;
/* tiling mode */
mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
- /* for some reason eg need to have room for stencil right after depth */
- if (surf->flags & RADEON_SURF_ZBUFFER) {
- surf->flags |= RADEON_SURF_SBUFFER;
- }
-
/* set some default value to avoid sanity check choking on them */
surf->tile_split = 1024;
surf->bankw = 1;
return 0;
}
- /* set tile split to row size, optimize latter for multi-sample surface
- * tile split >= 256 for render buffer surface. Also depth surface want
- * smaller value for optimal performances.
- */
- surf->tile_split = surf_man->hw_info.row_size;
- surf->stencil_tile_split = surf_man->hw_info.row_size / 2;
+ /* Tweak TILE_SPLIT for performance here. */
+ if (surf->nsamples > 1) {
+ if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
+ switch (surf->nsamples) {
+ case 2:
+ surf->tile_split = 128;
+ break;
+ case 4:
+ surf->tile_split = 128;
+ break;
+ case 8:
+ surf->tile_split = 256;
+ break;
+ case 16: /* cayman only */
+ surf->tile_split = 512;
+ break;
+ default:
+ fprintf(stderr, "radeon: Wrong number of samples %i (%i)\n",
+ surf->nsamples, __LINE__);
+ return -EINVAL;
+ }
+ surf->stencil_tile_split = 64;
+ } else {
+ /* tile split must be >= 256 for colorbuffer surfaces */
+ surf->tile_split = MAX2(surf->nsamples * surf->bpe * 64, 256);
+ if (surf->tile_split > 4096)
+ surf->tile_split = 4096;
+ }
+ } else {
+ /* set tile split to row size */
+ surf->tile_split = surf_man->hw_info.row_size;
+ surf->stencil_tile_split = surf_man->hw_info.row_size / 2;
+ }
/* bankw or bankh greater than 1 increase alignment requirement, not
* sure if it's worth using smaller bankw & bankh to stick with 2D
* fmask buffer has different optimal value figure them out once we
* use it.
*/
- if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
+ if (surf->flags & RADEON_SURF_SBUFFER) {
/* assume 1 bytes for stencil, we optimize for stencil as stencil
* and depth shares surface values
*/
/* ===========================================================================
- * public API
+ * Southern Islands family
*/
-struct radeon_surface_manager *radeon_surface_manager_new(int fd)
+#define SI__GB_TILE_MODE__PIPE_CONFIG(x) (((x) >> 6) & 0x1f)
+#define SI__PIPE_CONFIG__ADDR_SURF_P2 0
+#define SI__PIPE_CONFIG__ADDR_SURF_P4_8x16 4
+#define SI__PIPE_CONFIG__ADDR_SURF_P4_16x16 5
+#define SI__PIPE_CONFIG__ADDR_SURF_P4_16x32 6
+#define SI__PIPE_CONFIG__ADDR_SURF_P4_32x32 7
+#define SI__PIPE_CONFIG__ADDR_SURF_P8_16x16_8x16 8
+#define SI__PIPE_CONFIG__ADDR_SURF_P8_16x32_8x16 9
+#define SI__PIPE_CONFIG__ADDR_SURF_P8_32x32_8x16 10
+#define SI__PIPE_CONFIG__ADDR_SURF_P8_16x32_16x16 11
+#define SI__PIPE_CONFIG__ADDR_SURF_P8_32x32_16x16 12
+#define SI__PIPE_CONFIG__ADDR_SURF_P8_32x32_16x32 13
+#define SI__PIPE_CONFIG__ADDR_SURF_P8_32x64_32x32 14
+#define SI__GB_TILE_MODE__TILE_SPLIT(x) (((x) >> 11) & 0x7)
+#define SI__TILE_SPLIT__64B 0
+#define SI__TILE_SPLIT__128B 1
+#define SI__TILE_SPLIT__256B 2
+#define SI__TILE_SPLIT__512B 3
+#define SI__TILE_SPLIT__1024B 4
+#define SI__TILE_SPLIT__2048B 5
+#define SI__TILE_SPLIT__4096B 6
+#define SI__GB_TILE_MODE__BANK_WIDTH(x) (((x) >> 14) & 0x3)
+#define SI__BANK_WIDTH__1 0
+#define SI__BANK_WIDTH__2 1
+#define SI__BANK_WIDTH__4 2
+#define SI__BANK_WIDTH__8 3
+#define SI__GB_TILE_MODE__BANK_HEIGHT(x) (((x) >> 16) & 0x3)
+#define SI__BANK_HEIGHT__1 0
+#define SI__BANK_HEIGHT__2 1
+#define SI__BANK_HEIGHT__4 2
+#define SI__BANK_HEIGHT__8 3
+#define SI__GB_TILE_MODE__MACRO_TILE_ASPECT(x) (((x) >> 18) & 0x3)
+#define SI__MACRO_TILE_ASPECT__1 0
+#define SI__MACRO_TILE_ASPECT__2 1
+#define SI__MACRO_TILE_ASPECT__4 2
+#define SI__MACRO_TILE_ASPECT__8 3
+#define SI__GB_TILE_MODE__NUM_BANKS(x) (((x) >> 20) & 0x3)
+#define SI__NUM_BANKS__2_BANK 0
+#define SI__NUM_BANKS__4_BANK 1
+#define SI__NUM_BANKS__8_BANK 2
+#define SI__NUM_BANKS__16_BANK 3
+
+
+static void si_gb_tile_mode(uint32_t gb_tile_mode,
+ unsigned *num_pipes,
+ unsigned *num_banks,
+ uint32_t *macro_tile_aspect,
+ uint32_t *bank_w,
+ uint32_t *bank_h,
+ uint32_t *tile_split)
{
- struct radeon_surface_manager *surf_man;
+ if (num_pipes) {
+ switch (SI__GB_TILE_MODE__PIPE_CONFIG(gb_tile_mode)) {
+ case SI__PIPE_CONFIG__ADDR_SURF_P2:
+ default:
+ *num_pipes = 2;
+ break;
+ case SI__PIPE_CONFIG__ADDR_SURF_P4_8x16:
+ case SI__PIPE_CONFIG__ADDR_SURF_P4_16x16:
+ case SI__PIPE_CONFIG__ADDR_SURF_P4_16x32:
+ case SI__PIPE_CONFIG__ADDR_SURF_P4_32x32:
+ *num_pipes = 4;
+ break;
+ case SI__PIPE_CONFIG__ADDR_SURF_P8_16x16_8x16:
+ case SI__PIPE_CONFIG__ADDR_SURF_P8_16x32_8x16:
+ case SI__PIPE_CONFIG__ADDR_SURF_P8_32x32_8x16:
+ case SI__PIPE_CONFIG__ADDR_SURF_P8_16x32_16x16:
+ case SI__PIPE_CONFIG__ADDR_SURF_P8_32x32_16x16:
+ case SI__PIPE_CONFIG__ADDR_SURF_P8_32x32_16x32:
+ case SI__PIPE_CONFIG__ADDR_SURF_P8_32x64_32x32:
+ *num_pipes = 8;
+ break;
+ }
+ }
+ if (num_banks) {
+ switch (SI__GB_TILE_MODE__NUM_BANKS(gb_tile_mode)) {
+ default:
+ case SI__NUM_BANKS__2_BANK:
+ *num_banks = 2;
+ break;
+ case SI__NUM_BANKS__4_BANK:
+ *num_banks = 4;
+ break;
+ case SI__NUM_BANKS__8_BANK:
+ *num_banks = 8;
+ break;
+ case SI__NUM_BANKS__16_BANK:
+ *num_banks = 16;
+ break;
+ }
+ }
+ if (macro_tile_aspect) {
+ switch (SI__GB_TILE_MODE__MACRO_TILE_ASPECT(gb_tile_mode)) {
+ default:
+ case SI__MACRO_TILE_ASPECT__1:
+ *macro_tile_aspect = 1;
+ break;
+ case SI__MACRO_TILE_ASPECT__2:
+ *macro_tile_aspect = 2;
+ break;
+ case SI__MACRO_TILE_ASPECT__4:
+ *macro_tile_aspect = 4;
+ break;
+ case SI__MACRO_TILE_ASPECT__8:
+ *macro_tile_aspect = 8;
+ break;
+ }
+ }
+ if (bank_w) {
+ switch (SI__GB_TILE_MODE__BANK_WIDTH(gb_tile_mode)) {
+ default:
+ case SI__BANK_WIDTH__1:
+ *bank_w = 1;
+ break;
+ case SI__BANK_WIDTH__2:
+ *bank_w = 2;
+ break;
+ case SI__BANK_WIDTH__4:
+ *bank_w = 4;
+ break;
+ case SI__BANK_WIDTH__8:
+ *bank_w = 8;
+ break;
+ }
+ }
+ if (bank_h) {
+ switch (SI__GB_TILE_MODE__BANK_HEIGHT(gb_tile_mode)) {
+ default:
+ case SI__BANK_HEIGHT__1:
+ *bank_h = 1;
+ break;
+ case SI__BANK_HEIGHT__2:
+ *bank_h = 2;
+ break;
+ case SI__BANK_HEIGHT__4:
+ *bank_h = 4;
+ break;
+ case SI__BANK_HEIGHT__8:
+ *bank_h = 8;
+ break;
+ }
+ }
+ if (tile_split) {
+ switch (SI__GB_TILE_MODE__TILE_SPLIT(gb_tile_mode)) {
+ default:
+ case SI__TILE_SPLIT__64B:
+ *tile_split = 64;
+ break;
+ case SI__TILE_SPLIT__128B:
+ *tile_split = 128;
+ break;
+ case SI__TILE_SPLIT__256B:
+ *tile_split = 256;
+ break;
+ case SI__TILE_SPLIT__512B:
+ *tile_split = 512;
+ break;
+ case SI__TILE_SPLIT__1024B:
+ *tile_split = 1024;
+ break;
+ case SI__TILE_SPLIT__2048B:
+ *tile_split = 2048;
+ break;
+ case SI__TILE_SPLIT__4096B:
+ *tile_split = 4096;
+ break;
+ }
+ }
+}
- surf_man = calloc(1, sizeof(struct radeon_surface_manager));
- if (surf_man == NULL) {
- return NULL;
+static int si_init_hw_info(struct radeon_surface_manager *surf_man)
+{
+ uint32_t tiling_config;
+ drmVersionPtr version;
+ int r;
+
+ r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG,
+ &tiling_config);
+ if (r) {
+ return r;
}
- surf_man->fd = fd;
- if (radeon_get_value(fd, RADEON_INFO_DEVICE_ID, &surf_man->device_id)) {
- goto out_err;
+
+ surf_man->hw_info.allow_2d = 0;
+ version = drmGetVersion(surf_man->fd);
+ if (version && version->version_minor >= 33) {
+ if (!radeon_get_value(surf_man->fd, RADEON_INFO_SI_TILE_MODE_ARRAY, surf_man->hw_info.tile_mode_array)) {
+ surf_man->hw_info.allow_2d = 1;
+ }
}
- if (radeon_get_family(surf_man)) {
- goto out_err;
+ drmFreeVersion(version);
+
+ switch (tiling_config & 0xf) {
+ case 0:
+ surf_man->hw_info.num_pipes = 1;
+ break;
+ case 1:
+ surf_man->hw_info.num_pipes = 2;
+ break;
+ case 2:
+ surf_man->hw_info.num_pipes = 4;
+ break;
+ case 3:
+ surf_man->hw_info.num_pipes = 8;
+ break;
+ default:
+ surf_man->hw_info.num_pipes = 8;
+ surf_man->hw_info.allow_2d = 0;
+ break;
}
- if (surf_man->family <= CHIP_RV740) {
- if (r6_init_hw_info(surf_man)) {
- goto out_err;
+ switch ((tiling_config & 0xf0) >> 4) {
+ case 0:
+ surf_man->hw_info.num_banks = 4;
+ break;
+ case 1:
+ surf_man->hw_info.num_banks = 8;
+ break;
+ case 2:
+ surf_man->hw_info.num_banks = 16;
+ break;
+ default:
+ surf_man->hw_info.num_banks = 8;
+ surf_man->hw_info.allow_2d = 0;
+ break;
+ }
+
+ switch ((tiling_config & 0xf00) >> 8) {
+ case 0:
+ surf_man->hw_info.group_bytes = 256;
+ break;
+ case 1:
+ surf_man->hw_info.group_bytes = 512;
+ break;
+ default:
+ surf_man->hw_info.group_bytes = 256;
+ surf_man->hw_info.allow_2d = 0;
+ break;
+ }
+
+ switch ((tiling_config & 0xf000) >> 12) {
+ case 0:
+ surf_man->hw_info.row_size = 1024;
+ break;
+ case 1:
+ surf_man->hw_info.row_size = 2048;
+ break;
+ case 2:
+ surf_man->hw_info.row_size = 4096;
+ break;
+ default:
+ surf_man->hw_info.row_size = 4096;
+ surf_man->hw_info.allow_2d = 0;
+ break;
+ }
+ return 0;
+}
+
+static int si_surface_sanity(struct radeon_surface_manager *surf_man,
+ struct radeon_surface *surf,
+ unsigned mode, unsigned *tile_mode, unsigned *stencil_tile_mode)
+{
+ uint32_t gb_tile_mode;
+
+ /* check surface dimension */
+ if (surf->npix_x > 16384 || surf->npix_y > 16384 || surf->npix_z > 16384) {
+ return -EINVAL;
+ }
+
+ /* check mipmap last_level */
+ if (surf->last_level > 15) {
+ return -EINVAL;
+ }
+
+ /* force 1d on kernel that can't do 2d */
+ if (mode > RADEON_SURF_MODE_1D &&
+ (!surf_man->hw_info.allow_2d || !(surf->flags & RADEON_SURF_HAS_TILE_MODE_INDEX))) {
+ if (surf->nsamples > 1) {
+ fprintf(stderr, "radeon: Cannot use 1D tiling for an MSAA surface (%i).\n", __LINE__);
+ return -EFAULT;
}
- surf_man->surface_init = &r6_surface_init;
- surf_man->surface_best = &r6_surface_best;
- } else {
- if (eg_init_hw_info(surf_man)) {
- goto out_err;
+ mode = RADEON_SURF_MODE_1D;
+ surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
+ surf->flags |= RADEON_SURF_SET(mode, MODE);
+ }
+
+ if (surf->nsamples > 1 && mode != RADEON_SURF_MODE_2D) {
+ return -EINVAL;
+ }
+
+ if (!surf->tile_split) {
+ /* default value */
+ surf->mtilea = 1;
+ surf->bankw = 1;
+ surf->bankh = 1;
+ surf->tile_split = 64;
+ surf->stencil_tile_split = 64;
+ }
+
+ switch (mode) {
+ case RADEON_SURF_MODE_2D:
+ if (surf->flags & RADEON_SURF_SBUFFER) {
+ switch (surf->nsamples) {
+ case 1:
+ *stencil_tile_mode = SI_TILE_MODE_DEPTH_STENCIL_2D;
+ break;
+ case 2:
+ *stencil_tile_mode = SI_TILE_MODE_DEPTH_STENCIL_2D_2AA;
+ break;
+ case 4:
+ *stencil_tile_mode = SI_TILE_MODE_DEPTH_STENCIL_2D_4AA;
+ break;
+ case 8:
+ *stencil_tile_mode = SI_TILE_MODE_DEPTH_STENCIL_2D_8AA;
+ break;
+ default:
+ return -EINVAL;
+ }
+ /* retrieve tiling mode value */
+ gb_tile_mode = surf_man->hw_info.tile_mode_array[*stencil_tile_mode];
+ si_gb_tile_mode(gb_tile_mode, NULL, NULL, NULL, NULL, NULL, &surf->stencil_tile_split);
}
- surf_man->surface_init = &eg_surface_init;
- surf_man->surface_best = &eg_surface_best;
+ if (surf->flags & RADEON_SURF_ZBUFFER) {
+ switch (surf->nsamples) {
+ case 1:
+ *tile_mode = SI_TILE_MODE_DEPTH_STENCIL_2D;
+ break;
+ case 2:
+ *tile_mode = SI_TILE_MODE_DEPTH_STENCIL_2D_2AA;
+ break;
+ case 4:
+ *tile_mode = SI_TILE_MODE_DEPTH_STENCIL_2D_4AA;
+ break;
+ case 8:
+ *tile_mode = SI_TILE_MODE_DEPTH_STENCIL_2D_8AA;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else if (surf->flags & RADEON_SURF_SCANOUT) {
+ switch (surf->bpe) {
+ case 2:
+ *tile_mode = SI_TILE_MODE_COLOR_2D_SCANOUT_16BPP;
+ break;
+ case 4:
+ *tile_mode = SI_TILE_MODE_COLOR_2D_SCANOUT_32BPP;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ switch (surf->bpe) {
+ case 1:
+ *tile_mode = SI_TILE_MODE_COLOR_2D_8BPP;
+ break;
+ case 2:
+ *tile_mode = SI_TILE_MODE_COLOR_2D_16BPP;
+ break;
+ case 4:
+ *tile_mode = SI_TILE_MODE_COLOR_2D_32BPP;
+ break;
+ case 8:
+ case 16:
+ *tile_mode = SI_TILE_MODE_COLOR_2D_64BPP;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ /* retrieve tiling mode value */
+ gb_tile_mode = surf_man->hw_info.tile_mode_array[*tile_mode];
+ si_gb_tile_mode(gb_tile_mode, NULL, NULL, &surf->mtilea, &surf->bankw, &surf->bankh, &surf->tile_split);
+ break;
+ case RADEON_SURF_MODE_1D:
+ if (surf->flags & RADEON_SURF_SBUFFER) {
+ *stencil_tile_mode = SI_TILE_MODE_DEPTH_STENCIL_1D;
+ }
+ if (surf->flags & RADEON_SURF_ZBUFFER) {
+ *tile_mode = SI_TILE_MODE_DEPTH_STENCIL_1D;
+ } else if (surf->flags & RADEON_SURF_SCANOUT) {
+ *tile_mode = SI_TILE_MODE_COLOR_1D_SCANOUT;
+ } else {
+ *tile_mode = SI_TILE_MODE_COLOR_1D;
+ }
+ break;
+ case RADEON_SURF_MODE_LINEAR_ALIGNED:
+ default:
+ *tile_mode = SI_TILE_MODE_COLOR_LINEAR_ALIGNED;
+ }
+
+ return 0;
+}
+
+static void si_surf_minify(struct radeon_surface *surf,
+ struct radeon_surface_level *surflevel,
+ unsigned bpe, unsigned level,
+ uint32_t xalign, uint32_t yalign, uint32_t zalign,
+ uint32_t slice_align, unsigned offset)
+{
+ if (level == 0) {
+ surflevel->npix_x = surf->npix_x;
+ } else {
+ surflevel->npix_x = mip_minify(next_power_of_two(surf->npix_x), level);
+ }
+ surflevel->npix_y = mip_minify(surf->npix_y, level);
+ surflevel->npix_z = mip_minify(surf->npix_z, level);
+
+ if (level == 0 && surf->last_level > 0) {
+ surflevel->nblk_x = (next_power_of_two(surflevel->npix_x) + surf->blk_w - 1) / surf->blk_w;
+ surflevel->nblk_y = (next_power_of_two(surflevel->npix_y) + surf->blk_h - 1) / surf->blk_h;
+ surflevel->nblk_z = (next_power_of_two(surflevel->npix_z) + surf->blk_d - 1) / surf->blk_d;
+ } else {
+ surflevel->nblk_x = (surflevel->npix_x + surf->blk_w - 1) / surf->blk_w;
+ surflevel->nblk_y = (surflevel->npix_y + surf->blk_h - 1) / surf->blk_h;
+ surflevel->nblk_z = (surflevel->npix_z + surf->blk_d - 1) / surf->blk_d;
+ }
+
+ surflevel->nblk_y = ALIGN(surflevel->nblk_y, yalign);
+
+ /* XXX: Texture sampling uses unexpectedly large pitches in some cases,
+ * these are just guesses for the rules behind those
+ */
+ if (level == 0 && surf->last_level == 0)
+ /* Non-mipmap pitch padded to slice alignment */
+ /* Using just bpe here breaks stencil blitting; surf->bpe works. */
+ xalign = MAX2(xalign, slice_align / surf->bpe);
+ else if (surflevel->mode == RADEON_SURF_MODE_LINEAR_ALIGNED)
+ /* Small rows evenly distributed across slice */
+ xalign = MAX2(xalign, slice_align / bpe / surflevel->nblk_y);
+
+ surflevel->nblk_x = ALIGN(surflevel->nblk_x, xalign);
+ surflevel->nblk_z = ALIGN(surflevel->nblk_z, zalign);
+
+ surflevel->offset = offset;
+ surflevel->pitch_bytes = surflevel->nblk_x * bpe * surf->nsamples;
+ surflevel->slice_size = ALIGN(surflevel->pitch_bytes * surflevel->nblk_y, slice_align);
+
+ surf->bo_size = offset + surflevel->slice_size * surflevel->nblk_z * surf->array_size;
+}
+
+static void si_surf_minify_2d(struct radeon_surface *surf,
+ struct radeon_surface_level *surflevel,
+ unsigned bpe, unsigned level, unsigned slice_pt,
+ uint32_t xalign, uint32_t yalign, uint32_t zalign,
+ unsigned mtileb, unsigned offset)
+{
+ unsigned mtile_pr, mtile_ps;
+
+ if (level == 0) {
+ surflevel->npix_x = surf->npix_x;
+ } else {
+ surflevel->npix_x = mip_minify(next_power_of_two(surf->npix_x), level);
+ }
+ surflevel->npix_y = mip_minify(surf->npix_y, level);
+ surflevel->npix_z = mip_minify(surf->npix_z, level);
+
+ if (level == 0 && surf->last_level > 0) {
+ surflevel->nblk_x = (next_power_of_two(surflevel->npix_x) + surf->blk_w - 1) / surf->blk_w;
+ surflevel->nblk_y = (next_power_of_two(surflevel->npix_y) + surf->blk_h - 1) / surf->blk_h;
+ surflevel->nblk_z = (next_power_of_two(surflevel->npix_z) + surf->blk_d - 1) / surf->blk_d;
+ } else {
+ surflevel->nblk_x = (surflevel->npix_x + surf->blk_w - 1) / surf->blk_w;
+ surflevel->nblk_y = (surflevel->npix_y + surf->blk_h - 1) / surf->blk_h;
+ surflevel->nblk_z = (surflevel->npix_z + surf->blk_d - 1) / surf->blk_d;
+ }
+
+ if (surf->nsamples == 1 && surflevel->mode == RADEON_SURF_MODE_2D &&
+ !(surf->flags & RADEON_SURF_FMASK)) {
+ if (surflevel->nblk_x < xalign || surflevel->nblk_y < yalign) {
+ surflevel->mode = RADEON_SURF_MODE_1D;
+ return;
+ }
+ }
+ surflevel->nblk_x = ALIGN(surflevel->nblk_x, xalign);
+ surflevel->nblk_y = ALIGN(surflevel->nblk_y, yalign);
+ surflevel->nblk_z = ALIGN(surflevel->nblk_z, zalign);
+
+ /* macro tile per row */
+ mtile_pr = surflevel->nblk_x / xalign;
+ /* macro tile per slice */
+ mtile_ps = (mtile_pr * surflevel->nblk_y) / yalign;
+ surflevel->offset = offset;
+ surflevel->pitch_bytes = surflevel->nblk_x * bpe * slice_pt;
+ surflevel->slice_size = mtile_ps * mtileb * slice_pt;
+
+ surf->bo_size = offset + surflevel->slice_size * surflevel->nblk_z * surf->array_size;
+}
+
+static int si_surface_init_linear_aligned(struct radeon_surface_manager *surf_man,
+ struct radeon_surface *surf,
+ unsigned tile_mode,
+ uint64_t offset, unsigned start_level)
+{
+ uint32_t xalign, yalign, zalign, slice_align;
+ unsigned i;
+
+ /* compute alignment */
+ if (!start_level) {
+ surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
+ }
+ xalign = MAX2(8, 64 / surf->bpe);
+ yalign = 1;
+ zalign = 1;
+ slice_align = MAX2(64 * surf->bpe, surf_man->hw_info.group_bytes);
+
+ /* build mipmap tree */
+ for (i = start_level; i <= surf->last_level; i++) {
+ surf->level[i].mode = RADEON_SURF_MODE_LINEAR_ALIGNED;
+ si_surf_minify(surf, surf->level+i, surf->bpe, i, xalign, yalign, zalign, slice_align, offset);
+ /* level0 and first mipmap need to have alignment */
+ offset = surf->bo_size;
+ if (i == 0) {
+ offset = ALIGN(offset, surf->bo_alignment);
+ }
+ if (surf->flags & RADEON_SURF_HAS_TILE_MODE_INDEX) {
+ surf->tiling_index[i] = tile_mode;
+ }
+ }
+ return 0;
+}
+
+static int si_surface_init_1d(struct radeon_surface_manager *surf_man,
+ struct radeon_surface *surf,
+ struct radeon_surface_level *level,
+ unsigned bpe, unsigned tile_mode,
+ uint64_t offset, unsigned start_level)
+{
+ uint32_t xalign, yalign, zalign, slice_align;
+ unsigned alignment = MAX2(256, surf_man->hw_info.group_bytes);
+ unsigned i;
+
+ /* compute alignment */
+ xalign = 8;
+ yalign = 8;
+ zalign = 1;
+ slice_align = surf_man->hw_info.group_bytes;
+ if (surf->flags & RADEON_SURF_SCANOUT) {
+ xalign = MAX2((bpe == 1) ? 64 : 32, xalign);
+ }
+
+ if (start_level <= 1) {
+ surf->bo_alignment = MAX2(surf->bo_alignment, alignment);
+
+ if (offset) {
+ offset = ALIGN(offset, alignment);
+ }
+ }
+
+ /* build mipmap tree */
+ for (i = start_level; i <= surf->last_level; i++) {
+ level[i].mode = RADEON_SURF_MODE_1D;
+ si_surf_minify(surf, level+i, bpe, i, xalign, yalign, zalign, slice_align, offset);
+ /* level0 and first mipmap need to have alignment */
+ offset = surf->bo_size;
+ if (i == 0) {
+ offset = ALIGN(offset, alignment);
+ }
+ if (surf->flags & RADEON_SURF_HAS_TILE_MODE_INDEX) {
+ if (surf->level == level) {
+ surf->tiling_index[i] = tile_mode;
+ /* it's ok because stencil is done after */
+ surf->stencil_tiling_index[i] = tile_mode;
+ } else {
+ surf->stencil_tiling_index[i] = tile_mode;
+ }
+ }
+ }
+ return 0;
+}
+
+static int si_surface_init_1d_miptrees(struct radeon_surface_manager *surf_man,
+ struct radeon_surface *surf,
+ unsigned tile_mode, unsigned stencil_tile_mode)
+{
+ int r;
+
+ r = si_surface_init_1d(surf_man, surf, surf->level, surf->bpe, tile_mode, 0, 0);
+ if (r) {
+ return r;
+ }
+
+ if (surf->flags & RADEON_SURF_SBUFFER) {
+ r = si_surface_init_1d(surf_man, surf, surf->stencil_level, 1, stencil_tile_mode, surf->bo_size, 0);
+ surf->stencil_offset = surf->stencil_level[0].offset;
+ }
+ return r;
+}
+
+static int si_surface_init_2d(struct radeon_surface_manager *surf_man,
+ struct radeon_surface *surf,
+ struct radeon_surface_level *level,
+ unsigned bpe, unsigned tile_mode,
+ unsigned num_pipes, unsigned num_banks,
+ unsigned tile_split,
+ uint64_t offset,
+ unsigned start_level)
+{
+ uint64_t aligned_offset = offset;
+ unsigned tilew, tileh, tileb;
+ unsigned mtilew, mtileh, mtileb;
+ unsigned slice_pt;
+ unsigned i;
+
+ /* compute tile values */
+ tilew = 8;
+ tileh = 8;
+ tileb = tilew * tileh * bpe * surf->nsamples;
+ /* slices per tile */
+ slice_pt = 1;
+ if (tileb > tile_split && tile_split) {
+ slice_pt = tileb / tile_split;
+ }
+ tileb = tileb / slice_pt;
+
+ /* macro tile width & height */
+ mtilew = (tilew * surf->bankw * num_pipes) * surf->mtilea;
+ mtileh = (tileh * surf->bankh * num_banks) / surf->mtilea;
+
+ /* macro tile bytes */
+ mtileb = (mtilew / tilew) * (mtileh / tileh) * tileb;
+
+ if (start_level <= 1) {
+ unsigned alignment = MAX2(256, mtileb);
+ surf->bo_alignment = MAX2(surf->bo_alignment, alignment);
+
+ if (aligned_offset) {
+ aligned_offset = ALIGN(aligned_offset, alignment);
+ }
+ }
+
+ /* build mipmap tree */
+ for (i = start_level; i <= surf->last_level; i++) {
+ level[i].mode = RADEON_SURF_MODE_2D;
+ si_surf_minify_2d(surf, level+i, bpe, i, slice_pt, mtilew, mtileh, 1, mtileb, aligned_offset);
+ if (level[i].mode == RADEON_SURF_MODE_1D) {
+ switch (tile_mode) {
+ case SI_TILE_MODE_COLOR_2D_8BPP:
+ case SI_TILE_MODE_COLOR_2D_16BPP:
+ case SI_TILE_MODE_COLOR_2D_32BPP:
+ case SI_TILE_MODE_COLOR_2D_64BPP:
+ tile_mode = SI_TILE_MODE_COLOR_1D;
+ break;
+ case SI_TILE_MODE_COLOR_2D_SCANOUT_16BPP:
+ case SI_TILE_MODE_COLOR_2D_SCANOUT_32BPP:
+ tile_mode = SI_TILE_MODE_COLOR_1D_SCANOUT;
+ break;
+ case SI_TILE_MODE_DEPTH_STENCIL_2D:
+ tile_mode = SI_TILE_MODE_DEPTH_STENCIL_1D;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return si_surface_init_1d(surf_man, surf, level, bpe, tile_mode, offset, i);
+ }
+ /* level0 and first mipmap need to have alignment */
+ aligned_offset = offset = surf->bo_size;
+ if (i == 0) {
+ aligned_offset = ALIGN(aligned_offset, surf->bo_alignment);
+ }
+ if (surf->flags & RADEON_SURF_HAS_TILE_MODE_INDEX) {
+ if (surf->level == level) {
+ surf->tiling_index[i] = tile_mode;
+ /* it's ok because stencil is done after */
+ surf->stencil_tiling_index[i] = tile_mode;
+ } else {
+ surf->stencil_tiling_index[i] = tile_mode;
+ }
+ }
+ }
+ return 0;
+}
+
+static int si_surface_init_2d_miptrees(struct radeon_surface_manager *surf_man,
+ struct radeon_surface *surf,
+ unsigned tile_mode, unsigned stencil_tile_mode)
+{
+ unsigned num_pipes, num_banks;
+ uint32_t gb_tile_mode;
+ int r;
+
+ /* retrieve tiling mode value */
+ gb_tile_mode = surf_man->hw_info.tile_mode_array[tile_mode];
+ si_gb_tile_mode(gb_tile_mode, &num_pipes, &num_banks, NULL, NULL, NULL, NULL);
+
+ r = si_surface_init_2d(surf_man, surf, surf->level, surf->bpe, tile_mode, num_pipes, num_banks, surf->tile_split, 0, 0);
+ if (r) {
+ return r;
+ }
+
+ if (surf->flags & RADEON_SURF_SBUFFER) {
+ r = si_surface_init_2d(surf_man, surf, surf->stencil_level, 1, stencil_tile_mode, num_pipes, num_banks, surf->stencil_tile_split, surf->bo_size, 0);
+ surf->stencil_offset = surf->stencil_level[0].offset;
+ }
+ return r;
+}
+
+static int si_surface_init(struct radeon_surface_manager *surf_man,
+ struct radeon_surface *surf)
+{
+ unsigned mode, tile_mode, stencil_tile_mode;
+ int r;
+
+ /* MSAA surfaces support the 2D mode only. */
+ if (surf->nsamples > 1) {
+ surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
+ surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
+ }
+
+ /* tiling mode */
+ mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
+
+ if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
+ /* zbuffer only support 1D or 2D tiled surface */
+ switch (mode) {
+ case RADEON_SURF_MODE_1D:
+ case RADEON_SURF_MODE_2D:
+ break;
+ default:
+ mode = RADEON_SURF_MODE_1D;
+ surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
+ surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
+ break;
+ }
+ }
+
+ r = si_surface_sanity(surf_man, surf, mode, &tile_mode, &stencil_tile_mode);
+ if (r) {
+ return r;
+ }
+
+ surf->stencil_offset = 0;
+ surf->bo_alignment = 0;
+
+ /* check tiling mode */
+ switch (mode) {
+ case RADEON_SURF_MODE_LINEAR:
+ r = r6_surface_init_linear(surf_man, surf, 0, 0);
+ break;
+ case RADEON_SURF_MODE_LINEAR_ALIGNED:
+ r = si_surface_init_linear_aligned(surf_man, surf, tile_mode, 0, 0);
+ break;
+ case RADEON_SURF_MODE_1D:
+ r = si_surface_init_1d_miptrees(surf_man, surf, tile_mode, stencil_tile_mode);
+ break;
+ case RADEON_SURF_MODE_2D:
+ r = si_surface_init_2d_miptrees(surf_man, surf, tile_mode, stencil_tile_mode);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return r;
+}
+
+/*
+ * depending on surface
+ */
+static int si_surface_best(struct radeon_surface_manager *surf_man,
+ struct radeon_surface *surf)
+{
+ unsigned mode, tile_mode, stencil_tile_mode;
+
+ /* tiling mode */
+ mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
+
+ if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER) &&
+ !(surf->flags & RADEON_SURF_HAS_TILE_MODE_INDEX)) {
+ /* depth/stencil force 1d tiling for old mesa */
+ surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
+ surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
+ }
+
+ return si_surface_sanity(surf_man, surf, mode, &tile_mode, &stencil_tile_mode);
+}
+
+
+/* ===========================================================================
+ * Sea Islands family
+ */
+#define CIK__GB_TILE_MODE__PIPE_CONFIG(x) (((x) >> 6) & 0x1f)
+#define CIK__PIPE_CONFIG__ADDR_SURF_P2 0
+#define CIK__PIPE_CONFIG__ADDR_SURF_P4_8x16 4
+#define CIK__PIPE_CONFIG__ADDR_SURF_P4_16x16 5
+#define CIK__PIPE_CONFIG__ADDR_SURF_P4_16x32 6
+#define CIK__PIPE_CONFIG__ADDR_SURF_P4_32x32 7
+#define CIK__PIPE_CONFIG__ADDR_SURF_P8_16x16_8x16 8
+#define CIK__PIPE_CONFIG__ADDR_SURF_P8_16x32_8x16 9
+#define CIK__PIPE_CONFIG__ADDR_SURF_P8_32x32_8x16 10
+#define CIK__PIPE_CONFIG__ADDR_SURF_P8_16x32_16x16 11
+#define CIK__PIPE_CONFIG__ADDR_SURF_P8_32x32_16x16 12
+#define CIK__PIPE_CONFIG__ADDR_SURF_P8_32x32_16x32 13
+#define CIK__PIPE_CONFIG__ADDR_SURF_P8_32x64_32x32 14
+#define CIK__PIPE_CONFIG__ADDR_SURF_P16_32X32_8X16 16
+#define CIK__PIPE_CONFIG__ADDR_SURF_P16_32X32_16X16 17
+#define CIK__GB_TILE_MODE__TILE_SPLIT(x) (((x) >> 11) & 0x7)
+#define CIK__TILE_SPLIT__64B 0
+#define CIK__TILE_SPLIT__128B 1
+#define CIK__TILE_SPLIT__256B 2
+#define CIK__TILE_SPLIT__512B 3
+#define CIK__TILE_SPLIT__1024B 4
+#define CIK__TILE_SPLIT__2048B 5
+#define CIK__TILE_SPLIT__4096B 6
+#define CIK__GB_TILE_MODE__SAMPLE_SPLIT(x) (((x) >> 25) & 0x3)
+#define CIK__SAMPLE_SPLIT__1 0
+#define CIK__SAMPLE_SPLIT__2 1
+#define CIK__SAMPLE_SPLIT__4 2
+#define CIK__SAMPLE_SPLIT__8 3
+#define CIK__GB_MACROTILE_MODE__BANK_WIDTH(x) ((x) & 0x3)
+#define CIK__BANK_WIDTH__1 0
+#define CIK__BANK_WIDTH__2 1
+#define CIK__BANK_WIDTH__4 2
+#define CIK__BANK_WIDTH__8 3
+#define CIK__GB_MACROTILE_MODE__BANK_HEIGHT(x) (((x) >> 2) & 0x3)
+#define CIK__BANK_HEIGHT__1 0
+#define CIK__BANK_HEIGHT__2 1
+#define CIK__BANK_HEIGHT__4 2
+#define CIK__BANK_HEIGHT__8 3
+#define CIK__GB_MACROTILE_MODE__MACRO_TILE_ASPECT(x) (((x) >> 4) & 0x3)
+#define CIK__MACRO_TILE_ASPECT__1 0
+#define CIK__MACRO_TILE_ASPECT__2 1
+#define CIK__MACRO_TILE_ASPECT__4 2
+#define CIK__MACRO_TILE_ASPECT__8 3
+#define CIK__GB_MACROTILE_MODE__NUM_BANKS(x) (((x) >> 6) & 0x3)
+#define CIK__NUM_BANKS__2_BANK 0
+#define CIK__NUM_BANKS__4_BANK 1
+#define CIK__NUM_BANKS__8_BANK 2
+#define CIK__NUM_BANKS__16_BANK 3
+
+
+static void cik_get_2d_params(struct radeon_surface_manager *surf_man,
+ unsigned bpe, unsigned nsamples, bool is_color,
+ unsigned tile_mode,
+ uint32_t *num_pipes,
+ uint32_t *tile_split_ptr,
+ uint32_t *num_banks,
+ uint32_t *macro_tile_aspect,
+ uint32_t *bank_w,
+ uint32_t *bank_h)
+{
+ uint32_t gb_tile_mode = surf_man->hw_info.tile_mode_array[tile_mode];
+ unsigned tileb_1x, tileb;
+ unsigned gb_macrotile_mode;
+ unsigned macrotile_index;
+ unsigned tile_split, sample_split;
+
+ if (num_pipes) {
+ switch (CIK__GB_TILE_MODE__PIPE_CONFIG(gb_tile_mode)) {
+ case CIK__PIPE_CONFIG__ADDR_SURF_P2:
+ default:
+ *num_pipes = 2;
+ break;
+ case CIK__PIPE_CONFIG__ADDR_SURF_P4_8x16:
+ case CIK__PIPE_CONFIG__ADDR_SURF_P4_16x16:
+ case CIK__PIPE_CONFIG__ADDR_SURF_P4_16x32:
+ case CIK__PIPE_CONFIG__ADDR_SURF_P4_32x32:
+ *num_pipes = 4;
+ break;
+ case CIK__PIPE_CONFIG__ADDR_SURF_P8_16x16_8x16:
+ case CIK__PIPE_CONFIG__ADDR_SURF_P8_16x32_8x16:
+ case CIK__PIPE_CONFIG__ADDR_SURF_P8_32x32_8x16:
+ case CIK__PIPE_CONFIG__ADDR_SURF_P8_16x32_16x16:
+ case CIK__PIPE_CONFIG__ADDR_SURF_P8_32x32_16x16:
+ case CIK__PIPE_CONFIG__ADDR_SURF_P8_32x32_16x32:
+ case CIK__PIPE_CONFIG__ADDR_SURF_P8_32x64_32x32:
+ *num_pipes = 8;
+ break;
+ case CIK__PIPE_CONFIG__ADDR_SURF_P16_32X32_8X16:
+ case CIK__PIPE_CONFIG__ADDR_SURF_P16_32X32_16X16:
+ *num_pipes = 16;
+ break;
+ }
+ }
+ switch (CIK__GB_TILE_MODE__TILE_SPLIT(gb_tile_mode)) {
+ default:
+ case CIK__TILE_SPLIT__64B:
+ tile_split = 64;
+ break;
+ case CIK__TILE_SPLIT__128B:
+ tile_split = 128;
+ break;
+ case CIK__TILE_SPLIT__256B:
+ tile_split = 256;
+ break;
+ case CIK__TILE_SPLIT__512B:
+ tile_split = 512;
+ break;
+ case CIK__TILE_SPLIT__1024B:
+ tile_split = 1024;
+ break;
+ case CIK__TILE_SPLIT__2048B:
+ tile_split = 2048;
+ break;
+ case CIK__TILE_SPLIT__4096B:
+ tile_split = 4096;
+ break;
+ }
+ switch (CIK__GB_TILE_MODE__SAMPLE_SPLIT(gb_tile_mode)) {
+ default:
+ case CIK__SAMPLE_SPLIT__1:
+ sample_split = 1;
+ break;
+ case CIK__SAMPLE_SPLIT__2:
+ sample_split = 2;
+ break;
+ case CIK__SAMPLE_SPLIT__4:
+ sample_split = 4;
+ break;
+ case CIK__SAMPLE_SPLIT__8:
+ sample_split = 8;
+ break;
+ }
+
+ /* Adjust the tile split. */
+ tileb_1x = 8 * 8 * bpe;
+ if (is_color) {
+ tile_split = MAX2(256, sample_split * tileb_1x);
+ }
+ tile_split = MIN2(surf_man->hw_info.row_size, tile_split);
+
+ /* Determine the macrotile index. */
+ tileb = MIN2(tile_split, nsamples * tileb_1x);
+
+ for (macrotile_index = 0; tileb > 64; macrotile_index++) {
+ tileb >>= 1;
+ }
+ gb_macrotile_mode = surf_man->hw_info.macrotile_mode_array[macrotile_index];
+
+ if (tile_split_ptr) {
+ *tile_split_ptr = tile_split;
+ }
+ if (num_banks) {
+ switch (CIK__GB_MACROTILE_MODE__NUM_BANKS(gb_macrotile_mode)) {
+ default:
+ case CIK__NUM_BANKS__2_BANK:
+ *num_banks = 2;
+ break;
+ case CIK__NUM_BANKS__4_BANK:
+ *num_banks = 4;
+ break;
+ case CIK__NUM_BANKS__8_BANK:
+ *num_banks = 8;
+ break;
+ case CIK__NUM_BANKS__16_BANK:
+ *num_banks = 16;
+ break;
+ }
+ }
+ if (macro_tile_aspect) {
+ switch (CIK__GB_MACROTILE_MODE__MACRO_TILE_ASPECT(gb_macrotile_mode)) {
+ default:
+ case CIK__MACRO_TILE_ASPECT__1:
+ *macro_tile_aspect = 1;
+ break;
+ case CIK__MACRO_TILE_ASPECT__2:
+ *macro_tile_aspect = 2;
+ break;
+ case CIK__MACRO_TILE_ASPECT__4:
+ *macro_tile_aspect = 4;
+ break;
+ case CIK__MACRO_TILE_ASPECT__8:
+ *macro_tile_aspect = 8;
+ break;
+ }
+ }
+ if (bank_w) {
+ switch (CIK__GB_MACROTILE_MODE__BANK_WIDTH(gb_macrotile_mode)) {
+ default:
+ case CIK__BANK_WIDTH__1:
+ *bank_w = 1;
+ break;
+ case CIK__BANK_WIDTH__2:
+ *bank_w = 2;
+ break;
+ case CIK__BANK_WIDTH__4:
+ *bank_w = 4;
+ break;
+ case CIK__BANK_WIDTH__8:
+ *bank_w = 8;
+ break;
+ }
+ }
+ if (bank_h) {
+ switch (CIK__GB_MACROTILE_MODE__BANK_HEIGHT(gb_macrotile_mode)) {
+ default:
+ case CIK__BANK_HEIGHT__1:
+ *bank_h = 1;
+ break;
+ case CIK__BANK_HEIGHT__2:
+ *bank_h = 2;
+ break;
+ case CIK__BANK_HEIGHT__4:
+ *bank_h = 4;
+ break;
+ case CIK__BANK_HEIGHT__8:
+ *bank_h = 8;
+ break;
+ }
+ }
+}
+
+static int cik_init_hw_info(struct radeon_surface_manager *surf_man)
+{
+ uint32_t tiling_config;
+ drmVersionPtr version;
+ int r;
+
+ r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG,
+ &tiling_config);
+ if (r) {
+ return r;
+ }
+
+ surf_man->hw_info.allow_2d = 0;
+ version = drmGetVersion(surf_man->fd);
+ if (version && version->version_minor >= 35) {
+ if (!radeon_get_value(surf_man->fd, RADEON_INFO_SI_TILE_MODE_ARRAY, surf_man->hw_info.tile_mode_array) &&
+ !radeon_get_value(surf_man->fd, RADEON_INFO_CIK_MACROTILE_MODE_ARRAY, surf_man->hw_info.macrotile_mode_array)) {
+ surf_man->hw_info.allow_2d = 1;
+ }
+ }
+ drmFreeVersion(version);
+
+ switch (tiling_config & 0xf) {
+ case 0:
+ surf_man->hw_info.num_pipes = 1;
+ break;
+ case 1:
+ surf_man->hw_info.num_pipes = 2;
+ break;
+ case 2:
+ surf_man->hw_info.num_pipes = 4;
+ break;
+ case 3:
+ surf_man->hw_info.num_pipes = 8;
+ break;
+ default:
+ surf_man->hw_info.num_pipes = 8;
+ surf_man->hw_info.allow_2d = 0;
+ break;
+ }
+
+ switch ((tiling_config & 0xf0) >> 4) {
+ case 0:
+ surf_man->hw_info.num_banks = 4;
+ break;
+ case 1:
+ surf_man->hw_info.num_banks = 8;
+ break;
+ case 2:
+ surf_man->hw_info.num_banks = 16;
+ break;
+ default:
+ surf_man->hw_info.num_banks = 8;
+ surf_man->hw_info.allow_2d = 0;
+ break;
+ }
+
+ switch ((tiling_config & 0xf00) >> 8) {
+ case 0:
+ surf_man->hw_info.group_bytes = 256;
+ break;
+ case 1:
+ surf_man->hw_info.group_bytes = 512;
+ break;
+ default:
+ surf_man->hw_info.group_bytes = 256;
+ surf_man->hw_info.allow_2d = 0;
+ break;
+ }
+
+ switch ((tiling_config & 0xf000) >> 12) {
+ case 0:
+ surf_man->hw_info.row_size = 1024;
+ break;
+ case 1:
+ surf_man->hw_info.row_size = 2048;
+ break;
+ case 2:
+ surf_man->hw_info.row_size = 4096;
+ break;
+ default:
+ surf_man->hw_info.row_size = 4096;
+ surf_man->hw_info.allow_2d = 0;
+ break;
+ }
+ return 0;
+}
+
+static int cik_surface_sanity(struct radeon_surface_manager *surf_man,
+ struct radeon_surface *surf,
+ unsigned mode, unsigned *tile_mode, unsigned *stencil_tile_mode)
+{
+ /* check surface dimension */
+ if (surf->npix_x > 16384 || surf->npix_y > 16384 || surf->npix_z > 16384) {
+ return -EINVAL;
+ }
+
+ /* check mipmap last_level */
+ if (surf->last_level > 15) {
+ return -EINVAL;
+ }
+
+ /* force 1d on kernel that can't do 2d */
+ if (mode > RADEON_SURF_MODE_1D &&
+ (!surf_man->hw_info.allow_2d || !(surf->flags & RADEON_SURF_HAS_TILE_MODE_INDEX))) {
+ if (surf->nsamples > 1) {
+ fprintf(stderr, "radeon: Cannot use 1D tiling for an MSAA surface (%i).\n", __LINE__);
+ return -EFAULT;
+ }
+ mode = RADEON_SURF_MODE_1D;
+ surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
+ surf->flags |= RADEON_SURF_SET(mode, MODE);
+ }
+
+ if (surf->nsamples > 1 && mode != RADEON_SURF_MODE_2D) {
+ return -EINVAL;
+ }
+
+ if (!surf->tile_split) {
+ /* default value */
+ surf->mtilea = 1;
+ surf->bankw = 1;
+ surf->bankh = 1;
+ surf->tile_split = 64;
+ surf->stencil_tile_split = 64;
+ }
+
+ switch (mode) {
+ case RADEON_SURF_MODE_2D: {
+ if (surf->flags & RADEON_SURF_Z_OR_SBUFFER) {
+ switch (surf->nsamples) {
+ case 1:
+ *tile_mode = CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_64;
+ break;
+ case 2:
+ case 4:
+ *tile_mode = CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_128;
+ break;
+ case 8:
+ *tile_mode = CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_256;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (surf->flags & RADEON_SURF_SBUFFER) {
+ *stencil_tile_mode = *tile_mode;
+
+ cik_get_2d_params(surf_man, 1, surf->nsamples, false,
+ *stencil_tile_mode, NULL,
+ &surf->stencil_tile_split,
+ NULL, NULL, NULL, NULL);
+ }
+ } else if (surf->flags & RADEON_SURF_SCANOUT) {
+ *tile_mode = CIK_TILE_MODE_COLOR_2D_SCANOUT;
+ } else {
+ *tile_mode = CIK_TILE_MODE_COLOR_2D;
+ }
+
+ /* retrieve tiling mode values */
+ cik_get_2d_params(surf_man, surf->bpe, surf->nsamples,
+ !(surf->flags & RADEON_SURF_Z_OR_SBUFFER), *tile_mode,
+ NULL, &surf->tile_split, NULL, &surf->mtilea,
+ &surf->bankw, &surf->bankh);
+ break;
+ }
+ case RADEON_SURF_MODE_1D:
+ if (surf->flags & RADEON_SURF_SBUFFER) {
+ *stencil_tile_mode = CIK_TILE_MODE_DEPTH_STENCIL_1D;
+ }
+ if (surf->flags & RADEON_SURF_ZBUFFER) {
+ *tile_mode = CIK_TILE_MODE_DEPTH_STENCIL_1D;
+ } else if (surf->flags & RADEON_SURF_SCANOUT) {
+ *tile_mode = SI_TILE_MODE_COLOR_1D_SCANOUT;
+ } else {
+ *tile_mode = SI_TILE_MODE_COLOR_1D;
+ }
+ break;
+ case RADEON_SURF_MODE_LINEAR_ALIGNED:
+ default:
+ *tile_mode = SI_TILE_MODE_COLOR_LINEAR_ALIGNED;
+ }
+
+ return 0;
+}
+
+static int cik_surface_init_2d(struct radeon_surface_manager *surf_man,
+ struct radeon_surface *surf,
+ struct radeon_surface_level *level,
+ unsigned bpe, unsigned tile_mode,
+ unsigned tile_split,
+ unsigned num_pipes, unsigned num_banks,
+ uint64_t offset,
+ unsigned start_level)
+{
+ uint64_t aligned_offset = offset;
+ unsigned tilew, tileh, tileb_1x, tileb;
+ unsigned mtilew, mtileh, mtileb;
+ unsigned slice_pt;
+ unsigned i;
+
+ /* compute tile values */
+ tilew = 8;
+ tileh = 8;
+ tileb_1x = tilew * tileh * bpe;
+
+ tile_split = MIN2(surf_man->hw_info.row_size, tile_split);
+
+ tileb = surf->nsamples * tileb_1x;
+
+ /* slices per tile */
+ slice_pt = 1;
+ if (tileb > tile_split && tile_split) {
+ slice_pt = tileb / tile_split;
+ tileb = tileb / slice_pt;
+ }
+
+ /* macro tile width & height */
+ mtilew = (tilew * surf->bankw * num_pipes) * surf->mtilea;
+ mtileh = (tileh * surf->bankh * num_banks) / surf->mtilea;
+
+ /* macro tile bytes */
+ mtileb = (mtilew / tilew) * (mtileh / tileh) * tileb;
+
+ if (start_level <= 1) {
+ unsigned alignment = MAX2(256, mtileb);
+ surf->bo_alignment = MAX2(surf->bo_alignment, alignment);
+
+ if (aligned_offset) {
+ aligned_offset = ALIGN(aligned_offset, alignment);
+ }
+ }
+
+ /* build mipmap tree */
+ for (i = start_level; i <= surf->last_level; i++) {
+ level[i].mode = RADEON_SURF_MODE_2D;
+ si_surf_minify_2d(surf, level+i, bpe, i, slice_pt, mtilew, mtileh, 1, mtileb, aligned_offset);
+ if (level[i].mode == RADEON_SURF_MODE_1D) {
+ switch (tile_mode) {
+ case CIK_TILE_MODE_COLOR_2D:
+ tile_mode = SI_TILE_MODE_COLOR_1D;
+ break;
+ case CIK_TILE_MODE_COLOR_2D_SCANOUT:
+ tile_mode = SI_TILE_MODE_COLOR_1D_SCANOUT;
+ break;
+ case CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_64:
+ case CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_128:
+ case CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_256:
+ case CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_512:
+ case CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_ROW_SIZE:
+ tile_mode = CIK_TILE_MODE_DEPTH_STENCIL_1D;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return si_surface_init_1d(surf_man, surf, level, bpe, tile_mode, offset, i);
+ }
+ /* level0 and first mipmap need to have alignment */
+ aligned_offset = offset = surf->bo_size;
+ if (i == 0) {
+ aligned_offset = ALIGN(aligned_offset, surf->bo_alignment);
+ }
+ if (surf->flags & RADEON_SURF_HAS_TILE_MODE_INDEX) {
+ if (surf->level == level) {
+ surf->tiling_index[i] = tile_mode;
+ /* it's ok because stencil is done after */
+ surf->stencil_tiling_index[i] = tile_mode;
+ } else {
+ surf->stencil_tiling_index[i] = tile_mode;
+ }
+ }
+ }
+ return 0;
+}
+
+static int cik_surface_init_2d_miptrees(struct radeon_surface_manager *surf_man,
+ struct radeon_surface *surf,
+ unsigned tile_mode, unsigned stencil_tile_mode)
+{
+ int r;
+ uint32_t num_pipes, num_banks;
+
+ cik_get_2d_params(surf_man, surf->bpe, surf->nsamples,
+ !(surf->flags & RADEON_SURF_Z_OR_SBUFFER), tile_mode,
+ &num_pipes, NULL, &num_banks, NULL, NULL, NULL);
+
+ r = cik_surface_init_2d(surf_man, surf, surf->level, surf->bpe, tile_mode,
+ surf->tile_split, num_pipes, num_banks, 0, 0);
+ if (r) {
+ return r;
+ }
+
+ if (surf->flags & RADEON_SURF_SBUFFER) {
+ r = cik_surface_init_2d(surf_man, surf, surf->stencil_level, 1, stencil_tile_mode,
+ surf->stencil_tile_split, num_pipes, num_banks,
+ surf->bo_size, 0);
+ surf->stencil_offset = surf->stencil_level[0].offset;
+ }
+ return r;
+}
+
+static int cik_surface_init(struct radeon_surface_manager *surf_man,
+ struct radeon_surface *surf)
+{
+ unsigned mode, tile_mode, stencil_tile_mode;
+ int r;
+
+ /* MSAA surfaces support the 2D mode only. */
+ if (surf->nsamples > 1) {
+ surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
+ surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
+ }
+
+ /* tiling mode */
+ mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
+
+ if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
+ /* zbuffer only support 1D or 2D tiled surface */
+ switch (mode) {
+ case RADEON_SURF_MODE_1D:
+ case RADEON_SURF_MODE_2D:
+ break;
+ default:
+ mode = RADEON_SURF_MODE_1D;
+ surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
+ surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
+ break;
+ }
+ }
+
+ r = cik_surface_sanity(surf_man, surf, mode, &tile_mode, &stencil_tile_mode);
+ if (r) {
+ return r;
+ }
+
+ surf->stencil_offset = 0;
+ surf->bo_alignment = 0;
+
+ /* check tiling mode */
+ switch (mode) {
+ case RADEON_SURF_MODE_LINEAR:
+ r = r6_surface_init_linear(surf_man, surf, 0, 0);
+ break;
+ case RADEON_SURF_MODE_LINEAR_ALIGNED:
+ r = si_surface_init_linear_aligned(surf_man, surf, tile_mode, 0, 0);
+ break;
+ case RADEON_SURF_MODE_1D:
+ r = si_surface_init_1d_miptrees(surf_man, surf, tile_mode, stencil_tile_mode);
+ break;
+ case RADEON_SURF_MODE_2D:
+ r = cik_surface_init_2d_miptrees(surf_man, surf, tile_mode, stencil_tile_mode);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return r;
+}
+
+/*
+ * depending on surface
+ */
+static int cik_surface_best(struct radeon_surface_manager *surf_man,
+ struct radeon_surface *surf)
+{
+ unsigned mode, tile_mode, stencil_tile_mode;
+
+ /* tiling mode */
+ mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
+
+ if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER) &&
+ !(surf->flags & RADEON_SURF_HAS_TILE_MODE_INDEX)) {
+ /* depth/stencil force 1d tiling for old mesa */
+ surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
+ surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
+ }
+
+ return cik_surface_sanity(surf_man, surf, mode, &tile_mode, &stencil_tile_mode);
+}
+
+
+/* ===========================================================================
+ * public API
+ */
+drm_public struct radeon_surface_manager *
+radeon_surface_manager_new(int fd)
+{
+ struct radeon_surface_manager *surf_man;
+
+ surf_man = calloc(1, sizeof(struct radeon_surface_manager));
+ if (surf_man == NULL) {
+ return NULL;
+ }
+ surf_man->fd = fd;
+ if (radeon_get_value(fd, RADEON_INFO_DEVICE_ID, &surf_man->device_id)) {
+ goto out_err;
+ }
+ if (radeon_get_family(surf_man)) {
+ goto out_err;
+ }
+
+ if (surf_man->family <= CHIP_RV740) {
+ if (r6_init_hw_info(surf_man)) {
+ goto out_err;
+ }
+ surf_man->surface_init = &r6_surface_init;
+ surf_man->surface_best = &r6_surface_best;
+ } else if (surf_man->family <= CHIP_ARUBA) {
+ if (eg_init_hw_info(surf_man)) {
+ goto out_err;
+ }
+ surf_man->surface_init = &eg_surface_init;
+ surf_man->surface_best = &eg_surface_best;
+ } else if (surf_man->family < CHIP_BONAIRE) {
+ if (si_init_hw_info(surf_man)) {
+ goto out_err;
+ }
+ surf_man->surface_init = &si_surface_init;
+ surf_man->surface_best = &si_surface_best;
+ } else {
+ if (cik_init_hw_info(surf_man)) {
+ goto out_err;
+ }
+ surf_man->surface_init = &cik_surface_init;
+ surf_man->surface_best = &cik_surface_best;
}
return surf_man;
return NULL;
}
-void radeon_surface_manager_free(struct radeon_surface_manager *surf_man)
+drm_public void
+radeon_surface_manager_free(struct radeon_surface_manager *surf_man)
{
free(surf_man);
}
return 0;
}
-int radeon_surface_init(struct radeon_surface_manager *surf_man,
- struct radeon_surface *surf)
+drm_public int
+radeon_surface_init(struct radeon_surface_manager *surf_man,
+ struct radeon_surface *surf)
{
unsigned mode, type;
int r;
return surf_man->surface_init(surf_man, surf);
}
-int radeon_surface_best(struct radeon_surface_manager *surf_man,
- struct radeon_surface *surf)
+drm_public int
+radeon_surface_best(struct radeon_surface_manager *surf_man,
+ struct radeon_surface *surf)
{
unsigned mode, type;
int r;