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 <alexandros.frantzis@collabora.com>
Signed-off-by: Jakob Bornecrantz <jakob@collabora.com>
Reviewed-by: Gurchetan Singh <gurchetansingh@chromium.org>
Tested-by: Gurchetan Singh <gurchetansingh@chromium.org>
macos/master
Alexandros Frantzis 7 years ago committed by Jakob Bornecrantz
parent b16b08e60f
commit 313da6c8f4
  1. 85
      src/vrend_blitter.c

@ -75,6 +75,16 @@ struct vrend_blitter_ctx {
static struct vrend_blitter_ctx vrend_blit_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) static bool build_and_check(GLuint id, const char *buf)
{ {
GLint param; 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. */ /* implement blitting using OpenGL. */
void vrend_renderer_blit_gl(struct vrend_context *ctx, void vrend_renderer_blit_gl(struct vrend_context *ctx,
struct vrend_resource *src_res, struct vrend_resource *src_res,
@ -548,6 +610,8 @@ void vrend_renderer_blit_gl(struct vrend_context *ctx,
bool has_depth, has_stencil; bool has_depth, has_stencil;
bool blit_stencil, blit_depth; bool blit_stencil, blit_depth;
int dst_z; 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 = const struct util_format_description *src_desc =
util_format_description(src_res->base.format); util_format_description(src_res->base.format);
const struct util_format_description *dst_desc = 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.width0, info->dst.level),
u_minify(dst_res->base.height0, 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, /* Calculate src and dst points taking deltas into account */
info->dst.box.x + info->dst.box.width, calc_src_deltas_for_bounds(src_res, info, &src0_delta, &src1_delta);
info->dst.box.y + info->dst.box.height, 0); 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(); prog_id = glCreateProgram();
glAttachShader(prog_id, blit_ctx->vs); glAttachShader(prog_id, blit_ctx->vs);
@ -656,9 +731,7 @@ void vrend_renderer_blit_gl(struct vrend_context *ctx,
glDrawBuffers(1, &buffers); glDrawBuffers(1, &buffers);
blitter_set_texcoords(blit_ctx, src_res, info->src.level, blitter_set_texcoords(blit_ctx, src_res, info->src.level,
info->src.box.z + src_z, 0, info->src.box.z + src_z, 0,
info->src.box.x, info->src.box.y, src0.x, src0.y, src1.x, src1.y);
info->src.box.x + info->src.box.width,
info->src.box.y + info->src.box.height);
glBufferData(GL_ARRAY_BUFFER, sizeof(blit_ctx->vertices), blit_ctx->vertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(blit_ctx->vertices), blit_ctx->vertices, GL_STATIC_DRAW);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

Loading…
Cancel
Save