From 1c76f6e755a5ec0ad8fb37f173cbd47dc8c9cd2b Mon Sep 17 00:00:00 2001 From: "Juan A. Suarez Romero" Date: Tue, 1 Dec 2020 09:39:52 +0100 Subject: [PATCH] v3d: implement tile-based blit operation This implements fast-path blit using the TLB to blit from one buffer to another, if conditions for allowing this are met. v1: - Move checks in the code (Iago) v2: - Use function to compute tile width and height (Iago) - Fix commit message (Iago) - Use surface size to compute draw_tiles_{x,y} (Iago) - Move checks (Iago) - Fix tile draw parameters (Iago) Reviewed-by: Iago Toral Quiroga Signed-off-by: Juan A. Suarez Romero Part-of: --- src/gallium/drivers/v3d/v3d_blit.c | 123 +++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/src/gallium/drivers/v3d/v3d_blit.c b/src/gallium/drivers/v3d/v3d_blit.c index d1e895688bc..4bbe38f081c 100644 --- a/src/gallium/drivers/v3d/v3d_blit.c +++ b/src/gallium/drivers/v3d/v3d_blit.c @@ -513,6 +513,126 @@ v3d_tfu_blit(struct pipe_context *pctx, const struct pipe_blit_info *info) info->src.box.z, info->dst.box.z); } +static struct pipe_surface * +v3d_get_blit_surface(struct pipe_context *pctx, + struct pipe_resource *prsc, + unsigned level, + int16_t layer) +{ + struct pipe_surface tmpl; + + tmpl.format = prsc->format; + tmpl.u.tex.level = level; + tmpl.u.tex.first_layer = layer; + tmpl.u.tex.last_layer = layer; + + return pctx->create_surface(pctx, prsc, &tmpl); +} + +static bool +is_tile_unaligned(unsigned size, unsigned tile_size) +{ + return size & (tile_size - 1); +} + +static bool +v3d_tlb_blit(struct pipe_context *pctx, const struct pipe_blit_info *info) +{ + struct v3d_context *v3d = v3d_context(pctx); + struct v3d_screen *screen = v3d->screen; + + if (screen->devinfo.ver < 40) + return false; + + if ((info->mask & PIPE_MASK_RGBA) == 0) + return false; + + if (info->scissor_enable) + return false; + + if (info->src.box.x != info->dst.box.x || + info->src.box.y != info->dst.box.y || + info->src.box.width != info->dst.box.width || + info->src.box.height != info->dst.box.height) + return false; + + if (util_format_is_depth_or_stencil(info->dst.resource->format)) + return false; + + if (!v3d_rt_format_supported(&screen->devinfo, info->src.resource->format)) + return false; + + if (v3d_get_rt_format(&screen->devinfo, info->src.resource->format) != + v3d_get_rt_format(&screen->devinfo, info->dst.resource->format)) + return false; + + bool msaa = (info->src.resource->nr_samples > 1 || + info->dst.resource->nr_samples > 1); + bool is_msaa_resolve = (info->src.resource->nr_samples > 1 && + info->dst.resource->nr_samples < 2); + + if (is_msaa_resolve && + !v3d_format_supports_tlb_msaa_resolve(&screen->devinfo, info->src.resource->format)) + return false; + + v3d_flush_jobs_writing_resource(v3d, info->src.resource, V3D_FLUSH_DEFAULT, false); + + struct pipe_surface *dst_surf = + v3d_get_blit_surface(pctx, info->dst.resource, info->dst.level, info->dst.box.z); + struct pipe_surface *src_surf = + v3d_get_blit_surface(pctx, info->src.resource, info->src.level, info->src.box.z); + + struct pipe_surface *surfaces[V3D_MAX_DRAW_BUFFERS] = { 0 }; + surfaces[0] = dst_surf; + + uint32_t tile_width, tile_height, max_bpp; + v3d_get_tile_buffer_size(msaa, 1, surfaces, src_surf, &tile_width, &tile_height, &max_bpp); + + int dst_surface_width = u_minify(info->dst.resource->width0, + info->dst.level); + int dst_surface_height = u_minify(info->dst.resource->height0, + info->dst.level); + if (is_tile_unaligned(info->dst.box.x, tile_width) || + is_tile_unaligned(info->dst.box.y, tile_height) || + (is_tile_unaligned(info->dst.box.width, tile_width) && + info->dst.box.x + info->dst.box.width != dst_surface_width) || + (is_tile_unaligned(info->dst.box.height, tile_height) && + info->dst.box.y + info->dst.box.height != dst_surface_height)) { + pipe_surface_reference(&dst_surf, NULL); + pipe_surface_reference(&src_surf, NULL); + return false; + } + + struct v3d_job *job = v3d_get_job(v3d, 1u, surfaces, NULL, src_surf); + job->msaa = msaa; + job->tile_width = tile_width; + job->tile_height = tile_height; + job->internal_bpp = max_bpp; + job->draw_min_x = info->dst.box.x; + job->draw_min_y = info->dst.box.y; + job->draw_max_x = info->dst.box.x + info->dst.box.width; + job->draw_max_y = info->dst.box.y + info->dst.box.height; + job->draw_width = dst_surf->width; + job->draw_height = dst_surf->height; + job->draw_tiles_x = DIV_ROUND_UP(dst_surf->width, + job->tile_width); + job->draw_tiles_y = DIV_ROUND_UP(dst_surf->height, + job->tile_height); + + job->needs_flush = true; + job->store |= PIPE_CLEAR_COLOR0; + job->num_layers = info->dst.box.depth; + + v3d41_start_binning(v3d, job); + + v3d_job_submit(v3d, job); + + pipe_surface_reference(&dst_surf, NULL); + pipe_surface_reference(&src_surf, NULL); + + return true; +} + /* Optimal hardware path for blitting pixels. * Scaling, format conversion, up- and downsampling (resolve) are allowed. */ @@ -530,6 +650,9 @@ v3d_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info) if (v3d_tfu_blit(pctx, blit_info)) info.mask &= ~PIPE_MASK_RGBA; + if (v3d_tlb_blit(pctx, blit_info)) + info.mask &= ~PIPE_MASK_RGBA; + if (info.mask) v3d_render_blit(pctx, &info);