Allocate a CMASK on demand and use it to fast clear single-sample colorbuffers. Both FBOs and window system colorbuffers are fast cleared. Expand as needed when colorbuffers are mapped or displayed on screen. --- src/gallium/drivers/r600/evergreen_state.c | 11 ++++ src/gallium/drivers/r600/r600_blit.c | 81 ++++++++++++++++++++++++---- src/gallium/drivers/r600/r600_pipe.c | 4 ++ src/gallium/drivers/r600/r600_pipe.h | 2 + src/gallium/drivers/r600/r600_state_common.c | 2 +- src/gallium/drivers/r600/r600_texture.c | 5 +- 6 files changed, 94 insertions(+), 11 deletions(-)
diff --git a/src/gallium/drivers/r600/evergreen_state.c b/src/gallium/drivers/r600/evergreen_state.c index 16d40e0..7ccd629 100644 --- a/src/gallium/drivers/r600/evergreen_state.c +++ b/src/gallium/drivers/r600/evergreen_state.c @@ -3567,6 +3567,17 @@ void *evergreen_create_decompress_blend(struct r600_context *rctx) return evergreen_create_blend_state_mode(&rctx->context, &blend, mode); } +void *evergreen_create_fastclear_blend(struct r600_context *rctx) +{ + struct pipe_blend_state blend; + unsigned mode = V_028808_CB_ELIMINATE_FAST_CLEAR; + + memset(&blend, 0, sizeof(blend)); + blend.independent_blend_enable = true; + blend.rt[0].colormask = 0xf; + return evergreen_create_blend_state_mode(&rctx->context, &blend, mode); +} + void *evergreen_create_db_flush_dsa(struct r600_context *rctx) { struct pipe_depth_stencil_alpha_state dsa = {{0}}; diff --git a/src/gallium/drivers/r600/r600_blit.c b/src/gallium/drivers/r600/r600_blit.c index 2230e7b..cd3da40 100644 --- a/src/gallium/drivers/r600/r600_blit.c +++ b/src/gallium/drivers/r600/r600_blit.c @@ -24,6 +24,7 @@ #include "util/u_surface.h" #include "util/u_blitter.h" #include "util/u_format.h" +#include "evergreend.h" enum r600_blitter_op /* bitmask */ { @@ -314,7 +315,8 @@ static void r600_blit_decompress_color(struct pipe_context *ctx, cbsurf = ctx->create_surface(ctx, &rtex->resource.b.b, &surf_tmpl); r600_blitter_begin(ctx, R600_DECOMPRESS); - util_blitter_custom_color(rctx->blitter, cbsurf, rctx->custom_blend_decompress); + util_blitter_custom_color(rctx->blitter, cbsurf, + rtex->fmask_size ? rctx->custom_blend_decompress : rctx->custom_blend_fastclear); r600_blitter_end(ctx); pipe_surface_reference(&cbsurf, NULL); @@ -344,7 +346,7 @@ void r600_decompress_color_textures(struct r600_context *rctx, assert(view); tex = (struct r600_texture *)view->texture; - assert(tex->cmask_size && tex->fmask_size); + assert(tex->cmask_size); r600_blit_decompress_color(&rctx->context, tex, view->u.tex.first_level, view->u.tex.last_level, @@ -379,7 +381,7 @@ static bool r600_decompress_subresource(struct pipe_context *ctx, first_layer, last_layer, 0, u_max_sample(tex)); } - } else if (rtex->fmask_size && rtex->cmask_size) { + } else if (rtex->cmask_size) { r600_blit_decompress_color(ctx, rtex, level, level, first_layer, last_layer); } @@ -435,6 +437,27 @@ static void evergreen_set_clear_color(struct pipe_surface *cbuf, memcpy(clear_value, &uc, 2 * sizeof(uint32_t)); } +static void evergreen_check_alloc_cmask(struct pipe_context *ctx, + struct pipe_surface *cbuf) +{ + struct r600_context *rctx = (struct r600_context *)ctx; + struct r600_texture *tex = (struct r600_texture *)cbuf->texture; + struct r600_surface *surf = (struct r600_surface *)cbuf; + + if (tex->cmask) + return; + + r600_texture_init_cmask(rctx->screen, tex); + + /* update colorbuffer state bits */ + if (tex->cmask != NULL) { + uint64_t va = r600_resource_va(rctx->context.screen, &tex->cmask->b.b); + surf->cb_color_cmask = va >> 8; + surf->cb_color_cmask_slice = S_028C80_TILE_MAX(tex->cmask_slice_tile_max); + surf->cb_color_info |= S_028C70_FAST_CLEAR(1); + } +} + static bool can_fast_clear_color(struct pipe_context *ctx) { struct r600_context *rctx = (struct r600_context *)ctx; @@ -448,10 +471,6 @@ static bool can_fast_clear_color(struct pipe_context *ctx) for (i = 0; i < fb->nr_cbufs; i++) { struct r600_texture *tex = (struct r600_texture *)fb->cbufs[i]->texture; - if (tex->cmask_size == 0) { - return false; - } - /* 128-bit formats are unuspported */ if (util_format_get_blocksizebits(fb->cbufs[i]->format) > 64) { return false; @@ -462,6 +481,23 @@ static bool can_fast_clear_color(struct pipe_context *ctx) fb->cbufs[i]->u.tex.last_layer != util_max_layer(&tex->resource.b.b, 0)) { return false; } + + /* cannot clear mipmapped textures */ + if (fb->cbufs[i]->texture->last_level != 0) { + return false; + } + + /* only supported on tiled surfaces */ + if (tex->array_mode[0] < V_028C70_ARRAY_1D_TILED_THIN1) { + return false; + } + + /* ensure CMASK is enabled */ + evergreen_check_alloc_cmask(ctx, fb->cbufs[i]); + if (tex->cmask_size == 0) { + return false; + } + } return true; @@ -474,7 +510,7 @@ static void r600_clear(struct pipe_context *ctx, unsigned buffers, struct r600_context *rctx = (struct r600_context *)ctx; struct pipe_framebuffer_state *fb = &rctx->framebuffer.state; - /* fast color clear on AA framebuffers (EG+) */ + /* fast clear on colorbuffers (EG+) */ if ((buffers & PIPE_CLEAR_COLOR) && can_fast_clear_color(ctx)) { int i; @@ -482,7 +518,7 @@ static void r600_clear(struct pipe_context *ctx, unsigned buffers, struct r600_texture *tex = (struct r600_texture *)fb->cbufs[i]->texture; evergreen_set_clear_color(fb->cbufs[i], color); - r600_clear_buffer(ctx, fb->cbufs[i]->texture, + r600_clear_buffer(ctx, &tex->cmask->b.b, tex->cmask_offset, tex->cmask_size, 0); tex->dirty_level_mask |= 1 << fb->cbufs[i]->u.tex.level; } @@ -492,8 +528,18 @@ static void r600_clear(struct pipe_context *ctx, unsigned buffers, buffers &= ~PIPE_CLEAR_COLOR; if (!buffers) return; + } else if (buffers & PIPE_CLEAR_COLOR) { + int i; + + /* cannot use fast clear, make sure to disable expansion */ + for (i = 0; i < fb->nr_cbufs; i++) { + struct r600_texture *tex = (struct r600_texture *)fb->cbufs[i]->texture; + if (tex->fmask_size == 0) + tex->dirty_level_mask &= ~(1 << fb->cbufs[i]->u.tex.level); + } } + /* if hyperz enabled just clear hyperz */ if (fb->zsbuf && (buffers & PIPE_CLEAR_DEPTH)) { struct r600_texture *rtex; @@ -903,6 +949,22 @@ static void r600_blit(struct pipe_context *ctx, r600_blitter_end(ctx); } +static boolean r600_expand(struct pipe_context *ctx, struct pipe_resource *res) +{ + struct r600_texture *rtex = (struct r600_texture*)res; + + assert(res->target != PIPE_BUFFER); + + if (!rtex->is_depth && rtex->cmask_size) { + bool success = !!rtex->dirty_level_mask; + r600_blit_decompress_color(ctx, rtex, 0, res->last_level, + 0, res->array_size - 1); + return success; + } + + return false; +} + void r600_init_blit_functions(struct r600_context *rctx) { rctx->context.clear = r600_clear; @@ -910,4 +972,5 @@ void r600_init_blit_functions(struct r600_context *rctx) rctx->context.clear_depth_stencil = r600_clear_depth_stencil; rctx->context.resource_copy_region = r600_resource_copy_region; rctx->context.blit = r600_blit; + rctx->context.expand_resource = r600_expand; } diff --git a/src/gallium/drivers/r600/r600_pipe.c b/src/gallium/drivers/r600/r600_pipe.c index 49abf50..b80a5b5 100644 --- a/src/gallium/drivers/r600/r600_pipe.c +++ b/src/gallium/drivers/r600/r600_pipe.c @@ -340,6 +340,9 @@ static void r600_destroy_context(struct pipe_context *context) if (rctx->custom_blend_decompress) { rctx->context.delete_blend_state(&rctx->context, rctx->custom_blend_decompress); } + if (rctx->custom_blend_fastclear) { + rctx->context.delete_blend_state(&rctx->context, rctx->custom_blend_fastclear); + } util_unreference_framebuffer_state(&rctx->framebuffer.state); if (rctx->blitter) { @@ -434,6 +437,7 @@ static struct pipe_context *r600_create_context(struct pipe_screen *screen, void rctx->custom_dsa_flush = evergreen_create_db_flush_dsa(rctx); rctx->custom_blend_resolve = evergreen_create_resolve_blend(rctx); rctx->custom_blend_decompress = evergreen_create_decompress_blend(rctx); + rctx->custom_blend_fastclear = evergreen_create_fastclear_blend(rctx); rctx->has_vertex_cache = !(rctx->family == CHIP_CEDAR || rctx->family == CHIP_PALM || rctx->family == CHIP_SUMO || diff --git a/src/gallium/drivers/r600/r600_pipe.h b/src/gallium/drivers/r600/r600_pipe.h index 349a6cb..d94bde6 100644 --- a/src/gallium/drivers/r600/r600_pipe.h +++ b/src/gallium/drivers/r600/r600_pipe.h @@ -554,6 +554,7 @@ struct r600_context { void *custom_dsa_flush; void *custom_blend_resolve; void *custom_blend_decompress; + void *custom_blend_fastclear; /* With rasterizer discard, there doesn't have to be a pixel shader. * In that case, we bind this one: */ void *dummy_pixel_shader; @@ -706,6 +707,7 @@ void evergreen_update_vs_state(struct pipe_context *ctx, struct r600_pipe_shader void *evergreen_create_db_flush_dsa(struct r600_context *rctx); void *evergreen_create_resolve_blend(struct r600_context *rctx); void *evergreen_create_decompress_blend(struct r600_context *rctx); +void *evergreen_create_fastclear_blend(struct r600_context *rctx); boolean evergreen_is_format_supported(struct pipe_screen *screen, enum pipe_format format, enum pipe_texture_target target, diff --git a/src/gallium/drivers/r600/r600_state_common.c b/src/gallium/drivers/r600/r600_state_common.c index ea5a4e7..36a67d7 100644 --- a/src/gallium/drivers/r600/r600_state_common.c +++ b/src/gallium/drivers/r600/r600_state_common.c @@ -609,7 +609,7 @@ static void r600_set_sampler_views(struct pipe_context *pipe, unsigned shader, } /* Track compressed colorbuffers. */ - if (rtex->cmask_size && rtex->fmask_size) { + if (rtex->cmask_size) { dst->views.compressed_colortex_mask |= 1 << i; } else { dst->views.compressed_colortex_mask &= ~(1 << i); diff --git a/src/gallium/drivers/r600/r600_texture.c b/src/gallium/drivers/r600/r600_texture.c index 1e80ed9..2e98b0a 100644 --- a/src/gallium/drivers/r600/r600_texture.c +++ b/src/gallium/drivers/r600/r600_texture.c @@ -74,6 +74,7 @@ static void r600_copy_to_staging_texture(struct pipe_context *ctx, struct r600_t struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer; struct pipe_resource *dst = &rtransfer->staging->b.b; struct pipe_resource *src = transfer->resource; + struct r600_texture *srctex = (struct r600_texture*)src; if (src->nr_samples > 1) { r600_copy_region_with_blit(ctx, dst, 0, 0, 0, 0, @@ -81,7 +82,7 @@ static void r600_copy_to_staging_texture(struct pipe_context *ctx, struct r600_t return; } - if (!rctx->screen->dma_blit(ctx, dst, 0, 0, 0, 0, + if (srctex->dirty_level_mask || !rctx->screen->dma_blit(ctx, dst, 0, 0, 0, 0, src, transfer->level, &transfer->box)) { ctx->resource_copy_region(ctx, dst, 0, 0, 0, 0, @@ -105,6 +106,8 @@ static void r600_copy_from_staging_texture(struct pipe_context *ctx, struct r600 transfer->box.x, transfer->box.y, transfer->box.z, src, 0, &sbox); return; + } else { + ctx->expand_resource(ctx, dst); } if (!rctx->screen->dma_blit(ctx, dst, transfer->level, -- 1.8.1.2 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev