diff options
-rw-r--r-- | src/gallium/drivers/radeonsi/r600_blit.c | 16 | ||||
-rw-r--r-- | src/gallium/drivers/radeonsi/r600_resource.h | 1 | ||||
-rw-r--r-- | src/gallium/drivers/radeonsi/si_state.c | 5 |
3 files changed, 20 insertions, 2 deletions
diff --git a/src/gallium/drivers/radeonsi/r600_blit.c b/src/gallium/drivers/radeonsi/r600_blit.c index fef4cccb8e6..483596e37dd 100644 --- a/src/gallium/drivers/radeonsi/r600_blit.c +++ b/src/gallium/drivers/radeonsi/r600_blit.c @@ -430,6 +430,21 @@ static void r600_compressed_to_blittable(struct pipe_resource *tex, rtex->surface.level[0].npix_y = util_format_get_nblocksy(orig->format, orig->npix0_y); rtex->surface.level[level].npix_x = util_format_get_nblocksx(orig->format, orig->npix_x); rtex->surface.level[level].npix_y = util_format_get_nblocksy(orig->format, orig->npix_y); + + /* By dividing the dimensions by 4, we effectively decrement + * last_level by 2, therefore the last 2 mipmap levels disappear and + * aren't blittable. Note that the last 3 mipmap levels (4x4, 2x2, + * 1x1) have equal slice sizes, which is an important assumption + * for this to work. + * + * In order to make the last 2 mipmap levels blittable, we have to + * add the slice size of the last mipmap level to the texture + * address, so that even though the hw thinks it reads last_level-2, + * it will actually read last_level-1, and if we add the slice size*2, + * it will read last_level. That's how this workaround works. + */ + if (level > rtex->resource.b.b.last_level-2) + rtex->mipmap_shift = level - (rtex->resource.b.b.last_level-2); } static void r600_change_format(struct pipe_resource *tex, @@ -463,6 +478,7 @@ static void r600_reset_blittable_to_orig(struct pipe_resource *tex, rtex->surface.level[0].npix_y = orig->npix0_y; rtex->surface.level[level].npix_x = orig->npix_x; rtex->surface.level[level].npix_y = orig->npix_y; + rtex->mipmap_shift = 0; } static void r600_resource_copy_region(struct pipe_context *ctx, diff --git a/src/gallium/drivers/radeonsi/r600_resource.h b/src/gallium/drivers/radeonsi/r600_resource.h index 3f9c7692728..185ae25205b 100644 --- a/src/gallium/drivers/radeonsi/r600_resource.h +++ b/src/gallium/drivers/radeonsi/r600_resource.h @@ -67,6 +67,7 @@ struct r600_texture { struct r600_texture *flushed_depth_texture; boolean is_flushing_texture; struct radeon_surface surface; + unsigned mipmap_shift; /* Colorbuffer compression and fast clear. */ struct r600_fmask_info fmask; diff --git a/src/gallium/drivers/radeonsi/si_state.c b/src/gallium/drivers/radeonsi/si_state.c index 3be17a595e0..8cec3e234d8 100644 --- a/src/gallium/drivers/radeonsi/si_state.c +++ b/src/gallium/drivers/radeonsi/si_state.c @@ -2469,6 +2469,7 @@ static struct pipe_sampler_view *si_create_sampler_view(struct pipe_context *ctx va = r600_resource_va(ctx->screen, texture); va += surflevel[0].offset; + va += tmp->mipmap_shift * surflevel[texture->last_level].slice_size; view->state[0] = va >> 8; view->state[1] = (S_008F14_BASE_ADDRESS_HI(va >> 40) | S_008F14_DATA_FORMAT(format) | @@ -2480,10 +2481,10 @@ static struct pipe_sampler_view *si_create_sampler_view(struct pipe_context *ctx S_008F1C_DST_SEL_Z(si_map_swizzle(swizzle[2])) | S_008F1C_DST_SEL_W(si_map_swizzle(swizzle[3])) | S_008F1C_BASE_LEVEL(texture->nr_samples > 1 ? - 0 : state->u.tex.first_level) | + 0 : state->u.tex.first_level - tmp->mipmap_shift) | S_008F1C_LAST_LEVEL(texture->nr_samples > 1 ? util_logbase2(texture->nr_samples) : - state->u.tex.last_level) | + state->u.tex.last_level - tmp->mipmap_shift) | S_008F1C_TILING_INDEX(si_tile_mode_index(tmp, 0, false)) | S_008F1C_POW2_PAD(texture->last_level > 0) | S_008F1C_TYPE(si_tex_dim(texture->target, texture->nr_samples))); |