[Mesa-dev] [PATCH 1/2] gallium/drivers: Add threadsafe wrappers for pipe_context v2

Marek Olšák maraeo at gmail.com
Sat Jul 11 02:53:10 PDT 2015


Hi,

the surface_destroy and sampler_view_destroy wrappers won't be called,
because surface->context and view->context are always used for those
calls and "context" points to the driver context in this case. The
solution is to update the "context" pointer in create_sampler_view and
create_surface if you care at all. st/mesa might not like a different
"context" pointer, but other users should be fine.

Either way:

Reviewed-by: Marek Olšák <marek.olsak at amd.com>

Marek


On Sat, Jul 11, 2015 at 3:55 AM, Tom Stellard <thomas.stellard at amd.com> wrote:
> These wrappers can be used by state trackers to ensure threadsafe access
> to pipe_context objects.
>
> v2:
>   - Don't add wrappers for pipe_screen.
>   - Build system cleanups
>
> CC: 10.6 <mesa-stable at lists.freedesktop.org>
> ---
>  configure.ac                                       |   1 +
>  src/gallium/Makefile.am                            |   1 +
>  src/gallium/SConscript                             |   1 +
>  src/gallium/drivers/threadsafe/Makefile.am         |  11 +
>  src/gallium/drivers/threadsafe/Makefile.sources    |   3 +
>  src/gallium/drivers/threadsafe/SConscript          |  13 +
>  src/gallium/drivers/threadsafe/threadsafe.h        |  37 +++
>  .../drivers/threadsafe/threadsafe_context.c        | 276 +++++++++++++++++++++
>  8 files changed, 343 insertions(+)
>  create mode 100644 src/gallium/drivers/threadsafe/Makefile.am
>  create mode 100644 src/gallium/drivers/threadsafe/Makefile.sources
>  create mode 100644 src/gallium/drivers/threadsafe/SConscript
>  create mode 100644 src/gallium/drivers/threadsafe/threadsafe.h
>  create mode 100644 src/gallium/drivers/threadsafe/threadsafe_context.c
>
> diff --git a/configure.ac b/configure.ac
> index d819bef..6f93a2e 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -2358,6 +2358,7 @@ AC_CONFIG_FILES([Makefile
>                 src/gallium/drivers/rbug/Makefile
>                 src/gallium/drivers/softpipe/Makefile
>                 src/gallium/drivers/svga/Makefile
> +               src/gallium/drivers/threadsafe/Makefile
>                 src/gallium/drivers/trace/Makefile
>                 src/gallium/drivers/vc4/Makefile
>                 src/gallium/state_trackers/clover/Makefile
> diff --git a/src/gallium/Makefile.am b/src/gallium/Makefile.am
> index ede6e21..2290583 100644
> --- a/src/gallium/Makefile.am
> +++ b/src/gallium/Makefile.am
> @@ -12,6 +12,7 @@ SUBDIRS += auxiliary
>
>  SUBDIRS += \
>         drivers/noop \
> +       drivers/threadsafe \
>         drivers/trace \
>         drivers/rbug
>
> diff --git a/src/gallium/SConscript b/src/gallium/SConscript
> index eeb1c78..e6070b6 100644
> --- a/src/gallium/SConscript
> +++ b/src/gallium/SConscript
> @@ -17,6 +17,7 @@ SConscript([
>      'drivers/softpipe/SConscript',
>      'drivers/svga/SConscript',
>      'drivers/trace/SConscript',
> +    'drivers/threadsafe/SConscript',
>  ])
>
>  #
> diff --git a/src/gallium/drivers/threadsafe/Makefile.am b/src/gallium/drivers/threadsafe/Makefile.am
> new file mode 100644
> index 0000000..bab64bf
> --- /dev/null
> +++ b/src/gallium/drivers/threadsafe/Makefile.am
> @@ -0,0 +1,11 @@
> +include Makefile.sources
> +include $(top_srcdir)/src/gallium/Automake.inc
> +
> +AM_CFLAGS = \
> +       $(GALLIUM_DRIVER_CFLAGS)
> +
> +noinst_LTLIBRARIES = libthreadsafe.la
> +
> +libthreadsafe_la_SOURCES = $(C_SOURCES)
> +
> +EXTRA_DIST = SConscript
> diff --git a/src/gallium/drivers/threadsafe/Makefile.sources b/src/gallium/drivers/threadsafe/Makefile.sources
> new file mode 100644
> index 0000000..5e8778e
> --- /dev/null
> +++ b/src/gallium/drivers/threadsafe/Makefile.sources
> @@ -0,0 +1,3 @@
> +C_SOURCES := \
> +       threadsafe.h \
> +       threadsafe_context.c
> diff --git a/src/gallium/drivers/threadsafe/SConscript b/src/gallium/drivers/threadsafe/SConscript
> new file mode 100644
> index 0000000..bc3333e
> --- /dev/null
> +++ b/src/gallium/drivers/threadsafe/SConscript
> @@ -0,0 +1,13 @@
> +#######################################################################
> +# SConscript for noop convenience library
> +
> +Import('*')
> +
> +env = env.Clone()
> +
> +threadsafe = env.ConvenienceLibrary(
> +       target = 'threadsafe',
> +       source = env.ParseSourceList('Makefile.sources', 'C_SOURCES')
> +       ) + extra
> +
> +Export('threadsafe')
> diff --git a/src/gallium/drivers/threadsafe/threadsafe.h b/src/gallium/drivers/threadsafe/threadsafe.h
> new file mode 100644
> index 0000000..60614ed
> --- /dev/null
> +++ b/src/gallium/drivers/threadsafe/threadsafe.h
> @@ -0,0 +1,37 @@
> +/*
> + * Copyright 2015 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + *
> + * Authors: Tom Stellard <thomas.stellard at amd.com>
> + *
> + */
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +struct pipe_context;
> +
> +struct pipe_context *pipe_threadsafe_context(struct pipe_context *ctx);
> +
> +#ifdef __cplusplus
> +}
> +#endif
> diff --git a/src/gallium/drivers/threadsafe/threadsafe_context.c b/src/gallium/drivers/threadsafe/threadsafe_context.c
> new file mode 100644
> index 0000000..070adc5
> --- /dev/null
> +++ b/src/gallium/drivers/threadsafe/threadsafe_context.c
> @@ -0,0 +1,276 @@
> +/*
> + * Copyright 2015 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + *
> + * Authors: Tom Stellard <thomas.stellard at amd.com>
> + *
> + */
> +
> +#include <stdio.h>
> +
> +/**
> + * \file
> + *
> + * threadsafe_context is a wrapper around a pipe_context to make it thread
> + * safe.
> + *
> + * TODO: Implement all gallium functions.  Only the functions required by the
> + * clover state tracker have been implemented.
> + */
> +
> +#include "os/os_thread.h"
> +#include "pipe/p_context.h"
> +#include "util/u_memory.h"
> +
> +#include "threadsafe.h"
> +
> +
> +
> +struct threadsafe_context {
> +   struct pipe_context base;
> +   struct pipe_context *ctx;
> +   pipe_mutex mutex;
> +};
> +
> +static struct pipe_context *unwrap(struct pipe_context *ctx) {
> +   if (!ctx)
> +      return NULL;
> +   struct threadsafe_context *ts_ctx = (struct threadsafe_context*)ctx;
> +   return ts_ctx->ctx;
> +}
> +
> +#define THREADSAFE_CALL_VOID(ctx, function) \
> +   struct threadsafe_context *ts_ctx = (struct threadsafe_context*)(ctx); \
> +   pipe_mutex_lock(ts_ctx->mutex); \
> +   (unwrap(ctx)->function); \
> +   pipe_mutex_unlock(ts_ctx->mutex);
> +
> +#define THREADSAFE_CALL_RET(ctx, return_type, function) \
> +   struct threadsafe_context *ts_ctx = (struct threadsafe_context*)(ctx); \
> +   pipe_mutex_lock(ts_ctx->mutex); \
> +   return_type ret = (unwrap(ctx)->function); \
> +   pipe_mutex_unlock(ts_ctx->mutex); \
> +   return ret;
> +
> +
> +static void threadsafe_destroy(struct pipe_context *ctx) {
> +   THREADSAFE_CALL_VOID(ctx, destroy(unwrap(ctx)));
> +   FREE(ctx);
> +}
> +
> +static void *threadsafe_create_sampler_state(struct pipe_context *ctx,
> +                                       const struct pipe_sampler_state *state) {
> +   THREADSAFE_CALL_RET(ctx, void*, create_sampler_state(unwrap(ctx), state));
> +}
> +
> +static struct pipe_query *threadsafe_create_query(struct pipe_context *ctx,
> +                                                  unsigned query_type,
> +                                                  unsigned index) {
> +   THREADSAFE_CALL_RET(ctx, struct pipe_query*,
> +      create_query(unwrap(ctx), query_type, index));
> +}
> +
> +static void threadsafe_bind_compute_state(struct pipe_context *ctx,
> +                                          void * state) {
> +   THREADSAFE_CALL_VOID(ctx, bind_compute_state(unwrap(ctx), state));
> +}
> +
> +static void threadsafe_bind_sampler_states(struct pipe_context *ctx,
> +                                           unsigned shader, unsigned start_slot,
> +                                           unsigned num_samplers,
> +                                           void **samplers) {
> +   THREADSAFE_CALL_VOID(ctx,
> +      bind_sampler_states(unwrap(ctx), shader, start_slot, num_samplers,
> +                          samplers));
> +}
> +
> +static void threadsafe_set_sampler_views(struct pipe_context *ctx,
> +                                         unsigned shader, unsigned start_slot,
> +                                         unsigned num_views,
> +                                         struct pipe_sampler_view ** views) {
> +   THREADSAFE_CALL_VOID(ctx,
> +      set_sampler_views(unwrap(ctx), shader, start_slot, num_views, views));
> +}
> +
> +
> +static void threadsafe_set_compute_resources(struct pipe_context *ctx,
> +                                             unsigned start, unsigned count,
> +                                             struct pipe_surface **resources) {
> +   THREADSAFE_CALL_VOID(ctx,
> +      set_compute_resources(unwrap(ctx), start, count, resources));
> +}
> +
> +static void threadsafe_set_global_binding(struct pipe_context *ctx,
> +                                          unsigned first, unsigned count,
> +                                          struct pipe_resource **resources,
> +                                          uint32_t **handles) {
> +   THREADSAFE_CALL_VOID(ctx,
> +      set_global_binding(unwrap(ctx), first, count, resources, handles));
> +}
> +
> +static void threadsafe_launch_grid(struct pipe_context *ctx,
> +                                   const uint *block_layout,
> +                                   const uint *grid_layout,
> +                                   uint32_t pc, const void *input) {
> +   THREADSAFE_CALL_VOID(ctx,
> +      launch_grid(unwrap(ctx), block_layout, grid_layout, pc, input));
> +}
> +
> +static void threadsafe_delete_compute_state(struct pipe_context *ctx,
> +                                            void *state) {
> +   THREADSAFE_CALL_VOID(ctx, delete_compute_state(unwrap(ctx), state));
> +}
> +
> +static void *threadsafe_create_compute_state(struct pipe_context *ctx,
> +                                       const struct pipe_compute_state *state) {
> +   THREADSAFE_CALL_RET(ctx, void*, create_compute_state(unwrap(ctx), state));
> +}
> +
> +static void threadsafe_flush(struct pipe_context *ctx,
> +                             struct pipe_fence_handle **fence,
> +                             unsigned flags) {
> +   THREADSAFE_CALL_VOID(ctx, flush(unwrap(ctx), fence, flags));
> +}
> +
> +static struct pipe_sampler_view *threadsafe_create_sampler_view(
> +                                      struct pipe_context *ctx,
> +                                      struct pipe_resource *texture,
> +                                      const struct pipe_sampler_view *templat) {
> +   THREADSAFE_CALL_RET(ctx, struct pipe_sampler_view*,
> +      create_sampler_view(unwrap(ctx), texture, templat));
> +}
> +
> +static void threadsafe_resource_copy_region(struct pipe_context *ctx,
> +                                 struct pipe_resource *dst,
> +                                 unsigned dst_level,
> +                                 unsigned dstx, unsigned dsty, unsigned dstz,
> +                                 struct pipe_resource *src,
> +                                 unsigned src_level,
> +                                 const struct pipe_box *src_box) {
> +   THREADSAFE_CALL_VOID(ctx,
> +      resource_copy_region(unwrap(ctx), dst, dst_level, dstx, dsty, dstz, src,
> +                           src_level, src_box));
> +}
> +
> +static void threadsafe_sampler_view_destroy(struct pipe_context *ctx,
> +                                            struct pipe_sampler_view *view) {
> +   THREADSAFE_CALL_VOID(ctx, sampler_view_destroy(unwrap(ctx), view));
> +}
> +
> +static struct pipe_surface *threadsafe_create_surface(struct pipe_context *ctx,
> +                                           struct pipe_resource *resource,
> +                                           const struct pipe_surface *templat) {
> +   THREADSAFE_CALL_RET(ctx, struct pipe_surface*,
> +      create_surface(unwrap(ctx), resource, templat));
> +}
> +
> +
> +static void threadsafe_surface_destroy(struct pipe_context *ctx,
> +                                       struct pipe_surface *surface) {
> +   THREADSAFE_CALL_VOID(ctx, surface_destroy(unwrap(ctx), surface));
> +}
> +
> +static void threadsafe_transfer_inline_write(struct pipe_context *ctx,
> +                                             struct pipe_resource *resource,
> +                                             unsigned level, unsigned usage,
> +                                             const struct pipe_box *pipe_box,
> +                                             const void *data,
> +                                             unsigned stride,
> +                                             unsigned layer_stride) {
> +   THREADSAFE_CALL_VOID(ctx,
> +      transfer_inline_write(unwrap(ctx), resource, level, usage, pipe_box, data,
> +                            stride, layer_stride));
> +}
> +
> +static void *threadsafe_transfer_map(struct pipe_context *ctx,
> +                                     struct pipe_resource *resource,
> +                                     unsigned level,
> +                                     unsigned usage,
> +                                     const struct pipe_box *box,
> +                                     struct pipe_transfer **out_transfer) {
> +   THREADSAFE_CALL_RET(ctx, void*,
> +      transfer_map(unwrap(ctx), resource, level, usage, box, out_transfer));
> +}
> +
> +static void threadsafe_transfer_unmap(struct pipe_context *ctx,
> +                                      struct pipe_transfer *transfer) {
> +   THREADSAFE_CALL_VOID(ctx, transfer_unmap(unwrap(ctx), transfer));
> +}
> +
> +static void threadsafe_delete_sampler_state(struct pipe_context *ctx,
> +                                            void *state) {
> +   THREADSAFE_CALL_VOID(ctx, delete_sampler_state(unwrap(ctx), state));
> +}
> +
> +static void threadsafe_end_query(struct pipe_context *ctx,
> +                                 struct pipe_query *q) {
> +   THREADSAFE_CALL_VOID(ctx, end_query(unwrap(ctx), q));
> +}
> +
> +static void threadsafe_destroy_query(struct pipe_context *ctx,
> +                                     struct pipe_query *q) {
> +   THREADSAFE_CALL_VOID(ctx, destroy_query(unwrap(ctx), q));
> +}
> +
> +static boolean threadsafe_get_query_result(struct pipe_context *ctx,
> +                                           struct pipe_query *q,
> +                                           boolean wait,
> +                                           union pipe_query_result *result) {
> +   THREADSAFE_CALL_RET(ctx, boolean,
> +      get_query_result(unwrap(ctx), q, wait, result));
> +}
> +
> +#define INIT_FUNCTION(name) \
> +   ts_ctx->base.name = threadsafe_ ## name;
> +
> +struct pipe_context *pipe_threadsafe_context(struct pipe_context *ctx) {
> +   struct threadsafe_context *ts_ctx = CALLOC_STRUCT(threadsafe_context);
> +
> +   ts_ctx->ctx = ctx;
> +   ts_ctx->base.screen = ctx->screen;
> +   pipe_mutex_init(ts_ctx->mutex);
> +
> +   INIT_FUNCTION(destroy);
> +   INIT_FUNCTION(create_query);
> +   INIT_FUNCTION(bind_compute_state);
> +   INIT_FUNCTION(bind_sampler_states);
> +   INIT_FUNCTION(set_sampler_views);
> +   INIT_FUNCTION(set_compute_resources);
> +   INIT_FUNCTION(set_global_binding);
> +   INIT_FUNCTION(launch_grid);
> +   INIT_FUNCTION(delete_compute_state);
> +   INIT_FUNCTION(create_compute_state);
> +   INIT_FUNCTION(flush);
> +   INIT_FUNCTION(create_sampler_view);
> +   INIT_FUNCTION(resource_copy_region);
> +   INIT_FUNCTION(sampler_view_destroy);
> +   INIT_FUNCTION(create_surface);
> +   INIT_FUNCTION(surface_destroy);
> +   INIT_FUNCTION(transfer_inline_write);
> +   INIT_FUNCTION(transfer_map);
> +   INIT_FUNCTION(transfer_unmap);
> +   INIT_FUNCTION(create_sampler_state);
> +   INIT_FUNCTION(delete_sampler_state);
> +   INIT_FUNCTION(end_query);
> +   INIT_FUNCTION(destroy_query);
> +   INIT_FUNCTION(get_query_result);
> +   return &ts_ctx->base;
> +}
> --
> 2.0.4
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev


More information about the mesa-dev mailing list