From ff6e119572158beaf852c4eb8f8cbfcfaab99cc1 Mon Sep 17 00:00:00 2001
From: Andreas Kloeckner <inform@tiker.net>
Date: Mon, 13 Aug 2018 15:28:01 -0500
Subject: [PATCH] Implement sampler creation with properties

---
 doc/runtime_memory.rst | 27 +++++++++++----
 src/wrap_cl.hpp        | 76 ++++++++++++++++++++++++++++++++++++++----
 src/wrap_cl_part_2.cpp |  3 ++
 3 files changed, 93 insertions(+), 13 deletions(-)

diff --git a/doc/runtime_memory.rst b/doc/runtime_memory.rst
index 8431e44a..a4ad2d5f 100644
--- a/doc/runtime_memory.rst
+++ b/doc/runtime_memory.rst
@@ -352,13 +352,28 @@ Mapping Memory into Host Address Space
 Samplers
 --------
 
-.. class:: Sampler(context, normalized_coords, addressing_mode, filter_mode)
+.. class:: Sampler
 
-    *normalized_coords* is a :class:`bool` indicating whether
-    to use coordinates between 0 and 1 (*True*) or the texture's
-    natural pixel size (*False*).
-    See :class:`addressing_mode` and :class:`filter_mode` for possible
-    argument values.
+
+    .. method:: __init__(context, normalized_coords, addressing_mode, filter_mode)
+
+        *normalized_coords* is a :class:`bool` indicating whether
+        to use coordinates between 0 and 1 (*True*) or the texture's
+        natural pixel size (*False*).
+        See :class:`addressing_mode` and :class:`filter_mode` for possible
+        argument values.
+
+    .. method:: __init__(context, properties)
+
+        :arg properties: a sequence
+            of keys and values from :class:`sampler_properties` as accepted
+            by :c:func:`clCreateSamplerWithProperties` (see the OpenCL
+            spec for details). The trailing *0* is added automatically
+            and does not need to be included.
+
+        Requires OpenCL 2 or newer.
+
+        .. versionadded:: 2018.2
 
     .. attribute:: info
 
diff --git a/src/wrap_cl.hpp b/src/wrap_cl.hpp
index a444b798..a55c1806 100644
--- a/src/wrap_cl.hpp
+++ b/src/wrap_cl.hpp
@@ -3523,26 +3523,88 @@ namespace pyopencl
       cl_sampler m_sampler;
 
     public:
+#if PYOPENCL_CL_VERSION >= 0x2000
+      sampler(context const &ctx, py::sequence py_props)
+      {
+        int hex_plat_version = ctx.get_hex_platform_version();
+
+        if (hex_plat_version  < 0x2000)
+        {
+          std::cerr <<
+            "sampler properties given as an iterable, "
+            "which uses an OpenCL 2+-only interface, "
+            "but the context's platform does not "
+            "declare OpenCL 2 support. Proceeding "
+            "as requested, but the next thing you see "
+            "may be a crash." << std:: endl;
+        }
+
+        cl_sampler_properties props[py::len(py_props) + 1];
+        {
+          size_t i = 0;
+          for (auto prop: py_props)
+            props[i++] = py::cast<cl_sampler_properties>(prop);
+          props[i++] = 0;
+        }
+
+        cl_int status_code;
+        PYOPENCL_PRINT_CALL_TRACE("clCreateSamplerWithProperties");
+
+        m_sampler = clCreateSamplerWithProperties(
+            ctx.data(),
+            props,
+            &status_code);
+
+        if (status_code != CL_SUCCESS)
+          throw pyopencl::error("Sampler", status_code);
+      }
+#endif
+
       sampler(context const &ctx, bool normalized_coordinates,
           cl_addressing_mode am, cl_filter_mode fm)
       {
-        cl_int status_code;
         PYOPENCL_PRINT_CALL_TRACE("clCreateSampler");
 
+        int hex_plat_version = ctx.get_hex_platform_version();
+#if PYOPENCL_CL_VERSION >= 0x2000
+        if (hex_plat_version  >= 0x2000)
+        {
+            cl_sampler_properties props_list[] = {
+              CL_SAMPLER_NORMALIZED_COORDS, normalized_coordinates,
+              CL_SAMPLER_ADDRESSING_MODE, am,
+              CL_SAMPLER_FILTER_MODE, fm,
+              0,
+            };
+
+            cl_int status_code;
+
+            PYOPENCL_PRINT_CALL_TRACE("clCreateSamplerWithProperties");
+            m_sampler = clCreateSamplerWithProperties(
+                ctx.data(), props_list, &status_code);
+
+            if (status_code != CL_SUCCESS)
+              throw pyopencl::error("Sampler", status_code);
+        }
+        else
+#endif
+        {
+          cl_int status_code;
+
 #if defined(__GNUG__) && !defined(__clang__)
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
 #endif
-        m_sampler = clCreateSampler(
-            ctx.data(),
-            normalized_coordinates,
-            am, fm, &status_code);
+          m_sampler = clCreateSampler(
+              ctx.data(),
+              normalized_coordinates,
+              am, fm, &status_code);
 #if defined(__GNUG__) && !defined(__clang__)
 #pragma GCC diagnostic pop
 #endif
 
-        if (status_code != CL_SUCCESS)
-          throw pyopencl::error("Sampler", status_code);
+          if (status_code != CL_SUCCESS)
+            throw pyopencl::error("Sampler", status_code);
+        }
       }
 
       sampler(cl_sampler samp, bool retain)
diff --git a/src/wrap_cl_part_2.cpp b/src/wrap_cl_part_2.cpp
index ac1533e2..2e8e9e4c 100644
--- a/src/wrap_cl_part_2.cpp
+++ b/src/wrap_cl_part_2.cpp
@@ -299,6 +299,9 @@ void pyopencl_expose_part_2(py::module &m)
   {
     typedef sampler cls;
     py::class_<cls>(m, "Sampler", py::dynamic_attr())
+#if PYOPENCL_CL_VERSION >= 0x2000
+      .def(py::init<context const &, py::sequence>())
+#endif
       .def(py::init<context const &, bool, cl_addressing_mode, cl_filter_mode>())
       .DEF_SIMPLE_METHOD(get_info)
       .def(py::self == py::self)
-- 
GitLab