From 313da6c8f480a576cdc2c9dc866ebb8e8f8ecb17 Mon Sep 17 00:00:00 2001 From: Alexandros Frantzis Date: Mon, 23 Apr 2018 18:45:59 +0300 Subject: [PATCH] vrend: Properly handle out-of-bounds blits when blitting with GL Ensure we don't blit pixels originating from outside the extents of the source resource. To achieve this we clip the source blit region, and update the destination blit region accordingly, while respecting scaled blits. This fix will allow us to introduce swizzles for some formats in upcoming commits, and thus use the GL blitter for them, without introducing any regressions Signed-off-by: Alexandros Frantzis Signed-off-by: Jakob Bornecrantz Reviewed-by: Gurchetan Singh Tested-by: Gurchetan Singh --- src/vrend_blitter.c | 85 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 6 deletions(-) diff --git a/src/vrend_blitter.c b/src/vrend_blitter.c index c273f0f..b727436 100644 --- a/src/vrend_blitter.c +++ b/src/vrend_blitter.c @@ -75,6 +75,16 @@ struct vrend_blitter_ctx { static struct vrend_blitter_ctx vrend_blit_ctx; +struct vrend_blitter_point { + int x; + int y; +}; + +struct vrend_blitter_delta { + int dx; + int dy; +}; + static bool build_and_check(GLuint id, const char *buf) { GLint param; @@ -531,6 +541,58 @@ static inline GLenum to_gl_swizzle(int swizzle) } } +/* Calculate the delta required to keep 'v' within [0, max] */ +static int calc_delta_for_bound(int v, int max) +{ + int delta = 0; + + if (v < 0) + delta = -v; + else if (v > max) + delta = - (v - max); + + return delta; +} + +/* Calculate the deltas for the source blit region points in order to bound + * them within the source resource extents */ +static void calc_src_deltas_for_bounds(struct vrend_resource *src_res, + const struct pipe_blit_info *info, + struct vrend_blitter_delta *src0_delta, + struct vrend_blitter_delta *src1_delta) +{ + int max_x = u_minify(src_res->base.width0, info->src.level) - 1; + int max_y = u_minify(src_res->base.height0, info->src.level) - 1; + + /* point 0 uses inclusive bounds */ + src0_delta->dx = calc_delta_for_bound(info->src.box.x, max_x); + src0_delta->dy = calc_delta_for_bound(info->src.box.y, max_y); + + /* point 1 uses exclusive bounds */ + src1_delta->dx = calc_delta_for_bound(info->src.box.x + info->src.box.width, + max_x + 1); + src1_delta->dy = calc_delta_for_bound(info->src.box.y + info->src.box.height, + max_y + 1); +} + +/* Calculate dst delta values to adjust the dst points for any changes in the + * src points */ +static void calc_dst_deltas_from_src(const struct pipe_blit_info *info, + const struct vrend_blitter_delta *src0_delta, + const struct vrend_blitter_delta *src1_delta, + struct vrend_blitter_delta *dst0_delta, + struct vrend_blitter_delta *dst1_delta) +{ + float scale_x = (float)info->dst.box.width / (float)info->src.box.width; + float scale_y = (float)info->dst.box.height / (float)info->src.box.height; + + dst0_delta->dx = src0_delta->dx * scale_x; + dst0_delta->dy = src0_delta->dy * scale_y; + + dst1_delta->dx = src1_delta->dx * scale_x; + dst1_delta->dy = src1_delta->dy * scale_y; +} + /* implement blitting using OpenGL. */ void vrend_renderer_blit_gl(struct vrend_context *ctx, struct vrend_resource *src_res, @@ -548,6 +610,8 @@ void vrend_renderer_blit_gl(struct vrend_context *ctx, bool has_depth, has_stencil; bool blit_stencil, blit_depth; int dst_z; + struct vrend_blitter_delta src0_delta, src1_delta, dst0_delta, dst1_delta; + struct vrend_blitter_point src0, src1, dst0, dst1; const struct util_format_description *src_desc = util_format_description(src_res->base.format); const struct util_format_description *dst_desc = @@ -572,10 +636,21 @@ void vrend_renderer_blit_gl(struct vrend_context *ctx, u_minify(dst_res->base.width0, info->dst.level), u_minify(dst_res->base.height0, info->dst.level)); - blitter_set_rectangle(blit_ctx, info->dst.box.x, info->dst.box.y, - info->dst.box.x + info->dst.box.width, - info->dst.box.y + info->dst.box.height, 0); + /* Calculate src and dst points taking deltas into account */ + calc_src_deltas_for_bounds(src_res, info, &src0_delta, &src1_delta); + calc_dst_deltas_from_src(info, &src0_delta, &src1_delta, &dst0_delta, &dst1_delta); + + src0.x = info->src.box.x + src0_delta.dx; + src0.y = info->src.box.y + src0_delta.dy; + src1.x = info->src.box.x + info->src.box.width + src1_delta.dx; + src1.y = info->src.box.y + info->src.box.height + src1_delta.dy; + + dst0.x = info->dst.box.x + dst0_delta.dx; + dst0.y = info->dst.box.y + dst0_delta.dy; + dst1.x = info->dst.box.x + info->dst.box.width + dst1_delta.dx; + dst1.y = info->dst.box.y + info->dst.box.height + dst1_delta.dy; + blitter_set_rectangle(blit_ctx, dst0.x, dst0.y, dst1.x, dst1.y, 0); prog_id = glCreateProgram(); glAttachShader(prog_id, blit_ctx->vs); @@ -656,9 +731,7 @@ void vrend_renderer_blit_gl(struct vrend_context *ctx, glDrawBuffers(1, &buffers); blitter_set_texcoords(blit_ctx, src_res, info->src.level, info->src.box.z + src_z, 0, - info->src.box.x, info->src.box.y, - info->src.box.x + info->src.box.width, - info->src.box.y + info->src.box.height); + src0.x, src0.y, src1.x, src1.y); glBufferData(GL_ARRAY_BUFFER, sizeof(blit_ctx->vertices), blit_ctx->vertices, GL_STATIC_DRAW); glDrawArrays(GL_TRIANGLE_FAN, 0, 4);