summaryrefslogtreecommitdiff
path: root/radeon
diff options
context:
space:
mode:
authorMichel Dänzer <michel.daenzer@amd.com>2013-01-17 19:03:42 +0100
committerMichel Dänzer <michel@daenzer.net>2013-01-18 20:24:35 +0100
commit303ca37e722e68900cb7eb43ddbef8069b0c711b (patch)
tree0f892f7f7fbfc4d4b467b36c3edc0f9ea5079ba1 /radeon
parent08cb5c1d0245f6bfc1dd4d041eb418bc160c7b05 (diff)
radeon: Fix 1D tiling layout on SI.
Very similar to Evergreen, but slightly different rules for tile / slice alignment. Fortunately, these map quite naturally onto the previous fixes for linear aligned layout on SI. 2D tiling still needs more work here and possibly in the kernel. Signed-off-by: Michel Dänzer <michel.daenzer@amd.com>
Diffstat (limited to 'radeon')
-rw-r--r--radeon/radeon_surface.c111
1 files changed, 88 insertions, 23 deletions
diff --git a/radeon/radeon_surface.c b/radeon/radeon_surface.c
index eb587d24..8e93873f 100644
--- a/radeon/radeon_surface.c
+++ b/radeon/radeon_surface.c
@@ -1000,25 +1000,28 @@ static int eg_surface_best(struct radeon_surface_manager *surf_man,
* Southern Islands family
*/
-static void si_surf_minify_linear_aligned(struct radeon_surface *surf,
- unsigned level,
- uint32_t xalign, uint32_t yalign, uint32_t zalign, uint32_t slice_align,
- unsigned offset)
+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)
{
- 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);
+ 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);
if (level == 0 && surf->last_level > 0) {
- surf->level[level].nblk_x = (next_power_of_two(surf->level[level].npix_x) + surf->blk_w - 1) / surf->blk_w;
- surf->level[level].nblk_y = (next_power_of_two(surf->level[level].npix_y) + surf->blk_h - 1) / surf->blk_h;
- surf->level[level].nblk_z = (next_power_of_two(surf->level[level].npix_z) + surf->blk_d - 1) / surf->blk_d;
+ 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 {
- 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;
+ 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
*/
@@ -1027,17 +1030,16 @@ static void si_surf_minify_linear_aligned(struct radeon_surface *surf,
xalign = MAX2(xalign, slice_align / surf->bpe);
else
/* Small rows evenly distributed across slice */
- xalign = MAX2(xalign, slice_align / surf->bpe / surf->level[level].npix_y);
+ xalign = MAX2(xalign, slice_align / surf->bpe / surflevel->nblk_y);
- 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_z = ALIGN(surflevel->nblk_z, zalign);
- surf->level[level].offset = offset;
- surf->level[level].pitch_bytes = surf->level[level].nblk_x * surf->bpe * surf->nsamples;
- surf->level[level].slice_size = ALIGN(surf->level[level].pitch_bytes * surf->level[level].nblk_y, slice_align);
+ surflevel->offset = offset;
+ surflevel->pitch_bytes = surflevel->nblk_x * surf->bpe * surf->nsamples;
+ surflevel->slice_size = ALIGN(surflevel->pitch_bytes * surflevel->nblk_y, slice_align);
- 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 si_surface_init_linear_aligned(struct radeon_surface_manager *surf_man,
@@ -1059,7 +1061,48 @@ static int si_surface_init_linear_aligned(struct radeon_surface_manager *surf_ma
/* build mipmap tree */
for (i = start_level; i <= surf->last_level; i++) {
surf->level[i].mode = RADEON_SURF_MODE_LINEAR_ALIGNED;
- si_surf_minify_linear_aligned(surf, i, xalign, yalign, zalign, slice_align, offset);
+ 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);
+ }
+ }
+ 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,
+ uint64_t offset, unsigned start_level)
+{
+ uint32_t xalign, yalign, zalign, slice_align;
+ 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) {
+ 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++) {
+ 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)) {
@@ -1069,6 +1112,28 @@ static int si_surface_init_linear_aligned(struct radeon_surface_manager *surf_ma
return 0;
}
+static int si_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 = si_surface_init_1d(surf_man, surf, surf->level, surf->bpe, 0, 0);
+ if (r)
+ return r;
+
+ if (is_depth_stencil) {
+ r = si_surface_init_1d(surf_man, surf, stencil_level, 1,
+ surf->bo_size, 0);
+ surf->stencil_offset = stencil_level[0].offset;
+ }
+ return r;
+}
+
static int si_surface_init(struct radeon_surface_manager *surf_man,
struct radeon_surface *surf)
{
@@ -1115,7 +1180,7 @@ static int si_surface_init(struct radeon_surface_manager *surf_man,
r = si_surface_init_linear_aligned(surf_man, surf, 0, 0);
break;
case RADEON_SURF_MODE_1D:
- r = eg_surface_init_1d_miptrees(surf_man, surf);
+ r = si_surface_init_1d_miptrees(surf_man, surf);
break;
case RADEON_SURF_MODE_2D:
r = eg_surface_init_2d_miptrees(surf_man, surf);