[Mesa-dev] [PATCH 1/5] clover: Add threadsafe wrappers for pipe_screen and pipe_context

Tom Stellard thomas.stellard at amd.com
Thu May 7 16:36:54 PDT 2015


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



More information about the mesa-dev mailing list