[Mesa-dev] [PATCH 1/5] clover: Add threadsafe wrappers for pipe_screen and pipe_context
Francisco Jerez
currojerez at riseup.net
Fri May 8 10:47:39 PDT 2015
Tom Stellard <thomas.stellard at amd.com> writes:
> Events can be added to an OpenCL command queue concurrently from
> multiple threads, but pipe_context and pipe_screen objects
> are not threadsafe. The threadsafe wrappers protect all pipe_screen
> and pipe_context function calls with a mutex, so we can safely use
> them with multiple threads.
> ---
> src/gallium/state_trackers/clover/Makefile.am | 6 +-
> src/gallium/state_trackers/clover/Makefile.sources | 4 +
> src/gallium/state_trackers/clover/core/device.cpp | 2 +
> .../clover/core/pipe_threadsafe_context.c | 272 +++++++++++++++++++++
> .../clover/core/pipe_threadsafe_screen.c | 184 ++++++++++++++
> .../state_trackers/clover/core/threadsafe.h | 39 +++
> src/gallium/targets/opencl/Makefile.am | 3 +-
> 7 files changed, 508 insertions(+), 2 deletions(-)
> create mode 100644 src/gallium/state_trackers/clover/core/pipe_threadsafe_context.c
> create mode 100644 src/gallium/state_trackers/clover/core/pipe_threadsafe_screen.c
> create mode 100644 src/gallium/state_trackers/clover/core/threadsafe.h
>
> diff --git a/src/gallium/state_trackers/clover/Makefile.am b/src/gallium/state_trackers/clover/Makefile.am
> index f46d9ef..8b615ae 100644
> --- a/src/gallium/state_trackers/clover/Makefile.am
> +++ b/src/gallium/state_trackers/clover/Makefile.am
> @@ -1,5 +1,6 @@
> AUTOMAKE_OPTIONS = subdir-objects
>
> +include $(top_srcdir)/src/gallium/Automake.inc
> include Makefile.sources
>
> AM_CPPFLAGS = \
> @@ -32,6 +33,9 @@ cl_HEADERS = \
> $(top_srcdir)/include/CL/opencl.h
> endif
>
> +AM_CFLAGS = \
> + $(GALLIUM_CFLAGS)
> +
> noinst_LTLIBRARIES = libclover.la libcltgsi.la libclllvm.la
>
> libcltgsi_la_CXXFLAGS = \
> @@ -58,6 +62,6 @@ libclover_la_CXXFLAGS = \
> libclover_la_LIBADD = \
> libcltgsi.la libclllvm.la
>
> -libclover_la_SOURCES = $(CPP_SOURCES)
> +libclover_la_SOURCES = $(CPP_SOURCES) $(C_SOURCES)
>
> EXTRA_DIST = Doxyfile
> diff --git a/src/gallium/state_trackers/clover/Makefile.sources b/src/gallium/state_trackers/clover/Makefile.sources
> index 10bbda0..90e6b7e 100644
> --- a/src/gallium/state_trackers/clover/Makefile.sources
> +++ b/src/gallium/state_trackers/clover/Makefile.sources
> @@ -53,6 +53,10 @@ CPP_SOURCES := \
> util/range.hpp \
> util/tuple.hpp
>
> +C_SOURCES := \
> + core/pipe_threadsafe_context.c \
> + core/pipe_threadsafe_screen.c
> +
> LLVM_SOURCES := \
> llvm/invocation.cpp
>
> diff --git a/src/gallium/state_trackers/clover/core/device.cpp b/src/gallium/state_trackers/clover/core/device.cpp
> index 42b45b7..b145027 100644
> --- a/src/gallium/state_trackers/clover/core/device.cpp
> +++ b/src/gallium/state_trackers/clover/core/device.cpp
> @@ -22,6 +22,7 @@
>
> #include "core/device.hpp"
> #include "core/platform.hpp"
> +#include "core/threadsafe.h"
> #include "pipe/p_screen.h"
> #include "pipe/p_state.h"
>
> @@ -47,6 +48,7 @@ device::device(clover::platform &platform, pipe_loader_device *ldev) :
> pipe->destroy(pipe);
> throw error(CL_INVALID_DEVICE);
> }
> + pipe = pipe_threadsafe_screen(pipe);
> }
>
> device::~device() {
> diff --git a/src/gallium/state_trackers/clover/core/pipe_threadsafe_context.c b/src/gallium/state_trackers/clover/core/pipe_threadsafe_context.c
> new file mode 100644
> index 0000000..f08f56c
> --- /dev/null
> +++ b/src/gallium/state_trackers/clover/core/pipe_threadsafe_context.c
> @@ -0,0 +1,272 @@
> +/*
> + * 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.
> + */
> +
> +#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;
> + 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;
> +}
> diff --git a/src/gallium/state_trackers/clover/core/pipe_threadsafe_screen.c b/src/gallium/state_trackers/clover/core/pipe_threadsafe_screen.c
> new file mode 100644
> index 0000000..cc2f842
> --- /dev/null
> +++ b/src/gallium/state_trackers/clover/core/pipe_threadsafe_screen.c
> @@ -0,0 +1,184 @@
> +/*
> + * 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_screen is a wrapper around a pipe_screen to make it thread
> + * safe. Some functions are already theadsafe and don't require the mutex
> + * guard.
> + */
> +
> +#include "os/os_thread.h"
> +#include "pipe/p_context.h"
> +#include "pipe/p_screen.h"
> +#include "util/u_memory.h"
> +
> +#include "threadsafe.h"
> +
> +struct threadsafe_screen {
> + struct pipe_screen base;
> + struct pipe_screen *screen;
> + pipe_mutex mutex;
> +};
> +
> +static struct pipe_screen *unwrap(struct pipe_screen *screen) {
> + if (!screen)
> + return NULL;
> + struct threadsafe_screen *ts_screen = (struct threadsafe_screen*)screen;
> + return ts_screen->screen;
> +}
> +
> +#define THREADSAFE_CALL_VOID(screen, function) \
> + struct threadsafe_screen *ts_screen = (struct threadsafe_screen*)(screen); \
> + pipe_mutex_lock(ts_screen->mutex); \
> + (unwrap(screen)->function); \
> + pipe_mutex_unlock(ts_screen->mutex);
> +
> +#define THREADSAFE_CALL_RET(screen, return_type, function) \
> + struct threadsafe_screen *ts_screen = (struct threadsafe_screen*)(screen); \
> + pipe_mutex_lock(ts_screen->mutex); \
> + return_type ret = (unwrap(screen)->function); \
> + pipe_mutex_unlock(ts_screen->mutex); \
> + return ret;
> +
> +static struct pipe_context *threadsafe_context_create(
> + struct pipe_screen *screen,
> + void *priv) {
> + struct threadsafe_screen *ts_screen = (struct threadsafe_screen*)(screen);
> + struct pipe_context *ctx;
> +
> + pipe_mutex_lock(ts_screen->mutex);
> + ctx = unwrap(screen)->context_create(unwrap(screen), priv);
> + ctx = pipe_threadsafe_context(ctx);
> + ctx->screen = screen;
> + pipe_mutex_unlock(ts_screen->mutex);
> + return ctx;
> +}
> +
> +static void threadsafe_destroy(struct pipe_screen *screen) {
> + THREADSAFE_CALL_VOID(screen, destroy(unwrap(screen)));
> + FREE(screen);
> +}
> +
> +static boolean threadsafe_is_format_supported(struct pipe_screen *screen,
> + enum pipe_format format,
> + enum pipe_texture_target target,
> + unsigned sample_count,
> + unsigned bindings) {
> + return unwrap(screen)->is_format_supported(unwrap(screen), format, target,
> + sample_count, bindings);
> +}
> +
> +
> +static struct pipe_resource *threadsafe_resource_create(
> + struct pipe_screen *screen,
> + const struct pipe_resource *templat) {
> + THREADSAFE_CALL_RET(screen, struct pipe_resource*,
> + resource_create(unwrap(screen), templat));
> +}
> +
> +static void threadsafe_resource_destroy(struct pipe_screen *screen,
> + struct pipe_resource *pt) {
> + THREADSAFE_CALL_VOID(screen, resource_destroy(unwrap(screen), pt));
> +}
> +
> +static int threadsafe_get_compute_param(struct pipe_screen *screen,
> + enum pipe_compute_cap param,
> + void *ret) {
> + return unwrap(screen)->get_compute_param(unwrap(screen), param, ret);
> +}
> +
> +static int threadsafe_get_param(struct pipe_screen *screen,
> + enum pipe_cap param) {
> + return unwrap(screen)->get_param(unwrap(screen), param);
> +}
> +
> +static const char* threadsafe_get_name(struct pipe_screen *screen) {
> + return unwrap(screen)->get_name(unwrap(screen));
> +}
> +
> +static const char* threadsafe_get_device_vendor(struct pipe_screen *screen) {
> + return unwrap(screen)->get_device_vendor(unwrap(screen));
> +}
> +
> +static int threadsafe_get_shader_param(struct pipe_screen *screen,
> + unsigned shader,
> + enum pipe_shader_cap param) {
> + return unwrap(screen)->get_shader_param(unwrap(screen), shader, param);
> +}
> +
> +static void threadsafe_fence_reference(struct pipe_screen *screen,
> + struct pipe_fence_handle **ptr,
> + struct pipe_fence_handle *fence) {
> + THREADSAFE_CALL_VOID(screen, fence_reference(unwrap(screen), ptr, fence));
> +}
> +
> +static uint64_t threadsafe_get_timestamp(struct pipe_screen *screen) {
> + THREADSAFE_CALL_RET(screen, uint64_t, get_timestamp(unwrap(screen)));
> +}
> +
> +static boolean threadsafe_fence_signalled(struct pipe_screen *screen,
> + struct pipe_fence_handle *fence) {
> + THREADSAFE_CALL_RET(screen, boolean, fence_signalled(unwrap(screen), fence));
> +}
> +
> +static boolean threadsafe_fence_finish(struct pipe_screen *screen,
> + struct pipe_fence_handle *fence,
> + uint64_t timeout) {
> + THREADSAFE_CALL_RET(screen, boolean,
> + fence_finish(unwrap(screen), fence, timeout));
> +}
> +
> +#define INIT_FUNCTION(name) \
> + ts_screen->base.name = threadsafe_ ## name;
> +
> +struct pipe_screen *pipe_threadsafe_screen(struct pipe_screen *screen) {
> + struct threadsafe_screen *ts_screen = CALLOC_STRUCT(threadsafe_screen);
> +
> + ts_screen->screen = screen;
> + pipe_mutex_init(ts_screen->mutex);
> +
> + INIT_FUNCTION(context_create);
> + INIT_FUNCTION(destroy);
> + INIT_FUNCTION(is_format_supported);
> + INIT_FUNCTION(resource_create);
> + INIT_FUNCTION(resource_destroy);
> + INIT_FUNCTION(get_compute_param);
> + INIT_FUNCTION(get_param);
> + INIT_FUNCTION(get_name);
> + INIT_FUNCTION(get_device_vendor);
> + INIT_FUNCTION(get_shader_param);
> + INIT_FUNCTION(fence_reference);
> + INIT_FUNCTION(get_timestamp);
> + INIT_FUNCTION(fence_signalled);
> + INIT_FUNCTION(fence_finish);
> +
> + return &ts_screen->base;
> +}
> diff --git a/src/gallium/state_trackers/clover/core/threadsafe.h b/src/gallium/state_trackers/clover/core/threadsafe.h
> new file mode 100644
> index 0000000..f49ff8c
> --- /dev/null
> +++ b/src/gallium/state_trackers/clover/core/threadsafe.h
> @@ -0,0 +1,39 @@
> +/*
> + * 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_screen;
> +
> +struct pipe_context *pipe_threadsafe_context(struct pipe_context *ctx);
> +struct pipe_screen *pipe_threadsafe_screen(struct pipe_screen *screen);
> +
> +#ifdef __cplusplus
> +}
> +#endif
> diff --git a/src/gallium/targets/opencl/Makefile.am b/src/gallium/targets/opencl/Makefile.am
> index 5daf327..268370f 100644
> --- a/src/gallium/targets/opencl/Makefile.am
> +++ b/src/gallium/targets/opencl/Makefile.am
> @@ -38,7 +38,8 @@ lib at OPENCL_LIBNAME@_la_LIBADD = \
> -lclangEdit \
> -lclangLex \
> -lclangBasic \
> - $(LLVM_LIBS)
> + $(LLVM_LIBS) \
> + $(PTHREAD_LIBS)
>
> nodist_EXTRA_lib at OPENCL_LIBNAME@_la_SOURCES = dummy.cpp
> lib at OPENCL_LIBNAME@_la_SOURCES =
> --
> 2.0.4
This seems to be growing into a wrapping pipe driver kind of like noop
or trace, so it might deserve its own directory in gallium/drivers even
if no other state tracker currently requires contexts to be thread safe.
In any case it implements a lower-level API than anything else inside
clover/core, so a separate directory would be a better fit if you decide
to keep it inside clover (e.g. clover/pipe/threadsafe.h?).
The situation with screens is different, because many APIs will want it
to be thread-safe. I guess there are two ways to guarantee thread
safety of screens: Make it the driver's responsibility or the state
tracker's responsibility (in both cases your screen wrapper *might* be
useful for state trackers other than clover or drivers to obtain a
thread-safe screen out of a thread-unsafe one, but in the latter case
drivers are likely to be able to implement things more efficiently, with
finer-grained or no locking at all). You seem to have taken a mixed
approach with some hooks being thread-safe and some others not, this
seems strange and I guess it should be thoroughly documented if there is
some reason to do it.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 212 bytes
Desc: not available
URL: <http://lists.freedesktop.org/archives/mesa-dev/attachments/20150508/b248edc9/attachment-0001.sig>
More information about the mesa-dev
mailing list