If a driver uses the blitter utility and the draw module's AA point/line/ etc. helpers we have to very careful when using the pipe_context:: create_fs_state(), bind_fs_state() and delete_fs_state() functions. The draw module can override these driver functions.
This fixes the situation where the blitter's calls to create_fs_state() and bind_fs_state() were calling the draw module functions but delete_fs_state() was calling the driver's function. That mismatch led to memory corruption and crashes. The blitter code tries to avoid hitting the draw module functions. But that's derailed when the util_make_*fragment*() functions are called for creating shaders on demand. This patch adds new functions to patch in and restore the pipe::create_fs_state() function. We also call the ctx->bind_fs_state() function everywhere. Now we should never accidentally call any of the draw module functions. --- src/gallium/auxiliary/util/u_blitter.c | 82 ++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/src/gallium/auxiliary/util/u_blitter.c b/src/gallium/auxiliary/util/u_blitter.c index f3fe949..76fba24 100644 --- a/src/gallium/auxiliary/util/u_blitter.c +++ b/src/gallium/auxiliary/util/u_blitter.c @@ -137,10 +137,59 @@ struct blitter_context_priv /* The Draw module overrides these functions. * Always create the blitter before Draw. */ + void * (*create_fs_state)(struct pipe_context *, + const struct pipe_shader_state *); void (*bind_fs_state)(struct pipe_context *, void *); void (*delete_fs_state)(struct pipe_context *, void *); + + /* Only used between begin/end_create_fs_state() */ + void * (*saved_create_fs_state)(struct pipe_context *, + const struct pipe_shader_state *); }; + + +/** + * Need to call this before calling any of the util_make_*fragment*() + * functions. + * When we create/bind/delete fragment shaders we want to call the actual + * driver functions, not the draw module's functions. The draw modules for + * drawing AA points/lines can overide the driver's function so when we + * call util_make_*fragment*() we may wind up calling a draw module + * create_fs_state() function by mistake. + * + * This helper plugs in the real/driver create_fs_state() function into the + * pipe context. + * + * The alternative to this madness would be to pass a create_fs_state + * function into the util_make_*fragment*() functions to be explicit. + * But that's not simple either since the tgsi ureg code would need to be + * touched too. + */ +static INLINE void +begin_create_fs(struct blitter_context_priv *ctx) +{ + struct pipe_context *pipe = ctx->base.pipe; + assert(ctx->saved_create_fs_state == NULL); + ctx->saved_create_fs_state = pipe->create_fs_state; + pipe->create_fs_state = ctx->create_fs_state; +} + + +/** + * Need to call this after calling any of the util_make_*fragment*() + * functions to restore the pipe's create_fs_state() function. + */ +static INLINE void +end_create_fs(struct blitter_context_priv *ctx) +{ + struct pipe_context *pipe = ctx->base.pipe; + assert(ctx->saved_create_fs_state); + pipe->create_fs_state = ctx->saved_create_fs_state; + ctx->saved_create_fs_state = NULL; +} + + static struct pipe_surface * util_blitter_get_next_surface_layer(struct pipe_context *pipe, struct pipe_surface *surf); @@ -163,6 +212,7 @@ struct blitter_context *util_blitter_create(struct pipe_context *pipe) ctx->base.draw_rectangle = util_blitter_draw_rectangle; ctx->base.get_next_surface_layer = util_blitter_get_next_surface_layer; + ctx->create_fs_state = pipe->create_fs_state; ctx->bind_fs_state = pipe->bind_fs_state; ctx->delete_fs_state = pipe->delete_fs_state; @@ -356,10 +406,12 @@ static void bind_fs_empty(struct blitter_context_priv *ctx) struct pipe_context *pipe = ctx->base.pipe; if (!ctx->fs_empty) { + begin_create_fs(ctx); ctx->fs_empty = util_make_empty_fragment_shader(pipe); + end_create_fs(ctx); } - pipe->bind_fs_state(pipe, ctx->fs_empty); + ctx->bind_fs_state(pipe, ctx->fs_empty); } static void bind_fs_write_one_cbuf(struct blitter_context_priv *ctx) @@ -367,12 +419,14 @@ static void bind_fs_write_one_cbuf(struct blitter_context_priv *ctx) struct pipe_context *pipe = ctx->base.pipe; if (!ctx->fs_write_one_cbuf) { + begin_create_fs(ctx); ctx->fs_write_one_cbuf = util_make_fragment_passthrough_shader(pipe, TGSI_SEMANTIC_GENERIC, TGSI_INTERPOLATE_CONSTANT, FALSE); + end_create_fs(ctx); } - pipe->bind_fs_state(pipe, ctx->fs_write_one_cbuf); + ctx->bind_fs_state(pipe, ctx->fs_write_one_cbuf); } static void bind_fs_write_all_cbufs(struct blitter_context_priv *ctx) @@ -380,14 +434,18 @@ static void bind_fs_write_all_cbufs(struct blitter_context_priv *ctx) struct pipe_context *pipe = ctx->base.pipe; if (!ctx->fs_write_all_cbufs) { + begin_create_fs(ctx); ctx->fs_write_all_cbufs = util_make_fragment_passthrough_shader(pipe, TGSI_SEMANTIC_GENERIC, TGSI_INTERPOLATE_CONSTANT, TRUE); + end_create_fs(ctx); } - pipe->bind_fs_state(pipe, ctx->fs_write_all_cbufs); + ctx->bind_fs_state(pipe, ctx->fs_write_all_cbufs); } +void **special_addr = NULL; + void util_blitter_destroy(struct blitter_context *blitter) { struct blitter_context_priv *ctx = (struct blitter_context_priv*)blitter; @@ -850,6 +908,7 @@ static void *blitter_get_fs_texfetch_col(struct blitter_context_priv *ctx, shader = &ctx->fs_resolve[target][index][filter]; if (!*shader) { + begin_create_fs(ctx); if (filter == PIPE_TEX_FILTER_LINEAR) { *shader = util_make_fs_msaa_resolve_bilinear(pipe, tgsi_tex, src_nr_samples, @@ -860,6 +919,7 @@ static void *blitter_get_fs_texfetch_col(struct blitter_context_priv *ctx, src_nr_samples, is_uint, is_sint); } + end_create_fs(ctx); } } else { @@ -870,7 +930,9 @@ static void *blitter_get_fs_texfetch_col(struct blitter_context_priv *ctx, /* Create the fragment shader on-demand. */ if (!*shader) { + begin_create_fs(ctx); *shader = util_make_fs_blit_msaa_color(pipe, tgsi_tex); + end_create_fs(ctx); } } @@ -880,8 +942,10 @@ static void *blitter_get_fs_texfetch_col(struct blitter_context_priv *ctx, /* Create the fragment shader on-demand. */ if (!*shader) { + begin_create_fs(ctx); *shader = util_make_fragment_tex_shader(pipe, tgsi_tex, TGSI_INTERPOLATE_LINEAR); + end_create_fs(ctx); } return *shader; @@ -905,8 +969,10 @@ void *blitter_get_fs_texfetch_depth(struct blitter_context_priv *ctx, unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(target, nr_samples); + begin_create_fs(ctx); *shader = util_make_fs_blit_msaa_depth(pipe, tgsi_tex); + end_create_fs(ctx); } return *shader; @@ -917,9 +983,11 @@ void *blitter_get_fs_texfetch_depth(struct blitter_context_priv *ctx, if (!*shader) { unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(target, 0); + begin_create_fs(ctx); *shader = util_make_fragment_tex_shader_writedepth(pipe, tgsi_tex, TGSI_INTERPOLATE_LINEAR); + end_create_fs(ctx); } return *shader; @@ -943,8 +1011,10 @@ void *blitter_get_fs_texfetch_depthstencil(struct blitter_context_priv *ctx, unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(target, nr_samples); + begin_create_fs(ctx); *shader = util_make_fs_blit_msaa_depthstencil(pipe, tgsi_tex); + end_create_fs(ctx); } return *shader; @@ -955,9 +1025,11 @@ void *blitter_get_fs_texfetch_depthstencil(struct blitter_context_priv *ctx, if (!*shader) { unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(target, 0); + begin_create_fs(ctx); *shader = util_make_fragment_tex_shader_writedepthstencil(pipe, tgsi_tex, TGSI_INTERPOLATE_LINEAR); + end_create_fs(ctx); } return *shader; @@ -981,8 +1053,10 @@ void *blitter_get_fs_texfetch_stencil(struct blitter_context_priv *ctx, unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(target, nr_samples); + begin_create_fs(ctx); *shader = util_make_fs_blit_msaa_stencil(pipe, tgsi_tex); + end_create_fs(ctx); } return *shader; @@ -993,9 +1067,11 @@ void *blitter_get_fs_texfetch_stencil(struct blitter_context_priv *ctx, if (!*shader) { unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(target, 0); + begin_create_fs(ctx); *shader = util_make_fragment_tex_shader_writestencil(pipe, tgsi_tex, TGSI_INTERPOLATE_LINEAR); + end_create_fs(ctx); } return *shader; -- 1.7.10.4 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev